diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-08-05 22:45:40 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-08-08 10:55:39 -0400 |
commit | b21a41385118f9a6af3cd96ce71090c5ada52eb5 (patch) | |
tree | 4eb9124ae72e1a905094c259465718793698e603 /drivers | |
parent | f03a567054fea4f9d43c50ec91338266c0bd588d (diff) |
[SCSI] add global timeout to the scsi mid-layer
There are certain rogue devices (and the aic7xxx driver) that return
BUSY or QUEUE_FULL forever. This code will apply a global timeout (of
the total number of retries times the per command timer) to a given
command. If it is exceeded, the command is completed regardless of its
state.
The patch also removes the unused field in the command: timeout and
timeout_total.
This solves the problem of detecting an endless loop in the mid-layer
because of BUSY/QUEUE_FULL bouncing, but will not recover the device.
In the aic7xxx case, the driver can be recovered by sending a bus reset,
so possibly this should be tied into the error handler?
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/advansys.c | 4 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 15 |
2 files changed, 17 insertions, 2 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 0fb93363eb22..37ec5411e325 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -9200,8 +9200,8 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s) | |||
9200 | (unsigned) s->serial_number, s->retries, s->allowed); | 9200 | (unsigned) s->serial_number, s->retries, s->allowed); |
9201 | 9201 | ||
9202 | printk( | 9202 | printk( |
9203 | " timeout_per_command %d, timeout_total %d, timeout %d\n", | 9203 | " timeout_per_command %d\n", |
9204 | s->timeout_per_command, s->timeout_total, s->timeout); | 9204 | s->timeout_per_command); |
9205 | 9205 | ||
9206 | printk( | 9206 | printk( |
9207 | " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", | 9207 | " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", |
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d1aa95d45a70..4befbc275f94 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -268,6 +268,7 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) | |||
268 | } else | 268 | } else |
269 | put_device(&dev->sdev_gendev); | 269 | put_device(&dev->sdev_gendev); |
270 | 270 | ||
271 | cmd->jiffies_at_alloc = jiffies; | ||
271 | return cmd; | 272 | return cmd; |
272 | } | 273 | } |
273 | EXPORT_SYMBOL(scsi_get_command); | 274 | EXPORT_SYMBOL(scsi_get_command); |
@@ -798,9 +799,23 @@ static void scsi_softirq(struct softirq_action *h) | |||
798 | while (!list_empty(&local_q)) { | 799 | while (!list_empty(&local_q)) { |
799 | struct scsi_cmnd *cmd = list_entry(local_q.next, | 800 | struct scsi_cmnd *cmd = list_entry(local_q.next, |
800 | struct scsi_cmnd, eh_entry); | 801 | struct scsi_cmnd, eh_entry); |
802 | /* The longest time any command should be outstanding is the | ||
803 | * per command timeout multiplied by the number of retries. | ||
804 | * | ||
805 | * For a typical command, this is 2.5 minutes */ | ||
806 | unsigned long wait_for | ||
807 | = cmd->allowed * cmd->timeout_per_command; | ||
801 | list_del_init(&cmd->eh_entry); | 808 | list_del_init(&cmd->eh_entry); |
802 | 809 | ||
803 | disposition = scsi_decide_disposition(cmd); | 810 | disposition = scsi_decide_disposition(cmd); |
811 | if (disposition != SUCCESS && | ||
812 | time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { | ||
813 | dev_printk(KERN_ERR, &cmd->device->sdev_gendev, | ||
814 | "timing out command, waited %ds\n", | ||
815 | wait_for/HZ); | ||
816 | disposition = SUCCESS; | ||
817 | } | ||
818 | |||
804 | scsi_log_completion(cmd, disposition); | 819 | scsi_log_completion(cmd, disposition); |
805 | switch (disposition) { | 820 | switch (disposition) { |
806 | case SUCCESS: | 821 | case SUCCESS: |