Home | History | Annotate | Download | only in ltpscsi
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include "sg_include.h"
      5 #include "sg_err.h"
      6 
      7 /* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c
      8 *  which I guess was written by:
      9 *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
     10 
     11 * The rest of this is:
     12 *  Copyright (C) 1999 - 2003 D. Gilbert
     13 *
     14 *  This program is free software; you can redistribute it and/or modify
     15 *  it under the terms of the GNU General Public License as published by
     16 *  the Free Software Foundation; either version 2, or (at your option)
     17 *  any later version.
     18 *
     19 *  ASCII values for a number of symbolic constants, printing functions, etc.
     20 *
     21 *  Some of the tables have been updated for SCSI 2.
     22 *  Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
     23 *
     24 *  Version 0.89 (20030313)
     25 *      sense key specific field (bytes 15-17) decoding [Trent Piepho]
     26 */
     27 
     28 #define OUTP stderr
     29 
     30 static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12,
     31 	16, 12, 10, 10
     32 };
     33 
     34 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
     35 
     36 static const char unknown[] = "UNKNOWN";
     37 
     38 static const char *group_0_commands[] = {
     39 /* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
     40 /* 04-07 */ "Format Unit", "Read Block Limits", unknown,
     41 	    "Reasssign Blocks",
     42 /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown,
     43 	    unknown,
     44 /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space",
     45 	    "Inquiry",
     46 /* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve",
     47 /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
     48 /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic",
     49 /* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
     50 };
     51 
     52 static const char *group_1_commands[] = {
     53 /* 20-23 */ unknown, unknown, unknown, "Read Format capacities",
     54 /* 24-28 */ "Set window", "Read Capacity",
     55 	unknown, unknown, "Read (10)",
     56 /* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase",
     57 	"Read updated block",
     58 /* 2e-31 */ "Write Verify", "Verify", "Search High", "Search Equal",
     59 /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position",
     60 /* 35-37 */ "Synchronize Cache", "Lock/Unlock Cache",
     61 	    "Read Defect Data",
     62 /* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
     63 	"Read Buffer",
     64 /* 3d-3f */ "Update Block", "Read Long", "Write Long",
     65 };
     66 
     67 static const char *group_2_commands[] = {
     68 /* 40-41 */ "Change Definition", "Write Same",
     69 /* 42-48 */ "Read sub-channel", "Read TOC", "Read header",
     70 	"Play audio (10)", "Get configuration", "Play audio msf",
     71 	"Play audio track/index",
     72 /* 49-4f */ "Play track relative (10)", "Get event status notification",
     73 	"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
     74 	unknown,
     75 /* 50-55 */ "Xdwrite", "Xpwrite, Read disk info",
     76 	    "Xdread, Read track info",
     77 	"Reserve track", "Send OPC onfo", "Mode Select (10)",
     78 /* 56-5b */ "Reserve (10)", "Release (10)", "Repair track",
     79 	    "Read master cue",
     80 	"Mode Sense (10)", "Close track/session",
     81 /* 5c-5f */ "Read buffer capacity", "Send cue sheet",
     82 	    "Persistent reserve in",
     83 	"Persistent reserve out",
     84 };
     85 
     86 /* The following are 16 byte commands in group 4 */
     87 static const char *group_4_commands[] = {
     88 /* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)",
     89 	    "Extended copy",
     90 	"Receive copy results",
     91 /* 85-89 */ "Memory Export In (16)", "Access control in",
     92 	    "Access control out",
     93 	"Read (16)", "Memory Export Out (16)",
     94 /* 8a-8f */ "Write (16)", unknown, "Read attributes",
     95 	    "Write attributes",
     96 	"Write and verify (16)", "Verify (16)",
     97 /* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)",
     98 	"Lock/unlock cache (16)", "Write same (16)", unknown,
     99 /* 95-99 */ unknown, unknown, unknown, unknown, unknown,
    100 /* 9a-9f */ unknown, unknown, unknown, unknown, "Service action in",
    101 	"Service action out",
    102 };
    103 
    104 /* The following are 12 byte commands in group 5 */
    105 static const char *group_5_commands[] = {
    106 /* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance (in)",
    107 	"Maintenance (out)", "Move medium/play audio(12)",
    108 /* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)",
    109 	"Play track relative(12)",
    110 /* aa-ae */ "Write(12)", unknown, "Erase(12), Get Performance",
    111 	"Read DVD structure", "Write and verify(12)",
    112 /* af-b1 */ "Verify(12)", "Search data high(12)",
    113 	    "Search data equal(12)",
    114 /* b2-b4 */ "Search data low(12)", "Set limits(12)",
    115 	"Read element status attached",
    116 /* b5-b6 */ "Request volume element address",
    117 	    "Send volume tag, set streaming",
    118 /* b7-b9 */ "Read defect data(12)", "Read element status",
    119 	    "Read CD msf",
    120 /* ba-bc */ "Redundancy group (in), Scan",
    121 	"Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd",
    122 /* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd",
    123 	"Volume set (out), Send DVD structure",
    124 };
    125 
    126 #define group(opcode) (((opcode) >> 5) & 7)
    127 
    128 #define RESERVED_GROUP  0
    129 #define VENDOR_GROUP    1
    130 
    131 static const char **commands[] = {
    132 	group_0_commands, group_1_commands, group_2_commands,
    133 	(const char **)RESERVED_GROUP, group_4_commands,
    134 	group_5_commands, (const char **)VENDOR_GROUP,
    135 	(const char **)VENDOR_GROUP
    136 };
    137 
    138 static const char reserved[] = "RESERVED";
    139 static const char vendor[] = "VENDOR SPECIFIC";
    140 
    141 static void print_opcode(int opcode)
    142 {
    143 	const char **table = commands[group(opcode)];
    144 
    145 	switch ((unsigned long)table) {
    146 	case RESERVED_GROUP:
    147 		fprintf(OUTP, "%s(0x%02x)", reserved, opcode);
    148 		break;
    149 	case VENDOR_GROUP:
    150 		fprintf(OUTP, "%s(0x%02x)", vendor, opcode);
    151 		break;
    152 	default:
    153 		fprintf(OUTP, "%s", table[opcode & 0x1f]);
    154 		break;
    155 	}
    156 }
    157 
    158 void sg_print_command(const unsigned char *command)
    159 {
    160 	int k, s;
    161 	print_opcode(command[0]);
    162 	fprintf(OUTP, " [");
    163 	for (k = 0, s = COMMAND_SIZE(command[0]); k < s; ++k)
    164 		fprintf(OUTP, "%02x ", command[k]);
    165 	fprintf(OUTP, "]\n");
    166 }
    167 
    168 void sg_print_status(int masked_status)
    169 {
    170 	int scsi_status = (masked_status << 1) & 0x7e;
    171 
    172 	sg_print_scsi_status(scsi_status);
    173 }
    174 
    175 void sg_print_scsi_status(int scsi_status)
    176 {
    177 	const char *ccp;
    178 
    179 	scsi_status &= 0x7e;	/* sanitize as much as possible */
    180 	switch (scsi_status) {
    181 	case 0:
    182 		ccp = "Good";
    183 		break;
    184 	case 0x2:
    185 		ccp = "Check Condition";
    186 		break;
    187 	case 0x4:
    188 		ccp = "Condition Met";
    189 		break;
    190 	case 0x8:
    191 		ccp = "Busy";
    192 		break;
    193 	case 0x10:
    194 		ccp = "Intermediate";
    195 		break;
    196 	case 0x14:
    197 		ccp = "Intermediate-Condition Met";
    198 		break;
    199 	case 0x18:
    200 		ccp = "Reservation Conflict";
    201 		break;
    202 	case 0x22:
    203 		ccp = "Command Terminated (obsolete)";
    204 		break;
    205 	case 0x28:
    206 		ccp = "Task set Full";
    207 		break;
    208 	case 0x30:
    209 		ccp = "ACA Active";
    210 		break;
    211 	case 0x40:
    212 		ccp = "Task Aborted";
    213 		break;
    214 	default:
    215 		ccp = "Unknown status";
    216 		break;
    217 	}
    218 	fprintf(OUTP, "%s ", ccp);
    219 }
    220 
    221 /* In brackets is the related SCSI document (see www.t10.org) with the */
    222 /* peripheral device type after the colon */
    223 /* No programmatic use is made of these flags currently */
    224 #define D 0x0001		/* DIRECT ACCESS DEVICE (disk) [SBC-2: 0] */
    225 #define T 0x0002		/* SEQUENTIAL ACCESS DEVICE (tape) [SSC: 1] */
    226 #define L 0x0004		/* PRINTER DEVICE [SSC: 2] */
    227 #define P 0x0008		/* PROCESSOR DEVICE [SPC-2: 3] */
    228 #define W 0x0010		/* WRITE ONCE READ MULTIPLE DEVICE [SBC-2: 4] */
    229 #define R 0x0020		/* CD/DVD DEVICE [MMC-2: 5] */
    230 #define S 0x0040		/* SCANNER DEVICE [SCSI-2 (obsolete): 6] */
    231 #define O 0x0080		/* OPTICAL MEMORY DEVICE [SBC-2: 7] */
    232 #define M 0x0100		/* MEDIA CHANGER DEVICE [SMC-2: 8] */
    233 #define C 0x0200		/* COMMUNICATION DEVICE [SCSI-2 (obsolete): 9] */
    234 #define A 0x0400		/* ARRAY STORAGE [SCC-2: 12] */
    235 #define E 0x0800		/* ENCLOSURE SERVICES DEVICE [SES: 13] */
    236 #define B 0x1000		/* SIMPLIFIED DIRECT ACCESS DEVICE [RBC: 14] */
    237 #define K 0x2000		/* OPTICAL CARD READER/WRITER DEVICE [OCRW: 15] */
    238 
    239 #define SC_ALL_DEVS ( D|T|L|P|W|R|S|O|M|C|A|E|B|K )
    240 
    241 /* oft used strings are encoded using ASCII codes 0x1 to 0x1f . */
    242 /* This is to save space. This encoding should be UTF-8 and */
    243 /* UTF-16 friendly. */
    244 #define SC_AUDIO_PLAY_OPERATION "\x1"
    245 #define SC_LOGICAL_UNIT "\x2"
    246 #define SC_NOT_READY "\x3"
    247 #define SC_OPERATION "\x4"
    248 #define SC_IN_PROGRESS "\x5"
    249 #define SC_HARDWARE_IF "\x6"
    250 #define SC_CONTROLLER_IF "\x7"
    251 #define SC_DATA_CHANNEL_IF "\x8"
    252 #define SC_SERVO_IF "\x9"
    253 #define SC_SPINDLE_IF "\xa"
    254 #define SC_FIRMWARE_IF "\xb"
    255 #define SC_RECOVERED_DATA "\xc"
    256 #define SC_ERROR_RATE_TOO_HIGH "\xd"
    257 #define SC_TIMES_TOO_HIGH "\xe"
    258 
    259 struct error_info {
    260 	unsigned char code1, code2;
    261 	unsigned short int devices;
    262 	const char *text;
    263 };
    264 
    265 struct error_info2 {
    266 	unsigned char code1, code2_min, code2_max;
    267 	unsigned short int devices;
    268 	const char *text;
    269 };
    270 
    271 static struct error_info2 additional2[] = {
    272 	{0x40, 0x00, 0x7f, D, "Ram failure (%x)"},
    273 	{0x40, 0x80, 0xff, D | T | L | P | W | R | S | O | M | C,
    274 	 "Diagnostic failure on component (%x)"},
    275 	{0x41, 0x00, 0xff, D, "Data path failure (%x)"},
    276 	{0x42, 0x00, 0xff, D, "Power-on or self-test failure (%x)"},
    277 	{0, 0, 0, 0, NULL}
    278 };
    279 
    280 static struct error_info additional[] = {
    281 	{0x00, 0x00, SC_ALL_DEVS, "No additional sense information"},
    282 	{0x00, 0x01, T, "Filemark detected"},
    283 	{0x00, 0x02, T | S, "End-of-partition/medium detected"},
    284 	{0x00, 0x03, T, "Setmark detected"},
    285 	{0x00, 0x04, T | S, "Beginning-of-partition/medium detected"},
    286 	{0x00, 0x05, T | L | S, "End-of-data detected"},
    287 	{0x00, 0x06, SC_ALL_DEVS, "I/O process terminated"},
    288 	{0x00, 0x11, R, SC_AUDIO_PLAY_OPERATION SC_IN_PROGRESS},
    289 	{0x00, 0x12, R, SC_AUDIO_PLAY_OPERATION "paused"},
    290 	{0x00, 0x13, R, SC_AUDIO_PLAY_OPERATION "successfully completed"},
    291 	{0x00, 0x14, R, SC_AUDIO_PLAY_OPERATION "stopped due to error"},
    292 	{0x00, 0x15, R, "No current audio status to return"},
    293 	{0x00, 0x16, SC_ALL_DEVS, SC_OPERATION SC_IN_PROGRESS},
    294 	{0x00, 0x17, D | T | L | W | R | S | O | M | A | E | B | K,
    295 	 "Cleaning requested"},
    296 	{0x00, 0x18, T, "Erase" SC_OPERATION SC_IN_PROGRESS},
    297 	{0x00, 0x19, T, "Locate" SC_OPERATION SC_IN_PROGRESS},
    298 	{0x00, 0x1a, T, "Rewind" SC_OPERATION SC_IN_PROGRESS},
    299 	{0x00, 0x1b, T, "Set capacity" SC_OPERATION SC_IN_PROGRESS},
    300 	{0x00, 0x1c, T, "Verify" SC_OPERATION SC_IN_PROGRESS},
    301 	{0x01, 0x00, D | W | O | B | K, "No index/sector signal"},
    302 	{0x02, 0x00, D | W | R | O | M | B | K, "No seek complete"},
    303 	{0x03, 0x00, D | T | L | W | S | O | B | K,
    304 	 "Peripheral device write fault"},
    305 	{0x03, 0x01, T, "No write current"},
    306 	{0x03, 0x02, T, "Excessive write errors"},
    307 	{0x04, 0x00, SC_ALL_DEVS,
    308 	 SC_LOGICAL_UNIT SC_NOT_READY "cause not reportable"},
    309 	{0x04, 0x01, SC_ALL_DEVS,
    310 	 SC_LOGICAL_UNIT "is" SC_IN_PROGRESS "of becoming ready"},
    311 	{0x04, 0x02, SC_ALL_DEVS,
    312 	 SC_LOGICAL_UNIT SC_NOT_READY "initializing cmd. required"},
    313 	{0x04, 0x03, SC_ALL_DEVS,
    314 	 SC_LOGICAL_UNIT SC_NOT_READY "manual intervention required"},
    315 	{0x04, 0x04, D | T | L | R | O | B,
    316 	 SC_LOGICAL_UNIT SC_NOT_READY "format" SC_IN_PROGRESS},
    317 	{0x04, 0x05, D | T | W | O | M | C | A | B | K,
    318 	 SC_LOGICAL_UNIT SC_NOT_READY "rebuild" SC_IN_PROGRESS},
    319 	{0x04, 0x06, D | T | W | O | M | C | A | B | K,
    320 	 SC_LOGICAL_UNIT SC_NOT_READY "recalculation" SC_IN_PROGRESS},
    321 	{0x04, 0x07, SC_ALL_DEVS,
    322 	 SC_LOGICAL_UNIT SC_NOT_READY SC_OPERATION SC_IN_PROGRESS},
    323 	{0x04, 0x08, R,
    324 	 SC_LOGICAL_UNIT SC_NOT_READY "long write" SC_IN_PROGRESS},
    325 	{0x04, 0x09, SC_ALL_DEVS,
    326 	 SC_LOGICAL_UNIT SC_NOT_READY "self-test" SC_IN_PROGRESS},
    327 	{0x04, 0x0a, SC_ALL_DEVS,
    328 	 SC_LOGICAL_UNIT "not accessible, asymmetric access state transition"},
    329 	{0x04, 0x0b, SC_ALL_DEVS,
    330 	 SC_LOGICAL_UNIT "not accessible, target port in standby state"},
    331 	{0x04, 0x0c, SC_ALL_DEVS,
    332 	 SC_LOGICAL_UNIT "not accessible, target port in unavailable state"},
    333 	{0x04, 0x10, SC_ALL_DEVS,
    334 	 SC_LOGICAL_UNIT SC_NOT_READY "auxiliary memory not accessible"},
    335 	{0x05, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K,
    336 	 SC_LOGICAL_UNIT "does not respond to selection"},
    337 	{0x06, 0x00, D | W | R | O | M | B | K, "No reference position found"},
    338 	{0x07, 0x00, D | T | L | W | R | S | O | M | B | K,
    339 	 "Multiple peripheral devices selected"},
    340 	{0x08, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K,
    341 	 SC_LOGICAL_UNIT "communication failure"},
    342 	{0x08, 0x01, D | T | L | W | R | S | O | M | C | A | E | B | K,
    343 	 SC_LOGICAL_UNIT "communication time-out"},
    344 	{0x08, 0x02, D | T | L | W | R | S | O | M | C | A | E | B | K,
    345 	 SC_LOGICAL_UNIT "communication parity error"},
    346 	{0x08, 0x03, D | T | R | O | M | B | K,
    347 	 SC_LOGICAL_UNIT "communication CRC error (Ultra-DMA/32)"},
    348 	{0x08, 0x04, D | T | L | P | W | R | S | O | C | K,
    349 	 "Unreachable copy target"},
    350 	{0x09, 0x00, D | T | W | R | O | B, "Track following error"},
    351 	{0x09, 0x01, W | R | O | K, "Tracking servo failure"},
    352 	{0x09, 0x02, W | R | O | K, "Focus servo failure"},
    353 	{0x09, 0x03, W | R | O, "Spindle servo failure"},
    354 	{0x09, 0x04, D | T | W | R | O | B, "Head select fault"},
    355 	{0x0A, 0x00, SC_ALL_DEVS, "Error log overflow"},
    356 	{0x0B, 0x00, SC_ALL_DEVS, "Warning"},
    357 	{0x0B, 0x01, SC_ALL_DEVS, "Warning - specified temperature exceeded"},
    358 	{0x0B, 0x02, SC_ALL_DEVS, "Warning - enclosure degraded"},
    359 	{0x0C, 0x00, T | R | S, "Write error"},
    360 	{0x0C, 0x01, K, "Write error - recovered with auto reallocation"},
    361 	{0x0C, 0x02, D | W | O | B | K,
    362 	 "Write error - auto reallocation failed"},
    363 	{0x0C, 0x03, D | W | O | B | K, "Write error - recommend reassignment"},
    364 	{0x0C, 0x04, D | T | W | O | B, "Compression check miscompare error"},
    365 	{0x0C, 0x05, D | T | W | O | B,
    366 	 "Data expansion occurred during compression"},
    367 	{0x0C, 0x06, D | T | W | O | B, "Block not compressible"},
    368 	{0x0C, 0x07, R, "Write error - recovery needed"},
    369 	{0x0C, 0x08, R, "Write error - recovery failed"},
    370 	{0x0C, 0x09, R, "Write error - loss of streaming"},
    371 	{0x0C, 0x0A, R, "Write error - padding blocks added"},
    372 	{0x0C, 0x0B, D | T | W | R | O | M | B, "Auxiliary memory write error"},
    373 	{0x0C, 0x0C, SC_ALL_DEVS, "Write error - unexpected unsolicited data"},
    374 	{0x0C, 0x0D, SC_ALL_DEVS, "Write error - not enough unsolicited data"},
    375 	{0x0D, 0x00, D | T | L | P | W | R | S | O | C | A | K,
    376 	 "Error detected by third party temporary initiator"},
    377 	{0x0D, 0x01, D | T | L | P | W | R | S | O | C | A | K,
    378 	 "Third party device failure"},
    379 	{0x0D, 0x02, D | T | L | P | W | R | S | O | C | A | K,
    380 	 "Copy target device not reachable"},
    381 	{0x0D, 0x03, D | T | L | P | W | R | S | O | C | A | K,
    382 	 "Incorrect copy target device"},
    383 	{0x0D, 0x04, D | T | L | P | W | R | S | O | C | A | K,
    384 	 "Copy target device underrun"},
    385 	{0x0D, 0x05, D | T | L | P | W | R | S | O | C | A | K,
    386 	 "Copy target device overrun"},
    387 	{0x10, 0x00, D | W | O | B | K, "Id CRC or ECC error"},
    388 	{0x11, 0x00, D | T | W | R | S | O | B | K, "Unrecovered read error"},
    389 	{0x11, 0x01, D | T | W | R | S | O | B | K, "Read retries exhausted"},
    390 	{0x11, 0x02, D | T | W | R | S | O | B | K,
    391 	 "Error too long to correct"},
    392 	{0x11, 0x03, D | T | W | S | O | B | K, "Multiple read errors"},
    393 	{0x11, 0x04, D | W | O | B | K,
    394 	 "Unrecovered read error - auto reallocate failed"},
    395 	{0x11, 0x05, W | R | O | B, "L-EC uncorrectable error"},
    396 	{0x11, 0x06, W | R | O | B, "CIRC unrecovered error"},
    397 	{0x11, 0x07, W | O | B, "Data re-synchronization error"},
    398 	{0x11, 0x08, T, "Incomplete block read"},
    399 	{0x11, 0x09, T, "No gap found"},
    400 	{0x11, 0x0A, D | T | O | B | K, "Miscorrected error"},
    401 	{0x11, 0x0B, D | W | O | B | K,
    402 	 "Unrecovered read error - recommend reassignment"},
    403 	{0x11, 0x0C, D | W | O | B | K,
    404 	 "Unrecovered read error - recommend rewrite the data"},
    405 	{0x11, 0x0D, D | T | W | R | O | B, "De-compression CRC error"},
    406 	{0x11, 0x0E, D | T | W | R | O | B,
    407 	 "Cannot decompress using declared algorithm"},
    408 	{0x11, 0x0F, R, "Error reading UPC/EAN number"},
    409 	{0x11, 0x10, R, "Error reading ISRC number"},
    410 	{0x11, 0x11, R, "Read error - loss of streaming"},
    411 	{0x11, 0x12, D | T | W | R | O | M | B, "Auxiliary memory read error"},
    412 	{0x11, 0x13, SC_ALL_DEVS, "Read error - failed retransmission request"},
    413 	{0x12, 0x00, D | W | O | B | K, "Address mark not found for id field"},
    414 	{0x13, 0x00, D | W | O | B | K,
    415 	 "Address mark not found for data field"},
    416 	{0x14, 0x00, D | T | L | W | R | S | O | B | K,
    417 	 "Recorded entity not found"},
    418 	{0x14, 0x01, D | T | W | R | O | B | K, "Record not found"},
    419 	{0x14, 0x02, T, "Filemark or setmark not found"},
    420 	{0x14, 0x03, T, "End-of-data not found"},
    421 	{0x14, 0x04, T, "Block sequence error"},
    422 	{0x14, 0x05, D | T | W | O | B | K,
    423 	 "Record not found - recommend reassignment"},
    424 	{0x14, 0x06, D | T | W | O | B | K,
    425 	 "Record not found - data auto-reallocated"},
    426 	{0x14, 0x07, T, "Locate" SC_OPERATION " failure"},
    427 	{0x15, 0x00, D | T | L | W | R | S | O | M | B | K,
    428 	 "Random positioning error"},
    429 	{0x15, 0x01, D | T | L | W | R | S | O | M | B | K,
    430 	 "Mechanical positioning error"},
    431 	{0x15, 0x02, D | T | W | R | O | B | K,
    432 	 "Positioning error detected by read of medium"},
    433 	{0x16, 0x00, D | W | O | B | K, "Data synchronization mark error"},
    434 	{0x16, 0x01, D | W | O | B | K, "Data sync error - data rewritten"},
    435 	{0x16, 0x02, D | W | O | B | K, "Data sync error - recommend rewrite"},
    436 	{0x16, 0x03, D | W | O | B | K,
    437 	 "Data sync error - data auto-reallocated"},
    438 	{0x16, 0x04, D | W | O | B | K,
    439 	 "Data sync error - recommend reassignment"},
    440 	{0x17, 0x00, D | T | W | R | S | O | B | K,
    441 	 SC_RECOVERED_DATA "with no error correction applied"},
    442 	{0x17, 0x01, D | T | W | R | S | O | B | K,
    443 	 SC_RECOVERED_DATA "with retries"},
    444 	{0x17, 0x02, D | T | W | R | O | B | K,
    445 	 SC_RECOVERED_DATA "with positive head offset"},
    446 	{0x17, 0x03, D | T | W | R | O | B | K,
    447 	 SC_RECOVERED_DATA "with negative head offset"},
    448 	{0x17, 0x04, W | R | O | B,
    449 	 SC_RECOVERED_DATA "with retries and/or circ applied"},
    450 	{0x17, 0x05, D | W | R | O | B | K,
    451 	 SC_RECOVERED_DATA "using previous sector id"},
    452 	{0x17, 0x06, D | W | O | B | K,
    453 	 SC_RECOVERED_DATA "without ecc - data auto-reallocated"},
    454 	{0x17, 0x07, D | W | R | O | B | K,
    455 	 SC_RECOVERED_DATA "without ecc - recommend reassignment"},
    456 	{0x17, 0x08, D | W | R | O | B | K,
    457 	 SC_RECOVERED_DATA "without ecc - recommend rewrite"},
    458 	{0x17, 0x09, D | W | R | O | B | K,
    459 	 SC_RECOVERED_DATA "without ecc - data rewritten"},
    460 	{0x18, 0x00, D | T | W | R | O | B | K,
    461 	 SC_RECOVERED_DATA "with error correction applied"},
    462 	{0x18, 0x01, D | W | R | O | B | K,
    463 	 SC_RECOVERED_DATA "with error corr. & retries applied"},
    464 	{0x18, 0x02, D | W | R | O | B | K,
    465 	 SC_RECOVERED_DATA "- data auto-reallocated"},
    466 	{0x18, 0x03, R, SC_RECOVERED_DATA "with CIRC"},
    467 	{0x18, 0x04, R, SC_RECOVERED_DATA "with L-EC"},
    468 	{0x18, 0x05, D | W | R | O | B | K,
    469 	 SC_RECOVERED_DATA "- recommend reassignment"},
    470 	{0x18, 0x06, D | W | R | O | B | K,
    471 	 SC_RECOVERED_DATA "- recommend rewrite"},
    472 	{0x18, 0x07, D | W | O | B | K,
    473 	 SC_RECOVERED_DATA "with ecc - data rewritten"},
    474 	{0x18, 0x08, R, SC_RECOVERED_DATA "with linking"},
    475 	{0x19, 0x00, D | O | K, "Defect list error"},
    476 	{0x19, 0x01, D | O | K, "Defect list not available"},
    477 	{0x19, 0x02, D | O | K, "Defect list error in primary list"},
    478 	{0x19, 0x03, D | O | K, "Defect list error in grown list"},
    479 	{0x1A, 0x00, SC_ALL_DEVS, "Parameter list length error"},
    480 	{0x1B, 0x00, SC_ALL_DEVS, "Synchronous data transfer error"},
    481 	{0x1C, 0x00, D | O | B | K, "Defect list not found"},
    482 	{0x1C, 0x01, D | O | B | K, "Primary defect list not found"},
    483 	{0x1C, 0x02, D | O | B | K, "Grown defect list not found"},
    484 	{0x1D, 0x00, D | T | W | R | O | B | K,
    485 	 "Miscompare during verify" SC_OPERATION},
    486 	{0x1E, 0x00, D | W | O | B | K, "Recovered id with ecc correction"},
    487 	{0x1F, 0x00, D | O | K, "Partial defect list transfer"},
    488 	{0x20, 0x00, SC_ALL_DEVS, "Invalid command" SC_OPERATION " code"},
    489 	{0x20, 0x01, D | T | P | W | R | O | M | A | E | B | K,
    490 	 "Access denied - initiator pending-enrolled"},
    491 	{0x20, 0x02, D | T | P | W | R | O | M | A | E | B | K,
    492 	 "Access denied - no access rights"},
    493 	{0x20, 0x03, D | T | P | W | R | O | M | A | E | B | K,
    494 	 "Access denied - no mgmt id key"},
    495 	{0x20, 0x04, T, "Illegal command while in write capable state"},
    496 	{0x20, 0x05, T, "Obsolete"},
    497 	{0x20, 0x06, T, "Illegal command while in explicit address mode"},
    498 	{0x20, 0x07, T, "Illegal command while in implicit address mode"},
    499 	{0x20, 0x08, D | T | P | W | R | O | M | A | E | B | K,
    500 	 "Access denied - enrollment conflict"},
    501 	{0x20, 0x09, D | T | P | W | R | O | M | A | E | B | K,
    502 	 "Access denied - invalid LU identifier"},
    503 	{0x20, 0x0A, D | T | P | W | R | O | M | A | E | B | K,
    504 	 "Access denied - invalid proxy token"},
    505 	{0x20, 0x0B, D | T | P | W | R | O | M | A | E | B | K,
    506 	 "Access denied - ACL LUN conflict"},
    507 	{0x21, 0x00, D | T | W | R | O | M | B | K,
    508 	 "Logical block address out of range"},
    509 	{0x21, 0x01, D | T | W | R | O | M | B | K, "Invalid element address"},
    510 	{0x21, 0x02, R, "Invalid address for write"},
    511 	{0x22, 0x00, D, "Illegal function (use 20 00,24 00,or 26 00)"},
    512 	{0x24, 0x00, SC_ALL_DEVS, "Invalid field in cdb"},
    513 	{0x24, 0x01, SC_ALL_DEVS, "CDB decryption error"},
    514 	{0x25, 0x00, SC_ALL_DEVS, SC_LOGICAL_UNIT "not supported"},
    515 	{0x26, 0x00, SC_ALL_DEVS, "Invalid field in parameter list"},
    516 	{0x26, 0x01, SC_ALL_DEVS, "Parameter not supported"},
    517 	{0x26, 0x02, SC_ALL_DEVS, "Parameter value invalid"},
    518 	{0x26, 0x03, D | T | L | P | W | R | S | O | M | C | A | E | K,
    519 	 "Threshold parameters not supported"},
    520 	{0x26, 0x04, SC_ALL_DEVS, "Invalid release of persistent reservation"},
    521 	{0x26, 0x05, D | T | L | P | W | R | S | O | M | C | A | B | K,
    522 	 "Data decryption error"},
    523 	{0x26, 0x06, D | T | L | P | W | R | S | O | C | K,
    524 	 "Too many target descriptors"},
    525 	{0x26, 0x07, D | T | L | P | W | R | S | O | C | K,
    526 	 "Unsupported target descriptor type code"},
    527 	{0x26, 0x08, D | T | L | P | W | R | S | O | C | K,
    528 	 "Too many segment descriptors"},
    529 	{0x26, 0x09, D | T | L | P | W | R | S | O | C | K,
    530 	 "Unsupported segment descriptor type code"},
    531 	{0x26, 0x0A, D | T | L | P | W | R | S | O | C | K,
    532 	 "Unexpected inexact segment"},
    533 	{0x26, 0x0B, D | T | L | P | W | R | S | O | C | K,
    534 	 "Inline data length exceeded"},
    535 	{0x26, 0x0C, D | T | L | P | W | R | S | O | C | K,
    536 	 "Invalid" SC_OPERATION " for copy source or destination"},
    537 	{0x26, 0x0D, D | T | L | P | W | R | S | O | C | K,
    538 	 "Copy segment granularity violation"},
    539 	{0x27, 0x00, D | T | W | R | O | B | K, "Write protected"},
    540 	{0x27, 0x01, D | T | W | R | O | B | K, "Hardware write protected"},
    541 	{0x27, 0x02, D | T | W | R | O | B | K,
    542 	 SC_LOGICAL_UNIT "software write protected"},
    543 	{0x27, 0x03, T | R, "Associated write protect"},
    544 	{0x27, 0x04, T | R, "Persistent write protect"},
    545 	{0x27, 0x05, T | R, "Permanent write protect"},
    546 	{0x27, 0x06, R, "Conditional write protect"},
    547 	{0x28, 0x00, SC_ALL_DEVS,
    548 	 "Not ready to ready change, medium may have changed"},
    549 	{0x28, 0x01, D | T | W | R | O | M | B,
    550 	 "Import or export element accessed"},
    551 	{0x29, 0x00, SC_ALL_DEVS,
    552 	 "Power on,reset,or bus device reset occurred"},
    553 	{0x29, 0x01, SC_ALL_DEVS, "Power on occurred"},
    554 	{0x29, 0x02, SC_ALL_DEVS, "Scsi bus reset occurred"},
    555 	{0x29, 0x03, SC_ALL_DEVS, "Bus device reset function occurred"},
    556 	{0x29, 0x04, SC_ALL_DEVS, "Device internal reset"},
    557 	{0x29, 0x05, SC_ALL_DEVS, "Transceiver mode changed to single-ended"},
    558 	{0x29, 0x06, SC_ALL_DEVS, "Transceiver mode changed to lvd"},
    559 	{0x29, 0x07, SC_ALL_DEVS, "I_T nexus loss occurred"},
    560 	{0x2A, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K,
    561 	 "Parameters changed"},
    562 	{0x2A, 0x01, D | T | L | W | R | S | O | M | C | A | E | B | K,
    563 	 "Mode parameters changed"},
    564 	{0x2A, 0x02, D | T | L | W | R | S | O | M | C | A | E | K,
    565 	 "Log parameters changed"},
    566 	{0x2A, 0x03, D | T | L | P | W | R | S | O | M | C | A | E | K,
    567 	 "Reservations preempted"},
    568 	{0x2A, 0x04, D | T | L | P | W | R | S | O | M | C | A | E,
    569 	 "Reservations released"},
    570 	{0x2A, 0x05, D | T | L | P | W | R | S | O | M | C | A | E,
    571 	 "Registrations preempted"},
    572 	{0x2A, 0x06, SC_ALL_DEVS, "Asymmetric access state changed"},
    573 	{0x2A, 0x07, SC_ALL_DEVS,
    574 	 "Implicit asymmetric access state transition failed"},
    575 	{0x2B, 0x00, D | T | L | P | W | R | S | O | C | K,
    576 	 "Copy cannot execute since host cannot disconnect"},
    577 	{0x2C, 0x00, SC_ALL_DEVS, "Command sequence error"},
    578 	{0x2C, 0x01, S, "Too many windows specified"},
    579 	{0x2C, 0x02, S, "Invalid combination of windows specified"},
    580 	{0x2C, 0x03, R, "Current program area is not empty"},
    581 	{0x2C, 0x04, R, "Current program area is empty"},
    582 	{0x2C, 0x05, B, "Illegal power condition request"},
    583 	{0x2C, 0x06, R, "Persistent prevent conflict"},
    584 	{0x2C, 0x07, SC_ALL_DEVS, "Previous busy status"},
    585 	{0x2C, 0x08, SC_ALL_DEVS, "Previous task set full status"},
    586 	{0x2C, 0x09, D | T | L | P | W | R | S | O | M | E | B | K,
    587 	 "Previous reservation conflict status"},
    588 	{0x2D, 0x00, T, "Overwrite error on update in place"},
    589 	{0x2F, 0x00, SC_ALL_DEVS, "Commands cleared by another initiator"},
    590 	{0x30, 0x00, D | T | W | R | O | M | B | K,
    591 	 "Incompatible medium installed"},
    592 	{0x30, 0x01, D | T | W | R | O | B | K,
    593 	 "Cannot read medium - unknown format"},
    594 	{0x30, 0x02, D | T | W | R | O | B | K,
    595 	 "Cannot read medium - incompatible format"},
    596 	{0x30, 0x03, D | T | R | K, "Cleaning cartridge installed"},
    597 	{0x30, 0x04, D | T | W | R | O | B | K,
    598 	 "Cannot write medium - unknown format"},
    599 	{0x30, 0x05, D | T | W | R | O | B | K,
    600 	 "Cannot write medium - incompatible format"},
    601 	{0x30, 0x06, D | T | W | R | O | B,
    602 	 "Cannot format medium - incompatible medium"},
    603 	{0x30, 0x07, D | T | L | W | R | S | O | M | A | E | B | K,
    604 	 "Cleaning failure"},
    605 	{0x30, 0x08, R, "Cannot write - application code mismatch"},
    606 	{0x30, 0x09, R, "Current session not fixated for append"},
    607 	{0x30, 0x10, R, "Medium not formatted"},	/* should ascq be 0xa ?? */
    608 	{0x31, 0x00, D | T | W | R | O | B | K, "Medium format corrupted"},
    609 	{0x31, 0x01, D | L | R | O | B, "Format command failed"},
    610 	{0x31, 0x02, R, "Zoned formatting failed due to spare linking"},
    611 	{0x32, 0x00, D | W | O | B | K, "No defect spare location available"},
    612 	{0x32, 0x01, D | W | O | B | K, "Defect list update failure"},
    613 	{0x33, 0x00, T, "Tape length error"},
    614 	{0x34, 0x00, SC_ALL_DEVS, "Enclosure failure"},
    615 	{0x35, 0x00, SC_ALL_DEVS, "Enclosure services failure"},
    616 	{0x35, 0x01, SC_ALL_DEVS, "Unsupported enclosure function"},
    617 	{0x35, 0x02, SC_ALL_DEVS, "Enclosure services unavailable"},
    618 	{0x35, 0x03, SC_ALL_DEVS, "Enclosure services transfer failure"},
    619 	{0x35, 0x04, SC_ALL_DEVS, "Enclosure services transfer refused"},
    620 	{0x36, 0x00, L, "Ribbon,ink,or toner failure"},
    621 	{0x37, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K,
    622 	 "Rounded parameter"},
    623 	{0x38, 0x00, B, "Event status notification"},
    624 	{0x38, 0x02, B, "Esn - power management class event"},
    625 	{0x38, 0x04, B, "Esn - media class event"},
    626 	{0x38, 0x06, B, "Esn - device busy class event"},
    627 	{0x39, 0x00, D | T | L | W | R | S | O | M | C | A | E | K,
    628 	 "Saving parameters not supported"},
    629 	{0x3A, 0x00, D | T | L | W | R | S | O | M | B | K,
    630 	 "Medium not present"},
    631 	{0x3A, 0x01, D | T | W | R | O | M | B | K,
    632 	 "Medium not present - tray closed"},
    633 	{0x3A, 0x02, D | T | W | R | O | M | B | K,
    634 	 "Medium not present - tray open"},
    635 	{0x3A, 0x03, D | T | W | R | O | M | B,
    636 	 "Medium not present - loadable"},
    637 	{0x3A, 0x04, D | T | W | R | O | M | B,
    638 	 "Medium not present - medium auxiliary memory accessible"},
    639 	{0x3B, 0x00, T | L, "Sequential positioning error"},
    640 	{0x3B, 0x01, T, "Tape position error at beginning-of-medium"},
    641 	{0x3B, 0x02, T, "Tape position error at end-of-medium"},
    642 	{0x3B, 0x03, L, "Tape or electronic vertical forms unit " SC_NOT_READY},
    643 	{0x3B, 0x04, L, "Slew failure"},
    644 	{0x3B, 0x05, L, "Paper jam"},
    645 	{0x3B, 0x06, L, "Failed to sense top-of-form"},
    646 	{0x3B, 0x07, L, "Failed to sense bottom-of-form"},
    647 	{0x3B, 0x08, T, "Reposition error"},
    648 	{0x3B, 0x09, S, "Read past end of medium"},
    649 	{0x3B, 0x0A, S, "Read past beginning of medium"},
    650 	{0x3B, 0x0B, S, "Position past end of medium"},
    651 	{0x3B, 0x0C, T | S, "Position past beginning of medium"},
    652 	{0x3B, 0x0D, D | T | W | R | O | M | B | K,
    653 	 "Medium destination element full"},
    654 	{0x3B, 0x0E, D | T | W | R | O | M | B | K,
    655 	 "Medium source element empty"},
    656 	{0x3B, 0x0F, R, "End of medium reached"},
    657 	{0x3B, 0x11, D | T | W | R | O | M | B | K,
    658 	 "Medium magazine not accessible"},
    659 	{0x3B, 0x12, D | T | W | R | O | M | B | K, "Medium magazine removed"},
    660 	{0x3B, 0x13, D | T | W | R | O | M | B | K, "Medium magazine inserted"},
    661 	{0x3B, 0x14, D | T | W | R | O | M | B | K, "Medium magazine locked"},
    662 	{0x3B, 0x15, D | T | W | R | O | M | B | K, "Medium magazine unlocked"},
    663 	{0x3B, 0x16, R, "Mechanical positioning or changer error"},
    664 	{0x3D, 0x00, D | T | L | P | W | R | S | O | M | C | A | E | K,
    665 	 "Invalid bits in identify message"},
    666 	{0x3E, 0x00, SC_ALL_DEVS,
    667 	 SC_LOGICAL_UNIT "has not self-configured yet"},
    668 	{0x3E, 0x01, SC_ALL_DEVS, SC_LOGICAL_UNIT "failure"},
    669 	{0x3E, 0x02, SC_ALL_DEVS, "Timeout on logical unit"},
    670 	{0x3E, 0x03, SC_ALL_DEVS, SC_LOGICAL_UNIT "failed self-test"},
    671 	{0x3E, 0x04, SC_ALL_DEVS,
    672 	 SC_LOGICAL_UNIT "unable to update self-test log"},
    673 	{0x3F, 0x00, SC_ALL_DEVS, "Target operating conditions have changed"},
    674 	{0x3F, 0x01, SC_ALL_DEVS, "Microcode has been changed"},
    675 	{0x3F, 0x02, D | T | L | P | W | R | S | O | M | C | B | K,
    676 	 "Changed operating definition"},
    677 	{0x3F, 0x03, SC_ALL_DEVS, "Inquiry data has changed"},
    678 	{0x3F, 0x04, D | T | W | R | O | M | C | A | E | B | K,
    679 	 "Component device attached"},
    680 	{0x3F, 0x05, D | T | W | R | O | M | C | A | E | B | K,
    681 	 "Device identifier changed"},
    682 	{0x3F, 0x06, D | T | W | R | O | M | C | A | E | B,
    683 	 "Redundancy group created or modified"},
    684 	{0x3F, 0x07, D | T | W | R | O | M | C | A | E | B,
    685 	 "Redundancy group deleted"},
    686 	{0x3F, 0x08, D | T | W | R | O | M | C | A | E | B,
    687 	 "Spare created or modified"},
    688 	{0x3F, 0x09, D | T | W | R | O | M | C | A | E | B, "Spare deleted"},
    689 	{0x3F, 0x0A, D | T | W | R | O | M | C | A | E | B | K,
    690 	 "Volume set created or modified"},
    691 	{0x3F, 0x0B, D | T | W | R | O | M | C | A | E | B | K,
    692 	 "Volume set deleted"},
    693 	{0x3F, 0x0C, D | T | W | R | O | M | C | A | E | B | K,
    694 	 "Volume set deassigned"},
    695 	{0x3F, 0x0D, D | T | W | R | O | M | C | A | E | B | K,
    696 	 "Volume set reassigned"},
    697 	{0x3F, 0x0E, D | T | L | P | W | R | S | O | M | C | A | E,
    698 	 "Reported luns data has changed"},
    699 	{0x3F, 0x10, D | T | W | R | O | M | B, "Medium loadable"},
    700 	{0x3F, 0x11, D | T | W | R | O | M | B,
    701 	 "Medium auxiliary memory accessible"},
    702 	{0x40, 0x00, D, "Ram failure (should use 40 nn)"},
    703 	/*
    704 	 * FIXME(eric) - need a way to represent wildcards here.
    705 	 */
    706 	{0x40, 0x00, SC_ALL_DEVS,
    707 	 "Diagnostic failure on component nn (80h-ffh)"},
    708 	{0x41, 0x00, D, "Data path failure (should use 40 nn)"},
    709 	{0x42, 0x00, D, "Power-on or self-test failure (should use 40 nn)"},
    710 	{0x43, 0x00, SC_ALL_DEVS, "Message error"},
    711 	{0x44, 0x00, SC_ALL_DEVS, "Internal target failure"},
    712 	{0x45, 0x00, SC_ALL_DEVS, "Select or reselect failure"},
    713 	{0x46, 0x00, D | T | L | P | W | R | S | O | M | C | B | K,
    714 	 "Unsuccessful soft reset"},
    715 	{0x47, 0x00, SC_ALL_DEVS, "Scsi parity error"},
    716 	{0x47, 0x01, SC_ALL_DEVS, "Data phase CRC error detected"},
    717 	{0x47, 0x02, SC_ALL_DEVS,
    718 	 "Scsi parity error detected during st data phase"},
    719 	{0x47, 0x03, SC_ALL_DEVS, "Information unit CRC error detected"},
    720 	{0x47, 0x04, SC_ALL_DEVS,
    721 	 "Asynchronous information protection error detected"},
    722 	{0x47, 0x05, SC_ALL_DEVS, "Protocol service CRC error"},
    723 	{0x48, 0x00, SC_ALL_DEVS, "Initiator detected error message received"},
    724 	{0x49, 0x00, SC_ALL_DEVS, "Invalid message error"},
    725 	{0x4A, 0x00, SC_ALL_DEVS, "Command phase error"},
    726 	{0x4B, 0x00, SC_ALL_DEVS, "Data phase error"},
    727 	{0x4C, 0x00, SC_ALL_DEVS, SC_LOGICAL_UNIT "failed self-configuration"},
    728 	/*
    729 	 * FIXME(eric) - need a way to represent wildcards here.
    730 	 */
    731 	{0x4D, 0x00, SC_ALL_DEVS,
    732 	 "Tagged overlapped commands (nn = queue tag)"},
    733 	{0x4E, 0x00, SC_ALL_DEVS, "Overlapped commands attempted"},
    734 	{0x50, 0x00, T, "Write append error"},
    735 	{0x50, 0x01, T, "Write append position error"},
    736 	{0x50, 0x02, T, "Position error related to timing"},
    737 	{0x51, 0x00, T | R | O, "Erase failure"},
    738 	{0x52, 0x00, T, "Cartridge fault"},
    739 	{0x53, 0x00, D | T | L | W | R | S | O | M | B | K,
    740 	 "Media load or eject failed"},
    741 	{0x53, 0x01, T, "Unload tape failure"},
    742 	{0x53, 0x02, D | T | W | R | O | M | B | K, "Medium removal prevented"},
    743 	{0x54, 0x00, P, "Scsi to host system interface failure"},
    744 	{0x55, 0x00, P, "System resource failure"},
    745 	{0x55, 0x01, D | O | B | K, "System buffer full"},
    746 	{0x55, 0x02, D | T | L | P | W | R | S | O | M | A | E | K,
    747 	 "Insufficient reservation resources"},
    748 	{0x55, 0x03, D | T | L | P | W | R | S | O | M | C | A | E,
    749 	 "Insufficient resources"},
    750 	{0x55, 0x04, D | T | L | P | W | R | S | O | M | A | E,
    751 	 "Insufficient registration resources"},
    752 	{0x55, 0x05, D | T | P | W | R | O | M | A | E | B | K,
    753 	 "Insufficient access control resources"},
    754 	{0x55, 0x06, D | T | W | R | O | M | B,
    755 	 "Auxiliary memory out of space"},
    756 	{0x57, 0x00, R, "Unable to recover table-of-contents"},
    757 	{0x58, 0x00, O, "Generation does not exist"},
    758 	{0x59, 0x00, O, "Updated block read"},
    759 	{0x5A, 0x00, D | T | L | P | W | R | S | O | M | B | K,
    760 	 "Operator request or state change input"},
    761 	{0x5A, 0x01, D | T | W | R | O | M | B | K,
    762 	 "Operator medium removal request"},
    763 	{0x5A, 0x02, D | T | W | R | O | A | B | K,
    764 	 "Operator selected write protect"},
    765 	{0x5A, 0x03, D | T | W | R | O | A | B | K,
    766 	 "Operator selected write permit"},
    767 	{0x5B, 0x00, D | T | L | P | W | R | S | O | M | K, "Log exception"},
    768 	{0x5B, 0x01, D | T | L | P | W | R | S | O | M | K,
    769 	 "Threshold condition met"},
    770 	{0x5B, 0x02, D | T | L | P | W | R | S | O | M | K,
    771 	 "Log counter at maximum"},
    772 	{0x5B, 0x03, D | T | L | P | W | R | S | O | M | K,
    773 	 "Log list codes exhausted"},
    774 	{0x5C, 0x00, D | O, "Rpl status change"},
    775 	{0x5C, 0x01, D | O, "Spindles synchronized"},
    776 	{0x5C, 0x02, D | O, "Spindles not synchronized"},
    777 	{0x5D, 0x00, SC_ALL_DEVS, "Failure prediction threshold exceeded"},
    778 	{0x5D, 0x01, R | B, "Media failure prediction threshold exceeded"},
    779 	{0x5D, 0x02, R,
    780 	 SC_LOGICAL_UNIT "failure prediction threshold exceeded"},
    781 	{0x5D, 0x03, R, "spare area exhaustion prediction threshold exceeded"},
    782 	/* large series of "impending failure" messages */
    783 	{0x5D, 0x10, D | B, SC_HARDWARE_IF "general hard drive failure"},
    784 	{0x5D, 0x11, D | B, SC_HARDWARE_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    785 	{0x5D, 0x12, D | B, SC_HARDWARE_IF "data" SC_ERROR_RATE_TOO_HIGH},
    786 	{0x5D, 0x13, D | B, SC_HARDWARE_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    787 	{0x5D, 0x14, D | B, SC_HARDWARE_IF "too many block reassigns"},
    788 	{0x5D, 0x15, D | B, SC_HARDWARE_IF "access" SC_TIMES_TOO_HIGH},
    789 	{0x5D, 0x16, D | B, SC_HARDWARE_IF "start unit" SC_TIMES_TOO_HIGH},
    790 	{0x5D, 0x17, D | B, SC_HARDWARE_IF "channel parametrics"},
    791 	{0x5D, 0x18, D | B, SC_HARDWARE_IF "controller detected"},
    792 	{0x5D, 0x19, D | B, SC_HARDWARE_IF "throughput performance"},
    793 	{0x5D, 0x1A, D | B, SC_HARDWARE_IF "seek time performance"},
    794 	{0x5D, 0x1B, D | B, SC_HARDWARE_IF "spin-up retry count"},
    795 	{0x5D, 0x1C, D | B, SC_HARDWARE_IF "drive calibration retry count"},
    796 	{0x5D, 0x20, D | B, SC_CONTROLLER_IF "general hard drive failure"},
    797 	{0x5D, 0x21, D | B, SC_CONTROLLER_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    798 	{0x5D, 0x22, D | B, SC_CONTROLLER_IF "data" SC_ERROR_RATE_TOO_HIGH},
    799 	{0x5D, 0x23, D | B, SC_CONTROLLER_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    800 	{0x5D, 0x24, D | B, SC_CONTROLLER_IF "too many block reassigns"},
    801 	{0x5D, 0x25, D | B, SC_CONTROLLER_IF "access" SC_TIMES_TOO_HIGH},
    802 	{0x5D, 0x26, D | B, SC_CONTROLLER_IF "start unit" SC_TIMES_TOO_HIGH},
    803 	{0x5D, 0x27, D | B, SC_CONTROLLER_IF "channel parametrics"},
    804 	{0x5D, 0x28, D | B, SC_CONTROLLER_IF "controller detected"},
    805 	{0x5D, 0x29, D | B, SC_CONTROLLER_IF "throughput performance"},
    806 	{0x5D, 0x2A, D | B, SC_CONTROLLER_IF "seek time performance"},
    807 	{0x5D, 0x2B, D | B, SC_CONTROLLER_IF "spin-up retry count"},
    808 	{0x5D, 0x2C, D | B, SC_CONTROLLER_IF "drive calibration retry count"},
    809 	{0x5D, 0x30, D | B, SC_DATA_CHANNEL_IF "general hard drive failure"},
    810 	{0x5D, 0x31, D | B, SC_DATA_CHANNEL_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    811 	{0x5D, 0x32, D | B, SC_DATA_CHANNEL_IF "data" SC_ERROR_RATE_TOO_HIGH},
    812 	{0x5D, 0x33, D | B, SC_DATA_CHANNEL_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    813 	{0x5D, 0x34, D | B, SC_DATA_CHANNEL_IF "too many block reassigns"},
    814 	{0x5D, 0x35, D | B, SC_DATA_CHANNEL_IF "access" SC_TIMES_TOO_HIGH},
    815 	{0x5D, 0x36, D | B, SC_DATA_CHANNEL_IF "start unit" SC_TIMES_TOO_HIGH},
    816 	{0x5D, 0x37, D | B, SC_DATA_CHANNEL_IF "channel parametrics"},
    817 	{0x5D, 0x38, D | B, SC_DATA_CHANNEL_IF "controller detected"},
    818 	{0x5D, 0x39, D | B, SC_DATA_CHANNEL_IF "throughput performance"},
    819 	{0x5D, 0x3A, D | B, SC_DATA_CHANNEL_IF "seek time performance"},
    820 	{0x5D, 0x3B, D | B, SC_DATA_CHANNEL_IF "spin-up retry count"},
    821 	{0x5D, 0x3C, D | B, SC_DATA_CHANNEL_IF "drive calibration retry count"},
    822 	{0x5D, 0x40, D | B, SC_SERVO_IF "general hard drive failure"},
    823 	{0x5D, 0x41, D | B, SC_SERVO_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    824 	{0x5D, 0x42, D | B, SC_SERVO_IF "data" SC_ERROR_RATE_TOO_HIGH},
    825 	{0x5D, 0x43, D | B, SC_SERVO_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    826 	{0x5D, 0x44, D | B, SC_SERVO_IF "too many block reassigns"},
    827 	{0x5D, 0x45, D | B, SC_SERVO_IF "access" SC_TIMES_TOO_HIGH},
    828 	{0x5D, 0x46, D | B, SC_SERVO_IF "start unit" SC_TIMES_TOO_HIGH},
    829 	{0x5D, 0x47, D | B, SC_SERVO_IF "channel parametrics"},
    830 	{0x5D, 0x48, D | B, SC_SERVO_IF "controller detected"},
    831 	{0x5D, 0x49, D | B, SC_SERVO_IF "throughput performance"},
    832 	{0x5D, 0x4A, D | B, SC_SERVO_IF "seek time performance"},
    833 	{0x5D, 0x4B, D | B, SC_SERVO_IF "spin-up retry count"},
    834 	{0x5D, 0x4C, D | B, SC_SERVO_IF "drive calibration retry count"},
    835 	{0x5D, 0x50, D | B, SC_SPINDLE_IF "general hard drive failure"},
    836 	{0x5D, 0x51, D | B, SC_SPINDLE_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    837 	{0x5D, 0x52, D | B, SC_SPINDLE_IF "data" SC_ERROR_RATE_TOO_HIGH},
    838 	{0x5D, 0x53, D | B, SC_SPINDLE_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    839 	{0x5D, 0x54, D | B, SC_SPINDLE_IF "too many block reassigns"},
    840 	{0x5D, 0x55, D | B, SC_SPINDLE_IF "access" SC_TIMES_TOO_HIGH},
    841 	{0x5D, 0x56, D | B, SC_SPINDLE_IF "start unit" SC_TIMES_TOO_HIGH},
    842 	{0x5D, 0x57, D | B, SC_SPINDLE_IF "channel parametrics"},
    843 	{0x5D, 0x58, D | B, SC_SPINDLE_IF "controller detected"},
    844 	{0x5D, 0x59, D | B, SC_SPINDLE_IF "throughput performance"},
    845 	{0x5D, 0x5A, D | B, SC_SPINDLE_IF "seek time performance"},
    846 	{0x5D, 0x5B, D | B, SC_SPINDLE_IF "spin-up retry count"},
    847 	{0x5D, 0x5C, D | B, SC_SPINDLE_IF "drive calibration retry count"},
    848 	{0x5D, 0x60, D | B, SC_FIRMWARE_IF "general hard drive failure"},
    849 	{0x5D, 0x61, D | B, SC_FIRMWARE_IF "drive" SC_ERROR_RATE_TOO_HIGH},
    850 	{0x5D, 0x62, D | B, SC_FIRMWARE_IF "data" SC_ERROR_RATE_TOO_HIGH},
    851 	{0x5D, 0x63, D | B, SC_FIRMWARE_IF "seek" SC_ERROR_RATE_TOO_HIGH},
    852 	{0x5D, 0x64, D | B, SC_FIRMWARE_IF "too many block reassigns"},
    853 	{0x5D, 0x65, D | B, SC_FIRMWARE_IF "access" SC_TIMES_TOO_HIGH},
    854 	{0x5D, 0x66, D | B, SC_FIRMWARE_IF "start unit" SC_TIMES_TOO_HIGH},
    855 	{0x5D, 0x67, D | B, SC_FIRMWARE_IF "channel parametrics"},
    856 	{0x5D, 0x68, D | B, SC_FIRMWARE_IF "controller detected"},
    857 	{0x5D, 0x69, D | B, SC_FIRMWARE_IF "throughput performance"},
    858 	{0x5D, 0x6A, D | B, SC_FIRMWARE_IF "seek time performance"},
    859 	{0x5D, 0x6B, D | B, SC_FIRMWARE_IF "spin-up retry count"},
    860 	{0x5D, 0x6C, D | B, SC_FIRMWARE_IF "drive calibration retry count"},
    861 	{0x5D, 0xFF, SC_ALL_DEVS,
    862 	 "Failure prediction threshold exceeded (false)"},
    863 	{0x5E, 0x00, D | T | L | P | W | R | S | O | C | A | K,
    864 	 "Low power condition on"},
    865 	{0x5E, 0x01, D | T | L | P | W | R | S | O | C | A | K,
    866 	 "Idle condition activated by timer"},
    867 	{0x5E, 0x02, D | T | L | P | W | R | S | O | C | A | K,
    868 	 "Standby condition activated by timer"},
    869 	{0x5E, 0x03, D | T | L | P | W | R | S | O | C | A | K,
    870 	 "Idle condition activated by command"},
    871 	{0x5E, 0x04, D | T | L | P | W | R | S | O | C | A | K,
    872 	 "Standby condition activated by command"},
    873 	{0x5E, 0x41, B, "Power state change to active"},
    874 	{0x5E, 0x42, B, "Power state change to idle"},
    875 	{0x5E, 0x43, B, "Power state change to standby"},
    876 	{0x5E, 0x45, B, "Power state change to sleep"},
    877 	{0x5E, 0x47, B | K, "Power state change to device control"},
    878 	{0x60, 0x00, S, "Lamp failure"},
    879 	{0x61, 0x00, S, "Video acquisition error"},
    880 	{0x61, 0x01, S, "Unable to acquire video"},
    881 	{0x61, 0x02, S, "Out of focus"},
    882 	{0x62, 0x00, S, "Scan head positioning error"},
    883 	{0x63, 0x00, R, "End of user area encountered on this track"},
    884 	{0x63, 0x01, R, "Packet does not fit in available space"},
    885 	{0x64, 0x00, R, "Illegal mode for this track"},
    886 	{0x64, 0x01, R, "Invalid packet size"},
    887 	{0x65, 0x00, SC_ALL_DEVS, "Voltage fault"},
    888 	{0x66, 0x00, S, "Automatic document feeder cover up"},
    889 	{0x66, 0x01, S, "Automatic document feeder lift up"},
    890 	{0x66, 0x02, S, "Document jam in automatic document feeder"},
    891 	{0x66, 0x03, S, "Document miss feed automatic in document feeder"},
    892 	{0x67, 0x00, A, "Configuration failure"},
    893 	{0x67, 0x01, A, "Configuration of incapable logical units failed"},
    894 	{0x67, 0x02, A, "Add logical unit failed"},
    895 	{0x67, 0x03, A, "Modification of logical unit failed"},
    896 	{0x67, 0x04, A, "Exchange of logical unit failed"},
    897 	{0x67, 0x05, A, "Remove of logical unit failed"},
    898 	{0x67, 0x06, A, "Attachment of logical unit failed"},
    899 	{0x67, 0x07, A, "Creation of logical unit failed"},
    900 	{0x67, 0x08, A, "Assign failure occurred"},
    901 	{0x67, 0x09, A, "Multiply assigned logical unit"},
    902 	{0x67, 0x0A, SC_ALL_DEVS, "Set target port groups command failed"},
    903 	{0x68, 0x00, A, SC_LOGICAL_UNIT "not configured"},
    904 	{0x69, 0x00, A, "Data loss on logical unit"},
    905 	{0x69, 0x01, A, "Multiple logical unit failures"},
    906 	{0x69, 0x02, A, "Parity/data mismatch"},
    907 	{0x6A, 0x00, A, "Informational,refer to log"},
    908 	{0x6B, 0x00, A, "State change has occurred"},
    909 	{0x6B, 0x01, A, "Redundancy level got better"},
    910 	{0x6B, 0x02, A, "Redundancy level got worse"},
    911 	{0x6C, 0x00, A, "Rebuild failure occurred"},
    912 	{0x6D, 0x00, A, "Recalculate failure occurred"},
    913 	{0x6E, 0x00, A, "Command to logical unit failed"},
    914 	{0x6F, 0x00, R,
    915 	 "Copy protection key exchange failure - authentication failure"},
    916 	{0x6F, 0x01, R,
    917 	 "Copy protection key exchange failure - key not present"},
    918 	{0x6F, 0x02, R,
    919 	 "Copy protection key exchange failure - key not established"},
    920 	{0x6F, 0x03, R, "Read of scrambled sector without authentication"},
    921 	{0x6F, 0x04, R,
    922 	 "Media region code is mismatched to logical unit region"},
    923 	{0x6F, 0x05, R,
    924 	 "Drive region must be permanent/region reset count error"},
    925 	/*
    926 	 * FIXME(eric) - need a way to represent wildcards here.
    927 	 */
    928 	{0x70, 0x00, T, "Decompression exception short algorithm id of nn"},
    929 	{0x71, 0x00, T, "Decompression exception long algorithm id"},
    930 	{0x72, 0x00, R, "Session fixation error"},
    931 	{0x72, 0x01, R, "Session fixation error writing lead-in"},
    932 	{0x72, 0x02, R, "Session fixation error writing lead-out"},
    933 	{0x72, 0x03, R, "Session fixation error - incomplete track in session"},
    934 	{0x72, 0x04, R, "Empty or partially written reserved track"},
    935 	{0x72, 0x05, R, "No more track reservations allowed"},
    936 	{0x73, 0x00, R, "Cd control error"},
    937 	{0x73, 0x01, R, "Power calibration area almost full"},
    938 	{0x73, 0x02, R, "Power calibration area is full"},
    939 	{0x73, 0x03, R, "Power calibration area error"},
    940 	{0x73, 0x04, R, "Program memory area update failure"},
    941 	{0x73, 0x05, R, "Program memory area is full"},
    942 	{0x73, 0x06, R, "RMA/PMA is full"},
    943 	{0, 0, 0, NULL}
    944 };
    945 
    946 static const char *sc_oft_used[0x1f] = {
    947 	"umulig",		/* index 0x0 should be impossible */
    948 	"Audio play operation ",
    949 	"Logical unit ",
    950 	"not ready, ",
    951 	" operation",
    952 	" in progress ",
    953 	"Hardware impending failure ",
    954 	"Controller impending failure ",
    955 	"Data channel impending failure ",	/* index 0x8 */
    956 	"Servo impending failure ",
    957 	"Spindle impending failure ",
    958 	"Firmware impending failure ",
    959 	"Recovered data ",
    960 	" error rate too high",
    961 	" times too high",
    962 };
    963 
    964 static const char *snstext[] = {
    965 	"No Sense",		/* There is no sense information */
    966 	"Recovered Error",	/* The last command completed successfully
    967 				   but used error correction */
    968 	"Not Ready",		/* The addressed target is not ready */
    969 	"Medium Error",		/* Data error detected on the medium */
    970 	"Hardware Error",	/* Controller or device failure */
    971 	"Illegal Request",
    972 	"Unit Attention",	/* Removable medium was changed, or
    973 				   the target has been reset */
    974 	"Data Protect",		/* Access to the data is blocked */
    975 	"Blank Check",		/* Reached unexpected written or unwritten
    976 				   region of the medium */
    977 	"Key=9",		/* Vendor specific */
    978 	"Copy Aborted",		/* COPY or COMPARE was aborted */
    979 	"Aborted Command",	/* The target aborted the command */
    980 	"Equal",		/* SEARCH DATA found data equal (obsolete) */
    981 	"Volume Overflow",	/* Medium full with still data to be written */
    982 	"Miscompare",		/* Source data and data on the medium
    983 				   do not agree */
    984 	"Key=15"		/* Reserved */
    985 };
    986 
    987 static
    988 void sg_print_asc_ascq(unsigned char asc, unsigned char ascq)
    989 {
    990 	int k, j;
    991 	char obuff[256];
    992 	const char *ccp;
    993 	const char *oup;
    994 	char c;
    995 	int found = 0;
    996 
    997 	for (k = 0; additional[k].text; k++) {
    998 		if (additional[k].code1 == asc && additional[k].code2 == ascq) {
    999 			found = 1;
   1000 			ccp = additional[k].text;
   1001 			for (j = 0; *ccp && (j < sizeof(obuff)); ++ccp) {
   1002 				c = *ccp;
   1003 				if ((c < 0x20) && (c > 0)) {
   1004 					oup = sc_oft_used[(int)c];
   1005 					if (oup) {
   1006 						strcpy(obuff + j, oup);
   1007 						j += strlen(oup);
   1008 					} else {
   1009 						strcpy(obuff + j, "???");
   1010 						j += 3;
   1011 					}
   1012 				} else
   1013 					obuff[j++] = c;
   1014 			}
   1015 			if (j < sizeof(obuff))
   1016 				obuff[j] = '\0';
   1017 			else
   1018 				obuff[sizeof(obuff) - 1] = '\0';
   1019 			fprintf(OUTP, "Additional sense: %s\n", obuff);
   1020 		}
   1021 	}
   1022 	if (found)
   1023 		return;
   1024 
   1025 	for (k = 0; additional2[k].text; k++) {
   1026 		if ((additional2[k].code1 == asc) &&
   1027 		    (ascq >= additional2[k].code2_min) &&
   1028 		    (ascq <= additional2[k].code2_max)) {
   1029 			found = 1;
   1030 			fprintf(OUTP, "Additional sense: ");
   1031 			fprintf(OUTP, additional2[k].text, ascq);
   1032 			fprintf(OUTP, "\n");
   1033 		}
   1034 	}
   1035 	if (!found)
   1036 		fprintf(OUTP, "ASC=%2x ASCQ=%2x\n", asc, ascq);
   1037 }
   1038 
   1039 /* Print sense information */
   1040 void sg_print_sense(const char *leadin, const unsigned char *sense_buffer,
   1041 		    int sb_len)
   1042 {
   1043 	int k, s;
   1044 	int sense_key, sense_class, valid, code;
   1045 	int descriptor_format = 0;
   1046 	const char *error = NULL;
   1047 
   1048 	if (sb_len < 1) {
   1049 		fprintf(OUTP, "sense buffer empty\n");
   1050 		return;
   1051 	}
   1052 	sense_class = (sense_buffer[0] >> 4) & 0x07;
   1053 	code = sense_buffer[0] & 0xf;
   1054 	valid = sense_buffer[0] & 0x80;
   1055 	if (leadin)
   1056 		fprintf(OUTP, "%s: ", leadin);
   1057 
   1058 	if (sense_class == 7) {	/* extended sense data */
   1059 		s = sense_buffer[7] + 8;
   1060 		if (s > sb_len) {
   1061 			fprintf(OUTP,
   1062 				"Sense buffer too small (at %d bytes), %d bytes "
   1063 				"truncated\n", sb_len, s - sb_len);
   1064 			s = sb_len;
   1065 		}
   1066 
   1067 		switch (code) {
   1068 		case 0x0:
   1069 			error = "Current";	/* error concerns current command */
   1070 			break;
   1071 		case 0x1:
   1072 			error = "Deferred";	/* error concerns some earlier command */
   1073 			/* e.g., an earlier write to disk cache succeeded, but
   1074 			   now the disk discovers that it cannot write the data */
   1075 			break;
   1076 		case 0x2:
   1077 			descriptor_format = 1;
   1078 			error = "Descriptor current";
   1079 			/* new descriptor sense format */
   1080 			break;
   1081 		case 0x3:
   1082 			descriptor_format = 1;
   1083 			error = "Descriptor deferred";
   1084 			/* new descriptor sense format (deferred report) */
   1085 			break;
   1086 		default:
   1087 			error = "Invalid";
   1088 		}
   1089 		sense_key = sense_buffer[descriptor_format ? 1 : 2] & 0xf;
   1090 		fprintf(OUTP, "%s, Sense key: %s\n", error, snstext[sense_key]);
   1091 
   1092 		if (descriptor_format)
   1093 			sg_print_asc_ascq(sense_buffer[2], sense_buffer[3]);
   1094 		else {
   1095 			if (!valid)
   1096 				fprintf(OUTP, "[valid=0] ");
   1097 			fprintf(OUTP, "Info fld=0x%x, ",
   1098 				(int)((sense_buffer[3] << 24) |
   1099 				      (sense_buffer[4] << 16) | (sense_buffer[5]
   1100 								 << 8) |
   1101 				      sense_buffer[6]));
   1102 
   1103 			if (sense_buffer[2] & 0x80)
   1104 				fprintf(OUTP, "FMK ");	/* current command has read a filemark */
   1105 			if (sense_buffer[2] & 0x40)
   1106 				fprintf(OUTP, "EOM ");	/* end-of-medium condition exists */
   1107 			if (sense_buffer[2] & 0x20)
   1108 				fprintf(OUTP, "ILI ");	/* incorrect block length requested */
   1109 
   1110 			if (s > 13) {
   1111 				if (sense_buffer[12] || sense_buffer[13])
   1112 					sg_print_asc_ascq(sense_buffer[12],
   1113 							  sense_buffer[13]);
   1114 			}
   1115 			if (sense_key == 5 && s >= 18
   1116 			    && (sense_buffer[15] & 0x80)) {
   1117 				fprintf(OUTP,
   1118 					"Sense Key Specific: Error in %s byte %d",
   1119 					(sense_buffer[15] & 0x40) ? "Command" :
   1120 					"Data",
   1121 					(sense_buffer[16] << 8) |
   1122 					sense_buffer[17]);
   1123 				if (sense_buffer[15] & 0x08) {
   1124 					fprintf(OUTP, " bit %d\n",
   1125 						sense_buffer[15] & 0x07);
   1126 				} else {
   1127 					fprintf(OUTP, "\n");
   1128 				}
   1129 			}
   1130 		}
   1131 
   1132 	} else {		/* non-extended sense data */
   1133 
   1134 		/*
   1135 		 * Standard says:
   1136 		 *    sense_buffer[0] & 0200 : address valid
   1137 		 *    sense_buffer[0] & 0177 : vendor-specific error code
   1138 		 *    sense_buffer[1] & 0340 : vendor-specific
   1139 		 *    sense_buffer[1..3] : 21-bit logical block address
   1140 		 */
   1141 
   1142 		if (sb_len < 4) {
   1143 			fprintf(OUTP,
   1144 				"sense buffer too short (4 byte minimum)\n");
   1145 			return;
   1146 		}
   1147 		if (leadin)
   1148 			fprintf(OUTP, "%s: ", leadin);
   1149 		if (sense_buffer[0] < 15)
   1150 			fprintf(OUTP,
   1151 				"old sense: key %s\n",
   1152 				snstext[sense_buffer[0] & 0x0f]);
   1153 		else
   1154 			fprintf(OUTP, "sns = %2x %2x\n", sense_buffer[0],
   1155 				sense_buffer[2]);
   1156 
   1157 		fprintf(OUTP, "Non-extended sense class %d code 0x%0x ",
   1158 			sense_class, code);
   1159 		s = 4;
   1160 	}
   1161 
   1162 	fprintf(OUTP, "Raw sense data (in hex):\n  ");
   1163 	for (k = 0; k < s; ++k) {
   1164 		if ((k > 0) && (0 == (k % 24)))
   1165 			fprintf(OUTP, "\n  ");
   1166 		fprintf(OUTP, "%02x ", sense_buffer[k]);
   1167 	}
   1168 	fprintf(OUTP, "\n");
   1169 }
   1170 
   1171 static const char *hostbyte_table[] = {
   1172 	"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
   1173 	    "DID_BAD_TARGET",
   1174 	"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
   1175 	"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL
   1176 };
   1177 
   1178 void sg_print_host_status(int host_status)
   1179 {
   1180 	static int maxcode = 0;
   1181 	int i;
   1182 
   1183 	if (!maxcode) {
   1184 		for (i = 0; hostbyte_table[i]; i++) ;
   1185 		maxcode = i - 1;
   1186 	}
   1187 	fprintf(OUTP, "Host_status=0x%02x", host_status);
   1188 	if (host_status > maxcode) {
   1189 		fprintf(OUTP, "is invalid ");
   1190 		return;
   1191 	}
   1192 	fprintf(OUTP, "(%s) ", hostbyte_table[host_status]);
   1193 }
   1194 
   1195 static const char *driverbyte_table[] = {
   1196 	"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
   1197 	    "DRIVER_ERROR",
   1198 	"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL
   1199 };
   1200 
   1201 static const char *driversuggest_table[] = { "SUGGEST_OK",
   1202 	"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
   1203 	unknown, unknown, unknown, "SUGGEST_SENSE", NULL
   1204 };
   1205 
   1206 void sg_print_driver_status(int driver_status)
   1207 {
   1208 	static int driver_max = 0, suggest_max = 0;
   1209 	int i;
   1210 	int dr = driver_status & SG_ERR_DRIVER_MASK;
   1211 	int su = (driver_status & SG_ERR_SUGGEST_MASK) >> 4;
   1212 
   1213 	if (!driver_max) {
   1214 		for (i = 0; driverbyte_table[i]; i++) ;
   1215 		driver_max = i;
   1216 		for (i = 0; driversuggest_table[i]; i++) ;
   1217 		suggest_max = i;
   1218 	}
   1219 	fprintf(OUTP, "Driver_status=0x%02x", driver_status);
   1220 	fprintf(OUTP, " (%s,%s) ",
   1221 		dr < driver_max ? driverbyte_table[dr] : "invalid",
   1222 		su < suggest_max ? driversuggest_table[su] : "invalid");
   1223 }
   1224 
   1225 static int sg_sense_print(const char *leadin, int scsi_status,
   1226 			  int host_status, int driver_status,
   1227 			  const unsigned char *sense_buffer, int sb_len)
   1228 {
   1229 	int done_leadin = 0;
   1230 	int done_sense = 0;
   1231 
   1232 	scsi_status &= 0x7e;	/*sanity */
   1233 	if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
   1234 		return 1;	/* No problems */
   1235 	if (0 != scsi_status) {
   1236 		if (leadin)
   1237 			fprintf(OUTP, "%s: ", leadin);
   1238 		done_leadin = 1;
   1239 		fprintf(OUTP, "scsi status: ");
   1240 		sg_print_scsi_status(scsi_status);
   1241 		fprintf(OUTP, "\n");
   1242 		if (sense_buffer && ((scsi_status == SCSI_CHECK_CONDITION) ||
   1243 				     (scsi_status ==
   1244 				      SCSI_COMMAND_TERMINATED))) {
   1245 			sg_print_sense(0, sense_buffer, sb_len);
   1246 			done_sense = 1;
   1247 		}
   1248 	}
   1249 	if (0 != host_status) {
   1250 		if (leadin && (!done_leadin))
   1251 			fprintf(OUTP, "%s: ", leadin);
   1252 		if (done_leadin)
   1253 			fprintf(OUTP, "plus...: ");
   1254 		else
   1255 			done_leadin = 1;
   1256 		sg_print_host_status(host_status);
   1257 		fprintf(OUTP, "\n");
   1258 	}
   1259 	if (0 != driver_status) {
   1260 		if (leadin && (!done_leadin))
   1261 			fprintf(OUTP, "%s: ", leadin);
   1262 		if (done_leadin)
   1263 			fprintf(OUTP, "plus...: ");
   1264 		else
   1265 			done_leadin = 1;
   1266 		sg_print_driver_status(driver_status);
   1267 		fprintf(OUTP, "\n");
   1268 		if (sense_buffer && (!done_sense) &&
   1269 		    (SG_ERR_DRIVER_SENSE == (0xf & driver_status)))
   1270 			sg_print_sense(0, sense_buffer, sb_len);
   1271 	}
   1272 	return 0;
   1273 }
   1274 
   1275 #ifdef SG_IO
   1276 int sg_chk_n_print3(const char *leadin, struct sg_io_hdr *hp)
   1277 {
   1278 	return sg_sense_print(leadin, hp->status, hp->host_status,
   1279 			      hp->driver_status, hp->sbp, hp->sb_len_wr);
   1280 }
   1281 #endif
   1282 
   1283 int sg_chk_n_print(const char *leadin, int masked_status,
   1284 		   int host_status, int driver_status,
   1285 		   const unsigned char *sense_buffer, int sb_len)
   1286 {
   1287 	int scsi_status = (masked_status << 1) & 0x7e;
   1288 
   1289 	return sg_sense_print(leadin, scsi_status, host_status, driver_status,
   1290 			      sense_buffer, sb_len);
   1291 }
   1292 
   1293 #ifdef SG_IO
   1294 int sg_err_category3(struct sg_io_hdr *hp)
   1295 {
   1296 	return sg_err_category_new(hp->status, hp->host_status,
   1297 				   hp->driver_status, hp->sbp, hp->sb_len_wr);
   1298 }
   1299 #endif
   1300 
   1301 int sg_err_category(int masked_status, int host_status,
   1302 		    int driver_status, const unsigned char *sense_buffer,
   1303 		    int sb_len)
   1304 {
   1305 	int scsi_status = (masked_status << 1) & 0x7e;
   1306 
   1307 	return sg_err_category_new(scsi_status, host_status, driver_status,
   1308 				   sense_buffer, sb_len);
   1309 }
   1310 
   1311 int sg_err_category_new(int scsi_status, int host_status, int driver_status,
   1312 			const unsigned char *sense_buffer, int sb_len)
   1313 {
   1314 	scsi_status &= 0x7e;
   1315 	if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
   1316 		return SG_ERR_CAT_CLEAN;
   1317 	if ((SCSI_CHECK_CONDITION == scsi_status) ||
   1318 	    (SCSI_COMMAND_TERMINATED == scsi_status) ||
   1319 	    (SG_ERR_DRIVER_SENSE == (0xf & driver_status))) {
   1320 		if (sense_buffer && (sb_len > 2)) {
   1321 			int sense_key;
   1322 			unsigned char asc;
   1323 
   1324 			if (sense_buffer[0] & 0x2) {
   1325 				sense_key = sense_buffer[1] & 0xf;
   1326 				asc = sense_buffer[2];
   1327 			} else {
   1328 				sense_key = sense_buffer[2] & 0xf;
   1329 				asc = (sb_len > 12) ? sense_buffer[12] : 0;
   1330 			}
   1331 
   1332 			if (RECOVERED_ERROR == sense_key)
   1333 				return SG_ERR_CAT_RECOVERED;
   1334 			else if (UNIT_ATTENTION == sense_key) {
   1335 				if (0x28 == asc)
   1336 					return SG_ERR_CAT_MEDIA_CHANGED;
   1337 				if (0x29 == asc)
   1338 					return SG_ERR_CAT_RESET;
   1339 			}
   1340 		}
   1341 		return SG_ERR_CAT_SENSE;
   1342 	}
   1343 	if (0 != host_status) {
   1344 		if ((SG_ERR_DID_NO_CONNECT == host_status) ||
   1345 		    (SG_ERR_DID_BUS_BUSY == host_status) ||
   1346 		    (SG_ERR_DID_TIME_OUT == host_status))
   1347 			return SG_ERR_CAT_TIMEOUT;
   1348 	}
   1349 	if (0 != driver_status) {
   1350 		if (SG_ERR_DRIVER_TIMEOUT == driver_status)
   1351 			return SG_ERR_CAT_TIMEOUT;
   1352 	}
   1353 	return SG_ERR_CAT_OTHER;
   1354 }
   1355 
   1356 int sg_get_command_size(unsigned char opcode)
   1357 {
   1358 	return COMMAND_SIZE(opcode);
   1359 }
   1360 
   1361 void sg_get_command_name(unsigned char opcode, int buff_len, char *buff)
   1362 {
   1363 	const char **table = commands[group(opcode)];
   1364 
   1365 	if ((NULL == buff) || (buff_len < 1))
   1366 		return;
   1367 
   1368 	switch ((unsigned long)table) {
   1369 	case RESERVED_GROUP:
   1370 		strncpy(buff, reserved, buff_len);
   1371 		break;
   1372 	case VENDOR_GROUP:
   1373 		strncpy(buff, vendor, buff_len);
   1374 		break;
   1375 	default:
   1376 		strncpy(buff, table[opcode & 0x1f], buff_len);
   1377 		break;
   1378 	}
   1379 }
   1380