On Sat, 14 Jun 2008, Maciej Rutecki wrote: > 2008/6/13 Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>: > > [...] > > > > > 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
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);
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? */