diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-08-05 10:46:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-20 11:05:14 -0700 |
commit | 978e8c75a78d16d933dfa471fa247e7e61c9f7a4 (patch) | |
tree | 6b9448aedb68db6f0d0f3af790f6ba796afcc6a6 /drivers | |
parent | b0d87b9307f9e4b5803a3cad3ad00bee4beb1966 (diff) | |
download | linux-stable-978e8c75a78d16d933dfa471fa247e7e61c9f7a4.tar.gz |
usb-storage: automatically recognize bad residues
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/storage/transport.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 6610d2dd1e7f..f2062e171f88 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -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)); |