[SCSI] qla2xxx: Use bitmap to store loop_id's for fcports.
authorChad Dupuis <chad.dupuis@qlogic.com>
Wed, 22 Aug 2012 18:21:00 +0000 (14:21 -0400)
committerJames Bottomley <JBottomley@Parallels.com>
Mon, 24 Sep 2012 08:03:36 +0000 (12:03 +0400)
Store used fcport loop_id's in a bitmap so that as opposed to looping through
all fcports to find the next free loop_id, new loop_id lookup can be just be
done via bitops.

[jejb: plus fix for incorrect LOOPID_MAP_SIZE from Andrew Vasquez]
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_os.c

index d651179899fa250108b28f0d7afd818c5d13b938..0c4fd2cebc176661bef28ee649d8c7f6eb41c71c 100644 (file)
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes     |
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x0122       | 0x4b,0xba,0xfa |
+ * | Module Init and Probe        |       0x0123       | 0x4b,0xba,0xfa |
  * | Mailbox commands             |       0x1140       | 0x111a-0x111b  |
  * |                              |                    | 0x112c-0x112e  |
  * |                              |                    | 0x113a         |
index 39007f53aec0284b9cd855592d786823bbad5786..28c0b357561624d114a9bdb7a85414c1d6321070 100644 (file)
 #define MAX_FIBRE_DEVICES_2400 2048
 #define MAX_FIBRE_DEVICES_LOOP 128
 #define MAX_FIBRE_DEVICES_MAX  MAX_FIBRE_DEVICES_2400
+#define LOOPID_MAP_SIZE                (ha->max_fibre_devices)
 #define MAX_FIBRE_LUNS         0xFFFF
 #define        MAX_HOST_COUNT          16
 
@@ -2918,6 +2919,7 @@ struct qla_hw_data {
        void            *md_dump;
        uint32_t        md_dump_size;
 
+       void            *loop_id_map;
        struct qlt_hw_data tgt;
 };
 
index a44653b421612dcb35a302cc74a2ef64b689dd1a..290052352619e432cb400d115d7d2191f7959914 100644 (file)
@@ -3285,7 +3285,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                         */
                        if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
                                fcport->d_id.b24 = new_fcport->d_id.b24;
-                               fcport->loop_id = FC_NO_LOOP_ID;
+                               qla2x00_clear_loop_id(fcport);
                                fcport->flags |= (FCF_FABRIC_DEVICE |
                                    FCF_LOGIN_NEEDED);
                                break;
@@ -3306,7 +3306,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                                ha->isp_ops->fabric_logout(vha, fcport->loop_id,
                                    fcport->d_id.b.domain, fcport->d_id.b.area,
                                    fcport->d_id.b.al_pa);
-                               fcport->loop_id = FC_NO_LOOP_ID;
+                               qla2x00_clear_loop_id(fcport);
                        }
 
                        break;
@@ -3352,71 +3352,32 @@ int
 qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
 {
        int     rval;
-       int     found;
-       fc_port_t *fcport;
-       uint16_t first_loop_id;
        struct qla_hw_data *ha = vha->hw;
-       struct scsi_qla_host *vp;
-       struct scsi_qla_host *tvp;
        unsigned long flags = 0;
 
        rval = QLA_SUCCESS;
 
-       /* Save starting loop ID. */
-       first_loop_id = dev->loop_id;
-
-       for (;;) {
-               /* Skip loop ID if already used by adapter. */
-               if (dev->loop_id == vha->loop_id)
-                       dev->loop_id++;
-
-               /* Skip reserved loop IDs. */
-               while (qla2x00_is_reserved_id(vha, dev->loop_id))
-                       dev->loop_id++;
-
-               /* Reset loop ID if passed the end. */
-               if (dev->loop_id > ha->max_loop_id) {
-                       /* first loop ID. */
-                       dev->loop_id = ha->min_external_loopid;
-               }
-
-               /* Check for loop ID being already in use. */
-               found = 0;
-               fcport = NULL;
-
-               spin_lock_irqsave(&ha->vport_slock, flags);
-               list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
-                       list_for_each_entry(fcport, &vp->vp_fcports, list) {
-                               if (fcport->loop_id == dev->loop_id &&
-                                                               fcport != dev) {
-                                       /* ID possibly in use */
-                                       found++;
-                                       break;
-                               }
-                       }
-                       if (found)
-                               break;
-               }
-               spin_unlock_irqrestore(&ha->vport_slock, flags);
+       spin_lock_irqsave(&ha->vport_slock, flags);
 
-               /* If not in use then it is free to use. */
-               if (!found) {
-                       ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
-                           "Assigning new loopid=%x, portid=%x.\n",
-                           dev->loop_id, dev->d_id.b24);
-                       break;
-               }
+       dev->loop_id = find_first_zero_bit(ha->loop_id_map,
+           LOOPID_MAP_SIZE);
+       if (dev->loop_id >= LOOPID_MAP_SIZE ||
+           qla2x00_is_reserved_id(vha, dev->loop_id)) {
+               dev->loop_id = FC_NO_LOOP_ID;
+               rval = QLA_FUNCTION_FAILED;
+       } else
+               set_bit(dev->loop_id, ha->loop_id_map);
 
