Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / bus / cam / scsi / scsi_all.c
1 /*
2  * Implementation of Utility functions for all SCSI device types.
3  *
4  * Copyright (c) 1997, 1998 Justin T. Gibbs.
5  * Copyright (c) 1997, 1998 Kenneth D. Merry.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.14.2.9 2002/10/21 05:38:11 simokawa Exp $
30  */
31
32 #include <sys/param.h>
33
34 #ifdef _KERNEL
35 #include <opt_scsi.h>
36
37 #include <sys/systm.h>
38 #else
39 #include <errno.h>
40 #include <stdio.h>
41 #include <string.h>
42 #endif
43
44 #include <cam/cam.h>
45 #include <cam/cam_ccb.h>
46 #include <cam/cam_xpt.h>
47 #include <cam/cam_xpt_periph.h>
48 #include <cam/scsi/scsi_all.h>
49 #ifndef _KERNEL
50 #include <camlib.h>
51
52 #ifndef FALSE
53 #define FALSE   0
54 #endif /* FALSE */
55 #ifndef TRUE
56 #define TRUE    1
57 #endif /* TRUE */
58 #define ERESTART        -1              /* restart syscall */
59 #define EJUSTRETURN     -2              /* don't modify regs, just return */
60 #endif /* !_KERNEL */
61
62 const char *scsi_sense_key_text[] = 
63 {
64         "NO SENSE",
65         "RECOVERED ERROR",
66         "NOT READY",
67         "MEDIUM ERROR",
68         "HARDWARE FAILURE",
69         "ILLEGAL REQUEST",
70         "UNIT ATTENTION",
71         "DATA PROTECT",
72         "BLANK CHECK",
73         "Vendor Specific",
74         "COPY ABORTED",
75         "ABORTED COMMAND",
76         "EQUAL",
77         "VOLUME OVERFLOW",
78         "MISCOMPARE",
79         "RESERVED"
80 };
81
82 #if !defined(SCSI_NO_OP_STRINGS)
83
84 #define D 0x001
85 #define T 0x002
86 #define L 0x004
87 #define P 0x008
88 #define W 0x010
89 #define R 0x020
90 #define S 0x040
91 #define O 0x080
92 #define M 0x100
93 #define C 0x200
94 #define A 0x400
95 #define E 0x800
96
97 #define ALL 0xFFF
98
99 /*
100  * WARNING:  You must update the num_ops field below for this quirk table 
101  * entry if you add more entries.
102  */
103 static struct op_table_entry plextor_cd_ops[] = {
104         {0xD8, R, "CD-DA READ"}
105 };
106
107 static struct scsi_op_quirk_entry scsi_op_quirk_table[] = {
108         {
109                 /*
110                  * I believe that 0xD8 is the Plextor proprietary command
111                  * to read CD-DA data.  I'm not sure which Plextor CDROM
112                  * models support the command, though.  I know for sure
113                  * that the 4X, 8X, and 12X models do, and presumably the
114                  * 12-20X does.  I don't know about any earlier models,
115                  * though.  If anyone has any more complete information,
116                  * feel free to change this quirk entry.
117                  */
118                 {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"},
119                 1, /* number of vendor-specific opcodes for this entry */
120                 plextor_cd_ops
121         }
122 };
123
124 static struct op_table_entry scsi_op_codes[] = {
125 /*
126  * From: ftp://ftp.symbios.com/pub/standards/io/t10/drafts/spc/op-num.txt
127  * Modifications by Kenneth Merry (ken@FreeBSD.ORG)
128  *
129  * Note:  order is important in this table, scsi_op_desc() currently
130  * depends on the opcodes in the table being in order to save search time.
131  */
132 /*  
133  * File: OP-NUM.TXT
134  *
135  * SCSI Operation Codes
136  * Numeric Sorted Listing
137  * as of 11/13/96
138  * 
139  *     D - DIRECT ACCESS DEVICE (SBC)                    device column key
140  *     .T - SEQUENTIAL ACCESS DEVICE (SSC)              -------------------
141  *     . L - PRINTER DEVICE (SSC)                       M = Mandatory
142  *     .  P - PROCESSOR DEVICE (SPC)                    O = Optional
143  *     .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)    V = Vendor specific
144  *     .  . R - CD DEVICE (MMC)                         R = Reserved
145  *     .  .  S - SCANNER DEVICE (SGC)                   Z = Obsolete
146  *     .  .  .O - OPTICAL MEMORY DEVICE (SBC)
147  *     .  .  . M - MEDIA CHANGER DEVICE (SMC)
148  *     .  .  .  C - COMMUNICATION DEVICE (SSC)
149  *     .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
150  *     .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
151  * OP  DTLPWRSOMCAE  Description
152  * --  ------------  ---------------------------------------------------- */
153 /* 00  MMMMMMMMMMMM  TEST UNIT READY */
154 {0x00, ALL,             "TEST UNIT READY"},
155
156 /* 01   M            REWIND */
157 {0x01, T,           "REWIND"},
158 /* 01  Z V ZO ZO     REZERO UNIT */
159 {0x01, D|L|W|O|M,   "REZERO UNIT"},
160
161 /* 02  VVVVVV  V   */
162
163 /* 03  MMMMMMMMMMMM  REQUEST SENSE */
164 {0x03, ALL,         "REQUEST SENSE"},
165
166 /* 04  M    O O      FORMAT UNIT */
167 {0x04, D|R|O,       "FORMAT UNIT"},
168 /* 04   O            FORMAT MEDIUM */
169 {0x04, T,           "FORMAT MEDIUM"},
170 /* 04    O           FORMAT */
171 {0x04, L,           "FORMAT"},
172
173 /* 05  VMVVVV  V     READ BLOCK LIMITS */
174 {0x05, T,           "READ BLOCK LIMITS"},
175
176 /* 06  VVVVVV  V   */
177
178 /* 07  OVV O  OV     REASSIGN BLOCKS */
179 {0x07, D|W|O,       "REASSIGN BLOCKS"},
180 /* 07          O     INITIALIZE ELEMENT STATUS */
181 {0x07, M,           "INITIALIZE ELEMENT STATUS"},
182
183 /* 08  OMV OO OV     READ(06) */
184 {0x08, D|T|W|R|O,   "READ(06)"},
185 /* 08     O          RECEIVE */
186 {0x08, P,           "RECEIVE"},
187 /* 08           M    GET MESSAGE(06) */
188 {0x08, C,           "GET MESSAGE(06)"},
189
190 /* 09  VVVVVV  V   */
191
192 /* 0A  OM  O  OV     WRITE(06) */
193 {0x0A, D|T|W|O, "WRITE(06)"},
194 /* 0A     M          SEND(06) */
195 {0x0A, P,           "SEND(06)"},
196 /* 0A           M    SEND MESSAGE(06) */
197 {0x0A, C,           "SEND MESSAGE(06)"},
198 /* 0A    M           PRINT */
199 {0x0A, L,           "PRINT"},
200
201 /* 0B  Z   ZO ZV     SEEK(06) */
202 {0x0B, D|W|R|O,     "SEEK(06)"},
203 /* 0B    O           SLEW AND PRINT */
204 {0x0B, L,           "SLEW AND PRINT"},
205
206 /* 0C  VVVVVV  V   */
207 /* 0D  VVVVVV  V   */
208 /* 0E  VVVVVV  V   */
209 /* 0F  VOVVVV  V     READ REVERSE */
210 {0x0F, T,           "READ REVERSE"},
211
212 /* 10  VM VVV        WRITE FILEMARKS */
213 {0x10, T,           "WRITE FILEMARKS"},
214 /* 10    O O         SYNCHRONIZE BUFFER */
215 {0x10, L|W,         "SYNCHRONIZE BUFFER"},
216
217 /* 11  VMVVVV        SPACE */
218 {0x11, T,           "SPACE"},
219
220 /* 12  MMMMMMMMMMMM  INQUIRY */
221 {0x12, ALL,         "INQUIRY"},
222
223 /* 13  VOVVVV        VERIFY(06) */
224 {0x13, T,           "VERIFY(06)"},
225
226 /* 14  VOOVVV        RECOVER BUFFERED DATA */
227 {0x14, T|L,         "RECOVER BUFFERED DATA"},
228
229 /* 15  OMO OOOOOOOO  MODE SELECT(06) */
230 {0x15, ALL & ~(P),    "MODE SELECT(06)"},
231
232 /* 16  MMMOMMMM   O  RESERVE(06) */
233 {0x16, D|T|L|P|W|R|S|O|E, "RESERVE(06)"},
234 /* 16          M     RESERVE ELEMENT(06) */
235 {0x16, M,           "RESERVE ELEMENT(06)"},
236
237 /* 17  MMMOMMMM   O  RELEASE(06) */
238 {0x17, ALL & ~(M|C|A), "RELEASE(06)"},
239 /* 17          M     RELEASE ELEMENT(06) */
240 {0x17, M,           "RELEASE ELEMENT(06)"},
241
242 /* 18  OOOOOOOO      COPY */
243 {0x18, ALL & ~(M|C|A|E), "COPY"},
244
245 /* 19  VMVVVV        ERASE */
246 {0x19, T,           "ERASE"},
247
248 /* 1A  OMO OOOOOOOO  MODE SENSE(06) */
249 {0x1A, ALL & ~(P),  "MODE SENSE(06)"},
250
251 /* 1B  O   OM O      STOP START UNIT */
252 {0x1B, D|W|R|O,     "STOP START UNIT"},
253 /* 1B   O            LOAD UNLOAD */
254 {0x1B, T,           "LOAD UNLOAD"},
255 /* 1B        O       SCAN */
256 {0x1B, S,           "SCAN"},
257 /* 1B    O           STOP PRINT */
258 {0x1B, L,           "STOP PRINT"},
259
260 /* 1C  OOOOOOOOOO M  RECEIVE DIAGNOSTIC RESULTS */
261 {0x1C, ALL & ~(A),  "RECEIVE DIAGNOSTIC RESULTS"},
262
263 /* 1D  MMMMMMMMMMMM  SEND DIAGNOSTIC */
264 {0x1D, ALL,         "SEND DIAGNOSTIC"},
265
266 /* 1E  OO  OM OO     PREVENT ALLOW MEDIUM REMOVAL */
267 {0x1E, D|T|W|R|O|M, "PREVENT ALLOW MEDIUM REMOVAL"},
268
269 /* 1F */
270 /* 20  V   VV V */
271 /* 21  V   VV V */
272 /* 22  V   VV V */
273 /* 23  V   VV V */
274
275 /* 24  V   VVM       SET WINDOW */
276 {0x24, S,           "SET WINDOW"},
277
278 /* 25  M   M  M      READ CAPACITY */
279 {0x25, D|W|O,       "READ CAPACITY"},
280 /* 25       M        READ CD RECORDED CAPACITY */
281 {0x25, R,           "READ CD RECORDED CAPACITY"},
282 /* 25        O       GET WINDOW */
283 {0x25, S,           "GET WINDOW"},
284
285 /* 26  V   VV */
286 /* 27  V   VV */
287
288 /* 28  M   MMMM      READ(10) */
289 {0x28, D|W|R|S|O,   "READ(10)"},
290 /* 28           O    GET MESSAGE(10) */
291 {0x28, C,           "GET MESSAGE(10)"},
292
293 /* 29  V   VV O      READ GENERATION */
294 {0x29, O,           "READ GENERATION"},
295
296 /* 2A  M   MM M      WRITE(10) */
297 {0x2A, D|W|R|O,     "WRITE(10)"},
298 /* 2A        O       SEND(10) */
299 {0x2A, S,           "SEND(10)"},
300 /* 2A           O    SEND MESSAGE(10) */
301 {0x2A, C,           "SEND MESSAGE(10)"},
302
303 /* 2B  O   OM O      SEEK(10) */
304 {0x2B, D|W|R|O,     "SEEK(10)"},
305 /* 2B   O            LOCATE */
306 {0x2B, T,           "LOCATE"},
307 /* 2B          O     POSITION TO ELEMENT */
308 {0x2B, M,           "POSITION TO ELEMENT"},
309
310 /* 2C  V      O      ERASE(10) */
311 {0x2C, O,           "ERASE(10)"},
312
313 /* 2D  V   O  O      READ UPDATED BLOCK */
314 {0x2D, W|O,         "READ UPDATED BLOCK"},
315
316 /* 2E  O   O  O      WRITE AND VERIFY(10) */
317 {0x2E, D|W|O,       "WRITE AND VERIFY(10)"},
318
319 /* 2F  O   OO O      VERIFY(10) */
320 {0x2F, D|W|R|O,     "VERIFY(10)"},
321
322 /* 30  Z   ZO Z      SEARCH DATA HIGH(10) */
323 {0x30, D|W|R|O,     "SEARCH DATA HIGH(10)"},
324
325 /* 31  Z   ZO Z      SEARCH DATA EQUAL(10) */
326 {0x31, D|W|R|O,     "SEARCH DATA EQUAL(10)"},
327 /* 31        O       OBJECT POSITION */
328 {0x31, S,           "OBJECT POSITION"},
329
330 /* 32  Z   ZO Z      SEARCH DATA LOW(10) */
331 {0x32, D|W|R|O,     "SEARCH DATA LOW(10"},
332
333 /* 33  O   OO O      SET LIMITS(10) */
334 {0x33, D|W|R|O,     "SET LIMITS(10)"},
335
336 /* 34  O   OO O      PRE-FETCH */
337 {0x34, D|W|R|O,     "PRE-FETCH"},
338 /* 34   O            READ POSITION */
339 {0x34, T,           "READ POSITION"},
340 /* 34        O       GET DATA BUFFER STATUS */
341 {0x34, S,           "GET DATA BUFFER STATUS"},
342
343 /* 35  O   OM O      SYNCHRONIZE CACHE */
344 {0x35, D|W|R|O,     "SYNCHRONIZE CACHE"},
345
346 /* 36  O   OO O      LOCK UNLOCK CACHE */
347 {0x36, D|W|R|O,     "LOCK UNLOCK CACHE"},
348
349 /* 37  O      O      READ DEFECT DATA(10) */
350 {0x37, D|O,         "READ DEFECT DATA(10)"},
351
352 /* 38      O  O      MEDIUM SCAN */
353 {0x38, W|O,         "MEDIUM SCAN"},
354
355 /* 39  OOOOOOOO      COMPARE */
356 {0x39, ALL & ~(M|C|A|E), "COMPARE"},
357
358 /* 3A  OOOOOOOO      COPY AND VERIFY */
359 {0x3A, ALL & ~(M|C|A|E), "COPY AND VERIFY"},
360
361 /* 3B  OOOOOOOOOO O  WRITE BUFFER */
362 {0x3B, ALL & ~(A),  "WRITE BUFFER"},
363
364 /* 3C  OOOOOOOOOO    READ BUFFER */
365 {0x3C, ALL & ~(A|E),"READ BUFFER"},
366
367 /* 3D      O  O      UPDATE BLOCK */
368 {0x3D, W|O,         "UPDATE BLOCK"},
369
370 /* 3E  O   OO O      READ LONG */
371 {0x3E, D|W|R|O,     "READ LONG"},
372
373 /* 3F  O   O  O      WRITE LONG */
374 {0x3F, D|W|O,       "WRITE LONG"},
375
376 /* 40  OOOOOOOOOO    CHANGE DEFINITION */
377 {0x40, ALL & ~(A|E),"CHANGE DEFINITION"},
378
379 /* 41  O             WRITE SAME */
380 {0x41, D,           "WRITE SAME"},
381
382 /* 42       M        READ SUB-CHANNEL */
383 {0x42, R,           "READ SUB-CHANNEL"}, 
384
385 /* 43       M        READ TOC/PMA/ATIP {MMC Proposed} */
386 {0x43, R,           "READ TOC/PMA/ATIP {MMC Proposed}"},
387
388 /* 44   M            REPORT DENSITY SUPPORT */
389 {0x44, T,           "REPORT DENSITY SUPPORT"},
390 /* 44       M        READ HEADER */
391 {0x44, R,           "READ HEADER"},
392
393 /* 45       O        PLAY AUDIO(10) */
394 {0x45, R,           "PLAY AUDIO(10)"},
395
396 /* 46 */
397
398 /* 47       O        PLAY AUDIO MSF */
399 {0x47, R,           "PLAY AUDIO MSF"},
400
401 /* 48       O        PLAY AUDIO TRACK INDEX */
402 {0x48, R,           "PLAY AUDIO TRACK INDEX"},
403
404 /* 49       O        PLAY TRACK RELATIVE(10) */
405 {0x49, R,           "PLAY TRACK RELATIVE(10)"},
406
407 /* 4A */
408
409 /* 4B       O        PAUSE/RESUME */
410 {0x4B, R,           "PAUSE/RESUME"},
411
412 /* 4C  OOOOOOOOOOO   LOG SELECT */
413 {0x4C, ALL & ~(E),  "LOG SELECT"},
414
415 /* 4D  OOOOOOOOOOO   LOG SENSE */
416 {0x4D, ALL & ~(E),  "LOG SENSE"},
417
418 /* 4E       O        STOP PLAY/SCAN {MMC Proposed} */
419 {0x4E, R,           "STOP PLAY/SCAN {MMC Proposed}"},
420
421 /* 4F */
422
423 /* 50  O             XDWRITE(10) */
424 {0x50, D,           "XDWRITE(10)"},
425
426 /* 51  O             XPWRITE(10) */
427 {0x51, D,           "XPWRITE(10)"},
428 /* 51       M        READ DISC INFORMATION {MMC Proposed} */
429 {0x51, R,           "READ DISC INFORMATION {MMC Proposed}"},
430
431 /* 52  O             XDREAD(10) */
432 {0x52, D,           "XDREAD(10)"},
433 /* 52       M        READ TRACK INFORMATION {MMC Proposed} */
434 {0x52, R,           "READ TRACK INFORMATION {MMC Proposed}"},
435
436 /* 53       M        RESERVE TRACK {MMC Proposed} */
437 {0x53, R,           "RESERVE TRACK {MMC Proposed}"},
438
439 /* 54       O        SEND OPC INFORMATION {MMC Proposed} */
440 {0x54, R,           "SEND OPC INFORMATION {MMC Proposed}"},
441
442 /* 55  OOO OOOOOOOO  MODE SELECT(10) */
443 {0x55, ALL & ~(P),  "MODE SELECT(10)"},
444
445 /* 56  MMMOMMMM   O  RESERVE(10) */
446 {0x56, ALL & ~(M|C|A), "RESERVE(10)"},
447 /* 56          M     RESERVE ELEMENT(10) */
448 {0x56, M,           "RESERVE ELEMENT(10)"},
449
450 /* 57  MMMOMMMM   O  RELEASE(10) */
451 {0x57, ALL & ~(M|C|A), "RELEASE(10"},
452 /* 57          M     RELEASE ELEMENT(10) */
453 {0x57, M,           "RELEASE ELEMENT(10)"},
454
455 /* 58       O        REPAIR TRACK {MMC Proposed} */
456 {0x58, R,           "REPAIR TRACK {MMC Proposed}"},
457
458 /* 59       O        READ MASTER CUE {MMC Proposed} */
459 {0x59, R,           "READ MASTER CUE {MMC Proposed}"},
460
461 /* 5A  OOO OOOOOOOO  MODE SENSE(10) */
462 {0x5A, ALL & ~(P),  "MODE SENSE(10)"},
463
464 /* 5B       M        CLOSE TRACK/SESSION {MMC Proposed} */
465 {0x5B, R,           "CLOSE TRACK/SESSION {MMC Proposed}"},
466
467 /* 5C       O        READ BUFFER CAPACITY {MMC Proposed} */
468 {0x5C, R,           "READ BUFFER CAPACITY {MMC Proposed}"},
469
470 /* 5D       O        SEND CUE SHEET {MMC Proposed} */
471 {0x5D, R,           "SEND CUE SHEET {MMC Proposed}"},
472
473 /* 5E  OOOOOOOOO  O  PERSISTENT RESERVE IN */
474 {0x5E, ALL & ~(C|A),"PERSISTENT RESERVE IN"},
475
476 /* 5F  OOOOOOOOO  O  PERSISTENT RESERVE OUT */
477 {0x5F, ALL & ~(C|A),"PERSISTENT RESERVE OUT"},
478
479 /* 80  O             XDWRITE EXTENDED(16) */
480 {0x80, D,           "XDWRITE EXTENDED(16)"},
481
482 /* 81  O             REBUILD(16) */
483 {0x81, D,           "REBUILD(16)"},
484
485 /* 82  O             REGENERATE(16) */
486 {0x82, D,           "REGENERATE(16)"},
487
488 /* 83 */
489 /* 84 */
490 /* 85 */
491 /* 86 */
492 /* 87 */
493 /* 88 */
494 /* 89 */
495 /* 8A */
496 /* 8B */
497 /* 8C */
498 /* 8D */
499 /* 8E */
500 /* 8F */
501 /* 90 */
502 /* 91 */
503 /* 92 */
504 /* 93 */
505 /* 94 */
506 /* 95 */
507 /* 96 */
508 /* 97 */
509 /* 98 */
510 /* 99 */
511 /* 9A */
512 /* 9B */
513 /* 9C */
514 /* 9D */
515 /* 9E */
516 /* 9F */
517
518 /* A0  OOOOOOOOOOO   REPORT LUNS */
519 {0xA0, ALL & ~(E),  "REPORT LUNS"},
520
521 /* A1       O        BLANK {MMC Proposed} */
522 {0xA1, R,           "BLANK {MMC Proposed}"},
523
524 /* A2       O        WRITE CD MSF {MMC Proposed} */
525 {0xA2, R,           "WRITE CD MSF {MMC Proposed}"},
526
527 /* A3            M   MAINTENANCE (IN) */
528 {0xA3, A,           "MAINTENANCE (IN)"},
529
530 /* A4            O   MAINTENANCE (OUT) */
531 {0xA4, A,           "MAINTENANCE (OUT)"},
532
533 /* A5   O      M     MOVE MEDIUM */
534 {0xA5, T|M,         "MOVE MEDIUM"},
535 /* A5       O        PLAY AUDIO(12) */
536 {0xA5, R,           "PLAY AUDIO(12)"},
537
538 /* A6          O     EXCHANGE MEDIUM */
539 {0xA6, M,           "EXCHANGE MEDIUM"},
540 /* A6       O        LOAD/UNLOAD CD {MMC Proposed} */
541 {0xA6, R,           "LOAD/UNLOAD CD {MMC Proposed}"},
542
543 /* A7  OO  OO OO     MOVE MEDIUM ATTACHED */
544 {0xA7, D|T|W|R|O|M, "MOVE MEDIUM ATTACHED"},
545
546 /* A8      OM O      READ(12) */
547 {0xA8, W|R|O,       "READ(12)"},
548 /* A8           O    GET MESSAGE(12) */
549 {0xA8, C,           "GET MESSAGE(12)"},
550
551 /* A9       O        PLAY TRACK RELATIVE(12) */
552 {0xA9, R,           "PLAY TRACK RELATIVE(12)"},
553
554 /* AA      O  O      WRITE(12) */
555 {0xAA, W|O,         "WRITE(12)"},
556 /* AA       O        WRITE CD(12) {MMC Proposed} */
557 {0xAA, R,           "WRITE CD(12) {MMC Proposed}"},
558 /* AA           O    SEND MESSAGE(12) */
559 {0xAA, C,           "SEND MESSAGE(12)"},
560
561 /* AB */
562
563 /* AC         O      ERASE(12) */
564 {0xAC, O,           "ERASE(12)"},
565
566 /* AD */
567
568 /* AE      O  O      WRITE AND VERIFY(12) */
569 {0xAE, W|O,         "WRITE AND VERIFY(12)"},
570
571 /* AF      OO O      VERIFY(12) */
572 {0xAF, W|R|O,       "VERIFY(12)"},
573
574 /* B0      ZO Z      SEARCH DATA HIGH(12) */
575 {0xB0, W|R|O,       "SEARCH DATA HIGH(12)"},
576
577 /* B1      ZO Z      SEARCH DATA EQUAL(12) */
578 {0xB1, W|R|O,       "SEARCH DATA EQUAL(12)"},
579
580 /* B2      ZO Z      SEARCH DATA LOW(12) */
581 {0xB2, W|R|O,       "SEARCH DATA LOW(12)"},
582
583 /* B3      OO O      SET LIMITS(12) */
584 {0xB3, W|R|O,       "SET LIMITS(12)"},
585
586 /* B4  OO  OO OO     READ ELEMENT STATUS ATTACHED */
587 {0xB4, D|T|W|R|O|M, "READ ELEMENT STATUS ATTACHED"},
588
589 /* B5          O     REQUEST VOLUME ELEMENT ADDRESS */
590 {0xB5, M,           "REQUEST VOLUME ELEMENT ADDRESS"},
591
592 /* B6          O     SEND VOLUME TAG */
593 {0xB6, M,           "SEND VOLUME TAG"},
594
595 /* B7         O      READ DEFECT DATA(12) */
596 {0xB7, O,           "READ DEFECT DATA(12)"},
597
598 /* B8   O      M     READ ELEMENT STATUS */
599 {0xB8, T|M,         "READ ELEMENT STATUS"},
600 /* B8       O        SET CD SPEED {MMC Proposed} */
601 {0xB8, R,           "SET CD SPEED {MMC Proposed}"},
602
603 /* B9       M        READ CD MSF {MMC Proposed} */
604 {0xB9, R,           "READ CD MSF {MMC Proposed}"},
605
606 /* BA       O        SCAN {MMC Proposed} */
607 {0xBA, R,           "SCAN {MMC Proposed}"},
608 /* BA            M   REDUNDANCY GROUP (IN) */
609 {0xBA, A,           "REDUNDANCY GROUP (IN)"},
610
611 /* BB       O        SET CD-ROM SPEED {proposed} */
612 {0xBB, R,           "SET CD-ROM SPEED {proposed}"},
613 /* BB            O   REDUNDANCY GROUP (OUT) */
614 {0xBB, A,           "REDUNDANCY GROUP (OUT)"},
615
616 /* BC       O        PLAY CD {MMC Proposed} */
617 {0xBC, R,           "PLAY CD {MMC Proposed}"},
618 /* BC            M   SPARE (IN) */
619 {0xBC, A,           "SPARE (IN)"},
620
621 /* BD       M        MECHANISM STATUS {MMC Proposed} */
622 {0xBD, R,           "MECHANISM STATUS {MMC Proposed}"},
623 /* BD            O   SPARE (OUT) */
624 {0xBD, A,           "SPARE (OUT)"},
625
626 /* BE       O        READ CD {MMC Proposed} */
627 {0xBE, R,           "READ CD {MMC Proposed}"},
628 /* BE            M   VOLUME SET (IN) */
629 {0xBE, A,           "VOLUME SET (IN)"},
630
631 /* BF            O   VOLUME SET (OUT) */
632 {0xBF, A,           "VOLUME SET (OUT)"}
633 };
634
635 const char *
636 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
637 {
638         caddr_t match;
639         int i, j;
640         u_int16_t opmask;
641         u_int16_t pd_type;
642         int       num_ops[2];
643         struct op_table_entry *table[2];
644         int num_tables;
645
646         pd_type = SID_TYPE(inq_data);
647
648         match = cam_quirkmatch((caddr_t)inq_data,
649                                (caddr_t)scsi_op_quirk_table,
650                                sizeof(scsi_op_quirk_table)/
651                                sizeof(*scsi_op_quirk_table),
652                                sizeof(*scsi_op_quirk_table),
653                                scsi_inquiry_match);
654
655         if (match != NULL) {
656                 table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
657                 num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops;
658                 table[1] = scsi_op_codes;
659                 num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
660                 num_tables = 2;
661         } else {
662                 /*      
663                  * If this is true, we have a vendor specific opcode that
664                  * wasn't covered in the quirk table.
665                  */
666                 if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80)))
667                         return("Vendor Specific Command");
668
669                 table[0] = scsi_op_codes;
670                 num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
671                 num_tables = 1;
672         }
673
674         /* RBC is 'Simplified' Direct Access Device */
675         if (pd_type == T_RBC)
676                 pd_type = T_DIRECT;
677
678         opmask = 1 << pd_type;
679
680         for (j = 0; j < num_tables; j++) {
681                 for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){
682                         if ((table[j][i].opcode == opcode) 
683                          && ((table[j][i].opmask & opmask) != 0))
684                                 return(table[j][i].desc);
685                 }
686         }
687         
688         /*
689          * If we can't find a match for the command in the table, we just
690          * assume it's a vendor specifc command.
691          */
692         return("Vendor Specific Command");
693
694 }
695
696 #else /* SCSI_NO_OP_STRINGS */
697
698 const char *
699 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
700 {
701         return("");
702 }
703
704 #endif
705
706
707 #include <sys/param.h>
708
709
710 #if !defined(SCSI_NO_SENSE_STRINGS)
711 #define SST(asc, ascq, action, desc) \
712         asc, ascq, action, desc
713 #else 
714 #define SST(asc, ascq, action, desc) \
715         asc, ascq, action
716 #endif 
717
718 static const char quantum[] = "QUANTUM";
719
720 /*
721  * WARNING:  You must update the num_ascs field below for this quirk table 
722  * entry if you add more entries.
723  */
724 static struct asc_table_entry quantum_fireball_entries[] = {
725         {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, 
726              "Logical unit not ready, initializing cmd. required")}
727 };
728
729 static struct scsi_sense_quirk_entry asc_quirk_table[] = {
730         {
731                 /*
732                  * The Quantum Fireball ST and SE like to return 0x04 0x0b when
733                  * they really should return 0x04 0x02.  0x04,0x0b isn't
734                  * defined in any SCSI spec, and it isn't mentioned in the
735                  * hardware manual for these drives.
736                  */
737                 {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
738                 1, /* number of vendor-specific sense codes for this entry */
739                 quantum_fireball_entries
740         }
741 };
742
743 static struct asc_table_entry asc_text[] = {
744 /*
745  * From File: ASC-NUM.TXT
746  * SCSI ASC/ASCQ Assignments
747  * Numeric Sorted Listing
748  * as of  5/12/97
749  *
750  * D - DIRECT ACCESS DEVICE (SBC)                     device column key
751  * .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
752  * . L - PRINTER DEVICE (SSC)                           blank = reserved
753  * .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
754  * .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
755  * .  . R - CD DEVICE (MMC)
756  * .  .  S - SCANNER DEVICE (SGC)
757  * .  .  .O - OPTICAL MEMORY DEVICE (SBC)
758  * .  .  . M - MEDIA CHANGER DEVICE (SMC)
759  * .  .  .  C - COMMUNICATION DEVICE (SSC)
760  * .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
761  * .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
762  * DTLPWRSOMCAE        ASC   ASCQ  Action  Description
763  * ------------        ----  ----  ------  -----------------------------------*/
764 /* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NEPDEF,
765                         "No additional sense information") },
766 /*  T    S      */{SST(0x00, 0x01, SS_DEF,
767                         "Filemark detected") },
768 /*  T    S      */{SST(0x00, 0x02, SS_DEF,
769                         "End-of-partition/medium detected") },
770 /*  T           */{SST(0x00, 0x03, SS_DEF,
771                         "Setmark detected") },
772 /*  T    S      */{SST(0x00, 0x04, SS_DEF,
773                         "Beginning-of-partition/medium detected") },
774 /*  T    S      */{SST(0x00, 0x05, SS_DEF,
775                         "End-of-data detected") },
776 /* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_DEF,
777                         "I/O process terminated") },
778 /*      R       */{SST(0x00, 0x11, SS_NEDEF|EBUSY,
779                         "Audio play operation in progress") },
780 /*      R       */{SST(0x00, 0x12, SS_NEDEF,
781                         "Audio play operation paused") },
782 /*      R       */{SST(0x00, 0x13, SS_NEDEF,
783                         "Audio play operation successfully completed") },
784 /*      R       */{SST(0x00, 0x14, SS_DEF,
785                         "Audio play operation stopped due to error") },
786 /*      R       */{SST(0x00, 0x15, SS_DEF,
787                         "No current audio status to return") },
788 /* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_NEDEF|EBUSY,
789                         "Operation in progress") },
790 /* DTL WRSOM AE */{SST(0x00, 0x17, SS_DEF,
791                         "Cleaning requested") },
792 /* D   W  O     */{SST(0x01, 0x00, SS_DEF,
793                         "No index/sector signal") },
794 /* D   WR OM    */{SST(0x02, 0x00, SS_DEF,
795                         "No seek complete") },
796 /* DTL W SO     */{SST(0x03, 0x00, SS_DEF,
797                         "Peripheral device write fault") },
798 /*  T           */{SST(0x03, 0x01, SS_DEF,
799                         "No write current") },
800 /*  T           */{SST(0x03, 0x02, SS_DEF,
801                         "Excessive write errors") },
802 /* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
803                         "Logical unit not ready, cause not reportable") },
804 /* DTLPWRSOMCAE */{SST(0x04, 0x01, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
805                         "Logical unit is in process of becoming ready") },
806 /* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
807                         "Logical unit not ready, initializing cmd. required") },
808 /* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_NEDEF|ENXIO,
809                         "Logical unit not ready, manual intervention required")},
810 /* DTL    O     */{SST(0x04, 0x04, SS_NEDEF|EBUSY,
811                         "Logical unit not ready, format in progress") },
812 /* DT  W  OMCA  */{SST(0x04, 0x05, SS_NEDEF|EBUSY,
813                         "Logical unit not ready, rebuild in progress") },
814 /* DT  W  OMCA  */{SST(0x04, 0x06, SS_NEDEF|EBUSY,
815                         "Logical unit not ready, recalculation in progress") },
816 /* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_NEDEF|EBUSY,
817                         "Logical unit not ready, operation in progress") },
818 /*      R       */{SST(0x04, 0x08, SS_NEDEF|EBUSY,
819                         "Logical unit not ready, long write in progress") },
820 /* DTL WRSOMCAE */{SST(0x05, 0x00, SS_DEF,
821                         "Logical unit does not respond to selection") },
822 /* D   WR OM    */{SST(0x06, 0x00, SS_DEF,
823                         "No reference position found") },
824 /* DTL WRSOM    */{SST(0x07, 0x00, SS_DEF,
825                         "Multiple peripheral devices selected") },
826 /* DTL WRSOMCAE */{SST(0x08, 0x00, SS_DEF,
827                         "Logical unit communication failure") },
828 /* DTL WRSOMCAE */{SST(0x08, 0x01, SS_DEF,
829                         "Logical unit communication time-out") },
830 /* DTL WRSOMCAE */{SST(0x08, 0x02, SS_DEF,
831                         "Logical unit communication parity error") },
832 /* DT   R OM    */{SST(0x08, 0x03, SS_DEF,
833                         "Logical unit communication crc error (ultra-dma/32)")},
834 /* DT  WR O     */{SST(0x09, 0x00, SS_DEF,
835                         "Track following error") },
836 /*     WR O     */{SST(0x09, 0x01, SS_DEF,
837                         "Tracking servo failure") },
838 /*     WR O     */{SST(0x09, 0x02, SS_DEF,
839                         "Focus servo failure") },
840 /*     WR O     */{SST(0x09, 0x03, SS_DEF,
841                         "Spindle servo failure") },
842 /* DT  WR O     */{SST(0x09, 0x04, SS_DEF,
843                         "Head select fault") },
844 /* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_NEDEF|ENOSPC,
845                         "Error log overflow") },
846 /* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_DEF,
847                         "Warning") },
848 /* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_DEF,
849                         "Specified temperature exceeded") },
850 /* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_DEF,
851                         "Enclosure degraded") },
852 /*  T   RS      */{SST(0x0C, 0x00, SS_DEF,
853                         "Write error") },
854 /* D   W  O     */{SST(0x0C, 0x01, SS_NEDEF,
855                         "Write error - recovered with auto reallocation") },
856 /* D   W  O     */{SST(0x0C, 0x02, SS_DEF,
857                         "Write error - auto reallocation failed") },
858 /* D   W  O     */{SST(0x0C, 0x03, SS_DEF,
859                         "Write error - recommend reassignment") },
860 /* DT  W  O     */{SST(0x0C, 0x04, SS_NEPDEF,
861                         "Compression check miscompare error") },
862 /* DT  W  O     */{SST(0x0C, 0x05, SS_DEF,
863                         "Data expansion occurred during compression") },
864 /* DT  W  O     */{SST(0x0C, 0x06, SS_DEF,
865                         "Block not compressible") },
866 /*      R       */{SST(0x0C, 0x07, SS_DEF,
867                         "Write error - recovery needed") },
868 /*      R       */{SST(0x0C, 0x08, SS_DEF,
869                         "Write error - recovery failed") },
870 /*      R       */{SST(0x0C, 0x09, SS_DEF,
871                         "Write error - loss of streaming") },
872 /*      R       */{SST(0x0C, 0x0A, SS_DEF,
873                         "Write error - padding blocks added") },
874 /* D   W  O     */{SST(0x10, 0x00, SS_DEF,
875                         "ID CRC or ECC error") },
876 /* DT  WRSO     */{SST(0x11, 0x00, SS_DEF,
877                         "Unrecovered read error") },
878 /* DT  W SO     */{SST(0x11, 0x01, SS_DEF,
879                         "Read retries exhausted") },
880 /* DT  W SO     */{SST(0x11, 0x02, SS_DEF,
881                         "Error too long to correct") },
882 /* DT  W SO     */{SST(0x11, 0x03, SS_DEF,
883                         "Multiple read errors") },
884 /* D   W  O     */{SST(0x11, 0x04, SS_DEF,
885                         "Unrecovered read error - auto reallocate failed") },
886 /*     WR O     */{SST(0x11, 0x05, SS_DEF,
887                         "L-EC uncorrectable error") },
888 /*     WR O     */{SST(0x11, 0x06, SS_DEF,
889                         "CIRC unrecovered error") },
890 /*     W  O     */{SST(0x11, 0x07, SS_DEF,
891                         "Data re-synchronization error") },
892 /*  T           */{SST(0x11, 0x08, SS_DEF,
893                         "Incomplete block read") },
894 /*  T           */{SST(0x11, 0x09, SS_DEF,
895                         "No gap found") },
896 /* DT     O     */{SST(0x11, 0x0A, SS_DEF,
897                         "Miscorrected error") },
898 /* D   W  O     */{SST(0x11, 0x0B, SS_DEF,
899                         "Unrecovered read error - recommend reassignment") },
900 /* D   W  O     */{SST(0x11, 0x0C, SS_DEF,
901                         "Unrecovered read error - recommend rewrite the data")},
902 /* DT  WR O     */{SST(0x11, 0x0D, SS_DEF,
903                         "De-compression CRC error") },
904 /* DT  WR O     */{SST(0x11, 0x0E, SS_DEF,
905                         "Cannot decompress using declared algorithm") },
906 /*      R       */{SST(0x11, 0x0F, SS_DEF,
907                         "Error reading UPC/EAN number") },
908 /*      R       */{SST(0x11, 0x10, SS_DEF,
909                         "Error reading ISRC number") },
910 /*      R       */{SST(0x11, 0x11, SS_DEF,
911                         "Read error - loss of streaming") },
912 /* D   W  O     */{SST(0x12, 0x00, SS_DEF,
913                         "Address mark not found for id field") },
914 /* D   W  O     */{SST(0x13, 0x00, SS_DEF,
915                         "Address mark not found for data field") },
916 /* DTL WRSO     */{SST(0x14, 0x00, SS_DEF,
917                         "Recorded entity not found") },
918 /* DT  WR O     */{SST(0x14, 0x01, SS_DEF,
919                         "Record not found") },
920 /*  T           */{SST(0x14, 0x02, SS_DEF,
921                         "Filemark or setmark not found") },
922 /*  T           */{SST(0x14, 0x03, SS_DEF,
923                         "End-of-data not found") },
924 /*  T           */{SST(0x14, 0x04, SS_DEF,
925                         "Block sequence error") },
926 /* DT  W  O     */{SST(0x14, 0x05, SS_DEF,
927                         "Record not found - recommend reassignment") },
928 /* DT  W  O     */{SST(0x14, 0x06, SS_DEF,
929                         "Record not found - data auto-reallocated") },
930 /* DTL WRSOM    */{SST(0x15, 0x00, SS_DEF,
931                         "Random positioning error") },
932 /* DTL WRSOM    */{SST(0x15, 0x01, SS_DEF,
933                         "Mechanical positioning error") },
934 /* DT  WR O     */{SST(0x15, 0x02, SS_DEF,
935                         "Positioning error detected by read of medium") },
936 /* D   W  O     */{SST(0x16, 0x00, SS_DEF,
937                         "Data synchronization mark error") },
938 /* D   W  O     */{SST(0x16, 0x01, SS_DEF,
939                         "Data sync error - data rewritten") },
940 /* D   W  O     */{SST(0x16, 0x02, SS_DEF,
941                         "Data sync error - recommend rewrite") },
942 /* D   W  O     */{SST(0x16, 0x03, SS_NEDEF,
943                         "Data sync error - data auto-reallocated") },
944 /* D   W  O     */{SST(0x16, 0x04, SS_DEF,
945                         "Data sync error - recommend reassignment") },
946 /* DT  WRSO     */{SST(0x17, 0x00, SS_NEDEF,
947                         "Recovered data with no error correction applied") },
948 /* DT  WRSO     */{SST(0x17, 0x01, SS_NEDEF,
949                         "Recovered data with retries") },
950 /* DT  WR O     */{SST(0x17, 0x02, SS_NEDEF,
951                         "Recovered data with positive head offset") },
952 /* DT  WR O     */{SST(0x17, 0x03, SS_NEDEF,
953                         "Recovered data with negative head offset") },
954 /*     WR O     */{SST(0x17, 0x04, SS_NEDEF,
955                         "Recovered data with retries and/or CIRC applied") },
956 /* D   WR O     */{SST(0x17, 0x05, SS_NEDEF,
957                         "Recovered data using previous sector id") },
958 /* D   W  O     */{SST(0x17, 0x06, SS_NEDEF,
959                         "Recovered data without ECC - data auto-reallocated") },
960 /* D   W  O     */{SST(0x17, 0x07, SS_NEDEF,
961                         "Recovered data without ECC - recommend reassignment")},
962 /* D   W  O     */{SST(0x17, 0x08, SS_NEDEF,
963                         "Recovered data without ECC - recommend rewrite") },
964 /* D   W  O     */{SST(0x17, 0x09, SS_NEDEF,
965                         "Recovered data without ECC - data rewritten") },
966 /* D   W  O     */{SST(0x18, 0x00, SS_NEDEF,
967                         "Recovered data with error correction applied") },
968 /* D   WR O     */{SST(0x18, 0x01, SS_NEDEF,
969                         "Recovered data with error corr. & retries applied") },
970 /* D   WR O     */{SST(0x18, 0x02, SS_NEDEF,
971                         "Recovered data - data auto-reallocated") },
972 /*      R       */{SST(0x18, 0x03, SS_NEDEF,
973                         "Recovered data with CIRC") },
974 /*      R       */{SST(0x18, 0x04, SS_NEDEF,
975                         "Recovered data with L-EC") },
976 /* D   WR O     */{SST(0x18, 0x05, SS_NEDEF,
977                         "Recovered data - recommend reassignment") },
978 /* D   WR O     */{SST(0x18, 0x06, SS_NEDEF,
979                         "Recovered data - recommend rewrite") },
980 /* D   W  O     */{SST(0x18, 0x07, SS_NEDEF,
981                         "Recovered data with ECC - data rewritten") },
982 /* D      O     */{SST(0x19, 0x00, SS_DEF,
983                         "Defect list error") },
984 /* D      O     */{SST(0x19, 0x01, SS_DEF,
985                         "Defect list not available") },
986 /* D      O     */{SST(0x19, 0x02, SS_DEF,
987                         "Defect list error in primary list") },
988 /* D      O     */{SST(0x19, 0x03, SS_DEF,
989                         "Defect list error in grown list") },
990 /* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_DEF,
991                         "Parameter list length error") },
992 /* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_DEF,
993                         "Synchronous data transfer error") },
994 /* D      O     */{SST(0x1C, 0x00, SS_DEF,
995                         "Defect list not found") },
996 /* D      O     */{SST(0x1C, 0x01, SS_DEF,
997                         "Primary defect list not found") },
998 /* D      O     */{SST(0x1C, 0x02, SS_DEF,
999                         "Grown defect list not found") },
1000 /* D   W  O     */{SST(0x1D, 0x00, SS_NEPDEF,
1001                         "Miscompare during verify operation" )},
1002 /* D   W  O     */{SST(0x1E, 0x00, SS_NEDEF,
1003                         "Recovered id with ecc correction") },
1004 /* D      O     */{SST(0x1F, 0x00, SS_DEF,
1005                         "Partial defect list transfer") },
1006 /* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_DEF,
1007                         "Invalid command operation code") },
1008 /* DT  WR OM    */{SST(0x21, 0x00, SS_DEF,
1009                         "Logical block address out of range" )},
1010 /* DT  WR OM    */{SST(0x21, 0x01, SS_DEF,
1011                         "Invalid element address") },
1012 /* D            */{SST(0x22, 0x00, SS_DEF,
1013                         "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
1014 /* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_NEDEF|EINVAL,
1015                         "Invalid field in CDB") },
1016 /* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_NEDEF|ENXIO,
1017                         "Logical unit not supported") },
1018 /* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_NEDEF|EINVAL,
1019                         "Invalid field in parameter list") },
1020 /* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_NEDEF|EINVAL,
1021                         "Parameter not supported") },
1022 /* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_NEDEF|EINVAL,
1023                         "Parameter value invalid") },
1024 /* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_DEF,
1025                         "Threshold parameters not supported") },
1026 /* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_DEF,
1027                         "Invalid release of active persistent reservation") },
1028 /* DT  W  O     */{SST(0x27, 0x00, SS_NEDEF|EACCES,
1029                         "Write protected") },
1030 /* DT  W  O     */{SST(0x27, 0x01, SS_NEDEF|EACCES,
1031                         "Hardware write protected") },
1032 /* DT  W  O     */{SST(0x27, 0x02, SS_NEDEF|EACCES,
1033                         "Logical unit software write protected") },
1034 /*  T           */{SST(0x27, 0x03, SS_NEDEF|EACCES,
1035                         "Associated write protect") },
1036 /*  T           */{SST(0x27, 0x04, SS_NEDEF|EACCES,
1037                         "Persistent write protect") },
1038 /*  T           */{SST(0x27, 0x05, SS_NEDEF|EACCES,
1039                         "Permanent write protect") },
1040 /* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_NEDEF|ENXIO,
1041                         "Not ready to ready change, medium may have changed") },
1042 /* DT  WR OM    */{SST(0x28, 0x01, SS_DEF,
1043                         "Import or export element accessed") },
1044 /* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_NEDEF|ENXIO,
1045                         "Power on, reset, or bus device reset occurred") },
1046 /* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_DEF,
1047                         "Power on occurred") },
1048 /* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_DEF,
1049                         "Scsi bus reset occurred") },
1050 /* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_DEF,
1051                         "Bus device reset function occurred") },
1052 /* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_DEF,
1053                         "Device internal reset") },
1054 /* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_DEF,
1055                         "Transceiver mode changed to single-ended") },
1056 /* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_DEF,
1057                         "Transceiver mode changed to LVD") },
1058 /* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_DEF,
1059                         "Parameters changed") },
1060 /* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_DEF,
1061                         "Mode parameters changed") },
1062 /* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_DEF,
1063                         "Log parameters changed") },
1064 /* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_DEF,
1065                         "Reservations preempted") },
1066 /* DTLPWRSO C   */{SST(0x2B, 0x00, SS_DEF,
1067                         "Copy cannot execute since host cannot disconnect") },
1068 /* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_DEF,
1069                         "Command sequence error") },
1070 /*       S      */{SST(0x2C, 0x01, SS_DEF,
1071                         "Too many windows specified") },
1072 /*       S      */{SST(0x2C, 0x02, SS_DEF,
1073                         "Invalid combination of windows specified") },
1074 /*      R       */{SST(0x2C, 0x03, SS_DEF,
1075                         "Current program area is not empty") },
1076 /*      R       */{SST(0x2C, 0x04, SS_DEF,
1077                         "Current program area is empty") },
1078 /*  T           */{SST(0x2D, 0x00, SS_DEF,
1079                         "Overwrite error on update in place") },
1080 /* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_DEF,
1081                         "Commands cleared by another initiator") },
1082 /* DT  WR OM    */{SST(0x30, 0x00, SS_DEF,
1083                         "Incompatible medium installed") },
1084 /* DT  WR O     */{SST(0x30, 0x01, SS_DEF,
1085                         "Cannot read medium - unknown format") },
1086 /* DT  WR O     */{SST(0x30, 0x02, SS_DEF,
1087                         "Cannot read medium - incompatible format") },
1088 /* DT           */{SST(0x30, 0x03, SS_DEF,
1089                         "Cleaning cartridge installed") },
1090 /* DT  WR O     */{SST(0x30, 0x04, SS_DEF,
1091                         "Cannot write medium - unknown format") },
1092 /* DT  WR O     */{SST(0x30, 0x05, SS_DEF,
1093                         "Cannot write medium - incompatible format") },
1094 /* DT  W  O     */{SST(0x30, 0x06, SS_DEF,
1095                         "Cannot format medium - incompatible medium") },
1096 /* DTL WRSOM AE */{SST(0x30, 0x07, SS_DEF,
1097                         "Cleaning failure") },
1098 /*      R       */{SST(0x30, 0x08, SS_DEF,
1099                         "Cannot write - application code mismatch") },
1100 /*      R       */{SST(0x30, 0x09, SS_DEF,
1101                         "Current session not fixated for append") },
1102 /* DT  WR O     */{SST(0x31, 0x00, SS_DEF,
1103                         "Medium format corrupted") },
1104 /* D L  R O     */{SST(0x31, 0x01, SS_DEF,
1105                         "Format command failed") },
1106 /* D   W  O     */{SST(0x32, 0x00, SS_DEF,
1107                         "No defect spare location available") },
1108 /* D   W  O     */{SST(0x32, 0x01, SS_DEF,
1109                         "Defect list update failure") },
1110 /*  T           */{SST(0x33, 0x00, SS_DEF,
1111                         "Tape length error") },
1112 /* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_DEF,
1113                         "Enclosure failure") },
1114 /* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_DEF,
1115                         "Enclosure services failure") },
1116 /* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_DEF,
1117                         "Unsupported enclosure function") },
1118 /* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_DEF,
1119                         "Enclosure services unavailable") },
1120 /* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_DEF,
1121                         "Enclosure services transfer failure") },
1122 /* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_DEF,
1123                         "Enclosure services transfer refused") },
1124 /*   L          */{SST(0x36, 0x00, SS_DEF,
1125                         "Ribbon, ink, or toner failure") },
1126 /* DTL WRSOMCAE */{SST(0x37, 0x00, SS_DEF,
1127                         "Rounded parameter") },
1128 /* DTL WRSOMCAE */{SST(0x39, 0x00, SS_DEF,
1129                         "Saving parameters not supported") },
1130 /* DTL WRSOM    */{SST(0x3A, 0x00, SS_NEDEF|ENXIO,
1131                         "Medium not present") },
1132 /* DT  WR OM    */{SST(0x3A, 0x01, SS_NEDEF|ENXIO,
1133                         "Medium not present - tray closed") },
1134 /* DT  WR OM    */{SST(0x3A, 0x02, SS_NEDEF|ENXIO,
1135                         "Medium not present - tray open") },
1136 /*  TL          */{SST(0x3B, 0x00, SS_DEF,
1137                         "Sequential positioning error") },
1138 /*  T           */{SST(0x3B, 0x01, SS_DEF,
1139                         "Tape position error at beginning-of-medium") },
1140 /*  T           */{SST(0x3B, 0x02, SS_DEF,
1141                         "Tape position error at end-of-medium") },
1142 /*   L          */{SST(0x3B, 0x03, SS_DEF,
1143                         "Tape or electronic vertical forms unit not ready") },
1144 /*   L          */{SST(0x3B, 0x04, SS_DEF,
1145                         "Slew failure") },
1146 /*   L          */{SST(0x3B, 0x05, SS_DEF,
1147                         "Paper jam") },
1148 /*   L          */{SST(0x3B, 0x06, SS_DEF,
1149                         "Failed to sense top-of-form") },
1150 /*   L          */{SST(0x3B, 0x07, SS_DEF,
1151                         "Failed to sense bottom-of-form") },
1152 /*  T           */{SST(0x3B, 0x08, SS_DEF,
1153                         "Reposition error") },
1154 /*       S      */{SST(0x3B, 0x09, SS_DEF,
1155                         "Read past end of medium") },
1156 /*       S      */{SST(0x3B, 0x0A, SS_DEF,
1157                         "Read past beginning of medium") },
1158 /*       S      */{SST(0x3B, 0x0B, SS_DEF,
1159                         "Position past end of medium") },
1160 /*  T    S      */{SST(0x3B, 0x0C, SS_DEF,
1161                         "Position past beginning of medium") },
1162 /* DT  WR OM    */{SST(0x3B, 0x0D, SS_NEDEF|ENOSPC,
1163                         "Medium destination element full") },
1164 /* DT  WR OM    */{SST(0x3B, 0x0E, SS_DEF,
1165                         "Medium source element empty") },
1166 /*      R       */{SST(0x3B, 0x0F, SS_DEF,
1167                         "End of medium reached") },
1168 /* DT  WR OM    */{SST(0x3B, 0x11, SS_DEF,
1169                         "Medium magazine not accessible") },
1170 /* DT  WR OM    */{SST(0x3B, 0x12, SS_DEF,
1171                         "Medium magazine removed") },
1172 /* DT  WR OM    */{SST(0x3B, 0x13, SS_DEF,
1173                         "Medium magazine inserted") },
1174 /* DT  WR OM    */{SST(0x3B, 0x14, SS_DEF,
1175                         "Medium magazine locked") },
1176 /* DT  WR OM    */{SST(0x3B, 0x15, SS_DEF,
1177                         "Medium magazine unlocked") },
1178 /* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_DEF,
1179                         "Invalid bits in identify message") },
1180 /* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_DEF,
1181                         "Logical unit has not self-configured yet") },
1182 /* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_DEF,
1183                         "Logical unit failure") },
1184 /* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_DEF,
1185                         "Timeout on logical unit") },
1186 /* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_DEF,
1187                         "Target operating conditions have changed") },
1188 /* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_DEF,
1189                         "Microcode has been changed") },
1190 /* DTLPWRSOMC   */{SST(0x3F, 0x02, SS_DEF,
1191                         "Changed operating definition") },
1192 /* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_DEF,
1193                         "Inquiry data has changed") },
1194 /* DT  WR OMCAE */{SST(0x3F, 0x04, SS_DEF,
1195                         "Component device attached") },
1196 /* DT  WR OMCAE */{SST(0x3F, 0x05, SS_DEF,
1197                         "Device identifier changed") },
1198 /* DT  WR OMCAE */{SST(0x3F, 0x06, SS_DEF,
1199                         "Redundancy group created or modified") },
1200 /* DT  WR OMCAE */{SST(0x3F, 0x07, SS_DEF,
1201                         "Redundancy group deleted") },
1202 /* DT  WR OMCAE */{SST(0x3F, 0x08, SS_DEF,
1203                         "Spare created or modified") },
1204 /* DT  WR OMCAE */{SST(0x3F, 0x09, SS_DEF,
1205                         "Spare deleted") },
1206 /* DT  WR OMCAE */{SST(0x3F, 0x0A, SS_DEF,
1207                         "Volume set created or modified") },
1208 /* DT  WR OMCAE */{SST(0x3F, 0x0B, SS_DEF,
1209                         "Volume set deleted") },
1210 /* DT  WR OMCAE */{SST(0x3F, 0x0C, SS_DEF,
1211                         "Volume set deassigned") },
1212 /* DT  WR OMCAE */{SST(0x3F, 0x0D, SS_DEF,
1213                         "Volume set reassigned") },
1214 /* D            */{SST(0x40, 0x00, SS_DEF,
1215                         "Ram failure") }, /* deprecated - use 40 NN instead */
1216 /* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_DEF,
1217                         "Diagnostic failure: ASCQ = Component ID") },
1218 /* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_DEF|SSQ_RANGE,
1219                         NULL) },/* Range 0x80->0xFF */
1220 /* D            */{SST(0x41, 0x00, SS_DEF,
1221                         "Data path failure") }, /* deprecated - use 40 NN instead */
1222 /* D            */{SST(0x42, 0x00, SS_DEF,
1223                         "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
1224 /* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_DEF,
1225                         "Message error") },
1226 /* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_DEF,
1227                         "Internal target failure") },
1228 /* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_DEF,
1229                         "Select or reselect failure") },
1230 /* DTLPWRSOMC   */{SST(0x46, 0x00, SS_DEF,
1231                         "Unsuccessful soft reset") },
1232 /* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_DEF,
1233                         "SCSI parity error") },
1234 /* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_DEF,
1235                         "Initiator detected error message received") },
1236 /* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_DEF,
1237                         "Invalid message error") },
1238 /* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_DEF,
1239                         "Command phase error") },
1240 /* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_DEF,
1241                         "Data phase error") },
1242 /* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_DEF,
1243                         "Logical unit failed self-configuration") },
1244 /* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_DEF,
1245                         "Tagged overlapped commands: ASCQ = Queue tag ID") },
1246 /* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_DEF|SSQ_RANGE,
1247                         NULL)}, /* Range 0x00->0xFF */
1248 /* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_DEF,
1249                         "Overlapped commands attempted") },
1250 /*  T           */{SST(0x50, 0x00, SS_DEF,
1251                         "Write append error") },
1252 /*  T           */{SST(0x50, 0x01, SS_DEF,
1253                         "Write append position error") },
1254 /*  T           */{SST(0x50, 0x02, SS_DEF,
1255                         "Position error related to timing") },
1256 /*  T     O     */{SST(0x51, 0x00, SS_DEF,
1257                         "Erase failure") },
1258 /*  T           */{SST(0x52, 0x00, SS_DEF,
1259                         "Cartridge fault") },
1260 /* DTL WRSOM    */{SST(0x53, 0x00, SS_DEF,
1261                         "Media load or eject failed") },
1262 /*  T           */{SST(0x53, 0x01, SS_DEF,
1263                         "Unload tape failure") },
1264 /* DT  WR OM    */{SST(0x53, 0x02, SS_DEF,
1265                         "Medium removal prevented") },
1266 /*    P         */{SST(0x54, 0x00, SS_DEF,
1267                         "Scsi to host system interface failure") },
1268 /*    P         */{SST(0x55, 0x00, SS_DEF,
1269                         "System resource failure") },
1270 /* D      O     */{SST(0x55, 0x01, SS_NEDEF|ENOSPC,
1271                         "System buffer full") },
1272 /*      R       */{SST(0x57, 0x00, SS_DEF,
1273                         "Unable to recover table-of-contents") },
1274 /*        O     */{SST(0x58, 0x00, SS_DEF,
1275                         "Generation does not exist") },
1276 /*        O     */{SST(0x59, 0x00, SS_DEF,
1277                         "Updated block read") },
1278 /* DTLPWRSOM    */{SST(0x5A, 0x00, SS_DEF,
1279                         "Operator request or state change input") },
1280 /* DT  WR OM    */{SST(0x5A, 0x01, SS_DEF,
1281                         "Operator medium removal request") },
1282 /* DT  W  O     */{SST(0x5A, 0x02, SS_DEF,
1283                         "Operator selected write protect") },
1284 /* DT  W  O     */{SST(0x5A, 0x03, SS_DEF,
1285                         "Operator selected write permit") },
1286 /* DTLPWRSOM    */{SST(0x5B, 0x00, SS_DEF,
1287                         "Log exception") },
1288 /* DTLPWRSOM    */{SST(0x5B, 0x01, SS_DEF,
1289                         "Threshold condition met") },
1290 /* DTLPWRSOM    */{SST(0x5B, 0x02, SS_DEF,
1291                         "Log counter at maximum") },
1292 /* DTLPWRSOM    */{SST(0x5B, 0x03, SS_DEF,
1293                         "Log list codes exhausted") },
1294 /* D      O     */{SST(0x5C, 0x00, SS_DEF,
1295                         "RPL status change") },
1296 /* D      O     */{SST(0x5C, 0x01, SS_NEDEF,
1297                         "Spindles synchronized") },
1298 /* D      O     */{SST(0x5C, 0x02, SS_DEF,
1299                         "Spindles not synchronized") },
1300 /* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_DEF,
1301                         "Failure prediction threshold exceeded") },
1302 /* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_DEF,
1303                         "Failure prediction threshold exceeded (false)") },
1304 /* DTLPWRSO CA  */{SST(0x5E, 0x00, SS_DEF,
1305                         "Low power condition on") },
1306 /* DTLPWRSO CA  */{SST(0x5E, 0x01, SS_DEF,
1307                         "Idle condition activated by timer") },
1308 /* DTLPWRSO CA  */{SST(0x5E, 0x02, SS_DEF,
1309                         "Standby condition activated by timer") },
1310 /* DTLPWRSO CA  */{SST(0x5E, 0x03, SS_DEF,
1311                         "Idle condition activated by command") },
1312 /* DTLPWRSO CA  */{SST(0x5E, 0x04, SS_DEF,
1313                         "Standby condition activated by command") },
1314 /*       S      */{SST(0x60, 0x00, SS_DEF,
1315                         "Lamp failure") },
1316 /*       S      */{SST(0x61, 0x00, SS_DEF,
1317                         "Video acquisition error") },
1318 /*       S      */{SST(0x61, 0x01, SS_DEF,
1319                         "Unable to acquire video") },
1320 /*       S      */{SST(0x61, 0x02, SS_DEF,
1321                         "Out of focus") },
1322 /*       S      */{SST(0x62, 0x00, SS_DEF,
1323                         "Scan head positioning error") },
1324 /*      R       */{SST(0x63, 0x00, SS_DEF,
1325                         "End of user area encountered on this track") },
1326 /*      R       */{SST(0x63, 0x01, SS_NEDEF|ENOSPC,
1327                         "Packet does not fit in available space") },
1328 /*      R       */{SST(0x64, 0x00, SS_DEF,
1329                         "Illegal mode for this track") },
1330 /*      R       */{SST(0x64, 0x01, SS_DEF,
1331                         "Invalid packet size") },
1332 /* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_DEF,
1333                         "Voltage fault") },
1334 /*       S      */{SST(0x66, 0x00, SS_DEF,
1335                         "Automatic document feeder cover up") },
1336 /*       S      */{SST(0x66, 0x01, SS_DEF,
1337                         "Automatic document feeder lift up") },
1338 /*       S      */{SST(0x66, 0x02, SS_DEF,
1339                         "Document jam in automatic document feeder") },
1340 /*       S      */{SST(0x66, 0x03, SS_DEF,
1341                         "Document miss feed automatic in document feeder") },
1342 /*           A  */{SST(0x67, 0x00, SS_DEF,
1343                         "Configuration failure") },
1344 /*           A  */{SST(0x67, 0x01, SS_DEF,
1345                         "Configuration of incapable logical units failed") },
1346 /*           A  */{SST(0x67, 0x02, SS_DEF,
1347                         "Add logical unit failed") },
1348 /*           A  */{SST(0x67, 0x03, SS_DEF,
1349                         "Modification of logical unit failed") },
1350 /*           A  */{SST(0x67, 0x04, SS_DEF,
1351                         "Exchange of logical unit failed") },
1352 /*           A  */{SST(0x67, 0x05, SS_DEF,
1353                         "Remove of logical unit failed") },
1354 /*           A  */{SST(0x67, 0x06, SS_DEF,
1355                         "Attachment of logical unit failed") },
1356 /*           A  */{SST(0x67, 0x07, SS_DEF,
1357                         "Creation of logical unit failed") },
1358 /*           A  */{SST(0x68, 0x00, SS_DEF,
1359                         "Logical unit not configured") },
1360 /*           A  */{SST(0x69, 0x00, SS_DEF,
1361                         "Data loss on logical unit") },
1362 /*           A  */{SST(0x69, 0x01, SS_DEF,
1363                         "Multiple logical unit failures") },
1364 /*           A  */{SST(0x69, 0x02, SS_DEF,
1365                         "Parity/data mismatch") },
1366 /*           A  */{SST(0x6A, 0x00, SS_DEF,
1367                         "Informational, refer to log") },
1368 /*           A  */{SST(0x6B, 0x00, SS_DEF,
1369                         "State change has occurred") },
1370 /*           A  */{SST(0x6B, 0x01, SS_DEF,
1371                         "Redundancy level got better") },
1372 /*           A  */{SST(0x6B, 0x02, SS_DEF,
1373                         "Redundancy level got worse") },
1374 /*           A  */{SST(0x6C, 0x00, SS_DEF,
1375                         "Rebuild failure occurred") },
1376 /*           A  */{SST(0x6D, 0x00, SS_DEF,
1377                         "Recalculate failure occurred") },
1378 /*           A  */{SST(0x6E, 0x00, SS_DEF,
1379                         "Command to logical unit failed") },
1380 /*  T           */{SST(0x70, 0x00, SS_DEF,
1381                         "Decompression exception short: ASCQ = Algorithm ID") },
1382 /*  T           */{SST(0x70, 0xFF, SS_DEF|SSQ_RANGE,
1383                         NULL) }, /* Range 0x00 -> 0xFF */
1384 /*  T           */{SST(0x71, 0x00, SS_DEF,
1385                         "Decompression exception long: ASCQ = Algorithm ID") },
1386 /*  T           */{SST(0x71, 0xFF, SS_DEF|SSQ_RANGE,
1387                         NULL) }, /* Range 0x00 -> 0xFF */       
1388 /*      R       */{SST(0x72, 0x00, SS_DEF,
1389                         "Session fixation error") },
1390 /*      R       */{SST(0x72, 0x01, SS_DEF,
1391                         "Session fixation error writing lead-in") },
1392 /*      R       */{SST(0x72, 0x02, SS_DEF,
1393                         "Session fixation error writing lead-out") },
1394 /*      R       */{SST(0x72, 0x03, SS_DEF,
1395                         "Session fixation error - incomplete track in session") },
1396 /*      R       */{SST(0x72, 0x04, SS_DEF,
1397                         "Empty or partially written reserved track") },
1398 /*      R       */{SST(0x73, 0x00, SS_DEF,
1399                         "CD control error") },
1400 /*      R       */{SST(0x73, 0x01, SS_DEF,
1401                         "Power calibration area almost full") },
1402 /*      R       */{SST(0x73, 0x02, SS_NEDEF|ENOSPC,
1403                         "Power calibration area is full") },
1404 /*      R       */{SST(0x73, 0x03, SS_DEF,
1405                         "Power calibration area error") },
1406 /*      R       */{SST(0x73, 0x04, SS_DEF,
1407                         "Program memory area update failure") },
1408 /*      R       */{SST(0x73, 0x05, SS_DEF,
1409                         "program memory area is full") }
1410 };
1411
1412 #if !defined(SCSI_NO_SENSE_STRINGS)
1413 const char *
1414 scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data)
1415 {
1416         int i, j;
1417         caddr_t match;
1418         struct asc_table_entry *table[2];
1419         int table_size[2];
1420         int num_tables;
1421
1422         if (inq_data == NULL)
1423                 return(NULL);
1424
1425         match = cam_quirkmatch((caddr_t)inq_data,
1426                                (caddr_t)asc_quirk_table,
1427                                sizeof(asc_quirk_table)/sizeof(*asc_quirk_table),
1428                                sizeof(*asc_quirk_table), scsi_inquiry_match);
1429
1430         if (match != NULL) {
1431                 table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info;
1432                 table_size[0] = 
1433                         ((struct scsi_sense_quirk_entry *)match)->num_ascs;
1434                 table[1] = asc_text;
1435                 table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]);
1436                 num_tables = 2;
1437         } else {
1438                 table[0] = asc_text;
1439                 table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]);
1440                 num_tables = 1;
1441         }
1442
1443         for (j = 0; j < num_tables; j++) {
1444                 for (i = 0; i < table_size[j]; i++) {
1445                         if (table[j][i].asc == asc) {
1446
1447                                 /* Check for ranges */
1448                                 if ((table[j][i].action & SSQ_RANGE) != 0) {
1449                                 
1450                                         if (table[j][i].ascq >= ascq
1451                                          && table[j][i-1].ascq <= ascq)
1452                                                 return table[j][i-1].desc;
1453
1454                                         continue;
1455                                 }
1456                         
1457                                 if (table[j][i].ascq == ascq)
1458                                         return table[j][i].desc;
1459                         } 
1460                 }
1461         }
1462
1463         if (asc >= 0x80 && asc <= 0xff)
1464                 return "Vendor Specific ASC";
1465
1466         if (ascq >= 0x80 && ascq <= 0xff)
1467                 return "Vendor Specific ASCQ";
1468
1469         return "Reserved ASC/ASCQ pair";
1470 }
1471
1472 #else /* SCSI_NO_SENSE_STRINGS */
1473 const char *
1474 scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data)
1475 {
1476         return ("");
1477 }
1478 #endif
1479
1480 /*
1481  * Given a particular failed CCB and its device type information, return
1482  * the appropriate action from either the sense code quirk table or the
1483  * sense code table.
1484  */
1485 scsi_sense_action
1486 scsi_error_action(int asc, int ascq, struct scsi_inquiry_data *inq_data)
1487 {
1488         caddr_t match;
1489         struct asc_table_entry *table[2];
1490         int table_size[2];
1491         int num_tables;
1492         int i, j;
1493
1494         /*
1495          * If we don't have inquiry data, we can't match against any quirk
1496          * entries.
1497          */
1498         if (inq_data != NULL) {
1499                 match = cam_quirkmatch((caddr_t)inq_data,
1500                                        (caddr_t)asc_quirk_table,
1501                                        sizeof(asc_quirk_table) /
1502                                          sizeof(*asc_quirk_table),
1503                                        sizeof(*asc_quirk_table),
1504                                        scsi_inquiry_match);
1505         } else
1506                 match = NULL;
1507
1508         if (match != NULL) {
1509                 table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info;
1510                 table_size[0] = 
1511                         ((struct scsi_sense_quirk_entry *)match)->num_ascs;
1512                 table[1] = asc_text;
1513                 table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]);
1514                 num_tables = 2;
1515         } else {
1516                 table[0] = asc_text;
1517                 table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]);
1518                 num_tables = 1;
1519         }
1520
1521         for (j = 0; j < num_tables; j++) {
1522                 for (i = 0; i < table_size[j]; i++) {
1523                         if (table[j][i].asc == asc) {
1524
1525                                 /* Check for ranges */
1526                                 if ((table[j][i].action & SSQ_RANGE) != 0){
1527                                 
1528                                         if (table[j][i].ascq >= ascq
1529                                          && table[j][i-1].ascq <= ascq)
1530                                                 return table[j][i].action;
1531
1532                                         continue;
1533                                 }
1534
1535                                 /*
1536                                  * Check to see if we have a match.  If the
1537                                  * current ascq in the table is greater
1538                                  * than our ascq, and there aren't any more
1539                                  * tables to search, just return the
1540                                  * default action.
1541                                  */
1542                                 if (table[j][i].ascq == ascq)
1543                                         return(table[j][i].action);
1544                                 else if ((j == (num_tables - 1)) &&
1545                                         (table[j][i].ascq > ascq))
1546                                         return(SS_DEF);
1547                         }
1548                 }
1549         }
1550         /* 
1551          * If we get to this point, it's most likely a vendor specific
1552          * ASC and we don't have a quirk entry for it.  Oh well, we just
1553          * tell the error handling code to take the default action.
1554          */
1555         return(SS_DEF);
1556 }
1557
1558 char *
1559 scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
1560 {
1561         u_int8_t cdb_len;
1562         int i;
1563
1564         if (cdb_ptr == NULL)
1565                 return("");
1566
1567         /* Silence warnings */
1568         cdb_len = 0;
1569
1570         /*
1571          * This is taken from the SCSI-3 draft spec.
1572          * (T10/1157D revision 0.3)
1573          * The top 3 bits of an opcode are the group code.  The next 5 bits
1574          * are the command code.
1575          * Group 0:  six byte commands
1576          * Group 1:  ten byte commands
1577          * Group 2:  ten byte commands
1578          * Group 3:  reserved
1579          * Group 4:  sixteen byte commands
1580          * Group 5:  twelve byte commands
1581          * Group 6:  vendor specific
1582          * Group 7:  vendor specific
1583          */
1584         switch((*cdb_ptr >> 5) & 0x7) {
1585                 case 0:
1586                         cdb_len = 6;
1587                         break;
1588                 case 1:
1589                 case 2:
1590                         cdb_len = 10;
1591                         break;
1592                 case 3:
1593                 case 6:
1594                 case 7:
1595                         /* in this case, just print out the opcode */
1596                         cdb_len = 1;
1597                         break;
1598                 case 4:
1599                         cdb_len = 16;
1600                         break;
1601                 case 5:
1602                         cdb_len = 12;
1603                         break;
1604         }
1605         *cdb_string = '\0';
1606         for (i = 0; i < cdb_len; i++)
1607                 snprintf(cdb_string + strlen(cdb_string),
1608                     len - strlen(cdb_string), "%x ", cdb_ptr[i]);
1609
1610         return(cdb_string);
1611 }
1612 /*
1613  * scsi_sense_print will decode the sense data into human
1614  * readable form.  Sense handlers can use this to generate
1615  * a report.
1616  */
1617 /*
1618  * Because scsi_sense_print() utilizes transport layer functions, it will
1619  * only work in the kernel.
1620  */
1621 #ifdef _KERNEL
1622
1623 void 
1624 scsi_sense_print(struct ccb_scsiio *csio)
1625 {
1626         struct    scsi_sense_data *sense;
1627         u_int32_t info;
1628         int       error_code;
1629         int       sense_key;
1630         int       asc, ascq;
1631         struct ccb_getdev cgd;
1632         u_int8_t  command_print;
1633
1634         sense = &csio->sense_data;
1635         
1636         /*
1637          * If the CDB is a physical address, we can't deal with it..
1638          */
1639         if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0)
1640                 command_print = 0;
1641         else
1642                 command_print = 1;
1643
1644         /*
1645          * Get the device information.
1646          */
1647         xpt_setup_ccb(&cgd.ccb_h,
1648                       csio->ccb_h.path,
1649                       /*priority*/ 1);
1650         cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1651         xpt_action((union ccb *)&cgd);
1652
1653         /*
1654          * If the device is unconfigured, just pretend that it is a hard
1655          * drive.  scsi_op_desc() needs this.
1656          */
1657         if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
1658                 cgd.inq_data.device = T_DIRECT;
1659
1660         if (command_print != 0) {
1661                 char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
1662
1663                 xpt_print_path(csio->ccb_h.path);
1664
1665                 if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1666                         printf("%s. CDB: %s\n", 
1667                                 scsi_op_desc(csio->cdb_io.cdb_ptr[0],
1668                                 &cgd.inq_data),
1669                                 scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str,
1670                                                 sizeof(cdb_str)));
1671                 } else {
1672                         printf("%s. CDB: %s\n",
1673                                 scsi_op_desc(csio->cdb_io.cdb_bytes[0], 
1674                                 &cgd.inq_data), scsi_cdb_string(
1675                                 csio->cdb_io.cdb_bytes, cdb_str,
1676                                 sizeof(cdb_str)));
1677                 }
1678         }
1679
1680         /*
1681          * If the sense data is a physical pointer, forget it.
1682          */
1683         if (csio->ccb_h.flags & CAM_SENSE_PTR) {
1684                 if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1685                         return;
1686                 else {
1687                         /* 
1688                          * XXX KDM this is stupid, but casting the
1689                          * structure doesn't work...
1690                          */
1691                         bcopy(&csio->sense_data, sense, 
1692                               sizeof(struct scsi_sense_data *));
1693                 }
1694         } else {
1695                 /*
1696                  * If the physical sense flag is set, but the sense pointer
1697                  * is not also set, we assume that the user is an idiot and
1698                  * return.  (Well, okay, it could be that somehow, the
1699                  * entire csio is physical, but we would have probably core
1700                  * dumped on one of the bogus pointer deferences above
1701                  * already.)
1702                  */
1703                 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 
1704                         return;
1705                 else
1706                         sense = &csio->sense_data;
1707         }
1708
1709         xpt_print_path(csio->ccb_h.path);
1710         error_code = sense->error_code & SSD_ERRCODE;
1711         sense_key = sense->flags & SSD_KEY;
1712
1713         switch (error_code) {
1714         case SSD_DEFERRED_ERROR:
1715                 printf("Deferred Error: ");
1716                 /* FALLTHROUGH */
1717         case SSD_CURRENT_ERROR:
1718
1719                 printf("%s", scsi_sense_key_text[sense_key]);
1720                 info = scsi_4btoul(sense->info);
1721                 
1722                 if (sense->error_code & SSD_ERRCODE_VALID) {
1723
1724                         switch (sense_key) {
1725                         case SSD_KEY_NOT_READY:
1726                         case SSD_KEY_ILLEGAL_REQUEST:
1727                         case SSD_KEY_UNIT_ATTENTION:
1728                         case SSD_KEY_DATA_PROTECT:
1729                                 break;
1730                         case SSD_KEY_BLANK_CHECK:
1731                                 printf(" req sz: %d (decimal)",
1732                                     info);
1733                                 break;
1734                         default:
1735                                 if (info) {
1736                                         if (sense->flags & SSD_ILI) {
1737                                                 printf(" ILI (length mismatch):"
1738                                                        " %d", info);
1739                                         } else {
1740                                                 printf(" info:%x", info);
1741                                         }
1742                                 }
1743                         }
1744                 } else if (info)
1745                         printf(" info?:%x", info);
1746
1747                 if (sense->extra_len >= 4) {
1748                         if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
1749                                 printf(" csi:%x,%x,%x,%x",
1750                                        sense->cmd_spec_info[0],
1751                                        sense->cmd_spec_info[1],
1752                                        sense->cmd_spec_info[2],
1753                                        sense->cmd_spec_info[3]);
1754                         }
1755                 }
1756
1757                 asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
1758                 ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
1759
1760                 if (asc || ascq) {
1761                         const char *desc = scsi_sense_desc(asc, ascq,
1762                                                            &cgd.inq_data);
1763                         printf(" asc:%x,%x\n", asc, ascq);
1764
1765                         xpt_print_path(csio->ccb_h.path);
1766                         printf("%s", desc);
1767                 }
1768
1769                 if (sense->extra_len >= 7 && sense->fru) {
1770                         printf(" field replaceable unit: %x", sense->fru);
1771                 }
1772
1773                 if ((sense->extra_len >= 10)
1774                  && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
1775                         printf(" sks:%x,%x", sense->sense_key_spec[0],
1776                                scsi_2btoul(&sense->sense_key_spec[1]));
1777                 }
1778                 break;
1779
1780         default:
1781                 printf("error code %d",
1782                     sense->error_code & SSD_ERRCODE);
1783                 if (sense->error_code & SSD_ERRCODE_VALID) {
1784                         printf(" at block no. %d (decimal)",
1785                                info = scsi_4btoul(sense->info));
1786                 }
1787         }
1788
1789         printf("\n");
1790 }
1791
1792 #else /* !_KERNEL */
1793
1794
1795 char *
1796 scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, 
1797                   char *str, int str_len)
1798 {
1799         struct    scsi_sense_data *sense;
1800         u_int32_t info;
1801         int       error_code;
1802         int       sense_key;
1803         int       asc, ascq;
1804         u_int8_t  command_print;
1805         char      path_str[64];
1806         char      tmpstr[2048];
1807         int       tmpstrlen = 2048;
1808         int       cur_len = 0, tmplen = 0, retlen;
1809
1810         if ((device == NULL) || (csio == NULL) || (str == NULL))
1811                 return(NULL);
1812
1813         if (str_len <= 0)
1814                 return(NULL);
1815
1816         /*
1817          * If the CDB is a physical address, we can't deal with it..
1818          */
1819         if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0)
1820                 command_print = 0;
1821         else
1822                 command_print = 1;
1823
1824         cam_path_string(device, path_str, 64);
1825
1826         str[0] = '\0';
1827
1828         sense = NULL;
1829
1830         if (command_print != 0) {
1831                 char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
1832
1833                 retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str);
1834
1835                 if ((tmplen = str_len - cur_len - 1) < 0)
1836                         goto sst_bailout;
1837
1838                 strncat(str, tmpstr, tmplen);
1839                 cur_len += retlen;
1840                 str[str_len - 1] = '\0';
1841
1842                 if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1843                         retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", 
1844                                           scsi_op_desc(csio->cdb_io.cdb_ptr[0], 
1845                                                        &device->inq_data),
1846                                           scsi_cdb_string(csio->cdb_io.cdb_ptr, 
1847                                                           cdb_str,
1848                                                           sizeof(cdb_str)));
1849                 } else {
1850                         retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n",
1851                                          scsi_op_desc(csio->cdb_io.cdb_bytes[0],
1852                                           &device->inq_data), scsi_cdb_string(
1853                                           csio->cdb_io.cdb_bytes, cdb_str,
1854                                           sizeof(cdb_str)));
1855                 }
1856
1857                 if ((tmplen = str_len - cur_len - 1) < 0)
1858                         goto sst_bailout;
1859
1860                 strncat(str, tmpstr, tmplen);
1861                 cur_len += retlen;
1862                 str[str_len - 1] = '\0';
1863         }
1864
1865         /*
1866          * If the sense data is a physical pointer, forget it.
1867          */
1868         if (csio->ccb_h.flags & CAM_SENSE_PTR) {
1869                 if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1870                         return(NULL);
1871                 else {
1872                         /* 
1873                          * XXX KDM this is stupid, but casting the
1874                          * structure doesn't work...
1875                          */
1876                         bcopy(&csio->sense_data, sense, 
1877                               sizeof(struct scsi_sense_data *));
1878                 }
1879         } else {
1880                 /*
1881                  * If the physical sense flag is set, but the sense pointer
1882                  * is not also set, we assume that the user is an idiot and
1883                  * return.  (Well, okay, it could be that somehow, the
1884                  * entire csio is physical, but we would have probably core
1885                  * dumped on one of the bogus pointer deferences above
1886                  * already.)
1887                  */
1888                 if (csio->ccb_h.flags & CAM_SENSE_PHYS) 
1889                         return(NULL);
1890                 else
1891                         sense = &csio->sense_data;
1892         }
1893
1894
1895         retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str);
1896
1897         if ((tmplen = str_len - cur_len - 1) < 0)
1898                 goto sst_bailout;
1899
1900         strncat(str, tmpstr, tmplen);
1901         cur_len += retlen;
1902         str[str_len - 1] = '\0';
1903
1904         error_code = sense->error_code & SSD_ERRCODE;
1905         sense_key = sense->flags & SSD_KEY;
1906
1907         switch (error_code) {
1908         case SSD_DEFERRED_ERROR:
1909                 retlen = snprintf(tmpstr, tmpstrlen, "Deferred Error: ");
1910
1911                 if ((tmplen = str_len - cur_len - 1) < 0)
1912                         goto sst_bailout;
1913
1914                 strncat(str, tmpstr, tmplen);
1915                 cur_len += retlen;
1916                 str[str_len - 1] = '\0';
1917                 /* FALLTHROUGH */
1918         case SSD_CURRENT_ERROR:
1919
1920                 retlen = snprintf(tmpstr, tmpstrlen, "%s", 
1921                                   scsi_sense_key_text[sense_key]);
1922
1923                 if ((tmplen = str_len - cur_len - 1) < 0)
1924                         goto sst_bailout;
1925
1926                 strncat(str, tmpstr, tmplen);
1927                 cur_len += retlen;
1928                 str[str_len - 1] = '\0';
1929
1930                 info = scsi_4btoul(sense->info);
1931                 
1932                 if (sense->error_code & SSD_ERRCODE_VALID) {
1933
1934                         switch (sense_key) {
1935                         case SSD_KEY_NOT_READY:
1936                         case SSD_KEY_ILLEGAL_REQUEST:
1937                         case SSD_KEY_UNIT_ATTENTION:
1938                         case SSD_KEY_DATA_PROTECT:
1939                                 break;
1940                         case SSD_KEY_BLANK_CHECK:
1941                                 retlen = snprintf(tmpstr, tmpstrlen, 
1942                                                   " req sz: %d (decimal)", 
1943                                                   info);
1944
1945                                 if ((tmplen = str_len - cur_len - 1) < 0)
1946                                         goto sst_bailout;
1947
1948                                 strncat(str, tmpstr, tmplen);
1949                                 cur_len += retlen;
1950                                 str[str_len - 1] = '\0';
1951                                 break;
1952                         default:
1953                                 if (info) {
1954                                         if (sense->flags & SSD_ILI) {
1955                                                 retlen = snprintf (tmpstr,
1956                                                                    tmpstrlen, 
1957                                                                 " ILI (length "
1958                                                         "mismatch): %d", info);
1959                         
1960                                         } else {
1961                                                 retlen = snprintf(tmpstr,
1962                                                                   tmpstrlen, 
1963                                                                   " info:%x", 
1964                                                                   info);
1965                                         }
1966
1967                                         if ((tmplen = str_len - cur_len -1) < 0)
1968                                                 goto sst_bailout;
1969
1970                                         strncat(str, tmpstr, tmplen);
1971                                         cur_len += retlen;
1972                                         str[str_len - 1] = '\0';
1973                                 }
1974                         }
1975                 } else if (info) {
1976                         retlen = snprintf(tmpstr, tmpstrlen," info?:%x", info);
1977
1978                         if ((tmplen = str_len - cur_len -1) < 0)
1979                                 goto sst_bailout;
1980
1981                         strncat(str, tmpstr, tmplen);
1982                         cur_len += retlen;
1983                         str[str_len - 1] = '\0';
1984                 }
1985
1986                 if (sense->extra_len >= 4) {
1987                         if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
1988                                 retlen = snprintf(tmpstr, tmpstrlen, 
1989                                                   " csi:%x,%x,%x,%x",
1990                                                   sense->cmd_spec_info[0],
1991                                                   sense->cmd_spec_info[1],
1992                                                   sense->cmd_spec_info[2],
1993                                                   sense->cmd_spec_info[3]);
1994
1995                                 if ((tmplen = str_len - cur_len -1) < 0)
1996                                         goto sst_bailout;
1997
1998                                 strncat(str, tmpstr, tmplen);
1999                                 cur_len += retlen;
2000                                 str[str_len - 1] = '\0';
2001                         }
2002                 }
2003
2004                 asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
2005                 ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
2006
2007                 if (asc || ascq) {
2008                         const char *desc = scsi_sense_desc(asc, ascq,
2009                                                            &device->inq_data);
2010                         retlen = snprintf(tmpstr, tmpstrlen, 
2011                                           " asc:%x,%x\n%s%s", asc, ascq, 
2012                                           path_str, desc);
2013
2014                         if ((tmplen = str_len - cur_len -1) < 0)
2015                                 goto sst_bailout;
2016
2017                         strncat(str, tmpstr, tmplen);
2018                         cur_len += retlen;
2019                         str[str_len - 1] = '\0';
2020                 }
2021
2022                 if (sense->extra_len >= 7 && sense->fru) {
2023                         retlen = snprintf(tmpstr, tmpstrlen, 
2024                                           " field replaceable unit: %x", 
2025                                           sense->fru);
2026
2027                         if ((tmplen = str_len - cur_len -1) < 0)
2028                                 goto sst_bailout;
2029
2030                         strncat(str, tmpstr, tmplen);
2031                         str[str_len - 1] = '\0';
2032                         cur_len += retlen;
2033                 }
2034
2035                 if ((sense->extra_len >= 10)
2036                  && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
2037                         retlen = snprintf(tmpstr, tmpstrlen, " sks:%x,%x", 
2038                                         sense->sense_key_spec[0],
2039                                         scsi_2btoul(&sense->sense_key_spec[1]));
2040
2041                         if ((tmplen = str_len - cur_len -1) < 0)
2042                                 goto sst_bailout;
2043
2044                         strncat(str, tmpstr, tmplen);
2045                         str[str_len - 1] = '\0';
2046                         cur_len += retlen;
2047                 }
2048                 break;
2049
2050         default:
2051                 retlen = snprintf(tmpstr, tmpstrlen, "error code %d",
2052                                   sense->error_code & SSD_ERRCODE);
2053
2054                 if ((tmplen = str_len - cur_len -1) < 0)
2055                         goto sst_bailout;
2056
2057                 strncat(str, tmpstr, tmplen);
2058                 cur_len += retlen;
2059                 str[str_len - 1] = '\0';
2060
2061                 if (sense->error_code & SSD_ERRCODE_VALID) {
2062                         retlen = snprintf(tmpstr, tmpstrlen, 
2063                                           " at block no. %d (decimal)",
2064                                           info = scsi_4btoul(sense->info));
2065
2066                         if ((tmplen = str_len - cur_len -1) < 0)
2067                                 goto sst_bailout;
2068
2069                         strncat(str, tmpstr, tmplen);
2070                         cur_len += retlen;
2071                         str[str_len - 1] = '\0';
2072                 }
2073         }
2074
2075         retlen = snprintf(tmpstr, tmpstrlen, "\n");
2076
2077         if ((tmplen = str_len - cur_len -1) < 0)
2078                 goto sst_bailout;
2079
2080         strncat(str, tmpstr, tmplen);
2081         cur_len += retlen;
2082         str[str_len - 1] = '\0';
2083
2084 sst_bailout:
2085
2086         return(str);
2087 }
2088
2089 void
2090 scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, 
2091                  FILE *ofile)
2092 {
2093         char str[2048];
2094
2095         if ((device == NULL) || (csio == NULL) || (ofile == NULL))
2096                 return;
2097
2098         fprintf(ofile, "%s", scsi_sense_string(device, csio, str, 2048));
2099 }
2100
2101 #endif /* _KERNEL/!_KERNEL */
2102
2103 #ifdef _KERNEL
2104 int
2105 scsi_interpret_sense(union ccb *ccb, u_int32_t sense_flags,
2106                      u_int32_t *relsim_flags, u_int32_t *openings,
2107                      u_int32_t *timeout, scsi_sense_action error_action)
2108 #else
2109 int
2110 scsi_interpret_sense(struct cam_device *device, union ccb *ccb, 
2111                      u_int32_t sense_flags, u_int32_t *relsim_flags,
2112                      u_int32_t *openings, u_int32_t *timeout,
2113                      scsi_sense_action error_action)
2114 #endif
2115 {
2116         struct     scsi_sense_data *sense;
2117         int        error_code, sense_key, asc, ascq;
2118         int        error;
2119         int        print_sense;
2120         struct     ccb_scsiio *csio;
2121         int        retry;
2122
2123         csio = &ccb->csio;
2124         sense = &csio->sense_data;
2125         scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
2126
2127 #ifdef _KERNEL
2128         if (bootverbose) {
2129                 sense_flags |= SF_PRINT_ALWAYS;
2130                 print_sense = TRUE;
2131         } else if ((sense_flags & SF_NO_PRINT) == 0)
2132 #else
2133         if ((sense_flags & SF_NO_PRINT) == 0)
2134 #endif
2135                 print_sense = TRUE;
2136         else
2137                 print_sense = FALSE;
2138
2139         switch (error_code) {
2140         case SSD_DEFERRED_ERROR:
2141         {
2142                 /*
2143                  * XXX dufault@FreeBSD.org
2144                  * This error doesn't relate to the command associated
2145                  * with this request sense.  A deferred error is an error
2146                  * for a command that has already returned GOOD status
2147                  * (see 8.2.14.2).
2148                  *
2149                  * By my reading of that section, it looks like the current
2150                  * command has been cancelled, we should now clean things up
2151                  * (hopefully recovering any lost data) and then retry the
2152                  * current command.  There are two easy choices, both wrong:
2153                  *
2154                  * 1. Drop through (like we had been doing), thus treating
2155                  *    this as if the error were for the current command and
2156                  *    return and stop the current command.
2157                  * 
2158                  * 2. Issue a retry (like I made it do) thus hopefully
2159                  *    recovering the current transfer, and ignoring the
2160                  *    fact that we've dropped a command.
2161                  *
2162                  * These should probably be handled in a device specific
2163                  * sense handler or punted back up to a user mode daemon
2164                  */
2165
2166                 /* decrement the number of retries */
2167                 retry = ccb->ccb_h.retry_count > 0;
2168                 if (retry)
2169                         ccb->ccb_h.retry_count--;
2170
2171                 error = ERESTART;
2172                 break;
2173         }
2174         case SSD_CURRENT_ERROR:
2175         {
2176                 
2177                 switch (sense_key) {
2178                 case SSD_KEY_NO_SENSE:
2179                         /* Why were we called then? Well don't bail now */
2180                         /* FALLTHROUGH */
2181                 case SSD_KEY_EQUAL:
2182                         /* These should be filtered by the peripheral drivers */
2183                         print_sense = FALSE;
2184                         /* FALLTHROUGH */
2185                 case SSD_KEY_MISCOMPARE:
2186                         /* decrement the number of retries */
2187                         retry = ccb->ccb_h.retry_count > 0;
2188                         if (retry) {
2189                                 error = ERESTART;
2190                                 ccb->ccb_h.retry_count--;
2191                         } else {
2192                                 error = EIO;
2193                         }
2194                 case SSD_KEY_RECOVERED_ERROR:
2195                         error = 0;      /* not an error */
2196                         break;
2197                 case SSD_KEY_ILLEGAL_REQUEST:
2198                         if (((sense_flags & SF_QUIET_IR) != 0)
2199                          && ((sense_flags & SF_PRINT_ALWAYS) == 0))
2200                                 print_sense = FALSE;
2201                         error = EINVAL;
2202                         break;
2203                 case SSD_KEY_NOT_READY:
2204                 case SSD_KEY_DATA_PROTECT:
2205                 case SSD_KEY_VOLUME_OVERFLOW:
2206                 case SSD_KEY_BLANK_CHECK: /* should be filtered out by
2207                                              peripheral drivers */
2208                         retry = ccb->ccb_h.retry_count > 0;
2209                         if (retry) {
2210                                 ccb->ccb_h.retry_count--;
2211                                 error = ERESTART;
2212                                 print_sense = FALSE;
2213                         } else {
2214                                 if (((error_action & SSQ_PRINT_SENSE) == 0)
2215                                  && ((sense_flags & SF_PRINT_ALWAYS) == 0))
2216                                         print_sense = FALSE;
2217
2218                                 error = error_action & SS_ERRMASK;
2219                         }
2220
2221                         break;
2222                 case SSD_KEY_UNIT_ATTENTION:
2223                         /*
2224                          * This should also be filtered out by
2225                          * peripheral drivers since each has a different
2226                          * concept of what it means to invalidate the media.
2227                          */
2228                         if ((sense_flags & SF_RETRY_UA) != 0) {
2229                                 /* don't decrement retry count */
2230                                 error = ERESTART;
2231                                 print_sense = FALSE;
2232                         } else {
2233                                 /* decrement the number of retries */
2234                                 retry = ccb->ccb_h.retry_count > 0;
2235                                 if (retry) {
2236                                         ccb->ccb_h.retry_count--;
2237                                         error = ERESTART;
2238                                         print_sense = FALSE;
2239                                 } else {
2240                                         if (((error_action &
2241                                               SSQ_PRINT_SENSE) == 0)
2242                                          && ((sense_flags &
2243                                               SF_PRINT_ALWAYS) == 0))
2244                                                 print_sense = FALSE;
2245
2246                                         error = error_action & SS_ERRMASK;
2247                                 }
2248                         }
2249                         break;
2250                 case SSD_KEY_ABORTED_COMMAND:
2251                 default:
2252                         /* decrement the number of retries */
2253                         retry = ccb->ccb_h.retry_count > 0;
2254                         if (retry) {
2255                                 ccb->ccb_h.retry_count--;
2256                                 error = ERESTART;
2257                                 print_sense = FALSE;
2258                         } else {
2259                                 if (((error_action & SSQ_PRINT_SENSE) == 0)
2260                                  && ((sense_flags & SF_PRINT_ALWAYS) == 0))
2261                                         print_sense = FALSE;
2262
2263                                 error = error_action & SS_ERRMASK;
2264                         }
2265                         /*
2266                          * Make sure ABORTED COMMAND errors get
2267                          * printed as they're indicative of marginal
2268                          * SCSI busses that people should address.
2269                          */
2270                         if (sense_key == SSD_KEY_ABORTED_COMMAND)
2271                                 print_sense = TRUE;
2272                 }
2273                 break;
2274         }
2275         default:
2276                 /* decrement the number of retries */
2277                 retry = ccb->ccb_h.retry_count > 0;
2278                 if (retry) {
2279                         ccb->ccb_h.retry_count--;
2280                         error = ERESTART;
2281                         print_sense = FALSE;
2282                 } else 
2283                         error = EIO;
2284                 break;
2285         }
2286
2287         if (print_sense) {
2288 #ifdef _KERNEL
2289                 scsi_sense_print(csio);
2290 #else
2291                 scsi_sense_print(device, csio, stdout);
2292 #endif
2293         }
2294         
2295         return (error);
2296 }
2297
2298 /*
2299  * This function currently requires at least 36 bytes, or
2300  * SHORT_INQUIRY_LENGTH, worth of data to function properly.  If this
2301  * function needs more or less data in the future, another length should be
2302  * defined in scsi_all.h to indicate the minimum amount of data necessary
2303  * for this routine to function properly.
2304  */
2305 void
2306 scsi_print_inquiry(struct scsi_inquiry_data *inq_data)
2307 {
2308         u_int8_t type;
2309         char *dtype, *qtype;
2310         char vendor[16], product[48], revision[16], rstr[4];
2311
2312         type = SID_TYPE(inq_data);
2313
2314         /*
2315          * Figure out basic device type and qualifier.
2316          */
2317         if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) {
2318                 qtype = "(vendor-unique qualifier)";
2319         } else {
2320                 switch (SID_QUAL(inq_data)) {
2321                 case SID_QUAL_LU_CONNECTED:
2322                         qtype = "";
2323                         break;
2324
2325                 case SID_QUAL_LU_OFFLINE:
2326                         qtype = "(offline)";
2327                         break;
2328
2329                 case SID_QUAL_RSVD:
2330                         qtype = "(reserved qualifier)";
2331                         break;
2332                 default:
2333                 case SID_QUAL_BAD_LU:
2334                         qtype = "(lun not supported)";
2335                         break;
2336                 }
2337         }
2338
2339         switch (type) {
2340         case T_DIRECT:
2341                 dtype = "Direct Access";
2342                 break;
2343         case T_SEQUENTIAL:
2344                 dtype = "Sequential Access";
2345                 break;
2346         case T_PRINTER:
2347                 dtype = "Printer";
2348                 break;
2349         case T_PROCESSOR:
2350                 dtype = "Processor";
2351                 break;
2352         case T_CDROM:
2353                 dtype = "CD-ROM";
2354                 break;
2355         case T_WORM:
2356                 dtype = "Worm";
2357                 break;
2358         case T_SCANNER:
2359                 dtype = "Scanner";
2360                 break;
2361         case T_OPTICAL:
2362                 dtype = "Optical";
2363                 break;
2364         case T_CHANGER:
2365                 dtype = "Changer";
2366                 break;
2367         case T_COMM:
2368                 dtype = "Communication";
2369                 break;
2370         case T_STORARRAY:
2371                 dtype = "Storage Array";
2372                 break;
2373         case T_ENCLOSURE:
2374                 dtype = "Enclosure Services";
2375                 break;
2376         case T_RBC:
2377                 dtype = "Simplified Direct Access";
2378                 break;
2379         case T_OCRW:
2380                 dtype = "Optical Card Read/Write";
2381                 break;
2382         case T_NODEVICE:
2383                 dtype = "Uninstalled";
2384         default:
2385                 dtype = "unknown";
2386                 break;
2387         }
2388
2389         cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor),
2390                    sizeof(vendor));
2391         cam_strvis(product, inq_data->product, sizeof(inq_data->product),
2392                    sizeof(product));
2393         cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision),
2394                    sizeof(revision));
2395
2396         if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS)
2397                 bcopy("CCS", rstr, 4);
2398         else
2399                 snprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data));
2400         printf("<%s %s %s> %s %s SCSI-%s device %s\n",
2401                vendor, product, revision,
2402                SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed",
2403                dtype, rstr, qtype);
2404 }
2405
2406 /*
2407  * Table of syncrates that don't follow the "divisible by 4"
2408  * rule. This table will be expanded in future SCSI specs.
2409  */
2410 static struct {
2411         u_int period_factor;
2412         u_int period;   /* in 100ths of ns */
2413 } scsi_syncrates[] = {
2414         { 0x08, 625 },  /* FAST-160 */
2415         { 0x09, 1250 }, /* FAST-80 */
2416         { 0x0a, 2500 }, /* FAST-40 40MHz */
2417         { 0x0b, 3030 }, /* FAST-40 33MHz */
2418         { 0x0c, 5000 }  /* FAST-20 */
2419 };
2420
2421 /*
2422  * Return the frequency in kHz corresponding to the given
2423  * sync period factor.
2424  */
2425 u_int
2426 scsi_calc_syncsrate(u_int period_factor)
2427 {
2428         int i;
2429         int num_syncrates;
2430
2431         num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2432         /* See if the period is in the "exception" table */
2433         for (i = 0; i < num_syncrates; i++) {
2434
2435                 if (period_factor == scsi_syncrates[i].period_factor) {
2436                         /* Period in kHz */
2437                         return (100000000 / scsi_syncrates[i].period);
2438                 }
2439         }
2440
2441         /*
2442          * Wasn't in the table, so use the standard
2443          * 4 times conversion.
2444          */
2445         return (10000000 / (period_factor * 4 * 10));
2446 }
2447
2448 /*
2449  * Return the SCSI sync parameter that corresponsd to
2450  * the passed in period in 10ths of ns.
2451  */
2452 u_int
2453 scsi_calc_syncparam(u_int period)
2454 {
2455         int i;
2456         int num_syncrates;
2457
2458         if (period == 0)
2459                 return (~0);    /* Async */
2460
2461         /* Adjust for exception table being in 100ths. */
2462         period *= 10;
2463         num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2464         /* See if the period is in the "exception" table */
2465         for (i = 0; i < num_syncrates; i++) {
2466
2467                 if (period <= scsi_syncrates[i].period) {
2468                         /* Period in 100ths of ns */
2469                         return (scsi_syncrates[i].period_factor);
2470                 }
2471         }
2472
2473         /*
2474          * Wasn't in the table, so use the standard
2475          * 1/4 period in ns conversion.
2476          */
2477         return (period/400);
2478 }
2479
2480 void
2481 scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
2482                      void (*cbfcnp)(struct cam_periph *, union ccb *),
2483                      u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout)
2484 {
2485         struct scsi_test_unit_ready *scsi_cmd;
2486
2487         cam_fill_csio(csio,
2488                       retries,
2489                       cbfcnp,
2490                       CAM_DIR_NONE,
2491                       tag_action,
2492                       /*data_ptr*/NULL,
2493                       /*dxfer_len*/0,
2494                       sense_len,
2495                       sizeof(*scsi_cmd),
2496                       timeout);
2497
2498         scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes;
2499         bzero(scsi_cmd, sizeof(*scsi_cmd));
2500         scsi_cmd->opcode = TEST_UNIT_READY;
2501 }
2502
2503 void
2504 scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
2505                    void (*cbfcnp)(struct cam_periph *, union ccb *),
2506                    void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action,
2507                    u_int8_t sense_len, u_int32_t timeout)
2508 {
2509         struct scsi_request_sense *scsi_cmd;
2510
2511         cam_fill_csio(csio,
2512                       retries,
2513                       cbfcnp,
2514                       CAM_DIR_IN,
2515                       tag_action,
2516                       data_ptr,
2517                       dxfer_len,
2518                       sense_len,
2519                       sizeof(*scsi_cmd),
2520                       timeout);
2521
2522         scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes;
2523         bzero(scsi_cmd, sizeof(*scsi_cmd));
2524         scsi_cmd->opcode = REQUEST_SENSE;
2525 }
2526
2527 void
2528 scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
2529              void (*cbfcnp)(struct cam_periph *, union ccb *),
2530              u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len,
2531              int evpd, u_int8_t page_code, u_int8_t sense_len,
2532              u_int32_t timeout)
2533 {
2534         struct scsi_inquiry *scsi_cmd;
2535
2536         cam_fill_csio(csio,
2537                       retries,
2538                       cbfcnp,
2539                       /*flags*/CAM_DIR_IN,
2540                       tag_action,
2541                       /*data_ptr*/inq_buf,
2542                       /*dxfer_len*/inq_len,
2543                       sense_len,
2544                       sizeof(*scsi_cmd),
2545                       timeout);
2546
2547         scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes;
2548         bzero(scsi_cmd, sizeof(*scsi_cmd));
2549         scsi_cmd->opcode = INQUIRY;
2550         if (evpd) {
2551                 scsi_cmd->byte2 |= SI_EVPD;
2552                 scsi_cmd->page_code = page_code;                
2553         }
2554         /*
2555          * A 'transfer units' count of 256 is coded as
2556          * zero for all commands with a single byte count
2557          * field. 
2558          */
2559         if (inq_len == 256)
2560                 inq_len = 0;
2561         scsi_cmd->length = inq_len;
2562 }
2563
2564 void
2565 scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
2566                 void (*cbfcnp)(struct cam_periph *, union ccb *),
2567                 u_int8_t tag_action, int dbd, u_int8_t page_code,
2568                 u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2569                 u_int8_t sense_len, u_int32_t timeout)
2570 {
2571         u_int8_t cdb_len;
2572
2573         /*
2574          * Use the smallest possible command to perform the operation.
2575          */
2576         if (param_len < 256) {
2577                 /*
2578                  * We can fit in a 6 byte cdb.
2579                  */
2580                 struct scsi_mode_sense_6 *scsi_cmd;
2581
2582                 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2583                 bzero(scsi_cmd, sizeof(*scsi_cmd));
2584                 scsi_cmd->opcode = MODE_SENSE_6;
2585                 if (dbd != 0)
2586                         scsi_cmd->byte2 |= SMS_DBD;
2587                 scsi_cmd->page = page_code | page;
2588                 scsi_cmd->length = param_len;
2589                 cdb_len = sizeof(*scsi_cmd);
2590         } else {
2591                 /*
2592                  * Need a 10 byte cdb.
2593                  */
2594                 struct scsi_mode_sense_10 *scsi_cmd;
2595
2596                 scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes;
2597                 bzero(scsi_cmd, sizeof(*scsi_cmd));
2598                 scsi_cmd->opcode = MODE_SENSE_10;
2599                 if (dbd != 0)
2600                         scsi_cmd->byte2 |= SMS_DBD;
2601                 scsi_cmd->page = page_code | page;
2602                 scsi_ulto2b(param_len, scsi_cmd->length);
2603                 cdb_len = sizeof(*scsi_cmd);
2604         }
2605         cam_fill_csio(csio,
2606                       retries,
2607                       cbfcnp,
2608                       CAM_DIR_IN,
2609                       tag_action,
2610                       param_buf,
2611                       param_len,
2612                       sense_len,
2613                       cdb_len,
2614                       timeout);
2615 }
2616
2617 void
2618 scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
2619                  void (*cbfcnp)(struct cam_periph *, union ccb *),
2620                  u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2621                  u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2622                  u_int32_t timeout)
2623 {
2624         u_int8_t cdb_len;
2625
2626         /*
2627          * Use the smallest possible command to perform the operation.
2628          */
2629         if (param_len < 256) {
2630                 /*
2631                  * We can fit in a 6 byte cdb.
2632                  */
2633                 struct scsi_mode_select_6 *scsi_cmd;
2634
2635                 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2636                 bzero(scsi_cmd, sizeof(*scsi_cmd));
2637                 scsi_cmd->opcode = MODE_SELECT_6;
2638                 if (scsi_page_fmt != 0)
2639                         scsi_cmd->byte2 |= SMS_PF;
2640                 if (save_pages != 0)
2641                         scsi_cmd->byte2 |= SMS_SP;
2642                 scsi_cmd->length = param_len;
2643                 cdb_len = sizeof(*scsi_cmd);
2644         } else {
2645                 /*
2646                  * Need a 10 byte cdb.
2647                  */
2648                 struct scsi_mode_select_10 *scsi_cmd;
2649
2650                 scsi_cmd =
2651                     (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes;
2652                 bzero(scsi_cmd, sizeof(*scsi_cmd));
2653                 scsi_cmd->opcode = MODE_SELECT_10;
2654                 if (scsi_page_fmt != 0)
2655                         scsi_cmd->byte2 |= SMS_PF;
2656                 if (save_pages != 0)
2657                         scsi_cmd->byte2 |= SMS_SP;
2658                 scsi_ulto2b(param_len, scsi_cmd->length);
2659                 cdb_len = sizeof(*scsi_cmd);
2660         }
2661         cam_fill_csio(csio,
2662                       retries,
2663                       cbfcnp,
2664                       CAM_DIR_OUT,
2665                       tag_action,
2666                       param_buf,
2667                       param_len,
2668                       sense_len,
2669                       cdb_len,
2670                       timeout);
2671 }
2672
2673
2674 /* XXX allow specification of address and PMI bit and LBA */
2675 void
2676 scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
2677                    void (*cbfcnp)(struct cam_periph *, union ccb *),
2678                    u_int8_t tag_action,
2679                    struct scsi_read_capacity_data *rcap_buf,
2680                    u_int8_t sense_len, u_int32_t timeout)
2681 {
2682         struct scsi_read_capacity *scsi_cmd;
2683
2684         cam_fill_csio(csio,
2685                       retries,
2686                       cbfcnp,
2687                       /*flags*/CAM_DIR_IN,
2688                       tag_action,
2689                       /*data_ptr*/(u_int8_t *)rcap_buf,
2690                       /*dxfer_len*/sizeof(*rcap_buf),
2691                       sense_len,
2692                       sizeof(*scsi_cmd),
2693                       timeout);
2694
2695         scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes;
2696         bzero(scsi_cmd, sizeof(*scsi_cmd));
2697         scsi_cmd->opcode = READ_CAPACITY;
2698 }
2699
2700 /*
2701  * Prevent or allow the user to remove the media
2702  */
2703 void
2704 scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
2705              void (*cbfcnp)(struct cam_periph *, union ccb *),
2706              u_int8_t tag_action, u_int8_t action,
2707              u_int8_t sense_len, u_int32_t timeout)
2708 {
2709         struct scsi_prevent *scsi_cmd;
2710
2711         cam_fill_csio(csio,
2712                       retries,
2713                       cbfcnp,
2714                       /*flags*/CAM_DIR_NONE,
2715                       tag_action,
2716                       /*data_ptr*/NULL,
2717                       /*dxfer_len*/0,
2718                       sense_len,
2719                       sizeof(*scsi_cmd),
2720                       timeout);
2721
2722         scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes;
2723         bzero(scsi_cmd, sizeof(*scsi_cmd));
2724         scsi_cmd->opcode = PREVENT_ALLOW;
2725         scsi_cmd->how = action;
2726 }
2727
2728 /*
2729  * Syncronize the media to the contents of the cache for
2730  * the given lba/count pair.  Specifying 0/0 means sync
2731  * the whole cache.
2732  */
2733 void
2734 scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries,
2735                        void (*cbfcnp)(struct cam_periph *, union ccb *),
2736                        u_int8_t tag_action, u_int32_t begin_lba,
2737                        u_int16_t lb_count, u_int8_t sense_len,
2738                        u_int32_t timeout)
2739 {
2740         struct scsi_sync_cache *scsi_cmd;
2741
2742         cam_fill_csio(csio,
2743                       retries,
2744                       cbfcnp,
2745                       /*flags*/CAM_DIR_NONE,
2746                       tag_action,
2747                       /*data_ptr*/NULL,
2748                       /*dxfer_len*/0,
2749                       sense_len,
2750                       sizeof(*scsi_cmd),
2751                       timeout);
2752
2753         scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes;
2754         bzero(scsi_cmd, sizeof(*scsi_cmd));
2755         scsi_cmd->opcode = SYNCHRONIZE_CACHE;
2756         scsi_ulto4b(begin_lba, scsi_cmd->begin_lba);
2757         scsi_ulto2b(lb_count, scsi_cmd->lb_count);
2758 }
2759
2760 void
2761 scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
2762                 void (*cbfcnp)(struct cam_periph *, union ccb *),
2763                 u_int8_t tag_action, int readop, u_int8_t byte2,
2764                 int minimum_cmd_size, u_int32_t lba, u_int32_t block_count,
2765                 u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
2766                 u_int32_t timeout)
2767 {
2768         u_int8_t cdb_len;
2769         /*
2770          * Use the smallest possible command to perform the operation
2771          * as some legacy hardware does not support the 10 byte
2772          * commands.  If any of the lower 5 bits in byte2 is set, we have
2773          * to go with a larger command.
2774          *
2775          */
2776         if ((minimum_cmd_size < 10)
2777          && ((lba & 0x1fffff) == lba)
2778          && ((block_count & 0xff) == block_count)
2779          && ((byte2 & 0xe0) == 0)) {
2780                 /*
2781                  * We can fit in a 6 byte cdb.
2782                  */
2783                 struct scsi_rw_6 *scsi_cmd;
2784
2785                 scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
2786                 scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2787                 scsi_ulto3b(lba, scsi_cmd->addr);
2788                 scsi_cmd->length = block_count & 0xff;
2789                 scsi_cmd->control = 0;
2790                 cdb_len = sizeof(*scsi_cmd);
2791
2792                 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2793                           ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0],
2794                            scsi_cmd->addr[1], scsi_cmd->addr[2],
2795                            scsi_cmd->length, dxfer_len));
2796         } else if ((minimum_cmd_size < 12)
2797                 && ((block_count & 0xffff) == block_count)) {
2798                 /*
2799                  * Need a 10 byte cdb.
2800                  */
2801                 struct scsi_rw_10 *scsi_cmd;
2802
2803                 scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
2804                 scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2805                 scsi_cmd->byte2 = byte2;
2806                 scsi_ulto4b(lba, scsi_cmd->addr);
2807                 scsi_cmd->reserved = 0;
2808                 scsi_ulto2b(block_count, scsi_cmd->length);
2809                 scsi_cmd->control = 0;
2810                 cdb_len = sizeof(*scsi_cmd);
2811
2812                 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2813                           ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
2814                            scsi_cmd->addr[1], scsi_cmd->addr[2],
2815                            scsi_cmd->addr[3], scsi_cmd->length[0],
2816                            scsi_cmd->length[1], dxfer_len));
2817         } else {
2818                 /* 
2819                  * The block count is too big for a 10 byte CDB, use a 12
2820                  * byte CDB.  READ/WRITE(12) are currently only defined for
2821                  * optical devices.
2822                  */
2823                 struct scsi_rw_12 *scsi_cmd;
2824
2825                 scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
2826                 scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2827                 scsi_cmd->byte2 = byte2;
2828                 scsi_ulto4b(lba, scsi_cmd->addr);
2829                 scsi_cmd->reserved = 0;
2830                 scsi_ulto4b(block_count, scsi_cmd->length);
2831                 scsi_cmd->control = 0;
2832                 cdb_len = sizeof(*scsi_cmd);
2833
2834                 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2835                           ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0],
2836                            scsi_cmd->addr[1], scsi_cmd->addr[2],
2837                            scsi_cmd->addr[3], scsi_cmd->length[0],
2838                            scsi_cmd->length[1], scsi_cmd->length[2],
2839                            scsi_cmd->length[3], dxfer_len));
2840         }
2841         cam_fill_csio(csio,
2842                       retries,
2843                       cbfcnp,
2844                       /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
2845                       tag_action,
2846                       data_ptr,
2847                       dxfer_len,
2848                       sense_len,
2849                       cdb_len,
2850                       timeout);
2851 }
2852
2853 void 
2854 scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
2855                 void (*cbfcnp)(struct cam_periph *, union ccb *),
2856                 u_int8_t tag_action, int start, int load_eject,
2857                 int immediate, u_int8_t sense_len, u_int32_t timeout)
2858 {
2859         struct scsi_start_stop_unit *scsi_cmd;
2860         int extra_flags = 0;
2861
2862         scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes;
2863         bzero(scsi_cmd, sizeof(*scsi_cmd));
2864         scsi_cmd->opcode = START_STOP_UNIT;
2865         if (start != 0) {
2866                 scsi_cmd->how |= SSS_START;
2867                 /* it takes a lot of power to start a drive */
2868                 extra_flags |= CAM_HIGH_POWER;
2869         }
2870         if (load_eject != 0)
2871                 scsi_cmd->how |= SSS_LOEJ;
2872         if (immediate != 0)
2873                 scsi_cmd->byte2 |= SSS_IMMED;
2874
2875         cam_fill_csio(csio,
2876                       retries,
2877                       cbfcnp,
2878                       /*flags*/CAM_DIR_NONE | extra_flags,
2879                       tag_action,
2880                       /*data_ptr*/NULL,
2881                       /*dxfer_len*/0,
2882                       sense_len,
2883                       sizeof(*scsi_cmd),
2884                       timeout);
2885
2886 }
2887
2888
2889 /*      
2890  * Try make as good a match as possible with
2891  * available sub drivers
2892  */
2893 int
2894 scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2895 {
2896         struct scsi_inquiry_pattern *entry;
2897         struct scsi_inquiry_data *inq;
2898  
2899         entry = (struct scsi_inquiry_pattern *)table_entry;
2900         inq = (struct scsi_inquiry_data *)inqbuffer;
2901
2902         if (((SID_TYPE(inq) == entry->type)
2903           || (entry->type == T_ANY))
2904          && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2905                                    : entry->media_type & SIP_MEDIA_FIXED)
2906          && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2907          && (cam_strmatch(inq->product, entry->product,
2908                           sizeof(inq->product)) == 0)
2909          && (cam_strmatch(inq->revision, entry->revision,
2910                           sizeof(inq->revision)) == 0)) {
2911                 return (0);
2912         }
2913         return (-1);
2914 }
2915
2916 /*      
2917  * Try make as good a match as possible with
2918  * available sub drivers
2919  */
2920 int
2921 scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2922 {
2923         struct scsi_static_inquiry_pattern *entry;
2924         struct scsi_inquiry_data *inq;
2925  
2926         entry = (struct scsi_static_inquiry_pattern *)table_entry;
2927         inq = (struct scsi_inquiry_data *)inqbuffer;
2928
2929         if (((SID_TYPE(inq) == entry->type)
2930           || (entry->type == T_ANY))
2931          && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2932                                    : entry->media_type & SIP_MEDIA_FIXED)
2933          && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2934          && (cam_strmatch(inq->product, entry->product,
2935                           sizeof(inq->product)) == 0)
2936          && (cam_strmatch(inq->revision, entry->revision,
2937                           sizeof(inq->revision)) == 0)) {
2938                 return (0);
2939         }
2940         return (-1);
2941 }