Merge branch 'bnx2x-cnic-bnx2fc-bd-support'
Yuval Mintz says:
====================
bnx2x, cnic, bnx2fc: add support for BD
Commit 230d00eb4b
("bnx2x: new Multi-function mode - BD") added support
for a new multi-function mode, but it added only the support required by
bnx2x for L2 interfaces.
This adds the required changes to support the new multi-function mode in
the offloaded storage protocols.
Dave,
Please consider applying this series to `net-next'.
Do notice that this involves non-networking driver changes -
but sending this as a single series seemed like the best approach as
we had to have bnx2x changes to support the new functionality.
If this is problematic, please tell us what's the preferred solution here.
Changes from previous versions
------------------------------
- From v1 - no actual changes; v1 failed to reach netdev so in order to
keep things in line I've termed this one v2.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
02b5242847
|
@ -1386,4 +1386,16 @@ void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag,
|
|||
* @state: OS_DRIVER_STATE_* value reflecting current driver state
|
||||
*/
|
||||
void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state);
|
||||
|
||||
/**
|
||||
* bnx2x_nvram_read - reads data from nvram [might sleep]
|
||||
*
|
||||
* @bp: driver handle
|
||||
* @offset: byte offset in nvram
|
||||
* @ret_buf: pointer to buffer where data is to be stored
|
||||
* @buf_size: Length of 'ret_buf' in bytes
|
||||
*/
|
||||
int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
|
||||
int buf_size);
|
||||
|
||||
#endif /* BNX2X_CMN_H */
|
||||
|
|
|
@ -1348,8 +1348,8 @@ static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
|
||||
int buf_size)
|
||||
int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
|
||||
int buf_size)
|
||||
{
|
||||
int rc;
|
||||
u32 cmd_flags;
|
||||
|
|
|
@ -2075,6 +2075,25 @@ enum curr_cfg_method_e {
|
|||
CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */
|
||||
};
|
||||
|
||||
#define FC_NPIV_WWPN_SIZE 8
|
||||
#define FC_NPIV_WWNN_SIZE 8
|
||||
struct bdn_npiv_settings {
|
||||
u8 npiv_wwpn[FC_NPIV_WWPN_SIZE];
|
||||
u8 npiv_wwnn[FC_NPIV_WWNN_SIZE];
|
||||
};
|
||||
|
||||
struct bdn_fc_npiv_cfg {
|
||||
/* hdr used internally by the MFW */
|
||||
u32 hdr;
|
||||
u32 num_of_npiv;
|
||||
};
|
||||
|
||||
#define MAX_NUMBER_NPIV 64
|
||||
struct bdn_fc_npiv_tbl {
|
||||
struct bdn_fc_npiv_cfg fc_npiv_cfg;
|
||||
struct bdn_npiv_settings settings[MAX_NUMBER_NPIV];
|
||||
};
|
||||
|
||||
struct mdump_driver_info {
|
||||
u32 epoc;
|
||||
u32 drv_ver;
|
||||
|
|
|
@ -14653,6 +14653,90 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
|
|||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
/* For storage-only interfaces, change driver state */
|
||||
if (IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) {
|
||||
switch (ctl->drv_state) {
|
||||
case DRV_NOP:
|
||||
break;
|
||||
case DRV_ACTIVE:
|
||||
bnx2x_set_os_driver_state(bp,
|
||||
OS_DRIVER_STATE_ACTIVE);
|
||||
break;
|
||||
case DRV_INACTIVE:
|
||||
bnx2x_set_os_driver_state(bp,
|
||||
OS_DRIVER_STATE_DISABLED);
|
||||
break;
|
||||
case DRV_UNLOADED:
|
||||
bnx2x_set_os_driver_state(bp,
|
||||
OS_DRIVER_STATE_NOT_LOADED);
|
||||
break;
|
||||
default:
|
||||
BNX2X_ERR("Unknown cnic driver state: %d\n", ctl->drv_state);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bnx2x_get_fc_npiv(struct net_device *dev,
|
||||
struct cnic_fc_npiv_tbl *cnic_tbl)
|
||||
{
|
||||
struct bnx2x *bp = netdev_priv(dev);
|
||||
struct bdn_fc_npiv_tbl *tbl = NULL;
|
||||
u32 offset, entries;
|
||||
int rc = -EINVAL;
|
||||
int i;
|
||||
|
||||
if (!SHMEM2_HAS(bp, fc_npiv_nvram_tbl_addr[0]))
|
||||
goto out;
|
||||
|
||||
DP(BNX2X_MSG_MCP, "About to read the FC-NPIV table\n");
|
||||
|
||||
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
|
||||
if (!tbl) {
|
||||
BNX2X_ERR("Failed to allocate fc_npiv table\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset = SHMEM2_RD(bp, fc_npiv_nvram_tbl_addr[BP_PORT(bp)]);
|
||||
DP(BNX2X_MSG_MCP, "Offset of FC-NPIV in NVRAM: %08x\n", offset);
|
||||
|
||||
/* Read the table contents from nvram */
|
||||
if (bnx2x_nvram_read(bp, offset, (u8 *)tbl, sizeof(*tbl))) {
|
||||
BNX2X_ERR("Failed to read FC-NPIV table\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Since bnx2x_nvram_read() returns data in be32, we need to convert
|
||||
* the number of entries back to cpu endianness.
|
||||
*/
|
||||
entries = tbl->fc_npiv_cfg.num_of_npiv;
|
||||
entries = (__force u32)be32_to_cpu((__force __be32)entries);
|
||||
tbl->fc_npiv_cfg.num_of_npiv = entries;
|
||||
|
||||
if (!tbl->fc_npiv_cfg.num_of_npiv) {
|
||||
DP(BNX2X_MSG_MCP,
|
||||
"No FC-NPIV table [valid, simply not present]\n");
|
||||
goto out;
|
||||
} else if (tbl->fc_npiv_cfg.num_of_npiv > MAX_NUMBER_NPIV) {
|
||||
BNX2X_ERR("FC-NPIV table with bad length 0x%08x\n",
|
||||
tbl->fc_npiv_cfg.num_of_npiv);
|
||||
goto out;
|
||||
} else {
|
||||
DP(BNX2X_MSG_MCP, "Read 0x%08x entries from NVRAM\n",
|
||||
tbl->fc_npiv_cfg.num_of_npiv);
|
||||
}
|
||||
|
||||
/* Copy the data into cnic-provided struct */
|
||||
cnic_tbl->count = tbl->fc_npiv_cfg.num_of_npiv;
|
||||
for (i = 0; i < cnic_tbl->count; i++) {
|
||||
memcpy(cnic_tbl->wwpn[i], tbl->settings[i].npiv_wwpn, 8);
|
||||
memcpy(cnic_tbl->wwnn[i], tbl->settings[i].npiv_wwnn, 8);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
kfree(tbl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -14798,6 +14882,7 @@ static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
|
|||
cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS;
|
||||
cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
|
||||
cp->drv_ctl = bnx2x_drv_ctl;
|
||||
cp->drv_get_fc_npiv_tbl = bnx2x_get_fc_npiv;
|
||||
cp->drv_register_cnic = bnx2x_register_cnic;
|
||||
cp->drv_unregister_cnic = bnx2x_unregister_cnic;
|
||||
cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID(bp);
|
||||
|
|
|
@ -192,6 +192,7 @@ static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val)
|
|||
struct drv_ctl_info info;
|
||||
struct drv_ctl_io *io = &info.data.io;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = DRV_CTL_CTX_WR_CMD;
|
||||
io->cid_addr = cid_addr;
|
||||
io->offset = off;
|
||||
|
@ -206,6 +207,7 @@ static void cnic_ctx_tbl_wr(struct cnic_dev *dev, u32 off, dma_addr_t addr)
|
|||
struct drv_ctl_info info;
|
||||
struct drv_ctl_io *io = &info.data.io;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = DRV_CTL_CTXTBL_WR_CMD;
|
||||
io->offset = off;
|
||||
io->dma_addr = addr;
|
||||
|
@ -219,6 +221,7 @@ static void cnic_ring_ctl(struct cnic_dev *dev, u32 cid, u32 cl_id, int start)
|
|||
struct drv_ctl_info info;
|
||||
struct drv_ctl_l2_ring *ring = &info.data.ring;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
if (start)
|
||||
info.cmd = DRV_CTL_START_L2_CMD;
|
||||
else
|
||||
|
@ -236,6 +239,7 @@ static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val)
|
|||
struct drv_ctl_info info;
|
||||
struct drv_ctl_io *io = &info.data.io;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = DRV_CTL_IO_WR_CMD;
|
||||
io->offset = off;
|
||||
io->data = val;
|
||||
|
@ -249,13 +253,14 @@ static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off)
|
|||
struct drv_ctl_info info;
|
||||
struct drv_ctl_io *io = &info.data.io;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = DRV_CTL_IO_RD_CMD;
|
||||
io->offset = off;
|
||||
ethdev->drv_ctl(dev->netdev, &info);
|
||||
return io->data;
|
||||
}
|
||||
|
||||
static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg)
|
||||
static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg, int state)
|
||||
{
|
||||
struct cnic_local *cp = dev->cnic_priv;
|
||||
struct cnic_eth_dev *ethdev = cp->ethdev;
|
||||
|
@ -263,6 +268,7 @@ static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg)
|
|||
struct fcoe_capabilities *fcoe_cap =
|
||||
&info.data.register_data.fcoe_features;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
if (reg) {
|
||||
info.cmd = DRV_CTL_ULP_REGISTER_CMD;
|
||||
if (ulp_type == CNIC_ULP_FCOE && dev->fcoe_cap)
|
||||
|
@ -272,6 +278,7 @@ static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg)
|
|||
}
|
||||
|
||||
info.data.ulp_type = ulp_type;
|
||||
info.drv_state = state;
|
||||
ethdev->drv_ctl(dev->netdev, &info);
|
||||
}
|
||||
|
||||
|
@ -286,6 +293,7 @@ static void cnic_spq_completion(struct cnic_dev *dev, int cmd, u32 count)
|
|||
struct cnic_eth_dev *ethdev = cp->ethdev;
|
||||
struct drv_ctl_info info;
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = cmd;
|
||||
info.data.credit.credit_count = count;
|
||||
ethdev->drv_ctl(dev->netdev, &info);
|
||||
|
@ -591,7 +599,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
|
|||
|
||||
mutex_unlock(&cnic_lock);
|
||||
|
||||
cnic_ulp_ctl(dev, ulp_type, true);
|
||||
cnic_ulp_ctl(dev, ulp_type, true, DRV_ACTIVE);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -636,7 +644,10 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
|
|||
if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]))
|
||||
netdev_warn(dev->netdev, "Failed waiting for ULP up call to complete\n");
|
||||
|
||||
cnic_ulp_ctl(dev, ulp_type, false);
|
||||
if (test_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]))
|
||||
cnic_ulp_ctl(dev, ulp_type, false, DRV_UNLOADED);
|
||||
else
|
||||
cnic_ulp_ctl(dev, ulp_type, false, DRV_INACTIVE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4267,6 +4278,7 @@ static void cnic_delete_task(struct work_struct *work)
|
|||
|
||||
cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI);
|
||||
|
||||
memset(&info, 0, sizeof(struct drv_ctl_info));
|
||||
info.cmd = DRV_CTL_ISCSI_STOPPED_CMD;
|
||||
cp->ethdev->drv_ctl(dev->netdev, &info);
|
||||
}
|
||||
|
@ -5433,6 +5445,23 @@ static void cnic_free_dev(struct cnic_dev *dev)
|
|||
kfree(dev);
|
||||
}
|
||||
|
||||
static int cnic_get_fc_npiv_tbl(struct cnic_dev *dev,
|
||||
struct cnic_fc_npiv_tbl *npiv_tbl)
|
||||
{
|
||||
struct cnic_local *cp = dev->cnic_priv;
|
||||
struct bnx2x *bp = netdev_priv(dev->netdev);
|
||||
int ret;
|
||||
|
||||
if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
|
||||
return -EAGAIN; /* bnx2x is down */
|
||||
|
||||
if (!BNX2X_CHIP_IS_E2_PLUS(bp))
|
||||
return -EINVAL;
|
||||
|
||||
ret = cp->ethdev->drv_get_fc_npiv_tbl(dev->netdev, npiv_tbl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
|
||||
struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -5451,6 +5480,7 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
|
|||
cdev->register_device = cnic_register_device;
|
||||
cdev->unregister_device = cnic_unregister_device;
|
||||
cdev->iscsi_nl_msg_recv = cnic_iscsi_nl_msg_recv;
|
||||
cdev->get_fc_npiv_tbl = cnic_get_fc_npiv_tbl;
|
||||
|
||||
cp = cdev->cnic_priv;
|
||||
cp->dev = cdev;
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
#include "bnx2x/bnx2x_mfw_req.h"
|
||||
|
||||
#define CNIC_MODULE_VERSION "2.5.21"
|
||||
#define CNIC_MODULE_RELDATE "January 29, 2015"
|
||||
#define CNIC_MODULE_VERSION "2.5.22"
|
||||
#define CNIC_MODULE_RELDATE "July 20, 2015"
|
||||
|
||||
#define CNIC_ULP_RDMA 0
|
||||
#define CNIC_ULP_ISCSI 1
|
||||
|
@ -151,6 +151,11 @@ struct drv_ctl_register_data {
|
|||
|
||||
struct drv_ctl_info {
|
||||
int cmd;
|
||||
int drv_state;
|
||||
#define DRV_NOP 0
|
||||
#define DRV_ACTIVE 1
|
||||
#define DRV_INACTIVE 2
|
||||
#define DRV_UNLOADED 3
|
||||
union {
|
||||
struct drv_ctl_spq_credit credit;
|
||||
struct drv_ctl_io io;
|
||||
|
@ -161,6 +166,15 @@ struct drv_ctl_info {
|
|||
} data;
|
||||
};
|
||||
|
||||
#define MAX_NPIV_ENTRIES 64
|
||||
#define FC_NPIV_WWN_SIZE 8
|
||||
|
||||
struct cnic_fc_npiv_tbl {
|
||||
u8 wwpn[MAX_NPIV_ENTRIES][FC_NPIV_WWN_SIZE];
|
||||
u8 wwnn[MAX_NPIV_ENTRIES][FC_NPIV_WWN_SIZE];
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct cnic_ops {
|
||||
struct module *cnic_owner;
|
||||
/* Calls to these functions are protected by RCU. When
|
||||
|
@ -226,6 +240,8 @@ struct cnic_eth_dev {
|
|||
int (*drv_submit_kwqes_16)(struct net_device *,
|
||||
struct kwqe_16 *[], u32);
|
||||
int (*drv_ctl)(struct net_device *, struct drv_ctl_info *);
|
||||
int (*drv_get_fc_npiv_tbl)(struct net_device *,
|
||||
struct cnic_fc_npiv_tbl *);
|
||||
unsigned long reserved1[2];
|
||||
union drv_info_to_mcp *addr_drv_info_to_mcp;
|
||||
};
|
||||
|
@ -314,6 +330,7 @@ struct cnic_dev {
|
|||
struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type);
|
||||
int (*iscsi_nl_msg_recv)(struct cnic_dev *dev, u32 msg_type,
|
||||
char *data, u16 data_size);
|
||||
int (*get_fc_npiv_tbl)(struct cnic_dev *, struct cnic_fc_npiv_tbl *);
|
||||
unsigned long flags;
|
||||
#define CNIC_F_CNIC_UP 1
|
||||
#define CNIC_F_BNX2_CLASS 3
|
||||
|
|
|
@ -2051,9 +2051,49 @@ static int bnx2fc_disable(struct net_device *netdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static uint bnx2fc_npiv_create_vports(struct fc_lport *lport,
|
||||
struct cnic_fc_npiv_tbl *npiv_tbl)
|
||||
{
|
||||
struct fc_vport_identifiers vpid;
|
||||
uint i, created = 0;
|
||||
|
||||
if (npiv_tbl->count > MAX_NPIV_ENTRIES) {
|
||||
BNX2FC_HBA_DBG(lport, "Exceeded count max of npiv table\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Sanity check the first entry to make sure it's not 0 */
|
||||
if (wwn_to_u64(npiv_tbl->wwnn[0]) == 0 &&
|
||||
wwn_to_u64(npiv_tbl->wwpn[0]) == 0) {
|
||||
BNX2FC_HBA_DBG(lport, "First NPIV table entries invalid.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
vpid.roles = FC_PORT_ROLE_FCP_INITIATOR;
|
||||
vpid.vport_type = FC_PORTTYPE_NPIV;
|
||||
vpid.disable = false;
|
||||
|
||||
for (i = 0; i < npiv_tbl->count; i++) {
|
||||
vpid.node_name = wwn_to_u64(npiv_tbl->wwnn[i]);
|
||||
vpid.port_name = wwn_to_u64(npiv_tbl->wwpn[i]);
|
||||
scnprintf(vpid.symbolic_name, sizeof(vpid.symbolic_name),
|
||||
"NPIV[%u]:%016llx-%016llx",
|
||||
created, vpid.port_name, vpid.node_name);
|
||||
if (fc_vport_create(lport->host, 0, &vpid))
|
||||
created++;
|
||||
else
|
||||
BNX2FC_HBA_DBG(lport, "Failed to create vport\n");
|
||||
}
|
||||
done:
|
||||
return created;
|
||||
}
|
||||
|
||||
static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
|
||||
{
|
||||
struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr);
|
||||
struct bnx2fc_hba *hba;
|
||||
struct cnic_fc_npiv_tbl npiv_tbl;
|
||||
struct fc_lport *lport;
|
||||
|
||||
if (interface->enabled == false) {
|
||||
if (!ctlr->lp) {
|
||||
|
@ -2064,6 +2104,32 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
|
|||
interface->enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create static NPIV ports if any are contained in NVRAM */
|
||||
hba = interface->hba;
|
||||
lport = ctlr->lp;
|
||||
|
||||
if (!hba)
|
||||
goto done;
|
||||
|
||||
if (!hba->cnic)
|
||||
goto done;
|
||||
|
||||
if (!lport)
|
||||
goto done;
|
||||
|
||||
if (!lport->host)
|
||||
goto done;
|
||||
|
||||
if (!hba->cnic->get_fc_npiv_tbl)
|
||||
goto done;
|
||||
|
||||
memset(&npiv_tbl, 0, sizeof(npiv_tbl));
|
||||
if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl))
|
||||
goto done;
|
||||
|
||||
bnx2fc_npiv_create_vports(lport, &npiv_tbl);
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue