xref: /freebsd/sys/cam/scsi/scsi_all.c (revision 2ad872c5794e4c26fdf6ed219ad3f09ca0d5304a)
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  *	$Id: scsi_all.c,v 1.8 1998/12/06 00:05:47 mjacob Exp $
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 void
2294 scsi_print_inquiry(struct scsi_inquiry_data *inq_data)
2295 {
2296 	u_int8_t type;
2297 	char *dtype, *qtype;
2298 	char vendor[16], product[48], revision[16], rstr[4];
2299 
2300 	type = SID_TYPE(inq_data);
2301 
2302 	/*
2303 	 * Figure out basic device type and qualifier.
2304 	 */
2305 	if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) {
2306 		qtype = "(vendor-unique qualifier)";
2307 	} else {
2308 		switch (SID_QUAL(inq_data)) {
2309 		case SID_QUAL_LU_CONNECTED:
2310 			qtype = "";
2311 			break;
2312 
2313 		case SID_QUAL_LU_OFFLINE:
2314 			qtype = "(offline)";
2315 			break;
2316 
2317 		case SID_QUAL_RSVD:
2318 			qtype = "(reserved qualifier)";
2319 			break;
2320 		default:
2321 		case SID_QUAL_BAD_LU:
2322 			qtype = "(lun not supported)";
2323 			break;
2324 		}
2325 	}
2326 
2327 	switch (type) {
2328 	case T_DIRECT:
2329 		dtype = "Direct Access";
2330 		break;
2331 	case T_SEQUENTIAL:
2332 		dtype = "Sequential Access";
2333 		break;
2334 	case T_PRINTER:
2335 		dtype = "Printer";
2336 		break;
2337 	case T_PROCESSOR:
2338 		dtype = "Processor";
2339 		break;
2340 	case T_CDROM:
2341 		dtype = "CD-ROM";
2342 		break;
2343 	case T_WORM:
2344 		dtype = "Worm";
2345 		break;
2346 	case T_SCANNER:
2347 		dtype = "Scanner";
2348 		break;
2349 	case T_OPTICAL:
2350 		dtype = "Optical";
2351 		break;
2352 	case T_CHANGER:
2353 		dtype = "Changer";
2354 		break;
2355 	case T_COMM:
2356 		dtype = "Communication";
2357 		break;
2358 	case T_STORARRAY:
2359 		dtype = "Storage Arrray";
2360 		break;
2361 	case T_ENCLOSURE:
2362 		dtype = "Enclosure Services";
2363 		break;
2364 	case T_NODEVICE:
2365 		dtype = "Uninstalled";
2366 	default:
2367 		dtype = "unknown";
2368 		break;
2369 	}
2370 
2371 	cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor),
2372 		   sizeof(vendor));
2373 	cam_strvis(product, inq_data->product, sizeof(inq_data->product),
2374 		   sizeof(product));
2375 	cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision),
2376 		   sizeof(revision));
2377 
2378 	if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS)
2379 		bcopy("CCS", rstr, 4);
2380 	else
2381 		snprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data));
2382 	printf("<%s %s %s> %s %s SCSI-%s device %s\n",
2383 	       vendor, product, revision,
2384 	       SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed",
2385 	       dtype, rstr, qtype);
2386 }
2387 
2388 /*
2389  * Table of syncrates that don't follow the "divisible by 4"
2390  * rule. This table will be expanded in future SCSI specs.
2391  * I believe that FAST-40 has already been defined...
2392  */
2393 static struct {
2394         u_int period_factor;
2395         u_int period;	/* in 10ths of ns */
2396 } scsi_syncrates[] = {
2397         { 0x0a, 250 },
2398         { 0x0b, 303 },
2399         { 0x0c, 500 }
2400 };
2401 
2402 /*
2403  * Return the frequency in kHz corresponding to the given
2404  * sync period factor.
2405  */
2406 u_int
2407 scsi_calc_syncsrate(u_int period_factor)
2408 {
2409 	int i;
2410 	int num_syncrates;
2411 
2412 	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2413 	/* See if the period is in the "exception" table */
2414 	for (i = 0; i < num_syncrates; i++) {
2415 
2416 		if (period_factor == scsi_syncrates[i].period_factor) {
2417 			/* Period in kHz */
2418 			return (10000000 / scsi_syncrates[i].period);
2419 		}
2420 	}
2421 
2422 	/*
2423 	 * Wasn't in the table, so use the standard
2424 	 * 4 times conversion.
2425 	 */
2426 	return (10000000 / (period_factor * 4 * 10));
2427 }
2428 
2429 /*
2430  * Return the SCSI sync parameter that corresponsd to
2431  * the passed in period in 10ths of ns.
2432  */
2433 u_int
2434 scsi_calc_syncparam(u_int period)
2435 {
2436 	int i;
2437 	int num_syncrates;
2438 
2439 	if (period == 0)
2440 		return (~0);	/* Async */
2441 
2442 	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2443 	/* See if the period is in the "exception" table */
2444 	for (i = 0; i < num_syncrates; i++) {
2445 
2446 		if (period <= scsi_syncrates[i].period) {
2447 			/* Period in kHz */
2448 			return (scsi_syncrates[i].period_factor);
2449 		}
2450 	}
2451 
2452 	/*
2453 	 * Wasn't in the table, so use the standard
2454 	 * 1/4 period in ns conversion.
2455 	 */
2456 	return (period/40);
2457 }
2458 
2459 void
2460 scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
2461 		     void (*cbfcnp)(struct cam_periph *, union ccb *),
2462 		     u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout)
2463 {
2464 	struct scsi_test_unit_ready *scsi_cmd;
2465 
2466 	cam_fill_csio(csio,
2467 		      retries,
2468 		      cbfcnp,
2469 		      CAM_DIR_NONE,
2470 		      tag_action,
2471 		      /*data_ptr*/NULL,
2472 		      /*dxfer_len*/0,
2473 		      sense_len,
2474 		      sizeof(*scsi_cmd),
2475 		      timeout);
2476 
2477 	scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes;
2478 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2479 	scsi_cmd->opcode = TEST_UNIT_READY;
2480 }
2481 
2482 void
2483 scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
2484 		   void (*cbfcnp)(struct cam_periph *, union ccb *),
2485 		   void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action,
2486 		   u_int8_t sense_len, u_int32_t timeout)
2487 {
2488 	struct scsi_request_sense *scsi_cmd;
2489 
2490 	cam_fill_csio(csio,
2491 		      retries,
2492 		      cbfcnp,
2493 		      CAM_DIR_IN,
2494 		      tag_action,
2495 		      data_ptr,
2496 		      dxfer_len,
2497 		      sense_len,
2498 		      sizeof(*scsi_cmd),
2499 		      timeout);
2500 
2501 	scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes;
2502 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2503 	scsi_cmd->opcode = REQUEST_SENSE;
2504 }
2505 
2506 void
2507 scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
2508 	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2509 	     u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len,
2510 	     int evpd, u_int8_t page_code, u_int8_t sense_len,
2511 	     u_int32_t timeout)
2512 {
2513 	struct scsi_inquiry *scsi_cmd;
2514 
2515 	cam_fill_csio(csio,
2516 		      retries,
2517 		      cbfcnp,
2518 		      /*flags*/CAM_DIR_IN,
2519 		      tag_action,
2520 		      /*data_ptr*/inq_buf,
2521 		      /*dxfer_len*/inq_len,
2522 		      sense_len,
2523 		      sizeof(*scsi_cmd),
2524 		      timeout);
2525 
2526 	scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes;
2527 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2528 	scsi_cmd->opcode = INQUIRY;
2529 	if (evpd) {
2530 		scsi_cmd->byte2 |= SI_EVPD;
2531 		scsi_cmd->page_code = page_code;
2532 	}
2533 	scsi_cmd->length = inq_len;
2534 }
2535 
2536 void
2537 scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
2538 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2539 		u_int8_t tag_action, int dbd, u_int8_t page_code,
2540 		u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2541 		u_int8_t sense_len, u_int32_t timeout)
2542 {
2543 	u_int8_t cdb_len;
2544 
2545 	/*
2546 	 * Use the smallest possible command to perform the operation.
2547 	 */
2548 	if (param_len < 256) {
2549 		/*
2550 		 * We can fit in a 6 byte cdb.
2551 		 */
2552 		struct scsi_mode_sense_6 *scsi_cmd;
2553 
2554 		scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2555 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2556 		scsi_cmd->opcode = MODE_SENSE_6;
2557 		if (dbd != 0)
2558 			scsi_cmd->byte2 |= SMS_DBD;
2559 		scsi_cmd->page = page_code | page;
2560 		scsi_cmd->length = param_len;
2561 		cdb_len = sizeof(*scsi_cmd);
2562 	} else {
2563 		/*
2564 		 * Need a 10 byte cdb.
2565 		 */
2566 		struct scsi_mode_sense_10 *scsi_cmd;
2567 
2568 		scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes;
2569 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2570 		scsi_cmd->opcode = MODE_SENSE_10;
2571 		if (dbd != 0)
2572 			scsi_cmd->byte2 |= SMS_DBD;
2573 		scsi_cmd->page = page_code | page;
2574 		scsi_ulto2b(param_len, scsi_cmd->length);
2575 		cdb_len = sizeof(*scsi_cmd);
2576 	}
2577 	cam_fill_csio(csio,
2578 		      retries,
2579 		      cbfcnp,
2580 		      CAM_DIR_IN,
2581 		      tag_action,
2582 		      param_buf,
2583 		      param_len,
2584 		      sense_len,
2585 		      cdb_len,
2586 		      timeout);
2587 }
2588 
2589 void
2590 scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
2591 		 void (*cbfcnp)(struct cam_periph *, union ccb *),
2592 		 u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2593 		 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2594 		 u_int32_t timeout)
2595 {
2596 	u_int8_t cdb_len;
2597 
2598 	/*
2599 	 * Use the smallest possible command to perform the operation.
2600 	 */
2601 	if (param_len < 256) {
2602 		/*
2603 		 * We can fit in a 6 byte cdb.
2604 		 */
2605 		struct scsi_mode_select_6 *scsi_cmd;
2606 
2607 		scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2608 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2609 		scsi_cmd->opcode = MODE_SELECT_6;
2610 		if (scsi_page_fmt != 0)
2611 			scsi_cmd->byte2 |= SMS_PF;
2612 		if (save_pages != 0)
2613 			scsi_cmd->byte2 |= SMS_SP;
2614 		scsi_cmd->length = param_len;
2615 		cdb_len = sizeof(*scsi_cmd);
2616 	} else {
2617 		/*
2618 		 * Need a 10 byte cdb.
2619 		 */
2620 		struct scsi_mode_select_10 *scsi_cmd;
2621 
2622 		scsi_cmd =
2623 		    (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes;
2624 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2625 		scsi_cmd->opcode = MODE_SELECT_10;
2626 		if (scsi_page_fmt != 0)
2627 			scsi_cmd->byte2 |= SMS_PF;
2628 		if (save_pages != 0)
2629 			scsi_cmd->byte2 |= SMS_SP;
2630 		scsi_ulto2b(param_len, scsi_cmd->length);
2631 		cdb_len = sizeof(*scsi_cmd);
2632 	}
2633 	cam_fill_csio(csio,
2634 		      retries,
2635 		      cbfcnp,
2636 		      CAM_DIR_OUT,
2637 		      tag_action,
2638 		      param_buf,
2639 		      param_len,
2640 		      sense_len,
2641 		      cdb_len,
2642 		      timeout);
2643 }
2644 
2645 
2646 /* XXX allow specification of address and PMI bit and LBA */
2647 void
2648 scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
2649 		   void (*cbfcnp)(struct cam_periph *, union ccb *),
2650 		   u_int8_t tag_action,
2651 		   struct scsi_read_capacity_data *rcap_buf,
2652 		   u_int8_t sense_len, u_int32_t timeout)
2653 {
2654 	struct scsi_read_capacity *scsi_cmd;
2655 
2656 	cam_fill_csio(csio,
2657 		      retries,
2658 		      cbfcnp,
2659 		      /*flags*/CAM_DIR_IN,
2660 		      tag_action,
2661 		      /*data_ptr*/(u_int8_t *)rcap_buf,
2662 		      /*dxfer_len*/sizeof(*rcap_buf),
2663 		      sense_len,
2664 		      sizeof(*scsi_cmd),
2665 		      timeout);
2666 
2667 	scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes;
2668 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2669 	scsi_cmd->opcode = READ_CAPACITY;
2670 }
2671 
2672 /*
2673  * Prevent or allow the user to remove the media
2674  */
2675 void
2676 scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
2677 	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2678 	     u_int8_t tag_action, u_int8_t action,
2679 	     u_int8_t sense_len, u_int32_t timeout)
2680 {
2681 	struct scsi_prevent *scsi_cmd;
2682 
2683 	cam_fill_csio(csio,
2684 		      retries,
2685 		      cbfcnp,
2686 		      /*flags*/CAM_DIR_NONE,
2687 		      tag_action,
2688 		      /*data_ptr*/NULL,
2689 		      /*dxfer_len*/0,
2690 		      sense_len,
2691 		      sizeof(*scsi_cmd),
2692 		      timeout);
2693 
2694 	scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes;
2695 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2696 	scsi_cmd->opcode = PREVENT_ALLOW;
2697 	scsi_cmd->how = action;
2698 }
2699 
2700 /*
2701  * Syncronize the media to the contents of the cache for
2702  * the given lba/count pair.  Specifying 0/0 means sync
2703  * the whole cache.
2704  */
2705 void
2706 scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries,
2707 		       void (*cbfcnp)(struct cam_periph *, union ccb *),
2708 		       u_int8_t tag_action, u_int32_t begin_lba,
2709 		       u_int16_t lb_count, u_int8_t sense_len,
2710 		       u_int32_t timeout)
2711 {
2712 	struct scsi_sync_cache *scsi_cmd;
2713 
2714 	cam_fill_csio(csio,
2715 		      retries,
2716 		      cbfcnp,
2717 		      /*flags*/CAM_DIR_NONE,
2718 		      tag_action,
2719 		      /*data_ptr*/NULL,
2720 		      /*dxfer_len*/0,
2721 		      sense_len,
2722 		      sizeof(*scsi_cmd),
2723 		      timeout);
2724 
2725 	scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes;
2726 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2727 	scsi_cmd->opcode = SYNCHRONIZE_CACHE;
2728 	scsi_ulto4b(begin_lba, scsi_cmd->begin_lba);
2729 	scsi_ulto2b(lb_count, scsi_cmd->lb_count);
2730 }
2731 
2732 void
2733 scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
2734 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2735 		u_int8_t tag_action, int readop, u_int8_t byte2,
2736 		int minimum_cmd_size, u_int32_t lba, u_int32_t block_count,
2737 		u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
2738 		u_int32_t timeout)
2739 {
2740 	u_int8_t cdb_len;
2741 	/*
2742 	 * Use the smallest possible command to perform the operation
2743 	 * as some legacy hardware does not support the 10 byte
2744 	 * commands.  If any of the lower 5 bits in byte2 is set, we have
2745 	 * to go with a larger command.
2746 	 *
2747 	 */
2748 	if ((minimum_cmd_size < 10)
2749 	 && ((lba & 0x1fffff) == lba)
2750 	 && ((block_count & 0xff) == block_count)
2751 	 && ((byte2 & 0xe0) == 0)) {
2752 		/*
2753 		 * We can fit in a 6 byte cdb.
2754 		 */
2755 		struct scsi_rw_6 *scsi_cmd;
2756 
2757 		scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
2758 		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2759 		scsi_ulto3b(lba, scsi_cmd->addr);
2760 		scsi_cmd->length = block_count & 0xff;
2761 		scsi_cmd->control = 0;
2762 		cdb_len = sizeof(*scsi_cmd);
2763 
2764 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2765 			  ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0],
2766 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2767 			   scsi_cmd->length, dxfer_len));
2768 	} else if ((minimum_cmd_size < 12)
2769 		&& ((block_count & 0xffff) == block_count)) {
2770 		/*
2771 		 * Need a 10 byte cdb.
2772 		 */
2773 		struct scsi_rw_10 *scsi_cmd;
2774 
2775 		scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
2776 		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2777 		scsi_cmd->byte2 = byte2;
2778 		scsi_ulto4b(lba, scsi_cmd->addr);
2779 		scsi_cmd->reserved = 0;
2780 		scsi_ulto2b(block_count, scsi_cmd->length);
2781 		scsi_cmd->control = 0;
2782 		cdb_len = sizeof(*scsi_cmd);
2783 
2784 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2785 			  ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
2786 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2787 			   scsi_cmd->addr[3], scsi_cmd->length[0],
2788 			   scsi_cmd->length[1], dxfer_len));
2789 	} else {
2790 		/*
2791 		 * The block count is too big for a 10 byte CDB, use a 12
2792 		 * byte CDB.  READ/WRITE(12) are currently only defined for
2793 		 * optical devices.
2794 		 */
2795 		struct scsi_rw_12 *scsi_cmd;
2796 
2797 		scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
2798 		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2799 		scsi_cmd->byte2 = byte2;
2800 		scsi_ulto4b(lba, scsi_cmd->addr);
2801 		scsi_cmd->reserved = 0;
2802 		scsi_ulto4b(block_count, scsi_cmd->length);
2803 		scsi_cmd->control = 0;
2804 		cdb_len = sizeof(*scsi_cmd);
2805 
2806 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2807 			  ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0],
2808 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2809 			   scsi_cmd->addr[3], scsi_cmd->length[0],
2810 			   scsi_cmd->length[1], scsi_cmd->length[2],
2811 			   scsi_cmd->length[3], dxfer_len));
2812 	}
2813 	cam_fill_csio(csio,
2814 		      retries,
2815 		      cbfcnp,
2816 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
2817 		      tag_action,
2818 		      data_ptr,
2819 		      dxfer_len,
2820 		      sense_len,
2821 		      cdb_len,
2822 		      timeout);
2823 }
2824 
2825 void
2826 scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
2827 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2828 		u_int8_t tag_action, int start, int load_eject,
2829 		int immediate, u_int8_t sense_len, u_int32_t timeout)
2830 {
2831 	struct scsi_start_stop_unit *scsi_cmd;
2832 	int extra_flags = 0;
2833 
2834 	scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes;
2835 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2836 	scsi_cmd->opcode = START_STOP_UNIT;
2837 	if (start != 0) {
2838 		scsi_cmd->how |= SSS_START;
2839 		/* it takes a lot of power to start a drive */
2840 		extra_flags |= CAM_HIGH_POWER;
2841 	}
2842 	if (load_eject != 0)
2843 		scsi_cmd->how |= SSS_LOEJ;
2844 	if (immediate != 0)
2845 		scsi_cmd->byte2 |= SSS_IMMED;
2846 
2847 	cam_fill_csio(csio,
2848 		      retries,
2849 		      cbfcnp,
2850 		      /*flags*/CAM_DIR_NONE | extra_flags,
2851 		      tag_action,
2852 		      /*data_ptr*/NULL,
2853 		      /*dxfer_len*/0,
2854 		      sense_len,
2855 		      sizeof(*scsi_cmd),
2856 		      timeout);
2857 
2858 }
2859 
2860 
2861 /*
2862  * Try make as good a match as possible with
2863  * available sub drivers
2864  */
2865 int
2866 scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2867 {
2868 	struct scsi_inquiry_pattern *entry;
2869 	struct scsi_inquiry_data *inq;
2870 
2871 	entry = (struct scsi_inquiry_pattern *)table_entry;
2872 	inq = (struct scsi_inquiry_data *)inqbuffer;
2873 
2874 	if (((SID_TYPE(inq) == entry->type)
2875 	  || (entry->type == T_ANY))
2876 	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2877 				   : entry->media_type & SIP_MEDIA_FIXED)
2878 	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2879 	 && (cam_strmatch(inq->product, entry->product,
2880 			  sizeof(inq->product)) == 0)
2881 	 && (cam_strmatch(inq->revision, entry->revision,
2882 			  sizeof(inq->revision)) == 0)) {
2883 		return (0);
2884 	}
2885         return (-1);
2886 }
2887 
2888 /*
2889  * Try make as good a match as possible with
2890  * available sub drivers
2891  */
2892 int
2893 scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2894 {
2895 	struct scsi_static_inquiry_pattern *entry;
2896 	struct scsi_inquiry_data *inq;
2897 
2898 	entry = (struct scsi_static_inquiry_pattern *)table_entry;
2899 	inq = (struct scsi_inquiry_data *)inqbuffer;
2900 
2901 	if (((SID_TYPE(inq) == entry->type)
2902 	  || (entry->type == T_ANY))
2903 	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2904 				   : entry->media_type & SIP_MEDIA_FIXED)
2905 	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2906 	 && (cam_strmatch(inq->product, entry->product,
2907 			  sizeof(inq->product)) == 0)
2908 	 && (cam_strmatch(inq->revision, entry->revision,
2909 			  sizeof(inq->revision)) == 0)) {
2910 		return (0);
2911 	}
2912         return (-1);
2913 }
2914