diff options
Diffstat (limited to 'sys/cam/scsi/scsi_all.c')
-rw-r--r-- | sys/cam/scsi/scsi_all.c | 2678 |
1 files changed, 2678 insertions, 0 deletions
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c new file mode 100644 index 0000000..129847f --- /dev/null +++ b/sys/cam/scsi/scsi_all.c @@ -0,0 +1,2678 @@ +/* + * Implementation of Utility functions for all SCSI device types. + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * Copyright (c) 1997, 1998 Kenneth D. Merry. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> + +#ifdef KERNEL +#include <opt_scsi.h> + +#include <sys/systm.h> +#else +#include <errno.h> +#include <stdio.h> +#include <string.h> +#endif + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_xpt.h> +#include <cam/cam_xpt_periph.h> +#include <cam/scsi/scsi_all.h> +#ifndef KERNEL +#include <camlib.h> + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ +#define ERESTART -1 /* restart syscall */ +#define EJUSTRETURN -2 /* don't modify regs, just return */ +#endif /* !KERNEL */ + +const char *scsi_sense_key_text[] = +{ + "NO SENSE", + "RECOVERED ERROR", + "NOT READY", + "MEDIUM ERROR", + "HARDWARE FAILURE", + "ILLEGAL REQUEST", + "UNIT ATTENTION", + "DATA PROTECT", + "BLANK CHECK", + "Vendor Specific", + "COPY ABORTED", + "ABORTED COMMAND", + "EQUAL", + "VOLUME OVERFLOW", + "MISCOMPARE", + "RESERVED" +}; + +#if !defined(SCSI_NO_OP_STRINGS) + +#define D 0x001 +#define T 0x002 +#define L 0x004 +#define P 0x008 +#define W 0x010 +#define R 0x020 +#define S 0x040 +#define O 0x080 +#define M 0x100 +#define C 0x200 +#define A 0x400 +#define E 0x800 + +#define ALL 0xFFF + +/* + * WARNING: You must update the num_ops field below for this quirk table + * entry if you add more entries. + */ +static struct op_table_entry plextor_cd_ops[] = { + {0xD8, R, "CD-DA READ"} +}; + +static struct scsi_op_quirk_entry scsi_op_quirk_table[] = { + { + /* + * I believe that 0xD8 is the Plextor proprietary command + * to read CD-DA data. I'm not sure which Plextor CDROM + * models support the command, though. I know for sure + * that the 4X, 8X, and 12X models do, and presumably the + * 12-20X does. I don't know about any earlier models, + * though. If anyone has any more complete information, + * feel free to change this quirk entry. + */ + {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"}, + 1, /* number of vendor-specific opcodes for this entry */ + plextor_cd_ops + } +}; + +static struct op_table_entry scsi_op_codes[] = { +/* + * From: ftp://ftp.symbios.com/pub/standards/io/t10/drafts/spc/op-num.txt + * Modifications by Kenneth Merry (ken@plutotech.com) + * + * Note: order is important in this table, scsi_op_desc() currently + * depends on the opcodes in the table being in order to save search time. + */ +/* + * File: OP-NUM.TXT + * + * SCSI Operation Codes + * Numeric Sorted Listing + * as of 11/13/96 + * + * D - DIRECT ACCESS DEVICE (SBC) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + * . L - PRINTER DEVICE (SSC) M = Mandatory + * . P - PROCESSOR DEVICE (SPC) O = Optional + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) V = Vendor specific + * . . R - CD DEVICE (MMC) R = Reserved + * . . S - SCANNER DEVICE (SGC) Z = Obsolete + * . . .O - OPTICAL MEMORY DEVICE (SBC) + * . . . M - MEDIA CHANGER DEVICE (SMC) + * . . . C - COMMUNICATION DEVICE (SSC) + * . . . .A - STORAGE ARRAY DEVICE (SCC) + * . . . . E - ENCLOSURE SERVICES DEVICE (SES) + * OP DTLPWRSOMCAE Description + * -- ------------ ---------------------------------------------------- */ +/* 00 MMMMMMMMMMMM TEST UNIT READY */ +{0x00, ALL, "TEST UNIT READY"}, + +/* 01 M REWIND */ +{0x01, T, "REWIND"}, +/* 01 Z V ZO ZO REZERO UNIT */ +{0x01, D|L|W|O|M, "REZERO UNIT"}, + +/* 02 VVVVVV V */ + +/* 03 MMMMMMMMMMMM REQUEST SENSE */ +{0x03, ALL, "REQUEST SENSE"}, + +/* 04 M O O FORMAT UNIT */ +{0x04, D|R|O, "FORMAT UNIT"}, +/* 04 O FORMAT MEDIUM */ +{0x04, T, "FORMAT MEDIUM"}, +/* 04 O FORMAT */ +{0x04, L, "FORMAT"}, + +/* 05 VMVVVV V READ BLOCK LIMITS */ +{0x05, T, "READ BLOCK LIMITS"}, + +/* 06 VVVVVV V */ + +/* 07 OVV O OV REASSIGN BLOCKS */ +{0x07, D|W|O, "REASSIGN BLOCKS"}, +/* 07 O INITIALIZE ELEMENT STATUS */ +{0x07, M, "INITIALIZE ELEMENT STATUS"}, + +/* 08 OMV OO OV READ(06) */ +{0x08, D|T|W|R|O, "READ(06)"}, +/* 08 O RECEIVE */ +{0x08, P, "RECEIVE"}, +/* 08 M GET MESSAGE(06) */ +{0x08, C, "GET MESSAGE(06)"}, + +/* 09 VVVVVV V */ + +/* 0A OM O OV WRITE(06) */ +{0x0A, D|T|W|O, "WRITE(06)"}, +/* 0A M SEND(06) */ +{0x0A, P, "SEND(06)"}, +/* 0A M SEND MESSAGE(06) */ +{0x0A, C, "SEND MESSAGE(06)"}, +/* 0A M PRINT */ +{0x0A, L, "PRINT"}, + +/* 0B Z ZO ZV SEEK(06) */ +{0x0B, D|W|R|O, "SEEK(06)"}, +/* 0B O SLEW AND PRINT */ +{0x0B, L, "SLEW AND PRINT"}, + +/* 0C VVVVVV V */ +/* 0D VVVVVV V */ +/* 0E VVVVVV V */ +/* 0F VOVVVV V READ REVERSE */ +{0x0F, T, "READ REVERSE"}, + +/* 10 VM VVV WRITE FILEMARKS */ +{0x10, T, "WRITE FILEMARKS"}, +/* 10 O O SYNCHRONIZE BUFFER */ +{0x10, L|W, "SYNCHRONIZE BUFFER"}, + +/* 11 VMVVVV SPACE */ +{0x11, T, "SPACE"}, + +/* 12 MMMMMMMMMMMM INQUIRY */ +{0x12, ALL, "INQUIRY"}, + +/* 13 VOVVVV VERIFY(06) */ +{0x13, T, "VERIFY(06)"}, + +/* 14 VOOVVV RECOVER BUFFERED DATA */ +{0x14, T|L, "RECOVER BUFFERED DATA"}, + +/* 15 OMO OOOOOOOO MODE SELECT(06) */ +{0x15, ALL & ~(P), "MODE SELECT(06)"}, + +/* 16 MMMOMMMM O RESERVE(06) */ +{0x16, D|T|L|P|W|R|S|O|E, "RESERVE(06)"}, +/* 16 M RESERVE ELEMENT(06) */ +{0x16, M, "RESERVE ELEMENT(06)"}, + +/* 17 MMMOMMMM O RELEASE(06) */ +{0x17, ALL & ~(M|C|A), "RELEASE(06)"}, +/* 17 M RELEASE ELEMENT(06) */ +{0x17, M, "RELEASE ELEMENT(06)"}, + +/* 18 OOOOOOOO COPY */ +{0x18, ALL & ~(M|C|A|E), "COPY"}, + +/* 19 VMVVVV ERASE */ +{0x19, T, "ERASE"}, + +/* 1A OMO OOOOOOOO MODE SENSE(06) */ +{0x1A, ALL & ~(P), "MODE SENSE(06)"}, + +/* 1B O OM O STOP START UNIT */ +{0x1B, D|W|R|O, "STOP START UNIT"}, +/* 1B O LOAD UNLOAD */ +{0x1B, T, "LOAD UNLOAD"}, +/* 1B O SCAN */ +{0x1B, S, "SCAN"}, +/* 1B O STOP PRINT */ +{0x1B, L, "STOP PRINT"}, + +/* 1C OOOOOOOOOO M RECEIVE DIAGNOSTIC RESULTS */ +{0x1C, ALL & ~(A), "RECEIVE DIAGNOSTIC RESULTS"}, + +/* 1D MMMMMMMMMMMM SEND DIAGNOSTIC */ +{0x1D, ALL, "SEND DIAGNOSTIC"}, + +/* 1E OO OM OO PREVENT ALLOW MEDIUM REMOVAL */ +{0x1E, D|T|W|R|O|M, "PREVENT ALLOW MEDIUM REMOVAL"}, + +/* 1F */ +/* 20 V VV V */ +/* 21 V VV V */ +/* 22 V VV V */ +/* 23 V VV V */ + +/* 24 V VVM SET WINDOW */ +{0x24, S, "SET WINDOW"}, + +/* 25 M M M READ CAPACITY */ +{0x25, D|W|O, "READ CAPACITY"}, +/* 25 M READ CD RECORDED CAPACITY */ +{0x25, R, "READ CD RECORDED CAPACITY"}, +/* 25 O GET WINDOW */ +{0x25, S, "GET WINDOW"}, + +/* 26 V VV */ +/* 27 V VV */ + +/* 28 M MMMM READ(10) */ +{0x28, D|W|R|S|O, "READ(10)"}, +/* 28 O GET MESSAGE(10) */ +{0x28, C, "GET MESSAGE(10)"}, + +/* 29 V VV O READ GENERATION */ +{0x29, O, "READ GENERATION"}, + +/* 2A M MM M WRITE(10) */ +{0x2A, D|W|R|O, "WRITE(10)"}, +/* 2A O SEND(10) */ +{0x2A, S, "SEND(10)"}, +/* 2A O SEND MESSAGE(10) */ +{0x2A, C, "SEND MESSAGE(10)"}, + +/* 2B O OM O SEEK(10) */ +{0x2B, D|W|R|O, "SEEK(10)"}, +/* 2B O LOCATE */ +{0x2B, T, "LOCATE"}, +/* 2B O POSITION TO ELEMENT */ +{0x2B, M, "POSITION TO ELEMENT"}, + +/* 2C V O ERASE(10) */ +{0x2C, O, "ERASE(10)"}, + +/* 2D V O O READ UPDATED BLOCK */ +{0x2D, W|O, "READ UPDATED BLOCK"}, + +/* 2E O O O WRITE AND VERIFY(10) */ +{0x2E, D|W|O, "WRITE AND VERIFY(10)"}, + +/* 2F O OO O VERIFY(10) */ +{0x2F, D|W|R|O, "VERIFY(10)"}, + +/* 30 Z ZO Z SEARCH DATA HIGH(10) */ +{0x30, D|W|R|O, "SEARCH DATA HIGH(10)"}, + +/* 31 Z ZO Z SEARCH DATA EQUAL(10) */ +{0x31, D|W|R|O, "SEARCH DATA EQUAL(10)"}, +/* 31 O OBJECT POSITION */ +{0x31, S, "OBJECT POSITION"}, + +/* 32 Z ZO Z SEARCH DATA LOW(10) */ +{0x32, D|W|R|O, "SEARCH DATA LOW(10"}, + +/* 33 O OO O SET LIMITS(10) */ +{0x33, D|W|R|O, "SET LIMITS(10)"}, + +/* 34 O OO O PRE-FETCH */ +{0x34, D|W|R|O, "PRE-FETCH"}, +/* 34 O READ POSITION */ +{0x34, T, "READ POSITION"}, +/* 34 O GET DATA BUFFER STATUS */ +{0x34, S, "GET DATA BUFFER STATUS"}, + +/* 35 O OM O SYNCHRONIZE CACHE */ +{0x35, D|W|R|O, "SYNCHRONIZE CACHE"}, + +/* 36 O OO O LOCK UNLOCK CACHE */ +{0x36, D|W|R|O, "LOCK UNLOCK CACHE"}, + +/* 37 O O READ DEFECT DATA(10) */ +{0x37, D|O, "READ DEFECT DATA(10)"}, + +/* 38 O O MEDIUM SCAN */ +{0x38, W|O, "MEDIUM SCAN"}, + +/* 39 OOOOOOOO COMPARE */ +{0x39, ALL & ~(M|C|A|E), "COMPARE"}, + +/* 3A OOOOOOOO COPY AND VERIFY */ +{0x3A, ALL & ~(M|C|A|E), "COPY AND VERIFY"}, + +/* 3B OOOOOOOOOO O WRITE BUFFER */ +{0x3B, ALL & ~(A), "WRITE BUFFER"}, + +/* 3C OOOOOOOOOO READ BUFFER */ +{0x3C, ALL & ~(A|E),"READ BUFFER"}, + +/* 3D O O UPDATE BLOCK */ +{0x3D, W|O, "UPDATE BLOCK"}, + +/* 3E O OO O READ LONG */ +{0x3E, D|W|R|O, "READ LONG"}, + +/* 3F O O O WRITE LONG */ +{0x3F, D|W|O, "WRITE LONG"}, + +/* 40 OOOOOOOOOO CHANGE DEFINITION */ +{0x40, ALL & ~(A|E),"CHANGE DEFINITION"}, + +/* 41 O WRITE SAME */ +{0x41, D, "WRITE SAME"}, + +/* 42 M READ SUB-CHANNEL */ +{0x42, R, "READ SUB-CHANNEL"}, + +/* 43 M READ TOC/PMA/ATIP {MMC Proposed} */ +{0x43, R, "READ TOC/PMA/ATIP {MMC Proposed}"}, + +/* 44 M REPORT DENSITY SUPPORT */ +{0x44, T, "REPORT DENSITY SUPPORT"}, +/* 44 M READ HEADER */ +{0x44, R, "READ HEADER"}, + +/* 45 O PLAY AUDIO(10) */ +{0x45, R, "PLAY AUDIO(10)"}, + +/* 46 */ + +/* 47 O PLAY AUDIO MSF */ +{0x47, R, "PLAY AUDIO MSF"}, + +/* 48 O PLAY AUDIO TRACK INDEX */ +{0x48, R, "PLAY AUDIO TRACK INDEX"}, + +/* 49 O PLAY TRACK RELATIVE(10) */ +{0x49, R, "PLAY TRACK RELATIVE(10)"}, + +/* 4A */ + +/* 4B O PAUSE/RESUME */ +{0x4B, R, "PAUSE/RESUME"}, + +/* 4C OOOOOOOOOOO LOG SELECT */ +{0x4C, ALL & ~(E), "LOG SELECT"}, + +/* 4D OOOOOOOOOOO LOG SENSE */ +{0x4D, ALL & ~(E), "LOG SENSE"}, + +/* 4E O STOP PLAY/SCAN {MMC Proposed} */ +{0x4E, R, "STOP PLAY/SCAN {MMC Proposed}"}, + +/* 4F */ + +/* 50 O XDWRITE(10) */ +{0x50, D, "XDWRITE(10)"}, + +/* 51 O XPWRITE(10) */ +{0x51, D, "XPWRITE(10)"}, +/* 51 M READ DISC INFORMATION {MMC Proposed} */ +{0x51, R, "READ DISC INFORMATION {MMC Proposed}"}, + +/* 52 O XDREAD(10) */ +{0x52, D, "XDREAD(10)"}, +/* 52 M READ TRACK INFORMATION {MMC Proposed} */ +{0x52, R, "READ TRACK INFORMATION {MMC Proposed}"}, + +/* 53 M RESERVE TRACK {MMC Proposed} */ +{0x53, R, "RESERVE TRACK {MMC Proposed}"}, + +/* 54 O SEND OPC INFORMATION {MMC Proposed} */ +{0x54, R, "SEND OPC INFORMATION {MMC Proposed}"}, + +/* 55 OOO OOOOOOOO MODE SELECT(10) */ +{0x55, ALL & ~(P), "MODE SELECT(10)"}, + +/* 56 MMMOMMMM O RESERVE(10) */ +{0x56, ALL & ~(M|C|A), "RESERVE(10)"}, +/* 56 M RESERVE ELEMENT(10) */ +{0x56, M, "RESERVE ELEMENT(10)"}, + +/* 57 MMMOMMMM O RELEASE(10) */ +{0x57, ALL & ~(M|C|A), "RELEASE(10"}, +/* 57 M RELEASE ELEMENT(10) */ +{0x57, M, "RELEASE ELEMENT(10)"}, + +/* 58 O REPAIR TRACK {MMC Proposed} */ +{0x58, R, "REPAIR TRACK {MMC Proposed}"}, + +/* 59 O READ MASTER CUE {MMC Proposed} */ +{0x59, R, "READ MASTER CUE {MMC Proposed}"}, + +/* 5A OOO OOOOOOOO MODE SENSE(10) */ +{0x5A, ALL & ~(P), "MODE SENSE(10)"}, + +/* 5B M CLOSE TRACK/SESSION {MMC Proposed} */ +{0x5B, R, "CLOSE TRACK/SESSION {MMC Proposed}"}, + +/* 5C O READ BUFFER CAPACITY {MMC Proposed} */ +{0x5C, R, "READ BUFFER CAPACITY {MMC Proposed}"}, + +/* 5D O SEND CUE SHEET {MMC Proposed} */ +{0x5D, R, "SEND CUE SHEET {MMC Proposed}"}, + +/* 5E OOOOOOOOO O PERSISTENT RESERVE IN */ +{0x5E, ALL & ~(C|A),"PERSISTENT RESERVE IN"}, + +/* 5F OOOOOOOOO O PERSISTENT RESERVE OUT */ +{0x5F, ALL & ~(C|A),"PERSISTENT RESERVE OUT"}, + +/* 80 O XDWRITE EXTENDED(16) */ +{0x80, D, "XDWRITE EXTENDED(16)"}, + +/* 81 O REBUILD(16) */ +{0x81, D, "REBUILD(16)"}, + +/* 82 O REGENERATE(16) */ +{0x82, D, "REGENERATE(16)"}, + +/* 83 */ +/* 84 */ +/* 85 */ +/* 86 */ +/* 87 */ +/* 88 */ +/* 89 */ +/* 8A */ +/* 8B */ +/* 8C */ +/* 8D */ +/* 8E */ +/* 8F */ +/* 90 */ +/* 91 */ +/* 92 */ +/* 93 */ +/* 94 */ +/* 95 */ +/* 96 */ +/* 97 */ +/* 98 */ +/* 99 */ +/* 9A */ +/* 9B */ +/* 9C */ +/* 9D */ +/* 9E */ +/* 9F */ + +/* A0 OOOOOOOOOOO REPORT LUNS */ +{0xA0, ALL & ~(E), "REPORT LUNS"}, + +/* A1 O BLANK {MMC Proposed} */ +{0xA1, R, "BLANK {MMC Proposed}"}, + +/* A2 O WRITE CD MSF {MMC Proposed} */ +{0xA2, R, "WRITE CD MSF {MMC Proposed}"}, + +/* A3 M MAINTENANCE (IN) */ +{0xA3, A, "MAINTENANCE (IN)"}, + +/* A4 O MAINTENANCE (OUT) */ +{0xA4, A, "MAINTENANCE (OUT)"}, + +/* A5 O M MOVE MEDIUM */ +{0xA5, T|M, "MOVE MEDIUM"}, +/* A5 O PLAY AUDIO(12) */ +{0xA5, R, "PLAY AUDIO(12)"}, + +/* A6 O EXCHANGE MEDIUM */ +{0xA6, M, "EXCHANGE MEDIUM"}, +/* A6 O LOAD/UNLOAD CD {MMC Proposed} */ +{0xA6, R, "LOAD/UNLOAD CD {MMC Proposed}"}, + +/* A7 OO OO OO MOVE MEDIUM ATTACHED */ +{0xA7, D|T|W|R|O|M, "MOVE MEDIUM ATTACHED"}, + +/* A8 OM O READ(12) */ +{0xA8, W|R|O, "READ(12)"}, +/* A8 O GET MESSAGE(12) */ +{0xA8, C, "GET MESSAGE(12)"}, + +/* A9 O PLAY TRACK RELATIVE(12) */ +{0xA9, R, "PLAY TRACK RELATIVE(12)"}, + +/* AA O O WRITE(12) */ +{0xAA, W|O, "WRITE(12)"}, +/* AA O WRITE CD(12) {MMC Proposed} */ +{0xAA, R, "WRITE CD(12) {MMC Proposed}"}, +/* AA O SEND MESSAGE(12) */ +{0xAA, C, "SEND MESSAGE(12)"}, + +/* AB */ + +/* AC O ERASE(12) */ +{0xAC, O, "ERASE(12)"}, + +/* AD */ + +/* AE O O WRITE AND VERIFY(12) */ +{0xAE, W|O, "WRITE AND VERIFY(12)"}, + +/* AF OO O VERIFY(12) */ +{0xAF, W|R|O, "VERIFY(12)"}, + +/* B0 ZO Z SEARCH DATA HIGH(12) */ +{0xB0, W|R|O, "SEARCH DATA HIGH(12)"}, + +/* B1 ZO Z SEARCH DATA EQUAL(12) */ +{0xB1, W|R|O, "SEARCH DATA EQUAL(12)"}, + +/* B2 ZO Z SEARCH DATA LOW(12) */ +{0xB2, W|R|O, "SEARCH DATA LOW(12)"}, + +/* B3 OO O SET LIMITS(12) */ +{0xB3, W|R|O, "SET LIMITS(12)"}, + +/* B4 OO OO OO READ ELEMENT STATUS ATTACHED */ +{0xB4, D|T|W|R|O|M, "READ ELEMENT STATUS ATTACHED"}, + +/* B5 O REQUEST VOLUME ELEMENT ADDRESS */ +{0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS"}, + +/* B6 O SEND VOLUME TAG */ +{0xB6, M, "SEND VOLUME TAG"}, + +/* B7 O READ DEFECT DATA(12) */ +{0xB7, O, "READ DEFECT DATA(12)"}, + +/* B8 O M READ ELEMENT STATUS */ +{0xB8, T|M, "READ ELEMENT STATUS"}, +/* B8 O SET CD SPEED {MMC Proposed} */ +{0xB8, R, "SET CD SPEED {MMC Proposed}"}, + +/* B9 M READ CD MSF {MMC Proposed} */ +{0xB9, R, "READ CD MSF {MMC Proposed}"}, + +/* BA O SCAN {MMC Proposed} */ +{0xBA, R, "SCAN {MMC Proposed}"}, +/* BA M REDUNDANCY GROUP (IN) */ +{0xBA, A, "REDUNDANCY GROUP (IN)"}, + +/* BB O SET CD-ROM SPEED {proposed} */ +{0xBB, R, "SET CD-ROM SPEED {proposed}"}, +/* BB O REDUNDANCY GROUP (OUT) */ +{0xBB, A, "REDUNDANCY GROUP (OUT)"}, + +/* BC O PLAY CD {MMC Proposed} */ +{0xBC, R, "PLAY CD {MMC Proposed}"}, +/* BC M SPARE (IN) */ +{0xBC, A, "SPARE (IN)"}, + +/* BD M MECHANISM STATUS {MMC Proposed} */ +{0xBD, R, "MECHANISM STATUS {MMC Proposed}"}, +/* BD O SPARE (OUT) */ +{0xBD, A, "SPARE (OUT)"}, + +/* BE O READ CD {MMC Proposed} */ +{0xBE, R, "READ CD {MMC Proposed}"}, +/* BE M VOLUME SET (IN) */ +{0xBE, A, "VOLUME SET (IN)"}, + +/* BF O VOLUME SET (OUT) */ +{0xBF, A, "VOLUME SET (OUT)"} +}; + +const char * +scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) +{ + caddr_t match; + int i, j; + u_int16_t opmask; + u_int16_t pd_type; + int num_ops[2]; + struct op_table_entry *table[2]; + int num_tables; + + pd_type = SID_TYPE(inq_data); + + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)scsi_op_quirk_table, + sizeof(scsi_op_quirk_table)/ + sizeof(*scsi_op_quirk_table), + sizeof(*scsi_op_quirk_table), + scsi_inquiry_match); + + if (match != NULL) { + table[0] = ((struct scsi_op_quirk_entry *)match)->op_table; + num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops; + table[1] = scsi_op_codes; + num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); + num_tables = 2; + } else { + /* + * If this is true, we have a vendor specific opcode that + * wasn't covered in the quirk table. + */ + if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80))) + return("Vendor Specific Command"); + + table[0] = scsi_op_codes; + num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]); + num_tables = 1; + } + + opmask = 1 << pd_type; + + for (j = 0; j < num_tables; j++) { + for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){ + if ((table[j][i].opcode == opcode) + && ((table[j][i].opmask & opmask) != 0)) + return(table[j][i].desc); + } + } + + /* + * If we can't find a match for the command in the table, we just + * assume it's a vendor specifc command. + */ + return("Vendor Specific Command"); + +} + +#else /* SCSI_NO_OP_STRINGS */ + +const char * +scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) +{ + return(""); +} + +#endif + + +#include <sys/param.h> + + +#if !defined(SCSI_NO_SENSE_STRINGS) +#define SST(asc, ascq, action, desc) \ + asc, ascq, action, desc +#else +#define SST(asc, ascq, action, desc) \ + asc, asc, action +#endif + +/* + * If we're in the kernel, 'quantum' is already defined in cam_xpt.c. + * Otherwise, we need to define it. + */ +#ifdef KERNEL +extern const char quantum[]; +#else +static const char quantum[] = "QUANTUM"; +#endif + +/* + * WARNING: You must update the num_ascs field below for this quirk table + * entry if you add more entries. + */ +static struct asc_table_entry quantum_fireball_entries[] = { + {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, + "Logical unit not ready, initializing cmd. required")} +}; + +static struct scsi_sense_quirk_entry asc_quirk_table[] = { + { + /* + * The Quantum Fireball ST and SE like to return 0x04 0x0b when + * they really should return 0x04 0x02. 0x04,0x0b isn't + * defined in any SCSI spec, and it isn't mentioned in the + * hardware manual for these drives. + */ + {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, + 1, /* number of vendor-specific sense codes for this entry */ + quantum_fireball_entries + } +}; + +static struct asc_table_entry asc_text[] = { +/* + * From File: ASC-NUM.TXT + * SCSI ASC/ASCQ Assignments + * Numeric Sorted Listing + * as of 5/12/97 + * + * D - DIRECT ACCESS DEVICE (SBC) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + * . L - PRINTER DEVICE (SSC) blank = reserved + * . P - PROCESSOR DEVICE (SPC) not blank = allowed + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) + * . . R - CD DEVICE (MMC) + * . . S - SCANNER DEVICE (SGC) + * . . .O - OPTICAL MEMORY DEVICE (SBC) + * . . . M - MEDIA CHANGER DEVICE (SMC) + * . . . C - COMMUNICATION DEVICE (SSC) + * . . . .A - STORAGE ARRAY DEVICE (SCC) + * . . . . E - ENCLOSURE SERVICES DEVICE (SES) + * DTLPWRSOMCAE ASC ASCQ Action Description + * ------------ ---- ---- ------ -----------------------------------*/ +/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NEPDEF, + "No additional sense information") }, +/* T S */{SST(0x00, 0x01, SS_DEF, + "Filemark detected") }, +/* T S */{SST(0x00, 0x02, SS_DEF, + "End-of-partition/medium detected") }, +/* T */{SST(0x00, 0x03, SS_DEF, + "Setmark detected") }, +/* T S */{SST(0x00, 0x04, SS_DEF, + "Beginning-of-partition/medium detected") }, +/* T S */{SST(0x00, 0x05, SS_DEF, + "End-of-data detected") }, +/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_DEF, + "I/O process terminated") }, +/* R */{SST(0x00, 0x11, SS_NEDEF|EBUSY, + "Audio play operation in progress") }, +/* R */{SST(0x00, 0x12, SS_NEDEF, + "Audio play operation paused") }, +/* R */{SST(0x00, 0x13, SS_NEDEF, + "Audio play operation successfully completed") }, +/* R */{SST(0x00, 0x14, SS_DEF, + "Audio play operation stopped due to error") }, +/* R */{SST(0x00, 0x15, SS_DEF, + "No current audio status to return") }, +/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_NEDEF|EBUSY, + "Operation in progress") }, +/* DTL WRSOM AE */{SST(0x00, 0x17, SS_DEF, + "Cleaning requested") }, +/* D W O */{SST(0x01, 0x00, SS_DEF, + "No index/sector signal") }, +/* D WR OM */{SST(0x02, 0x00, SS_DEF, + "No seek complete") }, +/* DTL W SO */{SST(0x03, 0x00, SS_DEF, + "Peripheral device write fault") }, +/* T */{SST(0x03, 0x01, SS_DEF, + "No write current") }, +/* T */{SST(0x03, 0x02, SS_DEF, + "Excessive write errors") }, +/* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO, + "Logical unit not ready, cause not reportable") }, +/* DTLPWRSOMCAE */{SST(0x04, 0x01, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, + "Logical unit is in process of becoming ready") }, +/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO, + "Logical unit not ready, initializing cmd. required") }, +/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_NEDEF|ENXIO, + "Logical unit not ready, manual intervention required")}, +/* DTL O */{SST(0x04, 0x04, SS_NEDEF|EBUSY, + "Logical unit not ready, format in progress") }, +/* DT W OMCA */{SST(0x04, 0x05, SS_NEDEF|EBUSY, + "Logical unit not ready, rebuild in progress") }, +/* DT W OMCA */{SST(0x04, 0x06, SS_NEDEF|EBUSY, + "Logical unit not ready, recalculation in progress") }, +/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_NEDEF|EBUSY, + "Logical unit not ready, operation in progress") }, +/* R */{SST(0x04, 0x08, SS_NEDEF|EBUSY, + "Logical unit not ready, long write in progress") }, +/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_DEF, + "Logical unit does not respond to selection") }, +/* D WR OM */{SST(0x06, 0x00, SS_DEF, + "No reference position found") }, +/* DTL WRSOM */{SST(0x07, 0x00, SS_DEF, + "Multiple peripheral devices selected") }, +/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_DEF, + "Logical unit communication failure") }, +/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_DEF, + "Logical unit communication time-out") }, +/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_DEF, + "Logical unit communication parity error") }, +/* DT R OM */{SST(0x08, 0x03, SS_DEF, + "Logical unit communication crc error (ultra-dma/32)")}, +/* DT WR O */{SST(0x09, 0x00, SS_DEF, + "Track following error") }, +/* WR O */{SST(0x09, 0x01, SS_DEF, + "Tracking servo failure") }, +/* WR O */{SST(0x09, 0x02, SS_DEF, + "Focus servo failure") }, +/* WR O */{SST(0x09, 0x03, SS_DEF, + "Spindle servo failure") }, +/* DT WR O */{SST(0x09, 0x04, SS_DEF, + "Head select fault") }, +/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_NEDEF|ENOSPC, + "Error log overflow") }, +/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_DEF, + "Warning") }, +/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_DEF, + "Specified temperature exceeded") }, +/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_DEF, + "Enclosure degraded") }, +/* T RS */{SST(0x0C, 0x00, SS_DEF, + "Write error") }, +/* D W O */{SST(0x0C, 0x01, SS_NEDEF, + "Write error - recovered with auto reallocation") }, +/* D W O */{SST(0x0C, 0x02, SS_DEF, + "Write error - auto reallocation failed") }, +/* D W O */{SST(0x0C, 0x03, SS_DEF, + "Write error - recommend reassignment") }, +/* DT W O */{SST(0x0C, 0x04, SS_NEPDEF, + "Compression check miscompare error") }, +/* DT W O */{SST(0x0C, 0x05, SS_DEF, + "Data expansion occurred during compression") }, +/* DT W O */{SST(0x0C, 0x06, SS_DEF, + "Block not compressible") }, +/* R */{SST(0x0C, 0x07, SS_DEF, + "Write error - recovery needed") }, +/* R */{SST(0x0C, 0x08, SS_DEF, + "Write error - recovery failed") }, +/* R */{SST(0x0C, 0x09, SS_DEF, + "Write error - loss of streaming") }, +/* R */{SST(0x0C, 0x0A, SS_DEF, + "Write error - padding blocks added") }, +/* D W O */{SST(0x10, 0x00, SS_DEF, + "ID CRC or ECC error") }, +/* DT WRSO */{SST(0x11, 0x00, SS_DEF, + "Unrecovered read error") }, +/* DT W SO */{SST(0x11, 0x01, SS_DEF, + "Read retries exhausted") }, +/* DT W SO */{SST(0x11, 0x02, SS_DEF, + "Error too long to correct") }, +/* DT W SO */{SST(0x11, 0x03, SS_DEF, + "Multiple read errors") }, +/* D W O */{SST(0x11, 0x04, SS_DEF, + "Unrecovered read error - auto reallocate failed") }, +/* WR O */{SST(0x11, 0x05, SS_DEF, + "L-EC uncorrectable error") }, +/* WR O */{SST(0x11, 0x06, SS_DEF, + "CIRC unrecovered error") }, +/* W O */{SST(0x11, 0x07, SS_DEF, + "Data re-synchronization error") }, +/* T */{SST(0x11, 0x08, SS_DEF, + "Incomplete block read") }, +/* T */{SST(0x11, 0x09, SS_DEF, + "No gap found") }, +/* DT O */{SST(0x11, 0x0A, SS_DEF, + "Miscorrected error") }, +/* D W O */{SST(0x11, 0x0B, SS_DEF, + "Unrecovered read error - recommend reassignment") }, +/* D W O */{SST(0x11, 0x0C, SS_DEF, + "Unrecovered read error - recommend rewrite the data")}, +/* DT WR O */{SST(0x11, 0x0D, SS_DEF, + "De-compression CRC error") }, +/* DT WR O */{SST(0x11, 0x0E, SS_DEF, + "Cannot decompress using declared algorithm") }, +/* R */{SST(0x11, 0x0F, SS_DEF, + "Error reading UPC/EAN number") }, +/* R */{SST(0x11, 0x10, SS_DEF, + "Error reading ISRC number") }, +/* R */{SST(0x11, 0x11, SS_DEF, + "Read error - loss of streaming") }, +/* D W O */{SST(0x12, 0x00, SS_DEF, + "Address mark not found for id field") }, +/* D W O */{SST(0x13, 0x00, SS_DEF, + "Address mark not found for data field") }, +/* DTL WRSO */{SST(0x14, 0x00, SS_DEF, + "Recorded entity not found") }, +/* DT WR O */{SST(0x14, 0x01, SS_DEF, + "Record not found") }, +/* T */{SST(0x14, 0x02, SS_DEF, + "Filemark or setmark not found") }, +/* T */{SST(0x14, 0x03, SS_DEF, + "End-of-data not found") }, +/* T */{SST(0x14, 0x04, SS_DEF, + "Block sequence error") }, +/* DT W O */{SST(0x14, 0x05, SS_DEF, + "Record not found - recommend reassignment") }, +/* DT W O */{SST(0x14, 0x06, SS_DEF, + "Record not found - data auto-reallocated") }, +/* DTL WRSOM */{SST(0x15, 0x00, SS_DEF, + "Random positioning error") }, +/* DTL WRSOM */{SST(0x15, 0x01, SS_DEF, + "Mechanical positioning error") }, +/* DT WR O */{SST(0x15, 0x02, SS_DEF, + "Positioning error detected by read of medium") }, +/* D W O */{SST(0x16, 0x00, SS_DEF, + "Data synchronization mark error") }, +/* D W O */{SST(0x16, 0x01, SS_DEF, + "Data sync error - data rewritten") }, +/* D W O */{SST(0x16, 0x02, SS_DEF, + "Data sync error - recommend rewrite") }, +/* D W O */{SST(0x16, 0x03, SS_NEDEF, + "Data sync error - data auto-reallocated") }, +/* D W O */{SST(0x16, 0x04, SS_DEF, + "Data sync error - recommend reassignment") }, +/* DT WRSO */{SST(0x17, 0x00, SS_NEDEF, + "Recovered data with no error correction applied") }, +/* DT WRSO */{SST(0x17, 0x01, SS_NEDEF, + "Recovered data with retries") }, +/* DT WR O */{SST(0x17, 0x02, SS_NEDEF, + "Recovered data with positive head offset") }, +/* DT WR O */{SST(0x17, 0x03, SS_NEDEF, + "Recovered data with negative head offset") }, +/* WR O */{SST(0x17, 0x04, SS_NEDEF, + "Recovered data with retries and/or CIRC applied") }, +/* D WR O */{SST(0x17, 0x05, SS_NEDEF, + "Recovered data using previous sector id") }, +/* D W O */{SST(0x17, 0x06, SS_NEDEF, + "Recovered data without ECC - data auto-reallocated") }, +/* D W O */{SST(0x17, 0x07, SS_NEDEF, + "Recovered data without ECC - recommend reassignment")}, +/* D W O */{SST(0x17, 0x08, SS_NEDEF, + "Recovered data without ECC - recommend rewrite") }, +/* D W O */{SST(0x17, 0x09, SS_NEDEF, + "Recovered data without ECC - data rewritten") }, +/* D W O */{SST(0x18, 0x00, SS_NEDEF, + "Recovered data with error correction applied") }, +/* D WR O */{SST(0x18, 0x01, SS_NEDEF, + "Recovered data with error corr. & retries applied") }, +/* D WR O */{SST(0x18, 0x02, SS_NEDEF, + "Recovered data - data auto-reallocated") }, +/* R */{SST(0x18, 0x03, SS_NEDEF, + "Recovered data with CIRC") }, +/* R */{SST(0x18, 0x04, SS_NEDEF, + "Recovered data with L-EC") }, +/* D WR O */{SST(0x18, 0x05, SS_NEDEF, + "Recovered data - recommend reassignment") }, +/* D WR O */{SST(0x18, 0x06, SS_NEDEF, + "Recovered data - recommend rewrite") }, +/* D W O */{SST(0x18, 0x07, SS_NEDEF, + "Recovered data with ECC - data rewritten") }, +/* D O */{SST(0x19, 0x00, SS_DEF, + "Defect list error") }, +/* D O */{SST(0x19, 0x01, SS_DEF, + "Defect list not available") }, +/* D O */{SST(0x19, 0x02, SS_DEF, + "Defect list error in primary list") }, +/* D O */{SST(0x19, 0x03, SS_DEF, + "Defect list error in grown list") }, +/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_DEF, + "Parameter list length error") }, +/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_DEF, + "Synchronous data transfer error") }, +/* D O */{SST(0x1C, 0x00, SS_DEF, + "Defect list not found") }, +/* D O */{SST(0x1C, 0x01, SS_DEF, + "Primary defect list not found") }, +/* D O */{SST(0x1C, 0x02, SS_DEF, + "Grown defect list not found") }, +/* D W O */{SST(0x1D, 0x00, SS_NEPDEF, + "Miscompare during verify operation" )}, +/* D W O */{SST(0x1E, 0x00, SS_NEDEF, + "Recovered id with ecc correction") }, +/* D O */{SST(0x1F, 0x00, SS_DEF, + "Partial defect list transfer") }, +/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_DEF, + "Invalid command operation code") }, +/* DT WR OM */{SST(0x21, 0x00, SS_DEF, + "Logical block address out of range" )}, +/* DT WR OM */{SST(0x21, 0x01, SS_DEF, + "Invalid element address") }, +/* D */{SST(0x22, 0x00, SS_DEF, + "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */ +/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_NEDEF|EINVAL, + "Invalid field in CDB") }, +/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_NEDEF|ENXIO, + "Logical unit not supported") }, +/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_NEDEF|EINVAL, + "Invalid field in parameter list") }, +/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_NEDEF|EINVAL, + "Parameter not supported") }, +/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_NEDEF|EINVAL, + "Parameter value invalid") }, +/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_DEF, + "Threshold parameters not supported") }, +/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_DEF, + "Invalid release of active persistent reservation") }, +/* DT W O */{SST(0x27, 0x00, SS_NEDEF|EACCES, + "Write protected") }, +/* DT W O */{SST(0x27, 0x01, SS_NEDEF|EACCES, + "Hardware write protected") }, +/* DT W O */{SST(0x27, 0x02, SS_NEDEF|EACCES, + "Logical unit software write protected") }, +/* T */{SST(0x27, 0x03, SS_NEDEF|EACCES, + "Associated write protect") }, +/* T */{SST(0x27, 0x04, SS_NEDEF|EACCES, + "Persistent write protect") }, +/* T */{SST(0x27, 0x05, SS_NEDEF|EACCES, + "Permanent write protect") }, +/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_NEDEF|ENXIO, + "Not ready to ready change, medium may have changed") }, +/* DT WR OM */{SST(0x28, 0x01, SS_DEF, + "Import or export element accessed") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_NEDEF|ENXIO, + "Power on, reset, or bus device reset occurred") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_DEF, + "Power on occurred") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_DEF, + "Scsi bus reset occurred") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_DEF, + "Bus device reset function occurred") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_DEF, + "Device internal reset") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_DEF, + "Transceiver mode changed to single-ended") }, +/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_DEF, + "Transceiver mode changed to LVD") }, +/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_DEF, + "Parameters changed") }, +/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_DEF, + "Mode parameters changed") }, +/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_DEF, + "Log parameters changed") }, +/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_DEF, + "Reservations preempted") }, +/* DTLPWRSO C */{SST(0x2B, 0x00, SS_DEF, + "Copy cannot execute since host cannot disconnect") }, +/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_DEF, + "Command sequence error") }, +/* S */{SST(0x2C, 0x01, SS_DEF, + "Too many windows specified") }, +/* S */{SST(0x2C, 0x02, SS_DEF, + "Invalid combination of windows specified") }, +/* R */{SST(0x2C, 0x03, SS_DEF, + "Current program area is not empty") }, +/* R */{SST(0x2C, 0x04, SS_DEF, + "Current program area is empty") }, +/* T */{SST(0x2D, 0x00, SS_DEF, + "Overwrite error on update in place") }, +/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_DEF, + "Commands cleared by another initiator") }, +/* DT WR OM */{SST(0x30, 0x00, SS_DEF, + "Incompatible medium installed") }, +/* DT WR O */{SST(0x30, 0x01, SS_DEF, + "Cannot read medium - unknown format") }, +/* DT WR O */{SST(0x30, 0x02, SS_DEF, + "Cannot read medium - incompatible format") }, +/* DT */{SST(0x30, 0x03, SS_DEF, + "Cleaning cartridge installed") }, +/* DT WR O */{SST(0x30, 0x04, SS_DEF, + "Cannot write medium - unknown format") }, +/* DT WR O */{SST(0x30, 0x05, SS_DEF, + "Cannot write medium - incompatible format") }, +/* DT W O */{SST(0x30, 0x06, SS_DEF, + "Cannot format medium - incompatible medium") }, +/* DTL WRSOM AE */{SST(0x30, 0x07, SS_DEF, + "Cleaning failure") }, +/* R */{SST(0x30, 0x08, SS_DEF, + "Cannot write - application code mismatch") }, +/* R */{SST(0x30, 0x09, SS_DEF, + "Current session not fixated for append") }, +/* DT WR O */{SST(0x31, 0x00, SS_DEF, + "Medium format corrupted") }, +/* D L R O */{SST(0x31, 0x01, SS_DEF, + "Format command failed") }, +/* D W O */{SST(0x32, 0x00, SS_DEF, + "No defect spare location available") }, +/* D W O */{SST(0x32, 0x01, SS_DEF, + "Defect list update failure") }, +/* T */{SST(0x33, 0x00, SS_DEF, + "Tape length error") }, +/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_DEF, + "Enclosure failure") }, +/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_DEF, + "Enclosure services failure") }, +/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_DEF, + "Unsupported enclosure function") }, +/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_DEF, + "Enclosure services unavailable") }, +/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_DEF, + "Enclosure services transfer failure") }, +/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_DEF, + "Enclosure services transfer refused") }, +/* L */{SST(0x36, 0x00, SS_DEF, + "Ribbon, ink, or toner failure") }, +/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_DEF, + "Rounded parameter") }, +/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_DEF, + "Saving parameters not supported") }, +/* DTL WRSOM */{SST(0x3A, 0x00, SS_NEDEF|ENXIO, + "Medium not present") }, +/* DT WR OM */{SST(0x3A, 0x01, SS_NEDEF|ENXIO, + "Medium not present - tray closed") }, +/* DT WR OM */{SST(0x3A, 0x02, SS_NEDEF|ENXIO, + "Medium not present - tray open") }, +/* TL */{SST(0x3B, 0x00, SS_DEF, + "Sequential positioning error") }, +/* T */{SST(0x3B, 0x01, SS_DEF, + "Tape position error at beginning-of-medium") }, +/* T */{SST(0x3B, 0x02, SS_DEF, + "Tape position error at end-of-medium") }, +/* L */{SST(0x3B, 0x03, SS_DEF, + "Tape or electronic vertical forms unit not ready") }, +/* L */{SST(0x3B, 0x04, SS_DEF, + "Slew failure") }, +/* L */{SST(0x3B, 0x05, SS_DEF, + "Paper jam") }, +/* L */{SST(0x3B, 0x06, SS_DEF, + "Failed to sense top-of-form") }, +/* L */{SST(0x3B, 0x07, SS_DEF, + "Failed to sense bottom-of-form") }, +/* T */{SST(0x3B, 0x08, SS_DEF, + "Reposition error") }, +/* S */{SST(0x3B, 0x09, SS_DEF, + "Read past end of medium") }, +/* S */{SST(0x3B, 0x0A, SS_DEF, + "Read past beginning of medium") }, +/* S */{SST(0x3B, 0x0B, SS_DEF, + "Position past end of medium") }, +/* T S */{SST(0x3B, 0x0C, SS_DEF, + "Position past beginning of medium") }, +/* DT WR OM */{SST(0x3B, 0x0D, SS_NEDEF|ENOSPC, + "Medium destination element full") }, +/* DT WR OM */{SST(0x3B, 0x0E, SS_DEF, + "Medium source element empty") }, +/* R */{SST(0x3B, 0x0F, SS_DEF, + "End of medium reached") }, +/* DT WR OM */{SST(0x3B, 0x11, SS_DEF, + "Medium magazine not accessible") }, +/* DT WR OM */{SST(0x3B, 0x12, SS_DEF, + "Medium magazine removed") }, +/* DT WR OM */{SST(0x3B, 0x13, SS_DEF, + "Medium magazine inserted") }, +/* DT WR OM */{SST(0x3B, 0x14, SS_DEF, + "Medium magazine locked") }, +/* DT WR OM */{SST(0x3B, 0x15, SS_DEF, + "Medium magazine unlocked") }, +/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_DEF, + "Invalid bits in identify message") }, +/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_DEF, + "Logical unit has not self-configured yet") }, +/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_DEF, + "Logical unit failure") }, +/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_DEF, + "Timeout on logical unit") }, +/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_DEF, + "Target operating conditions have changed") }, +/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_DEF, + "Microcode has been changed") }, +/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_DEF, + "Changed operating definition") }, +/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_DEF, + "Inquiry data has changed") }, +/* DT WR OMCAE */{SST(0x3F, 0x04, SS_DEF, + "Component device attached") }, +/* DT WR OMCAE */{SST(0x3F, 0x05, SS_DEF, + "Device identifier changed") }, +/* DT WR OMCAE */{SST(0x3F, 0x06, SS_DEF, + "Redundancy group created or modified") }, +/* DT WR OMCAE */{SST(0x3F, 0x07, SS_DEF, + "Redundancy group deleted") }, +/* DT WR OMCAE */{SST(0x3F, 0x08, SS_DEF, + "Spare created or modified") }, +/* DT WR OMCAE */{SST(0x3F, 0x09, SS_DEF, + "Spare deleted") }, +/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_DEF, + "Volume set created or modified") }, +/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_DEF, + "Volume set deleted") }, +/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_DEF, + "Volume set deassigned") }, +/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_DEF, + "Volume set reassigned") }, +/* D */{SST(0x40, 0x00, SS_DEF, + "Ram failure") }, /* deprecated - use 40 NN instead */ +/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_DEF, + "Diagnostic failure: ASCQ = Component ID") }, +/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_DEF|SSQ_RANGE, + NULL) },/* Range 0x80->0xFF */ +/* D */{SST(0x41, 0x00, SS_DEF, + "Data path failure") }, /* deprecated - use 40 NN instead */ +/* D */{SST(0x42, 0x00, SS_DEF, + "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */ +/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_DEF, + "Message error") }, +/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_DEF, + "Internal target failure") }, +/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_DEF, + "Select or reselect failure") }, +/* DTLPWRSOMC */{SST(0x46, 0x00, SS_DEF, + "Unsuccessful soft reset") }, +/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_DEF, + "SCSI parity error") }, +/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_DEF, + "Initiator detected error message received") }, +/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_DEF, + "Invalid message error") }, +/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_DEF, + "Command phase error") }, +/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_DEF, + "Data phase error") }, +/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_DEF, + "Logical unit failed self-configuration") }, +/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_DEF, + "Tagged overlapped commands: ASCQ = Queue tag ID") }, +/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_DEF|SSQ_RANGE, + NULL)}, /* Range 0x00->0xFF */ +/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_DEF, + "Overlapped commands attempted") }, +/* T */{SST(0x50, 0x00, SS_DEF, + "Write append error") }, +/* T */{SST(0x50, 0x01, SS_DEF, + "Write append position error") }, +/* T */{SST(0x50, 0x02, SS_DEF, + "Position error related to timing") }, +/* T O */{SST(0x51, 0x00, SS_DEF, + "Erase failure") }, +/* T */{SST(0x52, 0x00, SS_DEF, + "Cartridge fault") }, +/* DTL WRSOM */{SST(0x53, 0x00, SS_DEF, + "Media load or eject failed") }, +/* T */{SST(0x53, 0x01, SS_DEF, + "Unload tape failure") }, +/* DT WR OM */{SST(0x53, 0x02, SS_DEF, + "Medium removal prevented") }, +/* P */{SST(0x54, 0x00, SS_DEF, + "Scsi to host system interface failure") }, +/* P */{SST(0x55, 0x00, SS_DEF, + "System resource failure") }, +/* D O */{SST(0x55, 0x01, SS_NEDEF|ENOSPC, + "System buffer full") }, +/* R */{SST(0x57, 0x00, SS_DEF, + "Unable to recover table-of-contents") }, +/* O */{SST(0x58, 0x00, SS_DEF, + "Generation does not exist") }, +/* O */{SST(0x59, 0x00, SS_DEF, + "Updated block read") }, +/* DTLPWRSOM */{SST(0x5A, 0x00, SS_DEF, + "Operator request or state change input") }, +/* DT WR OM */{SST(0x5A, 0x01, SS_DEF, + "Operator medium removal request") }, +/* DT W O */{SST(0x5A, 0x02, SS_DEF, + "Operator selected write protect") }, +/* DT W O */{SST(0x5A, 0x03, SS_DEF, + "Operator selected write permit") }, +/* DTLPWRSOM */{SST(0x5B, 0x00, SS_DEF, + "Log exception") }, +/* DTLPWRSOM */{SST(0x5B, 0x01, SS_DEF, + "Threshold condition met") }, +/* DTLPWRSOM */{SST(0x5B, 0x02, SS_DEF, + "Log counter at maximum") }, +/* DTLPWRSOM */{SST(0x5B, 0x03, SS_DEF, + "Log list codes exhausted") }, +/* D O */{SST(0x5C, 0x00, SS_DEF, + "RPL status change") }, +/* D O */{SST(0x5C, 0x01, SS_NEDEF, + "Spindles synchronized") }, +/* D O */{SST(0x5C, 0x02, SS_DEF, + "Spindles not synchronized") }, +/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_DEF, + "Failure prediction threshold exceeded") }, +/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_DEF, + "Failure prediction threshold exceeded (false)") }, +/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_DEF, + "Low power condition on") }, +/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_DEF, + "Idle condition activated by timer") }, +/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_DEF, + "Standby condition activated by timer") }, +/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_DEF, + "Idle condition activated by command") }, +/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_DEF, + "Standby condition activated by command") }, +/* S */{SST(0x60, 0x00, SS_DEF, + "Lamp failure") }, +/* S */{SST(0x61, 0x00, SS_DEF, + "Video acquisition error") }, +/* S */{SST(0x61, 0x01, SS_DEF, + "Unable to acquire video") }, +/* S */{SST(0x61, 0x02, SS_DEF, + "Out of focus") }, +/* S */{SST(0x62, 0x00, SS_DEF, + "Scan head positioning error") }, +/* R */{SST(0x63, 0x00, SS_DEF, + "End of user area encountered on this track") }, +/* R */{SST(0x63, 0x01, SS_NEDEF|ENOSPC, + "Packet does not fit in available space") }, +/* R */{SST(0x64, 0x00, SS_DEF, + "Illegal mode for this track") }, +/* R */{SST(0x64, 0x01, SS_DEF, + "Invalid packet size") }, +/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_DEF, + "Voltage fault") }, +/* S */{SST(0x66, 0x00, SS_DEF, + "Automatic document feeder cover up") }, +/* S */{SST(0x66, 0x01, SS_DEF, + "Automatic document feeder lift up") }, +/* S */{SST(0x66, 0x02, SS_DEF, + "Document jam in automatic document feeder") }, +/* S */{SST(0x66, 0x03, SS_DEF, + "Document miss feed automatic in document feeder") }, +/* A */{SST(0x67, 0x00, SS_DEF, + "Configuration failure") }, +/* A */{SST(0x67, 0x01, SS_DEF, + "Configuration of incapable logical units failed") }, +/* A */{SST(0x67, 0x02, SS_DEF, + "Add logical unit failed") }, +/* A */{SST(0x67, 0x03, SS_DEF, + "Modification of logical unit failed") }, +/* A */{SST(0x67, 0x04, SS_DEF, + "Exchange of logical unit failed") }, +/* A */{SST(0x67, 0x05, SS_DEF, + "Remove of logical unit failed") }, +/* A */{SST(0x67, 0x06, SS_DEF, + "Attachment of logical unit failed") }, +/* A */{SST(0x67, 0x07, SS_DEF, + "Creation of logical unit failed") }, +/* A */{SST(0x68, 0x00, SS_DEF, + "Logical unit not configured") }, +/* A */{SST(0x69, 0x00, SS_DEF, + "Data loss on logical unit") }, +/* A */{SST(0x69, 0x01, SS_DEF, + "Multiple logical unit failures") }, +/* A */{SST(0x69, 0x02, SS_DEF, + "Parity/data mismatch") }, +/* A */{SST(0x6A, 0x00, SS_DEF, + "Informational, refer to log") }, +/* A */{SST(0x6B, 0x00, SS_DEF, + "State change has occurred") }, +/* A */{SST(0x6B, 0x01, SS_DEF, + "Redundancy level got better") }, +/* A */{SST(0x6B, 0x02, SS_DEF, + "Redundancy level got worse") }, +/* A */{SST(0x6C, 0x00, SS_DEF, + "Rebuild failure occurred") }, +/* A */{SST(0x6D, 0x00, SS_DEF, + "Recalculate failure occurred") }, +/* A */{SST(0x6E, 0x00, SS_DEF, + "Command to logical unit failed") }, +/* T */{SST(0x70, 0x00, SS_DEF, + "Decompression exception short: ASCQ = Algorithm ID") }, +/* T */{SST(0x70, 0xFF, SS_DEF|SSQ_RANGE, + NULL) }, /* Range 0x00 -> 0xFF */ +/* T */{SST(0x71, 0x00, SS_DEF, + "Decompression exception long: ASCQ = Algorithm ID") }, +/* T */{SST(0x71, 0xFF, SS_DEF|SSQ_RANGE, + NULL) }, /* Range 0x00 -> 0xFF */ +/* R */{SST(0x72, 0x00, SS_DEF, + "Session fixation error") }, +/* R */{SST(0x72, 0x01, SS_DEF, + "Session fixation error writing lead-in") }, +/* R */{SST(0x72, 0x02, SS_DEF, + "Session fixation error writing lead-out") }, +/* R */{SST(0x72, 0x03, SS_DEF, + "Session fixation error - incomplete track in session") }, +/* R */{SST(0x72, 0x04, SS_DEF, + "Empty or partially written reserved track") }, +/* R */{SST(0x73, 0x00, SS_DEF, + "CD control error") }, +/* R */{SST(0x73, 0x01, SS_DEF, + "Power calibration area almost full") }, +/* R */{SST(0x73, 0x02, SS_NEDEF|ENOSPC, + "Power calibration area is full") }, +/* R */{SST(0x73, 0x03, SS_DEF, + "Power calibration area error") }, +/* R */{SST(0x73, 0x04, SS_DEF, + "Program memory area update failure") }, +/* R */{SST(0x73, 0x05, SS_DEF, + "program memory area is full") } +}; + +#if !defined(SCSI_NO_SENSE_STRINGS) +const char * +scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) +{ + int i, j; + caddr_t match; + struct asc_table_entry *table[2]; + int table_size[2]; + int num_tables; + + if (inq_data == NULL) + return(NULL); + + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)asc_quirk_table, + sizeof(asc_quirk_table)/sizeof(*asc_quirk_table), + sizeof(*asc_quirk_table), scsi_inquiry_match); + + if (match != NULL) { + table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; + table_size[0] = + ((struct scsi_sense_quirk_entry *)match)->num_ascs; + table[1] = asc_text; + table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); + num_tables = 2; + } else { + table[0] = asc_text; + table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); + num_tables = 1; + } + + for (j = 0; j < num_tables; j++) { + for (i = 0; i < table_size[j]; i++) { + if (table[j][i].asc == asc) { + + /* Check for ranges */ + if ((table[j][i].action & SSQ_RANGE) != 0) { + + if (table[j][i].ascq >= ascq + && table[j][i-1].ascq <= ascq) + return table[j][i-1].desc; + + continue; + } + + if (table[j][i].ascq == ascq) + return table[j][i].desc; + } + } + } + + if (asc >= 0x80 && asc <= 0xff) + return "Vendor Specific ASC"; + + if (ascq >= 0x80 && ascq <= 0xff) + return "Vendor Specific ASCQ"; + + return "Reserved ASC/ASCQ pair"; +} + +#else /* SCSI_NO_SENSE_STRINGS */ +const char * +scsi_sense_desc(int asc, int ascq, struct scsi_inquiry_data *inq_data) +{ + return (""); +} +#endif + +/* + * Given a particular failed CCB and its device type information, return + * the appropriate action from either the sense code quirk table or the + * sense code table. + */ +scsi_sense_action +scsi_error_action(int asc, int ascq, struct scsi_inquiry_data *inq_data) +{ + caddr_t match; + struct asc_table_entry *table[2]; + int table_size[2]; + int num_tables; + int i, j; + + /* + * If we don't have inquiry data, we can't match against any quirk + * entries. + */ + if (inq_data != NULL) { + match = cam_quirkmatch((caddr_t)inq_data, + (caddr_t)asc_quirk_table, + sizeof(asc_quirk_table) / + sizeof(*asc_quirk_table), + sizeof(*asc_quirk_table), + scsi_inquiry_match); + } else + match = NULL; + + if (match != NULL) { + table[0] = ((struct scsi_sense_quirk_entry *)match)->asc_info; + table_size[0] = + ((struct scsi_sense_quirk_entry *)match)->num_ascs; + table[1] = asc_text; + table_size[1] = sizeof(asc_text)/sizeof(asc_text[0]); + num_tables = 2; + } else { + table[0] = asc_text; + table_size[0] = sizeof(asc_text)/sizeof(asc_text[0]); + num_tables = 1; + } + + for (j = 0; j < num_tables; j++) { + for (i = 0; i < table_size[j]; i++) { + if (table[j][i].asc == asc) { + + /* Check for ranges */ + if ((table[j][i].action & SSQ_RANGE) != 0){ + + if (table[j][i].ascq >= ascq + && table[j][i-1].ascq <= ascq) + return table[j][i].action; + + continue; + } + + /* + * Check to see if we have a match. If the + * current ascq in the table is greater + * than our ascq, and there aren't any more + * tables to search, just return the + * default action. + */ + if (table[j][i].ascq == ascq) + return(table[j][i].action); + else if ((j == (num_tables - 1)) && + (table[j][i].ascq > ascq)) + return(SS_DEF); + } + } + } + /* + * If we get to this point, it's most likely a vendor specific + * ASC and we don't have a quirk entry for it. Oh well, we just + * tell the error handling code to take the default action. + */ + return(SS_DEF); +} + +char * +scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string) +{ + u_int8_t cdb_len; + char holdstr[8]; + int i; + + if (cdb_ptr == NULL) + return(""); + + /* Silence warnings */ + cdb_len = 0; + + /* + * This is taken from the SCSI-3 draft spec. + * (T10/1157D revision 0.3) + * The top 3 bits of an opcode are the group code. The next 5 bits + * are the command code. + * Group 0: six byte commands + * Group 1: ten byte commands + * Group 2: ten byte commands + * Group 3: reserved + * Group 4: sixteen byte commands + * Group 5: twelve byte commands + * Group 6: vendor specific + * Group 7: vendor specific + */ + switch((*cdb_ptr >> 5) & 0x7) { + case 0: + cdb_len = 6; + break; + case 1: + case 2: + cdb_len = 10; + break; + case 3: + case 6: + case 7: + /* in this case, just print out the opcode */ + cdb_len = 1; + break; + case 4: + cdb_len = 16; + break; + case 5: + cdb_len = 12; + break; + } + *cdb_string = '\0'; + for (i = 0; i < cdb_len; i++) { + sprintf(holdstr, "%x ", cdb_ptr[i]); + strcat(cdb_string, holdstr); + } + + return(cdb_string); +} +/* + * scsi_sense_print will decode the sense data into human + * readable form. Sense handlers can use this to generate + * a report. + */ +/* + * Because scsi_sense_print() utilizes transport layer functions, it will + * only work in the kernel. + */ +#ifdef KERNEL + +void +scsi_sense_print(struct ccb_scsiio *csio) +{ + struct scsi_sense_data *sense; + u_int32_t info; + int error_code; + int sense_key; + int asc, ascq; + struct ccb_getdev cgd; + u_int8_t command_print; + + sense = &csio->sense_data; + + /* + * If the CDB is a physical address, we can't deal with it.. + */ + if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) + command_print = 0; + else + command_print = 1; + + /* + * Get the device information. + */ + xpt_setup_ccb(&cgd.ccb_h, + csio->ccb_h.path, + /*priority*/ 1); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + + /* + * If the device is unconfigured, just pretend that it is a hard + * drive. scsi_op_desc() needs this. + */ + if (cgd.ccb_h.status == CAM_DEV_NOT_THERE) + cgd.inq_data.device = T_DIRECT; + + if (command_print != 0) { + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; + + xpt_print_path(csio->ccb_h.path); + + if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { + printf("%s. CDB: %s\n", + scsi_op_desc(csio->cdb_io.cdb_ptr[0], + &cgd.inq_data), + scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str)); + } else { + printf("%s. CDB: %s\n", + scsi_op_desc(csio->cdb_io.cdb_bytes[0], + &cgd.inq_data), scsi_cdb_string( + (u_int8_t *)&csio->cdb_io.cdb_bytes, cdb_str)); + } + } + + /* + * If the sense data is a physical pointer, forget it. + */ + if (csio->ccb_h.flags & CAM_SENSE_PTR) { + if (csio->ccb_h.flags & CAM_SENSE_PHYS) + return; + else { + /* + * XXX KDM this is stupid, but casting the + * structure doesn't work... + */ + bcopy(&csio->sense_data, sense, + sizeof(struct scsi_sense_data *)); + } + } else { + /* + * If the physical sense flag is set, but the sense pointer + * is not also set, we assume that the user is an idiot and + * return. (Well, okay, it could be that somehow, the + * entire csio is physical, but we would have probably core + * dumped on one of the bogus pointer deferences above + * already.) + */ + if (csio->ccb_h.flags & CAM_SENSE_PHYS) + return; + else + sense = &csio->sense_data; + } + + xpt_print_path(csio->ccb_h.path); + error_code = sense->error_code & SSD_ERRCODE; + sense_key = sense->flags & SSD_KEY; + + switch (error_code) { + case SSD_DEFERRED_ERROR: + printf("Deferred Error: "); + /* FALLTHROUGH */ + case SSD_CURRENT_ERROR: + + printf("%s", scsi_sense_key_text[sense_key]); + info = scsi_4btoul(sense->info); + + if (sense->error_code & SSD_ERRCODE_VALID) { + + switch (sense_key) { + case SSD_KEY_NOT_READY: + case SSD_KEY_ILLEGAL_REQUEST: + case SSD_KEY_UNIT_ATTENTION: + case SSD_KEY_DATA_PROTECT: + break; + case SSD_KEY_BLANK_CHECK: + printf(" req sz: %d (decimal)", + info); + break; + default: + if (info) { + if (sense->flags & SSD_ILI) { + printf(" ILI (length mismatch):" + " %d", info); + } else { + printf(" info:%x", info); + } + } + } + } else if (info) + printf(" info?:%x", info); + + if (sense->extra_len >= 4) { + if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { + printf(" csi:%x,%x,%x,%x", + sense->cmd_spec_info[0], + sense->cmd_spec_info[1], + sense->cmd_spec_info[2], + sense->cmd_spec_info[3]); + } + } + + asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; + ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; + + if (asc || ascq) { + const char *desc = scsi_sense_desc(asc, ascq, + &cgd.inq_data); + printf(" asc:%x,%x\n", asc, ascq); + + xpt_print_path(csio->ccb_h.path); + printf("%s", desc); + } + + if (sense->extra_len >= 7 && sense->fru) { + printf(" field replaceable unit: %x", sense->fru); + } + + if ((sense->extra_len >= 10) + && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { + printf(" sks:%x,%x", sense->sense_key_spec[0], + scsi_2btoul(&sense->sense_key_spec[1])); + } + break; + + default: + printf("error code %d", + sense->error_code & SSD_ERRCODE); + if (sense->error_code & SSD_ERRCODE_VALID) { + printf(" at block no. %d (decimal)", + info = scsi_4btoul(sense->info)); + } + } + + printf("\n"); +} + +#else /* !KERNEL */ + + +char * +scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio, + char *str, int str_len) +{ + struct scsi_sense_data *sense; + u_int32_t info; + int error_code; + int sense_key; + int asc, ascq; + u_int8_t command_print; + char path_str[64]; + char tmpstr[2048]; + int tmpstrlen = 2048; + int cur_len = 0, retlen; + + if ((device == NULL) || (csio == NULL) || (str == NULL)) + return(NULL); + + if (str_len <= 0) + return(NULL); + + /* + * If the CDB is a physical address, we can't deal with it.. + */ + if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0) + command_print = 0; + else + command_print = 1; + + cam_path_string(device, path_str, 64); + + str[0] = '\0'; + + sense = NULL; + + if (command_print != 0) { + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; + + retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); + + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + + if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) { + retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", + scsi_op_desc(csio->cdb_io.cdb_ptr[0], + &device->inq_data), + scsi_cdb_string(csio->cdb_io.cdb_ptr, + cdb_str)); + } else { + retlen = snprintf(tmpstr, tmpstrlen, "%s. CDB: %s\n", + scsi_op_desc(csio->cdb_io.cdb_bytes[0], + &device->inq_data), scsi_cdb_string( + (u_int8_t *)&csio->cdb_io.cdb_bytes, cdb_str)); + } + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + + /* + * If the sense data is a physical pointer, forget it. + */ + if (csio->ccb_h.flags & CAM_SENSE_PTR) { + if (csio->ccb_h.flags & CAM_SENSE_PHYS) + return(NULL); + else { + /* + * XXX KDM this is stupid, but casting the + * structure doesn't work... + */ + bcopy(&csio->sense_data, sense, + sizeof(struct scsi_sense_data *)); + } + } else { + /* + * If the physical sense flag is set, but the sense pointer + * is not also set, we assume that the user is an idiot and + * return. (Well, okay, it could be that somehow, the + * entire csio is physical, but we would have probably core + * dumped on one of the bogus pointer deferences above + * already.) + */ + if (csio->ccb_h.flags & CAM_SENSE_PHYS) + return(NULL); + else + sense = &csio->sense_data; + } + + + retlen = snprintf(tmpstr, tmpstrlen, "%s", path_str); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + + error_code = sense->error_code & SSD_ERRCODE; + sense_key = sense->flags & SSD_KEY; + + switch (error_code) { + case SSD_DEFERRED_ERROR: + retlen = snprintf(tmpstr, tmpstrlen, "Deferred Error: "); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + /* FALLTHROUGH */ + case SSD_CURRENT_ERROR: + + retlen = snprintf(tmpstr, tmpstrlen, "%s", + scsi_sense_key_text[sense_key]); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + + info = scsi_4btoul(sense->info); + + if (sense->error_code & SSD_ERRCODE_VALID) { + + switch (sense_key) { + case SSD_KEY_NOT_READY: + case SSD_KEY_ILLEGAL_REQUEST: + case SSD_KEY_UNIT_ATTENTION: + case SSD_KEY_DATA_PROTECT: + break; + case SSD_KEY_BLANK_CHECK: + retlen = snprintf(tmpstr, tmpstrlen, + " req sz: %d (decimal)", + info); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + break; + default: + if (info) { + if (sense->flags & SSD_ILI) { + retlen = snprintf (tmpstr, + tmpstrlen, + " ILI (length " + "mismatch): %d", info); + + } else { + retlen = snprintf(tmpstr, + tmpstrlen, + " info:%x", + info); + } + strncat(str, tmpstr, + str_len - cur_len - 1); + cur_len += retlen; + } + } + } else if (info) { + retlen = snprintf(tmpstr, tmpstrlen," info?:%x", info); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + + if (sense->extra_len >= 4) { + if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) { + retlen = snprintf(tmpstr, tmpstrlen, + " csi:%x,%x,%x,%x", + sense->cmd_spec_info[0], + sense->cmd_spec_info[1], + sense->cmd_spec_info[2], + sense->cmd_spec_info[3]); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + } + + asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; + ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; + + if (asc || ascq) { + const char *desc = scsi_sense_desc(asc, ascq, + &device->inq_data); + retlen = snprintf(tmpstr, tmpstrlen, + " asc:%x,%x\n%s%s", asc, ascq, + path_str, desc); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + + if (sense->extra_len >= 7 && sense->fru) { + retlen = snprintf(tmpstr, tmpstrlen, + " field replaceable unit: %x", + sense->fru); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + + if ((sense->extra_len >= 10) + && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) { + retlen = snprintf(tmpstr, tmpstrlen, " sks:%x,%x", + sense->sense_key_spec[0], + scsi_2btoul(&sense->sense_key_spec[1])); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + break; + + default: + retlen = snprintf(tmpstr, tmpstrlen, "error code %d", + sense->error_code & SSD_ERRCODE); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + + if (sense->error_code & SSD_ERRCODE_VALID) { + retlen = snprintf(tmpstr, tmpstrlen, + " at block no. %d (decimal)", + info = scsi_4btoul(sense->info)); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + } + } + + retlen = snprintf(tmpstr, tmpstrlen, "\n"); + strncat(str, tmpstr, str_len - cur_len - 1); + cur_len += retlen; + + return(str); +} + +void +scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio, + FILE *ofile) +{ + char str[2048]; + + if ((device == NULL) || (csio == NULL) || (ofile == NULL)) + return; + + fprintf(ofile, "%s", scsi_sense_string(device, csio, str, 2048)); +} + +#endif /* KERNEL/!KERNEL */ + +#ifdef KERNEL +int +scsi_interpret_sense(union ccb *ccb, u_int32_t sense_flags, + u_int32_t *relsim_flags, u_int32_t *openings, + u_int32_t *timeout, scsi_sense_action error_action) +#else +int +scsi_interpret_sense(struct cam_device *device, union ccb *ccb, + u_int32_t sense_flags, u_int32_t *relsim_flags, + u_int32_t *openings, u_int32_t *timeout, + scsi_sense_action error_action) +#endif +{ + struct scsi_sense_data *sense; + int error_code, sense_key, asc, ascq; + int error; + int print_sense; + struct ccb_scsiio *csio; + int retry; + + csio = &ccb->csio; + sense = &csio->sense_data; + scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); + +#ifdef KERNEL + if ((sense_flags & SF_NO_PRINT) == 0 || bootverbose) +#else + if ((sense_flags & SF_NO_PRINT) == 0) +#endif + print_sense = TRUE; + else + print_sense = FALSE; + + switch (error_code) { + case SSD_DEFERRED_ERROR: + { + /* + * XXX dufault@FreeBSD.org + * This error doesn't relate to the command associated + * with this request sense. A deferred error is an error + * for a command that has already returned GOOD status + * (see 8.2.14.2). + * + * By my reading of that section, it looks like the current + * command has been cancelled, we should now clean things up + * (hopefully recovering any lost data) and then retry the + * current command. There are two easy choices, both wrong: + * + * 1. Drop through (like we had been doing), thus treating + * this as if the error were for the current command and + * return and stop the current command. + * + * 2. Issue a retry (like I made it do) thus hopefully + * recovering the current transfer, and ignoring the + * fact that we've dropped a command. + * + * These should probably be handled in a device specific + * sense handler or punted back up to a user mode daemon + */ + + /* decrement the number of retries */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + + error = ERESTART; + break; + } + case SSD_CURRENT_ERROR: + { + + switch (sense_key) { + case SSD_KEY_NO_SENSE: + /* Why were we called then? Well don't bail now */ + /* FALLTHROUGH */ + case SSD_KEY_EQUAL: + /* These should be filtered by the peripheral drivers */ + /* FALLTHROUGH */ + case SSD_KEY_MISCOMPARE: + print_sense = FALSE; + /* FALLTHROUGH */ + case SSD_KEY_RECOVERED_ERROR: + + /* decrement the number of retries */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + + error = 0; + break; + case SSD_KEY_ILLEGAL_REQUEST: + if ((sense_flags & SF_QUIET_IR) != 0) + print_sense = FALSE; + + /* FALLTHROUGH */ + case SSD_KEY_NOT_READY: + case SSD_KEY_DATA_PROTECT: + case SSD_KEY_VOLUME_OVERFLOW: + case SSD_KEY_BLANK_CHECK: /* should be filtered out by + peripheral drivers */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + + if ((error_action & SSQ_PRINT_SENSE) == 0) + print_sense = FALSE; + + error = error_action & SS_ERRMASK; + + break; + case SSD_KEY_UNIT_ATTENTION: + /* + * This should also be filtered out by + * peripheral drivers since each has a different + * concept of what it means to invalidate the media. + */ + if ((sense_flags & SF_RETRY_UA) != 0) { + /* don't decrement retry count */ + error = ERESTART; + print_sense = FALSE; + } else { + /* decrement the number of retries */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + + if ((error_action & SSQ_PRINT_SENSE) == 0) + print_sense = FALSE; + + error = error_action & SS_ERRMASK; + } + break; + default: + /* decrement the number of retries */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + + if ((error_action & SSQ_PRINT_SENSE) == 0) + print_sense = FALSE; + + error = error_action & SS_ERRMASK; + } + break; + } + default: + /* decrement the number of retries */ + retry = ccb->ccb_h.retry_count > 0; + if (retry) + ccb->ccb_h.retry_count--; + error =EIO; + break; + } + + if (print_sense) { +#ifdef KERNEL + scsi_sense_print(csio); +#else + scsi_sense_print(device, csio, stdout); +#endif + } + + return (error); +} + +void +scsi_print_inquiry(struct scsi_inquiry_data *inq_data) +{ + u_int8_t type; + char *dtype, *qtype; + char vendor[16], product[48], revision[16]; + + type = SID_TYPE(inq_data); + + /* + * Figure out basic device type and qualifier. + */ + if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) { + qtype = "(vendor-unique qualifier)"; + } else { + switch (SID_QUAL(inq_data)) { + case SID_QUAL_LU_CONNECTED: + qtype = ""; + break; + + case SID_QUAL_LU_OFFLINE: + qtype = "(offline)"; + break; + + case SID_QUAL_RSVD: + qtype = "(reserved qualifier)"; + break; + default: + case SID_QUAL_BAD_LU: + qtype = "(lun not supported)"; + break; + } + } + + switch (type) { + case T_DIRECT: + dtype = "Direct Access"; + break; + case T_SEQUENTIAL: + dtype = "Sequential Access"; + break; + case T_PRINTER: + dtype = "Printer"; + break; + case T_PROCESSOR: + dtype = "Processor"; + break; + case T_CDROM: + dtype = "CD-ROM"; + break; + case T_WORM: + dtype = "Worm"; + break; + case T_SCANNER: + dtype = "Scanner"; + break; + case T_OPTICAL: + dtype = "Optical"; + break; + case T_CHANGER: + dtype = "Changer"; + break; + case T_COMM: + dtype = "Communication"; + break; + case T_STORARRAY: + dtype = "Storage Arrray"; + break; + case T_ENCLOSURE: + dtype = "Enclosure Services"; + break; + case T_NODEVICE: + dtype = "Uninstalled"; + default: + dtype = "unknown"; + break; + } + + cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), + sizeof(vendor)); + cam_strvis(product, inq_data->product, sizeof(inq_data->product), + sizeof(product)); + cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), + sizeof(revision)); + + printf("<%s %s %s> %s %s SCSI%d device %s\n", + vendor, product, revision, + SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed", + dtype, SID_ANSI_REV(inq_data), qtype); +} + +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + * I believe that FAST-40 has already been defined... + */ +static struct { + u_int period_factor; + u_int period; /* in 10ths of ns */ +} scsi_syncrates[] = { + { 0x0a, 250 }, + { 0x0b, 303 }, + { 0x0c, 500 } +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +u_int +scsi_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (10000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + +/* + * Return the SCSI sync parameter that corresponsd to + * the passed in period in 10ths of ns. + */ +u_int +scsi_calc_syncparam(u_int period) +{ + int i; + int num_syncrates; + + if (period == 0) + return (~0); /* Async */ + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period <= scsi_syncrates[i].period) { + /* Period in kHz */ + return (scsi_syncrates[i].period_factor); + } + } + + /* + * Wasn't in the table, so use the standard + * 1/4 period in ns conversion. + */ + return (period/40); +} + +void +scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_test_unit_ready *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = TEST_UNIT_READY; +} + +void +scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_request_sense *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_IN, + tag_action, + data_ptr, + dxfer_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = REQUEST_SENSE; +} + +void +scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len, + int evpd, u_int8_t page_code, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_inquiry *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/inq_buf, + /*dxfer_len*/inq_len, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = INQUIRY; + if (evpd) { + scsi_cmd->byte2 |= SI_EVPD; + scsi_cmd->page_code = page_code; + } + scsi_cmd->length = inq_len; +} + +void +scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int dbd, u_int8_t page_code, + u_int8_t page, u_int8_t *param_buf, u_int32_t param_len, + u_int8_t sense_len, u_int32_t timeout) +{ + u_int8_t cdb_len; + + /* + * Use the smallest possible command to perform the operation. + */ + if (param_len < 256) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_mode_sense_6 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SENSE_6; + if (dbd != 0) + scsi_cmd->byte2 |= SMS_DBD; + scsi_cmd->page = page_code | page; + scsi_cmd->length = param_len; + cdb_len = sizeof(*scsi_cmd); + } else { + /* + * Need a 10 byte cdb. + */ + struct scsi_mode_sense_10 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SENSE_10; + if (dbd != 0) + scsi_cmd->byte2 |= SMS_DBD; + scsi_cmd->page = page_code | page; + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + } + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_IN, + tag_action, + param_buf, + param_len, + sense_len, + cdb_len, + timeout); +} + +void +scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int scsi_page_fmt, int save_pages, + u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len, + u_int32_t timeout) +{ + u_int8_t cdb_len; + + /* + * Use the smallest possible command to perform the operation. + */ + if (param_len < 256) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_mode_select_6 *scsi_cmd; + + scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SELECT_6; + if (scsi_page_fmt != 0) + scsi_cmd->byte2 |= SMS_PF; + if (save_pages != 0) + scsi_cmd->byte2 |= SMS_SP; + scsi_cmd->length = param_len; + cdb_len = sizeof(*scsi_cmd); + } else { + /* + * Need a 10 byte cdb. + */ + struct scsi_mode_select_10 *scsi_cmd; + + scsi_cmd = + (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = MODE_SELECT_10; + if (scsi_page_fmt != 0) + scsi_cmd->byte2 |= SMS_PF; + if (save_pages != 0) + scsi_cmd->byte2 |= SMS_SP; + scsi_ulto2b(param_len, scsi_cmd->length); + cdb_len = sizeof(*scsi_cmd); + } + cam_fill_csio(csio, + retries, + cbfcnp, + CAM_DIR_OUT, + tag_action, + param_buf, + param_len, + sense_len, + cdb_len, + timeout); +} + + +/* XXX allow specification of address and PMI bit and LBA */ +void +scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, + struct scsi_read_capacity_data *rcap_buf, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_read_capacity *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + /*data_ptr*/(u_int8_t *)rcap_buf, + /*dxfer_len*/sizeof(*rcap_buf), + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = READ_CAPACITY; +} + +/* + * Prevent or allow the user to remove the media + */ +void +scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int8_t action, + u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_prevent *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = PREVENT_ALLOW; + scsi_cmd->how = action; +} + +/* + * Syncronize the media to the contents of the cache for + * the given lba/count pair. Specifying 0/0 means sync + * the whole cache. + */ +void +scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, u_int32_t begin_lba, + u_int16_t lb_count, u_int8_t sense_len, + u_int32_t timeout) +{ + struct scsi_sync_cache *scsi_cmd; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + + scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = SYNCHRONIZE_CACHE; + scsi_ulto4b(begin_lba, scsi_cmd->begin_lba); + scsi_ulto2b(lb_count, scsi_cmd->lb_count); +} + +/* + * Try make as good a match as possible with + * available sub drivers + */ +int +scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) +{ + struct scsi_inquiry_pattern *entry; + struct scsi_inquiry_data *inq; + + entry = (struct scsi_inquiry_pattern *)table_entry; + inq = (struct scsi_inquiry_data *)inqbuffer; + + if (((SID_TYPE(inq) == entry->type) + || (entry->type == T_ANY)) + && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE + : entry->media_type & SIP_MEDIA_FIXED) + && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) + && (cam_strmatch(inq->product, entry->product, sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, sizeof(inq->revision)) == 0)) { + return (0); + } + return (-1); +} + +/* + * Try make as good a match as possible with + * available sub drivers + */ +int +scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) +{ + struct scsi_static_inquiry_pattern *entry; + struct scsi_inquiry_data *inq; + + entry = (struct scsi_static_inquiry_pattern *)table_entry; + inq = (struct scsi_inquiry_data *)inqbuffer; + + if (((SID_TYPE(inq) == entry->type) + || (entry->type == T_ANY)) + && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE + : entry->media_type & SIP_MEDIA_FIXED) + && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) + && (cam_strmatch(inq->product, entry->product, sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, sizeof(inq->revision)) == 0)) { + return (0); + } + return (-1); +} |