From 2082ebc45af9c9c648383b8cde0dc1948eadbf31 Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Tue, 24 Jan 2012 20:38:46 +0000 Subject: [SCSI] fix the new host byte settings (DID_TARGET_FAILURE and DID_NEXUS_FAILURE) This patch fixes the host byte settings DID_TARGET_FAILURE and DID_NEXUS_FAILURE. The function __scsi_error_from_host_byte, tries to reset the host byte to DID_OK. But that does not happen because of the OR operation. Here is the flow. scsi_softirq_done-> scsi_decide_disposition -> __scsi_error_from_host_byte Let's take an example with DID_NEXUS_FAILURE. In scsi_decide_disposition, result will be set as DID_NEXUS_FAILURE (=0x11). Then in __scsi_error_from_host_byte, when we do OR with DID_OK. Purpose is to reset it back to DID_OK. But that does not happen. This patch fixes this issue. Signed-off-by: Babu Moger Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/scsi_error.c') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 5f84a148eb14..6ae3b5dbd379 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1540,7 +1540,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) * Need to modify host byte to signal a * permanent target failure */ - scmd->result |= (DID_TARGET_FAILURE << 16); + set_host_byte(scmd, DID_TARGET_FAILURE); rtn = SUCCESS; } /* if rtn == FAILED, we have no sense information; @@ -1560,7 +1560,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) case RESERVATION_CONFLICT: sdev_printk(KERN_INFO, scmd->device, "reservation conflict\n"); - scmd->result |= (DID_NEXUS_FAILURE << 16); + set_host_byte(scmd, DID_NEXUS_FAILURE); return SUCCESS; /* causes immediate i/o error */ default: return FAILED; -- cgit v1.2.3 From 47ac56db133cb0b6cf3c8b156db854c158fb9dae Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 13 Feb 2012 18:35:11 -0500 Subject: [SCSI] scsi_error: classify some ILLEGAL_REQUEST sense as a permanent TARGET_ERROR Permanent target failures are non-retryable and should be classified as TARGET_ERROR; otherwise dm-multipath will retry an IO request that will always fail at the target. A SCSI command that fails with ILLEGAL_REQUEST sense and Additional sense 0x20, 0x21, 0x24 or 0x26 represents a permanent TARGET_ERROR. Signed-off-by: Mike Snitzer Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/scsi/scsi_error.c') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6ae3b5dbd379..f66e90db3bee 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -366,6 +366,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) return TARGET_ERROR; case ILLEGAL_REQUEST: + if (sshdr.asc == 0x20 || /* Invalid command operation code */ + sshdr.asc == 0x21 || /* Logical block address out of range */ + sshdr.asc == 0x24 || /* Invalid field in cdb */ + sshdr.asc == 0x26) { /* Parameter value invalid */ + return TARGET_ERROR; + } + return SUCCESS; + default: return SUCCESS; } -- cgit v1.2.3 From 18a4d0a22ed6c54b67af7718c305cd010f09ddf8 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 9 Feb 2012 13:48:53 -0500 Subject: [SCSI] Handle disk devices which can not process medium access commands We have experienced several devices which fail in a fashion we do not currently handle gracefully in SCSI. After a failure these devices will respond to the SCSI primary command set (INQUIRY, TEST UNIT READY, etc.) but any command accessing the storage medium will time out. The following patch adds an callback that can be used by upper level drivers to inspect the results of an error handling command. This in turn has been used to implement additional checking in the SCSI disk driver. If a medium access command fails twice but TEST UNIT READY succeeds both times in the subsequent error handling we will offline the device. The maximum number of failed commands required to take a device offline can be tweaked in sysfs. Also add a new error flag to scsi_debug which allows this scenario to be easily reproduced. [jejb: fix up integer parsing to use kstrtouint] Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/scsi_error.c') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f66e90db3bee..2cfcbffa41fd 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -141,11 +142,11 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) else if (host->hostt->eh_timed_out) rtn = host->hostt->eh_timed_out(scmd); + scmd->result |= DID_TIME_OUT << 16; + if (unlikely(rtn == BLK_EH_NOT_HANDLED && - !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { - scmd->result |= DID_TIME_OUT << 16; + !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) rtn = BLK_EH_HANDLED; - } return rtn; } @@ -778,6 +779,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes) { struct scsi_device *sdev = scmd->device; + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); struct Scsi_Host *shost = sdev->host; DECLARE_COMPLETION_ONSTACK(done); unsigned long timeleft; @@ -832,6 +834,10 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, } scsi_eh_restore_cmnd(scmd, &ses); + + if (sdrv->eh_action) + rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); + return rtn; } -- cgit v1.2.3