Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59f4ff2e authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 1a21175a
Loading
Loading
Loading
Loading
+15 −2
Original line number Original line Diff line number Diff line
@@ -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
	/* try to compute the actual residue, based on how much data
	 * was really transferred and what the device tells us */
	 * was really transferred and what the device tells us */
	if (residue) {
	if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
		if (!(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);
			residue = min(residue, transfer_length);
			scsi_set_resid(srb, max(scsi_get_resid(srb),
			scsi_set_resid(srb, max(scsi_get_resid(srb),
			                                       (int) residue));
			                                       (int) residue));