Commit | Line | Data |
---|---|---|
34e49164 C |
1 | /* Driver for USB Mass Storage compliant devices |
2 | * SCSI layer glue code | |
3 | * | |
4 | * | |
5 | * | |
6 | * Current development and maintenance by: | |
7 | * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) | |
8 | * | |
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) | |
12 | * | |
13 | * Initial work by: | |
14 | * (c) 1999 Michael Gee (michael@linuxspecific.com) | |
15 | * | |
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. | |
21 | * | |
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. | |
26 | * | |
27 | * Also, for certain devices, the interrupt endpoint is used to convey | |
28 | * status of a command. | |
29 | * | |
30 | * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more | |
31 | * information about this driver. | |
32 | * | |
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. | |
37 | * | |
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. | |
42 | * | |
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. | |
46 | */ | |
47 | #include "scsiglue.h" | |
48 | #include "usb.h" | |
49 | #include "debug.h" | |
50 | #include "transport.h" | |
51 | ||
52 | #include <linux/slab.h> | |
53 | #include <linux/module.h> | |
54 | ||
55 | ||
56 | /*********************************************************************** | |
57 | * Host functions | |
58 | ***********************************************************************/ | |
59 | ||
60 | static const char* usb_storage_info(struct Scsi_Host *host) | |
61 | { | |
62 | return "SCSI emulation for USB Mass Storage devices"; | |
63 | } | |
64 | ||
65 | #if 0 | |
66 | /* detect a virtual adapter (always works) | |
67 | * Synchronization: 2.4: with the io_request_lock | |
68 | * 2.5: no locks. | |
69 | * fortunately we don't care. | |
70 | * */ | |
71 | static int usb_storage_detect(struct SHT *sht) | |
72 | { | |
73 | struct us_data *us; | |
74 | char local_name[32]; | |
75 | ||
76 | /* This is not nice at all, but how else are we to get the | |
77 | * data here? */ | |
78 | us = (struct us_data *)sht->proc_dir; | |
79 | ||
80 | /* set up the name of our subdirectory under /proc/scsi/ */ | |
81 | sprintf(local_name, "usb-storage-%d", us->host_number); | |
82 | sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); | |
83 | if (!sht->proc_name) | |
84 | return 0; | |
85 | strcpy(sht->proc_name, local_name); | |
86 | ||
87 | /* we start with no /proc directory entry */ | |
88 | sht->proc_dir = NULL; | |
89 | ||
90 | /* register the host */ | |
91 | us->host = scsi_register(sht, sizeof(us)); | |
92 | if (us->host) { | |
93 | struct usb_interface *iface; | |
94 | us->host->hostdata[0] = (unsigned long)us; | |
95 | us->host_no = us->host->host_no; | |
96 | iface = usb_ifnum_to_if(us->pusb_dev, us->ifnum); | |
97 | if (iface) | |
98 | scsi_set_device(us->host, &iface->dev); | |
99 | return 1; | |
100 | } | |
101 | ||
102 | /* odd... didn't register properly. Abort and free pointers */ | |
103 | kfree(sht->proc_name); | |
104 | sht->proc_name = NULL; | |
105 | return 0; | |
106 | } | |
107 | ||
108 | /* Release all resources used by the virtual host | |
109 | * | |
110 | * NOTE: There is no contention here, because we're already deregistered | |
111 | * the driver and we're doing each virtual host in turn, not in parallel | |
112 | * Synchronization: BKL, no spinlock. | |
113 | */ | |
114 | static int usb_storage_release(struct Scsi_Host *psh) | |
115 | { | |
116 | struct us_data *us = (struct us_data *)psh->hostdata[0]; | |
117 | ||
118 | US_DEBUGP("release() called for host %s\n", us->htmplt.name); | |
119 | ||
120 | /* Kill the control threads | |
121 | * | |
122 | * Enqueue the command, wake up the thread, and wait for | |
123 | * notification that it has exited. | |
124 | */ | |
125 | US_DEBUGP("-- sending exit command to thread\n"); | |
126 | BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); | |
127 | us->srb = NULL; | |
128 | up(&(us->sema)); | |
129 | wait_for_completion(&(us->notify)); | |
130 | ||
131 | /* remove the pointer to the data structure we were using */ | |
132 | (struct us_data*)psh->hostdata[0] = NULL; | |
133 | ||
134 | /* we always have a successful release */ | |
135 | return 0; | |
136 | } | |
137 | #endif | |
138 | ||
139 | /* queue a command */ | |
140 | /* This is always called with scsi_lock(srb->host) held */ | |
141 | static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) | |
142 | { | |
143 | struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; | |
144 | int state = atomic_read(&us->sm_state); | |
145 | ||
146 | US_DEBUGP("queuecommand() called\n"); | |
147 | srb->host_scribble = (unsigned char *)us; | |
148 | ||
149 | /* enqueue the command */ | |
150 | if (state != US_STATE_IDLE || us->srb != NULL) { | |
151 | printk(KERN_ERR USB_STORAGE "Error in %s: " | |
152 | "state = %d, us->srb = %p\n", | |
153 | __FUNCTION__, state, us->srb); | |
154 | return SCSI_MLQUEUE_HOST_BUSY; | |
155 | } | |
156 | ||
157 | srb->scsi_done = done; | |
158 | us->srb = srb; | |
159 | ||
160 | /* wake up the process task */ | |
161 | up(&(us->sema)); | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
166 | /*********************************************************************** | |
167 | * Error handling functions | |
168 | ***********************************************************************/ | |
169 | ||
170 | /* Command abort */ | |
171 | /* This is always called with scsi_lock(srb->host) held */ | |
172 | static int usb_storage_command_abort( Scsi_Cmnd *srb ) | |
173 | { | |
174 | struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; | |
175 | ||
176 | US_DEBUGP("command_abort() called\n"); | |
177 | ||
178 | /* Is this command still active? */ | |
179 | if (us->srb != srb) { | |
180 | US_DEBUGP ("-- nothing to abort\n"); | |
181 | return FAILED; | |
182 | } | |
183 | ||
184 | return usb_stor_abort_transport(us); | |
185 | } | |
186 | ||
187 | /* This invokes the transport reset mechanism to reset the state of the | |
188 | * device */ | |
189 | /* This is always called with scsi_lock(srb->host) held */ | |
190 | static int usb_storage_device_reset( Scsi_Cmnd *srb ) | |
191 | { | |
192 | struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; | |
193 | int state = atomic_read(&us->sm_state); | |
194 | int result; | |
195 | ||
196 | US_DEBUGP("device_reset() called\n" ); | |
197 | if (state != US_STATE_IDLE) { | |
198 | printk(KERN_ERR USB_STORAGE "Error in %s: " | |
199 | "invalid state %d\n", __FUNCTION__, state); | |
200 | return FAILED; | |
201 | } | |
202 | ||
203 | /* set the state and release the lock */ | |
204 | atomic_set(&us->sm_state, US_STATE_RESETTING); | |
205 | scsi_unlock(srb->device->host); | |
206 | ||
207 | /* lock the device pointers */ | |
208 | down(&(us->dev_semaphore)); | |
209 | ||
210 | /* do the reset */ | |
211 | result = us->transport_reset(us); | |
212 | ||
213 | /* unlock */ | |
214 | up(&(us->dev_semaphore)); | |
215 | ||
216 | /* lock access to the state and clear it */ | |
217 | scsi_lock(srb->device->host); | |
218 | atomic_set(&us->sm_state, US_STATE_IDLE); | |
219 | return result; | |
220 | } | |
221 | ||
222 | /* This resets the device port */ | |
223 | /* It refuses to work if there's more than one interface in | |
224 | this device, so that other users are not affected. */ | |
225 | /* This is always called with scsi_lock(srb->host) held */ | |
226 | ||
227 | static int usb_storage_bus_reset( Scsi_Cmnd *srb ) | |
228 | { | |
229 | struct us_data *us; | |
230 | int result; | |
231 | ||
232 | /* we use the usb_reset_device() function to handle this for us */ | |
233 | US_DEBUGP("bus_reset() called\n"); | |
234 | scsi_unlock(srb->device->host); | |
235 | us = (struct us_data *)srb->device->host->hostdata[0]; | |
236 | ||
237 | /* The USB subsystem doesn't handle synchronisation between | |
238 | a device's several drivers. Therefore we reset only devices | |
239 | with one interface which we of course own. | |
240 | */ | |
241 | ||
242 | //FIXME: needs locking against config changes | |
243 | ||
244 | if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { | |
245 | /* attempt to reset the port */ | |
246 | result = usb_reset_device(us->pusb_dev); | |
247 | US_DEBUGP("usb_reset_device returns %d\n", result); | |
248 | } else { | |
249 | result = -EBUSY; | |
250 | US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); | |
251 | } | |
252 | ||
253 | US_DEBUGP("bus_reset() complete\n"); | |
254 | scsi_lock(srb->device->host); | |
255 | return result < 0 ? FAILED : SUCCESS; | |
256 | } | |
257 | ||
258 | /*********************************************************************** | |
259 | * /proc/scsi/ functions | |
260 | ***********************************************************************/ | |
261 | ||
262 | /* we use this macro to help us write into the buffer */ | |
263 | #undef SPRINTF | |
264 | #define SPRINTF(args...) \ | |
265 | do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) | |
266 | ||
267 | static int usb_storage_proc_info (char *buffer, char **start, off_t offset, | |
268 | int length, int hostno, int inout) | |
269 | { | |
270 | struct us_data *us; | |
271 | char *pos = buffer; | |
272 | struct Scsi_Host *hostptr; | |
273 | unsigned long f; | |
274 | ||
275 | /* if someone is sending us data, just throw it away */ | |
276 | if (inout) | |
277 | return length; | |
278 | ||
279 | /* find our data from the given hostno */ | |
280 | hostptr = scsi_host_hn_get(hostno); | |
281 | if (!hostptr) { /* if we couldn't find it, we return an error */ | |
282 | return -ESRCH; | |
283 | } | |
284 | us = (struct us_data*)hostptr->hostdata[0]; | |
285 | ||
286 | /* if we couldn't find it, we return an error */ | |
287 | if (!us) { | |
288 | scsi_host_put(hostptr); | |
289 | return -ESRCH; | |
290 | } | |
291 | ||
292 | /* print the controller name */ | |
293 | SPRINTF(" Host scsi%d: usb-storage\n", hostno); | |
294 | ||
295 | /* print product, vendor, and serial number strings */ | |
296 | SPRINTF(" Vendor: %s\n", us->vendor); | |
297 | SPRINTF(" Product: %s\n", us->product); | |
298 | SPRINTF("Serial Number: %s\n", us->serial); | |
299 | ||
300 | /* show the protocol and transport */ | |
301 | SPRINTF(" Protocol: %s\n", us->protocol_name); | |
302 | SPRINTF(" Transport: %s\n", us->transport_name); | |
303 | ||
304 | /* show the device flags */ | |
305 | if (pos < buffer + length) { | |
306 | pos += sprintf(pos, " Quirks:"); | |
307 | f = us->flags; | |
308 | ||
309 | #define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) | |
310 | DO_FLAG(SINGLE_LUN); | |
311 | DO_FLAG(MODE_XLATE); | |
312 | DO_FLAG(START_STOP); | |
313 | DO_FLAG(IGNORE_SER); | |
314 | DO_FLAG(SCM_MULT_TARG); | |
315 | DO_FLAG(FIX_INQUIRY); | |
316 | DO_FLAG(FIX_CAPACITY); | |
317 | #undef DO_FLAG | |
318 | ||
319 | *(pos++) = '\n'; | |
320 | } | |
321 | ||
322 | /* release the reference count on this host */ | |
323 | scsi_host_put(hostptr); | |
324 | ||
325 | /* | |
326 | * Calculate start of next buffer, and return value. | |
327 | */ | |
328 | *start = buffer + offset; | |
329 | ||
330 | if ((pos - buffer) < offset) | |
331 | return (0); | |
332 | else if ((pos - buffer - offset) < length) | |
333 | return (pos - buffer - offset); | |
334 | else | |
335 | return (length); | |
336 | } | |
337 | ||
338 | /* | |
339 | * this defines our host template, with which we'll allocate hosts | |
340 | */ | |
341 | ||
342 | struct SHT usb_stor_host_template = { | |
343 | /* basic userland interface stuff */ | |
344 | .name = "usb-storage", | |
345 | .proc_name = "usb-storage", | |
346 | .proc_info = usb_storage_proc_info, | |
347 | .proc_dir = NULL, | |
348 | .info = usb_storage_info, | |
349 | .ioctl = NULL, | |
350 | ||
351 | /* old-style detect and release */ | |
352 | .detect = NULL, | |
353 | .release = NULL, | |
354 | ||
355 | /* command interface -- queued only */ | |
356 | .command = NULL, | |
357 | .queuecommand = usb_storage_queuecommand, | |
358 | ||
359 | /* error and abort handlers */ | |
360 | .eh_abort_handler = usb_storage_command_abort, | |
361 | .eh_device_reset_handler = usb_storage_device_reset, | |
362 | .eh_bus_reset_handler = usb_storage_bus_reset, | |
363 | .eh_host_reset_handler = NULL, | |
364 | .eh_strategy_handler = NULL, | |
365 | ||
366 | /* queue commands only, only one command per LUN */ | |
367 | .can_queue = 1, | |
368 | .cmd_per_lun = 1, | |
369 | ||
370 | /* unknown initiator id */ | |
371 | .this_id = -1, | |
372 | ||
373 | /* no limit on commands */ | |
374 | .max_sectors = 0, | |
375 | ||
376 | /* pre- and post- device scan functions */ | |
377 | .slave_alloc = NULL, | |
378 | .slave_configure = NULL, | |
379 | .slave_destroy = NULL, | |
380 | ||
381 | /* lots of sg segments can be handled */ | |
382 | .sg_tablesize = SG_ALL, | |
383 | ||
384 | /* use 32-bit address space for DMA */ | |
385 | .unchecked_isa_dma = FALSE, | |
386 | .highmem_io = FALSE, | |
387 | ||
388 | /* merge commands... this seems to help performance, but | |
389 | * periodically someone should test to see which setting is more | |
390 | * optimal. | |
391 | */ | |
392 | .use_clustering = TRUE, | |
393 | ||
394 | /* emulated HBA */ | |
395 | .emulated = TRUE, | |
396 | ||
397 | /* sorry, no BIOS to help us */ | |
398 | .bios_param = NULL, | |
399 | ||
400 | /* module management */ | |
401 | .module = THIS_MODULE | |
402 | }; | |
403 | ||
404 | /* For a device that is "Not Ready" */ | |
405 | unsigned char usb_stor_sense_notready[18] = { | |
406 | [0] = 0x70, /* current error */ | |
407 | [2] = 0x02, /* not ready */ | |
408 | [7] = 0x0a, /* additional length */ | |
409 | [12] = 0x04, /* not ready */ | |
410 | [13] = 0x03 /* manual intervention */ | |
411 | }; | |
412 | ||
413 | /* To Report "Illegal Request: Invalid Field in CDB */ | |
414 | unsigned char usb_stor_sense_invalidCDB[18] = { | |
415 | [0] = 0x70, /* current error */ | |
416 | [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */ | |
417 | [7] = 0x0a, /* additional length */ | |
418 | [12] = 0x24 /* Invalid Field in CDB */ | |
419 | }; | |
420 | ||
421 | #define USB_STOR_SCSI_SENSE_HDRSZ 4 | |
422 | #define USB_STOR_SCSI_SENSE_10_HDRSZ 8 | |
423 | ||
424 | struct usb_stor_scsi_sense_hdr | |
425 | { | |
426 | __u8* dataLength; | |
427 | __u8* mediumType; | |
428 | __u8* devSpecParms; | |
429 | __u8* blkDescLength; | |
430 | }; | |
431 | ||
432 | typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr; | |
433 | ||
434 | union usb_stor_scsi_sense_hdr_u | |
435 | { | |
436 | Usb_Stor_Scsi_Sense_Hdr hdr; | |
437 | __u8* array[USB_STOR_SCSI_SENSE_HDRSZ]; | |
438 | }; | |
439 | ||
440 | typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u; | |
441 | ||
442 | struct usb_stor_scsi_sense_hdr_10 | |
443 | { | |
444 | __u8* dataLengthMSB; | |
445 | __u8* dataLengthLSB; | |
446 | __u8* mediumType; | |
447 | __u8* devSpecParms; | |
448 | __u8* reserved1; | |
449 | __u8* reserved2; | |
450 | __u8* blkDescLengthMSB; | |
451 | __u8* blkDescLengthLSB; | |
452 | }; | |
453 | ||
454 | typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10; | |
455 | ||
456 | union usb_stor_scsi_sense_hdr_10_u | |
457 | { | |
458 | Usb_Stor_Scsi_Sense_Hdr_10 hdr; | |
459 | __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ]; | |
460 | }; | |
461 | ||
462 | typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u; | |
463 | ||
464 | void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*, | |
465 | Usb_Stor_Scsi_Sense_Hdr_10_u*, int* ); | |
466 | ||
467 | int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 ) | |
468 | { | |
469 | __u8 *buffer=0; | |
470 | int outputBufferSize = 0; | |
471 | int length=0; | |
472 | struct scatterlist *sg = 0; | |
473 | int i=0, j=0, element=0; | |
474 | Usb_Stor_Scsi_Sense_Hdr_u the6Locations; | |
475 | Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; | |
476 | int sb=0,si=0,db=0,di=0; | |
477 | int sgLength=0; | |
478 | ||
479 | US_DEBUGP("-- converting 10 byte sense data to 6 byte\n"); | |
480 | the10->cmnd[0] = the10->cmnd[0] & 0xBF; | |
481 | ||
482 | /* Determine buffer locations */ | |
483 | usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations, | |
484 | &length ); | |
485 | ||
486 | /* Work out minimum buffer to output */ | |
487 | outputBufferSize = *the10Locations.hdr.dataLengthLSB; | |
488 | outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ; | |
489 | ||
490 | /* Check to see if we need to trucate the output */ | |
491 | if ( outputBufferSize > length ) | |
492 | { | |
493 | printk( KERN_WARNING USB_STORAGE | |
494 | "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" ); | |
495 | printk( KERN_WARNING USB_STORAGE | |
496 | "outputBufferSize is %d and length is %d.\n", | |
497 | outputBufferSize, length ); | |
498 | } | |
499 | outputBufferSize = length; | |
500 | ||
501 | /* Data length */ | |
502 | if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */ | |
503 | { | |
504 | printk( KERN_WARNING USB_STORAGE | |
505 | "Command will be truncated to fit in SENSE6 buffer.\n" ); | |
506 | *the6Locations.hdr.dataLength = 0xff; | |
507 | } | |
508 | else | |
509 | { | |
510 | *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB; | |
511 | } | |
512 | ||
513 | /* Medium type and DevSpecific parms */ | |
514 | *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType; | |
515 | *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms; | |
516 | ||
517 | /* Block descriptor length */ | |
518 | if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */ | |
519 | { | |
520 | printk( KERN_WARNING USB_STORAGE | |
521 | "Command will be truncated to fit in SENSE6 buffer.\n" ); | |
522 | *the6Locations.hdr.blkDescLength = 0xff; | |
523 | } | |
524 | else | |
525 | { | |
526 | *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB; | |
527 | } | |
528 | ||
529 | if ( the10->use_sg == 0 ) | |
530 | { | |
531 | buffer = the10->request_buffer; | |
532 | /* Copy the rest of the data */ | |
533 | memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), | |
534 | &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), | |
535 | outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ ); | |
536 | /* initialise last bytes left in buffer due to smaller header */ | |
537 | memset( &(buffer[outputBufferSize | |
538 | -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]), | |
539 | 0, | |
540 | USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); | |
541 | } | |
542 | else | |
543 | { | |
544 | sg = (struct scatterlist *) the10->request_buffer; | |
545 | /* scan through this scatterlist and figure out starting positions */ | |
546 | for ( i=0; i < the10->use_sg; i++) | |
547 | { | |
548 | sgLength = sg[i].length; | |
549 | for ( j=0; j<sgLength; j++ ) | |
550 | { | |
551 | /* get to end of header */ | |
552 | if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) | |
553 | { | |
554 | db=i; | |
555 | di=j; | |
556 | } | |
557 | if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
558 | { | |
559 | sb=i; | |
560 | si=j; | |
561 | /* we've found both sets now, exit loops */ | |
562 | j=sgLength; | |
563 | i=the10->use_sg; | |
564 | } | |
565 | element++; | |
566 | } | |
567 | } | |
568 | ||
569 | /* Now we know where to start the copy from */ | |
570 | element = USB_STOR_SCSI_SENSE_HDRSZ; | |
571 | while ( element < outputBufferSize | |
572 | -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) | |
573 | { | |
574 | /* check limits */ | |
575 | if ( sb >= the10->use_sg || | |
576 | si >= sg[sb].length || | |
577 | db >= the10->use_sg || | |
578 | di >= sg[db].length ) | |
579 | { | |
580 | printk( KERN_ERR USB_STORAGE | |
581 | "Buffer overrun averted, this shouldn't happen!\n" ); | |
582 | break; | |
583 | } | |
584 | ||
585 | /* copy one byte */ | |
586 | { | |
587 | char *src = sg_address(sg[sb]) + si; | |
588 | char *dst = sg_address(sg[db]) + di; | |
589 | ||
590 | *dst = *src; | |
591 | } | |
592 | ||
593 | /* get next destination */ | |
594 | if ( sg[db].length-1 == di ) | |
595 | { | |
596 | db++; | |
597 | di=0; | |
598 | } | |
599 | else | |
600 | { | |
601 | di++; | |
602 | } | |
603 | ||
604 | /* get next source */ | |
605 | if ( sg[sb].length-1 == si ) | |
606 | { | |
607 | sb++; | |
608 | si=0; | |
609 | } | |
610 | else | |
611 | { | |
612 | si++; | |
613 | } | |
614 | ||
615 | element++; | |
616 | } | |
617 | /* zero the remaining bytes */ | |
618 | while ( element < outputBufferSize ) | |
619 | { | |
620 | /* check limits */ | |
621 | if ( db >= the10->use_sg || | |
622 | di >= sg[db].length ) | |
623 | { | |
624 | printk( KERN_ERR USB_STORAGE | |
625 | "Buffer overrun averted, this shouldn't happen!\n" ); | |
626 | break; | |
627 | } | |
628 | ||
629 | *(char*)(sg_address(sg[db])) = 0; | |
630 | ||
631 | /* get next destination */ | |
632 | if ( sg[db].length-1 == di ) | |
633 | { | |
634 | db++; | |
635 | di=0; | |
636 | } | |
637 | else | |
638 | { | |
639 | di++; | |
640 | } | |
641 | element++; | |
642 | } | |
643 | } | |
644 | ||
645 | /* All done any everything was fine */ | |
646 | return 0; | |
647 | } | |
648 | ||
649 | int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 ) | |
650 | { | |
651 | /* will be used to store part of buffer */ | |
652 | __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], | |
653 | *buffer=0; | |
654 | int outputBufferSize = 0; | |
655 | int length=0; | |
656 | struct scatterlist *sg = 0; | |
657 | int i=0, j=0, element=0; | |
658 | Usb_Stor_Scsi_Sense_Hdr_u the6Locations; | |
659 | Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations; | |
660 | int sb=0,si=0,db=0,di=0; | |
661 | int lsb=0,lsi=0,ldb=0,ldi=0; | |
662 | ||
663 | US_DEBUGP("-- converting 6 byte sense data to 10 byte\n"); | |
664 | the6->cmnd[0] = the6->cmnd[0] | 0x40; | |
665 | ||
666 | /* Determine buffer locations */ | |
667 | usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations, | |
668 | &length ); | |
669 | ||
670 | /* Work out minimum buffer to output */ | |
671 | outputBufferSize = *the6Locations.hdr.dataLength; | |
672 | outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ; | |
673 | ||
674 | /* Check to see if we need to trucate the output */ | |
675 | if ( outputBufferSize > length ) | |
676 | { | |
677 | printk( KERN_WARNING USB_STORAGE | |
678 | "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" ); | |
679 | printk( KERN_WARNING USB_STORAGE | |
680 | "outputBufferSize is %d and length is %d.\n", | |
681 | outputBufferSize, length ); | |
682 | } | |
683 | outputBufferSize = length; | |
684 | ||
685 | /* Block descriptor length - save these before overwriting */ | |
686 | tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB; | |
687 | tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB; | |
688 | *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength; | |
689 | *the10Locations.hdr.blkDescLengthMSB = 0; | |
690 | ||
691 | /* reserved - save these before overwriting */ | |
692 | tempBuffer[0] = *the10Locations.hdr.reserved1; | |
693 | tempBuffer[1] = *the10Locations.hdr.reserved2; | |
694 | *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0; | |
695 | ||
696 | /* Medium type and DevSpecific parms */ | |
697 | *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms; | |
698 | *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType; | |
699 | ||
700 | /* Data length */ | |
701 | *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength; | |
702 | *the10Locations.hdr.dataLengthMSB = 0; | |
703 | ||
704 | if ( !the6->use_sg ) | |
705 | { | |
706 | buffer = the6->request_buffer; | |
707 | /* Copy the rest of the data */ | |
708 | memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), | |
709 | &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]), | |
710 | outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ ); | |
711 | /* Put the first four bytes (after header) in place */ | |
712 | memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), | |
713 | tempBuffer, | |
714 | USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ ); | |
715 | } | |
716 | else | |
717 | { | |
718 | sg = (struct scatterlist *) the6->request_buffer; | |
719 | /* scan through this scatterlist and figure out ending positions */ | |
720 | for ( i=0; i < the6->use_sg; i++) | |
721 | { | |
722 | for ( j=0; j<sg[i].length; j++ ) | |
723 | { | |
724 | /* get to end of header */ | |
725 | if ( element == USB_STOR_SCSI_SENSE_HDRSZ ) | |
726 | { | |
727 | ldb=i; | |
728 | ldi=j; | |
729 | } | |
730 | if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
731 | { | |
732 | lsb=i; | |
733 | lsi=j; | |
734 | /* we've found both sets now, exit loops */ | |
735 | j=sg[i].length; | |
736 | i=the6->use_sg; | |
737 | break; | |
738 | } | |
739 | element++; | |
740 | } | |
741 | } | |
742 | /* scan through this scatterlist and figure out starting positions */ | |
743 | element = length-1; | |
744 | /* destination is the last element */ | |
745 | db=the6->use_sg-1; | |
746 | di=sg[db].length-1; | |
747 | for ( i=the6->use_sg-1; i >= 0; i--) | |
748 | { | |
749 | for ( j=sg[i].length-1; j>=0; j-- ) | |
750 | { | |
751 | /* get to end of header and find source for copy */ | |
752 | if ( element == length - 1 | |
753 | - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) ) | |
754 | { | |
755 | sb=i; | |
756 | si=j; | |
757 | /* we've found both sets now, exit loops */ | |
758 | j=-1; | |
759 | i=-1; | |
760 | } | |
761 | element--; | |
762 | } | |
763 | } | |
764 | /* Now we know where to start the copy from */ | |
765 | element = length-1 | |
766 | - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ); | |
767 | while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
768 | { | |
769 | /* check limits */ | |
770 | if ( ( sb <= lsb && si < lsi ) || | |
771 | ( db <= ldb && di < ldi ) ) | |
772 | { | |
773 | printk( KERN_ERR USB_STORAGE | |
774 | "Buffer overrun averted, this shouldn't happen!\n" ); | |
775 | break; | |
776 | } | |
777 | ||
778 | /* copy one byte */ | |
779 | { | |
780 | char *src = sg_address(sg[sb]) + si; | |
781 | char *dst = sg_address(sg[db]) + di; | |
782 | ||
783 | *dst = *src; | |
784 | } | |
785 | ||
786 | /* get next destination */ | |
787 | if ( di == 0 ) | |
788 | { | |
789 | db--; | |
790 | di=sg[db].length-1; | |
791 | } | |
792 | else | |
793 | { | |
794 | di--; | |
795 | } | |
796 | ||
797 | /* get next source */ | |
798 | if ( si == 0 ) | |
799 | { | |
800 | sb--; | |
801 | si=sg[sb].length-1; | |
802 | } | |
803 | else | |
804 | { | |
805 | si--; | |
806 | } | |
807 | ||
808 | element--; | |
809 | } | |
810 | /* copy the remaining four bytes */ | |
811 | while ( element >= USB_STOR_SCSI_SENSE_HDRSZ ) | |
812 | { | |
813 | /* check limits */ | |
814 | if ( db <= ldb && di < ldi ) | |
815 | { | |
816 | printk( KERN_ERR USB_STORAGE | |
817 | "Buffer overrun averted, this shouldn't happen!\n" ); | |
818 | break; | |
819 | } | |
820 | ||
821 | { | |
822 | char *dst = sg_address(sg[db]) + di; | |
823 | ||
824 | *dst = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ]; | |
825 | } | |
826 | ||
827 | ||
828 | /* get next destination */ | |
829 | if ( di == 0 ) | |
830 | { | |
831 | db--; | |
832 | di=sg[db].length-1; | |
833 | } | |
834 | else | |
835 | { | |
836 | di--; | |
837 | } | |
838 | element--; | |
839 | } | |
840 | } | |
841 | ||
842 | /* All done and everything was fine */ | |
843 | return 0; | |
844 | } | |
845 | ||
846 | void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6, | |
847 | Usb_Stor_Scsi_Sense_Hdr_10_u* the10, | |
848 | int* length_p ) | |
849 | ||
850 | { | |
851 | int i = 0, j=0, element=0; | |
852 | struct scatterlist *sg = 0; | |
853 | int length = 0; | |
854 | __u8* buffer=0; | |
855 | ||
856 | /* are we scatter-gathering? */ | |
857 | if ( srb->use_sg != 0 ) | |
858 | { | |
859 | /* loop over all the scatter gather structures and | |
860 | * get pointer to the data members in the headers | |
861 | * (also work out the length while we're here) | |
862 | */ | |
863 | sg = (struct scatterlist *) srb->request_buffer; | |
864 | for (i = 0; i < srb->use_sg; i++) | |
865 | { | |
866 | length += sg[i].length; | |
867 | /* We only do the inner loop for the headers */ | |
868 | if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
869 | { | |
870 | /* scan through this scatterlist */ | |
871 | for ( j=0; j<sg[i].length; j++ ) | |
872 | { | |
873 | if ( element < USB_STOR_SCSI_SENSE_HDRSZ ) | |
874 | { | |
875 | /* fill in the pointers for both header types */ | |
876 | the6->array[element] = sg_address(sg[i]) + j; | |
877 | the10->array[element] = sg_address(sg[i]) + j; | |
878 | ||
879 | } | |
880 | else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
881 | { | |
882 | /* only the longer headers still cares now */ | |
883 | the10->array[element] = sg_address(sg[i]) + j; | |
884 | ||
885 | } | |
886 | /* increase element counter */ | |
887 | element++; | |
888 | } | |
889 | } | |
890 | } | |
891 | } | |
892 | else | |
893 | { | |
894 | length = srb->request_bufflen; | |
895 | buffer = srb->request_buffer; | |
896 | if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ ) | |
897 | printk( KERN_ERR USB_STORAGE | |
898 | "Buffer length smaller than header!!" ); | |
899 | for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ ) | |
900 | { | |
901 | if ( i < USB_STOR_SCSI_SENSE_HDRSZ ) | |
902 | { | |
903 | the6->array[i] = &(buffer[i]); | |
904 | the10->array[i] = &(buffer[i]); | |
905 | } | |
906 | else | |
907 | { | |
908 | the10->array[i] = &(buffer[i]); | |
909 | } | |
910 | } | |
911 | } | |
912 | ||
913 | /* Set value of length passed in */ | |
914 | *length_p = length; | |
915 | } | |
916 |