/* Driver for USB Mass Storage compliant devices * * $Id: usb-storage.c,v 1.11 2000/06/20 03:19:31 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.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 #include #include #include #include #include #include #include #include #include #include #include #include "../scsi/scsi.h" #include "../scsi/hosts.h" #include "../scsi/sd.h" #include "usb-storage.h" #include "usb-storage-debug.h" /* direction table -- this indicates the direction of the data * transfer for each command code -- a 1 indicates input */ /* FIXME: we need to use the new direction indicators in the Scsi_Cmnd * structure, not this table. First we need to evaluate if it's being set * correctly for us, though */ 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; 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*); /* we allocate one of these for every device that we remember */ struct us_data { struct us_data *next; /* next device */ /* the device we're working with */ struct semaphore dev_semaphore; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ unsigned int flags; /* from filter initially */ /* information about the device -- always good */ char vendor[USB_STOR_STRING_LEN]; char product[USB_STOR_STRING_LEN]; char serial[USB_STOR_STRING_LEN]; char *transport_name; char *protocol_name; u8 subclass; u8 protocol; u8 max_lun; /* information about the device -- only good if device is attached */ u8 ifnum; /* interface number */ u8 ep_in; /* bulk in endpoint */ u8 ep_out; /* bulk out endpoint */ struct usb_endpoint_descriptor *ep_int; /* interrupt endpoint */ /* function pointers for this device */ trans_cmnd transport; /* transport function */ trans_reset transport_reset; /* transport device reset */ proto_cmnd proto_handler; /* protocol handler */ /* SCSI interfaces */ 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 */ /* thread information */ Scsi_Cmnd *queue_srb; /* the single queue slot */ int action; /* what to do */ int pid; /* control thread */ /* interrupt info for CBI devices -- only good if attached */ struct semaphore ip_waitq; /* for CBI interrupts */ int ip_wanted; /* is an IRQ expected? */ /* interrupt communications data */ struct semaphore irq_urb_sem; /* to protect irq_urb */ struct urb *irq_urb; /* for USB int requests */ unsigned char irqbuf[2]; /* buffer for USB IRQ */ /* control and bulk communications data */ struct semaphore current_urb_sem; /* to protect irq_urb */ struct urb *current_urb; /* non-int USB requests */ /* mutual exclusion structures */ struct semaphore notify; /* thread begin/end */ struct semaphore sleeper; /* to sleep the thread on */ struct semaphore queue_exclusion; /* to protect data structs */ }; /* * kernel thread actions */ #define US_ACT_COMMAND 1 #define US_ACT_DEVICE_RESET 2 #define US_ACT_BUS_RESET 3 #define US_ACT_HOST_RESET 4 #define US_ACT_EXIT 5 /* The list of structures and the protective lock for them */ static struct us_data *us_list; struct semaphore us_list_semaphore; 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 = { name: "usb-storage", probe: storage_probe, disconnect: storage_disconnect, }; /*********************************************************************** * Data transfer routines ***********************************************************************/ /* This is the completion handler which will wake us up when an URB * completes. */ static void usb_stor_blocking_completion(urb_t *urb) { api_wrapper_data *awd = (api_wrapper_data *)urb->context; if (waitqueue_active(awd->wakeup)) wake_up(awd->wakeup); } /* This is our function to emulate usb_control_msg() but give us enough * access to make aborts/resets work */ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size) { DECLARE_WAITQUEUE(wait, current); DECLARE_WAIT_QUEUE_HEAD(wqh); api_wrapper_data awd; int status; devrequest *dr; /* allocate the device request structure */ dr = kmalloc(sizeof(devrequest), GFP_KERNEL); if (!dr) return -ENOMEM; /* fill in the structure */ dr->requesttype = requesttype; dr->request = request; dr->value = cpu_to_le16(value); dr->index = cpu_to_le16(index); dr->length = cpu_to_le16(size); /* set up data structures for the wakeup system */ awd.wakeup = &wqh; awd.handler = 0; init_waitqueue_head(&wqh); add_wait_queue(&wqh, &wait); /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, (unsigned char*) dr, data, size, usb_stor_blocking_completion, &awd); /* submit the URB */ set_current_state(TASK_UNINTERRUPTIBLE); status = usb_submit_urb(us->current_urb); if (status) { /* something went wrong */ up(&(us->current_urb_sem)); remove_wait_queue(&wqh, &wait); kfree(dr); return status; } /* wait for the completion of the URB */ up(&(us->current_urb_sem)); if (us->current_urb->status == -EINPROGRESS) schedule_timeout(10*HZ); down(&(us->current_urb_sem)); /* we either timed out or got woken up -- clean up either way */ set_current_state(TASK_RUNNING); remove_wait_queue(&wqh, &wait); /* did we time out? */ if (us->current_urb->status == -EINPROGRESS) { US_DEBUGP("usb_stor_control_msg() timeout\n"); usb_unlink_urb(us->current_urb); status = -ETIMEDOUT; } else status = us->current_urb->status; /* return the actual length of the data transferred if no error*/ if (status >= 0) status = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); kfree(dr); return status; } /* This is our function to emulate usb_bulk_msg() but give us enough * access to make aborts/resets work */ int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, unsigned int len, unsigned int *act_len) { DECLARE_WAITQUEUE(wait, current); DECLARE_WAIT_QUEUE_HEAD(wqh); api_wrapper_data awd; int status; /* set up data structures for the wakeup system */ awd.wakeup = &wqh; awd.handler = 0; init_waitqueue_head(&wqh); add_wait_queue(&wqh, &wait); /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, usb_stor_blocking_completion, &awd); /* submit the URB */ set_current_state(TASK_UNINTERRUPTIBLE); status = usb_submit_urb(us->current_urb); if (status) { /* something went wrong */ up(&(us->current_urb_sem)); remove_wait_queue(&wqh, &wait); return status; } /* wait for the completion of the URB */ up(&(us->current_urb_sem)); if (us->current_urb->status == -EINPROGRESS) schedule_timeout(10*HZ); down(&(us->current_urb_sem)); /* we either timed out or got woken up -- clean up either way */ set_current_state(TASK_RUNNING); remove_wait_queue(&wqh, &wait); /* did we time out? */ if (us->current_urb->status == -EINPROGRESS) { US_DEBUGP("usb_stor_bulk_msg() timeout\n"); usb_unlink_urb(us->current_urb); status = -ETIMEDOUT; } else status = us->current_urb->status; /* return the actual length of the data transferred */ *act_len = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); return status; } /* * Transfer one SCSI scatter-gather buffer via bulk transfer * * Note that this function is necessary because we want the ability to * use scatter-gather memory. Good performance is achieved by a combination * of scatter-gather and clustering (which makes each chunk bigger). * * Note that the lower layer will always retry when a NAK occurs, up to the * timeout limit. Thus we don't have to worry about it for individual * packets. */ static int us_transfer_partial(struct us_data *us, char *buf, int length) { int result; int partial; int pipe; /* calculate the appropriate pipe information */ if (US_DIRECTION(us->srb->cmnd[0])) pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); else pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ US_DEBUGP("us_transfer_partial(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); /* 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); } /* did we send all the data? */ if (partial == length) { US_DEBUGP("us_transfer_partial(): transfer complete\n"); return US_BULK_TRANSFER_GOOD; } /* uh oh... we have an error code, so something went wrong. */ if (result) { /* NAK - that means we've retried a few times allready */ if (result == -ETIMEDOUT) { US_DEBUGP("us_transfer_partial(): device NAKed\n"); return US_BULK_TRANSFER_FAILED; } /* -ENOENT -- we canceled this transfer */ if (result == -ENOENT) { US_DEBUGP("us_transfer_partial(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } /* the catch-all case */ US_DEBUGP("us_transfer_partial(): unknown error\n"); return US_BULK_TRANSFER_FAILED; } /* no error code, so we must have transferred some data, * just not all of it */ return US_BULK_TRANSFER_SHORT; } /* * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * * Note that this uses us_transfer_partial to achieve it's goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us, int dir_in) { int i; int result = -1; struct scatterlist *sg; /* are we scatter-gathering? */ if (srb->use_sg) { /* loop over all the scatter gather structures and * make the appropriate requests for each, until done */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { result = us_transfer_partial(us, sg[i].address, sg[i].length); if (result) break; } } else /* no scatter-gather, just make the request */ result = us_transfer_partial(us, srb->request_buffer, srb->request_bufflen); /* return the result in the data structure itself */ srb->result = 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, struct us_data *us) { int i; unsigned int total = 0; struct scatterlist *sg; /* support those devices which need the length calculated * differently */ if (us->flags & US_FL_ALT_LENGTH) { if (srb->cmnd[0] == INQUIRY) { srb->cmnd[4] = 36; } if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) return srb->cmnd[4]; if (srb->cmnd[0] == TEST_UNIT_READY) return 0; } /* Are we going to scatter gather? */ if (srb->use_sg) { /* Add up the sizes of all the scatter-gather segments */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) total += sg[i].length; return total; } else /* Just return the length of the buffer */ return srb->request_bufflen; } /*********************************************************************** * Transport routines ***********************************************************************/ /* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and recieve the response. */ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us) { int need_auto_sense; int result; /* send the command to the transport layer */ result = us->transport(srb, us); /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on it's own, we need to auto-sense almost * every time. */ if (us->protocol == US_PR_CB) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; /* There are some exceptions to this. Notably, if this is * a UFI device and the command is REQUEST_SENSE or INQUIRY, * then it is impossible to truly determine status. */ if (us->subclass == US_SC_UFI && ((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY))) { US_DEBUGP("** no auto-sense for a special command\n"); need_auto_sense = 0; } } /* * If we have an error, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_ERROR) { /* FIXME: we need to invoke a transport reset here */ US_DEBUGP("-- transport indicates transport failure\n"); need_auto_sense = 0; srb->result = DID_ERROR << 16; return; } /* * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ if ((srb->result == US_BULK_TRANSFER_SHORT) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); need_auto_sense = 1; } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; void* old_request_buffer; int old_sg; int old_request_bufflen; unsigned char old_cmnd[MAX_COMMAND_SIZE]; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); /* save the old command */ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); /* set the command and the LUN */ srb->cmnd[0] = REQUEST_SENSE; srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[2] = 0; srb->cmnd[3] = 0; srb->cmnd[4] = 18; srb->cmnd[5] = 0; /* set the buffer length for transfer */ old_request_buffer = srb->request_buffer; old_request_bufflen = srb->request_bufflen; old_sg = srb->use_sg; srb->use_sg = 0; srb->request_bufflen = 18; srb->request_buffer = srb->sense_buffer; /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); if (temp_result != USB_STOR_TRANSPORT_GOOD) { /* FIXME: we need to invoke a transport reset here */ US_DEBUGP("-- auto-sense failure\n"); srb->result = DID_ERROR << 16; return; } US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION; /* we're done here, let's clean up */ srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = GOOD; } else /* if (need_auto_sense) */ srb->result = GOOD; /* Regardless of auto-sense, if we _know_ we have an error * condition, show that in the result code */ if (result == USB_STOR_TRANSPORT_FAILED) srb->result = CHECK_CONDITION; /* If we think we're good, then make sure the sense data shows it. * This is necessary because the auto-sense for some devices always * sets byte 0 == 0x70, even if there is no error */ if ((us->protocol == US_PR_CB) && (result == USB_STOR_TRANSPORT_GOOD) && ((srb->sense_buffer[2] & 0xf) == 0x0)) srb->sense_buffer[0] = 0x0; } /* * Control/Bulk/Interrupt transport */ /* The interrupt handler for CBI devices */ static void CBI_irq(struct urb *urb) { struct us_data *us = (struct us_data *)urb->context; US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); US_DEBUGP("-- IRQ state is %d\n", urb->status); /* is the device removed? */ if (urb->status != -ENOENT) { /* save the data for interpretation later */ US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", ((unsigned char*)urb->transfer_buffer)[0], ((unsigned char*)urb->transfer_buffer)[1]); /* was this a wanted interrupt? */ if (us->ip_wanted) { us->ip_wanted = 0; up(&(us->ip_waitq)); } else US_DEBUGP("ERROR: Unwanted interrupt received!\n"); } else US_DEBUGP("-- device has been removed\n"); } static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us) { int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); result = usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* Set up for status notification */ us->ip_wanted = 1; /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (us_transfer_length(srb, us)) { us_transfer(srb, us, US_DIRECTION(srb->cmnd[0])); US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); } /* STATUS STAGE */ /* go to sleep until we get this interrupt */ down(&(us->ip_waitq)); /* if we were woken up by an abort instead of the actual interrupt */ if (us->ip_wanted) { US_DEBUGP("Did not get interrupt on CBI\n"); us->ip_wanted = 0; return USB_STOR_TRANSPORT_ERROR; } US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", ((unsigned char*)us->irq_urb->transfer_buffer)[0], ((unsigned char*)us->irq_urb->transfer_buffer)[1]); /* UFI gives us ASC and ASCQ, like a request sense * * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI * devices, so we ignore the information for those commands. Note * that this means we could be ignoring a real error on these * commands, but that can't be helped. */ if (us->subclass == US_SC_UFI) { if (srb->cmnd[0] == REQUEST_SENSE || srb->cmnd[0] == INQUIRY) return USB_STOR_TRANSPORT_GOOD; else if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) return USB_STOR_TRANSPORT_FAILED; else return USB_STOR_TRANSPORT_GOOD; } /* If not UFI, we interpret the data as a result code * The first byte should always be a 0x0 * The second byte & 0x0F should be 0x0 for good, otherwise error */ if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) { US_DEBUGP("CBI IRQ data showed reserved bType\n"); return USB_STOR_TRANSPORT_ERROR; } switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) { case 0x00: return USB_STOR_TRANSPORT_GOOD; case 0x01: return USB_STOR_TRANSPORT_FAILED; default: return USB_STOR_TRANSPORT_ERROR; } US_DEBUGP("CBI_transport() reached end of function\n"); return USB_STOR_TRANSPORT_ERROR; } /* * Control/Bulk transport */ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us) { int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); result = usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0)); US_DEBUGP("-- usb_clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (us_transfer_length(srb, us)) { us_transfer(srb, us, US_DIRECTION(srb->cmnd[0])); US_DEBUGP("CB data stage result is 0x%x\n", srb->result); } /* STATUS STAGE */ /* NOTE: CB does not have a status stage. Silly, I know. So * we have to catch this at a higher level. */ return USB_STOR_TRANSPORT_GOOD; } /* * Bulk only transport */ /* Determine what the maximum LUN supported is */ static int Bulk_max_lun(struct us_data *us) { unsigned char data; int result; int pipe; /* issue the command */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); result = usb_control_msg(us->pusb_dev, pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, &data, sizeof(data), HZ); US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", result, data); /* if we have a successful request, return the result */ if (result == 1) return data; /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ return 0; } static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; int pipe; int partial; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us)); bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; bcb.Length = srb->cmd_len; /* construct the pipe handle */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); /* send it to out endpoint */ US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun, bcb.DataTransferLength, bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* 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); } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; } /* if the command transfered well, then we go to the data stage */ if (result == 0) { /* send/receive data payload, if there is any */ if (bcb.DataTransferLength) { us_transfer(srb, us, bcb.Flags); US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result); } } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ /* construct the pipe handle */ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); usb_clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } /* if we still have a failure at this point, we're in trouble */ US_DEBUGP("Bulk status result = %d\n", result); if (result) { return USB_STOR_TRANSPORT_ERROR; } /* check bulk status */ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n", le32_to_cpu(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || bcs.Tag != bcb.Tag || bcs.Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } /* based on the status code, we report good or bad */ switch (bcs.Status) { case US_BULK_STAT_OK: /* command good -- note that we could be short on data */ return USB_STOR_TRANSPORT_GOOD; case US_BULK_STAT_FAIL: /* command failed */ return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: /* phase error */ return USB_STOR_TRANSPORT_ERROR; } /* we should never get here, but if we do, we're in trouble */ return USB_STOR_TRANSPORT_ERROR; } /*********************************************************************** * Protocol routines ***********************************************************************/ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) { int old_cmnd = 0; /* Fix some commands -- this is a form of mode translation * ATAPI 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 */ srb->cmd_len = 12; /* determine the correct (or minimum) data length for these commands */ switch (srb->cmnd[0]) { /* 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; srb->cmnd[8] = srb->cmnd[4]; 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; /* change READ_6/WRITE_6 to READ_10/WRITE_10, which * are ATAPI 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] */ /* convert MODE_SELECT data here */ if (old_cmnd == MODE_SELECT) usb_stor_scsiSense6to10(srb); /* send the command to the transport layer */ invoke_transport(srb, us); /* Fix the MODE_SENSE data if we translated the command */ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) usb_stor_scsiSense10to6(srb); /* Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us */ if (srb->cmnd[0] == INQUIRY) { ((unsigned char *)us->srb->request_buffer)[2] |= 0x2; } } 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 (srb->cmnd[0]) { /* for INQUIRY, UFI devices only ever return 36 bytes */ case INQUIRY: 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: 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; /* 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] */ /* convert MODE_SELECT data here */ if (old_cmnd == MODE_SELECT) usb_stor_scsiSense6to10(srb); /* send the command to the transport layer */ invoke_transport(srb, us); /* Fix the MODE_SENSE data if we translated the command */ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) usb_stor_scsiSense10to6(srb); /* Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us */ if (srb->cmnd[0] == INQUIRY) { ((unsigned char *)us->srb->request_buffer)[2] |= 0x2; } } static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) { /* This code supports devices which do not support {READ|WRITE}_6 * Apparently, neither Windows or MacOS will use these commands, * so some devices do not support them */ if (us->flags & US_FL_MODE_XLATE) { /* translate READ_6 to READ_10 */ if (srb->cmnd[0] == 0x08) { /* get the control */ srb->cmnd[9] = us->srb->cmnd[5]; /* get the length */ srb->cmnd[8] = us->srb->cmnd[6]; srb->cmnd[7] = 0; /* set the reserved area to 0 */ srb->cmnd[6] = 0; /* get LBA */ srb->cmnd[5] = us->srb->cmnd[3]; srb->cmnd[4] = us->srb->cmnd[2]; srb->cmnd[3] = 0; srb->cmnd[2] = 0; /* LUN and other info in cmnd[1] can stay */ /* fix command code */ srb->cmnd[0] = 0x28; US_DEBUGP("Changing READ_6 to READ_10\n"); US_DEBUG(us_show_command(srb)); } /* translate WRITE_6 to WRITE_10 */ if (srb->cmnd[0] == 0x0A) { /* get the control */ srb->cmnd[9] = us->srb->cmnd[5]; /* get the length */ srb->cmnd[8] = us->srb->cmnd[4]; srb->cmnd[7] = 0; /* set the reserved area to 0 */ srb->cmnd[6] = 0; /* get LBA */ srb->cmnd[5] = us->srb->cmnd[3]; srb->cmnd[4] = us->srb->cmnd[2]; srb->cmnd[3] = 0; srb->cmnd[2] = 0; /* LUN and other info in cmnd[1] can stay */ /* fix command code */ srb->cmnd[0] = 0x2A; US_DEBUGP("Changing WRITE_6 to WRITE_10\n"); US_DEBUG(us_show_command(us->srb)); } } /* if (us->flags & US_FL_MODE_XLATE) */ /* send the command to the transport layer */ invoke_transport(srb, us); /* fix the results of an INQUIRY */ if (srb->cmnd[0] == INQUIRY) { US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n"); ((unsigned char*)us->srb->request_buffer)[2] |= 2; } } /*********************************************************************** * Reset routines ***********************************************************************/ /* This issues a CB[I] Reset to the device in question */ static int CB_reset(struct us_data *us) { unsigned char cmd[12]; int result; US_DEBUGP("CB_reset() called\n"); memset(cmd, 0xFF, sizeof(cmd)); cmd[0] = SEND_DIAGNOSTIC; cmd[1] = 4; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, sizeof(cmd), HZ*5); /* long wait for reset */ schedule_timeout(HZ*6); US_DEBUGP("CB_reset: clearing endpoint halt\n"); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); return 0; } /* FIXME: Does this work? */ static int Bulk_reset(struct us_data *us) { int result; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0, HZ*5); if (result < 0) US_DEBUGP("Bulk hard reset failed %d\n", result); usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* long wait for reset */ schedule_timeout(HZ*6); return result; } /*********************************************************************** * Host functions ***********************************************************************/ static const char* us_info(struct Scsi_Host *host) { return "SCSI emulation for USB Mass Storage devices"; } /* detect a virtual adapter (always works) */ static int us_detect(struct SHT *sht) { struct us_data *us; char local_name[32]; /* This is not nice at all, but how else are we to get the * data here? */ us = (struct us_data *)sht->proc_dir; /* set up the name of our subdirectory under /proc/scsi/ */ sprintf(local_name, "usb-storage-%d", us->host_number); sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); if (!sht->proc_name) return 0; strcpy(sht->proc_name, local_name); /* we start with no /proc directory entry */ sht->proc_dir = NULL; /* register the host */ us->host = scsi_register(sht, sizeof(us)); if (us->host) { us->host->hostdata[0] = (unsigned long)us; us->host_no = us->host->host_no; return 1; } /* odd... didn't register properly. Abort and free pointers */ kfree(sht->proc_name); sht->proc_name = NULL; return 0; } /* Release all resources used by the virtual host * * NOTE: There is no contention here, because we're allready deregistered * the driver and we're doing each virtual host in turn, not in parallel */ static int us_release(struct Scsi_Host *psh) { struct us_data *us = (struct us_data *)psh->hostdata[0]; US_DEBUGP("us_release() called for host %s\n", us->htmplt.name); /* Kill the control threads * * Enqueue the command, wake up the thread, and wait for * notification that it's exited. */ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n"); us->action = US_ACT_EXIT; up(&(us->sleeper)); down(&(us->notify)); /* free the data structure we were using */ US_DEBUGP("-- freeing URB\n"); kfree(us->current_urb); (struct us_data*)psh->hostdata[0] = NULL; /* we always have a successful release */ return 0; } /* run command */ static int us_command( Scsi_Cmnd *srb ) { US_DEBUGP("Bad use of us_command\n"); return DID_BAD_TARGET << 16; } /* run command */ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; US_DEBUGP("us_queuecommand() called\n"); srb->host_scribble = (unsigned char *)us; /* get exclusive access to the structures we want */ down(&(us->queue_exclusion)); /* enqueue the command */ us->queue_srb = srb; srb->scsi_done = done; us->action = US_ACT_COMMAND; /* wake up the process task */ up(&(us->queue_exclusion)); up(&(us->sleeper)); return 0; } /*********************************************************************** * Error handling functions ***********************************************************************/ /* Command abort * * Note that this is really only meaningful right now for CBI transport * devices which have failed to give us the command completion interrupt */ static int us_abort( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; US_DEBUGP("us_abort() called\n"); /* if we're stuck waiting for an IRQ, simulate it */ if (us->ip_wanted) { US_DEBUGP("-- simulating missing IRQ\n"); up(&(us->ip_waitq)); return SUCCESS; } return FAILED; } /* FIXME: this doesn't do anything right now */ static int us_bus_reset( Scsi_Cmnd *srb ) { // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" ); US_DEBUGP("Bus reset requested\n"); // us->transport_reset(us); return FAILED; } /* FIXME: This doesn't actually reset anything */ static int us_host_reset( Scsi_Cmnd *srb ) { printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" ); return FAILED; } /*********************************************************************** * /proc/scsi/ functions ***********************************************************************/ /* we use this macro to help us write into the buffer */ #undef SPRINTF #define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) int usb_stor_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct us_data *us; char *pos = buffer; /* if someone is sending us data, just throw it away */ if (inout) return length; /* lock the data structures */ down(&us_list_semaphore); /* find our data from hostno */ us = us_list; while (us) { if (us->host_no == hostno) break; us = us->next; } /* if we couldn't find it, we return an error */ if (!us) { up(&us_list_semaphore); return -ESRCH; } /* print the controler name */ SPRINTF(" Host scsi%d: usb-storage\n", hostno); /* print product, vendor, and serial number strings */ SPRINTF(" Vendor: %s\n", us->vendor); SPRINTF(" Product: %s\n", us->product); SPRINTF("Serial Number: %s\n", us->serial); /* show the protocol and transport */ SPRINTF(" Protocol: %s\n", us->protocol_name); SPRINTF(" Transport: %s\n", us->transport_name); /* show the GUID of the device */ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); /* release our lock on the data structures */ up(&us_list_semaphore); /* * Calculate start of next buffer, and return value. */ *start = buffer + offset; if ((pos - buffer) < offset) return (0); else if ((pos - buffer - offset) < length) return (pos - buffer - offset); else return (length); } /* * this defines our 'host' */ static Scsi_Host_Template my_host_template = { name: "usb-storage", proc_info: usb_stor_proc_info, info: us_info, detect: us_detect, release: us_release, command: us_command, queuecommand: us_queuecommand, eh_abort_handler: us_abort, eh_device_reset_handler:us_bus_reset, eh_bus_reset_handler: us_bus_reset, eh_host_reset_handler: us_host_reset, can_queue: 1, this_id: -1, sg_tablesize: SG_ALL, cmd_per_lun: 1, present: 0, unchecked_isa_dma: FALSE, use_clustering: TRUE, use_new_eh_code: TRUE, emulated: TRUE }; static unsigned char sense_notready[] = { [0] = 0x70, /* current error */ [2] = 0x02, /* not ready */ [5] = 0x0a, /* additional length */ [10] = 0x04, /* not ready */ [11] = 0x03 /* manual intervention */ }; static int usb_stor_control_thread(void * __us) { struct us_data *us = (struct us_data *)__us; int action; lock_kernel(); /* * This thread doesn't need any user-level access, * so get rid of all our resources.. */ daemonize(); /* set our name for identification purposes */ sprintf(current->comm, "usb-storage-%d", us->host_number); unlock_kernel(); /* signal that we've started the thread */ up(&(us->notify)); for(;;) { US_DEBUGP("*** thread sleeping.\n"); down(&(us->sleeper)); down(&(us->queue_exclusion)); US_DEBUGP("*** thread awakened.\n"); /* take the command off the queue */ action = us->action; us->action = 0; us->srb = us->queue_srb; /* release the queue lock as fast as possible */ up(&(us->queue_exclusion)); switch (action) { case US_ACT_COMMAND: /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ if (us->srb->target || (us->srb->lun > us->max_lun)) { US_DEBUGP("Bad device number (%d/%d)\n", us->srb->target, us->srb->lun); us->srb->result = DID_BAD_TARGET << 16; us->srb->scsi_done(us->srb); us->srb = NULL; break; } /* handle those devices which can't do a START_STOP */ if ((us->srb->cmnd[0] == START_STOP) && (us->flags & US_FL_START_STOP)) { us->srb->result = GOOD; us->srb->scsi_done(us->srb); us->srb = NULL; break; } /* lock the device pointers */ down(&(us->dev_semaphore)); /* our device has gone - pretend not ready */ if (!us->pusb_dev) { US_DEBUGP("Request is for removed device\n"); /* For REQUEST_SENSE, it's the data. But * for anything else, it should look like * we auto-sensed for it. */ if (us->srb->cmnd[0] == REQUEST_SENSE) { memcpy(us->srb->request_buffer, sense_notready, sizeof(sense_notready)); us->srb->result = GOOD; } else { memcpy(us->srb->sense_buffer, sense_notready, sizeof(sense_notready)); us->srb->result = CHECK_CONDITION; } } else { /* !us->pusb_dev */ /* we've got a command, let's do it! */ US_DEBUG(us_show_command(us->srb)); us->proto_handler(us->srb, us); } /* unlock the device pointers */ up(&(us->dev_semaphore)); /* indicate that the command is done */ US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); us->srb = NULL; break; case US_ACT_DEVICE_RESET: break; case US_ACT_BUS_RESET: break; case US_ACT_HOST_RESET: break; } /* end switch on action */ /* exit if we get a signal to exit */ if (action == US_ACT_EXIT) { US_DEBUGP("-- US_ACT_EXIT command recieved\n"); break; } } /* for (;;) */ /* notify the exit routine that we're actually exiting now */ up(&(us->notify)); return 0; } /* This is the list of devices we recognize, along with their flag data */ static struct us_unusual_dev us_unusual_dev_list[] = { { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0}, { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN}, { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP}, { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER}, { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge", US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH}, { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, { 0 }}; /* Search our ususual device list, based on vendor/product combinations * to see if we can support this device. Returns a pointer to a structure * defining how we should support this device, or NULL if it's not in the * list */ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, u16 bcdDevice) { struct us_unusual_dev* ptr; US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n", idVendor, idProduct, bcdDevice); ptr = us_unusual_dev_list; while ((ptr->idVendor != 0x0000) && !((ptr->idVendor == idVendor) && (ptr->idProduct == idProduct) && (ptr->bcdDeviceMin <= bcdDevice) && (ptr->bcdDeviceMax >= bcdDevice))) ptr++; /* if the search ended because we hit the end record, we failed */ if (ptr->idVendor == 0x0000) { US_DEBUGP("-- did not find a matching device\n"); return NULL; } /* otherwise, we found one! */ US_DEBUGP("-- found matching device: %s\n", ptr->name); return ptr; } /* Set up the IRQ pipe and handler * Note that this function assumes that all the data in the us_data * strucuture is current. This includes the ep_int field, which gives us * the endpoint for the interrupt. * Returns non-zero on failure, zero on success */ static int usb_stor_allocate_irq(struct us_data *ss) { unsigned int pipe; int maxp; int result; US_DEBUGP("Allocating IRQ for CBI transport\n"); /* lock access to the data structure */ down(&(ss->irq_urb_sem)); /* allocate the URB */ ss->irq_urb = usb_alloc_urb(0); if (!ss->irq_urb) { up(&(ss->irq_urb_sem)); US_DEBUGP("couldn't allocate interrupt URB"); return 1; } /* calculate the pipe and max packet size */ pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe)); if (maxp > sizeof(ss->irqbuf)) maxp = sizeof(ss->irqbuf); /* fill in the URB with our data */ FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp, CBI_irq, ss, ss->ep_int->bInterval); /* submit the URB for processing */ result = usb_submit_urb(ss->irq_urb); US_DEBUGP("usb_submit_urb() returns %d\n", result); if (result) { usb_free_urb(ss->irq_urb); up(&(ss->irq_urb_sem)); return 2; } /* unlock the data structure and return success */ up(&(ss->irq_urb_sem)); return 0; } /* Probe to see if a new device is actually a SCSI device */ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) { int i; char mf[USB_STOR_STRING_LEN]; /* manufacturer */ char prod[USB_STOR_STRING_LEN]; /* product */ char serial[USB_STOR_STRING_LEN]; /* serial number */ GUID(guid); /* Global Unique Identifier */ unsigned int flags; struct us_unusual_dev *unusual_dev; struct us_data *ss = NULL; int result; /* these are temporary copies -- we test on these, then put them * in the us-data structure */ struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct usb_endpoint_descriptor *ep_int = NULL; u8 subclass = 0; u8 protocol = 0; /* the altsettting 0 on the interface we're probing */ struct usb_interface_descriptor *altsetting = &(dev->actconfig->interface[ifnum].altsetting[0]); /* clear the temporary strings */ memset(mf, 0, sizeof(mf)); memset(prod, 0, sizeof(prod)); memset(serial, 0, sizeof(serial)); /* search for this device in our unusual device list */ unusual_dev = us_find_dev(dev->descriptor.idVendor, dev->descriptor.idProduct, dev->descriptor.bcdDevice); /* * Can we support this device, either because we know about it * from our unusual device list, or because it advertises that it's * compliant to the specification? */ if (!unusual_dev && !(dev->descriptor.bDeviceClass == 0 && altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE && altsetting->bInterfaceSubClass >= US_SC_MIN && altsetting->bInterfaceSubClass <= US_SC_MAX)) { /* if it's not a mass storage, we go no further */ return NULL; } /* At this point, we know we've got a live one */ US_DEBUGP("USB Mass Storage device detected\n"); /* Determine subclass and protocol, or copy from the interface */ if (unusual_dev) { subclass = unusual_dev->useProtocol; protocol = unusual_dev->useTransport; flags = unusual_dev->flags; } else { subclass = altsetting->bInterfaceSubClass; protocol = altsetting->bInterfaceProtocol; flags = 0; } /* * Find the endpoints we need * We are expecting a minimum of 2 endpoints - in and out (bulk). * An optional interrupt is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < altsetting->bNumEndpoints; i++) { /* is it an BULK endpoint? */ if ((altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { /* BULK in or out? */ if (altsetting->endpoint[i].bEndpointAddress & USB_DIR_IN) ep_in = &altsetting->endpoint[i]; else ep_out = &altsetting->endpoint[i]; } /* is it an interrupt endpoint? */ if ((altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ep_int = &altsetting->endpoint[i]; } } US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); /* set the interface -- STALL is an acceptable response here */ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); US_DEBUGP("Result from usb_set_interface is %d\n", result); if (result == -EPIPE) { US_DEBUGP("-- clearing stall on control interface\n"); usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); } else if (result != 0) { /* it's not a stall, but another error -- time to bail */ US_DEBUGP("-- Unknown error. Rejecting device\n"); return NULL; } /* Do some basic sanity checks, and bail if we find a problem */ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Sanity check failed. Rejecting device.\n"); return NULL; } /* At this point, we're committed to using the device */ /* clear the GUID and fetch the strings */ GUID_CLEAR(guid); if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf)); if (dev->descriptor.iProduct) usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod)); if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER)) usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial)); /* Create a GUID for this device */ if (dev->descriptor.iSerialNumber && serial[0]) { /* If we have a serial number, and it's a non-NULL string */ make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, serial); } else { /* We don't have a serial number, so we use 0 */ make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct, "0"); } /* lock access to the data structures */ down(&us_list_semaphore); /* * Now check if we have seen this GUID before * We're looking for a device with a matching GUID that isn't * allready on the system */ ss = us_list; while ((ss != NULL) && ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid))) ss = ss->next; if (ss != NULL) { /* Existing device -- re-connect */ US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); /* establish the connection to the new device upon reconnect */ ss->ifnum = ifnum; ss->pusb_dev = dev; /* copy over the endpoint data */ if (ep_in) ss->ep_in = ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if (ep_out) ss->ep_out = ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ss->ep_int = ep_int; /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; } else { /* New device -- allocate memory and initialize */ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), GFP_KERNEL)) == NULL) { printk(KERN_WARNING USB_STORAGE "Out of memory\n"); up(&us_list_semaphore); return NULL; } memset(ss, 0, sizeof(struct us_data)); /* allocate the URB we're going to use */ ss->current_urb = usb_alloc_urb(0); if (!ss->current_urb) { kfree(ss); return NULL; } /* Initialize the mutexes only when the struct is new */ init_MUTEX_LOCKED(&(ss->sleeper)); init_MUTEX_LOCKED(&(ss->notify)); init_MUTEX_LOCKED(&(ss->ip_waitq)); init_MUTEX(&(ss->queue_exclusion)); init_MUTEX(&(ss->irq_urb_sem)); init_MUTEX(&(ss->current_urb_sem)); init_MUTEX(&(ss->dev_semaphore)); /* copy over the subclass and protocol data */ ss->subclass = subclass; ss->protocol = protocol; ss->flags = flags; /* copy over the endpoint data */ if (ep_in) ss->ep_in = ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if (ep_out) ss->ep_out = ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ss->ep_int = ep_int; /* establish the connection to the new device */ ss->ifnum = ifnum; ss->pusb_dev = dev; /* copy over the identifiying strings */ strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN); if (strlen(ss->vendor) == 0) strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN); if (strlen(ss->product) == 0) strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN); if (strlen(ss->serial) == 0) strncpy(ss->serial, "None", USB_STOR_STRING_LEN); /* copy the GUID we created before */ memcpy(ss->guid, guid, sizeof(guid)); /* * Set the handler pointers based on the protocol * Again, this data is persistant across reattachments */ switch (ss->protocol) { case US_PR_CB: ss->transport_name = "Control/Bulk"; ss->transport = CB_transport; ss->transport_reset = CB_reset; ss->max_lun = 7; break; case US_PR_CBI: ss->transport_name = "Control/Bulk/Interrupt"; ss->transport = CBI_transport; ss->transport_reset = CB_reset; ss->max_lun = 7; break; case US_PR_BULK: ss->transport_name = "Bulk"; ss->transport = Bulk_transport; ss->transport_reset = Bulk_reset; ss->max_lun = Bulk_max_lun(ss); break; default: ss->transport_name = "Unknown"; up(&us_list_semaphore); kfree(ss->current_urb); kfree(ss); return NULL; break; } US_DEBUGP("Transport: %s\n", ss->transport_name); /* fix for single-lun devices */ if (ss->flags & US_FL_SINGLE_LUN) ss->max_lun = 0; switch (ss->subclass) { case US_SC_RBC: ss->protocol_name = "Reduced Block Commands (RBC)"; ss->proto_handler = transparent_scsi_command; break; case US_SC_8020: ss->protocol_name = "8020i"; ss->proto_handler = ATAPI_command; break; case US_SC_QIC: ss->protocol_name = "QIC-157"; US_DEBUGP("Sorry, device not supported. Please\n"); US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n"); US_DEBUGP("if you see this message.\n"); up(&us_list_semaphore); kfree(ss->current_urb); kfree(ss); return NULL; break; case US_SC_8070: ss->protocol_name = "8070i"; ss->proto_handler = ATAPI_command; break; case US_SC_SCSI: ss->protocol_name = "Transparent SCSI"; ss->proto_handler = transparent_scsi_command; break; case US_SC_UFI: ss->protocol_name = "Uniform Floppy Interface (UFI)"; ss->proto_handler = ufi_command; break; default: ss->protocol_name = "Unknown"; up(&us_list_semaphore); kfree(ss->current_urb); kfree(ss); return NULL; break; } US_DEBUGP("Protocol: %s\n", ss->protocol_name); /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; /* * Since this is a new device, we need to generate a scsi * host definition, and register with the higher SCSI layers */ /* Initialize the host template based on the default one */ memcpy(&(ss->htmplt), &my_host_template, sizeof(my_host_template)); /* Grab the next host number */ ss->host_number = my_host_number++; /* We abuse this pointer so we can pass the ss pointer to * the host controler thread in us_detect. But how else are * we to do it? */ (struct us_data *)ss->htmplt.proc_dir = ss; /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); if (ss->pid < 0) { printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); kfree(ss->current_urb); kfree(ss); return NULL; } /* wait for the thread to start */ down(&(ss->notify)); /* now register - our detect function will be called */ ss->htmplt.module = THIS_MODULE; scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt)); /* put us in the list */ ss->next = us_list; us_list = ss; } /* release the data structure lock */ up(&us_list_semaphore); printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n"); printk(KERN_DEBUG "USB Mass Storage device found at %d\n", dev->devnum); /* return a pointer for the disconnect function */ return ss; } /* Handle a disconnect event from the USB core */ static void storage_disconnect(struct usb_device *dev, void *ptr) { struct us_data *ss = ptr; int result; US_DEBUGP("storage_disconnect() called\n"); /* this is the odd case -- we disconnected but weren't using it */ if (!ss) { US_DEBUGP("-- device was not in use\n"); return; } /* lock access to the device data structure */ down(&(ss->dev_semaphore)); /* release the IRQ, if we have one */ down(&(ss->irq_urb_sem)); if (ss->irq_urb) { US_DEBUGP("-- releasing irq handle\n"); result = usb_unlink_urb(ss->irq_urb); ss->irq_urb = NULL; US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); usb_free_urb(ss->irq_urb); } up(&(ss->irq_urb_sem)); /* mark the device as gone */ ss->pusb_dev = NULL; /* lock access to the device data structure */ up(&(ss->dev_semaphore)); } /************************************************************** **************************************************************/ #define USB_STOR_SCSI_SENSE_HDRSZ 4 #define USB_STOR_SCSI_SENSE_10_HDRSZ 8 struct usb_stor_scsi_sense_hdr { __u8* dataLength; __u8* mediumType; __u8* devSpecParms; __u8* blkDescLength; }; typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; union usb_stor_scsi_sense_hdr_u { Usb_Stor_Scsi_Sense_Hdr hdr; __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; }; typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; struct usb_stor_scsi_sense_hdr_10 { __u8* dataLengthMSB; __u8* dataLengthLSB; __u8* mediumType; __u8* devSpecParms; __u8* reserved1; __u8* reserved2; __u8* blkDescLengthMSB; __u8* blkDescLengthLSB; }; typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; union usb_stor_scsi_sense_hdr_10_u { Usb_Stor_Scsi_Sense_Hdr_10 hdr; __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; }; typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ); int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) { __u8 *buffer=0; int outputBufferSize = 0; int length=0; struct scatterlist *sg = 0; int i=0, j=0, element=0; Usb_Stor_Scsi_Sense_Hdr_u the6Locations; Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; int sb=0,si=0,db=0,di=0; int sgLength=0; #if 0 /* Make sure we get a MODE_SENSE_10 command */ if ( the10->cmnd[0] != MODE_SENSE_10 ) { printk( KERN_ERR USB_STORAGE "Scsi_Cmnd was not a MODE_SENSE_10.\n" ); return -1; } /* Now start to format the output */ the10->cmnd[0] = MODE_SENSE; #endif US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); the10->cmnd[0] = the10->cmnd[0] & 0xBF; /* Determine buffer locations */ usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, &length ); /* Work out minimum buffer to output */ outputBufferSize = *the10Locations.hdr.dataLengthLSB; outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; /* Check to see if we need to truncate the output */ if ( outputBufferSize > length ) { printk( KERN_WARNING USB_STORAGE "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); printk( KERN_WARNING USB_STORAGE "outputBufferSize is %d and length is %d.\n", outputBufferSize, length ); } outputBufferSize = length; /* Data length */ if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ { printk( KERN_WARNING USB_STORAGE "Command will be truncated to fit in SENSE6 buffer.\n" ); *the6Locations.hdr.dataLength = 0xff; } else { *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; } /* Medium type and DevSpecific parms */ *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; /* Block descriptor length */ if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ { printk( KERN_WARNING USB_STORAGE "Command will be truncated to fit in SENSE6 buffer.\n" ); *the6Locations.hdr.blkDescLength = 0xff; } else { *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; } if ( the10->use_sg == 0 ) { buffer = the10->request_buffer; /* Copy the rest of the data */ memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); /* initialise last bytes left in buffer due to smaller header */ memset( &(buffer[outputBufferSize -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), 0, USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); } else { sg = (struct scatterlist *) the10->request_buffer; /* scan through this scatterlist and figure out starting positions */ for ( i=0; i < the10->use_sg; i++) { sgLength = sg[i].length; for ( j=0; juse_sg; } element++; } } /* Now we know where to start the copy from */ element = USB_STOR_SCSI_SENSE_HDRSZ; while ( element < outputBufferSize -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) { /* check limits */ if ( sb >= the10->use_sg || si >= sg[sb].length || db >= the10->use_sg || di >= sg[db].length ) { printk( KERN_ERR USB_STORAGE "Buffer overrun averted, this shouldn't happen!\n" ); break; } /* copy one byte */ sg[db].address[di] = sg[sb].address[si]; /* get next destination */ if ( sg[db].length-1 == di ) { db++; di=0; } else { di++; } /* get next source */ if ( sg[sb].length-1 == si ) { sb++; si=0; } else { si++; } element++; } /* zero the remaining bytes */ while ( element < outputBufferSize ) { /* check limits */ if ( db >= the10->use_sg || di >= sg[db].length ) { printk( KERN_ERR USB_STORAGE "Buffer overrun averted, this shouldn't happen!\n" ); break; } sg[db].address[di] = 0; /* get next destination */ if ( sg[db].length-1 == di ) { db++; di=0; } else { di++; } element++; } } /* All done any everything was fine */ return 0; } int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) { /* will be used to store part of buffer */ __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], *buffer=0; int outputBufferSize = 0; int length=0; struct scatterlist *sg = 0; int i=0, j=0, element=0; Usb_Stor_Scsi_Sense_Hdr_u the6Locations; Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; int sb=0,si=0,db=0,di=0; int lsb=0,lsi=0,ldb=0,ldi=0; #if 0 /* Make sure we get a MODE_SENSE command */ if ( the6->cmnd[0] != MODE_SENSE ) { printk( KERN_ERR USB_STORAGE "Scsi_Cmnd was not MODE_SENSE.\n" ); return -1; } /* Now start to format the output */ the6->cmnd[0] = MODE_SENSE_10; #endif US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); the6->cmnd[0] = the6->cmnd[0] | 0x40; /* Determine buffer locations */ usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, &length ); /* Work out minimum buffer to output */ outputBufferSize = *the6Locations.hdr.dataLength; outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; /* Check to see if we need to trucate the output */ if ( outputBufferSize > length ) { printk( KERN_WARNING USB_STORAGE "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); printk( KERN_WARNING USB_STORAGE "outputBufferSize is %d and length is %d.\n", outputBufferSize, length ); } outputBufferSize = length; /* Block descriptor length - save these before overwriting */ tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; *the10Locations.hdr.blkDescLengthMSB = 0; /* reserved - save these before overwriting */ tempBuffer[0] = *the10Locations.hdr.reserved1; tempBuffer[1] = *the10Locations.hdr.reserved2; *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; /* Medium type and DevSpecific parms */ *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; /* Data length */ *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; *the10Locations.hdr.dataLengthMSB = 0; if ( !the6->use_sg ) { buffer = the6->request_buffer; /* Copy the rest of the data */ memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); /* Put the first four bytes (after header) in place */ memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), tempBuffer, USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); } else { sg = (struct scatterlist *) the6->request_buffer; /* scan through this scatterlist and figure out ending positions */ for ( i=0; i < the6->use_sg; i++) { for ( j=0; juse_sg; break; } element++; } } /* scan through this scatterlist and figure out starting positions */ element = length-1; /* destination is the last element */ db=the6->use_sg-1; di=sg[db].length-1; for ( i=the6->use_sg-1; i >= 0; i--) { for ( j=sg[i].length-1; j>=0; j-- ) { /* get to end of header and find source for copy */ if ( element == length - 1 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) { sb=i; si=j; /* we've found both sets now, exit loops */ j=-1; i=-1; } element--; } } /* Now we know where to start the copy from */ element = length-1 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) { /* check limits */ if ( ( sb <= lsb && si < lsi ) || ( db <= ldb && di < ldi ) ) { printk( KERN_ERR USB_STORAGE "Buffer overrun averted, this shouldn't happen!\n" ); break; } /* copy one byte */ sg[db].address[di] = sg[sb].address[si]; /* get next destination */ if ( di == 0 ) { db--; di=sg[db].length-1; } else { di--; } /* get next source */ if ( si == 0 ) { sb--; si=sg[sb].length-1; } else { si--; } element--; } /* copy the remaining four bytes */ while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) { /* check limits */ if ( db <= ldb && di < ldi ) { printk( KERN_ERR USB_STORAGE "Buffer overrun averted, this shouldn't happen!\n" ); break; } sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; /* get next destination */ if ( di == 0 ) { db--; di=sg[db].length-1; } else { di--; } element--; } } /* All done and everything was fine */ return 0; } void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, Usb_Stor_Scsi_Sense_Hdr_10_u* the10, int* length_p ) { int i = 0, j=0, element=0; struct scatterlist *sg = 0; int length = 0; __u8* buffer=0; /* are we scatter-gathering? */ if ( srb->use_sg != 0 ) { /* loop over all the scatter gather structures and * get pointer to the data members in the headers * (also work out the length while we're here) */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { length += sg[i].length; /* We only do the inner loop for the headers */ if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) { /* scan through this scatterlist */ for ( j=0; jarray[element] = &(sg[i].address[j]); the10->array[element] = &(sg[i].address[j]); } else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) { /* only the longer headers still cares now */ the10->array[element] = &(sg[i].address[j]); } /* increase element counter */ element++; } } } } else { length = srb->request_bufflen; buffer = srb->request_buffer; if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) printk( KERN_ERR USB_STORAGE "Buffer length smaller than header!!" ); for( i=0; iarray[i] = &(buffer[i]); the10->array[i] = &(buffer[i]); } else { the10->array[i] = &(buffer[i]); } } } /* Set value of length passed in */ *length_p = length; } void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ) { int i=0, bufferSize = cmd->request_bufflen; __u8* buffer = cmd->request_buffer; struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer; printk( KERN_ERR "Dumping information about %p.\n", cmd ); printk( KERN_ERR "cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] ); printk( KERN_ERR "(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n", MODE_SENSE, MODE_SENSE_10 ); printk( KERN_ERR "buffer is %p with length %d.\n", buffer, bufferSize ); for ( i=0; iuse_sg ); for ( i=0; iuse_sg; i++ ) { printk( KERN_ERR "Length of scatterlist %d is %d.\n", i, sg[i].length ); printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", sg[i].address[0], sg[i].address[1], sg[i].address[2], sg[i].address[3], sg[i].address[4], sg[i].address[5], sg[i].address[6], sg[i].address[7], sg[i].address[8], sg[i].address[9], sg[i].address[10], sg[i].address[11], sg[i].address[12], sg[i].address[13], sg[i].address[14], sg[i].address[15] ); } } /************************************************************** **************************************************************/ /*********************************************************************** * Initialization and registration ***********************************************************************/ int __init usb_stor_init(void) { /* initialize internal global data elements */ us_list = NULL; init_MUTEX(&us_list_semaphore); my_host_number = 0; /* register the driver, return -1 if error */ if (usb_register(&storage_driver) < 0) return -1; /* we're all set */ printk(KERN_INFO "USB Mass Storage support registered.\n"); return 0; } void __exit usb_stor_exit(void) { struct us_data *next; US_DEBUGP("usb_stor_exit() called\n"); /* Deregister the driver * This eliminates races with probes and disconnects */ US_DEBUGP("-- calling usb_deregister()\n"); usb_deregister(&storage_driver) ; /* lock access to the data structures */ down(&us_list_semaphore); /* While there are still virtual hosts, unregister them * * Note that the us_release() routine will destroy the local data * structure. So we have to peel these off the top of the list * and keep updating the head pointer as we go. */ while (us_list) { /* keep track of where the next one is */ next = us_list->next; US_DEBUGP("-- calling scsi_unregister_module()\n"); scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt)); /* Now that scsi_unregister_module is done with the host * template, we can free the us_data structure (the host * template is inline in this structure). */ kfree (us_list); /* advance the list pointer */ us_list = next; } /* unlock the data structures */ up(&us_list_semaphore); } module_init(usb_stor_init) ; module_exit(usb_stor_exit) ;