| /* |
| * 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; |
| } |