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