Re: [Re: Linux 2.6.26-rc2] Write protect on on

Alan Stern
2008-06-20T20:22:41Z

[-- Attachment #1: Type: TEXT/PLAIN, Size: 916 bytes --]

On Sat, 14 Jun 2008, Maciej Rutecki wrote:

> 2008/6/13 Alan Stern <stern@rowland.harvard.edu>:
>
> [...]
>
> >
> > That patch wasn't meant to help; it wasn't complete. It was meant to
> > stimulate conversation -- and clearly it failed.
> >
> > Below is a complete patch. It's very ugly and isn't likely to get
> > accepted, but maybe it will convince people to start talking about the
> > problem. Maybe it will offend people's sensibilities so that they will
> > just _have_ to chime in, if only to complain about how bad the patch
> > is...
>
> [...]
>
> Tested with 2.6.26-rc2 and works fine. Thanks.

Not having received any comments on that earlier patch, I wrote a new
version. Actually it's a pair of patches, and they have to be applied
in order. They don't look as ugly as the old one and they have a
decent chance of being accepted.

If they also fix your problem, I'll submit them.

Alan Stern

[-- Attachment #2: Type: TEXT/PLAIN, Size: 11839 bytes --]

Index: usb-2.6/include/scsi/scsi_device.h
===================================================================
--- usb-2.6.orig/include/scsi/scsi_device.h
+++ usb-2.6/include/scsi/scsi_device.h
@@ -323,10 +323,11 @@ extern int scsi_is_target_device(const s
extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries,
- int flag);
+ int flag, unsigned *residue);
extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
- struct scsi_sense_hdr *, int timeout, int retries);
+ struct scsi_sense_hdr *, int timeout, int retries,
+ unsigned *residue);
extern int scsi_execute_async(struct scsi_device *sdev,
const unsigned char *cmd, int cmd_len, int data_direction,
void *buffer, unsigned bufflen, int use_sg,
Index: usb-2.6/drivers/ata/libata-scsi.c
===================================================================
--- usb-2.6.orig/drivers/ata/libata-scsi.c
+++ usb-2.6/drivers/ata/libata-scsi.c
@@ -332,7 +332,7 @@ int ata_cmd_ioctl(struct scsi_device *sc
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0, NULL);

if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
@@ -418,7 +418,7 @@ int ata_task_ioctl(struct scsi_device *s
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0, NULL);

if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
Index: usb-2.6/drivers/scsi/ch.c
===================================================================
--- usb-2.6.orig/drivers/scsi/ch.c
+++ usb-2.6/drivers/scsi/ch.c
@@ -189,7 +189,7 @@ ch_do_scsi(scsi_changer *ch, unsigned ch

result = scsi_execute_req(ch->device, cmd, direction, buffer,
buflength, &sshdr, timeout * HZ,
- MAX_RETRIES);
+ MAX_RETRIES, NULL);

dprintk("result: 0x%x\n",result);
if (driver_byte(result) & DRIVER_SENSE) {
Index: usb-2.6/drivers/scsi/scsi_ioctl.c
===================================================================
--- usb-2.6.orig/drivers/scsi/scsi_ioctl.c
+++ usb-2.6/drivers/scsi/scsi_ioctl.c
@@ -94,7 +94,7 @@ static int ioctl_internal_command(struct
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd));

result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0,
- &sshdr, timeout, retries);
+ &sshdr, timeout, retries, NULL);

SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result));

Index: usb-2.6/drivers/scsi/scsi_lib.c
===================================================================
--- usb-2.6.orig/drivers/scsi/scsi_lib.c
+++ usb-2.6/drivers/scsi/scsi_lib.c
@@ -175,13 +175,15 @@ int scsi_queue_insert(struct scsi_cmnd *
* @timeout: request timeout in seconds
* @retries: number of times to retry request
* @flags: or into request flags;
+ * @residue: number of bytes not transferred correctly
*
* returns the req->errors value which is the scsi_cmnd result
* field.
*/
int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
- unsigned char *sense, int timeout, int retries, int flags)
+ unsigned char *sense, int timeout, int retries, int flags,
+ unsigned *residue)
{
struct request *req;
int write = (data_direction == DMA_TO_DEVICE);
@@ -207,6 +209,8 @@ int scsi_execute(struct scsi_device *sde
*/
blk_execute_rq(req->q, NULL, req, 1);

+ if (residue)
+ *residue = req->data_len;
ret = req->errors;
out:
blk_put_request(req);
@@ -218,7 +222,8 @@ EXPORT_SYMBOL(scsi_execute);

int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
- struct scsi_sense_hdr *sshdr, int timeout, int retries)
+ struct scsi_sense_hdr *sshdr, int timeout, int retries,
+ unsigned *residue)
{
char *sense = NULL;
int result;
@@ -229,7 +234,7 @@ int scsi_execute_req(struct scsi_device
return DRIVER_ERROR << 24;
}
result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
- sense, timeout, retries, 0);
+ sense, timeout, retries, 0, residue);
if (sshdr)
scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);

