]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
USB: usb-storage: add BAD_SENSE flag
authorAlan Stern <stern@rowland.harvard.edu>
Mon, 7 Dec 2009 21:39:16 +0000 (16:39 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 19:55:26 +0000 (11:55 -0800)
This patch (as1311) fixes a problem in usb-storage: Some devices are
pretty broken when it comes to reporting sense data.  The information
they send back indicates that they have more than 18 bytes of sense
data available, but when the system asks for more than 18 they fail or
hang.  The symptom is that probing fails with multiple resets.

The patch adds a new BAD_SENSE flag to indicate that usb-storage
should never ask for more than 18 bytes of sense data.  The flag can
be set in an unusual_devs entry or via the "quirks=" module parameter,
and it is set automatically whenever a REQUEST SENSE command for more
than 18 bytes fails or times out.

An unusual_devs entry is added for the Agfa photo frame, which uses a
Prolific chip having this bug.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Daniel Kukula <daniel.kuku@gmail.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Documentation/kernel-parameters.txt
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
include/linux/usb_usual.h

index 777dc8a32df8d077fc9bdca101a071d3c7f97294..3f886e298f62bf6e32c870fc4df568769aeb5db2 100644 (file)
@@ -2663,6 +2663,8 @@ and is between 256 and 4096 characters. It is defined in the file
                        to a common usb-storage quirk flag as follows:
                                a = SANE_SENSE (collect more than 18 bytes
                                        of sense data);
+                               b = BAD_SENSE (don't collect more than 18
+                                       bytes of sense data);
                                c = FIX_CAPACITY (decrease the reported
                                        device capacity by one sector);
                                h = CAPACITY_HEURISTICS (decrease the
index 589f6b4404f0b1550718c66353ec4c807c0a46ac..cc313d16d727d0dc827627835d380249f638ab9c 100644 (file)
@@ -666,10 +666,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
         * to wait for at least one CHECK_CONDITION to determine
         * SANE_SENSE support
         */
-       if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
+       if (unlikely((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->fflags & US_FL_BAD_SENSE) &&
+           !(srb->cmnd[2] & 0x20))) {
                US_DEBUGP("-- SAT supported, increasing auto-sense\n");
                us->fflags |= US_FL_SANE_SENSE;
        }
@@ -718,6 +719,12 @@ Retry_Sense:
                if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
                        US_DEBUGP("-- auto-sense aborted\n");
                        srb->result = DID_ABORT << 16;
+
+                       /* If SANE_SENSE caused this problem, disable it */
+                       if (sense_size != US_SENSE_SIZE) {
+                               us->fflags &= ~US_FL_SANE_SENSE;
+                               us->fflags |= US_FL_BAD_SENSE;
+                       }
                        goto Handle_Errors;
                }
 
@@ -727,10 +734,11 @@ Retry_Sense:
                 * (small) sense request. This fixes some USB GSM modems
                 */
                if (temp_result == USB_STOR_TRANSPORT_FAILED &&
-                   (us->fflags & US_FL_SANE_SENSE) &&
-                   sense_size != US_SENSE_SIZE) {
+                               sense_size != US_SENSE_SIZE) {
                        US_DEBUGP("-- auto-sense failure, retry small sense\n");
                        sense_size = US_SENSE_SIZE;
+                       us->fflags &= ~US_FL_SANE_SENSE;
+                       us->fflags |= US_FL_BAD_SENSE;
                        goto Retry_Sense;
                }
 
@@ -754,6 +762,7 @@ Retry_Sense:
                 */
                if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) &&
                    !(us->fflags & US_FL_SANE_SENSE) &&
+                   !(us->fflags & US_FL_BAD_SENSE) &&
                    (srb->sense_buffer[0] & 0x7C) == 0x70) {
                        US_DEBUGP("-- SANE_SENSE support enabled\n");
                        us->fflags |= US_FL_SANE_SENSE;
index d4f034ebaa8a44080af462b8876ecbc632c62cee..64a0a2c27e12b4478734ae9683fead5750abfe67 100644 (file)
@@ -818,6 +818,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
+/* Reported by Daniel Kukula <daniel.kuku@gmail.com> */
+UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100,
+               "Prolific Technology, Inc.",
+               "Prolific Storage Gadget",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_BAD_SENSE ),
+
 /* Reported by Rogerio Brito <rbrito@ime.usp.br> */
 UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001,
                "Prolific Technology, Inc.",
index 1599d86154c471395f199a090c1bace80532e667..f5c0264caa3317a1b681d085d09d64af6050ddc1 100644 (file)
@@ -463,6 +463,9 @@ static void adjust_quirks(struct us_data *us)
                case 'a':
                        f |= US_FL_SANE_SENSE;
                        break;
+               case 'b':
+                       f |= US_FL_BAD_SENSE;
+                       break;
                case 'c':
                        f |= US_FL_FIX_CAPACITY;
                        break;
index 3d15fb9bc116fbba8f03612b9af2fae6b34ba8bf..a4b947e470a59b9a191e55edab3a0fdd24a2a469 100644 (file)
@@ -56,7 +56,9 @@
        US_FLAG(SANE_SENSE,     0x00008000)                     \
                /* Sane Sense (> 18 bytes) */                   \
        US_FLAG(CAPACITY_OK,    0x00010000)                     \
-               /* READ CAPACITY response is correct */
+               /* READ CAPACITY response is correct */         \
+       US_FLAG(BAD_SENSE,      0x00020000)                     \
+               /* Bad Sense (never more than 18 bytes) */
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };