diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
commit | 3797ba0b62debb71af4606910acacc9896a9ae3b (patch) | |
tree | 414eea76253c7871bfdf3bd9d1817771eb40917c /drivers/usb/usb-storage.c | |
parent | 2b6c0c580795a4404f72d2a794214dd9e080709d (diff) |
Merge with Linux 2.4.0-test2.
Diffstat (limited to 'drivers/usb/usb-storage.c')
-rw-r--r-- | drivers/usb/usb-storage.c | 730 |
1 files changed, 661 insertions, 69 deletions
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c index b9cead4fe..6d88d360b 100644 --- a/drivers/usb/usb-storage.c +++ b/drivers/usb/usb-storage.c @@ -1,11 +1,16 @@ /* Driver for USB Mass Storage compliant devices * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) + * $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 @@ -22,6 +27,20 @@ * * 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/module.h> @@ -88,6 +107,7 @@ struct us_data { char *protocol_name; u8 subclass; u8 protocol; + u8 max_lun; /* information about the device -- only good if device is attached */ u8 ifnum; /* interface number */ @@ -536,8 +556,9 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us) /* 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] = 0; + srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[2] = 0; srb->cmnd[3] = 0; srb->cmnd[4] = 18; @@ -791,7 +812,7 @@ static int Bulk_max_lun(struct us_data *us) result, data); /* if we have a successful request, return the result */ - if (!result) + if (result == 1) return data; /* if we get a STALL, clear the stall */ @@ -839,6 +860,9 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) 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 */ @@ -976,25 +1000,17 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) 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) { - unsigned char *dta = (unsigned char *)us->srb->request_buffer; - - /* FIXME: we need to compress the entire data structure here - */ - 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]); - } + /* 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 @@ -1084,24 +1100,16 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us) 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 here if we had to translate the command - */ - if (old_cmnd == MODE_SENSE) { - unsigned char *dta = (unsigned char *)us->srb->request_buffer; - - /* FIXME: we need to compress the entire data structure here - */ - 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]); - } + /* 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 @@ -1310,9 +1318,8 @@ static int us_release(struct Scsi_Host *psh) down(&(us->notify)); /* free the data structure we were using */ - US_DEBUGP("-- freeing private host data structure\n"); + US_DEBUGP("-- freeing URB\n"); kfree(us->current_urb); - kfree(us); (struct us_data*)psh->hostdata[0] = NULL; /* we always have a successful release */ @@ -1536,11 +1543,10 @@ static int usb_stor_control_thread(void * __us) switch (action) { case US_ACT_COMMAND: - /* reject if target != 0 or if single-lun device - * and LUN != 0 + /* reject if target != 0 or if LUN is higher than + * the maximum known LUN */ - if (us->srb->target || - ((us->flags & US_FL_SINGLE_LUN) && us->srb->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); @@ -1623,32 +1629,37 @@ static int usb_stor_control_thread(void * __us) /* 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, - "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0}, - { 0x04e6, 0x0001, 0x0200, - "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x04e6, 0x0002, 0x0100, - "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x04e6, 0x0006, 0x0100, - "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x057b, 0x0000, 0x0114, - "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x059b, 0x0030, 0x0100, - "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN}, - { 0x0693, 0x0002, 0x0100, - "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK, - US_FL_ALT_LENGTH}, - { 0x0781, 0x0001, 0x0200, - "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB, - US_FL_SINGLE_LUN | US_FL_START_STOP}, - { 0x0781, 0x0002, 0x0009, - "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK, - US_FL_SINGLE_LUN | US_FL_IGNORE_SER}, - { 0x07af, 0x0005, 0x0100, - "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0000, 0x0000, 0x0, - "", 0, 0, 0} -}; + { 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 @@ -1667,7 +1678,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, while ((ptr->idVendor != 0x0000) && !((ptr->idVendor == idVendor) && (ptr->idProduct == idProduct) && - (ptr->bcdDevice == bcdDevice))) + (ptr->bcdDeviceMin <= bcdDevice) && + (ptr->bcdDeviceMax >= bcdDevice))) ptr++; /* if the search ended because we hit the end record, we failed */ @@ -1968,20 +1980,21 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) 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; - /* FIXME: for testing purposes only */ - Bulk_max_lun(ss); + ss->max_lun = Bulk_max_lun(ss); break; default: @@ -1994,6 +2007,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) } 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)"; @@ -2134,6 +2151,576 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) 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; j<sgLength; j++ ) + { + /* get to end of header */ + if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) + { + db=i; + di=j; + } + if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + sb=i; + si=j; + /* we've found both sets now, exit loops */ + j=sgLength; + i=the10->use_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; j<sg[i].length; j++ ) + { + /* get to end of header */ + if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) + { + ldb=i; + ldi=j; + } + if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) + { + lsb=i; + lsi=j; + /* we've found both sets now, exit loops */ + j=sg[i].length; + i=the6->use_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; j<sg[i].length; j++ ) + { + if ( element < USB_STOR_SCSI_SENSE_HDRSZ ) + { + /* fill in the pointers for both header types */ + the6->array[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; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ ) + { + if ( i < USB_STOR_SCSI_SENSE_HDRSZ ) + { + the6->array[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; i<bufferSize; i+=16 ) + { + printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", + buffer[i], + buffer[i+1], + buffer[i+2], + buffer[i+3], + buffer[i+4], + buffer[i+5], + buffer[i+6], + buffer[i+7], + buffer[i+8], + buffer[i+9], + buffer[i+10], + buffer[i+11], + buffer[i+12], + buffer[i+13], + buffer[i+14], + buffer[i+15] ); + } + + printk( KERN_ERR "Buffer has %d scatterlists.\n", cmd->use_sg ); + for ( i=0; i<cmd->use_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 @@ -2183,6 +2770,11 @@ void __exit usb_stor_exit(void) 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; } |