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