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, 18 Dec 2009 22:03:59 +0000 (14:03 -0800)
commit a0bb108112a872c0b0c4b3ef4974f95fb75b155d upstream.

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>
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 9107b387e91fce095ee320dbeed53d5dfe5cb332..5bc4eaaa5b7fb302d51548c385b25ccd5569c4b3 100644 (file)
@@ -2645,6 +2645,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 11876c3b90000971b0d306e89927b2cae807403d..716c8d7885fa65a90893913fc45b9ae32574a3ff 100644 (file)
@@ -460,6 +460,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 };