aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2005-05-01 18:58:15 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2005-05-05 16:08:59 -0500
commit949bf797595fc99d4cadf9a294fe6fd32a4474e6 (patch)
tree0c91a5d3822785a5608db8a4970f40ea857a9e7b
parent69b528936b702d4c13ffa0d14215a029dc754e50 (diff)
downloadkernel_samsung_aries-949bf797595fc99d4cadf9a294fe6fd32a4474e6.zip
kernel_samsung_aries-949bf797595fc99d4cadf9a294fe6fd32a4474e6.tar.gz
kernel_samsung_aries-949bf797595fc99d4cadf9a294fe6fd32a4474e6.tar.bz2
[SCSI] fix command retries in spi_transport class
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>
-rw-r--r--drivers/scsi/scsi_transport_spi.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 303d765..28966d0 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -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"
@@ -41,6 +42,11 @@
#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 */