 1da177e4c3
			
		
	
	
	1da177e4c3
	
	
	
		
			
			Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
		
			
				
	
	
		
			254 lines
		
	
	
	
		
			8.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
	
		
			8.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Driver for USB Mass Storage compliant devices
 | |
|  *
 | |
|  * $Id: protocol.c,v 1.14 2002/04/22 03:39:43 mdharm Exp $
 | |
|  *
 | |
|  * Current development and maintenance by:
 | |
|  *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 | |
|  *
 | |
|  * Developed with the assistance of:
 | |
|  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
 | |
|  *   (c) 2002 Alan Stern (stern@rowland.org)
 | |
|  *
 | |
|  * Initial work by:
 | |
|  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
 | |
|  *
 | |
|  * This driver is based on the 'USB Mass Storage Class' document. This
 | |
|  * describes in detail the protocol used to communicate with such
 | |
|  * devices.  Clearly, the designers had SCSI and ATAPI commands in
 | |
|  * mind when they created this document.  The commands are all very
 | |
|  * similar to commands in the SCSI-II and ATAPI specifications.
 | |
|  *
 | |
|  * It is important to note that in a number of cases this class
 | |
|  * exhibits class-specific exemptions from the USB specification.
 | |
|  * Notably the usage of NAK, STALL and ACK differs from the norm, in
 | |
|  * that they are used to communicate wait, failed and OK on commands.
 | |
|  *
 | |
|  * Also, for certain devices, the interrupt endpoint is used to convey
 | |
|  * status of a command.
 | |
|  *
 | |
|  * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
 | |
|  * information about this driver.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms of the GNU General Public License as published by the
 | |
|  * Free Software Foundation; either version 2, or (at your option) any
 | |
|  * later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License along
 | |
|  * with this program; if not, write to the Free Software Foundation, Inc.,
 | |
|  * 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
|  */
 | |
| 
 | |
| #include <linux/highmem.h>
 | |
| #include <scsi/scsi.h>
 | |
| #include <scsi/scsi_cmnd.h>
 | |
| 
 | |
| #include "usb.h"
 | |
| #include "protocol.h"
 | |
| #include "debug.h"
 | |
| #include "scsiglue.h"
 | |
| #include "transport.h"
 | |
| 
 | |
| /***********************************************************************
 | |
|  * Protocol routines
 | |
|  ***********************************************************************/
 | |
| 
 | |
| void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
 | |
| {
 | |
| 	/* Pad the ATAPI command with zeros 
 | |
| 	 *
 | |
| 	 * NOTE: This only works because a scsi_cmnd struct field contains
 | |
| 	 * a unsigned char cmnd[16], so we know we have storage available
 | |
| 	 */
 | |
| 	for (; srb->cmd_len<12; srb->cmd_len++)
 | |
| 		srb->cmnd[srb->cmd_len] = 0;
 | |
| 
 | |
| 	/* set command length to 12 bytes */
 | |
| 	srb->cmd_len = 12;
 | |
| 
 | |
| 	/* send the command to the transport layer */
 | |
| 	usb_stor_invoke_transport(srb, us);
 | |
| }
 | |
| 
 | |
| void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
 | |
| {
 | |
| 	/* Pad the ATAPI command with zeros 
 | |
| 	 *
 | |
| 	 * NOTE: This only works because a scsi_cmnd struct field contains
 | |
| 	 * a unsigned char cmnd[16], so we know we have storage available
 | |
| 	 */
 | |
| 
 | |
| 	/* Pad the ATAPI command with zeros */
 | |
| 	for (; srb->cmd_len<12; srb->cmd_len++)
 | |
| 		srb->cmnd[srb->cmd_len] = 0;
 | |
| 
 | |
| 	/* set command length to 12 bytes */
 | |
| 	srb->cmd_len = 12;
 | |
| 
 | |
| 	/* send the command to the transport layer */
 | |
| 	usb_stor_invoke_transport(srb, us);
 | |
| }
 | |
| 
 | |
| 
 | |
| void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
 | |
| {
 | |
| 	/* fix some commands -- this is a form of mode translation
 | |
| 	 * UFI devices only accept 12 byte long commands 
 | |
| 	 *
 | |
| 	 * NOTE: This only works because a scsi_cmnd struct field contains
 | |
| 	 * a unsigned char cmnd[16], so we know we have storage available
 | |
| 	 */
 | |
| 
 | |
| 	/* Pad the ATAPI command with zeros */
 | |
| 	for (; srb->cmd_len<12; srb->cmd_len++)
 | |
| 		srb->cmnd[srb->cmd_len] = 0;
 | |
| 
 | |
| 	/* set command length to 12 bytes (this affects the transport layer) */
 | |
| 	srb->cmd_len = 12;
 | |
| 
 | |
| 	/* XXX We should be constantly re-evaluating the need for these */
 | |
| 
 | |
| 	/* determine the correct data length for these commands */
 | |
| 	switch (srb->cmnd[0]) {
 | |
| 
 | |
| 		/* for INQUIRY, UFI devices only ever return 36 bytes */
 | |
| 	case INQUIRY:
 | |
| 		srb->cmnd[4] = 36;
 | |
| 		break;
 | |
| 
 | |
| 		/* again, for MODE_SENSE_10, we get the minimum (8) */
 | |
| 	case MODE_SENSE_10:
 | |
| 		srb->cmnd[7] = 0;
 | |
| 		srb->cmnd[8] = 8;
 | |
| 		break;
 | |
| 
 | |
| 		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
 | |
| 	case REQUEST_SENSE:
 | |
| 		srb->cmnd[4] = 18;
 | |
| 		break;
 | |
| 	} /* end switch on cmnd[0] */
 | |
| 
 | |
| 	/* send the command to the transport layer */
 | |
| 	usb_stor_invoke_transport(srb, us);
 | |
| }
 | |
