| From 93c9bf4d1838d5851a18ca398b0ad66397f05056 Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Fri, 31 Oct 2014 14:49:47 -0400 |
| Subject: usb-storage: handle a skipped data phase |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit 93c9bf4d1838d5851a18ca398b0ad66397f05056 upstream. |
| |
| Sometimes mass-storage devices using the Bulk-only transport will |
| mistakenly skip the data phase of a command. Rather than sending the |
| data expected by the host or sending a zero-length packet, they go |
| directly to the status phase and send the CSW. |
| |
| This causes problems for usb-storage, for obvious reasons. The driver |
| will interpret the CSW as a short data transfer and will wait to |
| receive a CSW. The device won't have anything left to send, so the |
| command eventually times out. |
| |
| The SCSI layer doesn't retry commands after they time out (this is a |
| relatively recent change). Therefore we should do our best to detect |
| a skipped data phase and handle it promptly. |
| |
| This patch adds code to do that. If usb-storage receives a short |
| 13-byte data transfer from the device, and if the first four bytes of |
| the data match the CSW signature, the driver will set the residue to |
| the full transfer length and interpret the data as a CSW. |
| |
| This fixes Bugzilla #86611. |
| |
| Signed-off-by: Alan Stern <stern@rowland.harvard.edu> |
| CC: Matthew Dharm <mdharm-usb@one-eyed-alien.net> |
| Tested-by: Paul Osmialowski <newchief@king.net.pl> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/storage/transport.c | 26 ++++++++++++++++++++++++++ |
| 1 file changed, 26 insertions(+) |
| |
| --- a/drivers/usb/storage/transport.c |
| +++ b/drivers/usb/storage/transport.c |
| @@ -1118,6 +1118,31 @@ int usb_stor_Bulk_transport(struct scsi_ |
| */ |
| if (result == USB_STOR_XFER_LONG) |
| fake_sense = 1; |
| + |
| + /* |
| + * Sometimes a device will mistakenly skip the data phase |
| + * and go directly to the status phase without sending a |
| + * zero-length packet. If we get a 13-byte response here, |
| + * check whether it really is a CSW. |
| + */ |
| + if (result == USB_STOR_XFER_SHORT && |
| + srb->sc_data_direction == DMA_FROM_DEVICE && |
| + transfer_length - scsi_get_resid(srb) == |
| + US_BULK_CS_WRAP_LEN) { |
| + struct scatterlist *sg = NULL; |
| + unsigned int offset = 0; |
| + |
| + if (usb_stor_access_xfer_buf((unsigned char *) bcs, |
| + US_BULK_CS_WRAP_LEN, srb, &sg, |
| + &offset, FROM_XFER_BUF) == |
| + US_BULK_CS_WRAP_LEN && |
| + bcs->Signature == |
| + cpu_to_le32(US_BULK_CS_SIGN)) { |
| + usb_stor_dbg(us, "Device skipped data phase\n"); |
| + scsi_set_resid(srb, transfer_length); |
| + goto skipped_data_phase; |
| + } |
| + } |
| } |
| |
| /* See flow chart on pg 15 of the Bulk Only Transport spec for |
| @@ -1153,6 +1178,7 @@ int usb_stor_Bulk_transport(struct scsi_ |
| if (result != USB_STOR_XFER_GOOD) |
| return USB_STOR_TRANSPORT_ERROR; |
| |
| + skipped_data_phase: |
| /* check bulk status */ |
| residue = le32_to_cpu(bcs->Residue); |
| usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", |