Commit e91004e8 authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by Linus Torvalds

[PATCH] try more sd.c MODE SENSE modes

In sd.c we call MODE SENSE (6) in order to find out whether the
device is write protected. The info we need is in byte 2, the
header of the MODE SENSE answer, but in the request we have to
specify (i) what page(s) we want, and (ii) how many bytes we want.

Long ago we asked for 12 bytes from page 1 (Daniel Roche, 1.3.35).
Matthew Dharm made this 8 bytes from page 3F (all pages), patch-2.4.0-test8.
In patch-2.4.10 the 8 was increased to 255.

I found on the one hand devices that only react to page 0
(the vendor page), and return an error for page 3F.
And on the other hand devices that are unable to handle requests
for more bytes than they actually have.

So, it seems that the cautious way to ask for MODE SENSE data is
to first ask for the header only, see how much is available,
and then ask for everything.

The patch below first separates out the MODE SENSE call,
and then tries it three times: on all pages (3F), only the first
four bytes; on the vendor page (0), only the first four bytes;
on all pages (3F), 255 bytes.

This should be at least as robust as our current code.
I tried it on 8 SCSI devices (of which 2 fail under 2.5.33)
and found no problems.
parent 27254059
......@@ -1007,6 +1007,28 @@ sd_read_capacity(Scsi_Disk *sdkp, char *diskname,
sdkp->device->sector_size = sector_size;
}
static int
sd_do_mode_sense6(Scsi_Device *sdp, Scsi_Request *SRpnt,
int modepage, unsigned char *buffer, int len) {
unsigned char cmd[8];
memset((void *) &cmd[0], 0, 8);
cmd[0] = MODE_SENSE;
cmd[1] = (sdp->scsi_level <= SCSI_2) ? ((sdp->lun << 5) & 0xe0) : 0;
cmd[2] = modepage;
cmd[4] = len;
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
len, SD_TIMEOUT, MAX_RETRIES);
return SRpnt->sr_result;
}
/*
* read write protect setting, if possible - called only in sd_init_onedisk()
*/
......@@ -1014,50 +1036,38 @@ static void
sd_read_write_protect_flag(Scsi_Disk *sdkp, char *diskname,
Scsi_Request *SRpnt, unsigned char *buffer) {
Scsi_Device *sdp = sdkp->device;
unsigned char cmd[8];
int the_result;
int res;
/*
* For removable scsi disks we have to recognise the
* Write Protect Flag. This flag is kept in the Scsi_Disk
* struct and tested at open !
* Daniel Roche ( dan@lectra.fr )
*
* Changed to get all pages (0x3f) rather than page 1 to
* get around devices which do not have a page 1. Since
* we're only interested in the header anyway, this should
* be fine.
* -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
*
* As it turns out, some devices return an error for
* every MODE_SENSE request except one for page 0.
* So, we should also try that. --aeb
* First attempt: ask for all pages (0x3F), but only 4 bytes.
* We have to start carefully: some devices hang if we ask
* for more than is available.
*/
res = sd_do_mode_sense6(sdp, SRpnt, 0x3F, buffer, 4);
memset((void *) &cmd[0], 0, 8);
cmd[0] = MODE_SENSE;
cmd[1] = (sdp->scsi_level <= SCSI_2) ?
((sdp->lun << 5) & 0xe0) : 0;
cmd[2] = 0x3f; /* Get all pages */
cmd[4] = 255; /* Ask for 255 bytes, even tho we want just the first 8 */
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
255, SD_TIMEOUT, MAX_RETRIES);
/*
* Second attempt: ask for page 0
* When only page 0 is implemented, a request for page 3F may return
* Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB.
*/
if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0, buffer, 4);
the_result = SRpnt->sr_result;
/*
* Third attempt: ask 255 bytes, as we did earlier.
*/
if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0x3F, buffer, 255);
if (the_result) {
printk("%s: test WP failed, assume Write Enabled\n",
diskname);
/* alternatively, try page 0 */
if (res) {
printk(KERN_WARNING
"%s: test WP failed, assume Write Enabled\n", diskname);
} else {
sdkp->write_prot = ((buffer[2] & 0x80) != 0);
printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
sdkp->write_prot ? "on" : "off");
printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
diskname, buffer[0], buffer[1], buffer[2], buffer[3]);
}
}
......
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