Commit 68476aa5 authored by Matthew Dharm's avatar Matthew Dharm Committed by Greg Kroah-Hartman

[PATCH] USB storage: use scatter-gather core primitives

This patch switches the usb-storage driver to using the new USB core
scatter-gather primitives.  This _should_ create a significant performance
gain.
parent 7a9ae923
......@@ -654,44 +654,108 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_SHORT;
}
/*
* Transfer a scatter-gather list via bulk transfer
*
* This function does basically the same thing as usb_stor_bulk_transfer_buf()
* above, but it uses the usbcore scatter-gather primitives
*/
int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
struct scatterlist *sg, int num_sg, unsigned int length,
unsigned int *act_len)
{
int result;
int partial;
/* initialize the scatter-gather request block */
US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %d bytes, "
"%d entires\n", length, num_sg);
result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, SLAB_NOIO);
if (result) {
US_DEBUGP("usb_sg_init returned %d\n", result);
return USB_STOR_XFER_ERROR;
}
/* since the block has been initialized successfully, it's now
* okay to cancel it */
set_bit(US_FLIDX_CANCEL_SG, &us->flags);
/* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) {
US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(us->current_sg);
}
}
usb_sg_wait(us->current_sg);
clear_bit(US_FLIDX_CANCEL_SG, &us->flags);
result = us->current_sg->status;
partial = us->current_sg->bytes;
US_DEBUGP("usb_sg_wait() returned %d xferrerd %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) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x,"
"stalled at %d bytes\n", pipe, partial);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* NAK - that means we've tried this a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
}
/* the catch-all error case */
if (result) {
US_DEBUGP("-- unknown error\n");
return USB_STOR_XFER_ERROR;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("-- transfer complete\n");
return USB_STOR_XFER_GOOD;
}
/* no error code, so we must have transferred some data,
* just not all of it */
US_DEBUGP("-- transferred only %d bytes\n", partial);
return USB_STOR_XFER_SHORT;
}
/*
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
* Note that this uses usb_stor_bulk_transfer_buf to achieve its goals --
* this function simply determines if we're going to use scatter-gather or not,
* and acts appropriately.
* Nore that this uses the usb_stor_bulk_transfer_buf() and
* usb_stor_bulk_transfer_sglist() to achieve its goals --
* this function simply determines whether we're going to use
* scatter-gather or not, and acts apropriately.
*/
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 = USB_STOR_XFER_ERROR;
struct scatterlist *sg;
unsigned int amount;
int result;
unsigned int partial;
/* are we scatter-gathering? */
if (use_sg) {
/* loop over all the scatter gather structures and
* make the appropriate requests for each, until done
*/
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 */
amount = sg->length < length_left ?
sg->length : length_left;
result = usb_stor_bulk_transfer_buf(us, pipe,
sg_address(*sg), amount, &partial);
/* use the usb core scatter-gather primitives */
result = usb_stor_bulk_transfer_sglist(us, pipe,
(struct scatterlist *) buf, use_sg,
length_left, &partial);
length_left -= partial;
/* if we get an error, end the loop here */
if (result != USB_STOR_XFER_GOOD)
break;
}
} else {
/* no scatter-gather, just make the request */
result = usb_stor_bulk_transfer_buf(us, pipe, buf,
......@@ -926,6 +990,12 @@ void usb_stor_abort_transport(struct us_data *us)
usb_unlink_urb(us->current_urb);
}
/* If we are waiting for a scatter-gather operation, cancel it. */
if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) {
US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(us->current_sg);
}
/* If we are waiting for an IRQ, simulate it */
if (test_bit(US_FLIDX_IP_WANTED, &us->flags)) {
US_DEBUGP("-- simulating missing IRQ\n");
......
......@@ -164,6 +164,9 @@ extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
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_sglist(struct us_data *us, unsigned int pipe,
struct scatterlist *sg, int num_sg, 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);
......
......@@ -547,6 +547,13 @@ static int usb_stor_allocate_urbs(struct us_data *ss)
return 2;
}
US_DEBUGP("Allocating scatter-gather request block\n");
ss->current_sg = kmalloc(sizeof(*ss->current_sg), GFP_KERNEL);
if (!ss->current_sg) {
US_DEBUGP("allocation failed\n");
return 5;
}
/* allocate the IRQ URB, if it is needed */
if (ss->protocol == US_PR_CBI) {
US_DEBUGP("Allocating IRQ for CBI transport\n");
......@@ -607,6 +614,12 @@ static void usb_stor_deallocate_urbs(struct us_data *ss)
}
up(&(ss->irq_urb_sem));
/* free the scatter-gather request block */
if (ss->current_sg) {
kfree(ss->current_sg);
ss->current_sg = NULL;
}
/* free up the main URB for this device */
if (ss->current_urb) {
US_DEBUGP("-- releasing main URB\n");
......
......@@ -107,6 +107,7 @@ struct us_unusual_dev {
#define US_FL_DEV_ATTACHED 0x00010000 /* is the device attached? */
#define US_FLIDX_IP_WANTED 17 /* 0x00020000 is an IRQ expected? */
#define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */
#define US_FLIDX_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */
/* processing state machine states */
......@@ -184,6 +185,7 @@ struct us_data {
/* control and bulk communications data */
struct urb *current_urb; /* non-int USB requests */
struct usb_ctrlrequest *dr; /* control requests */
struct usb_sg_request *current_sg; /* scatter-gather USB */
/* the semaphore for sleeping the control thread */
struct semaphore sema; /* to sleep thread on */
......
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