xref: /dragonfly/sys/bus/cam/scsi/scsi_all.c (revision 851dc90d)
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.9 2002/10/21 05:38:11 simokawa Exp $
30  * $DragonFly: src/sys/bus/cam/scsi/scsi_all.c,v 1.3 2003/08/07 21:16:44 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 }
2527 
2528 void
2529 scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
2530 	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2531 	     u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len,
2532 	     int evpd, u_int8_t page_code, u_int8_t sense_len,
2533 	     u_int32_t timeout)
2534 {
2535 	struct scsi_inquiry *scsi_cmd;
2536 
2537 	cam_fill_csio(csio,
2538 		      retries,
2539 		      cbfcnp,
2540 		      /*flags*/CAM_DIR_IN,
2541 		      tag_action,
2542 		      /*data_ptr*/inq_buf,
2543 		      /*dxfer_len*/inq_len,
2544 		      sense_len,
2545 		      sizeof(*scsi_cmd),
2546 		      timeout);
2547 
2548 	scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes;
2549 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2550 	scsi_cmd->opcode = INQUIRY;
2551 	if (evpd) {
2552 		scsi_cmd->byte2 |= SI_EVPD;
2553 		scsi_cmd->page_code = page_code;
2554 	}
2555 	/*
2556 	 * A 'transfer units' count of 256 is coded as
2557 	 * zero for all commands with a single byte count
2558 	 * field.
2559 	 */
2560 	if (inq_len == 256)
2561 		inq_len = 0;
2562 	scsi_cmd->length = inq_len;
2563 }
2564 
2565 void
2566 scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
2567 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2568 		u_int8_t tag_action, int dbd, u_int8_t page_code,
2569 		u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2570 		u_int8_t sense_len, u_int32_t timeout)
2571 {
2572 	u_int8_t cdb_len;
2573 
2574 	/*
2575 	 * Use the smallest possible command to perform the operation.
2576 	 */
2577 	if (param_len < 256) {
2578 		/*
2579 		 * We can fit in a 6 byte cdb.
2580 		 */
2581 		struct scsi_mode_sense_6 *scsi_cmd;
2582 
2583 		scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2584 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2585 		scsi_cmd->opcode = MODE_SENSE_6;
2586 		if (dbd != 0)
2587 			scsi_cmd->byte2 |= SMS_DBD;
2588 		scsi_cmd->page = page_code | page;
2589 		scsi_cmd->length = param_len;
2590 		cdb_len = sizeof(*scsi_cmd);
2591 	} else {
2592 		/*
2593 		 * Need a 10 byte cdb.
2594 		 */
2595 		struct scsi_mode_sense_10 *scsi_cmd;
2596 
2597 		scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes;
2598 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2599 		scsi_cmd->opcode = MODE_SENSE_10;
2600 		if (dbd != 0)
2601 			scsi_cmd->byte2 |= SMS_DBD;
2602 		scsi_cmd->page = page_code | page;
2603 		scsi_ulto2b(param_len, scsi_cmd->length);
2604 		cdb_len = sizeof(*scsi_cmd);
2605 	}
2606 	cam_fill_csio(csio,
2607 		      retries,
2608 		      cbfcnp,
2609 		      CAM_DIR_IN,
2610 		      tag_action,
2611 		      param_buf,
2612 		      param_len,
2613 		      sense_len,
2614 		      cdb_len,
2615 		      timeout);
2616 }
2617 
2618 void
2619 scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
2620 		 void (*cbfcnp)(struct cam_periph *, union ccb *),
2621 		 u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2622 		 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2623 		 u_int32_t timeout)
2624 {
2625 	u_int8_t cdb_len;
2626 
2627 	/*
2628 	 * Use the smallest possible command to perform the operation.
2629 	 */
2630 	if (param_len < 256) {
2631 		/*
2632 		 * We can fit in a 6 byte cdb.
2633 		 */
2634 		struct scsi_mode_select_6 *scsi_cmd;
2635 
2636 		scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2637 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2638 		scsi_cmd->opcode = MODE_SELECT_6;
2639 		if (scsi_page_fmt != 0)
2640 			scsi_cmd->byte2 |= SMS_PF;
2641 		if (save_pages != 0)
2642 			scsi_cmd->byte2 |= SMS_SP;
2643 		scsi_cmd->length = param_len;
2644 		cdb_len = sizeof(*scsi_cmd);
2645 	} else {
2646 		/*
2647 		 * Need a 10 byte cdb.
2648 		 */
2649 		struct scsi_mode_select_10 *scsi_cmd;
2650 
2651 		scsi_cmd =
2652 		    (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes;
2653 		bzero(scsi_cmd, sizeof(*scsi_cmd));
2654 		scsi_cmd->opcode = MODE_SELECT_10;
2655 		if (scsi_page_fmt != 0)
2656 			scsi_cmd->byte2 |= SMS_PF;
2657 		if (save_pages != 0)
2658 			scsi_cmd->byte2 |= SMS_SP;
2659 		scsi_ulto2b(param_len, scsi_cmd->length);
2660 		cdb_len = sizeof(*scsi_cmd);
2661 	}
2662 	cam_fill_csio(csio,
2663 		      retries,
2664 		      cbfcnp,
2665 		      CAM_DIR_OUT,
2666 		      tag_action,
2667 		      param_buf,
2668 		      param_len,
2669 		      sense_len,
2670 		      cdb_len,
2671 		      timeout);
2672 }
2673 
2674 
2675 /* XXX allow specification of address and PMI bit and LBA */
2676 void
2677 scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
2678 		   void (*cbfcnp)(struct cam_periph *, union ccb *),
2679 		   u_int8_t tag_action,
2680 		   struct scsi_read_capacity_data *rcap_buf,
2681 		   u_int8_t sense_len, u_int32_t timeout)
2682 {
2683 	struct scsi_read_capacity *scsi_cmd;
2684 
2685 	cam_fill_csio(csio,
2686 		      retries,
2687 		      cbfcnp,
2688 		      /*flags*/CAM_DIR_IN,
2689 		      tag_action,
2690 		      /*data_ptr*/(u_int8_t *)rcap_buf,
2691 		      /*dxfer_len*/sizeof(*rcap_buf),
2692 		      sense_len,
2693 		      sizeof(*scsi_cmd),
2694 		      timeout);
2695 
2696 	scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes;
2697 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2698 	scsi_cmd->opcode = READ_CAPACITY;
2699 }
2700 
2701 /*
2702  * Prevent or allow the user to remove the media
2703  */
2704 void
2705 scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
2706 	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2707 	     u_int8_t tag_action, u_int8_t action,
2708 	     u_int8_t sense_len, u_int32_t timeout)
2709 {
2710 	struct scsi_prevent *scsi_cmd;
2711 
2712 	cam_fill_csio(csio,
2713 		      retries,
2714 		      cbfcnp,
2715 		      /*flags*/CAM_DIR_NONE,
2716 		      tag_action,
2717 		      /*data_ptr*/NULL,
2718 		      /*dxfer_len*/0,
2719 		      sense_len,
2720 		      sizeof(*scsi_cmd),
2721 		      timeout);
2722 
2723 	scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes;
2724 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2725 	scsi_cmd->opcode = PREVENT_ALLOW;
2726 	scsi_cmd->how = action;
2727 }
2728 
2729 /*
2730  * Syncronize the media to the contents of the cache for
2731  * the given lba/count pair.  Specifying 0/0 means sync
2732  * the whole cache.
2733  */
2734 void
2735 scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries,
2736 		       void (*cbfcnp)(struct cam_periph *, union ccb *),
2737 		       u_int8_t tag_action, u_int32_t begin_lba,
2738 		       u_int16_t lb_count, u_int8_t sense_len,
2739 		       u_int32_t timeout)
2740 {
2741 	struct scsi_sync_cache *scsi_cmd;
2742 
2743 	cam_fill_csio(csio,
2744 		      retries,
2745 		      cbfcnp,
2746 		      /*flags*/CAM_DIR_NONE,
2747 		      tag_action,
2748 		      /*data_ptr*/NULL,
2749 		      /*dxfer_len*/0,
2750 		      sense_len,
2751 		      sizeof(*scsi_cmd),
2752 		      timeout);
2753 
2754 	scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes;
2755 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2756 	scsi_cmd->opcode = SYNCHRONIZE_CACHE;
2757 	scsi_ulto4b(begin_lba, scsi_cmd->begin_lba);
2758 	scsi_ulto2b(lb_count, scsi_cmd->lb_count);
2759 }
2760 
2761 void
2762 scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
2763 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2764 		u_int8_t tag_action, int readop, u_int8_t byte2,
2765 		int minimum_cmd_size, u_int32_t lba, u_int32_t block_count,
2766 		u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
2767 		u_int32_t timeout)
2768 {
2769 	u_int8_t cdb_len;
2770 	/*
2771 	 * Use the smallest possible command to perform the operation
2772 	 * as some legacy hardware does not support the 10 byte
2773 	 * commands.  If any of the lower 5 bits in byte2 is set, we have
2774 	 * to go with a larger command.
2775 	 *
2776 	 */
2777 	if ((minimum_cmd_size < 10)
2778 	 && ((lba & 0x1fffff) == lba)
2779 	 && ((block_count & 0xff) == block_count)
2780 	 && ((byte2 & 0xe0) == 0)) {
2781 		/*
2782 		 * We can fit in a 6 byte cdb.
2783 		 */
2784 		struct scsi_rw_6 *scsi_cmd;
2785 
2786 		scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
2787 		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2788 		scsi_ulto3b(lba, scsi_cmd->addr);
2789 		scsi_cmd->length = block_count & 0xff;
2790 		scsi_cmd->control = 0;
2791 		cdb_len = sizeof(*scsi_cmd);
2792 
2793 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2794 			  ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0],
2795 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2796 			   scsi_cmd->length, dxfer_len));
2797 	} else if ((minimum_cmd_size < 12)
2798 		&& ((block_count & 0xffff) == block_count)) {
2799 		/*
2800 		 * Need a 10 byte cdb.
2801 		 */
2802 		struct scsi_rw_10 *scsi_cmd;
2803 
2804 		scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
2805 		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2806 		scsi_cmd->byte2 = byte2;
2807 		scsi_ulto4b(lba, scsi_cmd->addr);
2808 		scsi_cmd->reserved = 0;
2809 		scsi_ulto2b(block_count, scsi_cmd->length);
2810 		scsi_cmd->control = 0;
2811 		cdb_len = sizeof(*scsi_cmd);
2812 
2813 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2814 			  ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
2815 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2816 			   scsi_cmd->addr[3], scsi_cmd->length[0],
2817 			   scsi_cmd->length[1], dxfer_len));
2818 	} else {
2819 		/*
2820 		 * The block count is too big for a 10 byte CDB, use a 12
2821 		 * byte CDB.  READ/WRITE(12) are currently only defined for
2822 		 * optical devices.
2823 		 */
2824 		struct scsi_rw_12 *scsi_cmd;
2825 
2826 		scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
2827 		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2828 		scsi_cmd->byte2 = byte2;
2829 		scsi_ulto4b(lba, scsi_cmd->addr);
2830 		scsi_cmd->reserved = 0;
2831 		scsi_ulto4b(block_count, scsi_cmd->length);
2832 		scsi_cmd->control = 0;
2833 		cdb_len = sizeof(*scsi_cmd);
2834 
2835 		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2836 			  ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0],
2837 			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2838 			   scsi_cmd->addr[3], scsi_cmd->length[0],
2839 			   scsi_cmd->length[1], scsi_cmd->length[2],
2840 			   scsi_cmd->length[3], dxfer_len));
2841 	}
2842 	cam_fill_csio(csio,
2843 		      retries,
2844 		      cbfcnp,
2845 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
2846 		      tag_action,
2847 		      data_ptr,
2848 		      dxfer_len,
2849 		      sense_len,
2850 		      cdb_len,
2851 		      timeout);
2852 }
2853 
2854 void
2855 scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
2856 		void (*cbfcnp)(struct cam_periph *, union ccb *),
2857 		u_int8_t tag_action, int start, int load_eject,
2858 		int immediate, u_int8_t sense_len, u_int32_t timeout)
2859 {
2860 	struct scsi_start_stop_unit *scsi_cmd;
2861 	int extra_flags = 0;
2862 
2863 	scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes;
2864 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2865 	scsi_cmd->opcode = START_STOP_UNIT;
2866 	if (start != 0) {
2867 		scsi_cmd->how |= SSS_START;
2868 		/* it takes a lot of power to start a drive */
2869 		extra_flags |= CAM_HIGH_POWER;
2870 	}
2871 	if (load_eject != 0)
2872 		scsi_cmd->how |= SSS_LOEJ;
2873 	if (immediate != 0)
2874 		scsi_cmd->byte2 |= SSS_IMMED;
2875 
2876 	cam_fill_csio(csio,
2877 		      retries,
2878 		      cbfcnp,
2879 		      /*flags*/CAM_DIR_NONE | extra_flags,
2880 		      tag_action,
2881 		      /*data_ptr*/NULL,
2882 		      /*dxfer_len*/0,
2883 		      sense_len,
2884 		      sizeof(*scsi_cmd),
2885 		      timeout);
2886 
2887 }
2888 
2889 
2890 /*
2891  * Try make as good a match as possible with
2892  * available sub drivers
2893  */
2894 int
2895 scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2896 {
2897 	struct scsi_inquiry_pattern *entry;
2898 	struct scsi_inquiry_data *inq;
2899 
2900 	entry = (struct scsi_inquiry_pattern *)table_entry;
2901 	inq = (struct scsi_inquiry_data *)inqbuffer;
2902 
2903 	if (((SID_TYPE(inq) == entry->type)
2904 	  || (entry->type == T_ANY))
2905 	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2906 				   : entry->media_type & SIP_MEDIA_FIXED)
2907 	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2908 	 && (cam_strmatch(inq->product, entry->product,
2909 			  sizeof(inq->product)) == 0)
2910 	 && (cam_strmatch(inq->revision, entry->revision,
2911 			  sizeof(inq->revision)) == 0)) {
2912 		return (0);
2913 	}
2914         return (-1);
2915 }
2916 
2917 /*
2918  * Try make as good a match as possible with
2919  * available sub drivers
2920  */
2921 int
2922 scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2923 {
2924 	struct scsi_static_inquiry_pattern *entry;
2925 	struct scsi_inquiry_data *inq;
2926 
2927 	entry = (struct scsi_static_inquiry_pattern *)table_entry;
2928 	inq = (struct scsi_inquiry_data *)inqbuffer;
2929 
2930 	if (((SID_TYPE(inq) == entry->type)
2931 	  || (entry->type == T_ANY))
2932 	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2933 				   : entry->media_type & SIP_MEDIA_FIXED)
2934 	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2935 	 && (cam_strmatch(inq->product, entry->product,
2936 			  sizeof(inq->product)) == 0)
2937 	 && (cam_strmatch(inq->revision, entry->revision,
2938 			  sizeof(inq->revision)) == 0)) {
2939 		return (0);
2940 	}
2941         return (-1);
2942 }
2943