@@ -1815,7 +1820,7 @@ scsi_mode_select(struct scsi_device *sde
}

ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len,
- sshdr, timeout, retries);
+ sshdr, timeout, retries, NULL);
kfree(real_buffer);
return ret;
}
@@ -1880,7 +1885,7 @@ scsi_mode_sense(struct scsi_device *sdev
memset(buffer, 0, len);

result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- sshdr, timeout, retries);
+ sshdr, timeout, retries, NULL);

/* This code looks awful: what it's doing is making sure an
* ILLEGAL REQUEST sense return identifies the actual command
@@ -1962,7 +1967,7 @@ scsi_test_unit_ready(struct scsi_device
/* try to eat the UNIT_ATTENTION if there are enough retries */
do {
result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
- timeout, retries);
+ timeout, retries, NULL);
} while ((driver_byte(result) & DRIVER_SENSE) &&
sshdr && sshdr->sense_key == UNIT_ATTENTION &&
--retries);
Index: usb-2.6/drivers/scsi/scsi_scan.c
===================================================================
--- usb-2.6.orig/drivers/scsi/scsi_scan.c
+++ usb-2.6/drivers/scsi/scsi_scan.c
@@ -216,7 +216,7 @@ static void scsi_unlock_floptical(struct
scsi_cmd[4] = 0x2a; /* size */
scsi_cmd[5] = 0;
scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
- SCSI_TIMEOUT, 3);
+ SCSI_TIMEOUT, 3, NULL);
}

/**
@@ -580,7 +580,8 @@ static int scsi_probe_lun(struct scsi_de

result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
inq_result, try_inquiry_len, &sshdr,
- HZ / 2 + HZ * scsi_inq_timeout, 3);
+ HZ / 2 + HZ * scsi_inq_timeout, 3,
+ NULL);

SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s "
"with code 0x%x\n",
@@ -1376,7 +1377,7 @@ static int scsi_report_lun_scan(struct s

result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
lun_data, length, &sshdr,
- SCSI_TIMEOUT + 4 * HZ, 3);
+ SCSI_TIMEOUT + 4 * HZ, 3, NULL);

SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
" %s (try %d) result 0x%x\n", result
Index: usb-2.6/drivers/scsi/scsi_transport_spi.c
===================================================================
--- usb-2.6.orig/drivers/scsi/scsi_transport_spi.c
+++ usb-2.6/drivers/scsi/scsi_transport_spi.c
@@ -109,7 +109,7 @@ static int spi_execute(struct scsi_devic
for(i = 0; i < DV_RETRIES; i++) {
result = scsi_execute(sdev, cmd, dir, buffer, bufflen,
sense, DV_TIMEOUT, /* retries */ 1,
- REQ_FAILFAST);
+ REQ_FAILFAST, NULL);
if (result & DRIVER_SENSE) {
struct scsi_sense_hdr sshdr_tmp;
if (!sshdr)
Index: usb-2.6/drivers/scsi/sd.c
===================================================================
--- usb-2.6.orig/drivers/scsi/sd.c
+++ usb-2.6/drivers/scsi/sd.c
@@ -842,7 +842,7 @@ static int sd_sync_cache(struct scsi_dis
* flush everything.
*/
res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (res == 0)
break;
}
@@ -1070,7 +1070,7 @@ sd_spinup_disk(struct scsi_disk *sdkp)
the_result = scsi_execute_req(sdkp->device, cmd,
DMA_NONE, NULL, 0,
&sshdr, SD_TIMEOUT,
- SD_MAX_RETRIES);
+ SD_MAX_RETRIES, NULL);

