Commit af62566f authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB storage: Issue CBI clear_halt and fix BBB residue

This patch does 2 things (bad, I know -- but they're both pretty small
and pretty obscure).

The CBI specification states in section 2.4.3.1.3 that

	... the host shall also issue Clear Feature for Endpoint Halt
	to the Bulk In pipe if the device reports that the Data In
	command block has Failed.

along with a note in section 2.5.3 that Data Out commands should work
analogously.  This patch does that, along with cleaning up the status
detection logic a little.

For Bulk-only transfers we currently ignore the dResidue field in the CSW,
except for reporting it (without byte-swapping!) in a debug message.  The
patch uses it to compute the residue value returned to the SCSI layer.
Note that the Bulk-only spec allows devices to transfer more data than
they actually use (i.e., they may add padding or ignore stuff) and then
inform the host of this by means of the dResidue value.  The logic used is
simple: our reported residue is the larger of what the device claims and
what we didn't transfer, except that it can't be larger than the total
transfer length.
parent 78dd3042
...@@ -760,6 +760,7 @@ void usb_stor_stop_transport(struct us_data *us) ...@@ -760,6 +760,7 @@ void usb_stor_stop_transport(struct us_data *us)
int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
{ {
unsigned int transfer_length = srb->request_bufflen; unsigned int transfer_length = srb->request_bufflen;
unsigned int pipe = 0;
int result; int result;
/* COMMAND STAGE */ /* COMMAND STAGE */
...@@ -785,7 +786,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -785,7 +786,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* DATA STAGE */ /* DATA STAGE */
/* transfer the data payload for this command, if one exists*/ /* transfer the data payload for this command, if one exists*/
if (transfer_length) { if (transfer_length) {
unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? pipe = srb->sc_data_direction == SCSI_DATA_READ ?
us->recv_bulk_pipe : us->send_bulk_pipe; us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_transfer_sg(us, pipe, result = usb_stor_bulk_transfer_sg(us, pipe,
srb->request_buffer, transfer_length, srb->request_buffer, transfer_length,
...@@ -813,13 +814,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -813,13 +814,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == REQUEST_SENSE || if (srb->cmnd[0] == REQUEST_SENSE ||
srb->cmnd[0] == INQUIRY) srb->cmnd[0] == INQUIRY)
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
else {
if (us->iobuf[0]) if (us->iobuf[0])
return USB_STOR_TRANSPORT_FAILED; goto Failed;
else
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
} }
}
/* If not UFI, we interpret the data as a result code /* If not UFI, we interpret the data as a result code
* The first byte should always be a 0x0 * The first byte should always be a 0x0
...@@ -835,13 +833,17 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -835,13 +833,17 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
case 0x00: case 0x00:
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
case 0x01: case 0x01:
return USB_STOR_TRANSPORT_FAILED; goto Failed;
default:
return USB_STOR_TRANSPORT_ERROR;
} }
/* we should never get here, but if we do, we're in trouble */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
/* the CBI spec requires that the bulk pipe must be cleared
* following any data-in/out command failure (section 2.4.3.1.3)
*/
Failed:
if (pipe)
usb_stor_clear_halt(us, pipe);
return USB_STOR_TRANSPORT_FAILED;
} }
/* /*
...@@ -924,6 +926,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -924,6 +926,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
unsigned int transfer_length = srb->request_bufflen; unsigned int transfer_length = srb->request_bufflen;
unsigned int residue;
int result; int result;
int fake_sense = 0; int fake_sense = 0;
...@@ -999,9 +1002,10 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -999,9 +1002,10 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
/* check bulk status */ /* check bulk status */
US_DEBUGP("Bulk Status S 0x%x T 0x%x R %d Stat 0x%x\n", residue = le32_to_cpu(bcs->Residue);
US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
le32_to_cpu(bcs->Signature), bcs->Tag, le32_to_cpu(bcs->Signature), bcs->Tag,
bcs->Residue, bcs->Status); residue, bcs->Status);
if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) &&
bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) || bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) ||
bcs->Tag != srb->serial_number || bcs->Tag != srb->serial_number ||
...@@ -1010,6 +1014,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1010,6 +1014,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
residue = min(residue, transfer_length);
srb->resid = max(srb->resid, (int) residue);
/* based on the status code, we report good or bad */ /* based on the status code, we report good or bad */
switch (bcs->Status) { switch (bcs->Status) {
case US_BULK_STAT_OK: case US_BULK_STAT_OK:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment