[SCSI] Handle MLQUEUE busy response in scsi_send_eh_cmnd
scsi_send_eh_cmnd() is calling queuecommand() directly, so it needs to check the return value here. The only valid return codes for queuecommand() are 'busy' states, so we need to wait for a bit to allow the LLDD to recover. Based on an earlier patch from Wen Xiong. [jejb: fix confusion between msec and jiffies values and other issues] [bvanassche: correct stall_for interval] Cc: Wen Xiong <wenxiong@linux.vnet.ibm.com> Cc: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <JBottomley@Parallels.com>hifive-unleashed-5.1
parent
d522844a31
commit
fc73648a50
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/scsi_cmnd.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_device *sdev = scmd->device;
|
||||||
struct Scsi_Host *shost = sdev->host;
|
struct Scsi_Host *shost = sdev->host;
|
||||||
DECLARE_COMPLETION_ONSTACK(done);
|
DECLARE_COMPLETION_ONSTACK(done);
|
||||||
unsigned long timeleft;
|
unsigned long timeleft = timeout;
|
||||||
struct scsi_eh_save ses;
|
struct scsi_eh_save ses;
|
||||||
|
const unsigned long stall_for = msecs_to_jiffies(100);
|
||||||
int rtn;
|
int rtn;
|
||||||
|
|
||||||
|
retry:
|
||||||
scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
|
scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
|
||||||
shost->eh_action = &done;
|
shost->eh_action = &done;
|
||||||
|
|
||||||
scsi_log_send(scmd);
|
scsi_log_send(scmd);
|
||||||
scmd->scsi_done = scsi_eh_done;
|
scmd->scsi_done = scsi_eh_done;
|
||||||
shost->hostt->queuecommand(shost, scmd);
|
rtn = shost->hostt->queuecommand(shost, scmd);
|
||||||
|
if (rtn) {
|
||||||
timeleft = wait_for_completion_timeout(&done, timeout);
|
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;
|
shost->eh_action = NULL;
|
||||||
|
|
||||||
scsi_log_completion(scmd, SUCCESS);
|
scsi_log_completion(scmd, rtn);
|
||||||
|
|
||||||
SCSI_LOG_ERROR_RECOVERY(3,
|
SCSI_LOG_ERROR_RECOVERY(3,
|
||||||
printk("%s: scmd: %p, timeleft: %ld\n",
|
printk("%s: scmd: %p, timeleft: %ld\n",
|
||||||
__func__, scmd, timeleft));
|
__func__, scmd, timeleft));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is time left scsi_eh_done got called, and we will
|
* If there is time left scsi_eh_done got called, and we will examine
|
||||||
* examine the actual status codes to see whether the command
|
* the actual status codes to see whether the command actually did
|
||||||
* actually did complete normally, else tell the host to forget
|
* complete normally, else if we have a zero return and no time left,
|
||||||
* about this command.
|
* 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) {
|
if (timeleft) {
|
||||||
rtn = scsi_eh_completed_normally(scmd);
|
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;
|
rtn = FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!rtn) {
|
||||||
scsi_abort_eh_cmnd(scmd);
|
scsi_abort_eh_cmnd(scmd);
|
||||||
rtn = FAILED;
|
rtn = FAILED;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue