Commit 613d1564 authored by Matthew Dharm's avatar Matthew Dharm Committed by Linus Torvalds

[PATCH] sr.c should issue TEST_UNIT_READY

The linux/drivers/scsi/sr.c code will issue a MODE_SENSE[_10] command to
a device as the first command sent to the device.  If the device has
just come out of reset, it will likely respond with a UNIT_ATTENTION /
NOT_READY status, which causes the MODE_SENSE to fail.  In fact, the
device may have several UNIT_ATTENTION conditions queued up (power-up
reset, media change, etc.)

This results in the mode page 0x2a data not being properly read and
interpreted.  As an end-effect, things like packet-writing don't work
(because the writeable bit is not set).

The solution to this is to issue one or more TEST_UNIT_READY commands to
the device to clear any pending UNIT_ATTENTION conditions.  This is the
technique used by sd.c -- in fact, this code was lifted directly from
sd.c

At some point in the future, abstraction of this initial TEST_UNIT_READY
code between all high-level SCSI drivers may be apropriate.  For now,
this patch makes sr.c issue TEST_UNIT_READY to clear the UNIT_ATTENTION,
thus allowing the mode page 0x2a code to work properly.  Given the
approaching 2.6.0-final release, I urge that this patch be accepted.
parent 47150372
......@@ -695,6 +695,10 @@ static void get_capabilities(struct scsi_cd *cd)
unsigned char *buffer;
int rc, n;
struct scsi_mode_data data;
struct scsi_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE];
unsigned int the_result;
int retries;
static char *loadmech[] =
{
......@@ -708,11 +712,46 @@ static void get_capabilities(struct scsi_cd *cd)
""
};
/* allocate a request for the TEST_UNIT_READY */
SRpnt = scsi_allocate_request(cd->device);
if (!SRpnt) {
printk(KERN_WARNING "(get_capabilities:) Request allocation "
"failure.\n");
return;
}
/* allocate transfer buffer */
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer) {
printk(KERN_ERR "sr: out of memory.\n");
scsi_release_request(SRpnt);
return;
}
/* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION
* conditions are gone, or a timeout happens
*/
retries = 0;
do {
memset((void *)cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req (SRpnt, (void *) cmd, buffer,
0, SR_TIMEOUT, MAX_RETRIES);
the_result = SRpnt->sr_result;
retries++;
} while (retries < 5 &&
(!scsi_status_is_good(the_result) ||
((driver_byte(the_result) & DRIVER_SENSE) &&
SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
/* ask for mode page 0x2a */
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
SR_TIMEOUT, 3, &data);
......@@ -722,6 +761,7 @@ static void get_capabilities(struct scsi_cd *cd)
cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
CDC_DVD | CDC_DVD_RAM |
CDC_SELECT_DISC | CDC_SELECT_SPEED);
scsi_release_request(SRpnt);
kfree(buffer);
printk("%s: scsi-1 drive\n", cd->cdi.name);
return;
......@@ -775,6 +815,7 @@ static void get_capabilities(struct scsi_cd *cd)
/*else I don't think it can close its tray
cd->cdi.mask |= CDC_CLOSE_TRAY; */
scsi_release_request(SRpnt);
kfree(buffer);
}
......
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