]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'bnx2x-cnic-bnx2fc-bd-support'
authorDavid S. Miller <davem@davemloft.net>
Fri, 7 Aug 2015 04:54:13 +0000 (21:54 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Aug 2015 04:54:13 +0000 (21:54 -0700)
Yuval Mintz says:

====================
bnx2x, cnic, bnx2fc: add support for BD

Commit 230d00eb4bfe ("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>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic_if.h
drivers/scsi/bnx2fc/bnx2fc_fcoe.c

index fa7c532012654eb05ad42fce20e92c6ab03cef32..e18a0e4d3ed17a0a7a224b60fdd03a1025e45be0 100644 (file)
@@ -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 */
index 6b2050a198df8ebd43fb29ec4176424491f29ac8..6f909077b919281bfb51661f7aecea41b7b3ed2f 100644 (file)
@@ -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;
index 08a08fa49caad3fb8850b0f92f4285c43a667835..cafd5de675cf3836bd9f1a9776c5dfc4d6d5bdbd 100644 (file)
@@ -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;
index 31c63aa2252166a4a9fb5d811735d764e8d1d082..ad73a60de333e720043fec43b43c37befbb2f945 100644 (file)
@@ -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);
index 17c145fdf3ff6f40e2ef25098e1c0b423dcf9c5f..b69dc58faeab5b74ffc3142341efea084d83706d 100644 (file)
@@ -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;
index ef6125b0ee3ed35fbd96dc0a2c5647fa0894e3b0..789e5c7e93116ab29d944e57296d511789bfedb0 100644 (file)
@@ -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
index 98d06d15195806cd915a7ccf23f19447e27854d3..d5cdc4776707b13ad67159c5e0822adf26f392b8 100644 (file)
@@ -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;
 }