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