[SCSI] qla2xxx: Ramp down queue depth for attached SCSI devices when driver resources...
authorChad Dupuis <chad.dupuis@qlogic.com>
Wed, 30 Jan 2013 08:34:38 +0000 (03:34 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 22 Feb 2013 11:29:49 +0000 (11:29 +0000)
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@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_gbl.h
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c

index 2f3e7655db0d8e122598166aa955e9eb48349b5f..f7cdd259ef0b947018cb2b59e1bc9817c44be1a8 100644 (file)
@@ -17,7 +17,7 @@
  * |                              |                    | 0x113a         |
  * | Device Discovery             |       0x2087       | 0x2020-0x2022, |
  * |                              |                    | 0x2016         |
- * | Queue Command and IO tracing |       0x3030       | 0x3006-0x300b  |
+ * | Queue Command and IO tracing |       0x3031       | 0x3006-0x300b  |
  * |                              |                    | 0x3027-0x3028  |
  * |                              |                    | 0x302d-0x302e  |
  * | DPC Thread                   |       0x401d       | 0x4002,0x4013  |
index a84bb8d6ff74c28e4639e7348b13f155862723ae..06c6271d5911fd7d6882474a795e0f6f6cf56e23 100644 (file)
@@ -2536,6 +2536,7 @@ struct req_que {
        srb_t **outstanding_cmds;
        uint32_t current_outstanding_cmd;
        uint16_t num_outstanding_cmds;
+#define        MAX_Q_DEPTH             32
        int max_q_depth;
 };
 
@@ -3058,6 +3059,12 @@ struct qla_hw_data {
        struct work_struct idc_state_handler;
        struct work_struct nic_core_unrecoverable;
 
+#define HOST_QUEUE_RAMPDOWN_INTERVAL           (60 * HZ)
+#define HOST_QUEUE_RAMPUP_INTERVAL             (30 * HZ)
+       unsigned long   host_last_rampdown_time;
+       unsigned long   host_last_rampup_time;
+       int             cfg_lun_q_depth;
+
        struct qlt_hw_data tgt;
 };
 
@@ -3117,6 +3124,8 @@ typedef struct scsi_qla_host {
 #define MPI_RESET_NEEDED       19      /* Initiate MPI FW reset */
 #define ISP_QUIESCE_NEEDED     20      /* Driver need some quiescence */
 #define SCR_PENDING            21      /* SCR in target mode */
+#define HOST_RAMP_DOWN_QUEUE_DEPTH     22
+#define HOST_RAMP_UP_QUEUE_DEPTH       23
 
        uint32_t        device_flags;
 #define SWITCH_FOUND           BIT_0
index fba0651f678e8fd055bda540244904d461f41426..1732713e80cc0ec37762c08abb473a62878f1879 100644 (file)
@@ -97,6 +97,7 @@ extern int qlport_down_retry;
 extern int ql2xplogiabsentdevice;
 extern int ql2xloginretrycount;
 extern int ql2xfdmienable;
+extern int ql2xmaxqdepth;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xiidmaenable;
index c0462c04c885de1d8cf3008d7c6200e04ad11028..deb8618d1b8124b1e50900cb4f4dc6c303f6bcd0 100644 (file)
@@ -213,3 +213,22 @@ qla2x00_gid_list_size(struct qla_hw_data *ha)
 {
        return sizeof(struct gid_list_info) * ha->max_fibre_devices;
 }
+
+static inline void
+qla2x00_do_host_ramp_up(scsi_qla_host_t *vha)
+{
+       if (vha->hw->cfg_lun_q_depth >= ql2xmaxqdepth)
+               return;
+
+       /* Wait at least HOST_QUEUE_RAMPDOWN_INTERVAL before ramping up */
+       if (time_before(jiffies, (vha->hw->host_last_rampdown_time +
+           HOST_QUEUE_RAMPDOWN_INTERVAL)))
+               return;
+
+       /* Wait at least HOST_QUEUE_RAMPUP_INTERVAL between each ramp up */
+       if (time_before(jiffies, (vha->hw->host_last_rampup_time +
+           HOST_QUEUE_RAMPUP_INTERVAL)))
+               return;
+
+       set_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags);
+}
index 45130738c2bfd89e3ee0c91efa0cfa1538b53644..1b192c8bb133102a6612ec16ef2d615a6e2ba32f 100644 (file)
@@ -1934,6 +1934,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
        /* Fast path completion. */
        if (comp_status == CS_COMPLETE && scsi_status == 0) {
+               qla2x00_do_host_ramp_up(vha);
                qla2x00_process_completed_request(vha, req, handle);
 
                return;
@@ -2193,6 +2194,9 @@ out:
                    cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len,
                    resid_len, fw_resid_len);
 
+       if (!res)
+               qla2x00_do_host_ramp_up(vha);
+
        if (rsp->status_srb == NULL)
                sp->done(ha, sp, res);
 }
index 53efffce13a2c0f71f82cb293715e6d7a01c9fbe..da86d3828c1d985d8bec11b2303781a08c10ad68 100644 (file)
@@ -111,8 +111,7 @@ MODULE_PARM_DESC(ql2xfdmienable,
                "Enables FDMI registrations. "
                "0 - no FDMI. Default is 1 - perform FDMI.");
 
-#define MAX_Q_DEPTH    32
-static int ql2xmaxqdepth = MAX_Q_DEPTH;
+int ql2xmaxqdepth = MAX_Q_DEPTH;
 module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xmaxqdepth,
                "Maximum queue depth to set for each LUN. "