-               /* ID in use. Try next value. */
-               dev->loop_id++;
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
 
-               /* If wrap around. No free ID to use. */
-               if (dev->loop_id == first_loop_id) {
-                       dev->loop_id = FC_NO_LOOP_ID;
-                       rval = QLA_FUNCTION_FAILED;
-                       break;
-               }
-       }
+       if (rval == QLA_SUCCESS)
+               ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
+                   "Assigning new loopid=%x, portid=%x.\n",
+                   dev->loop_id, dev->d_id.b24);
+       else
+               ql_log(ql_log_warn, dev->vha, 0x2087,
+                   "No loop_id's available, portid=%x.\n",
+                   dev->d_id.b24);
 
        return (rval);
 }
@@ -3616,7 +3577,7 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
                        ha->isp_ops->fabric_logout(vha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
-                       fcport->loop_id = FC_NO_LOOP_ID;
+                       qla2x00_clear_loop_id(fcport);
                        fcport->login_retry = 0;
 
                        rval = 3;
index 6e457643c63909f51741b68f86bce197c4d9c81d..c12add2617123fdbca10ffff4e541117d3b48a4d 100644 (file)
@@ -57,6 +57,20 @@ host_to_fcp_swap(uint8_t *fcp, uint32_t bsize)
        return fcp;
 }
 
+static inline void
+qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
+{
+       int i;
+
+       if (IS_FWI2_CAPABLE(ha))
+               return;
+
+       for (i = 0; i < SNS_FIRST_LOOP_ID; i++)
+               set_bit(i, ha->loop_id_map);
+       set_bit(MANAGEMENT_SERVER, ha->loop_id_map);
+       set_bit(BROADCAST, ha->loop_id_map);
+}
+
 static inline int
 qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
 {
@@ -68,6 +82,18 @@ qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
            loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);
 }
 
+static inline void
+qla2x00_clear_loop_id(fc_port_t *fcport) {
+       struct qla_hw_data *ha = fcport->vha->hw;
+
+       if (fcport->loop_id == FC_NO_LOOP_ID ||
+           qla2x00_is_reserved_id(fcport->vha, fcport->loop_id))
+               return;
+
+       clear_bit(fcport->loop_id, ha->loop_id_map);
+       fcport->loop_id = FC_NO_LOOP_ID;
+}
+
 static inline void
 qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp)
 {
index caa4ce417681dc4e0b0f5c1807e9d63529cd3f36..5f990291c2594c20d6555d9c8cb6e3005137f048 100644 (file)
@@ -2872,6 +2872,7 @@ void qla2x00_free_fcports(struct scsi_qla_host *vha)
 
        list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
                list_del(&fcport->list);
+               qla2x00_clear_loop_id(fcport);
                kfree(fcport);
                fcport = NULL;
        }
@@ -3169,6 +3170,18 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
        }
 
        INIT_LIST_HEAD(&ha->vp_list);
+
+       /* Allocate memory for our loop_id bitmap */
+       ha->loop_id_map = kzalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE) * sizeof(long),
+           GFP_KERNEL);
+       if (!ha->loop_id_map)
+               goto fail_async_pd;
+       else {
+               qla2x00_set_reserved_loop_ids(ha);
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123,
+                   "loop_id_map=%p. \n", ha->loop_id_map);
+       }
+
        return 1;
 
 fail_async_pd:
@@ -3352,6 +3365,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        kfree(ha->nvram);
        kfree(ha->npiv_info);
        kfree(ha->swl);
+       kfree(ha->loop_id_map);
 
        ha->srb_mempool = NULL;
        ha->ctx_mempool = NULL;
@@ -3687,7 +3701,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
                        }
 
                        if (fcport->login_retry == 0 && status != QLA_SUCCESS)
-                               fcport->loop_id = FC_NO_LOOP_ID;
+                               qla2x00_clear_loop_id(fcport);
                }
                if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
                        break;