[SCSI] qla2xxx: Correct QUEUE_FULL handling.
authorAndrew Vasquez <andrew.vasquez@qlogic.com>
Fri, 13 Oct 2006 16:33:39 +0000 (09:33 -0700)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Wed, 25 Oct 2006 22:13:08 +0000 (15:13 -0700)
- Drop queue-depths across all luns for a given fcport
  during TASK_SET_FULL statuses.
- Ramp-up I/Os after throttling.
- Consolidate completion-status handling of CS_QUEUE_FULL with
  CS_COMPLETE as ISP24xx firmware no longer reports
  CS_QUEUE_FULL.

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c

index bab33f6d0bdb55709b42933e093d72be7d094047..c4fc40f8e8caee98555358c2a2d1d0a9d01f4138 100644 (file)
@@ -1545,6 +1545,9 @@ typedef struct fc_port {
        spinlock_t rport_lock;
        struct fc_rport *rport, *drport;
        u32 supported_classes;
+
+       unsigned long last_queue_full;
+       unsigned long last_ramp_up;
 } fc_port_t;
 
 /*
@@ -2255,6 +2258,7 @@ typedef struct scsi_qla_host {
        uint16_t        mgmt_svr_loop_id;
 
         uint32_t       login_retry_count;
+       int             max_q_depth;
 
        /* Fibre Channel Device List. */
        struct list_head        fcports;
index ca2f660a5438e152800de94db73ed54a8a1b25c0..32ebeec45ff000bdb51e4d13d1e4e05bc692f000 100644 (file)
@@ -62,6 +62,7 @@ extern int ql2xloginretrycount;
 extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
+extern int ql2xqfullrampup;
 
 extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
index 626c7178a4341bbf2b482c74d13b6abee23c66cc..d3b6df4d55c890990f75d0239a62fd65b22213a9 100644 (file)
@@ -6,6 +6,8 @@
  */
 #include "qla_def.h"
 
+#include <scsi/scsi_tcq.h>
+
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
 static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
 static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
@@ -593,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
        }
 }
 
+static void
+qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
+{
+       fc_port_t *fcport = data;
+
+       if (fcport->ha->max_q_depth <= sdev->queue_depth)
+               return;
+
+       if (sdev->ordered_tags)
+               scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+                   sdev->queue_depth + 1);
+       else
+               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+                   sdev->queue_depth + 1);
+
+       fcport->last_ramp_up = jiffies;
+
+       DEBUG2(qla_printk(KERN_INFO, fcport->ha,
+           "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
+           fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
+           sdev->queue_depth));
+}
+
+static void
+qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
+{
+       fc_port_t *fcport = data;
+
+       if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
+               return;
+
+       DEBUG2(qla_printk(KERN_INFO, fcport->ha,
+           "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
+           fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
+           sdev->queue_depth));
+}
+
+static inline void
+qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
+{
+       fc_port_t *fcport;
+       struct scsi_device *sdev;
+
+       sdev = sp->cmd->device;
+       if (sdev->queue_depth >= ha->max_q_depth)
+               return;
+
+       fcport = sp->fcport;
+       if (time_before(jiffies,
+           fcport->last_ramp_up + ql2xqfullrampup * HZ))
+               return;
+       if (time_before(jiffies,
+           fcport->last_queue_full + ql2xqfullrampup * HZ))
+               return;
+
+       spin_unlock_irq(&ha->hardware_lock);
+       starget_for_each_device(sdev->sdev_target, fcport,
+           qla2x00_adjust_sdev_qdepth_up);
+       spin_lock_irq(&ha->hardware_lock);
+}
+
 /**
  * qla2x00_process_completed_request() - Process a Fast Post response.
  * @ha: SCSI driver HA context
@@ -624,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
 
                /* Save ISP completion status */
                sp->cmd->result = DID_OK << 16;
+
+               qla2x00_ramp_up_queue_depth(ha, sp);
                qla2x00_sp_compl(ha, sp);
        } else {
                DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
@@ -823,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
         */
        switch (comp_status) {
        case CS_COMPLETE:
+       case CS_QUEUE_FULL:
                if (scsi_status == 0) {
                        cp->result = DID_OK << 16;
                        break;
@@ -849,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                }
                cp->result = DID_OK << 16 | lscsi_status;
 
+               if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+                       DEBUG2(printk(KERN_INFO
+                           "scsi(%ld): QUEUE FULL status detected "
+                           "0x%x-0x%x.\n", ha->host_no, comp_status,
+                           scsi_status));
+
+                       /* Adjust queue depth for all luns on the port. */
+                       fcport->last_queue_full = jiffies;
+                       spin_unlock_irq(&ha->hardware_lock);
+                       starget_for_each_device(cp->device->sdev_target,
+                           fcport, qla2x00_adjust_sdev_qdepth_down);
+                       spin_lock_irq(&ha->hardware_lock);
+                       break;
+               }
                if (lscsi_status != SS_CHECK_CONDITION)
                        break;
 
@@ -1066,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                        qla2x00_mark_device_lost(ha, fcport, 1, 1);
                break;
 
-       case CS_QUEUE_FULL:
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n",
-                   ha->host_no, comp_status, scsi_status));
-
-               /* SCSI Mid-Layer handles device queue full */
-
-               cp->result = DID_OK << 16 | lscsi_status;
-
-               break;
-
        default:
                DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
                    "0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status));
index 54f561d9c7a79c49972943397157fe5029cc8b8e..208607be78c7267a5770974b8d4be12d4b839b87 100644 (file)
@@ -77,6 +77,19 @@ MODULE_PARM_DESC(ql2xfdmienable,
                "Enables FDMI registratons "
                "Default is 0 - no FDMI. 1 - perfom FDMI.");
 
+#define MAX_Q_DEPTH    32
+static int ql2xmaxqdepth = MAX_Q_DEPTH;
+module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xmaxqdepth,
+               "Maximum queue depth to report for target devices.");
+
+int ql2xqfullrampup = 120;
+module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfullrampup,
+               "Number of seconds to wait to begin to ramp-up the queue "
+               "depth for a device after a queue-full condition has been "
+               "detected.  Default is 120 seconds.");
+
 /*
  * SCSI host template entry points
  */
@@ -1104,9 +1117,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
        struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
 
        if (sdev->tagged_supported)
-               scsi_activate_tcq(sdev, 32);
+               scsi_activate_tcq(sdev, ha->max_q_depth);
        else
-               scsi_deactivate_tcq(sdev, 32);
+               scsi_deactivate_tcq(sdev, ha->max_q_depth);
 
        rport->dev_loss_tmo = ha->port_down_retry_count + 5;
 
@@ -1413,6 +1426,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
        ha->optrom_size = OPTROM_SIZE_2300;
 
+       ha->max_q_depth = MAX_Q_DEPTH;
+       if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
+               ha->max_q_depth = ql2xmaxqdepth;
+
        /* Assign ISP specific operations. */
        ha->isp_ops.pci_config          = qla2100_pci_config;
        ha->isp_ops.reset_chip          = qla2x00_reset_chip;