From 10dab22664914505dcb804d9ad09cad6bc94d349 Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Thu, 11 Sep 2008 21:39:36 -0400 Subject: [SCSI] sd: Fix handling of NO_SENSE check condition The current handling of NO_SENSE check condition is the same as RECOVERED_ERROR, and assumes that in both cases, the I/O was fully transferred. We have seen cases of arrays returning with NO_SENSE (no error), but the I/O was not completely transferred, thus residual set. Thus, rather than return good_bytes as the entire transfer, set good_bytes to 0, so that the midlayer then applies the residual in calculating the transfer, and for sd, will fail the I/O and fall into a retry path. Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7c4d2e68df1..55e6ed4b886 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1054,7 +1054,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) good_bytes = sd_completed_bytes(SCpnt); break; case RECOVERED_ERROR: - case NO_SENSE: /* Inform the user, but make sure that it's not treated * as a hard error. */ @@ -1063,6 +1062,15 @@ static int sd_done(struct scsi_cmnd *SCpnt) memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); good_bytes = scsi_bufflen(SCpnt); break; + case NO_SENSE: + /* This indicates a false check condition, so ignore it. An + * unknown amount of data was transferred so treat it as an + * error. + */ + scsi_print_sense("sd", SCpnt); + SCpnt->result = 0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + break; case ABORTED_COMMAND: if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */ scsi_print_result(SCpnt); -- cgit v1.2.3 From d4c9b736080056ae3ba81dcf2ac418193c57dbb1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 10 Oct 2008 16:03:20 -0400 Subject: [SCSI] sd: remove command-size switching code This patch (as1138) removes from sd.c some old code for switching from 10-byte commands to 6-byte commands. This code is redundant -- the switching for READ and WRITE is already handled in scsi_io_completion() and the switching for MODE SENSE is already handled in scsi_mode_sense(). (There is no comparable switch for MODE SELECT, but I doubt one is needed.) Furthermore the other handlers do a better job; they check for appropriate ASC and ASCQ values before blindly switching the size. The code in sd.c is known to cause problems with some devices by switching when it shouldn't. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 55e6ed4b886..7e22aa7b8b8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1084,15 +1084,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) scsi_print_sense("sd", SCpnt); good_bytes = sd_completed_bytes(SCpnt); } - if (!scsi_device_protection(SCpnt->device) && - SCpnt->device->use_10_for_rw && - (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10)) - SCpnt->device->use_10_for_rw = 0; - if (SCpnt->device->use_10_for_ms && - (SCpnt->cmnd[0] == MODE_SENSE_10 || - SCpnt->cmnd[0] == MODE_SELECT_10)) - SCpnt->device->use_10_for_ms = 0; break; default: break; -- cgit v1.2.3 From 520a2c2741747062e75f91cd0faddb564fbc64d2 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 14 Oct 2008 11:34:20 -0700 Subject: [SCSI] sd: fix computation of the full size of the device When computing the full size of the device, we need to cast sdkp->capacity before shifting, since in some configurations sector_t can be a 32-bit number. Also, change ffz(~x) to the more idiomatic ilog2(x). Signed-off-by: H. Peter Anvin Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7e22aa7b8b8..7ba70bef8b5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1436,7 +1436,7 @@ got_data: { char cap_str_2[10], cap_str_10[10]; - u64 sz = sdkp->capacity << ffz(~sector_size); + u64 sz = (u64)sdkp->capacity << ilog2(sector_size); string_get_size(sz, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2)); -- cgit v1.2.3