Skip to content

Commit

Permalink
[SCSI] fix command retries in spi_transport class
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
James Bottomley authored and James Bottomley committed May 5, 2005
1 parent 69b5289 commit 949bf79
Showing 1 changed file with 34 additions and 15 deletions.
49 changes: 34 additions & 15 deletions drivers/scsi/scsi_transport_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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 */
Expand Down

0 comments on commit 949bf79

Please sign in to comment.