]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
usb-storage: automatically recognize bad residues
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 5 Aug 2008 14:46:23 +0000 (10:46 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 20 Aug 2008 18:05:14 +0000 (11:05 -0700)
commit 59f4ff2ecff4cef36378928cec891785b402e80c upstream

This patch (as1119b) will help to reduce the clutter of usb-storage's
unusual_devs file by automatically detecting some devices that need
the IGNORE_RESIDUE flag.  The idea is that devices should never return
a non-zero residue for an INQUIRY or a READ CAPACITY command unless
they failed to transfer all the requested data.  So if one of these
commands transfers a standard amount of data but there is a positive
residue, we know that the residue is bogus and we can set the flag.

This fixes the problems reported in Bugzilla #11125.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Matthew Frost <artusemrys@sbcglobal.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/storage/transport.c

index 6610d2dd1e7f4f099261788321765b486300ca47..f2062e171f88c37b82857ec28527a4b550b52558 100644 (file)
@@ -1034,8 +1034,21 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 
        /* try to compute the actual residue, based on how much data
         * was really transferred and what the device tells us */
-       if (residue) {
-               if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
+       if (residue && !(us->flags & US_FL_IGNORE_RESIDUE)) {
+
+               /* Heuristically detect devices that generate bogus residues
+                * by seeing what happens with INQUIRY and READ CAPACITY
+                * commands.
+                */
+               if (bcs->Status == US_BULK_STAT_OK &&
+                               scsi_get_resid(srb) == 0 &&
+                                       ((srb->cmnd[0] == INQUIRY &&
+                                               transfer_length == 36) ||
+                                       (srb->cmnd[0] == READ_CAPACITY &&
+                                               transfer_length == 8))) {
+                       us->flags |= US_FL_IGNORE_RESIDUE;
+
+               } else {
                        residue = min(residue, transfer_length);
                        scsi_set_resid(srb, max(scsi_get_resid(srb),
                                                               (int) residue));