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