Commit ff8f440f authored by James Bottomley's avatar James Bottomley

sd descriptor sense support

From: 	Douglas Gilbert <dougg@torque.net>

   - make all sd driver sense data handling able to use
     both fixed and descriptor format
   - permit 64 bit lbas associated with medium (or
     hardware) errors to be conveyed back to the block
     layer
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent d0aa9c61
...@@ -106,7 +106,7 @@ struct scsi_disk { ...@@ -106,7 +106,7 @@ struct scsi_disk {
}; };
static DEFINE_IDR(sd_index_idr); static DEFINE_IDR(sd_index_idr);
static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static DEFINE_SPINLOCK(sd_index_lock);
/* This semaphore is used to mediate the 0->1 reference get in the /* This semaphore is used to mediate the 0->1 reference get in the
* face of object destruction (i.e. we can't allow a get on an * face of object destruction (i.e. we can't allow a get on an
...@@ -763,15 +763,26 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -763,15 +763,26 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
int this_count = SCpnt->bufflen; int this_count = SCpnt->bufflen;
int good_bytes = (result == 0 ? this_count : 0); int good_bytes = (result == 0 ? this_count : 0);
sector_t block_sectors = 1; sector_t block_sectors = 1;
u64 first_err_block;
sector_t error_sector; sector_t error_sector;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
int info_valid;
if (result) {
sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
#ifdef CONFIG_SCSI_LOGGING #ifdef CONFIG_SCSI_LOGGING
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->request->rq_disk->disk_name, result)); SCpnt->request->rq_disk->disk_name, result));
if (0 != result) { if (sense_valid) {
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]" SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
"=%x,%x,%x,%x\n", SCpnt->sense_buffer[0], "ascq]=%x,%x,%x,%x\n", sshdr.response_code,
SCpnt->sense_buffer[2], SCpnt->sense_buffer[12], sshdr.sense_key, sshdr.asc, sshdr.ascq));
SCpnt->sense_buffer[13]));
} }
#endif #endif
/* /*
...@@ -788,17 +799,19 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -788,17 +799,19 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
if (blk_pc_request(SCpnt->request)) if (blk_pc_request(SCpnt->request))
good_bytes = this_count; good_bytes = this_count;
else if (driver_byte(result) != 0 && else if (driver_byte(result) != 0 &&
(SCpnt->sense_buffer[0] & 0x7f) == 0x70) { sense_valid && !sense_deferred) {
switch (SCpnt->sense_buffer[2]) { switch (sshdr.sense_key) {
case MEDIUM_ERROR: case MEDIUM_ERROR:
if (!(SCpnt->sense_buffer[0] & 0x80))
break;
if (!blk_fs_request(SCpnt->request)) if (!blk_fs_request(SCpnt->request))
break; break;
error_sector = (SCpnt->sense_buffer[3] << 24) | info_valid = scsi_get_sense_info_fld(
(SCpnt->sense_buffer[4] << 16) | SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
(SCpnt->sense_buffer[5] << 8) | &first_err_block);
SCpnt->sense_buffer[6]; /*
* May want to warn and skip if following cast results
* in actual truncation (if sector_t < 64 bits)
*/
error_sector = (sector_t)first_err_block;
if (SCpnt->request->bio != NULL) if (SCpnt->request->bio != NULL)
block_sectors = bio_sectors(SCpnt->request->bio); block_sectors = bio_sectors(SCpnt->request->bio);
switch (SCpnt->device->sector_size) { switch (SCpnt->device->sector_size) {
...@@ -838,7 +851,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -838,7 +851,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
*/ */
scsi_print_sense("sd", SCpnt); scsi_print_sense("sd", SCpnt);
SCpnt->result = 0; SCpnt->result = 0;
SCpnt->sense_buffer[0] = 0x0; memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
good_bytes = this_count; good_bytes = this_count;
break; break;
...@@ -867,16 +880,20 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -867,16 +880,20 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
{ {
struct scsi_sense_hdr sshdr;
if (!srp->sr_result) if (!srp->sr_result)
return 0; return 0;
if (!(driver_byte(srp->sr_result) & DRIVER_SENSE)) if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
return 0; return 0;
if (srp->sr_sense_buffer[2] != NOT_READY && /* not invoked for commands that could return deferred errors */
srp->sr_sense_buffer[2] != UNIT_ATTENTION) if (scsi_request_normalize_sense(srp, &sshdr)) {
return 0; if (sshdr.sense_key != NOT_READY &&
if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */ sshdr.sense_key != UNIT_ATTENTION)
return 0; return 0;
if (sshdr.asc != 0x3A) /* medium not present */
return 0;
}
set_media_not_present(sdkp); set_media_not_present(sdkp);
return 1; return 1;
} }
...@@ -891,6 +908,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -891,6 +908,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
unsigned long spintime_value = 0; unsigned long spintime_value = 0;
int retries, spintime; int retries, spintime;
unsigned int the_result; unsigned int the_result;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
spintime = 0; spintime = 0;
...@@ -904,19 +923,22 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -904,19 +923,22 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
memset((void *) &cmd[1], 0, 9); memset((void *) &cmd[1], 0, 9);
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0; memset(SRpnt->sr_sense_buffer, 0,
SRpnt->sr_sense_buffer[2] = 0; SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE; SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
the_result = SRpnt->sr_result; the_result = SRpnt->sr_result;
if (the_result)
sense_valid = scsi_request_normalize_sense(
SRpnt, &sshdr);
retries++; retries++;
} while (retries < 3 && } while (retries < 3 &&
(!scsi_status_is_good(the_result) || (!scsi_status_is_good(the_result) ||
((driver_byte(the_result) & DRIVER_SENSE) && ((driver_byte(the_result) & DRIVER_SENSE) &&
SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
/* /*
* If the drive has indicated to us that it doesn't have * If the drive has indicated to us that it doesn't have
...@@ -930,7 +952,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -930,7 +952,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
/* no sense, TUR either succeeded or failed /* no sense, TUR either succeeded or failed
* with a status error */ * with a status error */
if(!spintime && !scsi_status_is_good(the_result)) if(!spintime && !scsi_status_is_good(the_result))
printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result); printk(KERN_NOTICE "%s: Unit Not Ready, "
"error = 0x%x\n", diskname, the_result);
break; break;
} }
...@@ -945,15 +968,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -945,15 +968,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
* If manual intervention is required, or this is an * If manual intervention is required, or this is an
* absent USB storage device, a spinup is meaningless. * absent USB storage device, a spinup is meaningless.
*/ */
if (SRpnt->sr_sense_buffer[2] == NOT_READY && if (sense_valid &&
SRpnt->sr_sense_buffer[12] == 4 /* not ready */ && sshdr.sense_key == NOT_READY &&
SRpnt->sr_sense_buffer[13] == 3) { sshdr.asc == 4 && sshdr.ascq == 3) {
break; /* manual intervention required */ break; /* manual intervention required */
/* /*
* Issue command to spin up drive when not ready * Issue command to spin up drive when not ready
*/ */
} else if (SRpnt->sr_sense_buffer[2] == NOT_READY) { } else if (sense_valid && sshdr.sense_key == NOT_READY) {
if (!spintime) { if (!spintime) {
printk(KERN_NOTICE "%s: Spinning up disk...", printk(KERN_NOTICE "%s: Spinning up disk...",
diskname); diskname);
...@@ -962,8 +985,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -962,8 +985,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
memset((void *) &cmd[2], 0, 8); memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */ cmd[4] = 1; /* Start spin cycle */
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0; memset(SRpnt->sr_sense_buffer, 0,
SRpnt->sr_sense_buffer[2] = 0; SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE; SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req(SRpnt, (void *)cmd, scsi_wait_req(SRpnt, (void *)cmd,
...@@ -979,7 +1002,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -979,7 +1002,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
/* we don't understand the sense code, so it's /* we don't understand the sense code, so it's
* probably pointless to loop */ * probably pointless to loop */
if(!spintime) { if(!spintime) {
printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname); printk(KERN_NOTICE "%s: Unit Not Ready, "
"sense:\n", diskname);
scsi_print_req_sense("", SRpnt); scsi_print_req_sense("", SRpnt);
} }
break; break;
...@@ -1007,6 +1031,8 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1007,6 +1031,8 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
int the_result, retries; int the_result, retries;
int sector_size = 0; int sector_size = 0;
int longrc = 0; int longrc = 0;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
repeat: repeat:
retries = 3; retries = 3;
...@@ -1024,8 +1050,7 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1024,8 +1050,7 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
} }
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0; memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = DMA_FROM_DEVICE; SRpnt->sr_data_direction = DMA_FROM_DEVICE;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
...@@ -1035,6 +1060,9 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1035,6 +1060,9 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
return; return;
the_result = SRpnt->sr_result; the_result = SRpnt->sr_result;
if (the_result)
sense_valid = scsi_request_normalize_sense(SRpnt,
&sshdr);
retries--; retries--;
} while (the_result && retries); } while (the_result && retries);
...@@ -1056,7 +1084,7 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1056,7 +1084,7 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
/* Set dirty bit for removable devices if not ready - /* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */ * sometimes drives will not report this properly. */
if (sdp->removable && if (sdp->removable &&
SRpnt->sr_sense_buffer[2] == NOT_READY) sense_valid && sshdr.sense_key == NOT_READY)
sdp->changed = 1; sdp->changed = 1;
/* Either no media are present but the drive didn't tell us, /* Either no media are present but the drive didn't tell us,
...@@ -1264,6 +1292,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1264,6 +1292,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
const int dbd = 0; /* DBD */ const int dbd = 0; /* DBD */
const int modepage = 0x08; /* current values, cache page */ const int modepage = 0x08; /* current values, cache page */
struct scsi_mode_data data; struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
if (sdkp->device->skip_ms_page_8) if (sdkp->device->skip_ms_page_8)
goto defaults; goto defaults;
...@@ -1313,17 +1342,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1313,17 +1342,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
} }
bad_sense: bad_sense:
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
&& (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST sshdr.sense_key == ILLEGAL_REQUEST &&
/* ASC 0x24 ASCQ 0x00: Invalid field in CDB */ sshdr.asc == 0x24 && sshdr.ascq == 0x0)
&& SRpnt->sr_sense_buffer[12] == 0x24
&& SRpnt->sr_sense_buffer[13] == 0x00) {
printk(KERN_NOTICE "%s: cache data unavailable\n", printk(KERN_NOTICE "%s: cache data unavailable\n",
diskname); diskname); /* Invalid field in CDB */
} else { else
printk(KERN_ERR "%s: asking for cache data failed\n", printk(KERN_ERR "%s: asking for cache data failed\n",
diskname); diskname);
}
defaults: defaults:
printk(KERN_ERR "%s: assuming drive cache: write through\n", printk(KERN_ERR "%s: assuming drive cache: write through\n",
......
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