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.
This has been tested with multiple usb-storage peripherals. Please apply.
Matthew Dharm
===== drivers/scsi/sr.c 1.53 vs edited =====
--- 1.53/drivers/scsi/sr.c Tue Aug 19 10:38:06 2003
+++ edited/drivers/scsi/sr.c Mon Sep 1 13:28:41 2003
@@ -695,6 +695,10 @@
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 @@
""
};
+ /* 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 @@
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 @@
/*else I don't think it can close its tray
cd->cdi.mask |= CDC_CLOSE_TRAY; */
+ scsi_release_request(SRpnt);
kfree(buffer);
}
--
Matthew Dharm Home: [EMAIL PROTECTED]
Maintainer, Linux USB Mass Storage Driver
It's not that hard. No matter what the problem is, tell the customer
to reinstall Windows.
-- Nurse
User Friendly, 3/22/1998
pgp00000.pgp
Description: PGP signature
