ChangeSet 1.1243.50.9, 2003/06/10 14:35:30-07:00, mdharm-usb@one-eyed-alien.net [PATCH] USB: usb-storage: handle babble This patch introduces some handling for babble conditions. Basically, once a babble is detected, we return sense data saying the command was invalid. We also go on to transfer the CSW (for BBB transport) so we stay in phase with the device. This isn't guaranteed to work with every device that babbles, but it can't hurt compared to the current behavior. Properly operating devices are unaffected by this patch. drivers/usb/storage/transport.c | 34 ++++++++++++++++++++++++++++++++-- drivers/usb/storage/transport.h | 6 ++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Tue Jun 10 17:11:37 2003 +++ b/drivers/usb/storage/transport.c Tue Jun 10 17:11:37 2003 @@ -48,6 +48,7 @@ #include #include "transport.h" #include "protocol.h" +#include "scsiglue.h" #include "usb.h" #include "debug.h" @@ -303,6 +304,11 @@ US_DEBUGP("-- device NAKed\n"); return USB_STOR_XFER_ERROR; + /* babble - the device tried to send more than we wanted to read */ + case -EOVERFLOW: + US_DEBUGP("-- Babble\n"); + return USB_STOR_XFER_LONG; + /* the transfer was cancelled, presumably by an abort */ case -ECONNRESET: US_DEBUGP("-- transfer cancelled\n"); @@ -525,6 +531,12 @@ return; } + /* if the transport provided its own sense data, don't auto-sense */ + if (result == USB_STOR_TRANSPORT_NO_SENSE) { + srb->result = SAM_STAT_CHECK_CONDITION; + return; + } + /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible @@ -764,7 +776,7 @@ srb->request_buffer, transfer_length, srb->use_sg, &srb->resid); US_DEBUGP("CBI data stage result is 0x%x\n", result); - if (result == USB_STOR_XFER_ERROR) + if (result > USB_STOR_XFER_STALLED) return USB_STOR_TRANSPORT_ERROR; } @@ -854,7 +866,7 @@ srb->request_buffer, transfer_length, srb->use_sg, &srb->resid); US_DEBUGP("CB data stage result is 0x%x\n", result); - if (result == USB_STOR_XFER_ERROR) + if (result > USB_STOR_XFER_STALLED) return USB_STOR_TRANSPORT_ERROR; } @@ -899,6 +911,7 @@ struct bulk_cs_wrap bcs; unsigned int transfer_length = srb->request_bufflen; int result; + int fake_sense = 0; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); @@ -936,6 +949,15 @@ US_DEBUGP("Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; + + /* If the device tried to send back more data than the + * amount requested, the spec requires us to transfer + * the CSW anyway. Since there's no point retrying the + * the command, we'll return fake sense data indicating + * Illegal Request, Invalid Field in CDB. + */ + if (result == USB_STOR_XFER_LONG) + fake_sense = 1; } /* See flow chart on pg 15 of the Bulk Only Transport spec for @@ -975,6 +997,14 @@ /* based on the status code, we report good or bad */ switch (bcs.Status) { case US_BULK_STAT_OK: + /* device babbled -- return fake sense data */ + if (fake_sense) { + memcpy(srb->sense_buffer, + usb_stor_sense_invalidCDB, + sizeof(usb_stor_sense_invalidCDB)); + return USB_STOR_TRANSPORT_NO_SENSE; + } + /* command good -- note that data could be short */ return USB_STOR_TRANSPORT_GOOD; diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Tue Jun 10 17:11:37 2003 +++ b/drivers/usb/storage/transport.h Tue Jun 10 17:11:37 2003 @@ -122,7 +122,8 @@ #define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_SHORT 1 /* transferred less than expected */ #define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ -#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */ +#define USB_STOR_XFER_LONG 3 /* device tried to send too much */ +#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */ /* * Transport return codes @@ -130,7 +131,8 @@ #define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ #define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ +#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */ +#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */ /* * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED