summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bottomley <jejb@mulgrave.(none)>2005-01-22 21:26:01 -0600
committerJames Bottomley <jejb@mulgrave.(none)>2005-01-22 21:26:01 -0600
commitff8f440f41c390843ade3eaccd1b6ca959fbfb7b (patch)
treeb0051b28da97752f19a3f7b10fb04c2b68b2baf7
parentd0aa9c61ed246a2cf9573fa84790a6035864acfd (diff)
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: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/sd.c112
1 files changed, 69 insertions, 43 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 6ef8befab55b..523d68ad047b 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -106,7 +106,7 @@ struct scsi_disk {
};
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
* 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)
int this_count = SCpnt->bufflen;
int good_bytes = (result == 0 ? this_count : 0);
sector_t block_sectors = 1;
+ u64 first_err_block;
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
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->request->rq_disk->disk_name, result));
- if (0 != result) {
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]"
- "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0],
- SCpnt->sense_buffer[2], SCpnt->sense_buffer[12],
- SCpnt->sense_buffer[13]));
+ if (sense_valid) {
+ SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
+ "ascq]=%x,%x,%x,%x\n", sshdr.response_code,
+ sshdr.sense_key, sshdr.asc, sshdr.ascq));
}
#endif
/*
@@ -788,17 +799,19 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
if (blk_pc_request(SCpnt->request))
good_bytes = this_count;
else if (driver_byte(result) != 0 &&
- (SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
- switch (SCpnt->sense_buffer[2]) {
+ sense_valid && !sense_deferred) {
+ switch (sshdr.sense_key) {
case MEDIUM_ERROR:
- if (!(SCpnt->sense_buffer[0] & 0x80))
- break;
if (!blk_fs_request(SCpnt->request))
break;
- error_sector = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) |
- SCpnt->sense_buffer[6];
+ info_valid = scsi_get_sense_info_fld(
+ SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &first_err_block);
+ /*
+ * 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)
block_sectors = bio_sectors(SCpnt->request->bio);
switch (SCpnt->device->sector_size) {
@@ -838,7 +851,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
*/
scsi_print_sense("sd", SCpnt);
SCpnt->result = 0;
- SCpnt->sense_buffer[0] = 0x0;
+ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
good_bytes = this_count;
break;
@@ -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)
{
+ struct scsi_sense_hdr sshdr;
+
if (!srp->sr_result)
return 0;
if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
return 0;
- if (srp->sr_sense_buffer[2] != NOT_READY &&
- srp->sr_sense_buffer[2] != UNIT_ATTENTION)
- return 0;
- if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */
- return 0;
-
+ /* not invoked for commands that could return deferred errors */
+ if (scsi_request_normalize_sense(srp, &sshdr)) {
+ if (sshdr.sense_key != NOT_READY &&
+ sshdr.sense_key != UNIT_ATTENTION)
+ return 0;
+ if (sshdr.asc != 0x3A) /* medium not present */
+ return 0;
+ }
set_media_not_present(sdkp);
return 1;
}
@@ -891,6 +908,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
unsigned long spintime_value = 0;
int retries, spintime;
unsigned int the_result;
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
spintime = 0;
@@ -904,19 +923,22 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
memset((void *) &cmd[1], 0, 9);
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
the_result = SRpnt->sr_result;
+ if (the_result)
+ sense_valid = scsi_request_normalize_sense(
+ SRpnt, &sshdr);
retries++;
} while (retries < 3 &&
(!scsi_status_is_good(the_result) ||
((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
@@ -930,7 +952,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
/* no sense, TUR either succeeded or failed
* with a status error */
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;
}
@@ -945,15 +968,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
* If manual intervention is required, or this is an
* absent USB storage device, a spinup is meaningless.
*/
- if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
- SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
- SRpnt->sr_sense_buffer[13] == 3) {
+ if (sense_valid &&
+ sshdr.sense_key == NOT_READY &&
+ sshdr.asc == 4 && sshdr.ascq == 3) {
break; /* manual intervention required */
/*
* 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) {
printk(KERN_NOTICE "%s: Spinning up disk...",
diskname);
@@ -962,8 +985,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req(SRpnt, (void *)cmd,
@@ -979,7 +1002,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
/* we don't understand the sense code, so it's
* probably pointless to loop */
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);
}
break;
@@ -1007,6 +1031,8 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
int the_result, retries;
int sector_size = 0;
int longrc = 0;
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
repeat:
retries = 3;
@@ -1024,8 +1050,7 @@ repeat:
}
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_FROM_DEVICE;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
@@ -1035,6 +1060,9 @@ repeat:
return;
the_result = SRpnt->sr_result;
+ if (the_result)
+ sense_valid = scsi_request_normalize_sense(SRpnt,
+ &sshdr);
retries--;
} while (the_result && retries);
@@ -1056,7 +1084,7 @@ repeat:
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
if (sdp->removable &&
- SRpnt->sr_sense_buffer[2] == NOT_READY)
+ sense_valid && sshdr.sense_key == NOT_READY)
sdp->changed = 1;
/* 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,
const int dbd = 0; /* DBD */
const int modepage = 0x08; /* current values, cache page */
struct scsi_mode_data data;
+ struct scsi_sense_hdr sshdr;
if (sdkp->device->skip_ms_page_8)
goto defaults;
@@ -1313,17 +1342,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
}
bad_sense:
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70
- && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST
- /* ASC 0x24 ASCQ 0x00: Invalid field in CDB */
- && SRpnt->sr_sense_buffer[12] == 0x24
- && SRpnt->sr_sense_buffer[13] == 0x00) {
+ if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
+ sshdr.sense_key == ILLEGAL_REQUEST &&
+ sshdr.asc == 0x24 && sshdr.ascq == 0x0)
printk(KERN_NOTICE "%s: cache data unavailable\n",
- diskname);
- } else {
+ diskname); /* Invalid field in CDB */
+ else
printk(KERN_ERR "%s: asking for cache data failed\n",
diskname);
- }
defaults:
printk(KERN_ERR "%s: assuming drive cache: write through\n",