ChangeSet 1.738.5.25, 2002/10/13 13:48:19-07:00, mdharm-usb@one-eyed-alien.net [PATCH] usb-storage: generalize transfer functions This patch generalizes the transfer functions. This is in preparation for consolidating all sub-drivers to use a common set of functions. Oh, and this patch makes the residue field be initialized. Making this the correct value is still on the TODO list. diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/datafab.c Sun Oct 13 17:08:41 2002 @@ -522,6 +522,7 @@ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c Sun Oct 13 17:08:42 2002 +++ b/drivers/usb/storage/freecom.c Sun Oct 13 17:08:42 2002 @@ -108,69 +108,6 @@ /* All packets (except for status) are 64 bytes long. */ #define FCM_PACKET_LENGTH 64 -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_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 us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - - /* 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++) { - - US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); - - /* End this if we're done */ - if (transfer_amount == total_transferred) - break; - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); - total_transferred += 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 = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, unsigned int ipipe, unsigned int opipe, int count) @@ -206,10 +143,10 @@ /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count); US_DEBUGP("freecom_readdata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } static int @@ -248,10 +185,10 @@ /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, opipe, srb, count); US_DEBUGP("freecom_writedata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } /* diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/jumpshot.c Sun Oct 13 17:08:41 2002 @@ -464,7 +464,7 @@ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; - + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/sddr09.c Sun Oct 13 17:08:41 2002 @@ -1368,6 +1368,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + srb->resid = 0; info = (struct sddr09_card_info *)us->extra; if (!info) { nand_init_ecc(); diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c --- a/drivers/usb/storage/sddr55.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/sddr55.c Sun Oct 13 17:08:41 2002 @@ -743,6 +743,7 @@ unsigned short pages; struct sddr55_card_info *info; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr55_card_info), GFP_NOIO); diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/shuttle_usbat.c Sun Oct 13 17:08:41 2002 @@ -766,6 +766,7 @@ int i; char string[64]; + srb->resid = 0; len = srb->request_bufflen; /* Send A0 (ATA PACKET COMMAND). diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/transport.c Sun Oct 13 17:08:41 2002 @@ -541,33 +541,76 @@ } /* - * Transfer one SCSI scatter-gather buffer via bulk transfer + * Transfer one control message * - * 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). + * This function does basically the same thing as usb_stor_control_msg() + * above, except that return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. + */ +int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size) { + int result; + + US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " + "value=%04x index=%02x len=%d\n", + request, requesttype, value, index, size); + result = usb_stor_control_msg(us, pipe, request, requesttype, + value, index, data, size); + US_DEBUGP("usb_stor_control_msg returned %d\n", result); + + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("-- transfer aborted\n"); + return USB_STOR_XFER_ABORTED; + } + + /* a stall indicates a protocol error */ + if (result == -EPIPE) { + US_DEBUGP("-- stall on control pipe\n"); + return USB_STOR_XFER_ERROR; + } + + /* some other serious problem here */ + if (result < 0) { + US_DEBUGP("-- unknown error\n"); + return USB_STOR_XFER_ERROR; + } + + /* was the entire command transferred? */ + if (result < size) { + US_DEBUGP("-- transfer was short\n"); + return USB_STOR_XFER_SHORT; + } + + US_DEBUGP("-- transfer completed successfully\n"); + return USB_STOR_XFER_GOOD; +} + +/* + * Transfer one buffer via bulk transfer + * + * This function does basically the same thing as usb_stor_bulk_msg() + * above, except that: * - * 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. + * 1. If the bulk pipe stalls during the transfer, the halt is + * automatically cleared; + * 2. Return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. */ -int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) +int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len) { int result; int partial; - unsigned int pipe; - - /* get the appropriate pipe value */ - if (us->srb->sc_data_direction == SCSI_DATA_READ) - pipe = us->recv_bulk_pipe; - else - pipe = us->send_bulk_pipe; /* transfer the data */ - US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); + US_DEBUGP("usb_stor_bulk_transfer_buf(): 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 (act_len) + *act_len = partial; /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { @@ -579,25 +622,25 @@ /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + US_DEBUGP("-- transfer aborted\n"); return USB_STOR_XFER_ABORTED; } /* NAK - that means we've retried a few times already */ if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + US_DEBUGP("-- device NAKed\n"); return USB_STOR_XFER_ERROR; } /* the catch-all error case */ if (result) { - US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); + US_DEBUGP("-- unknown error\n"); return USB_STOR_XFER_ERROR; } /* did we send all the data? */ if (partial == length) { - US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); + US_DEBUGP("-- transfer complete\n"); return USB_STOR_XFER_GOOD; } @@ -610,59 +653,51 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve its goals -- this + * Note that this uses usb_stor_transfer_buf to achieve its 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. */ -void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us) +int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, + char *buf, unsigned int length_left, int use_sg, int *residual) { int i; int result = -1; struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; + unsigned int amount; + unsigned int partial; /* are we scatter-gathering? */ - if (srb->use_sg) { + if (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++) { + sg = (struct scatterlist *) buf; + for (i = 0; (i < use_sg) && (length_left > 0); (i++, ++sg)) { /* transfer the lesser of the next buffer or the * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); + amount = sg->length < length_left ? + sg->length : length_left; + result = usb_stor_bulk_transfer_buf(us, pipe, + sg_address(*sg), amount, &partial); + length_left -= partial; /* if we get an error, end the loop here */ - if (result) + if (result != USB_STOR_XFER_GOOD) break; } - } - else + } else { /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); + result = usb_stor_bulk_transfer_buf(us, pipe, buf, + length_left, &partial); + length_left -= partial; + } - /* return the result in the data structure itself */ - srb->result = result; + /* store the residual and return the error code */ + if (residual) + *residual = length_left; + return result; } /*********************************************************************** @@ -741,7 +776,7 @@ * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ - if ((srb->result == USB_STOR_XFER_SHORT) && + if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -973,6 +1008,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* re-initialize the mutex so that we avoid any races with @@ -984,14 +1020,14 @@ /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, us->send_ctrl_pipe, + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); + if (result != USB_STOR_XFER_GOOD) { /* Reset flag for status notification */ clear_bit(US_FLIDX_IP_WANTED, &us->flags); } @@ -1002,22 +1038,16 @@ return USB_STOR_TRANSPORT_ABORTED; } - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (result < 0) { + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length > 0) { + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* report any errors */ @@ -1092,39 +1122,34 @@ */ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, us->send_ctrl_pipe, + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return USB_STOR_TRANSPORT_ABORTED; + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length) + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CB data stage result is 0x%x\n", result); /* report any errors */ @@ -1178,12 +1203,13 @@ { struct bulk_cb_wrap bcb; 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); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); + 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; @@ -1221,26 +1247,24 @@ US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } - if (result < 0) - return USB_STOR_TRANSPORT_ERROR; - result = -EPIPE; + return USB_STOR_TRANSPORT_ERROR; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; } - /* if the command transfered well, then we go to the data stage */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - usb_stor_transfer(srb, us); - result = srb->result; - 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 USB_STOR_TRANSPORT_ABORTED; - } + /* DATA STAGE */ + /* send/receive data payload, if there is any */ + if (transfer_length) { + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_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 USB_STOR_TRANSPORT_ABORTED; + if (result == USB_STOR_XFER_ERROR) + return USB_STOR_TRANSPORT_ERROR; } /* See flow chart on pg 15 of the Bulk Only Transport spec for diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Sun Oct 13 17:08:41 2002 +++ b/drivers/usb/storage/transport.h Sun Oct 13 17:08:41 2002 @@ -115,7 +115,7 @@ #define US_BULK_GET_MAX_LUN 0xfe /* - * usb_stor_transfer() return codes, in order of severity + * usb_stor_bulk_transfer_xxx() return codes, in order of severity */ #define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ @@ -151,7 +151,6 @@ extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); extern void usb_stor_abort_transport(struct us_data*); -extern int usb_stor_transfer_partial(struct us_data*, char*, int); extern int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, unsigned int len, unsigned int *act_len); @@ -160,5 +159,18 @@ void *data, u16 size); extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); -extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size); +extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len); +extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, int use_sg, int *residual); + +static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us, + unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) { + return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, + length, srb->use_sg, &srb->resid); +} + #endif