Commit e7ac90bc authored by Andries E. Brouwer's avatar Andries E. Brouwer Committed by James Bottomley

[PATCH] scsi: ten -> use_10_for_rw / use_10_for_ms

In the old days, ancient scsi devices understood 6-byte commands
and more recent ones also understood 10-byte commands.
Thus, we had a "ten" flag indicating that 10-byte commands worked.

These days, especially for usb-storage devices, the opposite
sometimes holds - 10-byte commands are supported, but 6-byte commands
are not.

The patch below changes the field ten into the pair of fields
use_10_for_rw, use_10_for_ms set initially when the driver
thinks these are supported. Ifthe device returns ILLEGAL_REQUEST
they are cleared.

This patch obsoletes a large amount of code in usb-storage,
and not only that, once the subsequent patch removes all this
usb-storage code many devices will work that hang today.


Andries
parent e170f25f
...@@ -385,7 +385,8 @@ struct scsi_device { ...@@ -385,7 +385,8 @@ struct scsi_device {
* this device */ * this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */ * because we did a bus reset. */
unsigned ten:1; /* support ten byte read / write */ unsigned use_10_for_rw:1; /* first try 10-byte read / write */
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
unsigned remap:1; /* support remapping */ unsigned remap:1; /* support remapping */
// unsigned sync:1; /* Sync transfer state, managed by host */ // unsigned sync:1; /* Sync transfer state, managed by host */
// unsigned wide:1; /* WIDE transfer state, managed by host */ // unsigned wide:1; /* WIDE transfer state, managed by host */
...@@ -402,10 +403,6 @@ struct scsi_device { ...@@ -402,10 +403,6 @@ struct scsi_device {
container_of(d, struct scsi_device, sdev_driverfs_dev) container_of(d, struct scsi_device, sdev_driverfs_dev)
/*
* The Scsi_Cmnd structure is used by scsi.c internally, and for communication
* with low level drivers that support multiple outstanding commands.
*/
typedef struct scsi_pointer { typedef struct scsi_pointer {
char *ptr; /* data pointer */ char *ptr; /* data pointer */
int this_residual; /* left in this buffer */ int this_residual; /* left in this buffer */
...@@ -458,12 +455,13 @@ struct scsi_request { ...@@ -458,12 +455,13 @@ struct scsi_request {
}; };
/* /*
* FIXME(eric) - one of the great regrets that I have is that I failed to define * FIXME(eric) - one of the great regrets that I have is that I failed to
* these structure elements as something like sc_foo instead of foo. This would * define these structure elements as something like sc_foo instead of foo.
* make it so much easier to grep through sources and so forth. I propose that * This would make it so much easier to grep through sources and so forth.
* all new elements that get added to these structures follow this convention. * I propose that all new elements that get added to these structures follow
* As time goes on and as people have the stomach for it, it should be possible to * this convention. As time goes on and as people have the stomach for it,
* go back and retrofit at least some of the elements here with with the prefix. * it should be possible to go back and retrofit at least some of the elements
* here with with the prefix.
*/ */
struct scsi_cmnd { struct scsi_cmnd {
int sc_magic; int sc_magic;
......
...@@ -662,7 +662,6 @@ static struct Scsi_Device_Template *scsi_get_request_dev(struct request *req) ...@@ -662,7 +662,6 @@ static struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
* *
* b) We can just use scsi_requeue_command() here. This would * b) We can just use scsi_requeue_command() here. This would
* be used if we just wanted to retry, for example. * be used if we just wanted to retry, for example.
*
*/ */
void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
int block_sectors) int block_sectors)
...@@ -796,17 +795,20 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, ...@@ -796,17 +795,20 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
} }
} }
} }
/* If we had an ILLEGAL REQUEST returned, then we may have /*
* performed an unsupported command. The only thing this should be * If we had an ILLEGAL REQUEST returned, then we may have
* would be a ten byte read where only a six byte read was supported. * performed an unsupported command. The only thing this
* Also, on a system where READ CAPACITY failed, we have have read * should be would be a ten byte read where only a six byte
* past the end of the disk. * read was supported. Also, on a system where READ CAPACITY
* failed, we may have read past the end of the disk.
*/ */
switch (cmd->sense_buffer[2]) { switch (cmd->sense_buffer[2]) {
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (cmd->device->ten) { if (cmd->device->use_10_for_rw &&
cmd->device->ten = 0; (cmd->cmnd[0] == READ_10 ||
cmd->cmnd[0] == WRITE_10)) {
cmd->device->use_10_for_rw = 0;
/* /*
* This will cause a retry with a 6-byte * This will cause a retry with a 6-byte
* command. * command.
......
...@@ -320,7 +320,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) ...@@ -320,7 +320,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff; SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff;
SCpnt->cmnd[13] = (unsigned char) this_count & 0xff; SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0; SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
} else if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) { } else if ((this_count > 0xff) || (block > 0x1fffff) ||
SCpnt->device->use_10_for_rw) {
if (this_count > 0xffff) if (this_count > 0xffff)
this_count = 0xffff; this_count = 0xffff;
...@@ -768,11 +769,14 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) ...@@ -768,11 +769,14 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
break; break;
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (SCpnt->device->ten == 1) { if (SCpnt->device->use_10_for_rw &&
if (SCpnt->cmnd[0] == READ_10 || (SCpnt->cmnd[0] == READ_10 ||
SCpnt->cmnd[0] == WRITE_10) SCpnt->cmnd[0] == WRITE_10))
SCpnt->device->ten = 0; SCpnt->device->use_10_for_rw = 0;
} if (SCpnt->device->use_10_for_ms &&
(SCpnt->cmnd[0] == MODE_SENSE_10 ||
SCpnt->cmnd[0] == MODE_SELECT_10))
SCpnt->device->use_10_for_ms = 0;
break; break;
default: default:
...@@ -1094,16 +1098,29 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1094,16 +1098,29 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
sdkp->device->sector_size = sector_size; sdkp->device->sector_size = sector_size;
} }
/* called with buffer of length 512 */
static int static int
sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt, sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
int dbd, int modepage, unsigned char *buffer, int len) { unsigned char *buffer, int len) {
unsigned char cmd[8]; unsigned char cmd[12];
memset((void *) &cmd[0], 0, 8); memset((void *) &cmd[0], 0, 12);
cmd[0] = MODE_SENSE;
cmd[1] = dbd; cmd[1] = dbd;
cmd[2] = modepage; cmd[2] = modepage;
if (SRpnt->sr_device->use_10_for_ms) {
if (len < 8)
len = 8;
cmd[0] = MODE_SENSE_10;
cmd[8] = len;
} else {
if (len < 4)
len = 4;
cmd[0] = MODE_SENSE;
cmd[4] = len; cmd[4] = len;
}
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[0] = 0;
...@@ -1120,11 +1137,11 @@ sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt, ...@@ -1120,11 +1137,11 @@ sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt,
/* /*
* read write protect setting, if possible - called only in sd_init_onedisk() * read write protect setting, if possible - called only in sd_init_onedisk()
* called with buffer of length 512
*/ */
static void static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) { struct scsi_request *SRpnt, unsigned char *buffer) {
struct scsi_device *sdp = sdkp->device;
int res; int res;
/* /*
...@@ -1132,7 +1149,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1132,7 +1149,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* We have to start carefully: some devices hang if we ask * We have to start carefully: some devices hang if we ask
* for more than is available. * for more than is available.
*/ */
res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 4); res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4);
/* /*
* Second attempt: ask for page 0 * Second attempt: ask for page 0
...@@ -1140,13 +1157,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1140,13 +1157,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB. * Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB.
*/ */
if (res) if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0, 0, buffer, 4); res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4);
/* /*
* Third attempt: ask 255 bytes, as we did earlier. * Third attempt: ask 255 bytes, as we did earlier.
*/ */
if (res) if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 255); res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255);
if (res) { if (res) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1162,25 +1179,25 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1162,25 +1179,25 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
/* /*
* sd_read_cache_type - called only from sd_init_onedisk() * sd_read_cache_type - called only from sd_init_onedisk()
* called with buffer of length 512
*/ */
static void static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) { struct scsi_request *SRpnt, unsigned char *buffer) {
struct scsi_device *sdp = sdkp->device;
int len = 0, res; int len = 0, res;
const int dbd = 0x08; /* DBD */ const int dbd = 0x08; /* DBD */
const int modepage = 0x08; /* current values, cache page */ const int modepage = 0x08; /* current values, cache page */
/* cautiously ask */ /* cautiously ask */
res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, 4); res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4);
if (res == 0) { if (res == 0) {
/* that went OK, now ask for the proper length */ /* that went OK, now ask for the proper length */
len = buffer[0] + 1; len = buffer[0] + 1;
if (len > 128) if (len > 128)
len = 128; len = 128;
res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, len); res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len);
} }
if (res == 0 && buffer[3] + 6 < len) { if (res == 0 && buffer[3] + 6 < len) {
...@@ -1279,7 +1296,8 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) ...@@ -1279,7 +1296,8 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk)
if (sdkp->media_present) if (sdkp->media_present)
sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer); sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer);
SRpnt->sr_device->ten = 1; SRpnt->sr_device->use_10_for_rw = 1;
SRpnt->sr_device->use_10_for_ms = 0;
SRpnt->sr_device->remap = 1; SRpnt->sr_device->remap = 1;
leave: leave:
......
...@@ -559,7 +559,8 @@ static int sr_attach(struct scsi_device *sdev) ...@@ -559,7 +559,8 @@ static int sr_attach(struct scsi_device *sdev)
sprintf(cd->cdi.name, "sr%d", minor); sprintf(cd->cdi.name, "sr%d", minor);
sdev->sector_size = 2048; /* A guess, just in case */ sdev->sector_size = 2048; /* A guess, just in case */
sdev->ten = 1; sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 0;
sdev->remap = 1; sdev->remap = 1;
/* FIXME: need to handle a get_capabilities failure properly ?? */ /* FIXME: need to handle a get_capabilities failure properly ?? */
......
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