diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-06-26 20:42:18 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2010-06-26 20:42:18 +0000 |
commit | 95c5443b843c7875794c17aeba33213b71ba4dbb (patch) | |
tree | 0c25039640bb2607a15f2792558ea5b2b4c1a48d /target/linux/generic-2.4/patches/228-more_usb_fixes.patch | |
parent | c4f3caef75c247bcce4502391c072e10f741430a (diff) | |
download | upstream-95c5443b843c7875794c17aeba33213b71ba4dbb.tar.gz upstream-95c5443b843c7875794c17aeba33213b71ba4dbb.tar.bz2 upstream-95c5443b843c7875794c17aeba33213b71ba4dbb.zip |
remove generic linux 2.4 support
SVN-Revision: 21948
Diffstat (limited to 'target/linux/generic-2.4/patches/228-more_usb_fixes.patch')
-rw-r--r-- | target/linux/generic-2.4/patches/228-more_usb_fixes.patch | 843 |
1 files changed, 0 insertions, 843 deletions
diff --git a/target/linux/generic-2.4/patches/228-more_usb_fixes.patch b/target/linux/generic-2.4/patches/228-more_usb_fixes.patch deleted file mode 100644 index 16b554a805..0000000000 --- a/target/linux/generic-2.4/patches/228-more_usb_fixes.patch +++ /dev/null @@ -1,843 +0,0 @@ ---- a/drivers/scsi/hosts.c -+++ b/drivers/scsi/hosts.c -@@ -107,8 +107,21 @@ scsi_unregister(struct Scsi_Host * sh){ - if (shn) shn->host_registered = 0; - /* else {} : This should not happen, we should panic here... */ - -+ /* If we are removing the last host registered, it is safe to reuse -+ * its host number (this avoids "holes" at boot time) (DB) -+ * It is also safe to reuse those of numbers directly below which have -+ * been released earlier (to avoid some holes in numbering). -+ */ -+ if(sh->host_no == max_scsi_hosts - 1) { -+ while(--max_scsi_hosts >= next_scsi_host) { -+ shpnt = scsi_hostlist; -+ while(shpnt && shpnt->host_no != max_scsi_hosts - 1) -+ shpnt = shpnt->next; -+ if(shpnt) -+ break; -+ } -+ } - next_scsi_host--; -- - kfree((char *) sh); - } - ---- a/drivers/usb/hcd.c -+++ b/drivers/usb/hcd.c -@@ -1105,7 +1105,8 @@ static int hcd_submit_urb (struct urb *u - break; - case PIPE_BULK: - allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK -- | USB_ZERO_PACKET | URB_NO_INTERRUPT; -+ | USB_ZERO_PACKET | URB_NO_INTERRUPT -+ | URB_NO_TRANSFER_DMA_MAP; - break; - case PIPE_INTERRUPT: - allowed |= USB_DISABLE_SPD; -@@ -1212,7 +1213,8 @@ static int hcd_submit_urb (struct urb *u - urb->setup_packet, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); -- if (urb->transfer_buffer_length != 0) -+ if (urb->transfer_buffer_length != 0 -+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - urb->transfer_dma = pci_map_single ( - hcd->pdev, - urb->transfer_buffer, ---- a/drivers/usb/host/ehci-hcd.c -+++ b/drivers/usb/host/ehci-hcd.c -@@ -399,6 +399,27 @@ static int ehci_start (struct usb_hcd *h - ehci_mem_cleanup (ehci); - return retval; - } -+ -+{ -+ int misc_reg; -+ u32 vendor_id; -+ -+ pci_read_config_dword (ehci->hcd.pdev, PCI_VENDOR_ID, &vendor_id); -+ if (vendor_id == 0x31041106) { -+ /* VIA 6212 */ -+ printk(KERN_INFO "EHCI: Enabling VIA 6212 workarounds\n", misc_reg); -+ pci_read_config_byte(ehci->hcd.pdev, 0x49, &misc_reg); -+ misc_reg &= ~0x20; -+ pci_write_config_byte(ehci->hcd.pdev, 0x49, misc_reg); -+ pci_read_config_byte(ehci->hcd.pdev, 0x49, &misc_reg); -+ -+ pci_read_config_byte(ehci->hcd.pdev, 0x4b, &misc_reg); -+ misc_reg |= 0x20; -+ pci_write_config_byte(ehci->hcd.pdev, 0x4b, misc_reg); -+ pci_read_config_byte(ehci->hcd.pdev, 0x4b, &misc_reg); -+ } -+} -+ - writel (INTR_MASK, &ehci->regs->intr_enable); - writel (ehci->periodic_dma, &ehci->regs->frame_list); - ---- a/drivers/usb/host/ehci-q.c -+++ b/drivers/usb/host/ehci-q.c -@@ -791,6 +791,8 @@ static void qh_link_async (struct ehci_h - writel (cmd, &ehci->regs->command); - ehci->hcd.state = USB_STATE_RUNNING; - /* posted write need not be known to HC yet ... */ -+ -+ timer_action (ehci, TIMER_IO_WATCHDOG); - } - } - ---- a/drivers/usb/host/usb-uhci.c -+++ b/drivers/usb/host/usb-uhci.c -@@ -3034,6 +3034,21 @@ uhci_pci_probe (struct pci_dev *dev, con - - pci_set_master(dev); - -+ { -+ u8 misc_reg; -+ u32 vendor_id; -+ -+ pci_read_config_dword (dev, PCI_VENDOR_ID, &vendor_id); -+ if (vendor_id == 0x30381106) { -+ /* VIA 6212 */ -+ printk(KERN_INFO "UHCI: Enabling VIA 6212 workarounds\n"); -+ pci_read_config_byte(dev, 0x41, &misc_reg); -+ misc_reg &= ~0x10; -+ pci_write_config_byte(dev, 0x41, misc_reg); -+ pci_read_config_byte(dev, 0x41, &misc_reg); -+ } -+ } -+ - /* Search for the IO base address.. */ - for (i = 0; i < 6; i++) { - ---- a/drivers/usb/storage/transport.c -+++ b/drivers/usb/storage/transport.c -@@ -54,6 +54,22 @@ - #include <linux/sched.h> - #include <linux/errno.h> - #include <linux/slab.h> -+#include <linux/pci.h> -+#include "../hcd.h" -+ -+/* These definitions mirror those in pci.h, so they can be used -+ * interchangeably with their PCI_ counterparts */ -+enum dma_data_direction { -+ DMA_BIDIRECTIONAL = 0, -+ DMA_TO_DEVICE = 1, -+ DMA_FROM_DEVICE = 2, -+ DMA_NONE = 3, -+}; -+ -+#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir) -+#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir) -+ -+ - - /*********************************************************************** - * Helper routines -@@ -554,6 +570,543 @@ int usb_stor_transfer_partial(struct us_ - return US_BULK_TRANSFER_SHORT; - } - -+/*-------------------------------------------------------------------*/ -+/** -+ * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist -+ * @dev: device to which the scatterlist will be mapped -+ * @pipe: endpoint defining the mapping direction -+ * @sg: the scatterlist to unmap -+ * @n_hw_ents: the positive return value from usb_buffer_map_sg -+ * -+ * Reverses the effect of usb_buffer_map_sg(). -+ */ -+static void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, -+ struct scatterlist *sg, int n_hw_ents) -+{ -+ struct usb_bus *bus; -+ struct usb_hcd *hcd; -+ struct pci_dev *pdev; -+ -+ if (!dev -+ || !(bus = dev->bus) -+ || !(hcd = bus->hcpriv) -+ || !(pdev = hcd->pdev) -+ || !pdev->dma_mask) -+ return; -+ -+ dma_unmap_sg (pdev, sg, n_hw_ents, -+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -+} -+ -+/** -+ * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint -+ * @dev: device to which the scatterlist will be mapped -+ * @pipe: endpoint defining the mapping direction -+ * @sg: the scatterlist to map -+ * @nents: the number of entries in the scatterlist -+ * -+ * Return value is either < 0 (indicating no buffers could be mapped), or -+ * the number of DMA mapping array entries in the scatterlist. -+ * -+ * The caller is responsible for placing the resulting DMA addresses from -+ * the scatterlist into URB transfer buffer pointers, and for setting the -+ * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. -+ * -+ * Top I/O rates come from queuing URBs, instead of waiting for each one -+ * to complete before starting the next I/O. This is particularly easy -+ * to do with scatterlists. Just allocate and submit one URB for each DMA -+ * mapping entry returned, stopping on the first error or when all succeed. -+ * Better yet, use the usb_sg_*() calls, which do that (and more) for you. -+ * -+ * This call would normally be used when translating scatterlist requests, -+ * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it -+ * may be able to coalesce mappings for improved I/O efficiency. -+ * -+ * Reverse the effect of this call with usb_buffer_unmap_sg(). -+ */ -+static int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, -+ struct scatterlist *sg, int nents) -+{ -+ struct usb_bus *bus; -+ struct usb_hcd *hcd; -+ struct pci_dev *pdev; -+ -+ if (!dev -+ || usb_pipecontrol (pipe) -+ || !(bus = dev->bus) -+ || !(hcd = bus->hcpriv) -+ || !(pdev = hcd->pdev) -+ || !pdev->dma_mask) -+ return -1; -+ -+ // FIXME generic api broken like pci, can't report errors -+ return dma_map_sg (pdev, sg, nents, -+ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -+} -+ -+static void sg_clean (struct usb_sg_request *io) -+{ -+ struct usb_hcd *hcd = io->dev->bus->hcpriv; -+ struct pci_dev *pdev = hcd->pdev; -+ -+ if (io->urbs) { -+ while (io->entries--) -+ usb_free_urb (io->urbs [io->entries]); -+ kfree (io->urbs); -+ io->urbs = 0; -+ } -+ if (pdev->dma_mask != 0) -+ usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); -+ io->dev = 0; -+} -+ -+static void sg_complete (struct urb *urb) -+{ -+ struct usb_sg_request *io = (struct usb_sg_request *) urb->context; -+ -+ spin_lock (&io->lock); -+ -+ /* In 2.5 we require hcds' endpoint queues not to progress after fault -+ * reports, until the completion callback (this!) returns. That lets -+ * device driver code (like this routine) unlink queued urbs first, -+ * if it needs to, since the HC won't work on them at all. So it's -+ * not possible for page N+1 to overwrite page N, and so on. -+ * -+ * That's only for "hard" faults; "soft" faults (unlinks) sometimes -+ * complete before the HCD can get requests away from hardware, -+ * though never during cleanup after a hard fault. -+ */ -+ if (io->status -+ && (io->status != -ECONNRESET -+ || urb->status != -ECONNRESET) -+ && urb->actual_length) { -+ US_DEBUGP("Error: %s ep%d%s scatterlist error %d/%d\n", -+ io->dev->devpath, -+ usb_pipeendpoint (urb->pipe), -+ usb_pipein (urb->pipe) ? "in" : "out", -+ urb->status, io->status); -+ // BUG (); -+ } -+ -+ if (urb->status && urb->status != -ECONNRESET) { -+ int i, found, status; -+ -+ io->status = urb->status; -+ -+ /* the previous urbs, and this one, completed already. -+ * unlink pending urbs so they won't rx/tx bad data. -+ */ -+ for (i = 0, found = 0; i < io->entries; i++) { -+ if (!io->urbs [i]) -+ continue; -+ if (found) { -+ status = usb_unlink_urb (io->urbs [i]); -+ if (status != -EINPROGRESS && status != -EBUSY) -+ US_DEBUGP("Error: %s, unlink --> %d\n", __FUNCTION__, status); -+ } else if (urb == io->urbs [i]) -+ found = 1; -+ } -+ } -+ urb->dev = 0; -+ -+ /* on the last completion, signal usb_sg_wait() */ -+ io->bytes += urb->actual_length; -+ io->count--; -+ if (!io->count) -+ complete (&io->complete); -+ -+ spin_unlock (&io->lock); -+} -+ -+/** -+ * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request -+ * @io: request block being initialized. until usb_sg_wait() returns, -+ * treat this as a pointer to an opaque block of memory, -+ * @dev: the usb device that will send or receive the data -+ * @pipe: endpoint "pipe" used to transfer the data -+ * @period: polling rate for interrupt endpoints, in frames or -+ * (for high speed endpoints) microframes; ignored for bulk -+ * @sg: scatterlist entries -+ * @nents: how many entries in the scatterlist -+ * @length: how many bytes to send from the scatterlist, or zero to -+ * send every byte identified in the list. -+ * @mem_flags: SLAB_* flags affecting memory allocations in this call -+ * -+ * Returns zero for success, else a negative errno value. This initializes a -+ * scatter/gather request, allocating resources such as I/O mappings and urb -+ * memory (except maybe memory used by USB controller drivers). -+ * -+ * The request must be issued using usb_sg_wait(), which waits for the I/O to -+ * complete (or to be canceled) and then cleans up all resources allocated by -+ * usb_sg_init(). -+ * -+ * The request may be canceled with usb_sg_cancel(), either before or after -+ * usb_sg_wait() is called. -+ */ -+int usb_sg_init ( -+ struct usb_sg_request *io, -+ struct usb_device *dev, -+ unsigned pipe, -+ unsigned period, -+ struct scatterlist *sg, -+ int nents, -+ size_t length, -+ int mem_flags -+) -+{ -+ int i; -+ int urb_flags; -+ int dma; -+ struct usb_hcd *hcd; -+ -+ hcd = dev->bus->hcpriv; -+ -+ if (!io || !dev || !sg -+ || usb_pipecontrol (pipe) -+ || usb_pipeisoc (pipe) -+ || nents <= 0) -+ return -EINVAL; -+ -+ spin_lock_init (&io->lock); -+ io->dev = dev; -+ io->pipe = pipe; -+ io->sg = sg; -+ io->nents = nents; -+ -+ /* not all host controllers use DMA (like the mainstream pci ones); -+ * they can use PIO (sl811) or be software over another transport. -+ */ -+ dma = (hcd->pdev->dma_mask != 0); -+ if (dma) -+ io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); -+ else -+ io->entries = nents; -+ -+ /* initialize all the urbs we'll use */ -+ if (io->entries <= 0) -+ return io->entries; -+ -+ io->count = 0; -+ io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); -+ if (!io->urbs) -+ goto nomem; -+ -+ urb_flags = USB_ASYNC_UNLINK | URB_NO_INTERRUPT | URB_NO_TRANSFER_DMA_MAP; -+ if (usb_pipein (pipe)) -+ urb_flags |= URB_SHORT_NOT_OK; -+ -+ for (i = 0; i < io->entries; i++, io->count = i) { -+ unsigned len; -+ -+ io->urbs [i] = usb_alloc_urb (0); -+ if (!io->urbs [i]) { -+ io->entries = i; -+ goto nomem; -+ } -+ -+ io->urbs [i]->dev = 0; -+ io->urbs [i]->pipe = pipe; -+ io->urbs [i]->interval = period; -+ io->urbs [i]->transfer_flags = urb_flags; -+ -+ io->urbs [i]->complete = sg_complete; -+ io->urbs [i]->context = io; -+ io->urbs [i]->status = -EINPROGRESS; -+ io->urbs [i]->actual_length = 0; -+ -+ if (dma) { -+ /* hc may use _only_ transfer_dma */ -+ io->urbs [i]->transfer_dma = sg_dma_address (sg + i); -+ len = sg_dma_len (sg + i); -+ } else { -+ /* hc may use _only_ transfer_buffer */ -+ io->urbs [i]->transfer_buffer = -+ page_address (sg [i].page) + sg [i].offset; -+ len = sg [i].length; -+ } -+ -+ if (length) { -+ len = min_t (unsigned, len, length); -+ length -= len; -+ if (length == 0) -+ io->entries = i + 1; -+ } -+ io->urbs [i]->transfer_buffer_length = len; -+ } -+ io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; -+ -+ /* transaction state */ -+ io->status = 0; -+ io->bytes = 0; -+ init_completion (&io->complete); -+ return 0; -+ -+nomem: -+ sg_clean (io); -+ return -ENOMEM; -+} -+ -+/** -+ * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() -+ * @io: request block, initialized with usb_sg_init() -+ * -+ * This stops a request after it has been started by usb_sg_wait(). -+ * It can also prevents one initialized by usb_sg_init() from starting, -+ * so that call just frees resources allocated to the request. -+ */ -+void usb_sg_cancel (struct usb_sg_request *io) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave (&io->lock, flags); -+ -+ /* shut everything down, if it didn't already */ -+ if (!io->status) { -+ int i; -+ -+ io->status = -ECONNRESET; -+ for (i = 0; i < io->entries; i++) { -+ int retval; -+ -+ if (!io->urbs [i]->dev) -+ continue; -+ retval = usb_unlink_urb (io->urbs [i]); -+ if (retval != -EINPROGRESS && retval != -EBUSY) -+ US_DEBUGP("WARNING: %s, unlink --> %d\n", __FUNCTION__, retval); -+ } -+ } -+ spin_unlock_irqrestore (&io->lock, flags); -+} -+ -+/** -+ * usb_sg_wait - synchronously execute scatter/gather request -+ * @io: request block handle, as initialized with usb_sg_init(). -+ * some fields become accessible when this call returns. -+ * Context: !in_interrupt () -+ * -+ * This function blocks until the specified I/O operation completes. It -+ * leverages the grouping of the related I/O requests to get good transfer -+ * rates, by queueing the requests. At higher speeds, such queuing can -+ * significantly improve USB throughput. -+ * -+ * There are three kinds of completion for this function. -+ * (1) success, where io->status is zero. The number of io->bytes -+ * transferred is as requested. -+ * (2) error, where io->status is a negative errno value. The number -+ * of io->bytes transferred before the error is usually less -+ * than requested, and can be nonzero. -+ * (3) cancelation, a type of error with status -ECONNRESET that -+ * is initiated by usb_sg_cancel(). -+ * -+ * When this function returns, all memory allocated through usb_sg_init() or -+ * this call will have been freed. The request block parameter may still be -+ * passed to usb_sg_cancel(), or it may be freed. It could also be -+ * reinitialized and then reused. -+ * -+ * Data Transfer Rates: -+ * -+ * Bulk transfers are valid for full or high speed endpoints. -+ * The best full speed data rate is 19 packets of 64 bytes each -+ * per frame, or 1216 bytes per millisecond. -+ * The best high speed data rate is 13 packets of 512 bytes each -+ * per microframe, or 52 KBytes per millisecond. -+ * -+ * The reason to use interrupt transfers through this API would most likely -+ * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond -+ * could be transferred. That capability is less useful for low or full -+ * speed interrupt endpoints, which allow at most one packet per millisecond, -+ * of at most 8 or 64 bytes (respectively). -+ */ -+void usb_sg_wait (struct usb_sg_request *io) -+{ -+ int i, entries = io->entries; -+ -+ /* queue the urbs. */ -+ spin_lock_irq (&io->lock); -+ for (i = 0; i < entries && !io->status; i++) { -+ int retval; -+ -+ io->urbs [i]->dev = io->dev; -+ retval = usb_submit_urb (io->urbs [i]); -+ -+ /* after we submit, let completions or cancelations fire; -+ * we handshake using io->status. -+ */ -+ spin_unlock_irq (&io->lock); -+ switch (retval) { -+ /* maybe we retrying will recover */ -+ case -ENXIO: // hc didn't queue this one -+ case -EAGAIN: -+ case -ENOMEM: -+ io->urbs [i]->dev = 0; -+ retval = 0; -+ i--; -+ yield (); -+ break; -+ -+ /* no error? continue immediately. -+ * -+ * NOTE: to work better with UHCI (4K I/O buffer may -+ * need 3K of TDs) it may be good to limit how many -+ * URBs are queued at once; N milliseconds? -+ */ -+ case 0: -+ cpu_relax (); -+ break; -+ -+ /* fail any uncompleted urbs */ -+ default: -+ spin_lock_irq (&io->lock); -+ io->count -= entries - i; -+ if (io->status == -EINPROGRESS) -+ io->status = retval; -+ if (io->count == 0) -+ complete (&io->complete); -+ spin_unlock_irq (&io->lock); -+ -+ io->urbs [i]->dev = 0; -+ io->urbs [i]->status = retval; -+ -+ US_DEBUGP("%s, submit --> %d\n", __FUNCTION__, retval); -+ usb_sg_cancel (io); -+ } -+ spin_lock_irq (&io->lock); -+ if (retval && io->status == -ECONNRESET) -+ io->status = retval; -+ } -+ spin_unlock_irq (&io->lock); -+ -+ /* OK, yes, this could be packaged as non-blocking. -+ * So could the submit loop above ... but it's easier to -+ * solve neither problem than to solve both! -+ */ -+ wait_for_completion (&io->complete); -+ -+ sg_clean (io); -+} -+ -+/* -+ * Interpret the results of a URB transfer -+ * -+ * This function prints appropriate debugging messages, clears halts on -+ * non-control endpoints, and translates the status to the corresponding -+ * USB_STOR_XFER_xxx return code. -+ */ -+static int interpret_urb_result(struct us_data *us, unsigned int pipe, -+ unsigned int length, int result, unsigned int partial) -+{ -+ US_DEBUGP("Status code %d; transferred %u/%u\n", -+ result, partial, length); -+ switch (result) { -+ -+ /* no error code; did we send all the data? */ -+ case 0: -+ if (partial != length) { -+ US_DEBUGP("-- short transfer\n"); -+ return USB_STOR_XFER_SHORT; -+ } -+ -+ US_DEBUGP("-- transfer complete\n"); -+ return USB_STOR_XFER_GOOD; -+ -+ /* stalled */ -+ case -EPIPE: -+ /* for control endpoints, (used by CB[I]) a stall indicates -+ * a failed command */ -+ if (usb_pipecontrol(pipe)) { -+ US_DEBUGP("-- stall on control pipe\n"); -+ return USB_STOR_XFER_STALLED; -+ } -+ -+ /* for other sorts of endpoint, clear the stall */ -+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); -+ if (usb_stor_clear_halt(us, pipe) < 0) -+ return USB_STOR_XFER_ERROR; -+ return USB_STOR_XFER_STALLED; -+ -+ /* timeout or excessively long NAK */ -+ case -ETIMEDOUT: -+ US_DEBUGP("-- timeout or NAK\n"); -+ return USB_STOR_XFER_ERROR; -+ -+ /* babble - the device tried to send more than we wanted to read */ -+ case -EOVERFLOW: -+ US_DEBUGP("-- babble\n"); -+ return USB_STOR_XFER_LONG; -+ -+ /* the transfer was cancelled by abort, disconnect, or timeout */ -+ case -ECONNRESET: -+ US_DEBUGP("-- transfer cancelled\n"); -+ return USB_STOR_XFER_ERROR; -+ -+ /* short scatter-gather read transfer */ -+ case -EREMOTEIO: -+ US_DEBUGP("-- short read transfer\n"); -+ return USB_STOR_XFER_SHORT; -+ -+ /* abort or disconnect in progress */ -+ case -EIO: -+ US_DEBUGP("-- abort or disconnect in progress\n"); -+ return USB_STOR_XFER_ERROR; -+ -+ /* the catch-all error case */ -+ default: -+ US_DEBUGP("-- unknown error\n"); -+ return USB_STOR_XFER_ERROR; -+ } -+} -+ -+/* -+ * Transfer a scatter-gather list via bulk transfer -+ * -+ * This function does basically the same thing as usb_stor_bulk_msg() -+ * above, but it uses the usbcore scatter-gather library. -+ */ -+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; -+ -+ /* don't submit s-g requests during abort/disconnect processing */ -+ if (us->flags & ABORTING_OR_DISCONNECTING) -+ return USB_STOR_XFER_ERROR; -+ -+ /* initialize the scatter-gather request block */ -+ US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__, -+ 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_SG_ACTIVE, &us->flags); -+ -+ /* did an abort/disconnect occur during the submission? */ -+ if (us->flags & ABORTING_OR_DISCONNECTING) { -+ -+ /* cancel the request, if it hasn't been cancelled already */ -+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { -+ US_DEBUGP("-- cancelling sg request\n"); -+ usb_sg_cancel(&us->current_sg); -+ } -+ } -+ -+ /* wait for the completion of the transfer */ -+ usb_sg_wait(&us->current_sg); -+ clear_bit(US_FLIDX_SG_ACTIVE, &us->flags); -+ -+ result = us->current_sg.status; -+ if (act_len) -+ *act_len = us->current_sg.bytes; -+ return interpret_urb_result(us, pipe, length, result, -+ us->current_sg.bytes); -+} -+ - /* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. -@@ -569,6 +1122,8 @@ void usb_stor_transfer(Scsi_Cmnd *srb, s - struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; -+ unsigned int partial; -+ unsigned int pipe; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); -@@ -585,23 +1140,34 @@ void usb_stor_transfer(Scsi_Cmnd *srb, s - * 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 = usb_stor_transfer_partial(us, -- sg[i].address, sg[i].length); -- total_transferred += sg[i].length; -- } else -- result = usb_stor_transfer_partial(us, -- sg[i].address, -- transfer_amount - total_transferred); -- -- /* if we get an error, end the loop here */ -- if (result) -- break; -+ if (us->pusb_dev->speed == USB_SPEED_HIGH) { -+ /* calculate the appropriate pipe information */ -+ if (us->srb->sc_data_direction == SCSI_DATA_READ) -+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); -+ else -+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); -+ /* use the usb core scatter-gather primitives */ -+ result = usb_stor_bulk_transfer_sglist(us, pipe, -+ sg, srb->use_sg, transfer_amount, &partial); -+ } else { -+ 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 = usb_stor_transfer_partial(us, -+ sg[i].address, sg[i].length); -+ total_transferred += sg[i].length; -+ } else -+ result = usb_stor_transfer_partial(us, -+ sg[i].address, -+ transfer_amount - total_transferred); -+ -+ /* if we get an error, end the loop here */ -+ if (result) -+ break; -+ } - } - } - else ---- a/drivers/usb/storage/transport.h -+++ b/drivers/usb/storage/transport.h -@@ -127,6 +127,16 @@ struct bulk_cs_wrap { - #define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */ - - /* -+ * 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 /* transferred less than expected */ -+#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ -+#define USB_STOR_XFER_LONG 3 /* device tried to send too much */ -+#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */ -+ -+/* - * Transport return codes - */ - ---- a/drivers/usb/storage/usb.h -+++ b/drivers/usb/storage/usb.h -@@ -111,6 +111,60 @@ typedef int (*trans_reset)(struct us_dat - typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); - typedef void (*extra_data_destructor)(void *); /* extra data destructor */ - -+/* Dynamic flag definitions: used in set_bit() etc. */ -+#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */ -+#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */ -+#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */ -+#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */ -+#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \ -+ (1UL << US_FLIDX_DISCONNECTING)) -+#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */ -+ -+/* processing state machine states */ -+#define US_STATE_IDLE 1 -+#define US_STATE_RUNNING 2 -+#define US_STATE_RESETTING 3 -+#define US_STATE_ABORTING 4 -+ -+/** -+ * struct usb_sg_request - support for scatter/gather I/O -+ * @status: zero indicates success, else negative errno -+ * @bytes: counts bytes transferred. -+ * -+ * These requests are initialized using usb_sg_init(), and then are used -+ * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most -+ * members of the request object aren't for driver access. -+ * -+ * The status and bytecount values are valid only after usb_sg_wait() -+ * returns. If the status is zero, then the bytecount matches the total -+ * from the request. -+ * -+ * After an error completion, drivers may need to clear a halt condition -+ * on the endpoint. -+ */ -+struct usb_sg_request { -+ int status; -+ size_t bytes; -+ -+ /* -+ * members below are private to usbcore, -+ * and are not provided for driver access! -+ */ -+ spinlock_t lock; -+ -+ struct usb_device *dev; -+ int pipe; -+ struct scatterlist *sg; -+ int nents; -+ -+ int entries; -+ struct urb **urbs; -+ -+ int count; -+ struct completion complete; -+}; -+ -+ - /* we allocate one of these for every device that we remember */ - struct us_data { - struct us_data *next; /* next device */ -@@ -171,6 +225,7 @@ struct us_data { - struct urb *current_urb; /* non-int USB requests */ - struct completion current_done; /* the done flag */ - unsigned int tag; /* tag for bulk CBW/CSW */ -+ struct usb_sg_request current_sg; /* scatter-gather req. */ - - /* the semaphore for sleeping the control thread */ - struct semaphore sema; /* to sleep thread on */ ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -483,6 +483,8 @@ struct usb_driver { - #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ - /* ... less overhead for QUEUE_BULK */ - #define USB_TIMEOUT_KILLED 0x1000 // only set by HCD! -+#define URB_NO_TRANSFER_DMA_MAP 0x0400 /* urb->transfer_dma valid on submit */ -+#define URB_NO_SETUP_DMA_MAP 0x0800 /* urb->setup_dma valid on submit */ - - struct iso_packet_descriptor - { |