summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-07-29 11:58:06 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-13 17:32:50 -0700
commit59f4ff2ecff4cef36378928cec891785b402e80c (patch)
treeb49428f1fd19f26c75ed3e2d6994ba72d3a3d190 /drivers
parent1a21175a615ed346e8043f5e9d60a672266b84b4 (diff)
usb-storage: automatically recognize bad residues
This patch (as1119) 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/storage/transport.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index fcbbfdb7b2b0..3523a0bfa0ff 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1032,8 +1032,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->fflags & US_FL_IGNORE_RESIDUE)) {
+ if (residue && !(us->fflags & 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->fflags |= US_FL_IGNORE_RESIDUE;
+
+ } else {
residue = min(residue, transfer_length);
scsi_set_resid(srb, max(scsi_get_resid(srb),
(int) residue));