From 011b15df465745474e3ec85482633685933ed5a7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 4 Nov 2008 11:29:27 -0500 Subject: USB: change interface to usb_lock_device_for_reset() This patch (as1161) changes the interface to usb_lock_device_for_reset(). The existing interface is apparently not very clear, judging from the fact that several of its callers don't use it correctly. The new interface always returns 0 for success and it always requires the caller to unlock the device afterward. The new routine will not return immediately if it is called while the driver's probe method is running. Instead it will wait until the probe is over and the device has been unlocked. This shouldn't cause any problems; I don't know of any cases where drivers call usb_lock_device_for_reset() during probe. Signed-off-by: Alan Stern Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/usb/storage/transport.c') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 79108d5..2058db4 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1173,10 +1173,9 @@ int usb_stor_Bulk_reset(struct us_data *us) */ int usb_stor_port_reset(struct us_data *us) { - int result, rc_lock; + int result; - result = rc_lock = - usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); + result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); if (result < 0) US_DEBUGP("unable to lock device for reset: %d\n", result); else { @@ -1189,8 +1188,7 @@ int usb_stor_port_reset(struct us_data *us) US_DEBUGP("usb_reset_device returns %d\n", result); } - if (rc_lock) - usb_unlock_device(us->pusb_dev); + usb_unlock_device(us->pusb_dev); } return result; } -- cgit v1.1 From 1537e0ad944acf3a4c2b311a646d7993b89499f7 Mon Sep 17 00:00:00 2001 From: Ben Efros Date: Tue, 18 Nov 2008 13:31:13 -0800 Subject: USB: storage devices and SAT Add the SANE SENSE flag to indicate that a device is capable of handling more than 18-bytes of sense data. This functionality is required for USB-ATA bridges implementing SAT. A future patch will actually enable this function for several devices. The logic behind this is that we can detect support for SANE_SENSE in a few ways: 1) ATA PASS THROUGH (12) or (16) execute successfully 2) SPC-3 or higher is in use 3) A previous CHECK CONDITION occurred with sense format 70-73 and had a length greater than 18-bytes total Signed-off-by: Ben Efros Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/usb/storage/transport.c') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 2058db4..f584e72 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -579,6 +579,20 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) } /* + * Determine if this device is SAT by seeing if the + * command executed successfully. Otherwise we'll have + * to wait for at least one CHECK_CONDITION to determine + * SANE_SENSE support + */ + if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && + result == USB_STOR_TRANSPORT_GOOD && + !(us->fflags & US_FL_SANE_SENSE) && + !(srb->cmnd[2] & 0x20)) { + US_DEBUGP("-- SAT supported, increasing auto-sense\n"); + us->fflags |= US_FL_SANE_SENSE; + } + + /* * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ @@ -595,10 +609,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) if (need_auto_sense) { int temp_result; struct scsi_eh_save ses; + int sense_size = US_SENSE_SIZE; + + /* device supports and needs bigger sense buffer */ + if (us->fflags & US_FL_SANE_SENSE) + sense_size = ~0; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); - scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); + scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); /* FIXME: we must do the protocol translation here */ if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI || @@ -632,6 +651,25 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) return; } + /* If the sense data returned is larger than 18-bytes then we + * assume this device supports requesting more in the future. + * The response code must be 70h through 73h inclusive. + */ + if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && + !(us->fflags & US_FL_SANE_SENSE) && + (srb->sense_buffer[0] & 0x7C) == 0x70) { + US_DEBUGP("-- SANE_SENSE support enabled\n"); + us->fflags |= US_FL_SANE_SENSE; + + /* Indicate to the user that we truncated their sense + * because we didn't know it supported larger sense. + */ + US_DEBUGP("-- Sense data truncated to %i from %i\n", + US_SENSE_SIZE, + srb->sense_buffer[7] + 8); + srb->sense_buffer[7] = (US_SENSE_SIZE - 8); + } + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], -- cgit v1.1 From 64648a9dc4d7ac0189364188207310ec6bc75bbe Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 20 Nov 2008 14:20:03 -0500 Subject: USB: usb-storage: merge CB and CBI transport routines This patch (as1173) merges usb-storage's CB and CBI transports into a single routine. So much of their code is common, it's silly to keep them separate. Signed-off-by: Alan Stern CC: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 61 ++++++----------------------------------- 1 file changed, 9 insertions(+), 52 deletions(-) (limited to 'drivers/usb/storage/transport.c') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index f584e72..9cc30af 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -756,10 +756,10 @@ void usb_stor_stop_transport(struct us_data *us) } /* - * Control/Bulk/Interrupt transport + * Control/Bulk and Control/Bulk/Interrupt transport */ -int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) +int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = scsi_bufflen(srb); unsigned int pipe = 0; @@ -801,6 +801,13 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) } /* STATUS STAGE */ + + /* NOTE: CB does not have a status stage. Silly, I know. So + * we have to catch this at a higher level. + */ + if (us->protocol != US_PR_CBI) + return USB_STOR_TRANSPORT_GOOD; + result = usb_stor_intr_transfer(us, us->iobuf, 2); US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", us->iobuf[0], us->iobuf[1]); @@ -855,56 +862,6 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) } /* - * Control/Bulk transport - */ -int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - unsigned int transfer_length = scsi_bufflen(srb); - int result; - - /* COMMAND STAGE */ - /* let's send the command via the control pipe */ - result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - us->ifnum, srb->cmnd, srb->cmd_len); - - /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - - /* if we stalled the command, it means command failed */ - if (result == USB_STOR_XFER_STALLED) { - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - if (result != USB_STOR_XFER_GOOD) { - return USB_STOR_TRANSPORT_ERROR; - } - - /* DATA STAGE */ - /* transfer the data payload for this command, if one exists*/ - if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? - us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_srb(us, pipe, srb); - US_DEBUGP("CB data stage result is 0x%x\n", result); - - /* if we stalled the data transfer it means command failed */ - if (result == USB_STOR_XFER_STALLED) - return USB_STOR_TRANSPORT_FAILED; - if (result > USB_STOR_XFER_STALLED) - return USB_STOR_TRANSPORT_ERROR; - } - - /* STATUS STAGE */ - /* NOTE: CB does not have a status stage. Silly, I know. So - * we have to catch this at a higher level. - */ - return USB_STOR_TRANSPORT_GOOD; -} - -/* * Bulk only transport */ -- cgit v1.1 From 25ff1c316f6a763f1eefe7f8984b2d8c03888432 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 15 Dec 2008 12:43:41 -0500 Subject: USB: storage: add last-sector hacks This patch (as1189b) adds some hacks to usb-storage for dealing with the growing problems involving bad capacity values and last-sector accesses: A new flag, US_FL_CAPACITY_OK, is created to indicate that the device is known to report its capacity correctly. An unusual_devs entry for Linux's own File-backed Storage Gadget is added with this flag set, since g_file_storage always reports the correct capacity and since the capacity need not be even (it is determined by the size of the backing file). An entry in unusual_devs.h which has only the CAPACITY_OK flag set shouldn't prejudice libusual, since the device will work perfectly well with either usb-storage or ub. So a new macro, COMPLIANT_DEV, is added to let libusual know about these entries. When a last-sector access succeeds and the total number of sectors is odd (the unexpected case, in which guessing that the number is even might cause trouble), a WARN is triggered. The kerneloops.org project will collect these warnings, allowing us to add CAPACITY_OK flags for the devices in question before implementing the default-to-even heuristic. If users want to prevent the stack dump produced by the WARN, they can disable the hack by adding an unusual_devs entry for their device with the CAPACITY_OK flag. When a last-sector access fails three times in a row and neither the FIX_CAPACITY nor the CAPACITY_OK flag is set, we assume the last-sector bug is present. We replace the existing status and sense data with values that will cause the SCSI core to fail the access immediately rather than retry indefinitely. This should fix the difficulties people have been having with Nokia phones. Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 110 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers/usb/storage/transport.c') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 9cc30af..1d5438e 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -57,6 +57,9 @@ #include "scsiglue.h" #include "debug.h" +#include +#include "../../scsi/sd.h" + /*********************************************************************** * Data transfer routines @@ -511,6 +514,110 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, * Transport routines ***********************************************************************/ +/* There are so many devices that report the capacity incorrectly, + * this routine was written to counteract some of the resulting + * problems. + */ +static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) +{ + struct gendisk *disk; + struct scsi_disk *sdkp; + u32 sector; + + /* To Report "Medium Error: Record Not Found */ + static unsigned char record_not_found[18] = { + [0] = 0x70, /* current error */ + [2] = MEDIUM_ERROR, /* = 0x03 */ + [7] = 0x0a, /* additional length */ + [12] = 0x14 /* Record Not Found */ + }; + + /* If last-sector problems can't occur, whether because the + * capacity was already decremented or because the device is + * known to report the correct capacity, then we don't need + * to do anything. + */ + if (!us->use_last_sector_hacks) + return; + + /* Was this command a READ(10) or a WRITE(10)? */ + if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10) + goto done; + + /* Did this command access the last sector? */ + sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) | + (srb->cmnd[4] << 8) | (srb->cmnd[5]); + disk = srb->request->rq_disk; + if (!disk) + goto done; + sdkp = scsi_disk(disk); + if (!sdkp) + goto done; + if (sector + 1 != sdkp->capacity) + goto done; + + if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) { + + /* The command succeeded. If the capacity is odd + * (i.e., if the sector number is even) then the + * "always-even" heuristic would be wrong for this + * device. Issue a WARN() so that the kerneloops.org + * project will be notified and we will then know to + * mark the device with a CAPACITY_OK flag. Hopefully + * this will occur for only a few devices. + * + * Use the sign of us->last_sector_hacks to tell whether + * the warning has already been issued; we don't need + * more than one warning per device. + */ + if (!(sector & 1) && us->use_last_sector_hacks > 0) { + unsigned vid = le16_to_cpu( + us->pusb_dev->descriptor.idVendor); + unsigned pid = le16_to_cpu( + us->pusb_dev->descriptor.idProduct); + unsigned rev = le16_to_cpu( + us->pusb_dev->descriptor.bcdDevice); + + WARN(1, "%s: Successful last sector success at %u, " + "device %04x:%04x:%04x\n", + sdkp->disk->disk_name, sector, + vid, pid, rev); + us->use_last_sector_hacks = -1; + } + + } else { + /* The command failed. Allow up to 3 retries in case this + * is some normal sort of failure. After that, assume the + * capacity is wrong and we're trying to access the sector + * beyond the end. Replace the result code and sense data + * with values that will cause the SCSI core to fail the + * command immediately, instead of going into an infinite + * (or even just a very long) retry loop. + */ + if (++us->last_sector_retries < 3) + return; + srb->result = SAM_STAT_CHECK_CONDITION; + memcpy(srb->sense_buffer, record_not_found, + sizeof(record_not_found)); + + /* In theory we might want to issue a WARN() here if the + * capacity is even, since it could indicate the device + * has the READ CAPACITY bug _and_ the real capacity is + * odd. But it could also indicate that the device + * simply can't access its last sector, a failure mode + * which is surprisingly common. So no warning. + */ + } + + done: + /* Don't reset the retry counter for TEST UNIT READY commands, + * because they get issued after device resets which might be + * caused by a failed last-sector access. + */ + if (srb->cmnd[0] != TEST_UNIT_READY) + us->last_sector_retries = 0; +} + /* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to @@ -544,6 +651,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* if the transport provided its own sense data, don't auto-sense */ if (result == USB_STOR_TRANSPORT_NO_SENSE) { srb->result = SAM_STAT_CHECK_CONDITION; + last_sector_hacks(us, srb); return; } @@ -705,6 +813,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); + last_sector_hacks(us, srb); return; /* Error and abort processing: try to resynchronize with the device @@ -732,6 +841,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) us->transport_reset(us); } clear_bit(US_FLIDX_RESETTING, &us->dflags); + last_sector_hacks(us, srb); } /* Stop the current URB transfer */ -- cgit v1.1