qla2xxx: Honor FCP_RSP retry delay timer field.
authorChad Dupuis <chad.dupuis@qlogic.com>
Thu, 25 Sep 2014 09:16:59 +0000 (05:16 -0400)
committerChristoph Hellwig <hch@lst.de>
Thu, 25 Sep 2014 12:25:04 +0000 (14:25 +0200)
Parse the retry delay timer field from the FCP response data and if:

- It is not zero
- The SCSI status is busy or queue full

return SCSI_MLQUEUE_TARGET_BUSY for the number of milliseconds specified
in the retry delay timer field.

Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c

index d9daad7db6cef79ab31f9a4de95ca6510c729065..d529510bbc6cc4b6612dbb514ad5adc6207aaee5 100644 (file)
@@ -2023,6 +2023,8 @@ typedef struct fc_port {
        unsigned long last_ramp_up;
 
        uint16_t port_id;
+
+       unsigned long retry_delay_timestamp;
 } fc_port_t;
 
 #include "qla_mr.h"
index 7f2e1c71cc3174b728eec878226d40b7819d7af8..42bb357bf56b1dcd7d4e0391c1a39cfa2a164197 100644 (file)
@@ -567,7 +567,7 @@ struct sts_entry_24xx {
 #define SF_TRANSFERRED_DATA    BIT_11
 #define SF_FCP_RSP_DMA         BIT_0
 
-       uint16_t reserved_2;
+       uint16_t retry_delay;
        uint16_t scsi_status;           /* SCSI status. */
 #define SS_CONFIRMATION_REQ            BIT_12
 
index b3b1d6fc2d6cb0e2bbe5d2272e5508d09b303212..fee9eb7c8a60090b9f779ade26f1d17d751625cc 100644 (file)
@@ -279,3 +279,11 @@ qla2x00_handle_mbx_completion(struct qla_hw_data *ha, int status)
                complete(&ha->mbx_intr_comp);
        }
 }
+
+static inline void
+qla2x00_set_retry_delay_timestamp(fc_port_t *fcport, uint16_t retry_delay)
+{
+       if (retry_delay)
+               fcport->retry_delay_timestamp = jiffies +
+                   (retry_delay * HZ / 10);
+}
index 550ffdf0bf17d5493297e3d39f729aaf0950eecb..f15f87e1abd837f8186aa95a2e03fcd4269bbf81 100644 (file)
@@ -1983,6 +1983,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        int logit = 1;
        int res = 0;
        uint16_t state_flags = 0;
+       uint16_t retry_delay = 0;
 
        sts = (sts_entry_t *) pkt;
        sts24 = (struct sts_entry_24xx *) pkt;
@@ -2076,6 +2077,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                host_to_fcp_swap(sts24->data, sizeof(sts24->data));
                ox_id = le16_to_cpu(sts24->ox_id);
                par_sense_len = sizeof(sts24->data);
+               /* Valid values of the retry delay timer are 0x1-0xffef */
+               if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1)
+                       retry_delay = sts24->retry_delay;
        } else {
                if (scsi_status & SS_SENSE_LEN_VALID)
                        sense_len = le16_to_cpu(sts->req_sense_length);
@@ -2109,6 +2113,14 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
            scsi_status & SS_RESIDUAL_OVER)
                comp_status = CS_DATA_OVERRUN;
 
+       /*
+        * Check retry_delay_timer value if we receive a busy or
+        * queue full.
+        */
+       if (lscsi_status == SAM_STAT_TASK_SET_FULL ||
+           lscsi_status == SAM_STAT_BUSY)
+               qla2x00_set_retry_delay_timestamp(fcport, retry_delay);
+
        /*
         * Based on Host and scsi status generate status code for Linux
         */
index e742890d5d1b6cecff1dc0c97a0f8c4945430d24..daabf8c9c298d8076a66ef3ce90ab6ff83a1fc3d 100644 (file)
@@ -731,6 +731,15 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                goto qc24_target_busy;
        }
 
+       /*
+        * Return target busy if we've received a non-zero retry_delay_timer
+        * in a FCP_RSP.
+        */
+       if (time_after(jiffies, fcport->retry_delay_timestamp))
+               fcport->retry_delay_timestamp = 0;
+       else
+               goto qc24_target_busy;
+
        sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
        if (!sp)
                goto qc24_host_busy;