@@ -720,8 +719,10 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        }
 
        sp = qla2x00_get_sp(base_vha, fcport, GFP_ATOMIC);
-       if (!sp)
+       if (!sp) {
+               set_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags);
                goto qc24_host_busy;
+       }
 
        sp->u.scmd.cmd = cmd;
        sp->type = SRB_SCSI_CMD;
@@ -734,6 +735,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        if (rval != QLA_SUCCESS) {
                ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3013,
                    "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
+               set_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags);
                goto qc24_host_busy_free_sp;
        }
 
@@ -1458,6 +1460,81 @@ qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
        return tag_type;
 }
 
+static void
+qla2x00_host_ramp_down_queuedepth(scsi_qla_host_t *vha)
+{
+       scsi_qla_host_t *vp;
+       struct Scsi_Host *shost;
+       struct scsi_device *sdev;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+
+       ha->host_last_rampdown_time = jiffies;
+
+       if (ha->cfg_lun_q_depth <= vha->host->cmd_per_lun)
+               return;
+
+       if ((ha->cfg_lun_q_depth / 2) < vha->host->cmd_per_lun)
+               ha->cfg_lun_q_depth = vha->host->cmd_per_lun;
+       else
+               ha->cfg_lun_q_depth = ha->cfg_lun_q_depth / 2;
+
+       /*
+        * Geometrically ramp down the queue depth for all devices on this
+        * adapter
+        */
+       spin_lock_irqsave(&ha->vport_slock, flags);
+       list_for_each_entry(vp, &ha->vp_list, list) {
+               shost = vp->host;
+               shost_for_each_device(sdev, shost) {
+                       if (sdev->queue_depth > shost->cmd_per_lun) {
+                               if (sdev->queue_depth < ha->cfg_lun_q_depth)
+                                       continue;
+                               ql_log(ql_log_warn, vp, 0x3031,
+                                   "%ld:%d:%d: Ramping down queue depth to %d",
+                                   vp->host_no, sdev->id, sdev->lun,
+                                   ha->cfg_lun_q_depth);
+                               qla2x00_change_queue_depth(sdev,
+                                   ha->cfg_lun_q_depth, SCSI_QDEPTH_DEFAULT);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+       return;
+}
+
+static void
+qla2x00_host_ramp_up_queuedepth(scsi_qla_host_t *vha)
+{
+       scsi_qla_host_t *vp;
+       struct Scsi_Host *shost;
+       struct scsi_device *sdev;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+
+       ha->host_last_rampup_time = jiffies;
+       ha->cfg_lun_q_depth++;
+
+       /*
+        * Linearly ramp up the queue depth for all devices on this
+        * adapter
+        */
+       spin_lock_irqsave(&ha->vport_slock, flags);
+       list_for_each_entry(vp, &ha->vp_list, list) {
+               shost = vp->host;
+               shost_for_each_device(sdev, shost) {
+                       if (sdev->queue_depth > ha->cfg_lun_q_depth)
+                               continue;
+                       qla2x00_change_queue_depth(sdev, ha->cfg_lun_q_depth,
+                           SCSI_QDEPTH_RAMP_UP);
+               }
+       }
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+       return;
+}
+
 /**
  * qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
  * @ha: HA context
@@ -2235,6 +2312,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->init_cb_size = sizeof(init_cb_t);
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
        ha->optrom_size = OPTROM_SIZE_2300;
+       ha->cfg_lun_q_depth = ql2xmaxqdepth;
 
        /* Assign ISP specific operations. */
        if (IS_QLA2100(ha)) {
@@ -4610,6 +4688,18 @@ qla2x00_do_dpc(void *data)
                        qla2xxx_flash_npiv_conf(base_vha);
                }
 
+               if (test_and_clear_bit(HOST_RAMP_DOWN_QUEUE_DEPTH,
+                   &base_vha->dpc_flags)) {
+                       /* Prevents simultaneous ramp up and down */
+                       clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
+                           &base_vha->dpc_flags);
+                       qla2x00_host_ramp_down_queuedepth(base_vha);
+               }
+
+               if (test_and_clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
+                   &base_vha->dpc_flags))
+                       qla2x00_host_ramp_up_queuedepth(base_vha);
+
                if (!ha->interrupts_on)
                        ha->isp_ops->enable_intrs(ha);
 
@@ -4807,7 +4897,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
            test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
            test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
            test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
-           test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) {
+           test_bit(RELOGIN_NEEDED, &vha->dpc_flags) ||
+           test_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags) ||
+           test_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags))) {
                ql_dbg(ql_dbg_timer, vha, 0x600b,
                    "isp_abort_needed=%d loop_resync_needed=%d "
                    "fcport_update_needed=%d start_dpc=%d "
@@ -4820,12 +4912,15 @@ qla2x00_timer(scsi_qla_host_t *vha)
                ql_dbg(ql_dbg_timer, vha, 0x600c,
                    "beacon_blink_needed=%d isp_unrecoverable=%d "
                    "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d "
-                   "relogin_needed=%d.\n",
+                   "relogin_needed=%d, host_ramp_down_needed=%d "
+                   "host_ramp_up_needed=%d.\n",
                    test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags),
                    test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags),
                    test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags),
                    test_bit(VP_DPC_NEEDED, &vha->dpc_flags),
-                   test_bit(RELOGIN_NEEDED, &vha->dpc_flags));
+                   test_bit(RELOGIN_NEEDED, &vha->dpc_flags),
+                   test_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags),
+                   test_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags));
                qla2xxx_wake_dpc(vha);
        }