| 
 | |
| void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
 | |
| 				       struct us_data *us)
 | |
| {
 | |
| 	/* send the command to the transport layer */
 | |
| 	usb_stor_invoke_transport(srb, us);
 | |
| }
 | |
| 
 | |
| /***********************************************************************
 | |
|  * Scatter-gather transfer buffer access routines
 | |
|  ***********************************************************************/
 | |
| 
 | |
| /* Copy a buffer of length buflen to/from the srb's transfer buffer.
 | |
|  * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
 | |
|  * points to a list of s-g entries and we ignore srb->request_bufflen.
 | |
|  * For non-scatter-gather transfers, srb->request_buffer points to the
 | |
|  * transfer buffer itself and srb->request_bufflen is the buffer's length.)
 | |
|  * Update the *index and *offset variables so that the next copy will
 | |
|  * pick up from where this one left off. */
 | |
| 
 | |
| unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
 | |
| 	unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
 | |
| 	unsigned int *offset, enum xfer_buf_dir dir)
 | |
| {
 | |
| 	unsigned int cnt;
 | |
| 
 | |
| 	/* If not using scatter-gather, just transfer the data directly.
 | |
| 	 * Make certain it will fit in the available buffer space. */
 | |
| 	if (srb->use_sg == 0) {
 | |
| 		if (*offset >= srb->request_bufflen)
 | |
| 			return 0;
 | |
| 		cnt = min(buflen, srb->request_bufflen - *offset);
 | |
| 		if (dir == TO_XFER_BUF)
 | |
| 			memcpy((unsigned char *) srb->request_buffer + *offset,
 | |
| 					buffer, cnt);
 | |
| 		else
 | |
| 			memcpy(buffer, (unsigned char *) srb->request_buffer +
 | |
| 					*offset, cnt);
 | |
| 		*offset += cnt;
 | |
| 
 | |
| 	/* Using scatter-gather.  We have to go through the list one entry
 | |
| 	 * at a time.  Each s-g entry contains some number of pages, and
 | |
| 	 * each page has to be kmap()'ed separately.  If the page is already
 | |
| 	 * in kernel-addressable memory then kmap() will return its address.
 | |
| 	 * If the page is not directly accessible -- such as a user buffer
 | |
| 	 * located in high memory -- then kmap() will map it to a temporary
 | |
| 	 * position in the kernel's virtual address space. */
 | |
| 	} else {
 | |
| 		struct scatterlist *sg =
 | |
| 				(struct scatterlist *) srb->request_buffer
 | |
| 				+ *index;
 | |
| 
 | |
| 		/* This loop handles a single s-g list entry, which may
 | |
| 		 * include multiple pages.  Find the initial page structure
 | |
| 		 * and the starting offset within the page, and update
 | |
| 		 * the *offset and *index values for the next loop. */
 | |
| 		cnt = 0;
 | |
| 		while (cnt < buflen && *index < srb->use_sg) {
 | |
| 			struct page *page = sg->page +
 | |
| 					((sg->offset + *offset) >> PAGE_SHIFT);
 | |
| 			unsigned int poff =
 | |
| 					(sg->offset + *offset) & (PAGE_SIZE-1);
 | |
| 			unsigned int sglen = sg->length - *offset;
 | |
| 
 | |
| 			if (sglen > buflen - cnt) {
 | |
| 
 | |
| 				/* Transfer ends within this s-g entry */
 | |
| 				sglen = buflen - cnt;
 | |
| 				*offset += sglen;
 | |
| 			} else {
 | |
| 
 | |
| 				/* Transfer continues to next s-g entry */
 | |
| 				*offset = 0;
 | |
| 				++*index;
 | |
| 				++sg;
 | |
| 			}
 | |
| 
 | |
| 			/* Transfer the data for all the pages in this
 | |
| 			 * s-g entry.  For each page: call kmap(), do the
 | |
| 			 * transfer, and call kunmap() immediately after. */
 | |
| 			while (sglen > 0) {
 | |
| 				unsigned int plen = min(sglen, (unsigned int)
 | |
| 						PAGE_SIZE - poff);
 | |
| 				unsigned char *ptr = kmap(page);
 | |
| 
 | |
| 				if (dir == TO_XFER_BUF)
 | |
| 					memcpy(ptr + poff, buffer + cnt, plen);
 | |
| 				else
 | |
| 					memcpy(buffer + cnt, ptr + poff, plen);
 | |
| 				kunmap(page);
 | |
| 
 | |
| 				/* Start at the beginning of the next page */
 | |
| 				poff = 0;
 | |
| 				++page;
 | |
| 				cnt += plen;
 | |
| 				sglen -= plen;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Return the amount actually transferred */
 | |
| 	return cnt;
 | |
| }
 | |
| 
 | |
| /* Store the contents of buffer into srb's transfer buffer and set the
 | |
|  * SCSI residue. */
 | |
| void usb_stor_set_xfer_buf(unsigned char *buffer,
 | |
| 	unsigned int buflen, struct scsi_cmnd *srb)
 | |
| {
 | |
| 	unsigned int index = 0, offset = 0;
 | |
| 
 | |
| 	usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
 | |
| 			TO_XFER_BUF);
 | |
| 	if (buflen < srb->request_bufflen)
 | |
| 		srb->resid = srb->request_bufflen - buflen;
 | |
| }
 |