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