ChangeSet 1.855.9.13, 2002/11/05 11:17:41-08:00, stern@rowland.harvard.edu [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. diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Tue Nov 5 16:10:14 2002 +++ b/drivers/usb/storage/isd200.c Tue Nov 5 16:10:14 2002 @@ -31,6 +31,8 @@ * * History: * + * 2002-10-19: Removed the specialized transfer routines. + * (Alan Stern ) * 2001-02-24: Removed lots of duplicate code and simplified the structure. * (bjorn@haxx.se) * 2002-01-16: Fixed endianness bug so it works on the ppc arch. @@ -386,147 +388,6 @@ } } -/*********************************************************************** - * 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 @@ -546,23 +407,21 @@ struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; - int partial; - unsigned int transfer_amount; + unsigned int transfer_length; int dir = srb->sc_data_direction; 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; /* set up the command wrapper */ 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.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; if (us->flags & US_FL_SCM_MULT_TARG) bcb.Lun |= srb->target << 4; - bcb.Length = AtaCdbLength; /* copy the command payload */ @@ -572,33 +431,32 @@ /* 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", 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); - result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, - US_BULK_CB_WRAP_LEN, &partial); + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + (char *) &bcb, US_BULK_CB_WRAP_LEN, NULL); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { return ISD200_TRANSPORT_ABORTED; } - - 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) + if (result != USB_STOR_XFER_GOOD) return ISD200_TRANSPORT_ERROR; /* if the command transfered well, then we go to the data stage */ - if (!result && bcb.DataTransferLength) { - isd200_transfer(us, srb); - US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result); - - if (srb->result == ISD200_TRANSPORT_ABORTED) + if (transfer_length) { + unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + us->recv_bulk_pipe : us->send_bulk_pipe; + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + 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; + if (result == USB_STOR_XFER_ERROR) + return ISD200_TRANSPORT_ERROR; } /* See flow chart on pg 15 of the Bulk Only Transport spec for @@ -607,42 +465,31 @@ /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, - US_BULK_CS_WRAP_LEN, &partial); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); + /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { return ISD200_TRANSPORT_ABORTED; } /* did the attempt to read the CSW fail? */ - if (result == -EPIPE) { - 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; + if (result == USB_STOR_XFER_STALLED) { /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, - US_BULK_CS_WRAP_LEN, &partial); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); /* if the command was aborted, indicate that */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { 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 */ US_DEBUGP("Bulk status result = %d\n", result); - if (result) + if (result != USB_STOR_XFER_GOOD) return ISD200_TRANSPORT_ERROR; /* check bulk status */ @@ -651,7 +498,7 @@ bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { + bcs.Status > US_BULK_STAT_PHASE) { US_DEBUGP("Bulk logical error\n"); return ISD200_TRANSPORT_ERROR; } diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Tue Nov 5 16:10:14 2002 +++ b/drivers/usb/storage/transport.c Tue Nov 5 16:10:14 2002 @@ -1296,7 +1296,6 @@ struct bulk_cs_wrap bcs; unsigned int transfer_length = usb_stor_transfer_length(srb); int result; - int partial; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); @@ -1316,9 +1315,9 @@ 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, (bcb.Lun >> 4), (bcb.Lun & 0x0F), - bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, - US_BULK_CB_WRAP_LEN, &partial); + le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + (char *) &bcb, US_BULK_CB_WRAP_LEN, NULL); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -1326,23 +1325,8 @@ US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } - - /* 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 */ + if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - } /* DATA STAGE */ /* send/receive data payload, if there is any */ @@ -1366,8 +1350,8 @@ /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, - US_BULK_CS_WRAP_LEN, &partial); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + (char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1376,50 +1360,24 @@ } /* did the attempt to read the CSW fail? */ - if (result == -EPIPE) { - 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; + if (result == USB_STOR_XFER_STALLED) { /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, - US_BULK_CS_WRAP_LEN, &partial); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + (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? */ - 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; - } } /* if we still have a failure at this point, we're in trouble */ US_DEBUGP("Bulk status result = %d\n", result); - if (result) { + if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - } /* check bulk status */ US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", @@ -1427,7 +1385,7 @@ bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { + bcs.Status > US_BULK_STAT_PHASE) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; }