| NUC472_NUC442_BSP V3.04.000 The Board Support Package for NUC472/NUC442

UmasProtocol.c
Go to the documentation of this file.
1/* Driver for USB Mass Storage compliant devices
2 *
3 * $Id: protocol.c,v 1.7 2000/11/13 22:28:33 mdharm Exp $
4 *
5 * Current development and maintenance by:
6 * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
7 *
8 * Developed with the assistance of:
9 * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
10 *
11 * Initial work by:
12 * (c) 1999 Michael Gee (michael@linuxspecific.com)
13 *
14 * This driver is based on the 'USB Mass Storage Class' document. This
15 * describes in detail the protocol used to communicate with such
16 * devices. Clearly, the designers had SCSI and ATAPI commands in
17 * mind when they created this document. The commands are all very
18 * similar to commands in the SCSI-II and ATAPI specifications.
19 *
20 * It is important to note that in a number of cases this class
21 * exhibits class-specific exemptions from the USB specification.
22 * Notably the usage of NAK, STALL and ACK differs from the norm, in
23 * that they are used to communicate wait, failed and OK on commands.
24 *
25 * Also, for certain devices, the interrupt endpoint is used to convey
26 * status of a command.
27 *
28 * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
29 * information about this driver.
30 *
31 * This program is free software; you can redistribute it and/or modify it
32 * under the terms of the GNU General Public License as published by the
33 * Free Software Foundation; either version 2, or (at your option) any
34 * later version.
35 *
36 * This program is distributed in the hope that it will be useful, but
37 * WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 * General Public License for more details.
40 *
41 * You should have received a copy of the GNU General Public License along
42 * with this program; if not, write to the Free Software Foundation, Inc.,
43 * 675 Mass Ave, Cambridge, MA 02139, USA.
44 */
45
46/**************************************************************************/
56#include <stdio.h>
57#include <string.h>
58
59#include "NUC472_442.h"
60#include "usbh_core.h"
61
62#include "Umas.h"
63
65
66/***********************************************************************
67 * Helper routines
68 ***********************************************************************/
69
70static void usb_stor_scsiSenseParseBuffer(SCSI_CMD_T *srb,
71 Usb_Stor_Scsi_Sense_Hdr_u *the6,
72 Usb_Stor_Scsi_Sense_Hdr_10_u *the10, int *length_p)
73{
74 int i = 0, j = 0, element = 0;
75 int length = 0;
76 uint8_t *buffer = 0;
77 SCATTER_LIST_T *sg = 0;
78
79 /* are we scatter-gathering? */
80 if (srb->use_sg != 0)
81 {
82 /*
83 * loop over all the scatter gather structures and
84 * get pointer to the data members in the headers
85 * (also work out the length while we're here)
86 */
87 sg = (SCATTER_LIST_T *)srb->request_buff;
88 for (i = 0; i < srb->use_sg; i++)
89 {
90 length += sg[i].length;
91 /* We only do the inner loop for the headers */
92 if (element < USB_STOR_SCSI_SENSE_10_HDRSZ)
93 {
94 /* scan through this scatterlist */
95 for (j = 0; j < sg[i].length; j++)
96 {
97 if (element < USB_STOR_SCSI_SENSE_HDRSZ)
98 {
99 /* fill in the pointers for both header types */
100 the6->array[element] = (uint8_t *)&(sg[i].address[j]);
101 the10->array[element] = (uint8_t *)&(sg[i].address[j]);
102 }
103 else if (element < USB_STOR_SCSI_SENSE_10_HDRSZ)
104 {
105 /* only the longer headers still cares now */
106 the10->array[element] = (uint8_t *)&(sg[i].address[j]);
107 }
108 /* increase element counter */
109 element++;
110 } /* end of for */
111 }
112 } /* end of for */
113 }
114 else
115 {
116 length = srb->request_bufflen;
117 buffer = srb->request_buff;
118 if (length < USB_STOR_SCSI_SENSE_10_HDRSZ)
119 UMAS_DEBUG("Buffer length smaller than header!!\n");
120 for (i = 0; i < USB_STOR_SCSI_SENSE_10_HDRSZ; i++)
121 {
122 if (i < USB_STOR_SCSI_SENSE_HDRSZ)
123 {
124 the6->array[i] = &(buffer[i]);
125 the10->array[i] = &(buffer[i]);
126 }
127 else
128 the10->array[i] = &(buffer[i]);
129 }
130 }
131 /* Set value of length passed in */
132 *length_p = length;
133}
134
135
136
137static int usb_stor_scsiSense10to6(SCSI_CMD_T *the10)
138{
139 uint8_t *buffer=0;
140 int outputBufferSize = 0;
141 int length=0;
142 int i=0, j=0, element=0;
143 int sb=0,si=0,db=0,di=0;
144 int sgLength=0;
145 SCATTER_LIST_T *sg = 0;
146 Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
147 Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
148
149
150 UMAS_VDEBUG("usb_stor_scsiSense10to6 - converting 10 byte sense data to 6 byte\n");
151 the10->cmnd[0] = the10->cmnd[0] & 0xBF;
152
153 /* Determine buffer locations */
154 usb_stor_scsiSenseParseBuffer(the10, &the6Locations, &the10Locations, &length);
155
156 /* Work out minimum buffer to output */
157 outputBufferSize = *the10Locations.hdr.dataLengthLSB;
158 outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ;
159
160 /* Check to see if we need to trucate the output */
161 if (outputBufferSize > length)
162 {
163 UMAS_DEBUG("usb_stor_scsiSense10to6 - Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n");
164 UMAS_DEBUG("outputBufferSize is %d and length is %d.\n", outputBufferSize, length);
165 }
166 outputBufferSize = length;
167
168 /* Data length */
169 if (*the10Locations.hdr.dataLengthMSB != 0) /* MSB must be zero */
170 {
171 UMAS_DEBUG("usb_stor_scsiSense10to6 - Command will be truncated to fit in SENSE6 buffer.\n");
172 *the6Locations.hdr.dataLength = 0xff;
173 }
174 else
175 {
176 *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB;
177 }
178
179 /* Medium type and DevSpecific parms */
180 *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType;
181 *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms;
182
183 /* Block descriptor length */
184 if (*the10Locations.hdr.blkDescLengthMSB != 0) /* MSB must be zero */
185 {
186 UMAS_DEBUG("usb_stor_scsiSense10to6 - Command will be truncated to fit in SENSE6 buffer.\n");
187 *the6Locations.hdr.blkDescLength = 0xff;
188 }
189 else
190 {
191 *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB;
192 }
193
194 if (the10->use_sg == 0)
195 {
196 buffer = the10->request_buff;
197 /* Copy the rest of the data */
198 memcpy(&(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
199 &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
200 outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ );
201 /* initialise last bytes left in buffer due to smaller header */
202 memset(&(buffer[outputBufferSize
203 -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]),
204 0,
205 USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
206 }
207 else
208 {
209 sg = (SCATTER_LIST_T *) the10->request_buff;
210 /* scan through this scatterlist and figure out starting positions */
211 for (i = 0; i < the10->use_sg; i++)
212 {
213 sgLength = sg[i].length;
214 for (j = 0; j < sgLength; j++ )
215 {
216 /* get to end of header */
217 if (element == USB_STOR_SCSI_SENSE_HDRSZ)
218 {
219 db=i;
220 di=j;
221 }
222 if (element == USB_STOR_SCSI_SENSE_10_HDRSZ)
223 {
224 sb=i;
225 si=j;
226 /* we've found both sets now, exit loops */
227 j = sgLength;
228 i = the10->use_sg;
229 }
230 element++;
231 }
232 }
233
234 /* Now we know where to start the copy from */
235 element = USB_STOR_SCSI_SENSE_HDRSZ;
236 while (element < outputBufferSize
237 -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ))
238 {
239 /* check limits */
240 if ((sb >= the10->use_sg) || (si >= sg[sb].length) ||
241 (db >= the10->use_sg) || (di >= sg[db].length))
242 {
243 UMAS_DEBUG("usb_stor_scsiSense10to6 - Buffer overrun averted, this shouldn't happen!\n");
244 break;
245 }
246
247 /* copy one byte */
248 sg[db].address[di] = sg[sb].address[si];
249
250 /* get next destination */
251 if (sg[db].length - 1 == di)
252 {
253 db++;
254 di=0;
255 }
256 else
257 {
258 di++;
259 }
260
261 /* get next source */
262 if (sg[sb].length - 1 == si)
263 {
264 sb++;
265 si=0;
266 }
267 else
268 {
269 si++;
270 }
271 element++;
272 }
273 /* zero the remaining bytes */
274 while (element < outputBufferSize)
275 {
276 /* check limits */
277 if ((db >= the10->use_sg) || (di >= sg[db].length))
278 {
279 UMAS_DEBUG("usb_stor_scsiSense10to6 - Buffer overrun averted, this shouldn't happen!\n");
280 break;
281 }
282 sg[db].address[di] = 0;
283
284 /* get next destination */
285 if (sg[db].length-1 == di)
286 {
287 db++;
288 di=0;
289 }
290 else
291 {
292 di++;
293 }
294 element++;
295 }
296 }
297 /* All done any everything was fine */
298 return 0;
299}
300
301static int usb_stor_scsiSense6to10(SCSI_CMD_T* the6)
302{
303 /* will be used to store part of buffer */
304 uint8_t tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ], *buffer=0;
305 int outputBufferSize = 0;
306 int length=0;
307 int i = 0, j = 0, element = 0;
308 int sb = 0, si = 0, db = 0, di = 0;
309 int lsb = 0, lsi = 0, ldb = 0, ldi = 0;
310 SCATTER_LIST_T *sg = 0;
311 Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
312 Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
313
314 UMAS_VDEBUG("-- converting 6 byte sense data to 10 byte\n");
315 the6->cmnd[0] = the6->cmnd[0] | 0x40;
316
317 /* Determine buffer locations */
318 usb_stor_scsiSenseParseBuffer(the6, &the6Locations, &the10Locations, &length);
319
320 /* Work out minimum buffer to output */
321 outputBufferSize = *the6Locations.hdr.dataLength;
322 outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ;
323
324 /* Check to see if we need to trucate the output */
325 if (outputBufferSize > length)
326 {
327 UMAS_DEBUG("Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n");
328 UMAS_DEBUG("outputBufferSize is %d and length is %d.\n", outputBufferSize, length);
329 }
330 outputBufferSize = length;
331
332 /* Block descriptor length - save these before overwriting */
333 tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB;
334 tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB;
335 *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength;
336 *the10Locations.hdr.blkDescLengthMSB = 0;
337
338 /* reserved - save these before overwriting */
339 tempBuffer[0] = *the10Locations.hdr.reserved1;
340 tempBuffer[1] = *the10Locations.hdr.reserved2;
341 *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0;
342
343 /* Medium type and DevSpecific parms */
344 *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms;
345 *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType;
346
347 /* Data length */
348 *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength;
349 *the10Locations.hdr.dataLengthMSB = 0;
350
351 if (!the6->use_sg)
352 {
353 buffer = the6->request_buff;
354 /* Copy the rest of the data */
355 memcpy(&(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
356 &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
357 outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ);
358 /* Put the first four bytes (after header) in place */
359 memcpy(&(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]), tempBuffer,
360 USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
361 }
362 else
363 {
364 sg = (SCATTER_LIST_T *) the6->request_buff;
365 /* scan through this scatterlist and figure out ending positions */
366 for (i = 0; i < the6->use_sg; i++)
367 {
368 for (j = 0; j < sg[i].length; j++)
369 {
370 /* get to end of header */
371 if (element == USB_STOR_SCSI_SENSE_HDRSZ )
372 {
373 ldb = i;
374 ldi = j;
375 }
376 if (element == USB_STOR_SCSI_SENSE_10_HDRSZ)
377 {
378 lsb = i;
379 lsi = j;
380 /* we've found both sets now, exit loops */
381 j = sg[i].length;
382 i = the6->use_sg;
383 break;
384 }
385 element++;
386 }
387 }
388
389 /* scan through this scatterlist and figure out starting positions */
390 element = length - 1;
391
392 /* destination is the last element */
393 db=the6->use_sg - 1;
394 di=sg[db].length - 1;
395
396 for (i = the6->use_sg - 1; i >= 0; i--)
397 {
398 for (j = sg[i].length - 1; j >= 0; j--)
399 {
400 /* get to end of header and find source for copy */
401 if (element == length - 1
402 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ))
403 {
404 sb = i;
405 si = j;
406 /* we've found both sets now, exit loops */
407 j = -1;
408 i = -1;
409 }
410 element--;
411 }
412 }
413
414 /* Now we know where to start the copy from */
415 element = length - 1
416 - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
417 while (element >= USB_STOR_SCSI_SENSE_10_HDRSZ)
418 {
419 /* check limits */
420 if (((sb <= lsb) && (si < lsi)) || ((db <= ldb) && (di < ldi)))
421 {
422 UMAS_DEBUG("Buffer overrun averted, this shouldn't happen!\n");
423 break;
424 }
425
426 /* copy one byte */
427 sg[db].address[di] = sg[sb].address[si];
428
429 /* get next destination */
430 if (di == 0)
431 {
432 db--;
433 di = sg[db].length - 1;
434 }
435 else
436 {
437 di--;
438 }
439
440 /* get next source */
441 if (si == 0)
442 {
443 sb--;
444 si = sg[sb].length - 1;
445 }
446 else
447 {
448 si--;
449 }
450 element--;
451 }
452
453 /* copy the remaining four bytes */
454 while ( element >= USB_STOR_SCSI_SENSE_HDRSZ )
455 {
456 /* check limits */
457 if ((db <= ldb) && (di < ldi))
458 {
459 UMAS_DEBUG("Buffer overrun averted, this shouldn't happen!\n");
460 break;
461 }
462
463 sg[db].address[di] = tempBuffer[element - USB_STOR_SCSI_SENSE_HDRSZ];
464
465 /* get next destination */
466 if (di == 0)
467 {
468 db--;
469 di = sg[db].length - 1;
470 }
471 else
472 {
473 di--;
474 }
475 element--;
476 }
477 }
478 /* All done and everything was fine */
479 return 0;
480}
481
482
483
484/*
485 * Fix-up the return data from an INQUIRY command to show
486 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above umas
487 */
488static void fix_inquiry_data(SCSI_CMD_T *srb)
489{
490 uint8_t *data_ptr;
491
492 /* verify that it's an INQUIRY command */
493 if (srb->cmnd[0] != INQUIRY)
494 return;
495
496 UMAS_DEBUG("Fixing INQUIRY data to show SCSI rev 2\n");
497
498 /* find the location of the data */
499 if (srb->use_sg)
500 {
501 SCATTER_LIST_T *sg;
502
503 sg = (SCATTER_LIST_T *) srb->request_buff;
504 data_ptr = (uint8_t *) sg[0].address;
505 }
506 else
507 data_ptr = (uint8_t *)srb->request_buff;
508
509 /* Change the SCSI revision number */
510 data_ptr[2] |= 0x2;
511}
512
513
514
515/***********************************************************************
516 * Protocol routines
517 ***********************************************************************/
518void UMAS_Qic157Command(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
519{
520 /*
521 * Pad the ATAPI command with zeros
522 * NOTE: This only works because a SCSI_CMD_T struct field contains
523 * a uint8_t cmnd[12], so we know we have storage available
524 */
525 for (; srb->cmd_len<12; srb->cmd_len++)
526 srb->cmnd[srb->cmd_len] = 0;
527
528 /* set command length to 12 bytes */
529 srb->cmd_len = 12;
530
531 /* send the command to the transport layer */
532 UMAS_InvokeTransport(srb, umas);
533
534 /* fix the INQUIRY data if necessary */
535 fix_inquiry_data(srb);
536}
537
538
539
540
541void UMAS_AtapiCommand(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
542{
543 int old_cmnd = 0;
544
545 /*
546 * Fix some commands -- this is a form of mode translation
547 * ATAPI devices only accept 12 byte long commands
548 *
549 * NOTE: This only works because a SCSI_CMD_T struct field contains
550 * a uint8_t cmnd[12], so we know we have storage available
551 */
552
553 /* Pad the ATAPI command with zeros */
554 for (; srb->cmd_len<12; srb->cmd_len++)
555 srb->cmnd[srb->cmd_len] = 0;
556
557 /* set command length to 12 bytes */
558 srb->cmd_len = 12;
559
560 /* determine the correct (or minimum) data length for these commands */
561 switch (srb->cmnd[0])
562 {
563 /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
564 case MODE_SENSE:
565 case MODE_SELECT:
566 /* save the command so we can tell what it was */
567 old_cmnd = srb->cmnd[0];
568
569 srb->cmnd[11] = 0;
570 srb->cmnd[10] = 0;
571 srb->cmnd[9] = 0;
572 srb->cmnd[8] = srb->cmnd[4];
573 srb->cmnd[7] = 0;
574 srb->cmnd[6] = 0;
575 srb->cmnd[5] = 0;
576 srb->cmnd[4] = 0;
577 srb->cmnd[3] = 0;
578 srb->cmnd[2] = srb->cmnd[2];
579 srb->cmnd[1] = srb->cmnd[1];
580 srb->cmnd[0] = srb->cmnd[0] | 0x40;
581 break;
582
583 /* change READ_6/WRITE_6 to READ_10/WRITE_10, which are ATAPI commands */
584 case WRITE_6:
585 case READ_6:
586 srb->cmnd[11] = 0;
587 srb->cmnd[10] = 0;
588 srb->cmnd[9] = 0;
589 srb->cmnd[8] = srb->cmnd[4];
590 srb->cmnd[7] = 0;
591 srb->cmnd[6] = 0;
592 srb->cmnd[5] = srb->cmnd[3];
593 srb->cmnd[4] = srb->cmnd[2];
594 srb->cmnd[3] = srb->cmnd[1] & 0x1F;
595 srb->cmnd[2] = 0;
596 srb->cmnd[1] = srb->cmnd[1] & 0xE0;
597 srb->cmnd[0] = srb->cmnd[0] | 0x20;
598 break;
599 } /* end switch on cmnd[0] */
600
601 /* convert MODE_SELECT data here */
602 if (old_cmnd == MODE_SELECT)
603 usb_stor_scsiSense6to10(srb);
604
605 /* send the command to the transport layer */
606 UMAS_InvokeTransport(srb, umas);
607
608 /* Fix the MODE_SENSE data if we translated the command */
609 if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD))
610 usb_stor_scsiSense10to6(srb);
611
612 /* fix the INQUIRY data if necessary */
613 fix_inquiry_data(srb);
614}
615
616
617
618
619void UMAS_UfiCommand(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
620{
621 int old_cmnd = 0;
622
623 /*
624 * fix some commands -- this is a form of mode translation
625 * UFI devices only accept 12 byte long commands
626 *
627 * NOTE: This only works because a SCSI_CMD_T struct field contains
628 * a uint8_t cmnd[12], so we know we have storage available
629 */
630
631 /* set command length to 12 bytes (this affects the transport layer) */
632 srb->cmd_len = 12;
633
634 /* determine the correct (or minimum) data length for these commands */
635 switch (srb->cmnd[0])
636 {
637 /* for INQUIRY, UFI devices only ever return 36 bytes */
638 case INQUIRY:
639 srb->cmnd[4] = 36;
640 break;
641
642 /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
643 case MODE_SENSE:
644 case MODE_SELECT:
645 /* save the command so we can tell what it was */
646 old_cmnd = srb->cmnd[0];
647
648 srb->cmnd[11] = 0;
649 srb->cmnd[10] = 0;
650 srb->cmnd[9] = 0;
651
652 /*
653 * If we're sending data, we send all. If getting data,
654 * get the minimum
655 */
656 if (srb->cmnd[0] == MODE_SELECT)
657 srb->cmnd[8] = srb->cmnd[4];
658 else
659 srb->cmnd[8] = 8;
660
661 srb->cmnd[7] = 0;
662 srb->cmnd[6] = 0;
663 srb->cmnd[5] = 0;
664 srb->cmnd[4] = 0;
665 srb->cmnd[3] = 0;
666 srb->cmnd[2] = srb->cmnd[2];
667 srb->cmnd[1] = srb->cmnd[1];
668 srb->cmnd[0] = srb->cmnd[0] | 0x40;
669 break;
670
671 /* again, for MODE_SENSE_10, we get the minimum (8) */
672 case MODE_SENSE_10:
673 srb->cmnd[7] = 0;
674 srb->cmnd[8] = 8;
675 break;
676
677 /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
678 case REQUEST_SENSE:
679 srb->cmnd[4] = 18;
680 break;
681
682 /* change READ_6/WRITE_6 to READ_10/WRITE_10, which are UFI commands */
683 case WRITE_6:
684 case READ_6:
685 srb->cmnd[11] = 0;
686 srb->cmnd[10] = 0;
687 srb->cmnd[9] = 0;
688 srb->cmnd[8] = srb->cmnd[4];
689 srb->cmnd[7] = 0;
690 srb->cmnd[6] = 0;
691 srb->cmnd[5] = srb->cmnd[3];
692 srb->cmnd[4] = srb->cmnd[2];
693 srb->cmnd[3] = srb->cmnd[1] & 0x1F;
694 srb->cmnd[2] = 0;
695 srb->cmnd[1] = srb->cmnd[1] & 0xE0;
696 srb->cmnd[0] = srb->cmnd[0] | 0x20;
697 break;
698 } /* end switch on cmnd[0] */
699
700 /* convert MODE_SELECT data here */
701 if (old_cmnd == MODE_SELECT)
702 usb_stor_scsiSense6to10(srb);
703
704 /* send the command to the transport layer */
705 UMAS_InvokeTransport(srb, umas);
706
707 /* Fix the MODE_SENSE data if we translated the command */
708 if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD))
709 usb_stor_scsiSense10to6(srb);
710
711 /* Fix the data for an INQUIRY, if necessary */
712 fix_inquiry_data(srb);
713}
714
715void UMAS_TransparentScsiCommand(SCSI_CMD_T *srb, UMAS_DATA_T *umas)
716{
717 /*
718 * This code supports devices which do not support {READ|WRITE}_6
719 * Apparently, neither Windows or MacOS will use these commands,
720 * so some devices do not support them
721 */
722 if (umas->flags & UMAS_FL_MODE_XLATE)
723 {
724 /* translate READ_6 to READ_10 */
725 if (srb->cmnd[0] == READ_6)
726 {
727 /* get the control */
728 srb->cmnd[9] = umas->srb.cmnd[5];
729
730 /* get the length */
731 srb->cmnd[8] = umas->srb.cmnd[6];
732 srb->cmnd[7] = 0;
733
734 /* set the reserved area to 0 */
735 srb->cmnd[6] = 0;
736
737 /* get LBA */
738 srb->cmnd[5] = umas->srb.cmnd[3];
739 srb->cmnd[4] = umas->srb.cmnd[2];
740 srb->cmnd[3] = 0;
741 srb->cmnd[2] = 0;
742
743 /* LUN and other info in cmnd[1] can stay */
744
745 /* fix command code */
746 srb->cmnd[0] = 0x28;
747
748 UMAS_DEBUG("Changing READ_6 to READ_10\n");
749 UMAS_DEBUG_ShowCommand(srb);
750 }
751
752 /* translate WRITE_6 to WRITE_10 */
753 if (srb->cmnd[0] == WRITE_6)
754 {
755 /* get the control */
756 srb->cmnd[9] = umas->srb.cmnd[5];
757
758 /* get the length */
759 srb->cmnd[8] = umas->srb.cmnd[4];
760 srb->cmnd[7] = 0;
761
762 /* set the reserved area to 0 */
763 srb->cmnd[6] = 0;
764
765 /* get LBA */
766 srb->cmnd[5] = umas->srb.cmnd[3];
767 srb->cmnd[4] = umas->srb.cmnd[2];
768 srb->cmnd[3] = 0;
769 srb->cmnd[2] = 0;
770
771 /* LUN and other info in cmnd[1] can stay */
772
773 /* fix command code */
774 srb->cmnd[0] = 0x2A;
775
776 UMAS_DEBUG("Changing WRITE_6 to WRITE_10\n");
777 UMAS_DEBUG_ShowCommand(&umas->srb);
778 }
779 } /* if (umas->flags & UMAS_FL_MODE_XLATE) */
780
781 /* send the command to the transport layer */
782 UMAS_InvokeTransport(srb, umas);
783
784 /* fix the INQUIRY data if necessary */
785 fix_inquiry_data(srb);
786}
787
789
NUC472_442.h
NUC472/NUC442 peripheral access layer header file. This file contains all the peripheral register's d...
Umas.h
usbh_core.h
USB Host core driver header file.