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

[PATCH] USB storage: use the new transfer_buf() routine

This patch switches from using usb_stor_bulk_msg() to
usb_stor_bulk_transfer_buf(), which includes a great deal more logic.  This
allows for elimination of all sorts of duplicate code (clearing STALLs,
etc.).

This also eliminates the (now) redundant functions from the ISD-200 driver.
parent 88142a11
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
* *
* History: * History:
* *
* 2002-10-19: Removed the specialized transfer routines.
* (Alan Stern <stern@rowland.harvard.edu>)
* 2001-02-24: Removed lots of duplicate code and simplified the structure. * 2001-02-24: Removed lots of duplicate code and simplified the structure.
* (bjorn@haxx.se) * (bjorn@haxx.se)
* 2002-01-16: Fixed endianness bug so it works on the ppc arch. * 2002-01-16: Fixed endianness bug so it works on the ppc arch.
...@@ -386,147 +388,6 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) ...@@ -386,147 +388,6 @@ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb)
} }
} }
/***********************************************************************
* Data transfer routines
***********************************************************************/
/**************************************************************************
* Transfer one SCSI scatter-gather buffer via bulk transfer
*
* Note that this function is necessary because we want the ability to
* use scatter-gather memory. Good performance is achieved by a combination
* of scatter-gather and clustering (which makes each chunk bigger).
*
* Note that the lower layer will always retry when a NAK occurs, up to the
* timeout limit. Thus we don't have to worry about it for individual
* packets.
*/
static int isd200_transfer_partial( struct us_data *us,
unsigned char dataDirection,
char *buf, int length )
{
int result;
int partial;
unsigned int pipe;
/* calculate the appropriate pipe information */
if (dataDirection == SCSI_DATA_READ)
pipe = us->recv_bulk_pipe;
else
pipe = us->send_bulk_pipe;
/* transfer the data */
US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length);
result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
result, partial, length);
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
if (usb_stor_clear_halt(us, pipe) < 0)
return ISD200_TRANSPORT_FAILED;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("isd200_transfer_partial(): transfer complete\n");
return ISD200_TRANSPORT_GOOD;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
return ISD200_TRANSPORT_ABORTED;
}
/* uh oh... we have an error code, so something went wrong. */
if (result) {
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("isd200_transfer_partial(): device NAKed\n");
return ISD200_TRANSPORT_FAILED;
}
/* the catch-all case */
US_DEBUGP("isd200_transfer_partial(): unknown error\n");
return ISD200_TRANSPORT_FAILED;
}
/* no error code, so we must have transferred some data,
* just not all of it */
return ISD200_TRANSPORT_SHORT;
}
/**************************************************************************
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
* Note that this uses us_transfer_partial to achieve it's goals -- this
* function simply determines if we're going to use scatter-gather or not,
* and acts appropriately. For now, it also re-interprets the error codes.
*/
static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb )
{
int i;
int result = -1;
struct scatterlist *sg;
unsigned int total_transferred = 0;
unsigned int transfer_amount;
/* calculate how much we want to transfer */
int dir = srb->sc_data_direction;
srb->sc_data_direction = SCSI_DATA_WRITE;
transfer_amount = usb_stor_transfer_length(srb);
srb->sc_data_direction = dir;
/* was someone foolish enough to request more data than available
* buffer space? */
if (transfer_amount > srb->request_bufflen)
transfer_amount = srb->request_bufflen;
/* are we scatter-gathering? */
if (srb->use_sg) {
/* loop over all the scatter gather structures and
* make the appropriate requests for each, until done
*/
sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
/* transfer the lesser of the next buffer or the
* remaining data */
if (transfer_amount - total_transferred >=
sg[i].length) {
result = isd200_transfer_partial(us,
srb->sc_data_direction,
sg_address(sg[i]),
sg[i].length);
total_transferred += sg[i].length;
} else
result = isd200_transfer_partial(us,
srb->sc_data_direction,
sg_address(sg[i]),
transfer_amount - total_transferred);
/* if we get an error, end the loop here */
if (result)
break;
}
}
else
/* no scatter-gather, just make the request */
result = isd200_transfer_partial(us,
srb->sc_data_direction,
srb->request_buffer,
transfer_amount);
/* return the result in the data structure itself */
srb->result = result;
}
/*********************************************************************** /***********************************************************************
* Transport routines * Transport routines
...@@ -546,23 +407,21 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -546,23 +407,21 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
struct bulk_cb_wrap bcb; struct bulk_cb_wrap bcb;
struct bulk_cs_wrap bcs; struct bulk_cs_wrap bcs;
int result; int result;
int partial; unsigned int transfer_length;
unsigned int transfer_amount;
int dir = srb->sc_data_direction; int dir = srb->sc_data_direction;
srb->sc_data_direction = SCSI_DATA_WRITE; srb->sc_data_direction = SCSI_DATA_WRITE;
transfer_amount = usb_stor_transfer_length(srb); transfer_length = usb_stor_transfer_length(srb);
srb->sc_data_direction = dir; srb->sc_data_direction = dir;
/* set up the command wrapper */ /* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(transfer_amount); bcb.DataTransferLength = cpu_to_le32(transfer_length);
bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number; bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5; bcb.Lun = srb->cmnd[1] >> 5;
if (us->flags & US_FL_SCM_MULT_TARG) if (us->flags & US_FL_SCM_MULT_TARG)
bcb.Lun |= srb->target << 4; bcb.Lun |= srb->target << 4;
bcb.Length = AtaCdbLength; bcb.Length = AtaCdbLength;
/* copy the command payload */ /* copy the command payload */
...@@ -572,33 +431,32 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -572,33 +431,32 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
/* send it to out endpoint */ /* send it to out endpoint */
US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag, le32_to_cpu(bcb.Signature), bcb.Tag,
(bcb.Lun >> 4), (bcb.Lun & 0xFF), (bcb.Lun >> 4), (bcb.Lun & 0x0F),
le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
US_BULK_CB_WRAP_LEN, &partial); (char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result); US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */ /* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED; return ISD200_TRANSPORT_ABORTED;
} }
if (result != USB_STOR_XFER_GOOD)
else if (result == -EPIPE) {
/* if we stall, we need to clear it before we go on */
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
us->send_bulk_pipe);
if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0)
return ISD200_TRANSPORT_ERROR;
} else if (result)
return ISD200_TRANSPORT_ERROR; return ISD200_TRANSPORT_ERROR;
/* if the command transfered well, then we go to the data stage */ /* if the command transfered well, then we go to the data stage */
if (!result && bcb.DataTransferLength) { if (transfer_length) {
isd200_transfer(us, srb); unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ?
US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result); us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_transfer_srb(us, pipe, srb,
if (srb->result == ISD200_TRANSPORT_ABORTED) transfer_length);
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
/* if it was aborted, we need to indicate that */
if (result == USB_STOR_XFER_ABORTED)
return ISD200_TRANSPORT_ABORTED; return ISD200_TRANSPORT_ABORTED;
if (result == USB_STOR_XFER_ERROR)
return ISD200_TRANSPORT_ERROR;
} }
/* See flow chart on pg 15 of the Bulk Only Transport spec for /* See flow chart on pg 15 of the Bulk Only Transport spec for
...@@ -607,42 +465,31 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -607,42 +465,31 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
/* get CSW for device status */ /* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n"); US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
US_BULK_CS_WRAP_LEN, &partial); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */ /* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED; return ISD200_TRANSPORT_ABORTED;
} }
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == -EPIPE) { if (result == USB_STOR_XFER_STALLED) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
us->recv_bulk_pipe);
if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0)
return ISD200_TRANSPORT_ERROR;
/* get the status again */ /* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
US_BULK_CS_WRAP_LEN, &partial); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* if the command was aborted, indicate that */ /* if the command was aborted, indicate that */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED; return ISD200_TRANSPORT_ABORTED;
} }
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n",
us->recv_bulk_pipe);
usb_stor_clear_halt(us, us->recv_bulk_pipe);
return ISD200_TRANSPORT_ERROR;
}
} }
/* if we still have a failure at this point, we're in trouble */ /* if we still have a failure at this point, we're in trouble */
US_DEBUGP("Bulk status result = %d\n", result); US_DEBUGP("Bulk status result = %d\n", result);
if (result) if (result != USB_STOR_XFER_GOOD)
return ISD200_TRANSPORT_ERROR; return ISD200_TRANSPORT_ERROR;
/* check bulk status */ /* check bulk status */
...@@ -651,7 +498,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, ...@@ -651,7 +498,7 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
bcs.Residue, bcs.Status); bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
bcs.Tag != bcb.Tag || bcs.Tag != bcb.Tag ||
bcs.Status > US_BULK_STAT_PHASE || partial != 13) { bcs.Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n"); US_DEBUGP("Bulk logical error\n");
return ISD200_TRANSPORT_ERROR; return ISD200_TRANSPORT_ERROR;
} }
......
...@@ -1296,7 +1296,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1296,7 +1296,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
struct bulk_cs_wrap bcs; struct bulk_cs_wrap bcs;
unsigned int transfer_length = usb_stor_transfer_length(srb); unsigned int transfer_length = usb_stor_transfer_length(srb);
int result; int result;
int partial;
/* set up the command wrapper */ /* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
...@@ -1316,9 +1315,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1316,9 +1315,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
le32_to_cpu(bcb.Signature), bcb.Tag, le32_to_cpu(bcb.Signature), bcb.Tag,
(bcb.Lun >> 4), (bcb.Lun & 0x0F), (bcb.Lun >> 4), (bcb.Lun & 0x0F),
bcb.DataTransferLength, bcb.Flags, bcb.Length); le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
US_BULK_CB_WRAP_LEN, &partial); (char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result); US_DEBUGP("Bulk command transfer result=%d\n", result);
/* did we abort this command? */ /* did we abort this command? */
...@@ -1326,23 +1325,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1326,23 +1325,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
} }
if (result != USB_STOR_XFER_GOOD)
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
us->send_bulk_pipe);
result = usb_stor_clear_halt(us, us->send_bulk_pipe);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
return USB_STOR_TRANSPORT_ERROR;
} else if (result) {
/* unknown error -- we've got a problem */
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
}
/* DATA STAGE */ /* DATA STAGE */
/* send/receive data payload, if there is any */ /* send/receive data payload, if there is any */
...@@ -1366,8 +1350,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1366,8 +1350,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* get CSW for device status */ /* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n"); US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
US_BULK_CS_WRAP_LEN, &partial); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */ /* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
...@@ -1376,50 +1360,24 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1376,50 +1360,24 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
} }
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == -EPIPE) { if (result == USB_STOR_XFER_STALLED) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
us->recv_bulk_pipe);
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
if (result < 0)
return USB_STOR_TRANSPORT_ERROR;
/* get the status again */ /* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
US_BULK_CS_WRAP_LEN, &partial); (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED;
}
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n",
us->recv_bulk_pipe);
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
/* did we abort this command? */ /* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
return USB_STOR_TRANSPORT_ABORTED; return USB_STOR_TRANSPORT_ABORTED;
} }
return USB_STOR_TRANSPORT_ERROR;
}
} }
/* if we still have a failure at this point, we're in trouble */ /* if we still have a failure at this point, we're in trouble */
US_DEBUGP("Bulk status result = %d\n", result); US_DEBUGP("Bulk status result = %d\n", result);
if (result) { if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
}
/* check bulk status */ /* check bulk status */
US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
...@@ -1427,7 +1385,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1427,7 +1385,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
bcs.Residue, bcs.Status); bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
bcs.Tag != bcb.Tag || bcs.Tag != bcb.Tag ||
bcs.Status > US_BULK_STAT_PHASE || partial != 13) { bcs.Status > US_BULK_STAT_PHASE) {
US_DEBUGP("Bulk logical error\n"); US_DEBUGP("Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
......
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