/*
* If the drive has indicated to us that it
@@ -1126,7 +1126,8 @@ sd_spinup_disk(struct scsi_disk *sdkp)
cmd[4] = 1; /* Start spin cycle */
scsi_execute_req(sdkp->device, cmd, DMA_NONE,
NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES,
+ NULL);
spintime_expire = jiffies + 100 * HZ;
spintime = 1;
}
@@ -1199,7 +1200,8 @@ repeat:

the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
buffer, longrc ? 12 : 8, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES,
+ NULL);

if (media_not_present(sdkp, &sshdr))
return;
@@ -1794,7 +1796,7 @@ static int sd_start_stop_device(struct s
return -ENODEV;

res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES);
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (res) {
sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
sd_print_result(sdkp, res);
Index: usb-2.6/drivers/scsi/ses.c
===================================================================
--- usb-2.6.orig/drivers/scsi/ses.c
+++ usb-2.6/drivers/scsi/ses.c
@@ -77,7 +77,7 @@ static int ses_recv_diag(struct scsi_dev
};

return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
- NULL, SES_TIMEOUT, SES_RETRIES);
+ NULL, SES_TIMEOUT, SES_RETRIES, NULL);
}

static int ses_send_diag(struct scsi_device *sdev, int page_code,
@@ -95,7 +95,7 @@ static int ses_send_diag(struct scsi_dev
};

result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen,
- NULL, SES_TIMEOUT, SES_RETRIES);
+ NULL, SES_TIMEOUT, SES_RETRIES, NULL);
if (result)
sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n",
result);
@@ -369,7 +369,8 @@ static void ses_match_to_enclosure(struc
return;

if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf,
- VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES))
+ VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES,
+ NULL))
goto free;

len = (buf[2] << 8) + buf[3];
Index: usb-2.6/drivers/scsi/sr.c
===================================================================
--- usb-2.6.orig/drivers/scsi/sr.c
+++ usb-2.6/drivers/scsi/sr.c
@@ -177,7 +177,7 @@ int sr_test_unit_ready(struct scsi_devic
do {
the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL,
0, sshdr, SR_TIMEOUT,
- retries--);
+ retries--, NULL);

} while (retries > 0 &&
(!scsi_status_is_good(the_result) ||
@@ -687,7 +687,7 @@ static void get_sectorsize(struct scsi_c
/* Do the command and wait.. */
the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE,
buffer, 8, NULL, SR_TIMEOUT,
- MAX_RETRIES);
+ MAX_RETRIES, NULL);

retries--;

Index: usb-2.6/drivers/scsi/sr_ioctl.c
===================================================================
--- usb-2.6.orig/drivers/scsi/sr_ioctl.c
+++ usb-2.6/drivers/scsi/sr_ioctl.c
@@ -207,7 +207,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct pack
memset(sense, 0, sizeof(*sense));
result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
cgc->buffer, cgc->buflen, (char *)sense,
- cgc->timeout, IOCTL_RETRIES, 0);
+ cgc->timeout, IOCTL_RETRIES, 0, NULL);

scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr);

[-- Attachment #3: Type: TEXT/PLAIN, Size: 1104 bytes --]

Index: usb-2.6/drivers/scsi/scsi_lib.c
===================================================================
--- usb-2.6.orig/drivers/scsi/scsi_lib.c
+++ usb-2.6/drivers/scsi/scsi_lib.c
@@ -1852,6 +1852,7 @@ scsi_mode_sense(struct scsi_device *sdev
int use_10_for_ms;
int header_length;
int result;
+ unsigned residue;
struct scsi_sense_hdr my_sshdr;

memset(data, 0, sizeof(*data));
@@ -1885,7 +1886,7 @@ scsi_mode_sense(struct scsi_device *sdev
memset(buffer, 0, len);

result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- sshdr, timeout, retries, NULL);
+ sshdr, timeout, retries, &residue);

/* This code looks awful: what it's doing is making sure an
* ILLEGAL REQUEST sense return identifies the actual command
@@ -1907,6 +1908,8 @@ scsi_mode_sense(struct scsi_device *sdev
}

if(scsi_status_is_good(result)) {
+ if (residue > len - header_length)
+ return SAM_STAT_CHECK_CONDITION;
if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b &&
(modepage == 6 || modepage == 8))) {
/* Initio breakage? */