aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_transport_spi.c')
-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 303d7656f710..28966d05435c 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -22,6 +22,7 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/workqueue.h> 24#include <linux/workqueue.h>
25#include <linux/blkdev.h>
25#include <asm/semaphore.h> 26#include <asm/semaphore.h>
26#include <scsi/scsi.h> 27#include <scsi/scsi.h>
27#include "scsi_priv.h" 28#include "scsi_priv.h"
@@ -41,6 +42,11 @@
41 42
42#define SPI_MAX_ECHO_BUFFER_SIZE 4096 43#define SPI_MAX_ECHO_BUFFER_SIZE 4096
43 44
45#define DV_LOOPS 3
46#define DV_TIMEOUT (10*HZ)
47#define DV_RETRIES 3 /* should only need at most
48 * two cc/ua clears */
49
44/* Private data accessors (keep these out of the header file) */ 50/* Private data accessors (keep these out of the header file) */
45#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending) 51#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
46#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem) 52#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)
100 return result; 106 return result;
101} 107}
102 108
109/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions
110 * resulting from (likely) bus and device resets */
111static void spi_wait_req(struct scsi_request *sreq, const void *cmd,
112 void *buffer, unsigned bufflen)
113{
114 int i;
115
116 for(i = 0; i < DV_RETRIES; i++) {
117 sreq->sr_request->flags |= REQ_FAILFAST;
118
119 scsi_wait_req(sreq, cmd, buffer, bufflen,
120 DV_TIMEOUT, /* retries */ 1);
121 if (sreq->sr_result & DRIVER_SENSE) {
122 struct scsi_sense_hdr sshdr;
123
124 if (scsi_request_normalize_sense(sreq, &sshdr)
125 && sshdr.sense_key == UNIT_ATTENTION)
126 continue;
127 }
128 break;
129 }
130}
131
103static struct { 132static struct {
104 enum spi_signal_type value; 133 enum spi_signal_type value;
105 char *name; 134 char *name;
@@ -378,11 +407,6 @@ static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
378 if(i->f->set_##x) \ 407 if(i->f->set_##x) \
379 i->f->set_##x(sdev->sdev_target, y) 408 i->f->set_##x(sdev->sdev_target, y)
380 409
381#define DV_LOOPS 3
382#define DV_TIMEOUT (10*HZ)
383#define DV_RETRIES 3 /* should only need at most
384 * two cc/ua clears */
385
386enum spi_compare_returns { 410enum spi_compare_returns {
387 SPI_COMPARE_SUCCESS, 411 SPI_COMPARE_SUCCESS,
388 SPI_COMPARE_FAILURE, 412 SPI_COMPARE_FAILURE,
@@ -446,8 +470,7 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
446 for (r = 0; r < retries; r++) { 470 for (r = 0; r < retries; r++) {
447 sreq->sr_cmd_len = 0; /* wait_req to fill in */ 471 sreq->sr_cmd_len = 0; /* wait_req to fill in */
448 sreq->sr_data_direction = DMA_TO_DEVICE; 472 sreq->sr_data_direction = DMA_TO_DEVICE;
449 scsi_wait_req(sreq, spi_write_buffer, buffer, len, 473 spi_wait_req(sreq, spi_write_buffer, buffer, len);
450 DV_TIMEOUT, DV_RETRIES);
451 if(sreq->sr_result || !scsi_device_online(sdev)) { 474 if(sreq->sr_result || !scsi_device_online(sdev)) {
452 struct scsi_sense_hdr sshdr; 475 struct scsi_sense_hdr sshdr;
453 476
@@ -471,8 +494,7 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
471 memset(ptr, 0, len); 494 memset(ptr, 0, len);
472 sreq->sr_cmd_len = 0; /* wait_req to fill in */ 495 sreq->sr_cmd_len = 0; /* wait_req to fill in */
473 sreq->sr_data_direction = DMA_FROM_DEVICE; 496 sreq->sr_data_direction = DMA_FROM_DEVICE;
474 scsi_wait_req(sreq, spi_read_buffer, ptr, len, 497 spi_wait_req(sreq, spi_read_buffer, ptr, len);
475 DV_TIMEOUT, DV_RETRIES);
476 scsi_device_set_state(sdev, SDEV_QUIESCE); 498 scsi_device_set_state(sdev, SDEV_QUIESCE);
477 499
478 if (memcmp(buffer, ptr, len) != 0) 500 if (memcmp(buffer, ptr, len) != 0)
@@ -500,8 +522,7 @@ spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer,
500 522
501 memset(ptr, 0, len); 523 memset(ptr, 0, len);
502 524
503 scsi_wait_req(sreq, spi_inquiry, ptr, len, 525 spi_wait_req(sreq, spi_inquiry, ptr, len);
504 DV_TIMEOUT, DV_RETRIES);
505 526
506 if(sreq->sr_result || !scsi_device_online(sdev)) { 527 if(sreq->sr_result || !scsi_device_online(sdev)) {
507 scsi_device_set_state(sdev, SDEV_QUIESCE); 528 scsi_device_set_state(sdev, SDEV_QUIESCE);
@@ -593,8 +614,7 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
593 * (reservation conflict, device not ready, etc) just 614 * (reservation conflict, device not ready, etc) just
594 * skip the write tests */ 615 * skip the write tests */
595 for (l = 0; ; l++) { 616 for (l = 0; ; l++) {
596 scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0, 617 spi_wait_req(sreq, spi_test_unit_ready, NULL, 0);
597 DV_TIMEOUT, DV_RETRIES);
598 618
599 if(sreq->sr_result) { 619 if(sreq->sr_result) {
600 if(l >= 3) 620 if(l >= 3)
@@ -608,8 +628,7 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
608 sreq->sr_cmd_len = 0; 628 sreq->sr_cmd_len = 0;
609 sreq->sr_data_direction = DMA_FROM_DEVICE; 629 sreq->sr_data_direction = DMA_FROM_DEVICE;
610 630
611 scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4, 631 spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4);
612 DV_TIMEOUT, DV_RETRIES);
613 632
614 if (sreq->sr_result) 633 if (sreq->sr_result)
615 /* Device has no echo buffer */ 634 /* Device has no echo buffer */