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)
/* 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]) {
case MEDIUM_ERROR:
if (!(SCpnt->sense_buffer[0] & 0x80))
break;
error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) |
......@@ -696,7 +698,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
* hard error.
*/
print_sense("sd", SCpnt);
result = 0;
SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count;
break;
......
......@@ -181,6 +181,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
int this_count = SCpnt->bufflen >> 9;
int good_sectors = (result == 0 ? this_count : 0);
int block_sectors = 0;
long error_sector;
struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
#ifdef DEBUG
......@@ -194,33 +195,57 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
* memcpy's that could be avoided.
*/
if (driver_byte(result) != 0 && /* An error occurred */
SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */
(SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
SCpnt->sense_buffer[2] == VOLUME_OVERFLOW ||
SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) {
long error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) |
SCpnt->sense_buffer[6];
if (SCpnt->request->bio != NULL)
block_sectors = bio_sectors(SCpnt->request->bio);
if (block_sectors < 4)
block_sectors = 4;
if (cd->device->sector_size == 2048)
error_sector <<= 2;
error_sector &= ~(block_sectors - 1);
good_sectors = error_sector - SCpnt->request->sector;
if (good_sectors < 0 || good_sectors >= this_count)
good_sectors = 0;
/*
* The SCSI specification allows for the value returned by READ
* CAPACITY to be up to 75 2K sectors past the last readable
* block. 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);
(SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
switch (SCpnt->sense_buffer[2]) {
case MEDIUM_ERROR:
case VOLUME_OVERFLOW:
case ILLEGAL_REQUEST:
if (!(SCpnt->sense_buffer[0] & 0x90))
break;
error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) |
SCpnt->sense_buffer[6];
if (SCpnt->request->bio != NULL)
block_sectors =
bio_sectors(SCpnt->request->bio);
if (block_sectors < 4)
block_sectors = 4;
if (cd->device->sector_size == 2048)
error_sector <<= 2;
error_sector &= ~(block_sectors - 1);
good_sectors = error_sector - SCpnt->request->sector;
if (good_sectors < 0 || good_sectors >= this_count)
good_sectors = 0;
/*
* The SCSI specification allows for the value
* returned by READ CAPACITY to be up to 75 2K
* sectors past the last readable block.
* 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