Commit a5090bb3 authored by Mike Anderson's avatar Mike Anderson Committed by James Bottomley

[PATCH] recovered error forward port

Forward port of Kurt Garloff's recovered error fix.
http://marc.theaimsgroup.com/?l=linux-scsi&m=104470522312140&w=2

Also corrected some typos related to setting local scope variable by mistake.

Signature without fix:
Current sdc: sense key Recovered Error
Additional sense: Failure prediction threshold exceeded
end_request: I/O error, dev sdc, sector 1808
Buffer I/O error on device sdc, logical block 226

Signature with fix:
scsi_debug: cmd 28 00 00 00 3f 10 00 00 f0 00
scsi_debug: ... <1 0 0 0> non-zero result=0x8000002
Current sdsdc: sense key Recovered Error
Additional sense: Failure prediction threshold exceeded

 drivers/scsi/sd.c |    6 ++--
 drivers/scsi/sr.c |   79 +++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 56 insertions(+), 29 deletions(-)
parent 8809148d
...@@ -651,9 +651,11 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -651,9 +651,11 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
/* An error occurred */ /* An error occurred */
if (driver_byte(result) != 0 && /* An error occurred */ if (driver_byte(result) != 0 && /* An error occurred */
SCpnt->sense_buffer[0] == 0xF0) { /* Sense data is valid */ (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
switch (SCpnt->sense_buffer[2]) { switch (SCpnt->sense_buffer[2]) {
case MEDIUM_ERROR: case MEDIUM_ERROR:
if (!(SCpnt->sense_buffer[0] & 0x80))
break;
error_sector = (SCpnt->sense_buffer[3] << 24) | error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | (SCpnt->sense_buffer[5] << 8) |
...@@ -696,7 +698,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -696,7 +698,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
* hard error. * hard error.
*/ */
print_sense("sd", SCpnt); print_sense("sd", SCpnt);
result = 0; SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0; SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count; good_sectors = this_count;
break; break;
......
...@@ -181,6 +181,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -181,6 +181,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen >> 9;
int good_sectors = (result == 0 ? this_count : 0); int good_sectors = (result == 0 ? this_count : 0);
int block_sectors = 0; int block_sectors = 0;
long error_sector;
struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
#ifdef DEBUG #ifdef DEBUG
...@@ -194,33 +195,57 @@ static void rw_intr(struct scsi_cmnd * SCpnt) ...@@ -194,33 +195,57 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
* memcpy's that could be avoided. * memcpy's that could be avoided.
*/ */
if (driver_byte(result) != 0 && /* An error occurred */ if (driver_byte(result) != 0 && /* An error occurred */
SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */ (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
(SCpnt->sense_buffer[2] == MEDIUM_ERROR || switch (SCpnt->sense_buffer[2]) {
SCpnt->sense_buffer[2] == VOLUME_OVERFLOW || case MEDIUM_ERROR:
SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) { case VOLUME_OVERFLOW:
long error_sector = (SCpnt->sense_buffer[3] << 24) | case ILLEGAL_REQUEST:
(SCpnt->sense_buffer[4] << 16) | if (!(SCpnt->sense_buffer[0] & 0x90))
(SCpnt->sense_buffer[5] << 8) | break;
SCpnt->sense_buffer[6]; error_sector = (SCpnt->sense_buffer[3] << 24) |
if (SCpnt->request->bio != NULL) (SCpnt->sense_buffer[4] << 16) |
block_sectors = bio_sectors(SCpnt->request->bio); (SCpnt->sense_buffer[5] << 8) |
if (block_sectors < 4) SCpnt->sense_buffer[6];
block_sectors = 4; if (SCpnt->request->bio != NULL)
if (cd->device->sector_size == 2048) block_sectors =
error_sector <<= 2; bio_sectors(SCpnt->request->bio);
error_sector &= ~(block_sectors - 1); if (block_sectors < 4)
good_sectors = error_sector - SCpnt->request->sector; block_sectors = 4;
if (good_sectors < 0 || good_sectors >= this_count) if (cd->device->sector_size == 2048)
good_sectors = 0; error_sector <<= 2;
/* error_sector &= ~(block_sectors - 1);
* The SCSI specification allows for the value returned by READ good_sectors = error_sector - SCpnt->request->sector;
* CAPACITY to be up to 75 2K sectors past the last readable if (good_sectors < 0 || good_sectors >= this_count)
* block. Therefore, if we hit a medium error within the last good_sectors = 0;
* 75 2K sectors, we decrease the saved size value. /*
*/ * The SCSI specification allows for the value
if (error_sector < get_capacity(cd->disk) && * returned by READ CAPACITY to be up to 75 2K
cd->capacity - error_sector < 4 * 75) * sectors past the last readable block.
set_capacity(cd->disk, error_sector); * Therefore, if we hit a medium error within the
* last 75 2K sectors, we decrease the saved size
* value.
*/
if (error_sector < get_capacity(cd->disk) &&
cd->capacity - error_sector < 4 * 75)
set_capacity(cd->disk, error_sector);
break;
case RECOVERED_ERROR:
/*
* An error occured, but it recovered. Inform the
* user, but make sure that it's not treated as a
* hard error.
*/
print_sense("sr", SCpnt);
SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count;
break;
default:
break;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment