📄 usb-storage.c
字号:
/* Driver for USB Mass Storage compliant devices * * (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Further reference: * 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 commands in mind when they * created this document. The commands are all similar to commands * in the SCSI-II specification. * * 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. * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/usb.h>#include <linux/blk.h>#include "../scsi/scsi.h"#include "../scsi/hosts.h"#include "../scsi/sd.h"#include "usb-storage.h"#include "usb-storage-debug.h"/* * This is the size of the structure Scsi_Host_Template. We create * an instance of this structure in this file and this is a check * to see if this structure may have changed within the SCSI module. * This is by no means foolproof, but it does help us some. */#define SCSI_HOST_TEMPLATE_SIZE (104)/* direction table -- this indicates the direction of the data * transfer for each command code -- a 1 indicates input */unsigned char us_direction[256/8] = { 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};/* * Per device data */static int my_host_number;int usb_stor_debug = 1;struct us_data;typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);typedef int (*trans_reset)(struct us_data*);typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);struct us_data { struct us_data *next; /* next device */ struct usb_device *pusb_dev; /* this usb_device */ unsigned int flags; /* from filter initially */ __u8 ifnum; /* interface number */ __u8 ep_in; /* in endpoint */ __u8 ep_out; /* out ....... */ __u8 ep_int; /* interrupt . */ __u8 subclass; /* as in overview */ __u8 protocol; /* .............. */ __u8 attention_done; /* force attn on first cmd */ trans_cmnd transport; /* protocol specific do cmd */ trans_reset transport_reset; /* .......... device reset */ proto_cmnd proto_handler; /* protocol handler */ GUID(guid); /* unique dev id */ struct Scsi_Host *host; /* our dummy host data */ Scsi_Host_Template *htmplt; /* own host template */ int host_number; /* to find us */ int host_no; /* allocated by scsi */ Scsi_Cmnd *srb; /* current srb */ int action; /* what to do */ wait_queue_head_t waitq; /* thread waits */ wait_queue_head_t ip_waitq; /* for CBI interrupts */ __u16 ip_data; /* interrupt data */ int ip_wanted; /* needed */ int pid; /* control thread */ struct semaphore *notify; /* wait for thread to begin */ void *irq_handle; /* for USB int requests */ unsigned int irqpipe; /* pipe for release_irq */};/* * kernel thread actions */#define US_ACT_COMMAND 1#define US_ACT_ABORT 2#define US_ACT_DEVICE_RESET 3#define US_ACT_BUS_RESET 4#define US_ACT_HOST_RESET 5static struct us_data *us_list;static void * storage_probe(struct usb_device *dev, unsigned int ifnum);static void storage_disconnect(struct usb_device *dev, void *ptr);static struct usb_driver storage_driver = { "usb-storage", storage_probe, storage_disconnect, { NULL, NULL }};/*********************************************************************** * Data transfer routines ***********************************************************************//* Transfer one buffer (breaking into packets if necessary) * Note that this function is necessary because if the device NAKs, we * need to know that information directly * * FIXME: is the above true? Or will the URB status show ETIMEDOUT after * retrying several times allready? Perhaps this is the way we should * be going anyway? */static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length){ int max_size; int this_xfer; int result; int partial; int maxtry; /* determine the maximum packet size for these transfers */ max_size = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)) * 16; /* while we have data left to transfer */ while (length) { /* calculate how long this will be -- maximum or a remainder */ this_xfer = length > max_size ? max_size : length; length -= this_xfer; /* FIXME: this number is totally outrageous. We need to pick * a better (smaller) number). */ /* setup the retry counter */ maxtry = 100; /* set up the transfer loop */ do { /* transfer the data */ US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", (unsigned int)buf, this_xfer, 101 - maxtry); result = usb_bulk_msg(us->pusb_dev, pipe, buf, this_xfer, &partial, HZ*5); US_DEBUGP("bulk_msg returned %d xferred %d/%d\n", result, partial, this_xfer); /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); } /* update to show what data was transferred */ this_xfer -= partial; buf += partial; /* NAK - we retry a few times */ if (result == -ETIMEDOUT) { US_DEBUGP("us_one_transfer: device NAKed\n"); /* if our try counter reaches 0, bail out */ if (!maxtry--) return -ETIMEDOUT; /* just continue the while loop */ continue; } /* other errors (besides NAK) -- we just bail out*/ if (result != 0) { US_DEBUGP("us_one_transfer: device returned error %d\n", result); return result; } /* continue until this transfer is done */ } while ( this_xfer ); } /* if we get here, we're done and successful */ return 0;}static unsigned int us_transfer_length(Scsi_Cmnd *srb);/* transfer one SCSI command, using scatter-gather if requested *//* FIXME: what do the return codes here mean? */static int us_transfer(Scsi_Cmnd *srb, int dir_in){ struct us_data *us = (struct us_data *)srb->host_scribble; int i; int result = -1; unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* FIXME: stop transferring data at us_transfer_length(), not * bufflen */ if (srb->use_sg) { struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { result = us_one_transfer(us, pipe, sg[i].address, sg[i].length); if (result) break; } } else result = us_one_transfer(us, pipe, srb->request_buffer, us_transfer_length(srb)); if (result < 0) US_DEBUGP("us_transfer returning error %d\n", result); return result;}/* calculate the length of the data transfer (not the command) for any * given SCSI command */static unsigned int us_transfer_length(Scsi_Cmnd *srb){ int i; unsigned int total = 0; /* always zero for some commands */ switch (srb->cmnd[0]) { case SEEK_6: case SEEK_10: case REZERO_UNIT: case ALLOW_MEDIUM_REMOVAL: case START_STOP: case TEST_UNIT_READY: return 0; case REQUEST_SENSE: case INQUIRY: case MODE_SENSE: return srb->cmnd[4]; case LOG_SENSE: case MODE_SENSE_10: return (srb->cmnd[7] << 8) + srb->cmnd[8]; default: break; } if (srb->use_sg) { struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { total += sg[i].length; } return total; } else return srb->request_bufflen;}/*********************************************************************** * Protocol routines ***********************************************************************/static int CB_transport(Scsi_Cmnd *srb, struct us_data *us);static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us);static void ufi_command(Scsi_Cmnd *srb, struct us_data *us){ int old_cmnd = 0; /* 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[12], so we know we have storage available */ /* set command length to 12 bytes (this affects the transport layer) */ srb->cmd_len = 12; /* determine the correct (or minimum) data length for these commands */ switch (us->srb->cmnd[0]) { /* for INQUIRY, UFI devices only ever return 36 bytes */ case INQUIRY: us->srb->cmnd[4] = 36; break; /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ case MODE_SENSE: case MODE_SELECT: /* save the command so we can tell what it was */ old_cmnd = srb->cmnd[0]; srb->cmnd[11] = 0; srb->cmnd[10] = 0; srb->cmnd[9] = 0; /* if we're sending data, we send all. If getting data, * get the minimum */ if (srb->cmnd[0] == MODE_SELECT) srb->cmnd[8] = srb->cmnd[4]; else srb->cmnd[8] = 8; srb->cmnd[7] = 0; srb->cmnd[6] = 0; srb->cmnd[5] = 0; srb->cmnd[4] = 0; srb->cmnd[3] = 0; srb->cmnd[2] = srb->cmnd[2]; srb->cmnd[1] = srb->cmnd[1]; srb->cmnd[0] = srb->cmnd[0] | 0x40; break; /* again, for MODE_SENSE_10, we get the minimum (8) */ case MODE_SENSE_10: us->srb->cmnd[7] = 0; us->srb->cmnd[8] = 8; break; /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ case REQUEST_SENSE: us->srb->cmnd[4] = 18; break; /* change READ_6/WRITE_6 to READ_10/WRITE_10, which * are UFI commands */ case WRITE_6: case READ_6: srb->cmnd[11] = 0; srb->cmnd[10] = 0; srb->cmnd[9] = 0; srb->cmnd[8] = srb->cmnd[4]; srb->cmnd[7] = 0; srb->cmnd[6] = 0; srb->cmnd[5] = srb->cmnd[3]; srb->cmnd[4] = srb->cmnd[2]; srb->cmnd[3] = srb->cmnd[1] & 0x1F; srb->cmnd[2] = 0; srb->cmnd[1] = srb->cmnd[1] & 0xE0; srb->cmnd[0] = srb->cmnd[0] | 0x20; break; } /* end switch on cmnd[0] */ /* send the command to the transport layer */ us->srb->result = us->transport(srb, us); /* if we have an error, we're going to do a * REQUEST_SENSE automatically */ /* FIXME: we should only do this for device * errors, not system errors */ if (us->srb->result) { int temp_result; int count; void* old_request_buffer; US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); /* set the result so the higher layers expect this data */ us->srb->result = CHECK_CONDITION; us->srb->cmnd[0] = REQUEST_SENSE; us->srb->cmnd[1] = 0; us->srb->cmnd[2] = 0; us->srb->cmnd[3] = 0; us->srb->cmnd[4] = 18; us->srb->cmnd[5] = 0; /* set the buffer length for transfer */ old_request_buffer = us->srb->request_buffer; us->srb->request_bufflen = 18; us->srb->request_buffer = kmalloc(18, GFP_KERNEL); /* FIXME: what if this command fails? */ temp_result = us->transport(us->srb, us); US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); /* copy the data from the request buffer to the sense buffer */ for(count = 0; count < 18; count++) us->srb->sense_buffer[count] = ((unsigned char *)(us->srb->request_buffer))[count]; US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", us->srb->sense_buffer[2] & 0xf, us->srb->sense_buffer[12], us->srb->sense_buffer[13]); /* we're done here */ kfree(us->srb->request_buffer); us->srb->request_buffer = old_request_buffer; return; } /* FIXME: if we need to send more data, or recieve data, we should * do it here. Then, we can do status handling here also. * * This includes MODE_SENSE from above */ if (old_cmnd == MODE_SENSE) { unsigned char *dta = (unsigned char *)us->srb->request_buffer; /* calculate the new length */ int length = (dta[0] << 8) + dta[1] + 2; /* copy the available data length into the structure */ us->srb->cmnd[7] = length >> 8; us->srb->cmnd[8] = length & 0xFF; /* send the command to the transport layer */ us->srb->result = us->transport(srb, us); /* FIXME: this assumes that the 2nd attempt is always * successful convert MODE_SENSE_10 return data format * to MODE_SENSE_6 format */ dta[0] = dta[1]; /* data len */ dta[1] = dta[2]; /* med type */ dta[2] = dta[3]; /* dev-spec prm */ dta[3] = dta[7]; /* block desc len */ printk (KERN_DEBUG USB_STORAGE "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n", dta[0], dta[1], dta[2], dta[3]); } /* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/ * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry */ /* FIXME: here is where we need to fix-up the return data from * an INQUIRY command to show ANSI SCSI rev 2 */ /* FIXME: The rest of this is bogus. usb_control_msg() will only * return an error if we've really honked things up. If it just * needs a START_STOP, then we'll get some data back via
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -