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