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