blob: 0324f9795845f19bcdf7763a2ff3009d57b09465 [file] [log] [blame]
/*
* Copyright (c) 1999-2005 Douglas Gilbert.
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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.
*
*/
/* NOTICE:
* On 5th October 2004 (v1.00) this file name was changed from sg_err.c
* to sg_lib.c and the previous GPL was changed to a FreeBSD license.
* The intention is to maintain this file and the related sg_lib.h file
* as open source and encourage their unencumbered use.
*
* CONTRIBUTIONS:
* This file started out as a copy of SCSI opcodes, sense keys and
* additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem
* in the kernel source file: drivers/scsi/constant.c . That file
* bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale"
* and a GPL notice.
*
* Much of the data in this file is derived from SCSI draft standards
* found at http://www.t10.org with the "SCSI Primary Commands-3" (SPC-3)
* being the central point of reference.
*
* Other contributions:
* Version 0.91 (20031116)
* sense key specific field (bytes 15-17) decoding [Trent Piepho]
*
* CHANGELOG (changes prior to v0.97 removed):
* v0.97 (20040830)
* safe_strerror(), rename sg_decode_sense() to sg_normalize_sense()
* decode descriptor sense data format in full
* v0.98 (20040924) [SPC-3 rev 21]
* renamed from sg_err.c to sg_lib.c
* factor out sg_get_num() and sg_get_llnum() into this file
* add 'no_ascii<0' variant to dStrHex for ASCII-hex output only
* v1.00 (20041012)
* renamed from sg_err.c to sg_lib.c
* change GPL to FreeBSD license
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sg_include.h"
#include "sg_lib.h"
static char * version_str = "1.07 20050308";
FILE * sg_warnings_str = NULL; /* would like to default to stderr */
/* Commands with service actions that change the command name */
#define SG_MAINTENANCE_IN 0xa3
#define SG_MAINTENANCE_OUT 0xa4
#define SG_SERVICE_ACTION_IN_12 0xab
#define SG_SERVICE_ACTION_OUT_12 0xa9
#define SG_SERVICE_ACTION_IN_16 0x9e
#define SG_SERVICE_ACTION_OUT_16 0x9f
#define SG_VARIABLE_LENGTH_CMD 0x7f
static void dStrHexErr(const char* str, int len);
struct value_name_t {
int value;
int peri_dev_type; /* only non-zero to disambiguate by command set */
const char * name;
};
static const struct value_name_t normal_opcodes[] = {
{0, 0, "Test Unit Ready"},
{0x1, 0, "Rezero Unit"},
{0x1, 1, "Rewind"},
{0x3, 0, "Request Sense"},
{0x4, 0, "Format Unit"},
{0x4, 1, "Format medium"},
{0x4, 2, "Format"},
{0x5, 0, "Read Block Limits"},
{0x7, 0, "Reassign Blocks"},
{0x7, 8, "Initialize element status"},
{0x8, 0, "Read(6)"},
{0x8, 3, "Receive"},
{0xa, 0, "Write(6)"},
{0xa, 2, "Print"},
{0xa, 3, "Send"},
{0xb, 0, "Seek(6)"},
{0xb, 1, "Set capacity"},
{0xb, 2, "Slew and print"},
{0xf, 0, "Read reverse(6)"},
{0x10, 0, "Write filemarks(6)"},
{0x10, 2, "Synchronize buffer"},
{0x11, 0, "Space(6)"},
{0x12, 0, "Inquiry"},
{0x13, 0, "Verify(6)"}, /* SSC */
{0x14, 0, "Recover buffered data"},
{0x15, 0, "Mode select(6)"},
{0x16, 0, "Reserve(6)"},
{0x16, 8, "Reserve element(6)"},
{0x17, 0, "Release(6)"},
{0x17, 8, "Release element(6)"},
{0x18, 0, "Copy"},
{0x19, 0, "Erase(6)"},
{0x1a, 0, "Mode sense(6)"},
{0x1b, 0, "Start stop unit"},
{0x1b, 1, "Load unload"},
{0x1b, 0x12, "Load unload"},
{0x1b, 2, "Stop print"},
{0x1c, 0, "Receive diagnostic results"},
{0x1d, 0, "Send diagnostic"},
{0x1e, 0, "Prevent allow medium removal"},
{0x23, 0, "Read Format capacities"},
{0x24, 0, "Set window"},
{0x25, 0, "Read capacity(10)"},
{0x25, 0xf, "Read card capacity"},
{0x28, 0, "Read(10)"},
{0x29, 0, "Read generation"},
{0x2a, 0, "Write(10)"},
{0x2b, 0, "Seek(10)"},
{0x2b, 1, "Locate(10)"},
{0x2b, 8, "Position to element"},
{0x2c, 0, "Erase(10)"},
{0x2d, 0, "Read updated block"},
{0x2e, 0, "Write and verify(10)"},
{0x2f, 0, "Verify(10)"},
{0x30, 0, "Search data high(10)"},
{0x31, 0, "Search data equal(10)"},
{0x32, 0, "Search data low(10)"},
{0x33, 0, "Set limits(10)"},
{0x34, 0, "Pre-fetch(10)"},
{0x34, 1, "Read position"},
{0x35, 0, "Synchronize cache(10)"},
{0x36, 0, "Lock unlock cache(10)"},
{0x37, 0, "Read defect data(10)"},
{0x37, 8, "Initialize element status with range"},
{0x38, 0, "Medium scan"},
{0x39, 0, "Compare"},
{0x3a, 0, "Copy and verify"},
{0x3b, 0, "Write buffer"},
{0x3c, 0, "Read buffer"},
{0x3d, 0, "Update block"},
{0x3e, 0, "Read long(10)"},
{0x3f, 0, "Write long(10)"},
{0x40, 0, "Change definition"},
{0x41, 0, "Write same(10)"},
{0x42, 0, "Read sub-channel"},
{0x43, 0, "Read TOC/PMA/ATIP"},
{0x44, 0, "Report density support"},
{0x45, 0, "Play audio(10)"},
{0x46, 0, "Get configuration"},
{0x47, 0, "Play audio msf"},
{0x4a, 0, "Get event status notification"},
{0x4b, 0, "Pause/resume"},
{0x4c, 0, "Log select"},
{0x4d, 0, "Log sense"},
{0x4e, 0, "Stop play/scan"},
{0x50, 0, "Xdwrite(10)"},
{0x51, 0, "Xpwrite(10)"},
{0x51, 5, "Read disk information"},
{0x52, 0, "Xdread(10)"},
{0x52, 5, "Read track information"},
{0x53, 0, "Reserve track"},
{0x54, 0, "Send OPC information"},
{0x55, 0, "Mode select(10)"},
{0x56, 0, "Reserve(10)"},
{0x57, 0, "Release(10)"},
{0x58, 0, "Repair track"},
{0x5a, 0, "Mode sense(10)"},
{0x5b, 0, "Close track/session"},
{0x5c, 0, "Read buffer capacity"},
{0x5d, 0, "Send cue sheet"},
{0x5e, 0, "Persistent reserve in"},
{0x5f, 0, "Persistent reserve out"},
{0x80, 0, "Xdwrite extended(16)"},
{0x80, 1, "Write filemarks(16)"},
{0x81, 0, "Rebuild(16)"},
{0x81, 1, "Read reverse(16)"},
{0x82, 0, "Regenerate(16)"},
{0x83, 0, "Extended copy"},
{0x84, 0, "Receive copy results"},
{0x86, 0, "Access control in"},
{0x87, 0, "Access control out"},
{0x88, 0, "Read(16)"},
{0x8a, 0, "Write(16)"},
{0x8c, 0, "Read attribute"},
{0x8d, 0, "Write attribute"},
{0x8e, 0, "Write and verify(16)"},
{0x8f, 0, "Verify(16)"},
{0x90, 0, "Pre-fetch(16)"},
{0x91, 0, "Synchronize cache(16)"},
{0x91, 1, "Space(16)"},
{0x92, 0, "Lock unlock cache(16)"},
{0x92, 1, "Locate(16)"},
{0x93, 0, "Write same(16)"},
{0x93, 1, "Erase(16)"},
{0x98, 0, "ATA command pass through(16)"}, /* was 0x85 */
{0x9e, 0, "Service action in(16)"},
{0x9f, 0, "Service action out(16)"},
{0xa0, 0, "Report luns"},
{0xa1, 0, "ATA command pass through(12)"},
{0xa1, 5, "Blank"},
{0xa2, 0, "Trusted computing in"},
{0xa3, 0, "Maintenance in"},
{0xa3, 5, "Send key"},
{0xa4, 0, "Maintenance out"},
{0xa4, 5, "Report key"},
{0xa5, 0, "Move medium"},
{0xa5, 5, "Play audio(12)"},
{0xa6, 0, "Exchange medium"},
{0xa6, 5, "Load/unload medium"},
{0xa7, 0, "Move medium attached"},
{0xa7, 5, "Set read ahead"},
{0xa8, 0, "Read(12)"},
{0xa9, 0, "Service action out(12)"},
{0xaa, 0, "Write(12)"},
{0xab, 0, "Service action in(12)"},
{0xac, 0, "erase(12)"},
{0xac, 5, "Get performance"},
{0xad, 5, "Read DVD/BD structure"},
{0xae, 0, "Write and verify(12)"},
{0xaf, 0, "Verify(12)"},
{0xb0, 0, "Search data high(12)"},
{0xb1, 0, "Search data equal(12)"},
{0xb2, 0, "Search data low(12)"},
{0xb3, 0, "Set limits(12)"},
{0xb4, 0, "Read element status attached"},
{0xb5, 0, "Trusted computing out"},
{0xb5, 8, "Request volume element address"},
{0xb6, 0, "Set volume tag"},
{0xb6, 5, "Set streaming"},
{0xb7, 0, "Read defect data(12)"},
{0xb8, 0, "Read element status"},
{0xb9, 0, "Read CD msf"},
{0xba, 0, "Redundancy group in"},
{0xba, 5, "Scan"},
{0xbb, 0, "Redundancy group out"},
{0xbb, 5, "Set CD speed"},
{0xbc, 0, "Spare in"},
{0xbd, 0, "Spare out"},
{0xbd, 5, "Mechanism status"},
{0xbe, 0, "Volume set in"},
{0xbe, 5, "Read CD"},
{0xbf, 0, "Volume set out"},
{0xbf, 5, "Send DVD/BD structure"},
};
#define NORMAL_OPCODES_SZ \
(int)(sizeof(normal_opcodes) / sizeof(normal_opcodes[0]))
static const struct value_name_t maint_in_arr[] = {
{0x5, 0, "Report device identifier"},
{0xa, 0, "Report target port groups"},
{0xb, 0, "Report aliases"},
{0xc, 0, "Report supported operation codes"},
{0xd, 0, "Report supported task management functions"},
{0xe, 0, "Report priority"},
{0xf, 0, "Report timeout"},
};
#define MAINT_IN_SZ \
(int)(sizeof(maint_in_arr) / sizeof(maint_in_arr[0]))
static const struct value_name_t maint_out_arr[] = {
{0x6, 0, "Set device identifier"},
{0xa, 0, "Set target port groups"},
{0xb, 0, "Change aliases"},
{0xe, 0, "Set priority"},
{0xf, 0, "Set timeout"},
};
#define MAINT_OUT_SZ \
(int)(sizeof(maint_out_arr) / sizeof(maint_out_arr[0]))
static const struct value_name_t serv_in12_arr[] = {
{0x1, 0, "Read media serial number"},
};
#define SERV_IN12_SZ \
(int)(sizeof(serv_in12_arr) / sizeof(serv_in12_arr[0]))
static const struct value_name_t serv_out12_arr[] = {
{0xff, 0, "Impossible command name"},
};
#define SERV_OUT12_SZ \
(int)(sizeof(serv_out12_arr) / sizeof(serv_in12_arr[0]))
static const struct value_name_t serv_in16_arr[] = {
{0x10, 1, "Read capacity(16)"},
{0x11, 1, "Read long(16)"},
};
#define SERV_IN16_SZ \
(int)(sizeof(serv_in16_arr) / sizeof(serv_in16_arr[0]))
static const struct value_name_t serv_out16_arr[] = {
{0x11, 1, "Write long(16)"},
{0x1f, 0x12, "Notify data transfer device(16)"},
};
#define SERV_OUT16_SZ \
(int)(sizeof(serv_out16_arr) / sizeof(serv_in16_arr[0]))
static const struct value_name_t variable_length_arr[] = {
{0x1, 0, "Rebuild(32)"},
{0x2, 0, "Regenerate(32)"},
{0x3, 0, "Xdread(32)"},
{0x4, 0, "Xdwrite(32)"},
{0x5, 0, "Xdwrite extended(32)"},
{0x6, 0, "Xpwrite(32)"},
{0x7, 0, "Xdwriteread(32)"},
{0x8, 0, "Xdwrite extended(64)"},
{0x9, 0, "Read(32)"},
{0xa, 0, "Verify(32)"},
{0xb, 0, "Write(32)"},
{0xc, 0, "Write an verify(32)"},
{0xd, 0, "Write same(32)"},
{0x8801, 0, "Format OSD"},
{0x8802, 0, "Create (osd)"},
{0x8803, 0, "List (osd)"},
{0x8805, 0, "Read (osd)"},
{0x8806, 0, "Write (osd)"},
{0x8807, 0, "Append (osd)"},
{0x8808, 0, "Flush (osd)"},
{0x880a, 0, "Remove (osd)"},
{0x880b, 0, "Create partition (osd)"},
{0x880c, 0, "Remove partition (osd)"},
{0x880e, 0, "Get attributes (osd)"},
{0x880f, 0, "Set attributes (osd)"},
{0x8812, 0, "Create and write (osd)"},
{0x8815, 0, "Create collection (osd)"},
{0x8816, 0, "Remove collection (osd)"},
{0x8817, 0, "List collection (osd)"},
{0x8818, 0, "Set key (osd)"},
{0x8819, 0, "Set master key (osd)"},
{0x881a, 0, "Flush collection (osd)"},
{0x881b, 0, "Flush partition (osd)"},
{0x881c, 0, "Flush OSD"},
{0x8f7e, 0, "Perform SCSI command (osd)"},
{0x8f7f, 0, "Perform task management function (osd)"},
};
#define VARIABLE_LENGTH_SZ \
(int)(sizeof(variable_length_arr) / sizeof(variable_length_arr[0]))
/* searches 'arr' for match on 'value' then 'peri_type'. If matches
'value' but not 'peri_type' the yields first 'value' match entry.
There are 'arr_sz' elements of 'arr', if no match yields NULL. */
static const struct value_name_t * get_value_name(
const struct value_name_t * arr, int arr_sz, int value, int peri_type)
{
const struct value_name_t * maxp = arr + arr_sz;
const struct value_name_t * vp = arr;
const struct value_name_t * holdp;
for (; vp < maxp; ++vp) {
if (value == vp->value) {
if (peri_type == vp->peri_dev_type)
return vp;
holdp = vp;
while (((vp + 1) < maxp) &&
(value == (vp + 1)->value)) {
++vp;
if (peri_type == vp->peri_dev_type)
return vp;
}
return holdp;
}
}
return NULL;
}
void sg_set_warnings_str(FILE * warnings_str)
{
sg_warnings_str = warnings_str;
}
#define CMD_BUFF_LEN 64
void sg_print_command(const unsigned char * command)
{
int k, sz;
char buff[CMD_BUFF_LEN];
sg_get_command_name(command, 0, CMD_BUFF_LEN, buff);
buff[CMD_BUFF_LEN - 1] = '\0';
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "%s [", buff);
if (SG_VARIABLE_LENGTH_CMD == command[0])
sz = command[7] + 8;
else
sz = sg_get_command_size(command[0]);
for (k = 0; k < sz; ++k)
fprintf(sg_warnings_str, "%02x ", command[k]);
fprintf(sg_warnings_str, "]\n");
}
void sg_print_status(int masked_status)
{
int scsi_status = (masked_status << 1) & 0x7e;
sg_print_scsi_status(scsi_status);
}
void sg_print_scsi_status(int scsi_status)
{
const char * ccp;
scsi_status &= 0x7e; /* sanitize as much as possible */
switch (scsi_status) {
case 0: ccp = "Good"; break;
case 0x2: ccp = "Check Condition"; break;
case 0x4: ccp = "Condition Met"; break;
case 0x8: ccp = "Busy"; break;
case 0x10: ccp = "Intermediate"; break;
case 0x14: ccp = "Intermediate-Condition Met"; break;
case 0x18: ccp = "Reservation Conflict"; break;
case 0x22: ccp = "Command Terminated (obsolete)"; break;
case 0x28: ccp = "Task set Full"; break;
case 0x30: ccp = "ACA Active"; break;
case 0x40: ccp = "Task Aborted"; break;
default: ccp = "Unknown status"; break;
}
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "%s ", ccp);
}
struct error_info{
unsigned char code1, code2;
const char * text;
};
struct error_info2{
unsigned char code1, code2_min, code2_max;
const char * text;
};
static struct error_info2 additional2[] =
{
{0x40,0x01,0x7f,"Ram failure [0x%x]"},
{0x40,0x80,0xff,"Diagnostic failure on component [0x%x]"},
{0x41,0x01,0xff,"Data path failure [0x%x]"},
{0x42,0x01,0xff,"Power-on or self-test failure [0x%x]"},
{0x4d,0x00,0xff,"Tagged overlapped commands [0x%x]"},
{0x70,0x00,0xff,"Decompression exception short algorithm id of 0x%x"},
{0, 0, 0, NULL}
};
static struct error_info additional[] =
{
{0x00,0x00,"No additional sense information"},
{0x00,0x01,"Filemark detected"},
{0x00,0x02,"End-of-partition/medium detected"},
{0x00,0x03,"Setmark detected"},
{0x00,0x04,"Beginning-of-partition/medium detected"},
{0x00,0x05,"End-of-data detected"},
{0x00,0x06,"I/O process terminated"},
{0x00,0x11,"Audio play operation in progress"},
{0x00,0x12,"Audio play operation paused"},
{0x00,0x13,"Audio play operation successfully completed"},
{0x00,0x14,"Audio play operation stopped due to error"},
{0x00,0x15,"No current audio status to return"},
{0x00,0x16,"operation in progress"},
{0x00,0x17,"Cleaning requested"},
{0x00,0x18,"Erase operation in progress"},
{0x00,0x19,"Locate operation in progress"},
{0x00,0x1a,"Rewind operation in progress"},
{0x00,0x1b,"Set capacity operation in progress"},
{0x00,0x1c,"Verify operation in progress"},
{0x01,0x00,"No index/sector signal"},
{0x02,0x00,"No seek complete"},
{0x03,0x00,"Peripheral device write fault"},
{0x03,0x01,"No write current"},
{0x03,0x02,"Excessive write errors"},
{0x04,0x00,"Logical unit not ready, cause not reportable"},
{0x04,0x01,"Logical unit is in process of becoming ready"},
{0x04,0x02,"Logical unit not ready, "
"initializing command required"},
{0x04,0x03,"Logical unit not ready, "
"manual intervention required"},
{0x04,0x04,"Logical unit not ready, format in progress"},
{0x04,0x05,"Logical unit not ready, rebuild in progress"},
{0x04,0x06,"Logical unit not ready, recalculation in progress"},
{0x04,0x07,"Logical unit not ready, operation in progress"},
{0x04,0x08,"Logical unit not ready, long write in progress"},
{0x04,0x09,"Logical unit not ready, self-test in progress"},
{0x04,0x0a,"Logical unit "
"not accessible, asymmetric access state transition"},
{0x04,0x0b,"Logical unit "
"not accessible, target port in standby state"},
{0x04,0x0c,"Logical unit "
"not accessible, target port in unavailable state"},
{0x04,0x10,"Logical unit not ready, "
"auxiliary memory not accessible"},
{0x04,0x11,"Logical unit not ready, "
"notify (enable spinup) required"},
{0x04,0x12,"Logical unit not ready, offline"},
{0x05,0x00,"Logical unit does not respond to selection"},
{0x06,0x00,"No reference position found"},
{0x07,0x00,"Multiple peripheral devices selected"},
{0x08,0x00,"Logical unit communication failure"},
{0x08,0x01,"Logical unit communication time-out"},
{0x08,0x02,"Logical unit communication parity error"},
{0x08,0x03,"Logical unit communication CRC error (Ultra-DMA/32)"},
{0x08,0x04,"Unreachable copy target"},
{0x09,0x00,"Track following error"},
{0x09,0x01,"Tracking servo failure"},
{0x09,0x02,"Focus servo failure"},
{0x09,0x03,"Spindle servo failure"},
{0x09,0x04,"Head select fault"},
{0x0A,0x00,"Error log overflow"},
{0x0B,0x00,"Warning"},
{0x0B,0x01,"Warning - specified temperature exceeded"},
{0x0B,0x02,"Warning - enclosure degraded"},
{0x0C,0x00,"Write error"},
{0x0C,0x01,"Write error - recovered with auto reallocation"},
{0x0C,0x02,"Write error - auto reallocation failed"},
{0x0C,0x03,"Write error - recommend reassignment"},
{0x0C,0x04,"Compression check miscompare error"},
{0x0C,0x05,"Data expansion occurred during compression"},
{0x0C,0x06,"Block not compressible"},
{0x0C,0x07,"Write error - recovery needed"},
{0x0C,0x08,"Write error - recovery failed"},
{0x0C,0x09,"Write error - loss of streaming"},
{0x0C,0x0A,"Write error - padding blocks added"},
{0x0C,0x0B,"Auxiliary memory write error"},
{0x0C,0x0C,"Write error - unexpected unsolicited data"},
{0x0C,0x0D,"Write error - not enough unsolicited data"},
{0x0D,0x00,"Error detected by third party temporary initiator"},
{0x0D,0x01,"Third party device failure"},
{0x0D,0x02,"Copy target device not reachable"},
{0x0D,0x03,"Incorrect copy target device"},
{0x0D,0x04,"Copy target device underrun"},
{0x0D,0x05,"Copy target device overrun"},
{0x0E,0x00,"Invalid information unit"},
{0x0E,0x01,"Information unit too short"},
{0x0E,0x02,"Information unit too long"},
{0x10,0x00,"Id CRC or ECC error"},
{0x10,0x01,"Data block guard check failed"},
{0x10,0x02,"Data block application tag check failed"},
{0x10,0x03,"Data block reference tag check failed"},
{0x11,0x00,"Unrecovered read error"},
{0x11,0x01,"Read retries exhausted"},
{0x11,0x02,"Error too long to correct"},
{0x11,0x03,"Multiple read errors"},
{0x11,0x04,"Unrecovered read error - auto reallocate failed"},
{0x11,0x05,"L-EC uncorrectable error"},
{0x11,0x06,"CIRC unrecovered error"},
{0x11,0x07,"Data re-synchronization error"},
{0x11,0x08,"Incomplete block read"},
{0x11,0x09,"No gap found"},
{0x11,0x0A,"Miscorrected error"},
{0x11,0x0B,"Unrecovered read error - recommend reassignment"},
{0x11,0x0C,"Unrecovered read error - recommend rewrite the data"},
{0x11,0x0D,"De-compression CRC error"},
{0x11,0x0E,"Cannot decompress using declared algorithm"},
{0x11,0x0F,"Error reading UPC/EAN number"},
{0x11,0x10,"Error reading ISRC number"},
{0x11,0x11,"Read error - loss of streaming"},
{0x11,0x12,"Auxiliary memory read error"},
{0x11,0x13,"Read error - failed retransmission request"},
{0x12,0x00,"Address mark not found for id field"},
{0x13,0x00,"Address mark not found for data field"},
{0x14,0x00,"Recorded entity not found"},
{0x14,0x01,"Record not found"},
{0x14,0x02,"Filemark or setmark not found"},
{0x14,0x03,"End-of-data not found"},
{0x14,0x04,"Block sequence error"},
{0x14,0x05,"Record not found - recommend reassignment"},
{0x14,0x06,"Record not found - data auto-reallocated"},
{0x14,0x07,"Locate operation failure"},
{0x15,0x00,"Random positioning error"},
{0x15,0x01,"Mechanical positioning error"},
{0x15,0x02,"Positioning error detected by read of medium"},
{0x16,0x00,"Data synchronization mark error"},
{0x16,0x01,"Data sync error - data rewritten"},
{0x16,0x02,"Data sync error - recommend rewrite"},
{0x16,0x03,"Data sync error - data auto-reallocated"},
{0x16,0x04,"Data sync error - recommend reassignment"},
{0x17,0x00,"Recovered data with no error correction applied"},
{0x17,0x01,"Recovered data with retries"},
{0x17,0x02,"Recovered data with positive head offset"},
{0x17,0x03,"Recovered data with negative head offset"},
{0x17,0x04,"Recovered data with retries and/or circ applied"},
{0x17,0x05,"Recovered data using previous sector id"},
{0x17,0x06,"Recovered data without ECC - data auto-reallocated"},
{0x17,0x07,"Recovered data without ECC - recommend reassignment"},
{0x17,0x08,"Recovered data without ECC - recommend rewrite"},
{0x17,0x09,"Recovered data without ECC - data rewritten"},
{0x18,0x00,"Recovered data with error correction applied"},
{0x18,0x01,"Recovered data with error corr. & retries applied"},
{0x18,0x02,"Recovered data - data auto-reallocated"},
{0x18,0x03,"Recovered data with CIRC"},
{0x18,0x04,"Recovered data with L-EC"},
{0x18,0x05,"Recovered data - recommend reassignment"},
{0x18,0x06,"Recovered data - recommend rewrite"},
{0x18,0x07,"Recovered data with ECC - data rewritten"},
{0x18,0x08,"Recovered data with linking"},
{0x19,0x00,"Defect list error"},
{0x19,0x01,"Defect list not available"},
{0x19,0x02,"Defect list error in primary list"},
{0x19,0x03,"Defect list error in grown list"},
{0x1A,0x00,"Parameter list length error"},
{0x1B,0x00,"Synchronous data transfer error"},
{0x1C,0x00,"Defect list not found"},
{0x1C,0x01,"Primary defect list not found"},
{0x1C,0x02,"Grown defect list not found"},
{0x1D,0x00,"Miscompare during verify operation"},
{0x1E,0x00,"Recovered id with ECC correction"},
{0x1F,0x00,"Partial defect list transfer"},
{0x20,0x00,"Invalid command operation code"},
{0x20,0x01,"Access denied - initiator pending-enrolled"},
{0x20,0x02,"Access denied - no access rights"},
{0x20,0x03,"Access denied - no mgmt id key"},
{0x20,0x04,"Illegal command while in write capable state"},
{0x20,0x05,"Obsolete"},
{0x20,0x06,"Illegal command while in explicit address mode"},
{0x20,0x07,"Illegal command while in implicit address mode"},
{0x20,0x08,"Access denied - enrollment conflict"},
{0x20,0x09,"Access denied - invalid LU identifier"},
{0x20,0x0A,"Access denied - invalid proxy token"},
{0x20,0x0B,"Access denied - ACL LUN conflict"},
{0x21,0x00,"Logical block address out of range"},
{0x21,0x01,"Invalid element address"},
{0x21,0x02,"Invalid address for write"},
{0x22,0x00,"Illegal function (use 20 00, 24 00, or 26 00)"},
{0x24,0x00,"Invalid field in cdb"},
{0x24,0x01,"CDB decryption error"},
{0x24,0x04,"Security audit value frozen"},
{0x24,0x05,"Security working key frozen"},
{0x24,0x06,"Nonce not unique"},
{0x24,0x07,"Nonce timestamp out of range"},
{0x25,0x00,"Logical unit not supported"},
{0x26,0x00,"Invalid field in parameter list"},
{0x26,0x01,"Parameter not supported"},
{0x26,0x02,"Parameter value invalid"},
{0x26,0x03,"Threshold parameters not supported"},
{0x26,0x04,"Invalid release of persistent reservation"},
{0x26,0x05,"Data decryption error"},
{0x26,0x06,"Too many target descriptors"},
{0x26,0x07,"Unsupported target descriptor type code"},
{0x26,0x08,"Too many segment descriptors"},
{0x26,0x09,"Unsupported segment descriptor type code"},
{0x26,0x0A,"Unexpected inexact segment"},
{0x26,0x0B,"Inline data length exceeded"},
{0x26,0x0C,"Invalid operation for copy source or destination"},
{0x26,0x0D,"Copy segment granularity violation"},
{0x26,0x0E,"Invalid parameter while port is enabled"},
{0x26,0x0F,"Invalid data-out buffer integrity"},
{0x27,0x00,"Write protected"},
{0x27,0x01,"Hardware write protected"},
{0x27,0x02,"Logical unit software write protected"},
{0x27,0x03,"Associated write protect"},
{0x27,0x04,"Persistent write protect"},
{0x27,0x05,"Permanent write protect"},
{0x27,0x06,"Conditional write protect"},
{0x28,0x00,"Not ready to ready change, medium may have changed"},
{0x28,0x01,"Import or export element accessed"},
{0x29,0x00,"Power on, reset, or bus device reset occurred"},
{0x29,0x01,"Power on occurred"},
{0x29,0x02,"SCSI bus reset occurred"},
{0x29,0x03,"Bus device reset function occurred"},
{0x29,0x04,"Device internal reset"},
{0x29,0x05,"Transceiver mode changed to single-ended"},
{0x29,0x06,"Transceiver mode changed to lvd"},
{0x29,0x07,"I_T nexus loss occurred"},
{0x2A,0x00,"Parameters changed"},
{0x2A,0x01,"Mode parameters changed"},
{0x2A,0x02,"Log parameters changed"},
{0x2A,0x03,"Reservations preempted"},
{0x2A,0x04,"Reservations released"},
{0x2A,0x05,"Registrations preempted"},
{0x2A,0x06,"Asymmetric access state changed"},
{0x2A,0x07,"Implicit asymmetric access state transition failed"},
{0x2A,0x08,"Priority changed"},
{0x2A,0x09,"Capacity data has changed"},
{0x2A,0x10,"Timestamp changed"},
{0x2B,0x00,"Copy cannot execute since host cannot disconnect"},
{0x2C,0x00,"Command sequence error"},
{0x2C,0x01,"Too many windows specified"},
{0x2C,0x02,"Invalid combination of windows specified"},
{0x2C,0x03,"Current program area is not empty"},
{0x2C,0x04,"Current program area is empty"},
{0x2C,0x05,"Illegal power condition request"},
{0x2C,0x06,"Persistent prevent conflict"},
{0x2C,0x07,"Previous busy status"},
{0x2C,0x08,"Previous task set full status"},
{0x2C,0x09,"Previous reservation conflict status"},
{0x2C,0x0A,"Partition or collection contains user objects"},
{0x2C,0x0B,"Not reserved"},
{0x2D,0x00,"Overwrite error on update in place"},
{0x2E,0x00,"Insufficient time for operation"},
{0x2F,0x00,"Commands cleared by another initiator"},
{0x30,0x00,"Incompatible medium installed"},
{0x30,0x01,"Cannot read medium - unknown format"},
{0x30,0x02,"Cannot read medium - incompatible format"},
{0x30,0x03,"Cleaning cartridge installed"},
{0x30,0x04,"Cannot write medium - unknown format"},
{0x30,0x05,"Cannot write medium - incompatible format"},
{0x30,0x06,"Cannot format medium - incompatible medium"},
{0x30,0x07,"Cleaning failure"},
{0x30,0x08,"Cannot write - application code mismatch"},
{0x30,0x09,"Current session not fixated for append"},
{0x30,0x0A,"Cleaning request rejected"},
{0x30,0x0C,"WORM medium, overwrite attempted"},
{0x30,0x10,"Medium not formatted"},
{0x31,0x00,"Medium format corrupted"},
{0x31,0x01,"Format command failed"},
{0x31,0x02,"Zoned formatting failed due to spare linking"},
{0x32,0x00,"No defect spare location available"},
{0x32,0x01,"Defect list update failure"},
{0x33,0x00,"Tape length error"},
{0x34,0x00,"Enclosure failure"},
{0x35,0x00,"Enclosure services failure"},
{0x35,0x01,"Unsupported enclosure function"},
{0x35,0x02,"Enclosure services unavailable"},
{0x35,0x03,"Enclosure services transfer failure"},
{0x35,0x04,"Enclosure services transfer refused"},
{0x35,0x05,"Enclosure services checksum error"},
{0x36,0x00,"Ribbon,ink,or toner failure"},
{0x37,0x00,"Rounded parameter"},
{0x38,0x00,"Event status notification"},
{0x38,0x02,"Esn - power management class event"},
{0x38,0x04,"Esn - media class event"},
{0x38,0x06,"Esn - device busy class event"},
{0x39,0x00,"Saving parameters not supported"},
{0x3A,0x00,"Medium not present"},
{0x3A,0x01,"Medium not present - tray closed"},
{0x3A,0x02,"Medium not present - tray open"},
{0x3A,0x03,"Medium not present - loadable"},
{0x3A,0x04,"Medium not present - medium auxiliary memory accessible"},
{0x3B,0x00,"Sequential positioning error"},
{0x3B,0x01,"Tape position error at beginning-of-medium"},
{0x3B,0x02,"Tape position error at end-of-medium"},
{0x3B,0x03,"Tape or electronic vertical forms unit not ready, "},
{0x3B,0x04,"Slew failure"},
{0x3B,0x05,"Paper jam"},
{0x3B,0x06,"Failed to sense top-of-form"},
{0x3B,0x07,"Failed to sense bottom-of-form"},
{0x3B,0x08,"Reposition error"},
{0x3B,0x09,"Read past end of medium"},
{0x3B,0x0A,"Read past beginning of medium"},
{0x3B,0x0B,"Position past end of medium"},
{0x3B,0x0C,"Position past beginning of medium"},
{0x3B,0x0D,"Medium destination element full"},
{0x3B,0x0E,"Medium source element empty"},
{0x3B,0x0F,"End of medium reached"},
{0x3B,0x11,"Medium magazine not accessible"},
{0x3B,0x12,"Medium magazine removed"},
{0x3B,0x13,"Medium magazine inserted"},
{0x3B,0x14,"Medium magazine locked"},
{0x3B,0x15,"Medium magazine unlocked"},
{0x3B,0x16,"Mechanical positioning or changer error"},
{0x3B,0x17,"Read past end of user object"},
{0x3D,0x00,"Invalid bits in identify message"},
{0x3E,0x00,"Logical unit has not self-configured yet"},
{0x3E,0x01,"Logical unit failure"},
{0x3E,0x02,"Timeout on logical unit"},
{0x3E,0x03,"Logical unit failed self-test"},
{0x3E,0x04,"Logical unit unable to update self-test log"},
{0x3F,0x00,"Target operating conditions have changed"},
{0x3F,0x01,"Microcode has been changed"},
{0x3F,0x02,"Changed operating definition"},
{0x3F,0x03,"Inquiry data has changed"},
{0x3F,0x04,"Component device attached"},
{0x3F,0x05,"Device identifier changed"},
{0x3F,0x06,"Redundancy group created or modified"},
{0x3F,0x07,"Redundancy group deleted"},
{0x3F,0x08,"Spare created or modified"},
{0x3F,0x09,"Spare deleted"},
{0x3F,0x0A,"Volume set created or modified"},
{0x3F,0x0B,"Volume set deleted"},
{0x3F,0x0C,"Volume set deassigned"},
{0x3F,0x0D,"Volume set reassigned"},
{0x3F,0x0E,"Reported luns data has changed"},
{0x3F,0x0F,"Echo buffer overwritten"},
{0x3F,0x10,"Medium loadable"},
{0x3F,0x11,"Medium auxiliary memory accessible"},
/*
* ASC 0x40, 0x41 and 0x42 overridden by "additional2" array entries
* for ascq > 1. Preferred error message for this group is
* "Diagnostic failure on component nn (80h-ffh)".
*/
{0x40,0x00,"Ram failure (should use 40 nn)"},
{0x41,0x00,"Data path failure (should use 40 nn)"},
{0x42,0x00,"Power-on or self-test failure (should use 40 nn)"},
{0x43,0x00,"Message error"},
{0x44,0x00,"Internal target failure"},
{0x45,0x00,"Select or reselect failure"},
{0x46,0x00,"Unsuccessful soft reset"},
{0x47,0x00,"SCSI parity error"},
{0x47,0x01,"Data phase CRC error detected"},
{0x47,0x02,"SCSI parity error detected during st data phase"},
{0x47,0x03,"Information unit CRC error detected"},
{0x47,0x04,"Asynchronous information protection error detected"},
{0x47,0x05,"Protocol service CRC error"},
{0x47,0x7F,"Some commands cleared by iSCSI protocol event"},
{0x48,0x00,"Initiator detected error message received"},
{0x49,0x00,"Invalid message error"},
{0x4A,0x00,"Command phase error"},
{0x4B,0x00,"Data phase error"},
{0x4B,0x01,"Invalid target port transfer tag received"},
{0x4B,0x02,"Too much write data"},
{0x4B,0x03,"Ack/nak timeout"},
{0x4B,0x04,"Nak received"},
{0x4B,0x05,"Data offset error"},
{0x4B,0x06,"Initiator response timeout"},
{0x4C,0x00,"Logical unit failed self-configuration"},
/*
* ASC 0x4D overridden by an "additional2" array entry
* so there is no need to have them here.
*/
/* {0x4D,0x00,"Tagged overlapped commands (nn = queue tag)"}, */
{0x4E,0x00,"Overlapped commands attempted"},
{0x50,0x00,"Write append error"},
{0x50,0x01,"Write append position error"},
{0x50,0x02,"Position error related to timing"},
{0x51,0x00,"Erase failure"},
{0x51,0x01,"Erase failure - incomplete erase operation detected"},
{0x52,0x00,"Cartridge fault"},
{0x53,0x00,"Media load or eject failed"},
{0x53,0x01,"Unload tape failure"},
{0x53,0x02,"Medium removal prevented"},
{0x53,0x03,"Data transfer element prevented medium removal"},
{0x54,0x00,"SCSI to host system interface failure"},
{0x55,0x00,"System resource failure"},
{0x55,0x01,"System buffer full"},
{0x55,0x02,"Insufficient reservation resources"},
{0x55,0x03,"Insufficient resources"},
{0x55,0x04,"Insufficient registration resources"},
{0x55,0x05,"Insufficient access control resources"},
{0x55,0x06,"Auxiliary memory out of space"},
{0x55,0x07,"Quota error"},
{0x57,0x00,"Unable to recover table-of-contents"},
{0x58,0x00,"Generation does not exist"},
{0x59,0x00,"Updated block read"},
{0x5A,0x00,"Operator request or state change input"},
{0x5A,0x01,"Operator medium removal request"},
{0x5A,0x02,"Operator selected write protect"},
{0x5A,0x03,"Operator selected write permit"},
{0x5B,0x00,"Log exception"},
{0x5B,0x01,"Threshold condition met"},
{0x5B,0x02,"Log counter at maximum"},
{0x5B,0x03,"Log list codes exhausted"},
{0x5C,0x00,"Rpl status change"},
{0x5C,0x01,"Spindles synchronized"},
{0x5C,0x02,"Spindles not synchronized"},
{0x5D,0x00,"Failure prediction threshold exceeded"},
{0x5D,0x01,"Media failure prediction threshold exceeded"},
{0x5D,0x02,"Logical unit failure prediction threshold exceeded"},
{0x5D,0x03,"spare area exhaustion prediction threshold exceeded"},
{0x5D,0x10,"Hardware impending failure general hard drive failure"},
{0x5D,0x11,"Hardware impending failure drive error rate too high" },
{0x5D,0x12,"Hardware impending failure data error rate too high" },
{0x5D,0x13,"Hardware impending failure seek error rate too high" },
{0x5D,0x14,"Hardware impending failure too many block reassigns"},
{0x5D,0x15,"Hardware impending failure access times too high" },
{0x5D,0x16,"Hardware impending failure start unit times too high" },
{0x5D,0x17,"Hardware impending failure channel parametrics"},
{0x5D,0x18,"Hardware impending failure controller detected"},
{0x5D,0x19,"Hardware impending failure throughput performance"},
{0x5D,0x1A,"Hardware impending failure seek time performance"},
{0x5D,0x1B,"Hardware impending failure spin-up retry count"},
{0x5D,0x1C,"Hardware impending failure drive calibration retry count"},
{0x5D,0x20,"Controller impending failure general hard drive failure"},
{0x5D,0x21,"Controller impending failure drive error rate too high" },
{0x5D,0x22,"Controller impending failure data error rate too high" },
{0x5D,0x23,"Controller impending failure seek error rate too high" },
{0x5D,0x24,"Controller impending failure too many block reassigns"},
{0x5D,0x25,"Controller impending failure access times too high" },
{0x5D,0x26,"Controller impending failure start unit times too high" },
{0x5D,0x27,"Controller impending failure channel parametrics"},
{0x5D,0x28,"Controller impending failure controller detected"},
{0x5D,0x29,"Controller impending failure throughput performance"},
{0x5D,0x2A,"Controller impending failure seek time performance"},
{0x5D,0x2B,"Controller impending failure spin-up retry count"},
{0x5D,0x2C,"Controller impending failure drive calibration retry count"},
{0x5D,0x30,"Data channel impending failure general hard drive failure"},
{0x5D,0x31,"Data channel impending failure drive error rate too high" },
{0x5D,0x32,"Data channel impending failure data error rate too high" },
{0x5D,0x33,"Data channel impending failure seek error rate too high" },
{0x5D,0x34,"Data channel impending failure too many block reassigns"},
{0x5D,0x35,"Data channel impending failure access times too high" },
{0x5D,0x36,"Data channel impending failure start unit times too high" },
{0x5D,0x37,"Data channel impending failure channel parametrics"},
{0x5D,0x38,"Data channel impending failure controller detected"},
{0x5D,0x39,"Data channel impending failure throughput performance"},
{0x5D,0x3A,"Data channel impending failure seek time performance"},
{0x5D,0x3B,"Data channel impending failure spin-up retry count"},
{0x5D,0x3C,"Data channel impending failure drive calibration retry count"},
{0x5D,0x40,"Servo impending failure general hard drive failure"},
{0x5D,0x41,"Servo impending failure drive error rate too high" },
{0x5D,0x42,"Servo impending failure data error rate too high" },
{0x5D,0x43,"Servo impending failure seek error rate too high" },
{0x5D,0x44,"Servo impending failure too many block reassigns"},
{0x5D,0x45,"Servo impending failure access times too high" },
{0x5D,0x46,"Servo impending failure start unit times too high" },
{0x5D,0x47,"Servo impending failure channel parametrics"},
{0x5D,0x48,"Servo impending failure controller detected"},
{0x5D,0x49,"Servo impending failure throughput performance"},
{0x5D,0x4A,"Servo impending failure seek time performance"},
{0x5D,0x4B,"Servo impending failure spin-up retry count"},
{0x5D,0x4C,"Servo impending failure drive calibration retry count"},
{0x5D,0x50,"Spindle impending failure general hard drive failure"},
{0x5D,0x51,"Spindle impending failure drive error rate too high" },
{0x5D,0x52,"Spindle impending failure data error rate too high" },
{0x5D,0x53,"Spindle impending failure seek error rate too high" },
{0x5D,0x54,"Spindle impending failure too many block reassigns"},
{0x5D,0x55,"Spindle impending failure access times too high" },
{0x5D,0x56,"Spindle impending failure start unit times too high" },
{0x5D,0x57,"Spindle impending failure channel parametrics"},
{0x5D,0x58,"Spindle impending failure controller detected"},
{0x5D,0x59,"Spindle impending failure throughput performance"},
{0x5D,0x5A,"Spindle impending failure seek time performance"},
{0x5D,0x5B,"Spindle impending failure spin-up retry count"},
{0x5D,0x5C,"Spindle impending failure drive calibration retry count"},
{0x5D,0x60,"Firmware impending failure general hard drive failure"},
{0x5D,0x61,"Firmware impending failure drive error rate too high" },
{0x5D,0x62,"Firmware impending failure data error rate too high" },
{0x5D,0x63,"Firmware impending failure seek error rate too high" },
{0x5D,0x64,"Firmware impending failure too many block reassigns"},
{0x5D,0x65,"Firmware impending failure access times too high" },
{0x5D,0x66,"Firmware impending failure start unit times too high" },
{0x5D,0x67,"Firmware impending failure channel parametrics"},
{0x5D,0x68,"Firmware impending failure controller detected"},
{0x5D,0x69,"Firmware impending failure throughput performance"},
{0x5D,0x6A,"Firmware impending failure seek time performance"},
{0x5D,0x6B,"Firmware impending failure spin-up retry count"},
{0x5D,0x6C,"Firmware impending failure drive calibration retry count"},
{0x5D,0xFF,"Failure prediction threshold exceeded (false)"},
{0x5E,0x00,"Low power condition on"},
{0x5E,0x01,"Idle condition activated by timer"},
{0x5E,0x02,"Standby condition activated by timer"},
{0x5E,0x03,"Idle condition activated by command"},
{0x5E,0x04,"Standby condition activated by command"},
{0x5E,0x41,"Power state change to active"},
{0x5E,0x42,"Power state change to idle"},
{0x5E,0x43,"Power state change to standby"},
{0x5E,0x45,"Power state change to sleep"},
{0x5E,0x47,"Power state change to device control"},
{0x60,0x00,"Lamp failure"},
{0x61,0x00,"Video acquisition error"},
{0x61,0x01,"Unable to acquire video"},
{0x61,0x02,"Out of focus"},
{0x62,0x00,"Scan head positioning error"},
{0x63,0x00,"End of user area encountered on this track"},
{0x63,0x01,"Packet does not fit in available space"},
{0x64,0x00,"Illegal mode for this track"},
{0x64,0x01,"Invalid packet size"},
{0x65,0x00,"Voltage fault"},
{0x66,0x00,"Automatic document feeder cover up"},
{0x66,0x01,"Automatic document feeder lift up"},
{0x66,0x02,"Document jam in automatic document feeder"},
{0x66,0x03,"Document miss feed automatic in document feeder"},
{0x67,0x00,"Configuration failure"},
{0x67,0x01,"Configuration of incapable logical units failed"},
{0x67,0x02,"Add logical unit failed"},
{0x67,0x03,"Modification of logical unit failed"},
{0x67,0x04,"Exchange of logical unit failed"},
{0x67,0x05,"Remove of logical unit failed"},
{0x67,0x06,"Attachment of logical unit failed"},
{0x67,0x07,"Creation of logical unit failed"},
{0x67,0x08,"Assign failure occurred"},
{0x67,0x09,"Multiply assigned logical unit"},
{0x67,0x0A,"Set target port groups command failed"},
{0x68,0x00,"Logical unit not configured"},
{0x69,0x00,"Data loss on logical unit"},
{0x69,0x01,"Multiple logical unit failures"},
{0x69,0x02,"Parity/data mismatch"},
{0x6A,0x00,"Informational, refer to log"},
{0x6B,0x00,"State change has occurred"},
{0x6B,0x01,"Redundancy level got better"},
{0x6B,0x02,"Redundancy level got worse"},
{0x6C,0x00,"Rebuild failure occurred"},
{0x6D,0x00,"Recalculate failure occurred"},
{0x6E,0x00,"Command to logical unit failed"},
{0x6F,0x00,"Copy protection key exchange failure - authentication "
"failure"},
{0x6F,0x01,"Copy protection key exchange failure - key not present"},
{0x6F,0x02,"Copy protection key exchange failure - key not established"},
{0x6F,0x03,"Read of scrambled sector without authentication"},
{0x6F,0x04,"Media region code is mismatched to logical unit region"},
{0x6F,0x05,"Drive region must be permanent/region reset count error"},
/*
* ASC 0x70 overridden by an "additional2" array entry
* so there is no need to have them here.
*/
/* {0x70,0x00,"Decompression exception short algorithm id of nn"}, */
{0x71,0x00,"Decompression exception long algorithm id"},
{0x72,0x00,"Session fixation error"},
{0x72,0x01,"Session fixation error writing lead-in"},
{0x72,0x02,"Session fixation error writing lead-out"},
{0x72,0x03,"Session fixation error - incomplete track in session"},
{0x72,0x04,"Empty or partially written reserved track"},
{0x72,0x05,"No more track reservations allowed"},
{0x73,0x00,"Cd control error"},
{0x73,0x01,"Power calibration area almost full"},
{0x73,0x02,"Power calibration area is full"},
{0x73,0x03,"Power calibration area error"},
{0x73,0x04,"Program memory area update failure"},
{0x73,0x05,"Program memory area is full"},
{0x73,0x06,"RMA/PMA is full"},
{0, 0, NULL}
};
static const char *sense_key_desc[] = {
"No Sense", /* There is no sense information */
"Recovered Error", /* The last command completed successfully
but used error correction */
"Not Ready", /* The addressed target is not ready */
"Medium Error", /* Data error detected on the medium */
"Hardware Error", /* Controller or device failure */
"Illegal Request",
"Unit Attention", /* Removable medium was changed, or
the target has been reset */
"Data Protect", /* Access to the data is blocked */
"Blank Check", /* Reached unexpected written or unwritten
region of the medium */
"Key=9", /* Vendor specific */
"Copy Aborted", /* COPY or COMPARE was aborted */
"Aborted Command", /* The target aborted the command */
"Equal", /* SEARCH DATA found data equal (obsolete) */
"Volume Overflow", /* Medium full with data to be written */
"Miscompare", /* Source data and data on the medium
do not agree */
"Key=15" /* Reserved */
};
char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
{
if ((sense_key >= 0) && (sense_key < 16))
snprintf(buff, buff_len, "%s", sense_key_desc[sense_key]);
else
snprintf(buff, buff_len, "invalid value: 0x%x", sense_key);
return buff;
}
char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
{
int k, num, rlen;
int found = 0;
struct error_info * eip;
struct error_info2 * ei2p;
for (k = 0; additional2[k].text; ++k) {
ei2p = &additional2[k];
if ((ei2p->code1 == asc) &&
(ascq >= ei2p->code2_min) &&
(ascq <= ei2p->code2_max)) {
found = 1;
num = snprintf(buff, buff_len, "Additional sense: ");
rlen = buff_len - num;
num += snprintf(buff + num, ((rlen > 0) ? rlen : 0),
ei2p->text, ascq);
}
}
if (found)
return buff;
for (k = 0; additional[k].text; ++k) {
eip = &additional[k];
if (eip->code1 == asc &&
eip->code2 == ascq) {
found = 1;
snprintf(buff, buff_len, "Additional sense: %s", eip->text);
}
}
if (! found) {
if (asc >= 0x80)
snprintf(buff, buff_len, "vendor specific ASC=%2x, ASCQ=%2x",
asc, ascq);
else if (ascq >= 0x80)
snprintf(buff, buff_len, "ASC=%2x, vendor specific qualification "
"ASCQ=%2x", asc, ascq);
else
snprintf(buff, buff_len, "ASC=%2x, ASCQ=%2x", asc, ascq);
}
return buff;
}
const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
int sense_len, int desc_type)
{
int add_sen_len, add_len, desc_len, k;
const unsigned char * descp;
if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
return NULL;
if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
return NULL;
add_sen_len = (add_sen_len < (sense_len - 8)) ?
add_sen_len : (sense_len - 8);
descp = &sensep[8];
for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
descp += desc_len;
add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
desc_len = add_len + 2;
if (descp[0] == desc_type)
return descp;
if (add_len < 0) /* short descriptor ?? */
break;
}
return NULL;
}
int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
unsigned long long * info_outp)
{
int j;
const unsigned char * ucp;
unsigned long long ull;
if (sb_len < 7)
return 0;
switch (sensep[0] & 0x7f) {
case 0x70:
case 0x71:
if (info_outp)
*info_outp = (sensep[3] << 24) + (sensep[4] << 16) +
(sensep[5] << 8) + sensep[6];
return (sensep[0] & 0x80) ? 1 : 0;
case 0x72:
case 0x73:
ucp = sg_scsi_sense_desc_find(sensep, sb_len, 0 /* info desc */);
if (ucp && (0xa == ucp[1])) {
ull = 0;
for (j = 0; j < 8; ++j) {
if (j > 0)
ull <<= 8;
ull |= ucp[4 + j];
}
if (info_outp)
*info_outp = ull;
return !!(ucp[2] & 0x80);
} else
return 0;
default:
return 0;
}
}
int sg_get_sense_progress_fld(const unsigned char * sensep,
int sb_len, int * progress_outp)
{
const unsigned char * ucp;
int sk;
if (sb_len < 7)
return 0;
switch (sensep[0] & 0x7f) {
case 0x70:
case 0x71:
sk = (sensep[2] & 0xf);
if ((sb_len < 18) || ((NO_SENSE != sk) && (NOT_READY != sk)))
return 0;
if (sensep[15] & 0x80) {
if (progress_outp)
*progress_outp = (sensep[16] << 8) + sensep[17];
return 1;
} else
return 0;
case 0x72:
case 0x73:
sk = (sensep[1] & 0xf);
if ((NO_SENSE != sk) && (NOT_READY != sk))
return 0;
ucp = sg_scsi_sense_desc_find(sensep, sb_len, 2 /* sense key spec. */);
if (ucp && (0x6 == ucp[1]) && (0x80 & ucp[4])) {
if (progress_outp)
*progress_outp = (ucp[5] << 8) + ucp[6];
return 1;
} else
return 0;
default:
return 0;
}
}
/* Print descriptor format sense descriptors (assumes sense buffer is
in descriptor format) */
static void sg_print_sense_descriptors(const unsigned char * sense_buffer,
int sb_len)
{
int add_sen_len, add_len, desc_len, k, j, sense_key, processed, progress;
const unsigned char * descp;
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
return;
add_sen_len = (add_sen_len < (sb_len - 8)) ? add_sen_len : (sb_len - 8);
descp = &sense_buffer[8];
sense_key = (sense_buffer[1] & 0xf);
for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
descp += desc_len;
add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
desc_len = add_len + 2;
fprintf(sg_warnings_str, " Descriptor type: ");
processed = 1;
switch (descp[0]) {
case 0:
fprintf(sg_warnings_str, "Information\n");
if ((add_len >= 10) && (0x80 & descp[2])) {
fprintf(sg_warnings_str, " 0x");
for (j = 0; j < 8; ++j)
fprintf(sg_warnings_str, "%02x", descp[4 + j]);
fprintf(sg_warnings_str, "\n");
} else
processed = 0;
break;
case 1:
fprintf(sg_warnings_str, "Command specific\n");
if (add_len >= 10) {
fprintf(sg_warnings_str, " 0x");
for (j = 0; j < 8; ++j)
fprintf(sg_warnings_str, "%02x", descp[4 + j]);
fprintf(sg_warnings_str, "\n");
} else
processed = 0;
break;
case 2:
fprintf(sg_warnings_str, "Sense key specific:");
switch (sense_key) {
case ILLEGAL_REQUEST:
fprintf(sg_warnings_str, " Field pointer\n");
if (add_len < 6) {
processed = 0;
break;
}
fprintf(sg_warnings_str, " Error in %s byte %d",
(descp[4] & 0x40) ? "Command" : "Data",
(descp[5] << 8) | descp[6]);
if (descp[4] & 0x08) {
fprintf(sg_warnings_str, " bit %d\n", descp[4] & 0x07);
} else
fprintf(sg_warnings_str, "\n");
break;
case HARDWARE_ERROR:
case MEDIUM_ERROR:
case RECOVERED_ERROR:
fprintf(sg_warnings_str, " Actual retry count\n");
if (add_len < 6) {
processed = 0;
break;
}
fprintf(sg_warnings_str, " 0x%02x%02x\n", descp[5],
descp[6]);
break;
case NO_SENSE:
case NOT_READY:
fprintf(sg_warnings_str, " Progress indication: ");
if (add_len < 6) {
processed = 0;
fprintf(sg_warnings_str, " field too short\n");
break;
}
progress = (descp[5] << 8) + descp[6];
fprintf(sg_warnings_str, "%d %%\n",
(progress * 100) / 0x10000);
break;
case COPY_ABORTED:
fprintf(sg_warnings_str, " Segment pointer\n");
if (add_len < 6) {
processed = 0;
break;
}
fprintf(sg_warnings_str, " Relative to start of %s, byte %d",
(descp[4] & 0x20) ? "segment descriptor" :
"parameter list",
(descp[5] << 8) | descp[6]);
if (descp[4] & 0x08)
fprintf(sg_warnings_str, " bit %d\n", descp[4] & 0x07);
else
fprintf(sg_warnings_str, "\n");
break;
default:
fprintf(sg_warnings_str, " Sense_key: 0x%x unexpected\n",
sense_key);
processed = 0;
break;
}
break;
case 3:
fprintf(sg_warnings_str, "Field replaceable unit\n");
if (add_len >= 2)
fprintf(sg_warnings_str, " code=0x%x\n", descp[3]);
else
processed = 0;
break;
case 4:
fprintf(sg_warnings_str, "Stream commands\n");
if (add_len >= 2) {
if (descp[3] & 0x80)
fprintf(sg_warnings_str, " FILEMARK");
if (descp[3] & 0x40)
fprintf(sg_warnings_str, " End Of Medium (EOM)");
if (descp[3] & 0x20)
fprintf(sg_warnings_str, " Incorrect Length Indicator "
"(ILI)");
fprintf(sg_warnings_str, "\n");
} else
processed = 0;
break;
case 5:
fprintf(sg_warnings_str, "Block commands\n");
if (add_len >= 2)
fprintf(sg_warnings_str, " Incorrect Length Indicator "
"(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear");
else
processed = 0;
break;
case 6:
fprintf(sg_warnings_str, "OSD object identification\n");
processed = 0;
break;
case 7:
fprintf(sg_warnings_str, "OSD response integrity check value\n");
processed = 0;
break;
case 8:
fprintf(sg_warnings_str, "OSD attribute identification\n");
processed = 0;
break;
case 9:
fprintf(sg_warnings_str, "ATA return\n");
if (add_len >= 14) {
int extended, sector_count, lba_low, lba_mid, lba_high;
extended = descp[2] & 1;
sector_count = descp[5];
lba_low = descp[7];
lba_mid = descp[9];
lba_high = descp[11];
if (extended) {
sector_count += (descp[4] << 8);
lba_low += (descp[6] << 8);
lba_mid += (descp[8] << 8);
lba_high += (descp[10] << 8);
}
fprintf(sg_warnings_str, " extended=%d error=0x%x "
" sector_count=0x%x\n", extended, descp[3],
sector_count);
fprintf(sg_warnings_str, " lba_low=0x%x lba_mid=0x%x "
" lba_high=0x%x\n", lba_low, lba_mid, lba_high);
fprintf(sg_warnings_str, " device=0x%x status=0x%x\n",
descp[12], descp[13]);
} else
processed = 0;
break;
default:
fprintf(sg_warnings_str, "Unknown or vendor specific [0x%x]\n",
descp[0]);
processed = 0;
break;
}
if (! processed) {
if (add_len > 0) {
fprintf(sg_warnings_str, " ");
for (j = 0; (j < add_len) && ((k + j + 2) < add_sen_len);
++j) {
if ((j > 0) && (0 == (j % 24)))
fprintf(sg_warnings_str, "\n ");
fprintf(sg_warnings_str, "%02x ", descp[j + 2]);
}
fprintf(sg_warnings_str, "\n");
}
}
if (add_len < 0) {
fprintf(sg_warnings_str, " short descriptor\n");
break;
}
}
}
/* Print sense information */
void sg_print_sense(const char * leadin, const unsigned char * sense_buffer,
int sb_len)
{
int len, valid, progress;
unsigned int info;
int descriptor_format = 0;
const char * error = NULL;
char error_buff[64];
char add_sense[128];
struct sg_scsi_sense_hdr ssh;
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
if (sb_len < 1) {
fprintf(sg_warnings_str, "sense buffer empty\n");
return;
}
if (leadin)
fprintf(sg_warnings_str, "%s: ", leadin);
len = sb_len;
if (sg_scsi_normalize_sense(sense_buffer, sb_len, &ssh)) {
switch (ssh.response_code) {
case 0x70: /* fixed, current */
error = "Fixed format, current";
len = (sb_len > 7) ? (sense_buffer[7] + 8) : sb_len;
len = (len > sb_len) ? sb_len : len;
break;
case 0x71: /* fixed, deferred */
/* error related to a previous command */
error = "Fixed format, <<<deferred>>>";
len = (sb_len > 7) ? (sense_buffer[7] + 8) : sb_len;
len = (len > sb_len) ? sb_len : len;
break;
case 0x72: /* descriptor, current */
descriptor_format = 1;
error = "Descriptor format, current";
break;
case 0x73: /* descriptor, deferred */
descriptor_format = 1;
error = "Descriptor format, <<<deferred>>>";
break;
case 0x0:
error = "Response code: 0x0 (?)";
break;
default:
snprintf(error_buff, sizeof(error_buff),
"Unknown response code: 0x%x", ssh.response_code);
error = error_buff;
break;
}
fprintf(sg_warnings_str, " %s; Sense key: %s\n ", error,
sense_key_desc[ssh.sense_key]);
if (descriptor_format) {
fprintf(sg_warnings_str, "%s\n",
sg_get_asc_ascq_str(ssh.asc, ssh.ascq,
sizeof(add_sense), add_sense));
sg_print_sense_descriptors(sense_buffer, len);
} else if (len > 2) { /* fixed format */
if (len > 12)
fprintf(sg_warnings_str, "%s\n",
sg_get_asc_ascq_str(ssh.asc, ssh.ascq,
sizeof(add_sense), add_sense));
valid = sense_buffer[0] & 0x80;
if (len > 6) {
info = (unsigned int)((sense_buffer[3] << 24) |
(sense_buffer[4] << 16) | (sense_buffer[5] << 8) |
sense_buffer[6]);
if (valid)
fprintf(sg_warnings_str, " Info fld=0x%x [%u] ", info,
info);
else if (info > 0)
fprintf(sg_warnings_str, " Valid=0, Info fld=0x%x [%u] ",
info, info);
}
if (sense_buffer[2] & 0xe0) {
if (sense_buffer[2] & 0x80)
fprintf(sg_warnings_str, " FMK");
/* current command has read a filemark */
if (sense_buffer[2] & 0x40)
fprintf(sg_warnings_str, " EOM");
/* end-of-medium condition exists */
if (sense_buffer[2] & 0x20)
fprintf(sg_warnings_str, " ILI");
/* incorrect block length requested */
fprintf(sg_warnings_str, "\n");
}
if ((len >= 14) && sense_buffer[14])
fprintf(sg_warnings_str, " Field replaceable unit code: "
"%d\n", sense_buffer[14]);
if ((len >= 18) && (sense_buffer[15] & 0x80)) {
/* sense key specific decoding */
switch (ssh.sense_key) {
case ILLEGAL_REQUEST:
fprintf(sg_warnings_str, " Sense Key Specific: Error in "
"%s byte %d",
(sense_buffer[15] & 0x40) ? "Command" : "Data",
(sense_buffer[16] << 8) | sense_buffer[17]);
if (sense_buffer[15] & 0x08)
fprintf(sg_warnings_str, " bit %d\n",
sense_buffer[15] & 0x07);
else
fprintf(sg_warnings_str, "\n");
break;
case NO_SENSE:
case NOT_READY:
progress = (sense_buffer[16] << 8) + sense_buffer[17];
fprintf(sg_warnings_str, " Progress indication: %d %%\n",
(progress * 100) / 0x10000);
break;
case HARDWARE_ERROR:
case MEDIUM_ERROR:
case RECOVERED_ERROR:
fprintf(sg_warnings_str, " Actual retry count: "
"0x%02x%02x\n", sense_buffer[16],
sense_buffer[17]);
break;
case COPY_ABORTED:
fprintf(sg_warnings_str, " Segment pointer: ");
fprintf(sg_warnings_str, "Relative to start of %s, byte %d",
(sense_buffer[15] & 0x20) ? "segment descriptor" :
"parameter list",
(sense_buffer[16] << 8) + sense_buffer[17]);
if (sense_buffer[15] & 0x08)
fprintf(sg_warnings_str, " bit %d\n",
sense_buffer[15] & 0x07);
else
fprintf(sg_warnings_str, "\n");
break;
default:
fprintf(sg_warnings_str, " Sense_key: 0x%x unexpected\n",
ssh.sense_key);
break;
}
}
} else
fprintf(sg_warnings_str, " fixed descriptor length too short, "
"len=%d\n", len);
} else { /* non-extended sense data */
/*
* Standard says:
* sense_buffer[0] & 0200 : address valid
* sense_buffer[0] & 0177 : vendor-specific error code
* sense_buffer[1] & 0340 : vendor-specific
* sense_buffer[1..3] : 21-bit logical block address
*/
if (sb_len < 4) {
fprintf(sg_warnings_str, "sense buffer too short (4 byte "
"minimum)\n");
return;
}
if (leadin)
fprintf(sg_warnings_str, "%s: ", leadin);
if (sense_buffer[0] < 15)
fprintf(sg_warnings_str, "old (SCSI-1) sense: key %s\n",
sense_key_desc[sense_buffer[0] & 0x0f]);
else
fprintf(sg_warnings_str, "sns = %2x %2x\n", sense_buffer[0],
sense_buffer[2]);
fprintf(sg_warnings_str, "Non-extended sense class %d code 0x%0x ",
(sense_buffer[0] >> 4) & 0x07, sense_buffer[0] & 0xf);
len = 4;
}
fprintf(sg_warnings_str, " Raw sense data (in hex):\n");
dStrHexErr((const char *)sense_buffer, len);
}
static const char * linux_host_bytes[] = {
"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
"DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
"DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR"
};
#define LINUX_HOST_BYTES_SZ \
(int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0]))
void sg_print_host_status(int host_status)
{
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "Host_status=0x%02x ", host_status);
if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ))
fprintf(sg_warnings_str, "is invalid ");
else
fprintf(sg_warnings_str, "[%s] ", linux_host_bytes[host_status]);
}
static const char * linux_driver_bytes[] = {
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
"DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
"DRIVER_SENSE"
};
#define LINUX_DRIVER_BYTES_SZ \
(int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0]))
static const char * linux_driver_suggests[] = {
"SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
"SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
"SUGGEST_SENSE"
};
#define LINUX_DRIVER_SUGGESTS_SZ \
(int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0]))
void sg_print_driver_status(int driver_status)
{
int driv, sugg;
const char * driv_cp = "invalid";
const char * sugg_cp = "invalid";
driv = driver_status & SG_LIB_DRIVER_MASK;
if (driv < LINUX_DRIVER_BYTES_SZ)
driv_cp = linux_driver_bytes[driv];
sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4;
if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
sugg_cp = linux_driver_suggests[sugg];
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "Driver_status=0x%02x", driver_status);
fprintf(sg_warnings_str, " [%s, %s] ", driv_cp, sugg_cp);
}
/* Returns 1 if no errors found and thus nothing printed; otherwise
prints error/warning (prefix by 'leadin') and returns 0. */
static int sg_sense_print(const char * leadin, int scsi_status,
int host_status, int driver_status,
const unsigned char * sense_buffer, int sb_len)
{
int done_leadin = 0;
int done_sense = 0;
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
scsi_status &= 0x7e; /*sanity */
if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
return 1; /* No problems */
if (0 != scsi_status) {
if (leadin)
fprintf(sg_warnings_str, "%s: ", leadin);
done_leadin = 1;
fprintf(sg_warnings_str, "SCSI status: ");
sg_print_scsi_status(scsi_status);
fprintf(sg_warnings_str, "\n");
if (sense_buffer && ((scsi_status == SCSI_CHECK_CONDITION) ||
(scsi_status == SCSI_COMMAND_TERMINATED))) {
/* SCSI_COMMAND_TERMINATED is obsolete */
sg_print_sense(0, sense_buffer, sb_len);
done_sense = 1;
}
}
if (0 != host_status) {
if (leadin && (! done_leadin))
fprintf(sg_warnings_str, "%s: ", leadin);
if (done_leadin)
fprintf(sg_warnings_str, "plus...: ");
else
done_leadin = 1;
sg_print_host_status(host_status);
fprintf(sg_warnings_str, "\n");
}
if (0 != driver_status) {
if (leadin && (! done_leadin))
fprintf(sg_warnings_str, "%s: ", leadin);
if (done_leadin)
fprintf(sg_warnings_str, "plus...: ");
else
done_leadin = 1;
sg_print_driver_status(driver_status);
fprintf(sg_warnings_str, "\n");
if (sense_buffer && (! done_sense) &&
(SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
sg_print_sense(0, sense_buffer, sb_len);
}
return 0;
}
int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len,
struct sg_scsi_sense_hdr * sshp)
{
if (sshp)
memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
if ((NULL == sensep) || (0 == sb_len) || (0x70 != (0x70 & sensep[0])))
return 0;
if (sshp) {
sshp->response_code = (0x7f & sensep[0]);
if (sshp->response_code >= 0x72) { /* descriptor format */
if (sb_len > 1)
sshp->sense_key = (0xf & sensep[1]);
if (sb_len > 2)
sshp->asc = sensep[2];
if (sb_len > 3)
sshp->ascq = sensep[3];
if (sb_len > 7)
sshp->additional_length = sensep[7];
} else { /* fixed format */
if (sb_len > 2)
sshp->sense_key = (0xf & sensep[2]);
if (sb_len > 7) {
sb_len = (sb_len < (sensep[7] + 8)) ? sb_len :
(sensep[7] + 8);
if (sb_len > 12)
sshp->asc = sensep[12];
if (sb_len > 13)
sshp->ascq = sensep[13];
}
}
}
return 1;
}
#ifdef SG_IO
int sg_normalize_sense(const struct sg_io_hdr * hp,
struct sg_scsi_sense_hdr * sshp)
{
if ((NULL == hp) || (0 == hp->sb_len_wr)) {
if (sshp)
memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
return 0;
}
return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp);
}
/* Returns 1 if no errors found and thus nothing printed; otherwise
returns 0. */
int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp)
{
return sg_sense_print(leadin, hp->status, hp->host_status,
hp->driver_status, hp->sbp, hp->sb_len_wr);
}
#endif
/* Returns 1 if no errors found and thus nothing printed; otherwise
returns 0. */
int sg_chk_n_print(const char * leadin, int masked_status,
int host_status, int driver_status,
const unsigned char * sense_buffer, int sb_len)
{
int scsi_status = (masked_status << 1) & 0x7e;
return sg_sense_print(leadin, scsi_status, host_status, driver_status,
sense_buffer, sb_len);
}
#ifdef SG_IO
int sg_err_category3(struct sg_io_hdr * hp)
{
return sg_err_category_new(hp->status, hp->host_status,
hp->driver_status, hp->sbp, hp->sb_len_wr);
}
#endif
int sg_err_category(int masked_status, int host_status,
int driver_status, const unsigned char * sense_buffer,
int sb_len)
{
int scsi_status = (masked_status << 1) & 0x7e;
return sg_err_category_new(scsi_status, host_status, driver_status,
sense_buffer, sb_len);
}
int sg_err_category_new(int scsi_status, int host_status, int driver_status,
const unsigned char * sense_buffer, int sb_len)
{
int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status);
scsi_status &= 0x7e;
if ((0 == scsi_status) && (0 == host_status) &&
(0 == masked_driver_status))
return SG_LIB_CAT_CLEAN;
if ((SCSI_CHECK_CONDITION == scsi_status) ||
(SCSI_COMMAND_TERMINATED == scsi_status) ||
(SG_LIB_DRIVER_SENSE == masked_driver_status)) {
struct sg_scsi_sense_hdr ssh;
if ((sense_buffer && (sb_len > 2)) &&
(sg_scsi_normalize_sense(sense_buffer, sb_len, &ssh))) {
switch (ssh.sense_key) {
case RECOVERED_ERROR:
return SG_LIB_CAT_RECOVERED;
case MEDIUM_ERROR:
case HARDWARE_ERROR:
return SG_LIB_CAT_MEDIUM_HARD;
case UNIT_ATTENTION:
if (0x28 == ssh.asc)
return SG_LIB_CAT_MEDIA_CHANGED;
if (0x29 == ssh.asc)
return SG_LIB_CAT_RESET;
break;
case ILLEGAL_REQUEST:
if ((0x20 == ssh.asc) && (0x0 == ssh.ascq))
return SG_LIB_CAT_INVALID_OP;
else
return SG_LIB_CAT_ILLEGAL_REQ;
break;
}
}
return SG_LIB_CAT_SENSE;
}
if (0 != host_status) {
if ((SG_LIB_DID_NO_CONNECT == host_status) ||
(SG_LIB_DID_BUS_BUSY == host_status) ||
(SG_LIB_DID_TIME_OUT == host_status))
return SG_LIB_CAT_TIMEOUT;
}
if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status)
return SG_LIB_CAT_TIMEOUT;
return SG_LIB_CAT_OTHER;
}
/* gives wrong answer for variable length command (opcode=0x7f) */
int sg_get_command_size(unsigned char opcode)
{
switch ((opcode >> 5) & 0x7) {
case 0:
return 6;
case 1: case 2: case 6: case 7:
return 10;
case 3: case 5:
return 12;
break;
case 4:
return 16;
default:
return 10;
}
}
void sg_get_command_name(const unsigned char * cmdp, int peri_type,
int buff_len, char * buff)
{
int service_action;
if ((NULL == buff) || (buff_len < 1))
return;
if (NULL == cmdp) {
strncpy(buff, "<null> command pointer", buff_len);
return;
}
service_action = (SG_VARIABLE_LENGTH_CMD == cmdp[0]) ?
(cmdp[1] & 0x1f) : ((cmdp[8] << 8) | cmdp[9]);
sg_get_opcode_sa_name(cmdp[0], service_action, peri_type, buff_len, buff);
}
void sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action,
int peri_type, int buff_len, char * buff)
{
const struct value_name_t * vnp;
if ((NULL == buff) || (buff_len < 1))
return;
switch ((int)cmd_byte0) {
case SG_VARIABLE_LENGTH_CMD:
vnp = get_value_name(variable_length_arr, VARIABLE_LENGTH_SZ,
service_action, peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Variable length service action=0x%x",
service_action);
break;
case SG_MAINTENANCE_IN:
vnp = get_value_name(maint_in_arr, MAINT_IN_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Maintenance in service action=0x%x",
service_action);
break;
case SG_MAINTENANCE_OUT:
vnp = get_value_name(maint_out_arr, MAINT_OUT_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Maintenance out service action=0x%x",
service_action);
break;
case SG_SERVICE_ACTION_IN_12:
vnp = get_value_name(serv_in12_arr, SERV_IN12_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Service action in(12)=0x%x",
service_action);
break;
case SG_SERVICE_ACTION_OUT_12:
vnp = get_value_name(serv_out12_arr, SERV_OUT12_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Service action out(12)=0x%x",
service_action);
break;
case SG_SERVICE_ACTION_IN_16:
vnp = get_value_name(serv_in16_arr, SERV_IN16_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Service action in(16)=0x%x",
service_action);
break;
case SG_SERVICE_ACTION_OUT_16:
vnp = get_value_name(serv_out16_arr, SERV_OUT16_SZ, service_action,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Service action out(16)=0x%x",
service_action);
break;
default:
sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
break;
}
}
void sg_get_opcode_name(unsigned char cmd_byte0, int peri_type,
int buff_len, char * buff)
{
const struct value_name_t * vnp;
int grp;
if ((NULL == buff) || (buff_len < 1))
return;
if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) {
strncpy(buff, "Variable length", buff_len);
return;
}
grp = (cmd_byte0 >> 5) & 0x7;
switch (grp) {
case 0:
case 1:
case 2:
case 4:
case 5:
vnp = get_value_name(normal_opcodes, NORMAL_OPCODES_SZ, cmd_byte0,
peri_type);
if (vnp)
strncpy(buff, vnp->name, buff_len);
else
snprintf(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
break;
case 3:
snprintf(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0);
break;
case 6:
case 7:
snprintf(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0);
break;
default:
snprintf(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
break;
}
}
/* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
Allows for situation in which strerror() is given a wild value (or the
C library is incomplete) and returns NULL. Still not thread safe.
*/
static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ',
'e', 'r', 'r', 'n', 'o', ':', ' ', 0};
char * safe_strerror(int errnum)
{
size_t len;
char * errstr;
errstr = strerror(errnum);
if (NULL == errstr) {
len = strlen(safe_errbuf);
snprintf(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum);
safe_errbuf[sizeof(safe_errbuf) - 1] = '\0'; /* bombproof */
return safe_errbuf;
}
return errstr;
}
/* Note the ASCII-hex output goes to stdout. [All other output from functions
in this file go to sg_warnings_str (default stderr).]
'no_ascii' allows for 3 output types:
> 0 each line has address then up to 16 ASCII-hex bytes
= 0 in addition, the bytes are listed in ASCII to the right
< 0 only the ASCII-hex bytes are listed (up to 16 per line) */
void dStrHex(const char* str, int len, int no_ascii)
{
const char* p = str;
unsigned char c;
char buff[82];
int a = 0;
const int bpstart = 5;
const int cpstart = 60;
int cpos = cpstart;
int bpos = bpstart;
int i, k;
if (len <= 0)
return;
memset(buff, ' ', 80);
buff[80] = '\0';
if (no_ascii < 0) {
for (k = 0; k < len; k++) {
c = *p++;
bpos += 3;
if (bpos == (bpstart + (9 * 3)))
bpos++;
sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
buff[bpos + 2] = ' ';
if ((k > 0) && (0 == ((k + 1) % 16))) {
printf("%.60s\n", buff);
bpos = bpstart;
memset(buff, ' ', 80);
}
}
if (bpos > bpstart)
printf("%.60s\n", buff);
return;
}
/* no_ascii>=0, start each line with address (offset) */
k = sprintf(buff + 1, "%.2x", a);
buff[k + 1] = ' ';
if (bpos >= ((bpstart + (9 * 3))))
bpos++;
for (i = 0; i < len; i++) {
c = *p++;
bpos += 3;
if (bpos == (bpstart + (9 * 3)))
bpos++;
sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
buff[bpos + 2] = ' ';
if (no_ascii)
buff[cpos++] = ' ';
else {
if ((c < ' ') || (c >= 0x7f))
c='.';
buff[cpos++] = c;
}
if (cpos > (cpstart+15)) {
printf("%.76s\n", buff);
bpos = bpstart;
cpos = cpstart;
a += 16;
memset(buff, ' ', 80);
k = sprintf(buff + 1, "%.2x", a);
buff[k + 1] = ' ';
}
}
if (cpos > cpstart)
printf("%.76s\n", buff);
}
/* Output to ASCII-Hex bytes to sg_warnings_str (assumed to be initialized);
* 16 bytes per line with an extra space between the 8th and 9th bytes */
static void dStrHexErr(const char* str, int len)
{
const char * p = str;
unsigned char c;
char buff[82];
const int bpstart = 5;
int bpos = bpstart;
int k;
if (len <= 0)
return;
memset(buff, ' ', 80);
buff[80] = '\0';
for (k = 0; k < len; k++) {
c = *p++;
bpos += 3;
if (bpos == (bpstart + (9 * 3)))
bpos++;
sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
buff[bpos + 2] = ' ';
if ((k > 0) && (0 == ((k + 1) % 16))) {
fprintf(sg_warnings_str, "%.60s\n", buff);
bpos = bpstart;
memset(buff, ' ', 80);
}
}
if (bpos > bpstart)
fprintf(sg_warnings_str, "%.60s\n", buff);
return;
}
/* If the number in 'buf' can be decoded or the multiplier is unknown
then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
Main (SI) multipliers supported: K, M, G. */
int sg_get_num(const char * buf)
{
int res, num, n;
unsigned int unum;
char * cp;
char c = 'c';
char c2, c3;
if ((NULL == buf) || ('\0' == buf[0]))
return -1;
if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
res = sscanf(buf + 2, "%x", &unum);
num = (int)unum;
} else
res = sscanf(buf, "%d%c%c%c", &num, &c, &c2, &c3);
if (res < 1)
return -1LL;
else if (1 == res)
return num;
else {
if (res > 2)
c2 = toupper(c2);
if (res > 3)
c3 = toupper(c3);
switch (toupper(c)) {
case 'C':
return num;
case 'W':
return num * 2;
case 'B':
return num * 512;
case 'K':
if (2 == res)
return num * 1024;
if (('B' == c2) || ('D' == c2))
return num * 1000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1024;
return -1;
case 'M':
if (2 == res)
return num * 1048576;
if (('B' == c2) || ('D' == c2))
return num * 1000000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1048576;
return -1;
case 'G':
if (2 == res)
return num * 1073741824;
if (('B' == c2) || ('D' == c2))
return num * 1000000000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1073741824;
return -1;
case 'X':
cp = strchr(buf, 'x');
if (NULL == cp)
cp = strchr(buf, 'X');
if (cp) {
n = sg_get_num(cp + 1);
if (-1 != n)
return num * n;
}
return -1;
default:
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "unrecognized multiplier\n");
return -1;
}
}
}
/* If the number in 'buf' can be decoded or the multiplier is unknown
then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal
multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
Main (SI) multipliers supported: K, M, G, T, P. */
long long sg_get_llnum(const char * buf)
{
int res;
long long num, ll;
unsigned long long unum;
char * cp;
char c = 'c';
char c2, c3;
if ((NULL == buf) || ('\0' == buf[0]))
return -1LL;
if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
res = sscanf(buf + 2, "%llx", &unum);
num = unum;
} else
res = sscanf(buf, "%lld%c%c%c", &num, &c, &c2, &c3);
if (res < 1)
return -1LL;
else if (1 == res)
return num;
else {
if (res > 2)
c2 = toupper(c2);
if (res > 3)
c3 = toupper(c3);
switch (toupper(c)) {
case 'C':
return num;
case 'W':
return num * 2;
case 'B':
return num * 512;
case 'K':
if (2 == res)
return num * 1024;
if (('B' == c2) || ('D' == c2))
return num * 1000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1024;
return -1LL;
case 'M':
if (2 == res)
return num * 1048576;
if (('B' == c2) || ('D' == c2))
return num * 1000000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1048576;
return -1LL;
case 'G':
if (2 == res)
return num * 1073741824;
if (('B' == c2) || ('D' == c2))
return num * 1000000000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1073741824;
return -1LL;
case 'T':
if (2 == res)
return num * 1099511627776LL;
if (('B' == c2) || ('D' == c2))
return num * 1000000000000LL;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1099511627776LL;
return -1LL;
case 'P':
if (2 == res)
return num * 1099511627776LL * 1024;
if (('B' == c2) || ('D' == c2))
return num * 1000000000000LL * 1000;
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1099511627776LL * 1024;
return -1LL;
case 'X':
cp = strchr(buf, 'x');
if (NULL == cp)
cp = strchr(buf, 'X');
if (cp) {
ll = sg_get_llnum(cp + 1);
if (-1LL != ll)
return num * ll;
}
return -1LL;
default:
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
fprintf(sg_warnings_str, "unrecognized multiplier\n");
return -1LL;
}
}
}
const char * sg_lib_version()
{
return version_str;
}