Merge with Linux 2.4.0-test6-pre2.
[linux-2.6/linux-mips.git] / drivers / usb / storage / scsiglue.c
blob7517d63bce5285ca05451c53bbd68840bedc7601
1 /* Driver for USB Mass Storage compliant devices
2 * SCSI layer glue code
4 * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $
6 * Current development and maintainance by:
7 * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
9 * Developed with the assistance of:
10 * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
11 * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
13 * Initial work by:
14 * (c) 1999 Michael Gee (michael@linuxspecific.com)
16 * This driver is based on the 'USB Mass Storage Class' document. This
17 * describes in detail the protocol used to communicate with such
18 * devices. Clearly, the designers had SCSI and ATAPI commands in
19 * mind when they created this document. The commands are all very
20 * similar to commands in the SCSI-II and ATAPI specifications.
22 * It is important to note that in a number of cases this class
23 * exhibits class-specific exemptions from the USB specification.
24 * Notably the usage of NAK, STALL and ACK differs from the norm, in
25 * that they are used to communicate wait, failed and OK on commands.
27 * Also, for certain devices, the interrupt endpoint is used to convey
28 * status of a command.
30 * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
31 * information about this driver.
33 * This program is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by the
35 * Free Software Foundation; either version 2, or (at your option) any
36 * later version.
38 * This program is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
43 * You should have received a copy of the GNU General Public License along
44 * with this program; if not, write to the Free Software Foundation, Inc.,
45 * 675 Mass Ave, Cambridge, MA 02139, USA.
47 #include "scsiglue.h"
48 #include "usb.h"
49 #include "debug.h"
51 #include <linux/malloc.h>
54 * kernel thread actions
57 #define US_ACT_COMMAND 1
58 #define US_ACT_DEVICE_RESET 2
59 #define US_ACT_BUS_RESET 3
60 #define US_ACT_HOST_RESET 4
61 #define US_ACT_EXIT 5
63 /***********************************************************************
64 * Host functions
65 ***********************************************************************/
67 static const char* host_info(struct Scsi_Host *host)
69 return "SCSI emulation for USB Mass Storage devices";
72 /* detect a virtual adapter (always works) */
73 static int detect(struct SHT *sht)
75 struct us_data *us;
76 char local_name[32];
78 /* This is not nice at all, but how else are we to get the
79 * data here? */
80 us = (struct us_data *)sht->proc_dir;
82 /* set up the name of our subdirectory under /proc/scsi/ */
83 sprintf(local_name, "usb-storage-%d", us->host_number);
84 sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
85 if (!sht->proc_name)
86 return 0;
87 strcpy(sht->proc_name, local_name);
89 /* we start with no /proc directory entry */
90 sht->proc_dir = NULL;
92 /* register the host */
93 us->host = scsi_register(sht, sizeof(us));
94 if (us->host) {
95 us->host->hostdata[0] = (unsigned long)us;
96 us->host_no = us->host->host_no;
97 return 1;
100 /* odd... didn't register properly. Abort and free pointers */
101 kfree(sht->proc_name);
102 sht->proc_name = NULL;
103 return 0;
106 /* Release all resources used by the virtual host
108 * NOTE: There is no contention here, because we're allready deregistered
109 * the driver and we're doing each virtual host in turn, not in parallel
111 static int release(struct Scsi_Host *psh)
113 struct us_data *us = (struct us_data *)psh->hostdata[0];
115 US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
117 /* Kill the control threads
119 * Enqueue the command, wake up the thread, and wait for
120 * notification that it's exited.
122 US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
123 us->action = US_ACT_EXIT;
124 wake_up(&(us->wqh));
125 down(&(us->notify));
127 /* free the data structure we were using */
128 US_DEBUGP("-- freeing URB\n");
129 kfree(us->current_urb);
130 (struct us_data*)psh->hostdata[0] = NULL;
132 /* we always have a successful release */
133 return 0;
136 /* run command */
137 static int command( Scsi_Cmnd *srb )
139 US_DEBUGP("Bad use of us_command\n");
141 return DID_BAD_TARGET << 16;
144 /* run command */
145 static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
147 struct us_data *us = (struct us_data *)srb->host->hostdata[0];
149 US_DEBUGP("queuecommand() called\n");
150 srb->host_scribble = (unsigned char *)us;
152 /* get exclusive access to the structures we want */
153 down(&(us->queue_exclusion));
155 /* enqueue the command */
156 us->queue_srb = srb;
157 srb->scsi_done = done;
158 us->action = US_ACT_COMMAND;
160 /* release the lock on the structure */
161 up(&(us->queue_exclusion));
163 /* wake up the process task */
164 wake_up(&(us->wqh));
166 return 0;
169 /***********************************************************************
170 * Error handling functions
171 ***********************************************************************/
173 /* Command abort
175 * Note that this is really only meaningful right now for CBI transport
176 * devices which have failed to give us the command completion interrupt
178 static int command_abort( Scsi_Cmnd *srb )
180 struct us_data *us = (struct us_data *)srb->host->hostdata[0];
181 wait_queue_head_t *wqh = (wait_queue_head_t *)us->current_urb->context;
183 US_DEBUGP("command_abort() called\n");
185 /* if we're stuck waiting for an IRQ, simulate it */
186 if (us->ip_wanted) {
187 US_DEBUGP("-- simulating missing IRQ\n");
188 up(&(us->ip_waitq));
189 return SUCCESS;
192 /* if we have an urb pending, let's wake the control thread up */
193 if (us->current_urb->status == -EINPROGRESS) {
194 /* cancel the URB */
195 usb_unlink_urb(us->current_urb);
197 /* wake the control thread up */
198 if (waitqueue_active(wqh))
199 wake_up(wqh);
201 /* wait for us to be done */
202 down(&(us->notify));
203 return SUCCESS;
206 US_DEBUGP ("-- nothing to abort\n");
207 return FAILED;
210 /* FIXME: this doesn't do anything right now */
211 static int bus_reset( Scsi_Cmnd *srb )
213 // struct us_data *us = (struct us_data *)srb->host->hostdata[0];
215 printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
216 US_DEBUGP("Bus reset requested\n");
217 // us->transport_reset(us);
218 return FAILED;
221 /* FIXME: This doesn't actually reset anything */
222 static int host_reset( Scsi_Cmnd *srb )
224 printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
225 return FAILED;
228 /***********************************************************************
229 * /proc/scsi/ functions
230 ***********************************************************************/
232 /* we use this macro to help us write into the buffer */
233 #undef SPRINTF
234 #define SPRINTF(args...) \
235 do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
237 static int proc_info (char *buffer, char **start, off_t offset, int length,
238 int hostno, int inout)
240 struct us_data *us;
241 char *pos = buffer;
243 /* if someone is sending us data, just throw it away */
244 if (inout)
245 return length;
247 /* lock the data structures */
248 down(&us_list_semaphore);
250 /* find our data from hostno */
251 us = us_list;
252 while (us) {
253 if (us->host_no == hostno)
254 break;
255 us = us->next;
258 /* if we couldn't find it, we return an error */
259 if (!us) {
260 up(&us_list_semaphore);
261 return -ESRCH;
264 /* print the controler name */
265 SPRINTF(" Host scsi%d: usb-storage\n", hostno);
267 /* print product, vendor, and serial number strings */
268 SPRINTF(" Vendor: %s\n", us->vendor);
269 SPRINTF(" Product: %s\n", us->product);
270 SPRINTF("Serial Number: %s\n", us->serial);
272 /* show the protocol and transport */
273 SPRINTF(" Protocol: %s\n", us->protocol_name);
274 SPRINTF(" Transport: %s\n", us->transport_name);
276 /* show the GUID of the device */
277 SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
279 /* release our lock on the data structures */
280 up(&us_list_semaphore);
283 * Calculate start of next buffer, and return value.
285 *start = buffer + offset;
287 if ((pos - buffer) < offset)
288 return (0);
289 else if ((pos - buffer - offset) < length)
290 return (pos - buffer - offset);
291 else
292 return (length);
296 * this defines our 'host'
299 Scsi_Host_Template usb_stor_host_template = {
300 name: "usb-storage",
301 proc_info: proc_info,
302 info: host_info,
304 detect: detect,
305 release: release,
306 command: command,
307 queuecommand: queuecommand,
309 eh_abort_handler: command_abort,
310 eh_device_reset_handler:bus_reset,
311 eh_bus_reset_handler: bus_reset,
312 eh_host_reset_handler: host_reset,
314 can_queue: 1,
315 this_id: -1,
317 sg_tablesize: SG_ALL,
318 cmd_per_lun: 1,
319 present: 0,
320 unchecked_isa_dma: FALSE,
321 use_clustering: TRUE,
322 use_new_eh_code: TRUE,
323 emulated: TRUE
326 unsigned char usb_stor_sense_notready[18] = {
327 [0] = 0x70, /* current error */
328 [2] = 0x02, /* not ready */
329 [5] = 0x0a, /* additional length */
330 [10] = 0x04, /* not ready */
331 [11] = 0x03 /* manual intervention */
334 #define USB_STOR_SCSI_SENSE_HDRSZ 4
335 #define USB_STOR_SCSI_SENSE_10_HDRSZ 8
337 struct usb_stor_scsi_sense_hdr
339 __u8* dataLength;
340 __u8* mediumType;
341 __u8* devSpecParms;
342 __u8* blkDescLength;
345 typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr;
347 union usb_stor_scsi_sense_hdr_u
349 Usb_Stor_Scsi_Sense_Hdr hdr;
350 __u8* array[USB_STOR_SCSI_SENSE_HDRSZ];
353 typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u;
355 struct usb_stor_scsi_sense_hdr_10
357 __u8* dataLengthMSB;
358 __u8* dataLengthLSB;
359 __u8* mediumType;
360 __u8* devSpecParms;
361 __u8* reserved1;
362 __u8* reserved2;
363 __u8* blkDescLengthMSB;
364 __u8* blkDescLengthLSB;
367 typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10;
369 union usb_stor_scsi_sense_hdr_10_u
371 Usb_Stor_Scsi_Sense_Hdr_10 hdr;
372 __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ];
375 typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u;
377 void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*,
378 Usb_Stor_Scsi_Sense_Hdr_10_u*, int* );
380 int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
382 __u8 *buffer=0;
383 int outputBufferSize = 0;
384 int length=0;
385 struct scatterlist *sg = 0;
386 int i=0, j=0, element=0;
387 Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
388 Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
389 int sb=0,si=0,db=0,di=0;
390 int sgLength=0;
392 US_DEBUGP("-- converting 10 byte sense data to 6 byte\n");
393 the10->cmnd[0] = the10->cmnd[0] & 0xBF;
395 /* Determine buffer locations */
396 usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations,
397 &length );
399 /* Work out minimum buffer to output */
400 outputBufferSize = *the10Locations.hdr.dataLengthLSB;
401 outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ;
403 /* Check to see if we need to trucate the output */
404 if ( outputBufferSize > length )
406 printk( KERN_WARNING USB_STORAGE
407 "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" );
408 printk( KERN_WARNING USB_STORAGE
409 "outputBufferSize is %d and length is %d.\n",
410 outputBufferSize, length );
412 outputBufferSize = length;
414 /* Data length */
415 if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */
417 printk( KERN_WARNING USB_STORAGE
418 "Command will be truncated to fit in SENSE6 buffer.\n" );
419 *the6Locations.hdr.dataLength = 0xff;
421 else
423 *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB;
426 /* Medium type and DevSpecific parms */
427 *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType;
428 *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms;
430 /* Block descriptor length */
431 if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */
433 printk( KERN_WARNING USB_STORAGE
434 "Command will be truncated to fit in SENSE6 buffer.\n" );
435 *the6Locations.hdr.blkDescLength = 0xff;
437 else
439 *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB;
442 if ( the10->use_sg == 0 )
444 buffer = the10->request_buffer;
445 /* Copy the rest of the data */
446 memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
447 &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
448 outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ );
449 /* initialise last bytes left in buffer due to smaller header */
450 memset( &(buffer[outputBufferSize
451 -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]),
453 USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
455 else
457 sg = (struct scatterlist *) the10->request_buffer;
458 /* scan through this scatterlist and figure out starting positions */
459 for ( i=0; i < the10->use_sg; i++)
461 sgLength = sg[i].length;
462 for ( j=0; j<sgLength; j++ )
464 /* get to end of header */
465 if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
467 db=i;
468 di=j;
470 if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
472 sb=i;
473 si=j;
474 /* we've found both sets now, exit loops */
475 j=sgLength;
476 i=the10->use_sg;
478 element++;
482 /* Now we know where to start the copy from */
483 element = USB_STOR_SCSI_SENSE_HDRSZ;
484 while ( element < outputBufferSize
485 -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
487 /* check limits */
488 if ( sb >= the10->use_sg ||
489 si >= sg[sb].length ||
490 db >= the10->use_sg ||
491 di >= sg[db].length )
493 printk( KERN_ERR USB_STORAGE
494 "Buffer overrun averted, this shouldn't happen!\n" );
495 break;
498 /* copy one byte */
499 sg[db].address[di] = sg[sb].address[si];
501 /* get next destination */
502 if ( sg[db].length-1 == di )
504 db++;
505 di=0;
507 else
509 di++;
512 /* get next source */
513 if ( sg[sb].length-1 == si )
515 sb++;
516 si=0;
518 else
520 si++;
523 element++;
525 /* zero the remaining bytes */
526 while ( element < outputBufferSize )
528 /* check limits */
529 if ( db >= the10->use_sg ||
530 di >= sg[db].length )
532 printk( KERN_ERR USB_STORAGE
533 "Buffer overrun averted, this shouldn't happen!\n" );
534 break;
537 sg[db].address[di] = 0;
539 /* get next destination */
540 if ( sg[db].length-1 == di )
542 db++;
543 di=0;
545 else
547 di++;
549 element++;
553 /* All done any everything was fine */
554 return 0;
557 int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
559 /* will be used to store part of buffer */
560 __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ],
561 *buffer=0;
562 int outputBufferSize = 0;
563 int length=0;
564 struct scatterlist *sg = 0;
565 int i=0, j=0, element=0;
566 Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
567 Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
568 int sb=0,si=0,db=0,di=0;
569 int lsb=0,lsi=0,ldb=0,ldi=0;
571 US_DEBUGP("-- converting 6 byte sense data to 10 byte\n");
572 the6->cmnd[0] = the6->cmnd[0] | 0x40;
574 /* Determine buffer locations */
575 usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations,
576 &length );
578 /* Work out minimum buffer to output */
579 outputBufferSize = *the6Locations.hdr.dataLength;
580 outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ;
582 /* Check to see if we need to trucate the output */
583 if ( outputBufferSize > length )
585 printk( KERN_WARNING USB_STORAGE
586 "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" );
587 printk( KERN_WARNING USB_STORAGE
588 "outputBufferSize is %d and length is %d.\n",
589 outputBufferSize, length );
591 outputBufferSize = length;
593 /* Block descriptor length - save these before overwriting */
594 tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB;
595 tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB;
596 *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength;
597 *the10Locations.hdr.blkDescLengthMSB = 0;
599 /* reserved - save these before overwriting */
600 tempBuffer[0] = *the10Locations.hdr.reserved1;
601 tempBuffer[1] = *the10Locations.hdr.reserved2;
602 *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0;
604 /* Medium type and DevSpecific parms */
605 *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms;
606 *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType;
608 /* Data length */
609 *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength;
610 *the10Locations.hdr.dataLengthMSB = 0;
612 if ( !the6->use_sg )
614 buffer = the6->request_buffer;
615 /* Copy the rest of the data */
616 memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
617 &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
618 outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ );
619 /* Put the first four bytes (after header) in place */
620 memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
621 tempBuffer,
622 USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
624 else
626 sg = (struct scatterlist *) the6->request_buffer;
627 /* scan through this scatterlist and figure out ending positions */
628 for ( i=0; i < the6->use_sg; i++)
630 for ( j=0; j<sg[i].length; j++ )
632 /* get to end of header */
633 if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
635 ldb=i;
636 ldi=j;
638 if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
640 lsb=i;
641 lsi=j;
642 /* we've found both sets now, exit loops */
643 j=sg[i].length;
644 i=the6->use_sg;
645 break;
647 element++;
650 /* scan through this scatterlist and figure out starting positions */
651 element = length-1;
652 /* destination is the last element */
653 db=the6->use_sg-1;
654 di=sg[db].length-1;
655 for ( i=the6->use_sg-1; i >= 0; i--)
657 for ( j=sg[i].length-1; j>=0; j-- )
659 /* get to end of header and find source for copy */
660 if ( element == length - 1
661 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
663 sb=i;
664 si=j;
665 /* we've found both sets now, exit loops */
666 j=-1;
667 i=-1;
669 element--;
672 /* Now we know where to start the copy from */
673 element = length-1
674 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
675 while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ )
677 /* check limits */
678 if ( ( sb <= lsb && si < lsi ) ||
679 ( db <= ldb && di < ldi ) )
681 printk( KERN_ERR USB_STORAGE
682 "Buffer overrun averted, this shouldn't happen!\n" );
683 break;
686 /* copy one byte */
687 sg[db].address[di] = sg[sb].address[si];
689 /* get next destination */
690 if ( di == 0 )
692 db--;
693 di=sg[db].length-1;
695 else
697 di--;
700 /* get next source */
701 if ( si == 0 )
703 sb--;
704 si=sg[sb].length-1;
706 else
708 si--;
711 element--;
713 /* copy the remaining four bytes */
714 while ( element >= USB_STOR_SCSI_SENSE_HDRSZ )
716 /* check limits */
717 if ( db <= ldb && di < ldi )
719 printk( KERN_ERR USB_STORAGE
720 "Buffer overrun averted, this shouldn't happen!\n" );
721 break;
724 sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ];
726 /* get next destination */
727 if ( di == 0 )
729 db--;
730 di=sg[db].length-1;
732 else
734 di--;
736 element--;
740 /* All done and everything was fine */
741 return 0;
744 void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6,
745 Usb_Stor_Scsi_Sense_Hdr_10_u* the10,
746 int* length_p )
749 int i = 0, j=0, element=0;
750 struct scatterlist *sg = 0;
751 int length = 0;
752 __u8* buffer=0;
754 /* are we scatter-gathering? */
755 if ( srb->use_sg != 0 )
757 /* loop over all the scatter gather structures and
758 * get pointer to the data members in the headers
759 * (also work out the length while we're here)
761 sg = (struct scatterlist *) srb->request_buffer;
762 for (i = 0; i < srb->use_sg; i++)
764 length += sg[i].length;
765 /* We only do the inner loop for the headers */
766 if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
768 /* scan through this scatterlist */
769 for ( j=0; j<sg[i].length; j++ )
771 if ( element < USB_STOR_SCSI_SENSE_HDRSZ )
773 /* fill in the pointers for both header types */
774 the6->array[element] = &(sg[i].address[j]);
775 the10->array[element] = &(sg[i].address[j]);
777 else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
779 /* only the longer headers still cares now */
780 the10->array[element] = &(sg[i].address[j]);
782 /* increase element counter */
783 element++;
788 else
790 length = srb->request_bufflen;
791 buffer = srb->request_buffer;
792 if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ )
793 printk( KERN_ERR USB_STORAGE
794 "Buffer length smaller than header!!" );
795 for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ )
797 if ( i < USB_STOR_SCSI_SENSE_HDRSZ )
799 the6->array[i] = &(buffer[i]);
800 the10->array[i] = &(buffer[i]);
802 else
804 the10->array[i] = &(buffer[i]);
809 /* Set value of length passed in */
810 *length_p = length;