[SCSI] fix command retries in spi_transport class
authorJames Bottomley <James.Bottomley@steeleye.com>
Sun, 1 May 2005 23:58:15 +0000 (18:58 -0500)
committerJames Bottomley <jejb@mulgrave.(none)>
Thu, 5 May 2005 21:08:59 +0000 (16:08 -0500)
The premise is that domain validation is likely to trigger errors which
it wants to know about, so the only time it should be retrying them is
when it gets a unit attention (likely as the result of a previous bus or
device reset).  Ironically, the previous coding retried three times in
all cases except those of unit attention.  The attached fixes this to do
the right thing.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/scsi_transport_spi.c

index 303d7656f71021fa592ab0924212a03361f9a445..28966d05435cf6506c214ab56b8b92050ab85c81 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/workqueue.h>
+#include <linux/blkdev.h>
 #include <asm/semaphore.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 
 #define SPI_MAX_ECHO_BUFFER_SIZE       4096
 
+#define DV_LOOPS       3
+#define DV_TIMEOUT     (10*HZ)
+#define DV_RETRIES     3       /* should only need at most 
+                                * two cc/ua clears */
+
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
 #define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
@@ -100,6 +106,29 @@ static int sprint_frac(char *dest, int value, int denom)
        return result;
 }
 
+/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions
+ * resulting from (likely) bus and device resets */
+static void spi_wait_req(struct scsi_request *sreq, const void *cmd,
+                        void *buffer, unsigned bufflen)
+{
+       int i;
+
+       for(i = 0; i < DV_RETRIES; i++) {
+               sreq->sr_request->flags |= REQ_FAILFAST;
+
+               scsi_wait_req(sreq, cmd, buffer, bufflen,
+                             DV_TIMEOUT, /* retries */ 1);
+               if (sreq->sr_result & DRIVER_SENSE) {
+                       struct scsi_sense_hdr sshdr;
+
+                       if (scsi_request_normalize_sense(sreq, &sshdr)
+                           && sshdr.sense_key == UNIT_ATTENTION)
+                               continue;
+               }
+               break;
+       }
+}
+
 static struct {
        enum spi_signal_type    value;
        char                    *name;
@@ -378,11 +407,6 @@ static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
        if(i->f->set_##x)               \
                i->f->set_##x(sdev->sdev_target, y)
 
-#define DV_LOOPS       3
-#define DV_TIMEOUT     (10*HZ)
-#define DV_RETRIES     3       /* should only need at most 
-                                * two cc/ua clears */
-
 enum spi_compare_returns {
        SPI_COMPARE_SUCCESS,
        SPI_COMPARE_FAILURE,
@@ -446,8 +470,7 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
        for (r = 0; r < retries; r++) {
                sreq->sr_cmd_len = 0;   /* wait_req to fill in */
                sreq->sr_data_direction = DMA_TO_DEVICE;
-               scsi_wait_req(sreq, spi_write_buffer, buffer, len,
-                             DV_TIMEOUT, DV_RETRIES);
+               spi_wait_req(sreq, spi_write_buffer, buffer, len);
                if(sreq->sr_result || !scsi_device_online(sdev)) {
                        struct scsi_sense_hdr sshdr;
 
@@ -471,8 +494,7 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
                memset(ptr, 0, len);
                sreq->sr_cmd_len = 0;   /* wait_req to fill in */
                sreq->sr_data_direction = DMA_FROM_DEVICE;
-               scsi_wait_req(sreq, spi_read_buffer, ptr, len,
-                             DV_TIMEOUT, DV_RETRIES);
+               spi_wait_req(sreq, spi_read_buffer, ptr, len);
                scsi_device_set_state(sdev, SDEV_QUIESCE);
 
                if (memcmp(buffer, ptr, len) != 0)
@@ -500,8 +522,7 @@ spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer,
 
                memset(ptr, 0, len);
 
-               scsi_wait_req(sreq, spi_inquiry, ptr, len,
-                             DV_TIMEOUT, DV_RETRIES);
+               spi_wait_req(sreq, spi_inquiry, ptr, len);
                
                if(sreq->sr_result || !scsi_device_online(sdev)) {
                        scsi_device_set_state(sdev, SDEV_QUIESCE);
@@ -593,8 +614,7 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
         * (reservation conflict, device not ready, etc) just
         * skip the write tests */
        for (l = 0; ; l++) {
-               scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0,
-                             DV_TIMEOUT, DV_RETRIES);
+               spi_wait_req(sreq, spi_test_unit_ready, NULL, 0);
 
                if(sreq->sr_result) {
                        if(l >= 3)
@@ -608,8 +628,7 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
        sreq->sr_cmd_len = 0;
        sreq->sr_data_direction = DMA_FROM_DEVICE;
 
-       scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4,
-                     DV_TIMEOUT, DV_RETRIES);
+       spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4);
 
        if (sreq->sr_result)
                /* Device has no echo buffer */