mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			844 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			844 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- 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
 | |
|  {
 |