|
@@ -25,6 +25,7 @@
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/blkdev.h>
|
|
|
#include <linux/delay.h>
|
|
|
+#include <linux/jiffies.h>
|
|
|
|
|
|
#include <scsi/scsi.h>
|
|
|
#include <scsi/scsi_cmnd.h>
|
|
@@ -791,32 +792,48 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
|
|
|
struct scsi_device *sdev = scmd->device;
|
|
|
struct Scsi_Host *shost = sdev->host;
|
|
|
DECLARE_COMPLETION_ONSTACK(done);
|
|
|
- unsigned long timeleft;
|
|
|
+ unsigned long timeleft = timeout;
|
|
|
struct scsi_eh_save ses;
|
|
|
+ const unsigned long stall_for = msecs_to_jiffies(100);
|
|
|
int rtn;
|
|
|
|
|
|
+retry:
|
|
|
scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
|
|
|
shost->eh_action = &done;
|
|
|
|
|
|
scsi_log_send(scmd);
|
|
|
scmd->scsi_done = scsi_eh_done;
|
|
|
- shost->hostt->queuecommand(shost, scmd);
|
|
|
-
|
|
|
- timeleft = wait_for_completion_timeout(&done, timeout);
|
|
|
+ rtn = shost->hostt->queuecommand(shost, scmd);
|
|
|
+ if (rtn) {
|
|
|
+ if (timeleft > stall_for) {
|
|
|
+ scsi_eh_restore_cmnd(scmd, &ses);
|
|
|
+ timeleft -= stall_for;
|
|
|
+ msleep(jiffies_to_msecs(stall_for));
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
+ /* signal not to enter either branch of the if () below */
|
|
|
+ timeleft = 0;
|
|
|
+ rtn = NEEDS_RETRY;
|
|
|
+ } else {
|
|
|
+ timeleft = wait_for_completion_timeout(&done, timeout);
|
|
|
+ }
|
|
|
|
|
|
shost->eh_action = NULL;
|
|
|
|
|
|
- scsi_log_completion(scmd, SUCCESS);
|
|
|
+ scsi_log_completion(scmd, rtn);
|
|
|
|
|
|
SCSI_LOG_ERROR_RECOVERY(3,
|
|
|
printk("%s: scmd: %p, timeleft: %ld\n",
|
|
|
__func__, scmd, timeleft));
|
|
|
|
|
|
/*
|
|
|
- * If there is time left scsi_eh_done got called, and we will
|
|
|
- * examine the actual status codes to see whether the command
|
|
|
- * actually did complete normally, else tell the host to forget
|
|
|
- * about this command.
|
|
|
+ * If there is time left scsi_eh_done got called, and we will examine
|
|
|
+ * the actual status codes to see whether the command actually did
|
|
|
+ * complete normally, else if we have a zero return and no time left,
|
|
|
+ * the command must still be pending, so abort it and return FAILED.
|
|
|
+ * If we never actually managed to issue the command, because
|
|
|
+ * ->queuecommand() kept returning non zero, use the rtn = FAILED
|
|
|
+ * value above (so don't execute either branch of the if)
|
|
|
*/
|
|
|
if (timeleft) {
|
|
|
rtn = scsi_eh_completed_normally(scmd);
|
|
@@ -837,7 +854,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
|
|
|
rtn = FAILED;
|
|
|
break;
|
|
|
}
|
|
|
- } else {
|
|
|
+ } else if (!rtn) {
|
|
|
scsi_abort_eh_cmnd(scmd);
|
|
|
rtn = FAILED;
|
|
|
}
|