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