2 * Implementation of Utility functions for all SCSI device types.
4 * Copyright (c) 1997, 1998 Justin T. Gibbs.
5 * Copyright (c) 1997, 1998, 2003 Kenneth D. Merry.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
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.20 2007/11/24 19:19:43 pavalos Exp $
33 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/libkern.h>
40 #include <sys/kernel.h>
41 #include <sys/sysctl.h>
50 #define ksnprintf snprintf /* ick, userland uses us too */
51 #define kprintf printf
55 #include "../cam_ccb.h"
56 #include "../cam_xpt.h"
60 #include <sys/camlib.h>
68 #define ERESTART -1 /* restart syscall */
69 #define EJUSTRETURN -2 /* don't modify regs, just return */
73 * This is the default number of seconds we wait for devices to settle
74 * after a SCSI bus reset.
77 #define SCSI_DELAY 2000
80 * All devices need _some_ sort of bus settle delay, so we'll set it to
81 * a minimum value of 100ms.
83 #ifndef SCSI_MIN_DELAY
84 #define SCSI_MIN_DELAY 100
87 * Make sure the user isn't using seconds instead of milliseconds.
89 #if (SCSI_DELAY < SCSI_MIN_DELAY)
90 #error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value"
95 static int ascentrycomp(const void *key, const void *member);
96 static int senseentrycomp(const void *key, const void *member);
97 static void fetchtableentries(int sense_key, int asc, int ascq,
98 struct scsi_inquiry_data *,
99 const struct sense_key_table_entry **,
100 const struct asc_table_entry **);
102 static void init_scsi_delay(void);
103 static int sysctl_scsi_delay(SYSCTL_HANDLER_ARGS);
104 static int set_scsi_delay(int delay);
107 #if !defined(SCSI_NO_OP_STRINGS)
124 static struct op_table_entry plextor_cd_ops[] = {
125 {0xD8, R, "CD-DA READ"}
128 static struct scsi_op_quirk_entry scsi_op_quirk_table[] = {
131 * I believe that 0xD8 is the Plextor proprietary command
132 * to read CD-DA data. I'm not sure which Plextor CDROM
133 * models support the command, though. I know for sure
134 * that the 4X, 8X, and 12X models do, and presumably the
135 * 12-20X does. I don't know about any earlier models,
136 * though. If anyone has any more complete information,
137 * feel free to change this quirk entry.
139 {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"},
140 sizeof(plextor_cd_ops)/sizeof(struct op_table_entry),
145 static struct op_table_entry scsi_op_codes[] = {
147 * From: ftp://ftp.symbios.com/pub/standards/io/t10/drafts/spc/op-num.txt
148 * Modifications by Kenneth Merry (ken@FreeBSD.ORG)
150 * Note: order is important in this table, scsi_op_desc() currently
151 * depends on the opcodes in the table being in order to save search time.
156 * SCSI Operation Codes
157 * Numeric Sorted Listing
160 * D - DIRECT ACCESS DEVICE (SBC) device column key
161 * .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
162 * . L - PRINTER DEVICE (SSC) M = Mandatory
163 * . P - PROCESSOR DEVICE (SPC) O = Optional
164 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) V = Vendor specific
165 * . . R - CD DEVICE (MMC) R = Reserved
166 * . . S - SCANNER DEVICE (SGC) Z = Obsolete
167 * . . .O - OPTICAL MEMORY DEVICE (SBC)
168 * . . . M - MEDIA CHANGER DEVICE (SMC)
169 * . . . C - COMMUNICATION DEVICE (SSC)
170 * . . . .A - STORAGE ARRAY DEVICE (SCC)
171 * . . . . E - ENCLOSURE SERVICES DEVICE (SES)
172 * OP DTLPWRSOMCAE Description
173 * -- ------------ ---------------------------------------------------- */
174 /* 00 MMMMMMMMMMMM TEST UNIT READY */
175 {0x00, ALL, "TEST UNIT READY"},
179 /* 01 Z V ZO ZO REZERO UNIT */
180 {0x01, D|L|W|O|M, "REZERO UNIT"},
184 /* 03 MMMMMMMMMMMM REQUEST SENSE */
185 {0x03, ALL, "REQUEST SENSE"},
187 /* 04 M O O FORMAT UNIT */
188 {0x04, D|R|O, "FORMAT UNIT"},
189 /* 04 O FORMAT MEDIUM */
190 {0x04, T, "FORMAT MEDIUM"},
194 /* 05 VMVVVV V READ BLOCK LIMITS */
195 {0x05, T, "READ BLOCK LIMITS"},
199 /* 07 OVV O OV REASSIGN BLOCKS */
200 {0x07, D|W|O, "REASSIGN BLOCKS"},
201 /* 07 O INITIALIZE ELEMENT STATUS */
202 {0x07, M, "INITIALIZE ELEMENT STATUS"},
204 /* 08 OMV OO OV READ(06) */
205 {0x08, D|T|W|R|O, "READ(06)"},
207 {0x08, P, "RECEIVE"},
208 /* 08 M GET MESSAGE(06) */
209 {0x08, C, "GET MESSAGE(06)"},
213 /* 0A OM O OV WRITE(06) */
214 {0x0A, D|T|W|O, "WRITE(06)"},
216 {0x0A, P, "SEND(06)"},
217 /* 0A M SEND MESSAGE(06) */
218 {0x0A, C, "SEND MESSAGE(06)"},
222 /* 0B Z ZO ZV SEEK(06) */
223 {0x0B, D|W|R|O, "SEEK(06)"},
224 /* 0B O SLEW AND PRINT */
225 {0x0B, L, "SLEW AND PRINT"},
230 /* 0F VOVVVV V READ REVERSE */
231 {0x0F, T, "READ REVERSE"},
233 /* 10 VM VVV WRITE FILEMARKS */
234 {0x10, T, "WRITE FILEMARKS"},
235 /* 10 O O SYNCHRONIZE BUFFER */
236 {0x10, L|W, "SYNCHRONIZE BUFFER"},
238 /* 11 VMVVVV SPACE */
241 /* 12 MMMMMMMMMMMM INQUIRY */
242 {0x12, ALL, "INQUIRY"},
244 /* 13 VOVVVV VERIFY(06) */
245 {0x13, T, "VERIFY(06)"},
247 /* 14 VOOVVV RECOVER BUFFERED DATA */
248 {0x14, T|L, "RECOVER BUFFERED DATA"},
250 /* 15 OMO OOOOOOOO MODE SELECT(06) */
251 {0x15, ALL & ~(P), "MODE SELECT(06)"},
253 /* 16 MMMOMMMM O RESERVE(06) */
254 {0x16, D|T|L|P|W|R|S|O|E, "RESERVE(06)"},
255 /* 16 M RESERVE ELEMENT(06) */
256 {0x16, M, "RESERVE ELEMENT(06)"},
258 /* 17 MMMOMMMM O RELEASE(06) */
259 {0x17, ALL & ~(M|C|A), "RELEASE(06)"},
260 /* 17 M RELEASE ELEMENT(06) */
261 {0x17, M, "RELEASE ELEMENT(06)"},
263 /* 18 OOOOOOOO COPY */
264 {0x18, ALL & ~(M|C|A|E), "COPY"},
266 /* 19 VMVVVV ERASE */
269 /* 1A OMO OOOOOOOO MODE SENSE(06) */
270 {0x1A, ALL & ~(P), "MODE SENSE(06)"},
272 /* 1B O OM O STOP START UNIT */
273 {0x1B, D|W|R|O, "STOP START UNIT"},
274 /* 1B O LOAD UNLOAD */
275 {0x1B, T, "LOAD UNLOAD"},
278 /* 1B O STOP PRINT */
279 {0x1B, L, "STOP PRINT"},
281 /* 1C OOOOOOOOOO M RECEIVE DIAGNOSTIC RESULTS */
282 {0x1C, ALL & ~(A), "RECEIVE DIAGNOSTIC RESULTS"},
284 /* 1D MMMMMMMMMMMM SEND DIAGNOSTIC */
285 {0x1D, ALL, "SEND DIAGNOSTIC"},
287 /* 1E OO OM OO PREVENT ALLOW MEDIUM REMOVAL */
288 {0x1E, D|T|W|R|O|M, "PREVENT ALLOW MEDIUM REMOVAL"},
296 /* 24 V VVM SET WINDOW */
297 {0x24, S, "SET WINDOW"},
299 /* 25 M M M READ CAPACITY */
300 {0x25, D|W|O, "READ CAPACITY"},
301 /* 25 M READ CD RECORDED CAPACITY */
302 {0x25, R, "READ CD RECORDED CAPACITY"},
303 /* 25 O GET WINDOW */
304 {0x25, S, "GET WINDOW"},
309 /* 28 M MMMM READ(10) */
310 {0x28, D|W|R|S|O, "READ(10)"},
311 /* 28 O GET MESSAGE(10) */
312 {0x28, C, "GET MESSAGE(10)"},
314 /* 29 V VV O READ GENERATION */
315 {0x29, O, "READ GENERATION"},
317 /* 2A M MM M WRITE(10) */
318 {0x2A, D|W|R|O, "WRITE(10)"},
320 {0x2A, S, "SEND(10)"},
321 /* 2A O SEND MESSAGE(10) */
322 {0x2A, C, "SEND MESSAGE(10)"},
324 /* 2B O OM O SEEK(10) */
325 {0x2B, D|W|R|O, "SEEK(10)"},
328 /* 2B O POSITION TO ELEMENT */
329 {0x2B, M, "POSITION TO ELEMENT"},
331 /* 2C V O ERASE(10) */
332 {0x2C, O, "ERASE(10)"},
334 /* 2D V O O READ UPDATED BLOCK */
335 {0x2D, W|O, "READ UPDATED BLOCK"},
337 /* 2E O O O WRITE AND VERIFY(10) */
338 {0x2E, D|W|O, "WRITE AND VERIFY(10)"},
340 /* 2F O OO O VERIFY(10) */
341 {0x2F, D|W|R|O, "VERIFY(10)"},
343 /* 30 Z ZO Z SEARCH DATA HIGH(10) */
344 {0x30, D|W|R|O, "SEARCH DATA HIGH(10)"},
346 /* 31 Z ZO Z SEARCH DATA EQUAL(10) */
347 {0x31, D|W|R|O, "SEARCH DATA EQUAL(10)"},
348 /* 31 O OBJECT POSITION */
349 {0x31, S, "OBJECT POSITION"},
351 /* 32 Z ZO Z SEARCH DATA LOW(10) */
352 {0x32, D|W|R|O, "SEARCH DATA LOW(10"},
354 /* 33 O OO O SET LIMITS(10) */
355 {0x33, D|W|R|O, "SET LIMITS(10)"},
357 /* 34 O OO O PRE-FETCH */
358 {0x34, D|W|R|O, "PRE-FETCH"},
359 /* 34 O READ POSITION */
360 {0x34, T, "READ POSITION"},
361 /* 34 O GET DATA BUFFER STATUS */
362 {0x34, S, "GET DATA BUFFER STATUS"},
364 /* 35 O OM O SYNCHRONIZE CACHE */
365 {0x35, D|W|R|O, "SYNCHRONIZE CACHE"},
367 /* 36 O OO O LOCK UNLOCK CACHE */
368 {0x36, D|W|R|O, "LOCK UNLOCK CACHE"},
370 /* 37 O O READ DEFECT DATA(10) */
371 {0x37, D|O, "READ DEFECT DATA(10)"},
373 /* 38 O O MEDIUM SCAN */
374 {0x38, W|O, "MEDIUM SCAN"},
376 /* 39 OOOOOOOO COMPARE */
377 {0x39, ALL & ~(M|C|A|E), "COMPARE"},
379 /* 3A OOOOOOOO COPY AND VERIFY */
380 {0x3A, ALL & ~(M|C|A|E), "COPY AND VERIFY"},
382 /* 3B OOOOOOOOOO O WRITE BUFFER */
383 {0x3B, ALL & ~(A), "WRITE BUFFER"},
385 /* 3C OOOOOOOOOO READ BUFFER */
386 {0x3C, ALL & ~(A|E),"READ BUFFER"},
388 /* 3D O O UPDATE BLOCK */
389 {0x3D, W|O, "UPDATE BLOCK"},
391 /* 3E O OO O READ LONG */
392 {0x3E, D|W|R|O, "READ LONG"},
394 /* 3F O O O WRITE LONG */
395 {0x3F, D|W|O, "WRITE LONG"},
397 /* 40 OOOOOOOOOO CHANGE DEFINITION */
398 {0x40, ALL & ~(A|E),"CHANGE DEFINITION"},
400 /* 41 O WRITE SAME */
401 {0x41, D, "WRITE SAME"},
403 /* 42 M READ SUB-CHANNEL */
404 {0x42, R, "READ SUB-CHANNEL"},
406 /* 43 M READ TOC/PMA/ATIP {MMC Proposed} */
407 {0x43, R, "READ TOC/PMA/ATIP {MMC Proposed}"},
409 /* 44 M REPORT DENSITY SUPPORT */
410 {0x44, T, "REPORT DENSITY SUPPORT"},
411 /* 44 M READ HEADER */
412 {0x44, R, "READ HEADER"},
414 /* 45 O PLAY AUDIO(10) */
415 {0x45, R, "PLAY AUDIO(10)"},
419 /* 47 O PLAY AUDIO MSF */
420 {0x47, R, "PLAY AUDIO MSF"},
422 /* 48 O PLAY AUDIO TRACK INDEX */
423 {0x48, R, "PLAY AUDIO TRACK INDEX"},
425 /* 49 O PLAY TRACK RELATIVE(10) */
426 {0x49, R, "PLAY TRACK RELATIVE(10)"},
430 /* 4B O PAUSE/RESUME */
431 {0x4B, R, "PAUSE/RESUME"},
433 /* 4C OOOOOOOOOOO LOG SELECT */
434 {0x4C, ALL & ~(E), "LOG SELECT"},
436 /* 4D OOOOOOOOOOO LOG SENSE */
437 {0x4D, ALL & ~(E), "LOG SENSE"},
439 /* 4E O STOP PLAY/SCAN {MMC Proposed} */
440 {0x4E, R, "STOP PLAY/SCAN {MMC Proposed}"},
444 /* 50 O XDWRITE(10) */
445 {0x50, D, "XDWRITE(10)"},
447 /* 51 O XPWRITE(10) */
448 {0x51, D, "XPWRITE(10)"},
449 /* 51 M READ DISC INFORMATION {MMC Proposed} */
450 {0x51, R, "READ DISC INFORMATION {MMC Proposed}"},
452 /* 52 O XDREAD(10) */
453 {0x52, D, "XDREAD(10)"},
454 /* 52 M READ TRACK INFORMATION {MMC Proposed} */
455 {0x52, R, "READ TRACK INFORMATION {MMC Proposed}"},
457 /* 53 M RESERVE TRACK {MMC Proposed} */
458 {0x53, R, "RESERVE TRACK {MMC Proposed}"},
460 /* 54 O SEND OPC INFORMATION {MMC Proposed} */
461 {0x54, R, "SEND OPC INFORMATION {MMC Proposed}"},
463 /* 55 OOO OOOOOOOO MODE SELECT(10) */
464 {0x55, ALL & ~(P), "MODE SELECT(10)"},
466 /* 56 MMMOMMMM O RESERVE(10) */
467 {0x56, ALL & ~(M|C|A), "RESERVE(10)"},
468 /* 56 M RESERVE ELEMENT(10) */
469 {0x56, M, "RESERVE ELEMENT(10)"},
471 /* 57 MMMOMMMM O RELEASE(10) */
472 {0x57, ALL & ~(M|C|A), "RELEASE(10"},
473 /* 57 M RELEASE ELEMENT(10) */
474 {0x57, M, "RELEASE ELEMENT(10)"},
476 /* 58 O REPAIR TRACK {MMC Proposed} */
477 {0x58, R, "REPAIR TRACK {MMC Proposed}"},
479 /* 59 O READ MASTER CUE {MMC Proposed} */
480 {0x59, R, "READ MASTER CUE {MMC Proposed}"},
482 /* 5A OOO OOOOOOOO MODE SENSE(10) */
483 {0x5A, ALL & ~(P), "MODE SENSE(10)"},
485 /* 5B M CLOSE TRACK/SESSION {MMC Proposed} */
486 {0x5B, R, "CLOSE TRACK/SESSION {MMC Proposed}"},
488 /* 5C O READ BUFFER CAPACITY {MMC Proposed} */
489 {0x5C, R, "READ BUFFER CAPACITY {MMC Proposed}"},
491 /* 5D O SEND CUE SHEET {MMC Proposed} */
492 {0x5D, R, "SEND CUE SHEET {MMC Proposed}"},
494 /* 5E OOOOOOOOO O PERSISTENT RESERVE IN */
495 {0x5E, ALL & ~(C|A),"PERSISTENT RESERVE IN"},
497 /* 5F OOOOOOOOO O PERSISTENT RESERVE OUT */
498 {0x5F, ALL & ~(C|A),"PERSISTENT RESERVE OUT"},
500 /* 80 O XDWRITE EXTENDED(16) */
501 {0x80, D, "XDWRITE EXTENDED(16)"},
503 /* 81 O REBUILD(16) */
504 {0x81, D, "REBUILD(16)"},
506 /* 82 O REGENERATE(16) */
507 {0x82, D, "REGENERATE(16)"},
514 /* 88 MM OO O O READ(16) */
515 {0x88, D|T|W|R|O, "READ(16)"},
517 /* 8A OM O O O WRITE(16) */
518 {0x8A, D|T|W|R|O, "WRITE(16)"},
538 /* XXX KDM ALL for these? op-num.txt defines them for none.. */
539 /* 9E SERVICE ACTION IN(16) */
540 {0x9E, ALL, "SERVICE ACTION IN(16)"},
541 /* 9F SERVICE ACTION OUT(16) */
542 {0x9F, ALL, "SERVICE ACTION OUT(16)"},
544 /* A0 OOOOOOOOOOO REPORT LUNS */
545 {0xA0, ALL & ~(E), "REPORT LUNS"},
547 /* A1 O BLANK {MMC Proposed} */
548 {0xA1, R, "BLANK {MMC Proposed}"},
550 /* A2 O WRITE CD MSF {MMC Proposed} */
551 {0xA2, R, "WRITE CD MSF {MMC Proposed}"},
553 /* A3 M MAINTENANCE (IN) */
554 {0xA3, A, "MAINTENANCE (IN)"},
556 /* A4 O MAINTENANCE (OUT) */
557 {0xA4, A, "MAINTENANCE (OUT)"},
559 /* A5 O M MOVE MEDIUM */
560 {0xA5, T|M, "MOVE MEDIUM"},
561 /* A5 O PLAY AUDIO(12) */
562 {0xA5, R, "PLAY AUDIO(12)"},
564 /* A6 O EXCHANGE MEDIUM */
565 {0xA6, M, "EXCHANGE MEDIUM"},
566 /* A6 O LOAD/UNLOAD CD {MMC Proposed} */
567 {0xA6, R, "LOAD/UNLOAD CD {MMC Proposed}"},
569 /* A7 OO OO OO MOVE MEDIUM ATTACHED */
570 {0xA7, D|T|W|R|O|M, "MOVE MEDIUM ATTACHED"},
572 /* A8 O OM O READ(12) */
573 {0xA8,D|W|R|O, "READ(12)"},
574 /* A8 O GET MESSAGE(12) */
575 {0xA8, C, "GET MESSAGE(12)"},
577 /* A9 O PLAY TRACK RELATIVE(12) */
578 {0xA9, R, "PLAY TRACK RELATIVE(12)"},
580 /* AA O O O WRITE(12) */
581 {0xAA,D|W|O, "WRITE(12)"},
582 /* AA O WRITE CD(12) {MMC Proposed} */
583 {0xAA, R, "WRITE CD(12) {MMC Proposed}"},
584 /* AA O SEND MESSAGE(12) */
585 {0xAA, C, "SEND MESSAGE(12)"},
590 {0xAC, O, "ERASE(12)"},
594 /* AE O O WRITE AND VERIFY(12) */
595 {0xAE, W|O, "WRITE AND VERIFY(12)"},
597 /* AF OO O VERIFY(12) */
598 {0xAF, W|R|O, "VERIFY(12)"},
600 /* B0 ZO Z SEARCH DATA HIGH(12) */
601 {0xB0, W|R|O, "SEARCH DATA HIGH(12)"},
603 /* B1 ZO Z SEARCH DATA EQUAL(12) */
604 {0xB1, W|R|O, "SEARCH DATA EQUAL(12)"},
606 /* B2 ZO Z SEARCH DATA LOW(12) */
607 {0xB2, W|R|O, "SEARCH DATA LOW(12)"},
609 /* B3 OO O SET LIMITS(12) */
610 {0xB3, W|R|O, "SET LIMITS(12)"},
612 /* B4 OO OO OO READ ELEMENT STATUS ATTACHED */
613 {0xB4, D|T|W|R|O|M, "READ ELEMENT STATUS ATTACHED"},
615 /* B5 O REQUEST VOLUME ELEMENT ADDRESS */
616 {0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS"},
618 /* B6 O SEND VOLUME TAG */
619 {0xB6, M, "SEND VOLUME TAG"},
621 /* B7 O READ DEFECT DATA(12) */
622 {0xB7, O, "READ DEFECT DATA(12)"},
624 /* B8 O M READ ELEMENT STATUS */
625 {0xB8, T|M, "READ ELEMENT STATUS"},
626 /* B8 O SET CD SPEED {MMC Proposed} */
627 {0xB8, R, "SET CD SPEED {MMC Proposed}"},
629 /* B9 M READ CD MSF {MMC Proposed} */
630 {0xB9, R, "READ CD MSF {MMC Proposed}"},
632 /* BA O SCAN {MMC Proposed} */
633 {0xBA, R, "SCAN {MMC Proposed}"},
634 /* BA M REDUNDANCY GROUP (IN) */
635 {0xBA, A, "REDUNDANCY GROUP (IN)"},
637 /* BB O SET CD-ROM SPEED {proposed} */
638 {0xBB, R, "SET CD-ROM SPEED {proposed}"},
639 /* BB O REDUNDANCY GROUP (OUT) */
640 {0xBB, A, "REDUNDANCY GROUP (OUT)"},
642 /* BC O PLAY CD {MMC Proposed} */
643 {0xBC, R, "PLAY CD {MMC Proposed}"},
644 /* BC M SPARE (IN) */
645 {0xBC, A, "SPARE (IN)"},
647 /* BD M MECHANISM STATUS {MMC Proposed} */
648 {0xBD, R, "MECHANISM STATUS {MMC Proposed}"},
649 /* BD O SPARE (OUT) */
650 {0xBD, A, "SPARE (OUT)"},
652 /* BE O READ CD {MMC Proposed} */
653 {0xBE, R, "READ CD {MMC Proposed}"},
654 /* BE M VOLUME SET (IN) */
655 {0xBE, A, "VOLUME SET (IN)"},
657 /* BF O VOLUME SET (OUT) */
658 {0xBF, A, "VOLUME SET (OUT)"}
662 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
669 struct op_table_entry *table[2];
672 pd_type = SID_TYPE(inq_data);
674 match = cam_quirkmatch((caddr_t)inq_data,
675 (caddr_t)scsi_op_quirk_table,
676 sizeof(scsi_op_quirk_table)/
677 sizeof(*scsi_op_quirk_table),
678 sizeof(*scsi_op_quirk_table),
682 table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
683 num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops;
684 table[1] = scsi_op_codes;
685 num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
689 * If this is true, we have a vendor specific opcode that
690 * wasn't covered in the quirk table.
692 if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80)))
693 return("Vendor Specific Command");
695 table[0] = scsi_op_codes;
696 num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
700 /* RBC is 'Simplified' Direct Access Device */
701 if (pd_type == T_RBC)
704 opmask = 1 << pd_type;
706 for (j = 0; j < num_tables; j++) {
707 for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){
708 if ((table[j][i].opcode == opcode)
709 && ((table[j][i].opmask & opmask) != 0))
710 return(table[j][i].desc);
715 * If we can't find a match for the command in the table, we just
716 * assume it's a vendor specifc command.
718 return("Vendor Specific Command");
722 #else /* SCSI_NO_OP_STRINGS */
725 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
733 #include <sys/param.h>
735 #if !defined(SCSI_NO_SENSE_STRINGS)
736 #define SST(asc, ascq, action, desc) \
737 asc, ascq, action, desc
739 const char empty_string[] = "";
741 #define SST(asc, ascq, action, desc) \
742 asc, ascq, action, empty_string
745 const struct sense_key_table_entry sense_key_table[] =
747 { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
748 { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
750 SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
753 { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
754 { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
755 { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
756 { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
757 { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
758 { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
759 { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
760 { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
761 { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
762 { SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
763 { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
764 { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
765 { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
768 const int sense_key_table_size =
769 sizeof(sense_key_table)/sizeof(sense_key_table[0]);
771 static struct asc_table_entry quantum_fireball_entries[] = {
772 {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
773 "Logical unit not ready, initializing cmd. required")}
776 static struct asc_table_entry sony_mo_entries[] = {
777 {SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
778 "Logical unit not ready, cause not reportable")}
781 static struct scsi_sense_quirk_entry sense_quirk_table[] = {
784 * The Quantum Fireball ST and SE like to return 0x04 0x0b when
785 * they really should return 0x04 0x02. 0x04,0x0b isn't
786 * defined in any SCSI spec, and it isn't mentioned in the
787 * hardware manual for these drives.
789 {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
791 sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
792 /*sense key entries*/NULL,
793 quantum_fireball_entries
797 * This Sony MO drive likes to return 0x04, 0x00 when it
800 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
802 sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
803 /*sense key entries*/NULL,
808 const int sense_quirk_table_size =
809 sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
811 static struct asc_table_entry asc_table[] = {
813 * From File: ASC-NUM.TXT
814 * SCSI ASC/ASCQ Assignments
815 * Numeric Sorted Listing
818 * D - DIRECT ACCESS DEVICE (SBC) device column key
819 * .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
820 * . L - PRINTER DEVICE (SSC) blank = reserved
821 * . P - PROCESSOR DEVICE (SPC) not blank = allowed
822 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
823 * . . R - CD DEVICE (MMC)
824 * . . S - SCANNER DEVICE (SGC)
825 * . . .O - OPTICAL MEMORY DEVICE (SBC)
826 * . . . M - MEDIA CHANGER DEVICE (SMC)
827 * . . . C - COMMUNICATION DEVICE (SSC)
828 * . . . .A - STORAGE ARRAY DEVICE (SCC)
829 * . . . . E - ENCLOSURE SERVICES DEVICE (SES)
830 * DTLPWRSOMCAE ASC ASCQ Action Description
831 * ------------ ---- ---- ------ -----------------------------------*/
832 /* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP,
833 "No additional sense information") },
834 /* T S */{SST(0x00, 0x01, SS_RDEF,
835 "Filemark detected") },
836 /* T S */{SST(0x00, 0x02, SS_RDEF,
837 "End-of-partition/medium detected") },
838 /* T */{SST(0x00, 0x03, SS_RDEF,
839 "Setmark detected") },
840 /* T S */{SST(0x00, 0x04, SS_RDEF,
841 "Beginning-of-partition/medium detected") },
842 /* T S */{SST(0x00, 0x05, SS_RDEF,
843 "End-of-data detected") },
844 /* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF,
845 "I/O process terminated") },
846 /* R */{SST(0x00, 0x11, SS_FATAL|EBUSY,
847 "Audio play operation in progress") },
848 /* R */{SST(0x00, 0x12, SS_NOP,
849 "Audio play operation paused") },
850 /* R */{SST(0x00, 0x13, SS_NOP,
851 "Audio play operation successfully completed") },
852 /* R */{SST(0x00, 0x14, SS_RDEF,
853 "Audio play operation stopped due to error") },
854 /* R */{SST(0x00, 0x15, SS_NOP,
855 "No current audio status to return") },
856 /* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY,
857 "Operation in progress") },
858 /* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF,
859 "Cleaning requested") },
860 /* D W O */{SST(0x01, 0x00, SS_RDEF,
861 "No index/sector signal") },
862 /* D WR OM */{SST(0x02, 0x00, SS_RDEF,
863 "No seek complete") },
864 /* DTL W SO */{SST(0x03, 0x00, SS_RDEF,
865 "Peripheral device write fault") },
866 /* T */{SST(0x03, 0x01, SS_RDEF,
867 "No write current") },
868 /* T */{SST(0x03, 0x02, SS_RDEF,
869 "Excessive write errors") },
870 /* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
871 "Logical unit not ready, cause not reportable") },
872 /* DTLPWRSOMCAE */{SST(0x04, 0x01, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
873 "Logical unit is in process of becoming ready") },
874 /* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
875 "Logical unit not ready, initializing cmd. required") },
876 /* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO,
877 "Logical unit not ready, manual intervention required")},
878 /* DTL O */{SST(0x04, 0x04, SS_FATAL|EBUSY,
879 "Logical unit not ready, format in progress") },
880 /* DT W OMCA */{SST(0x04, 0x05, SS_FATAL|EBUSY,
881 "Logical unit not ready, rebuild in progress") },
882 /* DT W OMCA */{SST(0x04, 0x06, SS_FATAL|EBUSY,
883 "Logical unit not ready, recalculation in progress") },
884 /* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY,
885 "Logical unit not ready, operation in progress") },
886 /* R */{SST(0x04, 0x08, SS_FATAL|EBUSY,
887 "Logical unit not ready, long write in progress") },
888 /* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF,
889 "Logical unit does not respond to selection") },
890 /* D WR OM */{SST(0x06, 0x00, SS_RDEF,
891 "No reference position found") },
892 /* DTL WRSOM */{SST(0x07, 0x00, SS_RDEF,
893 "Multiple peripheral devices selected") },
894 /* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF,
895 "Logical unit communication failure") },
896 /* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF,
897 "Logical unit communication time-out") },
898 /* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF,
899 "Logical unit communication parity error") },
900 /* DT R OM */{SST(0x08, 0x03, SS_RDEF,
901 "Logical unit communication crc error (ultra-dma/32)")},
902 /* DT WR O */{SST(0x09, 0x00, SS_RDEF,
903 "Track following error") },
904 /* WR O */{SST(0x09, 0x01, SS_RDEF,
905 "Tracking servo failure") },
906 /* WR O */{SST(0x09, 0x02, SS_RDEF,
907 "Focus servo failure") },
908 /* WR O */{SST(0x09, 0x03, SS_RDEF,
909 "Spindle servo failure") },
910 /* DT WR O */{SST(0x09, 0x04, SS_RDEF,
911 "Head select fault") },
912 /* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC,
913 "Error log overflow") },
914 /* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF,
916 /* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF,
917 "Specified temperature exceeded") },
918 /* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF,
919 "Enclosure degraded") },
920 /* T RS */{SST(0x0C, 0x00, SS_RDEF,
922 /* D W O */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
923 "Write error - recovered with auto reallocation") },
924 /* D W O */{SST(0x0C, 0x02, SS_RDEF,
925 "Write error - auto reallocation failed") },
926 /* D W O */{SST(0x0C, 0x03, SS_RDEF,
927 "Write error - recommend reassignment") },
928 /* DT W O */{SST(0x0C, 0x04, SS_RDEF,
929 "Compression check miscompare error") },
930 /* DT W O */{SST(0x0C, 0x05, SS_RDEF,
931 "Data expansion occurred during compression") },
932 /* DT W O */{SST(0x0C, 0x06, SS_RDEF,
933 "Block not compressible") },
934 /* R */{SST(0x0C, 0x07, SS_RDEF,
935 "Write error - recovery needed") },
936 /* R */{SST(0x0C, 0x08, SS_RDEF,
937 "Write error - recovery failed") },
938 /* R */{SST(0x0C, 0x09, SS_RDEF,
939 "Write error - loss of streaming") },
940 /* R */{SST(0x0C, 0x0A, SS_RDEF,
941 "Write error - padding blocks added") },
942 /* D W O */{SST(0x10, 0x00, SS_RDEF,
943 "ID CRC or ECC error") },
944 /* DT WRSO */{SST(0x11, 0x00, SS_RDEF,
945 "Unrecovered read error") },
946 /* DT W SO */{SST(0x11, 0x01, SS_RDEF,
947 "Read retries exhausted") },
948 /* DT W SO */{SST(0x11, 0x02, SS_RDEF,
949 "Error too long to correct") },
950 /* DT W SO */{SST(0x11, 0x03, SS_RDEF,
951 "Multiple read errors") },
952 /* D W O */{SST(0x11, 0x04, SS_RDEF,
953 "Unrecovered read error - auto reallocate failed") },
954 /* WR O */{SST(0x11, 0x05, SS_RDEF,
955 "L-EC uncorrectable error") },
956 /* WR O */{SST(0x11, 0x06, SS_RDEF,
957 "CIRC unrecovered error") },
958 /* W O */{SST(0x11, 0x07, SS_RDEF,
959 "Data re-synchronization error") },
960 /* T */{SST(0x11, 0x08, SS_RDEF,
961 "Incomplete block read") },
962 /* T */{SST(0x11, 0x09, SS_RDEF,
964 /* DT O */{SST(0x11, 0x0A, SS_RDEF,
965 "Miscorrected error") },
966 /* D W O */{SST(0x11, 0x0B, SS_RDEF,
967 "Unrecovered read error - recommend reassignment") },
968 /* D W O */{SST(0x11, 0x0C, SS_RDEF,
969 "Unrecovered read error - recommend rewrite the data")},
970 /* DT WR O */{SST(0x11, 0x0D, SS_RDEF,
971 "De-compression CRC error") },
972 /* DT WR O */{SST(0x11, 0x0E, SS_RDEF,
973 "Cannot decompress using declared algorithm") },
974 /* R */{SST(0x11, 0x0F, SS_RDEF,
975 "Error reading UPC/EAN number") },
976 /* R */{SST(0x11, 0x10, SS_RDEF,
977 "Error reading ISRC number") },
978 /* R */{SST(0x11, 0x11, SS_RDEF,
979 "Read error - loss of streaming") },
980 /* D W O */{SST(0x12, 0x00, SS_RDEF,
981 "Address mark not found for id field") },
982 /* D W O */{SST(0x13, 0x00, SS_RDEF,
983 "Address mark not found for data field") },
984 /* DTL WRSO */{SST(0x14, 0x00, SS_RDEF,
985 "Recorded entity not found") },
986 /* DT WR O */{SST(0x14, 0x01, SS_RDEF,
987 "Record not found") },
988 /* T */{SST(0x14, 0x02, SS_RDEF,
989 "Filemark or setmark not found") },
990 /* T */{SST(0x14, 0x03, SS_RDEF,
991 "End-of-data not found") },
992 /* T */{SST(0x14, 0x04, SS_RDEF,
993 "Block sequence error") },
994 /* DT W O */{SST(0x14, 0x05, SS_RDEF,
995 "Record not found - recommend reassignment") },
996 /* DT W O */{SST(0x14, 0x06, SS_RDEF,
997 "Record not found - data auto-reallocated") },
998 /* DTL WRSOM */{SST(0x15, 0x00, SS_RDEF,
999 "Random positioning error") },
1000 /* DTL WRSOM */{SST(0x15, 0x01, SS_RDEF,
1001 "Mechanical positioning error") },
1002 /* DT WR O */{SST(0x15, 0x02, SS_RDEF,
1003 "Positioning error detected by read of medium") },
1004 /* D W O */{SST(0x16, 0x00, SS_RDEF,
1005 "Data synchronization mark error") },
1006 /* D W O */{SST(0x16, 0x01, SS_RDEF,
1007 "Data sync error - data rewritten") },
1008 /* D W O */{SST(0x16, 0x02, SS_RDEF,
1009 "Data sync error - recommend rewrite") },
1010 /* D W O */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1011 "Data sync error - data auto-reallocated") },
1012 /* D W O */{SST(0x16, 0x04, SS_RDEF,
1013 "Data sync error - recommend reassignment") },
1014 /* DT WRSO */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1015 "Recovered data with no error correction applied") },
1016 /* DT WRSO */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1017 "Recovered data with retries") },
1018 /* DT WR O */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE,
1019 "Recovered data with positive head offset") },
1020 /* DT WR O */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1021 "Recovered data with negative head offset") },
1022 /* WR O */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE,
1023 "Recovered data with retries and/or CIRC applied") },
1024 /* D WR O */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE,
1025 "Recovered data using previous sector id") },
1026 /* D W O */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE,
1027 "Recovered data without ECC - data auto-reallocated") },
1028 /* D W O */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE,
1029 "Recovered data without ECC - recommend reassignment")},
1030 /* D W O */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE,
1031 "Recovered data without ECC - recommend rewrite") },
1032 /* D W O */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE,
1033 "Recovered data without ECC - data rewritten") },
1034 /* D W O */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1035 "Recovered data with error correction applied") },
1036 /* D WR O */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1037 "Recovered data with error corr. & retries applied") },
1038 /* D WR O */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE,
1039 "Recovered data - data auto-reallocated") },
1040 /* R */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1041 "Recovered data with CIRC") },
1042 /* R */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE,
1043 "Recovered data with L-EC") },
1044 /* D WR O */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE,
1045 "Recovered data - recommend reassignment") },
1046 /* D WR O */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE,
1047 "Recovered data - recommend rewrite") },
1048 /* D W O */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE,
1049 "Recovered data with ECC - data rewritten") },
1050 /* D O */{SST(0x19, 0x00, SS_RDEF,
1051 "Defect list error") },
1052 /* D O */{SST(0x19, 0x01, SS_RDEF,
1053 "Defect list not available") },
1054 /* D O */{SST(0x19, 0x02, SS_RDEF,
1055 "Defect list error in primary list") },
1056 /* D O */{SST(0x19, 0x03, SS_RDEF,
1057 "Defect list error in grown list") },
1058 /* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF,
1059 "Parameter list length error") },
1060 /* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF,
1061 "Synchronous data transfer error") },
1062 /* D O */{SST(0x1C, 0x00, SS_RDEF,
1063 "Defect list not found") },
1064 /* D O */{SST(0x1C, 0x01, SS_RDEF,
1065 "Primary defect list not found") },
1066 /* D O */{SST(0x1C, 0x02, SS_RDEF,
1067 "Grown defect list not found") },
1068 /* D W O */{SST(0x1D, 0x00, SS_FATAL,
1069 "Miscompare during verify operation" )},
1070 /* D W O */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1071 "Recovered id with ecc correction") },
1072 /* D O */{SST(0x1F, 0x00, SS_RDEF,
1073 "Partial defect list transfer") },
1074 /* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL,
1075 "Invalid command operation code") },
1076 /* DT WR OM */{SST(0x21, 0x00, SS_FATAL|EINVAL,
1077 "Logical block address out of range" )},
1078 /* DT WR OM */{SST(0x21, 0x01, SS_FATAL|EINVAL,
1079 "Invalid element address") },
1080 /* D */{SST(0x22, 0x00, SS_FATAL|EINVAL,
1081 "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
1082 /* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL,
1083 "Invalid field in CDB") },
1084 /* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO,
1085 "Logical unit not supported") },
1086 /* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL,
1087 "Invalid field in parameter list") },
1088 /* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL,
1089 "Parameter not supported") },
1090 /* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL,
1091 "Parameter value invalid") },
1092 /* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL,
1093 "Threshold parameters not supported") },
1094 /* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL,
1095 "Invalid release of active persistent reservation") },
1096 /* DT W O */{SST(0x27, 0x00, SS_FATAL|EACCES,
1097 "Write protected") },
1098 /* DT W O */{SST(0x27, 0x01, SS_FATAL|EACCES,
1099 "Hardware write protected") },
1100 /* DT W O */{SST(0x27, 0x02, SS_FATAL|EACCES,
1101 "Logical unit software write protected") },
1102 /* T */{SST(0x27, 0x03, SS_FATAL|EACCES,
1103 "Associated write protect") },
1104 /* T */{SST(0x27, 0x04, SS_FATAL|EACCES,
1105 "Persistent write protect") },
1106 /* T */{SST(0x27, 0x05, SS_FATAL|EACCES,
1107 "Permanent write protect") },
1108 /* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_FATAL|ENXIO,
1109 "Not ready to ready change, medium may have changed") },
1110 /* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO,
1111 "Import or export element accessed") },
1113 * XXX JGibbs - All of these should use the same errno, but I don't think
1114 * ENXIO is the correct choice. Should we borrow from the networking
1115 * errnos? ECONNRESET anyone?
1117 /* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_FATAL|ENXIO,
1118 "Power on, reset, or bus device reset occurred") },
1119 /* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF,
1120 "Power on occurred") },
1121 /* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF,
1122 "Scsi bus reset occurred") },
1123 /* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF,
1124 "Bus device reset function occurred") },
1125 /* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF,
1126 "Device internal reset") },
1127 /* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF,
1128 "Transceiver mode changed to single-ended") },
1129 /* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF,
1130 "Transceiver mode changed to LVD") },
1131 /* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF,
1132 "Parameters changed") },
1133 /* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF,
1134 "Mode parameters changed") },
1135 /* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF,
1136 "Log parameters changed") },
1137 /* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF,
1138 "Reservations preempted") },
1139 /* DTLPWRSO C */{SST(0x2B, 0x00, SS_RDEF,
1140 "Copy cannot execute since host cannot disconnect") },
1141 /* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF,
1142 "Command sequence error") },
1143 /* S */{SST(0x2C, 0x01, SS_RDEF,
1144 "Too many windows specified") },
1145 /* S */{SST(0x2C, 0x02, SS_RDEF,
1146 "Invalid combination of windows specified") },
1147 /* R */{SST(0x2C, 0x03, SS_RDEF,
1148 "Current program area is not empty") },
1149 /* R */{SST(0x2C, 0x04, SS_RDEF,
1150 "Current program area is empty") },
1151 /* T */{SST(0x2D, 0x00, SS_RDEF,
1152 "Overwrite error on update in place") },
1153 /* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF,
1154 "Commands cleared by another initiator") },
1155 /* DT WR OM */{SST(0x30, 0x00, SS_RDEF,
1156 "Incompatible medium installed") },
1157 /* DT WR O */{SST(0x30, 0x01, SS_RDEF,
1158 "Cannot read medium - unknown format") },
1159 /* DT WR O */{SST(0x30, 0x02, SS_RDEF,
1160 "Cannot read medium - incompatible format") },
1161 /* DT */{SST(0x30, 0x03, SS_RDEF,
1162 "Cleaning cartridge installed") },
1163 /* DT WR O */{SST(0x30, 0x04, SS_RDEF,
1164 "Cannot write medium - unknown format") },
1165 /* DT WR O */{SST(0x30, 0x05, SS_RDEF,
1166 "Cannot write medium - incompatible format") },
1167 /* DT W O */{SST(0x30, 0x06, SS_RDEF,
1168 "Cannot format medium - incompatible medium") },
1169 /* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF,
1170 "Cleaning failure") },
1171 /* R */{SST(0x30, 0x08, SS_RDEF,
1172 "Cannot write - application code mismatch") },
1173 /* R */{SST(0x30, 0x09, SS_RDEF,
1174 "Current session not fixated for append") },
1175 /* DT WR O */{SST(0x31, 0x00, SS_RDEF,
1176 "Medium format corrupted") },
1177 /* D L R O */{SST(0x31, 0x01, SS_RDEF,
1178 "Format command failed") },
1179 /* D W O */{SST(0x32, 0x00, SS_RDEF,
1180 "No defect spare location available") },
1181 /* D W O */{SST(0x32, 0x01, SS_RDEF,
1182 "Defect list update failure") },
1183 /* T */{SST(0x33, 0x00, SS_RDEF,
1184 "Tape length error") },
1185 /* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF,
1186 "Enclosure failure") },
1187 /* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF,
1188 "Enclosure services failure") },
1189 /* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF,
1190 "Unsupported enclosure function") },
1191 /* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF,
1192 "Enclosure services unavailable") },
1193 /* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF,
1194 "Enclosure services transfer failure") },
1195 /* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF,
1196 "Enclosure services transfer refused") },
1197 /* L */{SST(0x36, 0x00, SS_RDEF,
1198 "Ribbon, ink, or toner failure") },
1199 /* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF,
1200 "Rounded parameter") },
1201 /* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF,
1202 "Saving parameters not supported") },
1203 /* DTL WRSOM */{SST(0x3A, 0x00, SS_FATAL|ENXIO,
1204 "Medium not present") },
1205 /* DT WR OM */{SST(0x3A, 0x01, SS_FATAL|ENXIO,
1206 "Medium not present - tray closed") },
1207 /* DT WR OM */{SST(0x3A, 0x02, SS_FATAL|ENXIO,
1208 "Medium not present - tray open") },
1209 /* TL */{SST(0x3B, 0x00, SS_RDEF,
1210 "Sequential positioning error") },
1211 /* T */{SST(0x3B, 0x01, SS_RDEF,
1212 "Tape position error at beginning-of-medium") },
1213 /* T */{SST(0x3B, 0x02, SS_RDEF,
1214 "Tape position error at end-of-medium") },
1215 /* L */{SST(0x3B, 0x03, SS_RDEF,
1216 "Tape or electronic vertical forms unit not ready") },
1217 /* L */{SST(0x3B, 0x04, SS_RDEF,
1219 /* L */{SST(0x3B, 0x05, SS_RDEF,
1221 /* L */{SST(0x3B, 0x06, SS_RDEF,
1222 "Failed to sense top-of-form") },
1223 /* L */{SST(0x3B, 0x07, SS_RDEF,
1224 "Failed to sense bottom-of-form") },
1225 /* T */{SST(0x3B, 0x08, SS_RDEF,
1226 "Reposition error") },
1227 /* S */{SST(0x3B, 0x09, SS_RDEF,
1228 "Read past end of medium") },
1229 /* S */{SST(0x3B, 0x0A, SS_RDEF,
1230 "Read past beginning of medium") },
1231 /* S */{SST(0x3B, 0x0B, SS_RDEF,
1232 "Position past end of medium") },
1233 /* T S */{SST(0x3B, 0x0C, SS_RDEF,
1234 "Position past beginning of medium") },
1235 /* DT WR OM */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC,
1236 "Medium destination element full") },
1237 /* DT WR OM */{SST(0x3B, 0x0E, SS_RDEF,
1238 "Medium source element empty") },
1239 /* R */{SST(0x3B, 0x0F, SS_RDEF,
1240 "End of medium reached") },
1241 /* DT WR OM */{SST(0x3B, 0x11, SS_RDEF,
1242 "Medium magazine not accessible") },
1243 /* DT WR OM */{SST(0x3B, 0x12, SS_RDEF,
1244 "Medium magazine removed") },
1245 /* DT WR OM */{SST(0x3B, 0x13, SS_RDEF,
1246 "Medium magazine inserted") },
1247 /* DT WR OM */{SST(0x3B, 0x14, SS_RDEF,
1248 "Medium magazine locked") },
1249 /* DT WR OM */{SST(0x3B, 0x15, SS_RDEF,
1250 "Medium magazine unlocked") },
1251 /* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF,
1252 "Invalid bits in identify message") },
1253 /* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF,
1254 "Logical unit has not self-configured yet") },
1255 /* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF,
1256 "Logical unit failure") },
1257 /* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF,
1258 "Timeout on logical unit") },
1259 /* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF,
1260 "Target operating conditions have changed") },
1261 /* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF,
1262 "Microcode has been changed") },
1263 /* DTLPWRSOMC */{SST(0x3F, 0x02, SS_RDEF,
1264 "Changed operating definition") },
1265 /* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_RDEF,
1266 "Inquiry data has changed") },
1267 /* DT WR OMCAE */{SST(0x3F, 0x04, SS_RDEF,
1268 "Component device attached") },
1269 /* DT WR OMCAE */{SST(0x3F, 0x05, SS_RDEF,
1270 "Device identifier changed") },
1271 /* DT WR OMCAE */{SST(0x3F, 0x06, SS_RDEF,
1272 "Redundancy group created or modified") },
1273 /* DT WR OMCAE */{SST(0x3F, 0x07, SS_RDEF,
1274 "Redundancy group deleted") },
1275 /* DT WR OMCAE */{SST(0x3F, 0x08, SS_RDEF,
1276 "Spare created or modified") },
1277 /* DT WR OMCAE */{SST(0x3F, 0x09, SS_RDEF,
1279 /* DT WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF,
1280 "Volume set created or modified") },
1281 /* DT WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF,
1282 "Volume set deleted") },
1283 /* DT WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF,
1284 "Volume set deassigned") },
1285 /* DT WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF,
1286 "Volume set reassigned") },
1287 /* D */{SST(0x40, 0x00, SS_RDEF,
1288 "Ram failure") }, /* deprecated - use 40 NN instead */
1289 /* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF,
1290 "Diagnostic failure: ASCQ = Component ID") },
1291 /* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE,
1292 NULL) },/* Range 0x80->0xFF */
1293 /* D */{SST(0x41, 0x00, SS_RDEF,
1294 "Data path failure") }, /* deprecated - use 40 NN instead */
1295 /* D */{SST(0x42, 0x00, SS_RDEF,
1296 "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
1297 /* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF,
1299 /* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF,
1300 "Internal target failure") },
1301 /* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF,
1302 "Select or reselect failure") },
1303 /* DTLPWRSOMC */{SST(0x46, 0x00, SS_RDEF,
1304 "Unsuccessful soft reset") },
1305 /* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF,
1306 "SCSI parity error") },
1307 /* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF,
1308 "Initiator detected error message received") },
1309 /* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF,
1310 "Invalid message error") },
1311 /* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF,
1312 "Command phase error") },
1313 /* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF,
1314 "Data phase error") },
1315 /* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF,
1316 "Logical unit failed self-configuration") },
1317 /* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF,
1318 "Tagged overlapped commands: ASCQ = Queue tag ID") },
1319 /* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE,
1320 NULL)}, /* Range 0x00->0xFF */
1321 /* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF,
1322 "Overlapped commands attempted") },
1323 /* T */{SST(0x50, 0x00, SS_RDEF,
1324 "Write append error") },
1325 /* T */{SST(0x50, 0x01, SS_RDEF,
1326 "Write append position error") },
1327 /* T */{SST(0x50, 0x02, SS_RDEF,
1328 "Position error related to timing") },
1329 /* T O */{SST(0x51, 0x00, SS_RDEF,
1331 /* T */{SST(0x52, 0x00, SS_RDEF,
1332 "Cartridge fault") },
1333 /* DTL WRSOM */{SST(0x53, 0x00, SS_RDEF,
1334 "Media load or eject failed") },
1335 /* T */{SST(0x53, 0x01, SS_RDEF,
1336 "Unload tape failure") },
1337 /* DT WR OM */{SST(0x53, 0x02, SS_RDEF,
1338 "Medium removal prevented") },
1339 /* P */{SST(0x54, 0x00, SS_RDEF,
1340 "Scsi to host system interface failure") },
1341 /* P */{SST(0x55, 0x00, SS_RDEF,
1342 "System resource failure") },
1343 /* D O */{SST(0x55, 0x01, SS_FATAL|ENOSPC,
1344 "System buffer full") },
1345 /* R */{SST(0x57, 0x00, SS_RDEF,
1346 "Unable to recover table-of-contents") },
1347 /* O */{SST(0x58, 0x00, SS_RDEF,
1348 "Generation does not exist") },
1349 /* O */{SST(0x59, 0x00, SS_RDEF,
1350 "Updated block read") },
1351 /* DTLPWRSOM */{SST(0x5A, 0x00, SS_RDEF,
1352 "Operator request or state change input") },
1353 /* DT WR OM */{SST(0x5A, 0x01, SS_RDEF,
1354 "Operator medium removal request") },
1355 /* DT W O */{SST(0x5A, 0x02, SS_RDEF,
1356 "Operator selected write protect") },
1357 /* DT W O */{SST(0x5A, 0x03, SS_RDEF,
1358 "Operator selected write permit") },
1359 /* DTLPWRSOM */{SST(0x5B, 0x00, SS_RDEF,
1361 /* DTLPWRSOM */{SST(0x5B, 0x01, SS_RDEF,
1362 "Threshold condition met") },
1363 /* DTLPWRSOM */{SST(0x5B, 0x02, SS_RDEF,
1364 "Log counter at maximum") },
1365 /* DTLPWRSOM */{SST(0x5B, 0x03, SS_RDEF,
1366 "Log list codes exhausted") },
1367 /* D O */{SST(0x5C, 0x00, SS_RDEF,
1368 "RPL status change") },
1369 /* D O */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1370 "Spindles synchronized") },
1371 /* D O */{SST(0x5C, 0x02, SS_RDEF,
1372 "Spindles not synchronized") },
1373 /* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF,
1374 "Failure prediction threshold exceeded") },
1375 /* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF,
1376 "Failure prediction threshold exceeded (false)") },
1377 /* DTLPWRSO CA */{SST(0x5E, 0x00, SS_RDEF,
1378 "Low power condition on") },
1379 /* DTLPWRSO CA */{SST(0x5E, 0x01, SS_RDEF,
1380 "Idle condition activated by timer") },
1381 /* DTLPWRSO CA */{SST(0x5E, 0x02, SS_RDEF,
1382 "Standby condition activated by timer") },
1383 /* DTLPWRSO CA */{SST(0x5E, 0x03, SS_RDEF,
1384 "Idle condition activated by command") },
1385 /* DTLPWRSO CA */{SST(0x5E, 0x04, SS_RDEF,
1386 "Standby condition activated by command") },
1387 /* S */{SST(0x60, 0x00, SS_RDEF,
1389 /* S */{SST(0x61, 0x00, SS_RDEF,
1390 "Video acquisition error") },
1391 /* S */{SST(0x61, 0x01, SS_RDEF,
1392 "Unable to acquire video") },
1393 /* S */{SST(0x61, 0x02, SS_RDEF,
1395 /* S */{SST(0x62, 0x00, SS_RDEF,
1396 "Scan head positioning error") },
1397 /* R */{SST(0x63, 0x00, SS_RDEF,
1398 "End of user area encountered on this track") },
1399 /* R */{SST(0x63, 0x01, SS_FATAL|ENOSPC,
1400 "Packet does not fit in available space") },
1401 /* R */{SST(0x64, 0x00, SS_RDEF,
1402 "Illegal mode for this track") },
1403 /* R */{SST(0x64, 0x01, SS_RDEF,
1404 "Invalid packet size") },
1405 /* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF,
1407 /* S */{SST(0x66, 0x00, SS_RDEF,
1408 "Automatic document feeder cover up") },
1409 /* S */{SST(0x66, 0x01, SS_RDEF,
1410 "Automatic document feeder lift up") },
1411 /* S */{SST(0x66, 0x02, SS_RDEF,
1412 "Document jam in automatic document feeder") },
1413 /* S */{SST(0x66, 0x03, SS_RDEF,
1414 "Document miss feed automatic in document feeder") },
1415 /* A */{SST(0x67, 0x00, SS_RDEF,
1416 "Configuration failure") },
1417 /* A */{SST(0x67, 0x01, SS_RDEF,
1418 "Configuration of incapable logical units failed") },
1419 /* A */{SST(0x67, 0x02, SS_RDEF,
1420 "Add logical unit failed") },
1421 /* A */{SST(0x67, 0x03, SS_RDEF,
1422 "Modification of logical unit failed") },
1423 /* A */{SST(0x67, 0x04, SS_RDEF,
1424 "Exchange of logical unit failed") },
1425 /* A */{SST(0x67, 0x05, SS_RDEF,
1426 "Remove of logical unit failed") },
1427 /* A */{SST(0x67, 0x06, SS_RDEF,
1428 "Attachment of logical unit failed") },
1429 /* A */{SST(0x67, 0x07, SS_RDEF,
1430 "Creation of logical unit failed") },
1431 /* A */{SST(0x68, 0x00, SS_RDEF,
1432 "Logical unit not configured") },
1433 /* A */{SST(0x69, 0x00, SS_RDEF,
1434 "Data loss on logical unit") },
1435 /* A */{SST(0x69, 0x01, SS_RDEF,
1436 "Multiple logical unit failures") },
1437 /* A */{SST(0x69, 0x02, SS_RDEF,
1438 "Parity/data mismatch") },
1439 /* A */{SST(0x6A, 0x00, SS_RDEF,
1440 "Informational, refer to log") },
1441 /* A */{SST(0x6B, 0x00, SS_RDEF,
1442 "State change has occurred") },
1443 /* A */{SST(0x6B, 0x01, SS_RDEF,
1444 "Redundancy level got better") },
1445 /* A */{SST(0x6B, 0x02, SS_RDEF,
1446 "Redundancy level got worse") },
1447 /* A */{SST(0x6C, 0x00, SS_RDEF,
1448 "Rebuild failure occurred") },
1449 /* A */{SST(0x6D, 0x00, SS_RDEF,
1450 "Recalculate failure occurred") },
1451 /* A */{SST(0x6E, 0x00, SS_RDEF,
1452 "Command to logical unit failed") },
1453 /* T */{SST(0x70, 0x00, SS_RDEF,
1454 "Decompression exception short: ASCQ = Algorithm ID") },
1455 /* T */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE,
1456 NULL) }, /* Range 0x00 -> 0xFF */
1457 /* T */{SST(0x71, 0x00, SS_RDEF,
1458 "Decompression exception long: ASCQ = Algorithm ID") },
1459 /* T */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE,
1460 NULL) }, /* Range 0x00 -> 0xFF */
1461 /* R */{SST(0x72, 0x00, SS_RDEF,
1462 "Session fixation error") },
1463 /* R */{SST(0x72, 0x01, SS_RDEF,
1464 "Session fixation error writing lead-in") },
1465 /* R */{SST(0x72, 0x02, SS_RDEF,
1466 "Session fixation error writing lead-out") },
1467 /* R */{SST(0x72, 0x03, SS_RDEF,
1468 "Session fixation error - incomplete track in session") },
1469 /* R */{SST(0x72, 0x04, SS_RDEF,
1470 "Empty or partially written reserved track") },
1471 /* R */{SST(0x73, 0x00, SS_RDEF,
1472 "CD control error") },
1473 /* R */{SST(0x73, 0x01, SS_RDEF,
1474 "Power calibration area almost full") },
1475 /* R */{SST(0x73, 0x02, SS_FATAL|ENOSPC,
1476 "Power calibration area is full") },
1477 /* R */{SST(0x73, 0x03, SS_RDEF,
1478 "Power calibration area error") },
1479 /* R */{SST(0x73, 0x04, SS_RDEF,
1480 "Program memory area update failure") },
1481 /* R */{SST(0x73, 0x05, SS_RDEF,
1482 "program memory area is full") }
1485 const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
1494 ascentrycomp(const void *key, const void *member)
1498 const struct asc_table_entry *table_entry;
1500 asc = ((const struct asc_key *)key)->asc;
1501 ascq = ((const struct asc_key *)key)->ascq;
1502 table_entry = (const struct asc_table_entry *)member;
1504 if (asc >= table_entry->asc) {
1506 if (asc > table_entry->asc)
1509 if (ascq <= table_entry->ascq) {
1510 /* Check for ranges */
1511 if (ascq == table_entry->ascq
1512 || ((table_entry->action & SSQ_RANGE) != 0
1513 && ascq >= (table_entry - 1)->ascq))
1523 senseentrycomp(const void *key, const void *member)
1526 const struct sense_key_table_entry *table_entry;
1528 sense_key = *((const int *)key);
1529 table_entry = (const struct sense_key_table_entry *)member;
1531 if (sense_key >= table_entry->sense_key) {
1532 if (sense_key == table_entry->sense_key)
1540 fetchtableentries(int sense_key, int asc, int ascq,
1541 struct scsi_inquiry_data *inq_data,
1542 const struct sense_key_table_entry **sense_entry,
1543 const struct asc_table_entry **asc_entry)
1546 const struct asc_table_entry *asc_tables[2];
1547 const struct sense_key_table_entry *sense_tables[2];
1548 struct asc_key asc_ascq;
1549 size_t asc_tables_size[2];
1550 size_t sense_tables_size[2];
1552 int num_sense_tables;
1555 /* Default to failure */
1556 *sense_entry = NULL;
1559 if (inq_data != NULL)
1560 match = cam_quirkmatch((caddr_t)inq_data,
1561 (caddr_t)sense_quirk_table,
1562 sense_quirk_table_size,
1563 sizeof(*sense_quirk_table),
1564 scsi_inquiry_match);
1566 if (match != NULL) {
1567 struct scsi_sense_quirk_entry *quirk;
1569 quirk = (struct scsi_sense_quirk_entry *)match;
1570 asc_tables[0] = quirk->asc_info;
1571 asc_tables_size[0] = quirk->num_ascs;
1572 asc_tables[1] = asc_table;
1573 asc_tables_size[1] = asc_table_size;
1575 sense_tables[0] = quirk->sense_key_info;
1576 sense_tables_size[0] = quirk->num_sense_keys;
1577 sense_tables[1] = sense_key_table;
1578 sense_tables_size[1] = sense_key_table_size;
1579 num_sense_tables = 2;
1581 asc_tables[0] = asc_table;
1582 asc_tables_size[0] = asc_table_size;
1584 sense_tables[0] = sense_key_table;
1585 sense_tables_size[0] = sense_key_table_size;
1586 num_sense_tables = 1;
1590 asc_ascq.ascq = ascq;
1591 for (i = 0; i < num_asc_tables; i++) {
1594 found_entry = bsearch(&asc_ascq, asc_tables[i],
1596 sizeof(**asc_tables),
1600 *asc_entry = (struct asc_table_entry *)found_entry;
1605 for (i = 0; i < num_sense_tables; i++) {
1608 found_entry = bsearch(&sense_key, sense_tables[i],
1609 sense_tables_size[i],
1610 sizeof(**sense_tables),
1615 (struct sense_key_table_entry *)found_entry;
1622 scsi_sense_desc(int sense_key, int asc, int ascq,
1623 struct scsi_inquiry_data *inq_data,
1624 const char **sense_key_desc, const char **asc_desc)
1626 const struct asc_table_entry *asc_entry;
1627 const struct sense_key_table_entry *sense_entry;
1629 fetchtableentries(sense_key, asc, ascq,
1634 *sense_key_desc = sense_entry->desc;
1636 if (asc_entry != NULL)
1637 *asc_desc = asc_entry->desc;
1638 else if (asc >= 0x80 && asc <= 0xff)
1639 *asc_desc = "Vendor Specific ASC";
1640 else if (ascq >= 0x80 && ascq <= 0xff)
1641 *asc_desc = "Vendor Specific ASCQ";
1643 *asc_desc = "Reserved ASC/ASCQ pair";
1647 * Given sense and device type information, return the appropriate action.
1648 * If we do not understand the specific error as identified by the ASC/ASCQ
1649 * pair, fall back on the more generic actions derived from the sense key.
1652 scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
1653 u_int32_t sense_flags)
1655 const struct asc_table_entry *asc_entry;
1656 const struct sense_key_table_entry *sense_entry;
1657 int error_code, sense_key, asc, ascq;
1658 scsi_sense_action action;
1660 scsi_extract_sense(&csio->sense_data, &error_code,
1661 &sense_key, &asc, &ascq);
1663 if (error_code == SSD_DEFERRED_ERROR) {
1665 * XXX dufault@FreeBSD.org
1666 * This error doesn't relate to the command associated
1667 * with this request sense. A deferred error is an error
1668 * for a command that has already returned GOOD status
1669 * (see SCSI2 8.2.14.2).
1671 * By my reading of that section, it looks like the current
1672 * command has been cancelled, we should now clean things up
1673 * (hopefully recovering any lost data) and then retry the
1674 * current command. There are two easy choices, both wrong:
1676 * 1. Drop through (like we had been doing), thus treating
1677 * this as if the error were for the current command and
1678 * return and stop the current command.
1680 * 2. Issue a retry (like I made it do) thus hopefully
1681 * recovering the current transfer, and ignoring the
1682 * fact that we've dropped a command.
1684 * These should probably be handled in a device specific
1685 * sense handler or punted back up to a user mode daemon
1687 action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
1689 fetchtableentries(sense_key, asc, ascq,
1695 * Override the 'No additional Sense' entry (0,0)
1696 * with the error action of the sense key.
1698 if (asc_entry != NULL
1699 && (asc != 0 || ascq != 0))
1700 action = asc_entry->action;
1702 action = sense_entry->action;
1704 if (sense_key == SSD_KEY_RECOVERED_ERROR) {
1706 * The action succeeded but the device wants
1707 * the user to know that some recovery action
1710 action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK);
1711 action |= SS_NOP|SSQ_PRINT_SENSE;
1712 } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) {
1713 if ((sense_flags & SF_QUIET_IR) != 0)
1714 action &= ~SSQ_PRINT_SENSE;
1715 } else if (sense_key == SSD_KEY_UNIT_ATTENTION) {
1716 if ((sense_flags & SF_RETRY_UA) != 0
1717 && (action & SS_MASK) == SS_FAIL) {
1718 action &= ~(SS_MASK|SSQ_MASK);
1719 action |= SS_RETRY|SSQ_DECREMENT_COUNT|
1726 sense_flags |= SF_PRINT_ALWAYS;
1728 if ((sense_flags & SF_PRINT_ALWAYS) != 0)
1729 action |= SSQ_PRINT_SENSE;
1730 else if ((sense_flags & SF_NO_PRINT) != 0)
1731 action &= ~SSQ_PRINT_SENSE;
1737 scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
1742 if (cdb_ptr == NULL)
1745 /* Silence warnings */
1749 * This is taken from the SCSI-3 draft spec.
1750 * (T10/1157D revision 0.3)
1751 * The top 3 bits of an opcode are the group code. The next 5 bits
1752 * are the command code.
1753 * Group 0: six byte commands
1754 * Group 1: ten byte commands
1755 * Group 2: ten byte commands
1757 * Group 4: sixteen byte commands
1758 * Group 5: twelve byte commands
1759 * Group 6: vendor specific
1760 * Group 7: vendor specific
1762 switch((*cdb_ptr >> 5) & 0x7) {
1773 /* in this case, just print out the opcode */
1784 for (i = 0; i < cdb_len; i++)
1785 ksnprintf(cdb_string + strlen(cdb_string),
1786 len - strlen(cdb_string), "%x ", cdb_ptr[i]);
1792 scsi_status_string(struct ccb_scsiio *csio)
1794 switch(csio->scsi_status) {
1795 case SCSI_STATUS_OK:
1797 case SCSI_STATUS_CHECK_COND:
1798 return("Check Condition");
1799 case SCSI_STATUS_BUSY:
1801 case SCSI_STATUS_INTERMED:
1802 return("Intermediate");
1803 case SCSI_STATUS_INTERMED_COND_MET:
1804 return("Intermediate-Condition Met");
1805 case SCSI_STATUS_RESERV_CONFLICT:
1806 return("Reservation Conflict");
1807 case SCSI_STATUS_CMD_TERMINATED:
1808 return("Command Terminated");
1809 case SCSI_STATUS_QUEUE_FULL:
1810 return("Queue Full");
1811 case SCSI_STATUS_ACA_ACTIVE:
1812 return("ACA Active");
1813 case SCSI_STATUS_TASK_ABORTED:
1814 return("Task Aborted");
1816 static char unkstr[64];
1817 ksnprintf(unkstr, sizeof(unkstr), "Unknown %#x",
1825 * scsi_command_string() returns 0 for success and -1 for failure.
1829 scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb)
1832 scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
1836 struct scsi_inquiry_data *inq_data;
1837 char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
1839 struct ccb_getdev cgd;
1844 * Get the device information.
1846 xpt_setup_ccb(&cgd.ccb_h,
1849 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1850 xpt_action((union ccb *)&cgd);
1853 * If the device is unconfigured, just pretend that it is a hard
1854 * drive. scsi_op_desc() needs this.
1856 if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
1857 cgd.inq_data.device = T_DIRECT;
1859 inq_data = &cgd.inq_data;
1861 #else /* !_KERNEL */
1863 inq_data = &device->inq_data;
1865 #endif /* _KERNEL/!_KERNEL */
1867 if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1868 sbuf_printf(sb, "%s. CDB: %s",
1869 scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data),
1870 scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str,
1873 sbuf_printf(sb, "%s. CDB: %s",
1874 scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data),
1875 scsi_cdb_string(csio->cdb_io.cdb_bytes, cdb_str,
1883 * scsi_sense_sbuf() returns 0 for success and -1 for failure.
1887 scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb,
1888 scsi_sense_string_flags flags)
1889 #else /* !_KERNEL */
1891 scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
1892 struct sbuf *sb, scsi_sense_string_flags flags)
1893 #endif /* _KERNEL/!_KERNEL */
1895 struct scsi_sense_data *sense;
1896 struct scsi_inquiry_data *inq_data;
1898 struct ccb_getdev cgd;
1899 #endif /* _KERNEL */
1909 #endif /* !_KERNEL */
1910 if ((csio == NULL) || (sb == NULL))
1914 * If the CDB is a physical address, we can't deal with it..
1916 if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0)
1917 flags &= ~SSS_FLAG_PRINT_COMMAND;
1920 xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str));
1921 #else /* !_KERNEL */
1922 cam_path_string(device, path_str, sizeof(path_str));
1923 #endif /* _KERNEL/!_KERNEL */
1927 * Get the device information.
1929 xpt_setup_ccb(&cgd.ccb_h,
1932 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1933 xpt_action((union ccb *)&cgd);
1936 * If the device is unconfigured, just pretend that it is a hard
1937 * drive. scsi_op_desc() needs this.
1939 if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
1940 cgd.inq_data.device = T_DIRECT;
1942 inq_data = &cgd.inq_data;
1944 #else /* !_KERNEL */
1946 inq_data = &device->inq_data;
1948 #endif /* _KERNEL/!_KERNEL */
1952 if (flags & SSS_FLAG_PRINT_COMMAND) {
1954 sbuf_cat(sb, path_str);
1957 scsi_command_string(csio, sb);
1958 #else /* !_KERNEL */
1959 scsi_command_string(device, csio, sb);
1960 #endif /* _KERNEL/!_KERNEL */
1964 * If the sense data is a physical pointer, forget it.
1966 if (csio->ccb_h.flags & CAM_SENSE_PTR) {
1967 if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1971 * bcopy the pointer to avoid unaligned access
1972 * errors on finicky architectures. We don't
1973 * ensure that the sense data is pointer aligned.
1975 bcopy(&csio->sense_data, &sense,
1976 sizeof(struct scsi_sense_data *));
1980 * If the physical sense flag is set, but the sense pointer
1981 * is not also set, we assume that the user is an idiot and
1982 * return. (Well, okay, it could be that somehow, the
1983 * entire csio is physical, but we would have probably core
1984 * dumped on one of the bogus pointer deferences above
1987 if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1990 sense = &csio->sense_data;
1994 sbuf_cat(sb, path_str);
1996 error_code = sense->error_code & SSD_ERRCODE;
1997 sense_key = sense->flags & SSD_KEY;
1999 switch (error_code) {
2000 case SSD_DEFERRED_ERROR:
2001 sbuf_printf(sb, "Deferred Error: ");
2004 case SSD_CURRENT_ERROR:
2006 const char *sense_key_desc;
2007 const char *asc_desc;
2009 asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
2010 ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
2011 scsi_sense_desc(sense_key, asc, ascq, inq_data,
2012 &sense_key_desc, &asc_desc);
2013 sbuf_cat(sb, sense_key_desc);
2015 info = scsi_4btoul(sense->info);
2017 if (sense->error_code & SSD_ERRCODE_VALID) {
2019 switch (sense_key) {
2020 case SSD_KEY_NOT_READY:
2021 case SSD_KEY_ILLEGAL_REQUEST:
2022 case SSD_KEY_UNIT_ATTENTION:
2023 case SSD_KEY_DATA_PROTECT:
2025 case SSD_KEY_BLANK_CHECK:
2026 sbuf_printf(sb, " req sz: %d (decimal)", info);
2030 if (sense->flags & SSD_ILI) {
2031 sbuf_printf(sb, " ILI (length "
2032 "mismatch): %d", info);
2035 sbuf_printf(sb, " info:%x",
2041 sbuf_printf(sb, " info?:%x", info);
2044 if (sense->extra_len >= 4) {
2045 if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
2046 sbuf_printf(sb, " csi:%x,%x,%x,%x",
2047 sense->cmd_spec_info[0],
2048 sense->cmd_spec_info[1],
2049 sense->cmd_spec_info[2],
2050 sense->cmd_spec_info[3]);
2054 sbuf_printf(sb, " asc:%x,%x\n%s%s", asc, ascq,
2055 path_str, asc_desc);
2057 if (sense->extra_len >= 7 && sense->fru) {
2058 sbuf_printf(sb, " field replaceable unit: %x",
2062 if ((sense->extra_len >= 10)
2063 && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
2065 case SSD_KEY_ILLEGAL_REQUEST: {
2069 if (sense->sense_key_spec[0] & 0x40)
2076 /* Bit pointer is valid */
2077 if (sense->sense_key_spec[0] & 0x08)
2078 ksnprintf(tmpstr2, sizeof(tmpstr2),
2080 sense->sense_key_spec[0] & 0x7);
2082 ": %s byte %d %s is invalid",
2086 &sense->sense_key_spec[1]),
2090 case SSD_KEY_RECOVERED_ERROR:
2091 case SSD_KEY_HARDWARE_ERROR:
2092 case SSD_KEY_MEDIUM_ERROR:
2093 sbuf_printf(sb, " actual retry count: %d",
2095 &sense->sense_key_spec[1]));
2098 sbuf_printf(sb, " sks:%#x,%#x",
2099 sense->sense_key_spec[0],
2101 &sense->sense_key_spec[1]));
2109 sbuf_printf(sb, "error code %d",
2110 sense->error_code & SSD_ERRCODE);
2112 if (sense->error_code & SSD_ERRCODE_VALID) {
2113 sbuf_printf(sb, " at block no. %d (decimal)",
2114 info = scsi_4btoul(sense->info));
2118 sbuf_printf(sb, "\n");
2125 scsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len)
2126 #else /* !_KERNEL */
2128 scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio,
2129 char *str, int str_len)
2130 #endif /* _KERNEL/!_KERNEL */
2134 sbuf_new(&sb, str, str_len, 0);
2137 scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND);
2138 #else /* !_KERNEL */
2139 scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND);
2140 #endif /* _KERNEL/!_KERNEL */
2144 return(sbuf_data(&sb));
2149 scsi_sense_print(struct ccb_scsiio *csio)
2154 sbuf_new(&sb, str, sizeof(str), 0);
2156 scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND);
2160 kprintf("%s", sbuf_data(&sb));
2163 #else /* !_KERNEL */
2165 scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio,
2171 if ((device == NULL) || (csio == NULL) || (ofile == NULL))
2174 sbuf_new(&sb, str, sizeof(str), 0);
2176 scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND);
2180 fprintf(ofile, "%s", sbuf_data(&sb));
2183 #endif /* _KERNEL/!_KERNEL */
2186 * This function currently requires at least 36 bytes, or
2187 * SHORT_INQUIRY_LENGTH, worth of data to function properly. If this
2188 * function needs more or less data in the future, another length should be
2189 * defined in scsi_all.h to indicate the minimum amount of data necessary
2190 * for this routine to function properly.
2193 scsi_print_inquiry(struct scsi_inquiry_data *inq_data)
2196 char *dtype, *qtype;
2197 char vendor[16], product[48], revision[16], rstr[4];
2199 type = SID_TYPE(inq_data);
2202 * Figure out basic device type and qualifier.
2204 if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) {
2205 qtype = "(vendor-unique qualifier)";
2207 switch (SID_QUAL(inq_data)) {
2208 case SID_QUAL_LU_CONNECTED:
2212 case SID_QUAL_LU_OFFLINE:
2213 qtype = "(offline)";
2217 qtype = "(reserved qualifier)";
2220 case SID_QUAL_BAD_LU:
2221 qtype = "(lun not supported)";
2228 dtype = "Direct Access";
2231 dtype = "Sequential Access";
2237 dtype = "Processor";
2255 dtype = "Communication";
2258 dtype = "Storage Array";
2261 dtype = "Enclosure Services";
2264 dtype = "Simplified Direct Access";
2267 dtype = "Optical Card Read/Write";
2270 dtype = "Uninstalled";
2276 cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor),
2278 cam_strvis(product, inq_data->product, sizeof(inq_data->product),
2280 cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision),
2283 if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS)
2284 bcopy("CCS", rstr, 4);
2286 ksnprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data));
2287 kprintf("<%s %s %s> %s %s SCSI-%s device %s\n",
2288 vendor, product, revision,
2289 SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed",
2290 dtype, rstr, qtype);
2294 * Table of syncrates that don't follow the "divisible by 4"
2295 * rule. This table will be expanded in future SCSI specs.
2298 u_int period_factor;
2299 u_int period; /* in 100ths of ns */
2300 } scsi_syncrates[] = {
2301 { 0x08, 625 }, /* FAST-160 */
2302 { 0x09, 1250 }, /* FAST-80 */
2303 { 0x0a, 2500 }, /* FAST-40 40MHz */
2304 { 0x0b, 3030 }, /* FAST-40 33MHz */
2305 { 0x0c, 5000 } /* FAST-20 */
2309 * Return the frequency in kHz corresponding to the given
2310 * sync period factor.
2313 scsi_calc_syncsrate(u_int period_factor)
2318 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2319 /* See if the period is in the "exception" table */
2320 for (i = 0; i < num_syncrates; i++) {
2322 if (period_factor == scsi_syncrates[i].period_factor) {
2324 return (100000000 / scsi_syncrates[i].period);
2329 * Wasn't in the table, so use the standard
2330 * 4 times conversion.
2332 return (10000000 / (period_factor * 4 * 10));
2336 * Return the SCSI sync parameter that corresponsd to
2337 * the passed in period in 10ths of ns.
2340 scsi_calc_syncparam(u_int period)
2346 return (~0); /* Async */
2348 /* Adjust for exception table being in 100ths. */
2350 num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2351 /* See if the period is in the "exception" table */
2352 for (i = 0; i < num_syncrates; i++) {
2354 if (period <= scsi_syncrates[i].period) {
2355 /* Period in 100ths of ns */
2356 return (scsi_syncrates[i].period_factor);
2361 * Wasn't in the table, so use the standard
2362 * 1/4 period in ns conversion.
2364 return (period/400);
2368 scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
2369 void (*cbfcnp)(struct cam_periph *, union ccb *),
2370 u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout)
2372 struct scsi_test_unit_ready *scsi_cmd;
2385 scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes;
2386 bzero(scsi_cmd, sizeof(*scsi_cmd));
2387 scsi_cmd->opcode = TEST_UNIT_READY;
2391 scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
2392 void (*cbfcnp)(struct cam_periph *, union ccb *),
2393 void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action,
2394 u_int8_t sense_len, u_int32_t timeout)
2396 struct scsi_request_sense *scsi_cmd;
2409 scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes;
2410 bzero(scsi_cmd, sizeof(*scsi_cmd));
2411 scsi_cmd->opcode = REQUEST_SENSE;
2412 scsi_cmd->length = dxfer_len;
2416 scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
2417 void (*cbfcnp)(struct cam_periph *, union ccb *),
2418 u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len,
2419 int evpd, u_int8_t page_code, u_int8_t sense_len,
2422 struct scsi_inquiry *scsi_cmd;
2427 /*flags*/CAM_DIR_IN,
2429 /*data_ptr*/inq_buf,
2430 /*dxfer_len*/inq_len,
2435 scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes;
2436 bzero(scsi_cmd, sizeof(*scsi_cmd));
2437 scsi_cmd->opcode = INQUIRY;
2439 scsi_cmd->byte2 |= SI_EVPD;
2440 scsi_cmd->page_code = page_code;
2443 * A 'transfer units' count of 256 is coded as
2444 * zero for all commands with a single byte count
2449 scsi_cmd->length = inq_len;
2453 scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
2454 void (*cbfcnp)(struct cam_periph *, union ccb *),
2455 u_int8_t tag_action, int dbd, u_int8_t page_code,
2456 u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2457 u_int8_t sense_len, u_int32_t timeout)
2459 return(scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd,
2460 page_code, page, param_buf, param_len, 0,
2461 sense_len, timeout));
2465 scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries,
2466 void (*cbfcnp)(struct cam_periph *, union ccb *),
2467 u_int8_t tag_action, int dbd, u_int8_t page_code,
2468 u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2469 int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout)
2474 * Use the smallest possible command to perform the operation.
2476 if ((param_len < 256) && (minimum_cmd_size < 10)) {
2478 * We can fit in a 6 byte cdb.
2480 struct scsi_mode_sense_6 *scsi_cmd;
2482 scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2483 bzero(scsi_cmd, sizeof(*scsi_cmd));
2484 scsi_cmd->opcode = MODE_SENSE_6;
2486 scsi_cmd->byte2 |= SMS_DBD;
2487 scsi_cmd->page = page_code | page;
2488 scsi_cmd->length = param_len;
2489 cdb_len = sizeof(*scsi_cmd);
2492 * Need a 10 byte cdb.
2494 struct scsi_mode_sense_10 *scsi_cmd;
2496 scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes;
2497 bzero(scsi_cmd, sizeof(*scsi_cmd));
2498 scsi_cmd->opcode = MODE_SENSE_10;
2500 scsi_cmd->byte2 |= SMS_DBD;
2501 scsi_cmd->page = page_code | page;
2502 scsi_ulto2b(param_len, scsi_cmd->length);
2503 cdb_len = sizeof(*scsi_cmd);
2518 scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
2519 void (*cbfcnp)(struct cam_periph *, union ccb *),
2520 u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2521 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2524 return(scsi_mode_select_len(csio, retries, cbfcnp, tag_action,
2525 scsi_page_fmt, save_pages, param_buf,
2526 param_len, 0, sense_len, timeout));
2530 scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries,
2531 void (*cbfcnp)(struct cam_periph *, union ccb *),
2532 u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2533 u_int8_t *param_buf, u_int32_t param_len,
2534 int minimum_cmd_size, u_int8_t sense_len,
2540 * Use the smallest possible command to perform the operation.
2542 if ((param_len < 256) && (minimum_cmd_size < 10)) {
2544 * We can fit in a 6 byte cdb.
2546 struct scsi_mode_select_6 *scsi_cmd;
2548 scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2549 bzero(scsi_cmd, sizeof(*scsi_cmd));
2550 scsi_cmd->opcode = MODE_SELECT_6;
2551 if (scsi_page_fmt != 0)
2552 scsi_cmd->byte2 |= SMS_PF;
2553 if (save_pages != 0)
2554 scsi_cmd->byte2 |= SMS_SP;
2555 scsi_cmd->length = param_len;
2556 cdb_len = sizeof(*scsi_cmd);
2559 * Need a 10 byte cdb.
2561 struct scsi_mode_select_10 *scsi_cmd;
2564 (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes;
2565 bzero(scsi_cmd, sizeof(*scsi_cmd));
2566 scsi_cmd->opcode = MODE_SELECT_10;
2567 if (scsi_page_fmt != 0)
2568 scsi_cmd->byte2 |= SMS_PF;
2569 if (save_pages != 0)
2570 scsi_cmd->byte2 |= SMS_SP;
2571 scsi_ulto2b(param_len, scsi_cmd->length);
2572 cdb_len = sizeof(*scsi_cmd);
2587 scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
2588 void (*cbfcnp)(struct cam_periph *, union ccb *),
2589 uint8_t tag_action, uint64_t lba, int reladr, int pmi,
2590 struct scsi_read_capacity_data_long *rcap_buf,
2591 uint8_t sense_len, uint32_t timeout)
2593 struct scsi_read_capacity_16 *scsi_cmd;
2598 /*flags*/CAM_DIR_IN,
2600 /*data_ptr*/(u_int8_t *)rcap_buf,
2601 /*dxfer_len*/sizeof(*rcap_buf),
2605 scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
2606 bzero(scsi_cmd, sizeof(*scsi_cmd));
2607 scsi_cmd->opcode = SERVICE_ACTION_IN;
2608 scsi_cmd->service_action = SRC16_SERVICE_ACTION;
2609 scsi_u64to8b(lba, scsi_cmd->addr);
2610 scsi_ulto4b(sizeof(*rcap_buf), scsi_cmd->alloc_len);
2612 reladr |= SRC16_PMI;
2614 reladr |= SRC16_RELADR;
2618 * Prevent or allow the user to remove the media
2621 scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
2622 void (*cbfcnp)(struct cam_periph *, union ccb *),
2623 u_int8_t tag_action, u_int8_t action,
2624 u_int8_t sense_len, u_int32_t timeout)
2626 struct scsi_prevent *scsi_cmd;
2631 /*flags*/CAM_DIR_NONE,
2639 scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes;
2640 bzero(scsi_cmd, sizeof(*scsi_cmd));
2641 scsi_cmd->opcode = PREVENT_ALLOW;
2642 scsi_cmd->how = action;
2645 /* XXX allow specification of address and PMI bit and LBA */
2647 scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
2648 void (*cbfcnp)(struct cam_periph *, union ccb *),
2649 u_int8_t tag_action,
2650 struct scsi_read_capacity_data *rcap_buf,
2651 u_int8_t sense_len, u_int32_t timeout)
2653 struct scsi_read_capacity *scsi_cmd;
2658 /*flags*/CAM_DIR_IN,
2660 /*data_ptr*/(u_int8_t *)rcap_buf,
2661 /*dxfer_len*/sizeof(*rcap_buf),
2666 scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes;
2667 bzero(scsi_cmd, sizeof(*scsi_cmd));
2668 scsi_cmd->opcode = READ_CAPACITY;
2672 scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries,
2673 void (*cbfcnp)(struct cam_periph *, union ccb *),
2674 u_int8_t tag_action, struct scsi_report_luns_data *rpl_buf,
2675 u_int32_t alloc_len, u_int8_t sense_len, u_int32_t timeout)
2677 struct scsi_report_luns *scsi_cmd;
2682 /*flags*/CAM_DIR_IN,
2684 /*data_ptr*/(u_int8_t *)rpl_buf,
2685 /*dxfer_len*/alloc_len,
2689 scsi_cmd = (struct scsi_report_luns *)&csio->cdb_io.cdb_bytes;
2690 bzero(scsi_cmd, sizeof(*scsi_cmd));
2691 scsi_cmd->opcode = REPORT_LUNS;
2692 scsi_ulto4b(alloc_len, scsi_cmd->addr);
2696 * Syncronize the media to the contents of the cache for
2697 * the given lba/count pair. Specifying 0/0 means sync
2701 scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries,
2702 void (*cbfcnp)(struct cam_periph *, union ccb *),
2703 u_int8_t tag_action, u_int32_t begin_lba,
2704 u_int16_t lb_count, u_int8_t sense_len,
2707 struct scsi_sync_cache *scsi_cmd;
2712 /*flags*/CAM_DIR_NONE,
2720 scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes;
2721 bzero(scsi_cmd, sizeof(*scsi_cmd));
2722 scsi_cmd->opcode = SYNCHRONIZE_CACHE;
2723 scsi_ulto4b(begin_lba, scsi_cmd->begin_lba);
2724 scsi_ulto2b(lb_count, scsi_cmd->lb_count);
2728 scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
2729 void (*cbfcnp)(struct cam_periph *, union ccb *),
2730 u_int8_t tag_action, int readop, u_int8_t byte2,
2731 int minimum_cmd_size, u_int64_t lba, u_int32_t block_count,
2732 u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
2738 * Use the smallest possible command to perform the operation
2739 * as some legacy hardware does not support the 10 byte commands.
2740 * If any of the bits in byte2 is set, we have to go with a larger
2743 if ((minimum_cmd_size < 10)
2744 && ((lba & 0x1fffff) == lba)
2745 && ((block_count & 0xff) == block_count)
2748 * We can fit in a 6 byte cdb.
2750 struct scsi_rw_6 *scsi_cmd;
2752 scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
2753 scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2754 scsi_ulto3b(lba, scsi_cmd->addr);
2755 scsi_cmd->length = block_count & 0xff;
2756 scsi_cmd->control = 0;
2757 cdb_len = sizeof(*scsi_cmd);
2759 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2760 ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0],
2761 scsi_cmd->addr[1], scsi_cmd->addr[2],
2762 scsi_cmd->length, dxfer_len));
2763 } else if ((minimum_cmd_size < 12)
2764 && ((block_count & 0xffff) == block_count)
2765 && ((lba & 0xffffffffU) == lba)) {
2767 * Need a 10 byte cdb.
2769 struct scsi_rw_10 *scsi_cmd;
2771 scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
2772 scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2773 scsi_cmd->byte2 = byte2;
2774 scsi_ulto4b(lba, scsi_cmd->addr);
2775 scsi_cmd->reserved = 0;
2776 scsi_ulto2b(block_count, scsi_cmd->length);
2777 scsi_cmd->control = 0;
2778 cdb_len = sizeof(*scsi_cmd);
2780 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2781 ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
2782 scsi_cmd->addr[1], scsi_cmd->addr[2],
2783 scsi_cmd->addr[3], scsi_cmd->length[0],
2784 scsi_cmd->length[1], dxfer_len));
2785 } else if ((minimum_cmd_size < 16)
2786 && ((block_count & 0xffffffffU) == block_count)
2787 && ((lba & 0xffffffffU) == lba)) {
2789 * The block count is too big for a 10 byte CDB, use a 12
2792 struct scsi_rw_12 *scsi_cmd;
2794 scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
2795 scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2796 scsi_cmd->byte2 = byte2;
2797 scsi_ulto4b(lba, scsi_cmd->addr);
2798 scsi_cmd->reserved = 0;
2799 scsi_ulto4b(block_count, scsi_cmd->length);
2800 scsi_cmd->control = 0;
2801 cdb_len = sizeof(*scsi_cmd);
2803 CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2804 ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0],
2805 scsi_cmd->addr[1], scsi_cmd->addr[2],
2806 scsi_cmd->addr[3], scsi_cmd->length[0],
2807 scsi_cmd->length[1], scsi_cmd->length[2],
2808 scsi_cmd->length[3], dxfer_len));
2811 * 16 byte CDB. We'll only get here if the LBA is larger
2812 * than 2^32, or if the user asks for a 16 byte command.
2814 struct scsi_rw_16 *scsi_cmd;
2816 scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes;
2817 scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2818 scsi_cmd->byte2 = byte2;
2819 scsi_u64to8b(lba, scsi_cmd->addr);
2820 scsi_cmd->reserved = 0;
2821 scsi_ulto4b(block_count, scsi_cmd->length);
2822 scsi_cmd->control = 0;
2823 cdb_len = sizeof(*scsi_cmd);
2828 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
2838 scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
2839 void (*cbfcnp)(struct cam_periph *, union ccb *),
2840 u_int8_t tag_action, int start, int load_eject,
2841 int immediate, u_int8_t sense_len, u_int32_t timeout)
2843 struct scsi_start_stop_unit *scsi_cmd;
2844 int extra_flags = 0;
2846 scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes;
2847 bzero(scsi_cmd, sizeof(*scsi_cmd));
2848 scsi_cmd->opcode = START_STOP_UNIT;
2850 scsi_cmd->how |= SSS_START;
2851 /* it takes a lot of power to start a drive */
2852 extra_flags |= CAM_HIGH_POWER;
2854 if (load_eject != 0)
2855 scsi_cmd->how |= SSS_LOEJ;
2857 scsi_cmd->byte2 |= SSS_IMMED;
2862 /*flags*/CAM_DIR_NONE | extra_flags,
2873 scsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries,
2874 void (*cbfcnp)(struct cam_periph *, union ccb *),
2875 u_int8_t tag_action, u_int8_t page_code, u_int8_t page,
2876 int save_pages, int ppc, u_int32_t paramptr,
2877 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2880 struct scsi_log_sense *scsi_cmd;
2883 scsi_cmd = (struct scsi_log_sense *)&csio->cdb_io.cdb_bytes;
2884 bzero(scsi_cmd, sizeof(*scsi_cmd));
2885 scsi_cmd->opcode = LOG_SENSE;
2886 scsi_cmd->page = page_code | page;
2887 if (save_pages != 0)
2888 scsi_cmd->byte2 |= SLS_SP;
2890 scsi_cmd->byte2 |= SLS_PPC;
2891 scsi_ulto2b(paramptr, scsi_cmd->paramptr);
2892 scsi_ulto2b(param_len, scsi_cmd->length);
2893 cdb_len = sizeof(*scsi_cmd);
2898 /*flags*/CAM_DIR_IN,
2900 /*data_ptr*/param_buf,
2901 /*dxfer_len*/param_len,
2908 scsi_log_select(struct ccb_scsiio *csio, u_int32_t retries,
2909 void (*cbfcnp)(struct cam_periph *, union ccb *),
2910 u_int8_t tag_action, u_int8_t page_code, int save_pages,
2911 int pc_reset, u_int8_t *param_buf, u_int32_t param_len,
2912 u_int8_t sense_len, u_int32_t timeout)
2914 struct scsi_log_select *scsi_cmd;
2917 scsi_cmd = (struct scsi_log_select *)&csio->cdb_io.cdb_bytes;
2918 bzero(scsi_cmd, sizeof(*scsi_cmd));
2919 scsi_cmd->opcode = LOG_SELECT;
2920 scsi_cmd->page = page_code & SLS_PAGE_CODE;
2921 if (save_pages != 0)
2922 scsi_cmd->byte2 |= SLS_SP;
2924 scsi_cmd->byte2 |= SLS_PCR;
2925 scsi_ulto2b(param_len, scsi_cmd->length);
2926 cdb_len = sizeof(*scsi_cmd);
2931 /*flags*/CAM_DIR_OUT,
2933 /*data_ptr*/param_buf,
2934 /*dxfer_len*/param_len,
2941 * Try make as good a match as possible with
2942 * available sub drivers
2945 scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2947 struct scsi_inquiry_pattern *entry;
2948 struct scsi_inquiry_data *inq;
2950 entry = (struct scsi_inquiry_pattern *)table_entry;
2951 inq = (struct scsi_inquiry_data *)inqbuffer;
2953 if (((SID_TYPE(inq) == entry->type)
2954 || (entry->type == T_ANY))
2955 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2956 : entry->media_type & SIP_MEDIA_FIXED)
2957 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2958 && (cam_strmatch(inq->product, entry->product,
2959 sizeof(inq->product)) == 0)
2960 && (cam_strmatch(inq->revision, entry->revision,
2961 sizeof(inq->revision)) == 0)) {
2969 init_scsi_delay(void)
2974 TUNABLE_INT_FETCH("kern.cam.scsi_delay", &delay);
2976 if (set_scsi_delay(delay) != 0) {
2977 kprintf("cam: invalid value for tunable kern.cam.scsi_delay\n");
2978 set_scsi_delay(SCSI_DELAY);
2981 SYSINIT(scsi_delay, SI_BOOT1_TUNABLES, SI_ORDER_ANY, init_scsi_delay, NULL);
2984 sysctl_scsi_delay(SYSCTL_HANDLER_ARGS)
2989 error = sysctl_handle_int(oidp, &delay, sizeof(delay), req);
2990 if (error != 0 || req->newptr == NULL)
2992 return (set_scsi_delay(delay));
2994 SYSCTL_PROC(_kern_cam, OID_AUTO, scsi_delay, CTLTYPE_INT|CTLFLAG_RW,
2995 0, 0, sysctl_scsi_delay, "I",
2996 "Delay to allow devices to settle after a SCSI bus reset (ms)");
2999 set_scsi_delay(int delay)
3002 * If someone sets this to 0, we assume that they want the
3003 * minimum allowable bus settle delay.
3006 kprintf("cam: using minimum scsi_delay (%dms)\n",
3008 delay = SCSI_MIN_DELAY;
3010 if (delay < SCSI_MIN_DELAY)
3015 #endif /* _KERNEL */
3018 * Try make as good a match as possible with
3019 * available sub drivers
3022 scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
3024 struct scsi_static_inquiry_pattern *entry;
3025 struct scsi_inquiry_data *inq;
3027 entry = (struct scsi_static_inquiry_pattern *)table_entry;
3028 inq = (struct scsi_inquiry_data *)inqbuffer;
3030 if (((SID_TYPE(inq) == entry->type)
3031 || (entry->type == T_ANY))
3032 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
3033 : entry->media_type & SIP_MEDIA_FIXED)
3034 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
3035 && (cam_strmatch(inq->product, entry->product,
3036 sizeof(inq->product)) == 0)
3037 && (cam_strmatch(inq->revision, entry->revision,
3038 sizeof(inq->revision)) == 0)) {