diff options
Diffstat (limited to 'sg_logs.c')
-rw-r--r-- | sg_logs.c | 1299 |
1 files changed, 868 insertions, 431 deletions
@@ -4,12 +4,15 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <getopt.h> +#define __STDC_FORMAT_MACROS 1 +#include <inttypes.h> #include "sg_lib.h" #include "sg_cmds_basic.h" -/* A utility program for the Linux OS SCSI generic ("sg") device driver. -* Copyright (C) 2000-2006 D. Gilbert +/* A utility program originally written for the Linux OS SCSI subsystem. +* Copyright (C) 2000-2007 D. Gilbert * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -19,36 +22,556 @@ */ -static char * version_str = "0.65 20061012"; /* SPC-4 revision 7a */ +static char * version_str = "0.69 20070129"; /* SPC-4 revision 8 */ -#define ME "sg_logs: " - -#define MX_ALLOC_LEN (0xfffe) +#define MX_ALLOC_LEN (0xfffc) #define SHORT_RESP_LEN 128 -#define PG_CODE_ALL 0x0 -#define SUBPG_CODE_ALL 0xff + +#define ALL_PAGE_LPAGE 0x0 +#define BUFF_OVER_UNDER_LPAGE 0x1 +#define WRITE_ERR_LPAGE 0x2 +#define READ_ERR_LPAGE 0x3 +#define READ_REV_ERR_LPAGE 0x4 +#define VERIFY_ERR_LPAGE 0x5 +#define NON_MEDIUM_LPAGE 0x6 +#define LAST_N_ERR_LPAGE 0x7 +#define LAST_N_DEFERRED_LPAGE 0xb +#define TEMPERATURE_LPAGE 0xd +#define START_STOP_LPAGE 0xe +#define APP_CLIENT_LPAGE 0xf +#define SELF_TEST_LPAGE 0x10 +#define PORT_SPECIFIC_LPAGE 0x18 +#define GSP_LPAGE 0x19 +#define IE_LPAGE 0x2f +#define NOT_SUBPG_LOG 0x0 +#define ALL_SUBPG_LOG 0xff #define PCB_STR_LEN 128 +static unsigned char rsp_buff[MX_ALLOC_LEN]; + +static struct option long_options[] = { + {"all", 0, 0, 'a'}, + {"control", 1, 0, 'c'}, + {"help", 0, 0, 'h'}, + {"hex", 0, 0, 'H'}, + {"list", 0, 0, 'l'}, + {"maxlen", 1, 0, 'm'}, + {"name", 0, 0, 'n'}, + {"new", 0, 0, 'N'}, + {"old", 0, 0, 'O'}, + {"page", 1, 0, 'p'}, + {"paramp", 1, 0, 'P'}, + {"pcb", 0, 0, 'q'}, + {"ppc", 0, 0, 'Q'}, + {"raw", 0, 0, 'r'}, + {"reset", 0, 0, 'R'}, + {"sp", 0, 0, 's'}, + {"select", 0, 0, 'S'}, + {"temperature", 0, 0, 't'}, + {"transport", 0, 0, 'T'}, + {"verbose", 0, 0, 'v'}, + {"version", 0, 0, 'V'}, + {0, 0, 0, 0}, +}; + +struct opts_t { + int do_all; + int do_help; + int do_hex; + int do_list; + int do_name; + int do_pcb; + int do_ppc; + int do_raw; + int do_pcreset; + int do_select; + int do_sp; + int do_temperature; + int do_transport; + int do_verbose; + int do_version; + int page_control; + int maxlen; + int pg_code; + int subpg_code; + int paramp; + const char * device_name; + int opt_new; +}; + +static void usage() +{ + printf("Usage: sg_logs [--all] [--control=PC] [--help] [--hex] " + "[--list] [--maxlen=LEN]\n" + " [--name] [--page=PG[,SPG]] [--paramp=PP] [--pcb] " + "[--ppc]\n" + " [--raw] [--reset] [--select] [--sp] " + "[--temperature]\n" + " [--transport] [--verbose] [--version] DEVICE\n" + " where:\n" + " --all|-a fetch and decode all log pages\n" + " use twice to fetch and decode all log pages " + "and subpages\n" + " --control=PC|-c PC page control(PC) (default: 1)\n" + " 0: current threshhold, 1: current " + "cumulative\n" + " 2: default threshhold, 3: default " + "cumulative\n" + " --help|-h print usage message then exit\n" + " --hex|-H output response in hex (default: decode if " + "known)\n" + " --list|-l list supported log page names (equivalent to " + "'-p 0')\n" + " use twice to list supported log page and " + "subpage names\n" + " --maxlen=LEN|-m LEN max response length (def: 0 " + "-> everything)\n" + " --name|-n decode some pages into multiple name=value " + "lines\n" + " --page=PG|-p PG page code (in decimal)\n" + " --page=PG,SPG|-p PG,SPG\n" + " page code plus subpage code (both default " + "to 0)\n" + " --paramp=PP|-P PP parameter pointer (decimal) (def: 0)\n" + " --pcb|-q show parameter control bytes in decoded " + "output\n"); + printf(" --ppc|-Q set the Parameter Pointer Control (PPC) bit " + "(def: 0)\n" + " --raw|-r output response in binary to stdout\n" + " --reset|-R reset log parameters (takes PC and SP into " + "account)\n" + " (uses PCR bit in LOG SELECT)\n" + " --select|-S perform LOG SELECT using SP and PC values\n" + " --sp|-s set the Saving Parameters (SP) bit (def: 0)\n" + " --temperature|-t decode temperature (log page 0xd or " + "0x2f)\n" + " --transport|-T decode transport (protocol specific port " + "0x18) log page\n" + " --verbose|-v increase verbosity\n" + " --version|-V output version string then exit\n\n" + "Performs a SCSI LOG SENSE (or LOG SELECT) command\n"); +} + +static void usage_old() +{ + printf("Usage: sg_logs [-a] [-A] [-c=PC] [-h] [-H] [-l] [-L] " + "[-m=LEN] [-n]\n" + " [-p=PG[,SPG]] [-paramp=PP] [-pcb] [-ppc] " + "[-r] [-select]\n" + " [-sp] [-t] [-T] [-v] [-V] [-?] DEVICE\n" + " where:\n" + " -a fetch and decode all log pages\n" + " -A fetch and decode all log pages and subpages\n" + " -c=PC page control(PC) (default: 1)\n" + " 0: current threshhold, 1: current cumulative\n" + " 2: default threshhold, 3: default cumulative\n" + " -h output in hex (default: decode if known)\n" + " -H output in hex (same as '-h')\n" + " -l list supported log page names (equivalent to " + "'-p=0')\n" + " -L list supported log page and subpages names " + "(equivalent to\n" + " '-p=0,ff')\n" + " -m=LEN max response length (decimal) (def: 0 " + "-> everything)\n" + " -n decode some pages into multiple name=value " + "lines\n" + " -p=PG page code in hex (def: 0)\n" + " -p=PG,SPG both in hex, (defs: 0,0)\n" + " -paramp=PP (in hex) (def: 0)\n" + " -pcb show parameter control bytes in decoded " + "output\n"); + printf(" -ppc set the Parameter Pointer Control (PPC) bit " + "(def: 0)\n" + " -r reset log parameters (takes PC and SP into " + "account)\n" + " (uses PCR bit in LOG SELECT)\n" + " -select perform LOG SELECT using SP and PC values\n" + " -sp set the Saving Parameters (SP) bit (def: 0)\n" + " -t outputs temperature log page (0xd)\n" + " -T outputs transport (protocol specific port) log " + "page (0x18)\n" + " -v increase verbosity\n" + " -V output version string\n" + " -? output this usage message\n\n" + "Performs a SCSI LOG SENSE (or LOG SELECT) command\n"); +} + +static void usage_for(const struct opts_t * optsp) +{ + if (optsp->opt_new) + usage(); + else + usage_old(); +} + +/* Trying to decode multipliers as sg_get_num() [as sg_libs does] would + * only confuse things here, so use this local trimmed version */ +static int get_num(const char * buf) +{ + int res, len, num; + unsigned int unum; + const char * commap; + + if ((NULL == buf) || ('\0' == buf[0])) + return -1; + len = strlen(buf); + commap = strchr(buf + 1, ','); + if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { + res = sscanf(buf + 2, "%x", &unum); + num = unum; + } else if (commap && ('H' == toupper(*(commap - 1)))) { + res = sscanf(buf, "%x", &unum); + num = unum; + } else if ((NULL == commap) && ('H' == toupper(buf[len - 1]))) { + res = sscanf(buf, "%x", &unum); + num = unum; + } else + res = sscanf(buf, "%d", &num); + if (1 == res) + return num; + else + return -1; +} + +static int process_cl_new(struct opts_t * optsp, int argc, char * argv[]) +{ + int c, n, nn; + char * cp; + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "aAc:hHlLm:nNOp:P:qQrRsStTvV", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'a': + ++optsp->do_all; + break; + case 'A': + optsp->do_all += 2; + break; + case 'c': + n = sg_get_num(optarg); + if ((n < 0) || (n > 3)) { + fprintf(stderr, "bad argument to '--control='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->page_control = n; + break; + case 'h': + case '?': + ++optsp->do_help; + break; + case 'H': + ++optsp->do_hex; + break; + case 'l': + ++optsp->do_list; + break; + case 'L': + optsp->do_list += 2; + break; + case 'm': + n = sg_get_num(optarg); + if (n < 0) { + fprintf(stderr, "bad argument to '--maxlen='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->maxlen = n; + break; + case 'n': + ++optsp->do_name; + break; + case 'N': + break; /* ignore */ + case 'O': + optsp->opt_new = 0; + return 0; + case 'p': + cp = strchr(optarg, ','); + n = get_num(optarg); + if ((n < 0) || (n > 63)) { + fprintf(stderr, "Bad argument to '--page='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + if (cp) { + nn = get_num(cp + 1); + if ((nn < 0) || (nn > 255)) { + fprintf(stderr, "Bad second value in argument to " + "'--page='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } else + nn = 0; + optsp->pg_code = n; + optsp->subpg_code = nn; + break; + case 'P': + n = sg_get_num(optarg); + if (n < 0) { + fprintf(stderr, "bad argument to '--paramp='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->paramp = n; + break; + case 'q': + ++optsp->do_pcb; + break; + case 'Q': + ++optsp->do_ppc; + break; + case 'r': + ++optsp->do_raw; + break; + case 'R': + ++optsp->do_pcreset; + ++optsp->do_select; + break; + case 's': + ++optsp->do_sp; + break; + case 'S': + ++optsp->do_select; + break; + case 't': + ++optsp->do_temperature; + break; + case 'T': + ++optsp->do_transport; + break; + case 'v': + ++optsp->do_verbose; + break; + case 'V': + ++optsp->do_version; + break; + default: + fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c); + if (optsp->do_help) + break; + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + if (optind < argc) { + if (NULL == optsp->device_name) { + optsp->device_name = argv[optind]; + ++optind; + } + if (optind < argc) { + for (; optind < argc; ++optind) + fprintf(stderr, "Unexpected extra argument: %s\n", + argv[optind]); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + return 0; +} + +static int process_cl_old(struct opts_t * optsp, int argc, char * argv[]) +{ + int k, jmp_out, plen, num, n; + unsigned int u, uu; + const char * cp; + + for (k = 1; k < argc; ++k) { + cp = argv[k]; + plen = strlen(cp); + if (plen <= 0) + continue; + if ('-' == *cp) { + for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) { + switch (*cp) { + case 'a': + ++optsp->do_all; + break; + case 'A': + optsp->do_all += 2; + break; + case 'h': + case 'H': + ++optsp->do_hex; + break; + case 'l': + ++optsp->do_list; + break; + case 'L': + optsp->do_list += 2; + break; + case 'n': + ++optsp->do_name; + break; + case 'N': + optsp->opt_new = 1; + return 0; + case 'O': + break; + case 'r': + optsp->do_pcreset = 1; + optsp->do_select = 1; + break; + case 't': + ++optsp->do_temperature; + break; + case 'T': + ++optsp->do_transport; + break; + case 'v': + ++optsp->do_verbose; + break; + case 'V': + ++optsp->do_version; + break; + case '?': + ++optsp->do_help; + break; + case '-': + ++cp; + jmp_out = 1; + break; + default: + jmp_out = 1; + break; + } + if (jmp_out) + break; + } + if (plen <= 0) + continue; + if (0 == strncmp("c=", cp, 2)) { + num = sscanf(cp + 2, "%x", &u); + if ((1 != num) || (u > 3)) { + printf("Bad page control after '-c=' option [0..3]\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->page_control = u; + } else if (0 == strncmp("m=", cp, 2)) { + num = sscanf(cp + 2, "%d", &n); + if ((1 != num) || (n < 0) || (n > MX_ALLOC_LEN)) { + printf("Bad maximum response length after '-m=' option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->maxlen = n; + } else if (0 == strncmp("p=", cp, 2)) { + if (NULL == strchr(cp + 2, ',')) { + num = sscanf(cp + 2, "%x", &u); + if ((1 != num) || (u > 63)) { + fprintf(stderr, "Bad page code value after '-p=' " + "option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->pg_code = u; + } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) { + if (uu > 255) { + fprintf(stderr, "Bad sub page code value after '-p=' " + "option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->pg_code = u; + optsp->subpg_code = uu; + } else { + fprintf(stderr, "Bad page code, subpage code sequence " + "after '-p=' option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strncmp("paramp=", cp, 7)) { + num = sscanf(cp + 7, "%x", &u); + if ((1 != num) || (u > 0xffff)) { + printf("Bad parameter pointer after '-paramp=' option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->paramp = u; + } else if (0 == strncmp("pcb", cp, 3)) + optsp->do_pcb = 1; + else if (0 == strncmp("ppc", cp, 3)) + optsp->do_ppc = 1; + else if (0 == strncmp("select", cp, 6)) + optsp->do_select = 1; + else if (0 == strncmp("sp", cp, 2)) + optsp->do_sp = 1; + else if (0 == strncmp("old", cp, 3)) + ; + else if (jmp_out) { + fprintf(stderr, "Unrecognized option: %s\n", cp); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == optsp->device_name) + optsp->device_name = cp; + else { + fprintf(stderr, "too many arguments, got: %s, not expecting: " + "%s\n", optsp->device_name, cp); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } + return 0; +} + +static int process_cl(struct opts_t * optsp, int argc, char * argv[]) +{ + int res; + char * cp; + + cp = getenv("SG3_UTILS_OLD_OPTS"); + if (cp) { + optsp->opt_new = 0; + res = process_cl_old(optsp, argc, argv); + if ((0 == res) && optsp->opt_new) + res = process_cl_new(optsp, argc, argv); + } else { + optsp->opt_new = 1; + res = process_cl_new(optsp, argc, argv); + if ((0 == res) && (0 == optsp->opt_new)) + res = process_cl_old(optsp, argc, argv); + } + return res; +} + +static void dStrRaw(const char* str, int len) +{ + int k; + + for (k = 0 ; k < len; ++k) + printf("%c", str[k]); +} /* Call LOG SENSE twice: the first time ask for 4 byte response to determine actual length of response; then a second time requesting the min(actual_len, mx_resp_len) bytes. If the calculated length for the - second fetch is odd then it is incremented (perhaps should be made modulo 4 - in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for + second fetch is odd then it is incremented (perhaps should be made modulo + 4 in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for log_sense not supported, SG_LIB_CAT_ILLEGAL_REQ for bad field in log sense command, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND and -1 for other errors. */ -static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code, - int subpg_code, int paramp, unsigned char * resp, - int mx_resp_len, int noisy, int verbose) +static int do_logs(int sg_fd, unsigned char * resp, int mx_resp_len, + int noisy, const struct opts_t * optsp) { int actual_len; int res; memset(resp, 0, mx_resp_len); - if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, subpg_code, - paramp, resp, 4, noisy, verbose))) { + if ((res = sg_ll_log_sense(sg_fd, optsp->do_ppc, optsp->do_sp, + optsp->page_control, optsp->pg_code, + optsp->subpg_code, optsp->paramp, + resp, 4, noisy, optsp->do_verbose))) { switch (res) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_INVALID_OP: @@ -61,7 +584,7 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code, } } actual_len = (resp[2] << 8) + resp[3] + 4; - if (verbose > 1) { + if ((0 == optsp->do_raw) && (optsp->do_verbose > 1)) { fprintf(stderr, " Log sense (find length) response:\n"); dStrHex((const char *)resp, 4, 1); fprintf(stderr, " hence calculated response length=%d\n", @@ -72,8 +595,10 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code, actual_len += 1; if (actual_len > mx_resp_len) actual_len = mx_resp_len; - if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, subpg_code, - paramp, resp, actual_len, noisy, verbose))) { + if ((res = sg_ll_log_sense(sg_fd, optsp->do_ppc, optsp->do_sp, + optsp->page_control, optsp->pg_code, + optsp->subpg_code, optsp->paramp, + resp, actual_len, noisy, optsp->do_verbose))) { switch (res) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_INVALID_OP: @@ -85,58 +610,13 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code, return -1; } } - if (verbose > 1) { + if ((0 == optsp->do_raw) && (optsp->do_verbose > 1)) { fprintf(stderr, " Log sense response:\n"); dStrHex((const char *)resp, actual_len, 1); } return 0; } -static void usage() -{ - printf("Usage: sg_logs [-a] [-A] [-c=<page_control] [-h] [-H] [-l] " - "[-L]\n" - " [-m=<max_len>] [-p=<page_number>[," - "<subpage_code>]]\n" - " [-paramp=<parameter_pointer>] [-pcb] [-ppc] " - "[-r] [-select]\n" - " [-sp] [-t] [-T] [-v] [-V] [-?] <scsi_device>\n" - " where:\n" - " -a fetch and decode all log pages\n" - " -A fetch and decode all log pages and subpages\n" - " -c=<page_control> page control(PC) (default: 1)\n" - " 0: current threshhold, 1: current cumulative\n" - " 2: default threshhold, 3: default cumulative\n" - " -h output in hex (default: decode if known)\n" - " -H output in hex (same as '-h')\n" - " -l list supported log page names (equivalent to " - "'-p=0')\n" - " -L list supported log page and subpages names " - "(equivalent to\n" - " '-p=0,ff')\n" - " -m=<max_len> max response length (decimal) (def: 0 " - "-> everything)\n" - " -p=<page_code> page code (in hex)\n" - " -p=<page_code>,<subpage_code> both in hex, (defs: 0)\n" - " -paramp=<parameter_pointer> (in hex) (def: 0)\n" - " -pcb show parameter control bytes (ignored if -h " - "given)\n"); - printf(" -ppc set the Parameter Pointer Control (PPC) bit " - "(def: 0)\n" - " -r reset log parameters (takes PC and SP into " - "account)\n" - " (uses PCR bit in LOG SELECT)\n" - " -select perform LOG SELECT using SP and PC values\n" - " -sp set the Saving Parameters (SP) bit (def: 0)\n" - " -t outputs temperature log page (0xd)\n" - " -T outputs transport (protocol specific port) log " - "page (0x18)\n" - " -v verbose: output cdbs prior to execution\n" - " -V output version string\n" - " -? output this usage message\n\n" - "Performs a SCSI LOG SENSE (or LOG SELECT) command\n"); -} - static void show_page_name(int pg_code, int subpg_code, struct sg_simple_inquiry_resp * inq_dat) { @@ -145,42 +625,48 @@ static void show_page_name(int pg_code, int subpg_code, memset(b, 0, sizeof(b)); /* first process log pages that do not depend on peripheral type */ - if (0 == subpg_code) + if (NOT_SUBPG_LOG == subpg_code) snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code); else snprintf(b, sizeof(b) - 1, " 0x%02x,0x%02x ", pg_code, subpg_code); done = 1; - if ((0 == subpg_code) || (0xff == subpg_code)) { + if ((NOT_SUBPG_LOG == subpg_code) || (ALL_SUBPG_LOG == subpg_code)) { switch (pg_code) { - case 0x0: printf("%sSupported log pages", b); break; - case 0x1: printf("%sBuffer over-run/under-run", b); break; - case 0x2: printf("%sError counters (write)", b); break; - case 0x3: printf("%sError counters (read)", b); break; - case 0x4: printf("%sError counters (read reverse)", b); break; - case 0x5: printf("%sError counters (verify)", b); break; - case 0x6: printf("%sNon-medium errors", b); break; - case 0x7: printf("%sLast n error events", b); break; - case 0xb: printf("%sLast n deferred errors or " + case ALL_PAGE_LPAGE: printf("%sSupported log pages", b); break; + case BUFF_OVER_UNDER_LPAGE: + printf("%sBuffer over-run/under-run", b); + break; + case WRITE_ERR_LPAGE: printf("%sError counters (write)", b); break; + case READ_ERR_LPAGE: printf("%sError counters (read)", b); break; + case READ_REV_ERR_LPAGE: + printf("%sError counters (read reverse)", b); + break; + case VERIFY_ERR_LPAGE: printf("%sError counters (verify)", b); break; + case NON_MEDIUM_LPAGE: printf("%sNon-medium errors", b); break; + case LAST_N_ERR_LPAGE: printf("%sLast n error events", b); break; + case LAST_N_DEFERRED_LPAGE: printf("%sLast n deferred errors or " "asynchronous events", b); break; - case 0xd: printf("%sTemperature", b); break; - case 0xe: printf("%sStart-stop cycle counter", b); break; - case 0xf: printf("%sApplication client", b); break; - case 0x10: printf("%sSelf-test results", b); break; - case 0x18: printf("%sProtocol specific port", b); break; - case 0x19: printf("%sGeneral statistics and performance", b); break; - case 0x2f: printf("%sInformational exceptions (SMART)", b); break; + case TEMPERATURE_LPAGE: printf("%sTemperature", b); break; + case START_STOP_LPAGE: printf("%sStart-stop cycle counter", b); break; + case APP_CLIENT_LPAGE: printf("%sApplication client", b); break; + case SELF_TEST_LPAGE: printf("%sSelf-test results", b); break; + case PORT_SPECIFIC_LPAGE: printf("%sProtocol specific port", b); break; + case GSP_LPAGE: + printf("%sGeneral statistics and performance", b); + break; + case IE_LPAGE: printf("%sInformational exceptions (SMART)", b); break; default : done = 0; break; } if (done) { - if (0xff == subpg_code) + if (ALL_SUBPG_LOG == subpg_code) printf(" and subpages\n"); else printf("\n"); return; } } - if ((0x19 == pg_code) && (subpg_code > 0) && (subpg_code < 32)) { + if ((GSP_LPAGE == pg_code) && (subpg_code > 0) && (subpg_code < 32)) { printf("%sGroup statistics and performance (%d)\n", b, subpg_code); return; } @@ -364,7 +850,7 @@ static void show_buffer_under_overrun_page(unsigned char * resp, int len, ull <<= 8; ull |= xp[j]; } - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); } if (show_pcb) { pcb = ucp[2]; @@ -387,16 +873,16 @@ static void show_error_counter_page(unsigned char * resp, int len, char pcb_str[PCB_STR_LEN]; switch(resp[0] & 0x3f) { - case 2: + case WRITE_ERR_LPAGE: printf("Write error counter page\n"); break; - case 3: + case READ_ERR_LPAGE: printf("Read error counter page\n"); break; - case 4: + case READ_REV_ERR_LPAGE: printf("Read Reverse error counter page\n"); break; - case 5: + case VERIFY_ERR_LPAGE: printf("Verify error counter page\n"); break; default: @@ -433,7 +919,7 @@ static void show_error_counter_page(unsigned char * resp, int len, ull <<= 8; ull |= xp[j]; } - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); if (show_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); @@ -482,7 +968,7 @@ static void show_non_medium_error_page(unsigned char * resp, int len, ull <<= 8; ull |= xp[j]; } - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); if (show_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); @@ -616,7 +1102,7 @@ static void show_self_test_page(unsigned char * resp, int len, int show_pcb) ull <<= 8; ull |= ucp[13]; ull <<= 8; ull |= ucp[14]; ull <<= 8; ull |= ucp[15]; if ((0xffffffffffffffffULL != ull) && (res > 0) && ( res < 0xf)) - printf(" address of first error = 0x%llx\n", ull); + printf(" address of first error = 0x%" PRIx64 "\n", ull); if (ucp[16] & 0xf) printf(" sense key = 0x%x, asc = 0x%x, asq = 0x%x", ucp[16] & 0xf, ucp[17], ucp[18]); @@ -628,7 +1114,7 @@ static void show_self_test_page(unsigned char * resp, int len, int show_pcb) } } -static void show_Temperature_page(unsigned char * resp, int len, +static void show_temperature_page(unsigned char * resp, int len, int show_pcb, int hdr, int show_unknown) { int k, num, extra, pc, pcb; @@ -926,7 +1412,6 @@ static void show_sas_phy_event_info(int peis, unsigned long val, case 0x61: printf(" Received SMP frame count: %lu\n", val); break; - /* case 0x63: */ case 0x63: printf(" Received SMP frame error count: %lu\n", val); break; @@ -935,11 +1420,10 @@ static void show_sas_phy_event_info(int peis, unsigned long val, } } -static int show_protocol_specific_page(unsigned char * resp, int len, - int show_pcb) +static void show_sas_rel_target_port(unsigned char * ucp, int param_len, + const struct opts_t * optsp) { - int k, j, m, num, param_len, nphys, pcb, t, sz, spld_len; - unsigned char * ucp; + int j, m, n, nphys, pcb, t, sz, spld_len; unsigned char * vcp; unsigned long long ull; unsigned long ul; @@ -947,35 +1431,59 @@ static int show_protocol_specific_page(unsigned char * resp, int len, char s[64]; sz = sizeof(s); - num = len - 4; - for (k = 0, ucp = resp + 4; k < num; ) { - pcb = ucp[2]; - param_len = ucp[3] + 4; - /* each phy has a 48 byte descriptor but since param_len is - an 8 bit quantity then only the first 5 phys (of, for example, - a 8 phy wide link) can be represented */ - if (6 != (0xf & ucp[4])) - return 0; /* only decode SAS log page [sas2r05a] */ - if (0 == k) - printf("SAS Protocol Specific page\n"); - printf("relative target port id = %d\n", (ucp[0] << 8) | ucp[1]); - nphys = ucp[7]; + pcb = ucp[2]; + t = (ucp[0] << 8) | ucp[1]; + if (optsp->do_name) + printf("rel_target_port=%d\n", t); + else + printf("relative target port id = %d\n", t); + nphys = ucp[7]; + if (optsp->do_name) + printf(" num_phys=%d\n", nphys); + else { printf(" number of phys = %d", nphys); - if (show_pcb) { + if ((optsp->do_pcb) && (0 == optsp->do_name)) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); + } - for (j = 0, vcp = ucp + 8; j < (param_len - 8); - vcp += spld_len, j += spld_len) { + for (j = 0, vcp = ucp + 8; j < (param_len - 8); + vcp += spld_len, j += spld_len) { + if (optsp->do_name) + printf(" phy_id=%d\n", vcp[1]); + else printf(" phy identifier = %d\n", vcp[1]); - spld_len = vcp[3]; - if (spld_len < 44) - spld_len = 48; - else - spld_len += 4; - t = ((0x70 & vcp[4]) >> 4); + spld_len = vcp[3]; + if (spld_len < 44) + spld_len = 48; + else + spld_len += 4; + t = ((0x70 & vcp[4]) >> 4); + if (optsp->do_name) { + printf(" att_dev_type=%d\n", t); + printf(" att_iport_mask=0x%x\n", vcp[6]); + printf(" att_phy_id=%d\n", vcp[24]); + for (n = 0, ull = vcp[16]; n < 8; ++n) { + ull <<= 8; ull |= vcp[16 + n]; + } + printf(" att_sas_addr=0x%" PRIx64 "\n", ull); + printf(" att_tport_mask=0x%x\n", vcp[7]); + ul = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; + printf(" inv_dwords=%ld\n", ul); + ul = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43]; + printf(" loss_dword_sync=%ld\n", ul); + printf(" neg_log_lrate=%d\n", 0xf & vcp[5]); + ul = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; + printf(" phy_reset_probs=%ld\n", ul); + ul = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; + printf(" running_disparity=%ld\n", ul); + for (n = 0, ull = vcp[8]; n < 8; ++n) { + ull <<= 8; ull |= vcp[8 + n]; + } + printf(" sas_addr=0x%" PRIx64 "\n", ull); + } else { switch (t) { case 0: snprintf(s, sz, "no device attached"); break; case 1: snprintf(s, sz, "end device"); break; @@ -1002,21 +1510,19 @@ static int show_protocol_specific_page(unsigned char * resp, int len, case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break; default: snprintf(s, sz, "reserved [%d]", t); break; } - printf(" negotiated physical link rate: %s\n", s); + printf(" negotiated logical link rate: %s\n", s);/* sas2r07 */ printf(" attached initiator port: ssp=%d stp=%d smp=%d\n", !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2)); printf(" attached target port: ssp=%d stp=%d smp=%d\n", !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2)); - ull = vcp[8]; ull <<= 8; ull |= vcp[9]; ull <<= 8; ull |= vcp[10]; - ull <<= 8; ull |= vcp[11]; ull <<= 8; ull |= vcp[12]; - ull <<= 8; ull |= vcp[13]; ull <<= 8; ull |= vcp[14]; - ull <<= 8; ull |= vcp[15]; - printf(" SAS address = 0x%llx\n", ull); - ull = vcp[16]; ull <<= 8; ull |= vcp[17]; ull <<= 8; ull |= vcp[18]; - ull <<= 8; ull |= vcp[19]; ull <<= 8; ull |= vcp[20]; - ull <<= 8; ull |= vcp[21]; ull <<= 8; ull |= vcp[22]; - ull <<= 8; ull |= vcp[23]; - printf(" attached SAS address = 0x%llx\n", ull); + for (n = 0, ull = vcp[8]; n < 8; ++n) { + ull <<= 8; ull |= vcp[8 + n]; + } + printf(" SAS address = 0x%" PRIx64 "\n", ull); + for (n = 0, ull = vcp[16]; n < 8; ++n) { + ull <<= 8; ull |= vcp[16 + n]; + } + printf(" attached SAS address = 0x%" PRIx64 "\n", ull); printf(" attached phy identifier = %d\n", vcp[24]); ul = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; printf(" Invalid DWORD count = %ld\n", ul); @@ -1026,25 +1532,50 @@ static int show_protocol_specific_page(unsigned char * resp, int len, printf(" Loss of DWORD synchronization = %ld\n", ul); ul = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; printf(" Phy reset problem = %ld\n", ul); - if (spld_len > 51) { - int num_ped, peis; - unsigned char * xcp; - unsigned long pvdt; - - num_ped = vcp[51]; - if (num_ped > 0) - printf(" Phy event descriptors:\n"); - xcp = vcp + 52; - for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { - peis = xcp[3]; - ul = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | - xcp[7]; - pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) | - xcp[11]; - show_sas_phy_event_info(peis, ul, pvdt); - } + } + if (spld_len > 51) { + int num_ped, peis; + unsigned char * xcp; + unsigned long pvdt; + + num_ped = vcp[51]; + if (num_ped > 0) { + if (optsp->do_name) { + printf(" phy_event_desc_num=%d\n", num_ped); + return; /* don't decode at this stage */ + } else + printf(" Phy event descriptors:\n"); + } + xcp = vcp + 52; + for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { + peis = xcp[3]; + ul = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | + xcp[7]; + pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) | + xcp[11]; + show_sas_phy_event_info(peis, ul, pvdt); } } + } +} + +static int show_protocol_specific_page(unsigned char * resp, int len, + const struct opts_t * optsp) +{ + int k, num, param_len; + unsigned char * ucp; + + num = len - 4; + for (k = 0, ucp = resp + 4; k < num; ) { + param_len = ucp[3] + 4; + /* each phy has a 48 byte descriptor but since param_len is + an 8 bit quantity then only the first 5 phys (of, for example, + a 8 phy wide link) can be represented */ + if (6 != (0xf & ucp[4])) + return 0; /* only decode SAS log page [sas2r05a] */ + if ((0 == k) && (0 == optsp->do_name)) + printf("SAS Protocol Specific page\n"); + show_sas_rel_target_port(ucp, param_len, optsp); k += param_len; ucp += param_len; } @@ -1103,7 +1634,7 @@ static void show_format_status_page(unsigned char * resp, int len, if (all_ff) printf(" <not available>"); else - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); if (show_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); @@ -1252,8 +1783,13 @@ static void show_background_scan_results_page(unsigned char * resp, int len, printf("unknown [0x%x] background scan status value\n", j); printf(" Number of background scans performed: %d\n", (ucp[10] << 8) + ucp[11]); +#ifdef SG3_UTILS_MINGW + printf(" Background medium scan progress: %g%%\n", + (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0); +#else printf(" Background medium scan progress: %.2f%%\n", (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0); +#endif break; default: printf(" Medium scan parameter # %d\n", pc); @@ -1332,51 +1868,52 @@ static void show_sequential_access_page(unsigned char * resp, int len, gbytes = ull / 1000000000; switch (pc) { case 0: - printf(" Data bytes received with WRITE commands: %llu GB", - gbytes); + printf(" Data bytes received with WRITE commands: %" PRIu64 + " GB", gbytes); if (verbose) - printf(" [%llu bytes]", ull); + printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 1: - printf(" Data bytes written to media by WRITE commands: %llu " - "GB", gbytes); + printf(" Data bytes written to media by WRITE commands: %" PRIu64 + " GB", gbytes); if (verbose) - printf(" [%llu bytes]", ull); + printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 2: - printf(" Data bytes read from media by READ commands: %llu " - "GB", gbytes); + printf(" Data bytes read from media by READ commands: %" PRIu64 + " GB", gbytes); if (verbose) - printf(" [%llu bytes]", ull); + printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 3: - printf(" Data bytes transferred by READ commands: %llu " - "GB", gbytes); + printf(" Data bytes transferred by READ commands: %" PRIu64 + " GB", gbytes); if (verbose) - printf(" [%llu bytes]", ull); + printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 4: - printf(" Native capacity from BOP to EOD: %llu MB\n", ull); + printf(" Native capacity from BOP to EOD: %" PRIu64 " MB\n", + ull); break; case 5: printf(" Native capacity from BOP to EW of current partition: " - "%llu MB\n", ull); + "%" PRIu64 " MB\n", ull); break; case 6: printf(" Minimum native capacity from EW to EOP of current " - "partition: %llu MB\n", ull); + "partition: %" PRIu64 " MB\n", ull); break; case 7: - printf(" Native capacity from BOP to current position: %llu " - "MB\n", ull); + printf(" Native capacity from BOP to current position: %" + PRIu64 " MB\n", ull); break; case 8: - printf(" Maximum native capacity in device object buffer: %llu " - "MB\n", ull); + printf(" Maximum native capacity in device object buffer: %" + PRIu64 " MB\n", ull); break; case 0x100: if (ull > 0) @@ -1384,14 +1921,14 @@ static void show_sequential_access_page(unsigned char * resp, int len, else printf(" Cleaning action not required (or completed)\n"); if (verbose) - printf(" cleaning value: %llu\n", ull); + printf(" cleaning value: %" PRIu64 "\n", ull); break; default: if (pc >= 0x8000) - printf(" Vendor specific parameter [0x%x] value: %llu\n", - pc, ull); + printf(" Vendor specific parameter [0x%x] value: %" PRIu64 + "\n", pc, ull); else - printf(" Reserved parameter [0x%x] value: %llu\n", + printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); break; } @@ -1436,51 +1973,53 @@ static void show_device_stats_page(unsigned char * resp, int len, } switch (pc) { case 0: - printf(" Lifetime media loads: %llu\n", ull); + printf(" Lifetime media loads: %" PRIu64 "\n", ull); break; case 1: - printf(" Lifetime cleaning operations: %llu\n", ull); + printf(" Lifetime cleaning operations: %" PRIu64 "\n", ull); break; case 2: - printf(" Lifetime power on hours: %llu\n", ull); + printf(" Lifetime power on hours: %" PRIu64 "\n", ull); break; case 3: - printf(" Lifetime media motion (head) hours: %llu\n", ull); + printf(" Lifetime media motion (head) hours: %" PRIu64 "\n", + ull); break; case 4: - printf(" Lifetime metres of tape processed: %llu\n", ull); + printf(" Lifetime metres of tape processed: %" PRIu64 "\n", + ull); break; case 5: printf(" Lifetime media motion (head) hours when " - "incompatible media last loaded: %llu\n", ull); + "incompatible media last loaded: %" PRIu64 "\n", ull); break; case 6: - printf(" Lifetime power on hours when " - "last temperature condition occurred: %llu\n", ull); + printf(" Lifetime power on hours when last temperature " + "condition occurred: %" PRIu64 "\n", ull); break; case 7: printf(" Lifetime power on hours when last power " - "consumption condition occurred: %llu\n", ull); + "consumption condition occurred: %" PRIu64 "\n", ull); break; case 8: printf(" Media motion (head) hours since last successful " - "cleaning operation: %llu\n", ull); + "cleaning operation: %" PRIu64 "\n", ull); break; case 9: printf(" Media motion (head) hours since 2nd to last " - "successful cleaning: %llu\n", ull); + "successful cleaning: %" PRIu64 "\n", ull); break; case 0xa: printf(" Media motion (head) hours since 3rd to last " - "successful cleaning: %llu\n", ull); + "successful cleaning: %" PRIu64 "\n", ull); break; case 0xb: printf(" Lifetime power on hours when last operator " "initiated forced reset\n and/or emergency " - "eject occurred: %llu\n", ull); + "eject occurred: %" PRIu64 "\n", ull); break; default: - printf(" Reserved parameter [0x%x] value: %llu\n", + printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); break; } @@ -1545,7 +2084,7 @@ static void show_seagate_cache_page(unsigned char * resp, int len, ull <<= 8; ull |= xp[j]; } - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); if (show_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); @@ -1598,7 +2137,7 @@ static void show_seagate_factory_page(unsigned char * resp, int len, if (0 == pc) printf(" = %.2f", ((double)ull) / 60.0 ); else - printf(" = %llu", ull); + printf(" = %" PRIu64 "", ull); } if (show_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); @@ -1610,9 +2149,9 @@ static void show_seagate_factory_page(unsigned char * resp, int len, } } -static void show_ascii_page(unsigned char * resp, int len, int show_pcb, +static void show_ascii_page(unsigned char * resp, int len, struct sg_simple_inquiry_resp * inq_dat, - int verbose) + const struct opts_t * optsp) { int k, num, done, pg_code, subpg_code, spf; @@ -1626,7 +2165,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, pg_code = resp[0] & 0x3f; subpg_code = spf ? resp[1] : 0; - if ((0 != pg_code ) && (0xff == subpg_code)) { + if ((ALL_PAGE_LPAGE != pg_code ) && (ALL_SUBPG_LOG == subpg_code)) { printf("Supported subpages for log page=0x%x\n", pg_code); for (k = 0; k < num; k += 2) show_page_name((int)resp[4 + k], (int)resp[4 + k + 1], @@ -1634,7 +2173,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, return; } switch (pg_code) { - case 0: + case ALL_PAGE_LPAGE: if (spf) { printf("Supported log pages and subpages:\n"); for (k = 0; k < num; k += 2) @@ -1646,27 +2185,27 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, show_page_name((int)resp[4 + k], 0, inq_dat); } break; - case 0x1: - show_buffer_under_overrun_page(resp, len, show_pcb); + case BUFF_OVER_UNDER_LPAGE: + show_buffer_under_overrun_page(resp, len, optsp->do_pcb); break; - case 0x2: - case 0x3: - case 0x4: - case 0x5: - show_error_counter_page(resp, len, show_pcb); + case WRITE_ERR_LPAGE: + case READ_ERR_LPAGE: + case READ_REV_ERR_LPAGE: + case VERIFY_ERR_LPAGE: + show_error_counter_page(resp, len, optsp->do_pcb); break; - case 0x6: - show_non_medium_error_page(resp, len, show_pcb); + case NON_MEDIUM_LPAGE: + show_non_medium_error_page(resp, len, optsp->do_pcb); break; - case 0x7: - show_last_n_error_page(resp, len, show_pcb); + case LAST_N_ERR_LPAGE: + show_last_n_error_page(resp, len, optsp->do_pcb); break; case 0x8: { switch (inq_dat->peripheral_type) { case 0: case 4: case 7: case 0xe: /* disk (direct access) type devices */ - show_format_status_page(resp, len, show_pcb); + show_format_status_page(resp, len, optsp->do_pcb); break; default: done = 0; @@ -1674,15 +2213,16 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, } } break; - case 0xb: - show_last_n_deferred_error_page(resp, len, show_pcb); + case LAST_N_DEFERRED_LPAGE: + show_last_n_deferred_error_page(resp, len, optsp->do_pcb); break; case 0xc: { switch (inq_dat->peripheral_type) { case 1: case 2: case 8: /* tape, (printer) and medium changer type devices */ - show_sequential_access_page(resp, len, show_pcb, verbose); + show_sequential_access_page(resp, len, optsp->do_pcb, + optsp->do_verbose); break; default: done = 0; @@ -1690,21 +2230,21 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, } } break; - case 0xd: - show_Temperature_page(resp, len, show_pcb, 1, 1); + case TEMPERATURE_LPAGE: + show_temperature_page(resp, len, optsp->do_pcb, 1, 1); break; - case 0xe: - show_Start_Stop_page(resp, len, show_pcb, verbose); + case START_STOP_LPAGE: + show_Start_Stop_page(resp, len, optsp->do_pcb, optsp->do_verbose); break; - case 0x10: - show_self_test_page(resp, len, show_pcb); + case SELF_TEST_LPAGE: + show_self_test_page(resp, len, optsp->do_pcb); break; case 0x14: { switch (inq_dat->peripheral_type) { case 1: case 8: case 0x12: /* tape, medium changer and adc type devices */ - show_device_stats_page(resp, len, show_pcb); + show_device_stats_page(resp, len, optsp->do_pcb); break; default: done = 0; @@ -1717,8 +2257,8 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, switch (inq_dat->peripheral_type) { case 0: case 4: case 7: case 0xe: /* disk (direct access) type devices */ - show_background_scan_results_page(resp, len, show_pcb, - verbose); + show_background_scan_results_page(resp, len, optsp->do_pcb, + optsp->do_verbose); break; default: done = 0; @@ -1731,7 +2271,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, switch (inq_dat->peripheral_type) { case 0: case 4: case 7: case 0xe: /* disk (direct access) type devices */ - show_non_volatile_cache_page(resp, len, show_pcb); + show_non_volatile_cache_page(resp, len, optsp->do_pcb); break; default: done = 0; @@ -1739,18 +2279,18 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, } } break; - case 0x18: - done = show_protocol_specific_page(resp, len, show_pcb); + case PORT_SPECIFIC_LPAGE: + done = show_protocol_specific_page(resp, len, optsp); break; - case 0x2f: - show_IE_page(resp, len, show_pcb, 1); + case IE_LPAGE: + show_IE_page(resp, len, optsp->do_pcb, 1); break; case 0x37: { switch (inq_dat->peripheral_type) { case 0: case 4: case 7: case 0xe: /* disk (direct access) type devices */ - show_seagate_cache_page(resp, len, show_pcb); + show_seagate_cache_page(resp, len, optsp->do_pcb); break; default: done = 0; @@ -1763,7 +2303,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, switch (inq_dat->peripheral_type) { case 0: case 4: case 7: case 0xe: /* disk (direct access) type devices */ - show_seagate_factory_page(resp, len, show_pcb); + show_seagate_factory_page(resp, len, optsp->do_pcb); break; case 1: case 2: case 8: /* streaming or medium changer devices */ @@ -1793,20 +2333,36 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb, } static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len, - int verbose) + struct opts_t * optsp) { + int len; int res = 0; - res = do_logs(sg_fd, 0, 0, 1, 0xd, 0, 0, resp, max_len, 0, verbose); - if (0 == res) - show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0, 0); - else if (SG_LIB_CAT_NOT_READY == res) + optsp->pg_code = TEMPERATURE_LPAGE; + optsp->subpg_code = NOT_SUBPG_LOG; + res = do_logs(sg_fd, resp, max_len, 0, optsp); + if (0 == res) { + len = (resp[2] << 8) + resp[3] + 4; + if (optsp->do_raw) + dStrRaw((const char *)resp, len); + else if (optsp->do_hex) + dStrHex((const char *)resp, len, 1); + else + show_temperature_page(resp, len, optsp->do_pcb, 0, 0); + }else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "Device not ready\n"); else { - res = do_logs(sg_fd, 0, 0, 1, 0x2f, 0, 0, resp, max_len, 0, verbose); - if (0 == res) - show_IE_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0); - else + optsp->pg_code = IE_LPAGE; + res = do_logs(sg_fd, resp, max_len, 0, optsp); + if (0 == res) { + len = (resp[2] << 8) + resp[3] + 4; + if (optsp->do_raw) + dStrRaw((const char *)resp, len); + else if (optsp->do_hex) + dStrHex((const char *)resp, len, 1); + else + show_IE_page(resp, len, 0, 0); + } else fprintf(stderr, "Unable to find temperature in either log page " "(temperature or IE)\n"); } @@ -1814,199 +2370,80 @@ static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len, return (res >= 0) ? res : SG_LIB_CAT_OTHER; } -static unsigned char rsp_buff[MX_ALLOC_LEN]; int main(int argc, char * argv[]) { - int sg_fd, k, num, pg_len, res, plen, jmp_out, resp_len; - const char * file_name = 0; - const char * cp; - unsigned int u, uu; - int pg_code = 0; - int subpg_code = 0; - int subpg_code_set = 0; - int pc = 1; /* N.B. some disks only give data for current cumulative */ - int paramp = 0; - int do_list = 0; - int do_pcb = 0; - int do_ppc = 0; - int do_select = 0; - int do_sp = 0; - int do_hex = 0; - int do_all = 0; - int do_temp = 0; - int do_pcreset = 0; - int do_verbose = 0; - int max_len = 0; + int sg_fd, k, pg_len, res, resp_len; int ret = 0; struct sg_simple_inquiry_resp inq_out; + struct opts_t opts; + memset(&opts, 0, sizeof(opts)); memset(rsp_buff, 0, sizeof(rsp_buff)); - for (k = 1; k < argc; ++k) { - cp = argv[k]; - plen = strlen(cp); - if (plen <= 0) - continue; - if ('-' == *cp) { - for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) { - switch (*cp) { - case 'a': - do_all = 1; - break; - case 'A': - do_all = 2; - break; - case 'h': - case 'H': - do_hex = 1; - break; - case 'l': - do_list = 1; - break; - case 'L': - do_list = 2; - break; - case 'r': - do_pcreset = 1; - do_select = 1; - break; - case 't': - do_temp = 1; - break; - case 'T': - pg_code = 0x18; - break; - case 'v': - ++do_verbose; - break; - case 'V': - fprintf(stderr, "Version string: %s\n", version_str); - exit(0); - case '?': - usage(); - return SG_LIB_SYNTAX_ERROR; - case '-': - ++cp; - jmp_out = 1; - break; - default: - jmp_out = 1; - break; - } - if (jmp_out) - break; - } - if (plen <= 0) - continue; - if (0 == strncmp("c=", cp, 2)) { - num = sscanf(cp + 2, "%x", &u); - if ((1 != num) || (u > 3)) { - printf("Bad page control after '-c=' option [0..3]\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - pc = u; - } else if (0 == strncmp("m=", cp, 2)) { - num = sscanf(cp + 2, "%d", &max_len); - if ((1 != num) || (max_len < 0) || (max_len > MX_ALLOC_LEN)) { - printf("Bad maximum response length after '-m=' option\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - } else if (0 == strncmp("p=", cp, 2)) { - if (NULL == strchr(cp + 2, ',')) { - num = sscanf(cp + 2, "%x", &u); - if ((1 != num) || (u > 63)) { - fprintf(stderr, "Bad page code value after '-p=' " - "option\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - pg_code = u; - } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) { - if (uu > 255) { - fprintf(stderr, "Bad sub page code value after '-p=' " - "option\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - pg_code = u; - subpg_code = uu; - subpg_code_set = 1; - } else { - fprintf(stderr, "Bad page code, subpage code sequence " - "after '-p=' option\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - } else if (0 == strncmp("paramp=", cp, 7)) { - num = sscanf(cp + 7, "%x", &u); - if ((1 != num) || (u > 0xffff)) { - printf("Bad parameter pointer after '-paramp=' option\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - paramp = u; - } else if (0 == strncmp("pcb", cp, 3)) - do_pcb = 1; - else if (0 == strncmp("ppc", cp, 3)) - do_ppc = 1; - else if (0 == strncmp("select", cp, 6)) - do_select = 1; - else if (0 == strncmp("sp", cp, 2)) - do_sp = 1; - else if (jmp_out) { - fprintf(stderr, "Unrecognized option: %s\n", cp); - usage(); - return SG_LIB_SYNTAX_ERROR; - } - } else if (0 == file_name) - file_name = cp; - else { - fprintf(stderr, "too many arguments, got: %s, not expecting: " - "%s\n", file_name, cp); - usage(); - return SG_LIB_SYNTAX_ERROR; - } + /* N.B. some disks only give data for current cumulative */ + opts.page_control = 1; + res = process_cl(&opts, argc, argv); + if (res) + return SG_LIB_SYNTAX_ERROR; + if (opts.do_help) { + usage_for(&opts); + return 0; + } + if (opts.do_version) { + fprintf(stderr, "Version string: %s\n", version_str); + return 0; } - - if (0 == file_name) { - fprintf(stderr, "No <scsi_device> argument given. Try '-?' for " - "usage.\n"); + + if (NULL == opts.device_name) { + fprintf(stderr, "No DEVICE argument given\n"); + usage_for(&opts); return SG_LIB_SYNTAX_ERROR; } - if ((sg_fd = sg_cmds_open_device(file_name, 0 /* rw */, - do_verbose)) < 0) { - if ((sg_fd = sg_cmds_open_device(file_name, 1 /* r0 */, - do_verbose)) < 0) { - fprintf(stderr, ME "error opening file: %s: %s \n", file_name, - safe_strerror(-sg_fd)); + if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /* rw */, + opts.do_verbose)) < 0) { + if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* r0 */, + opts.do_verbose)) < 0) { + fprintf(stderr, "error opening file: %s: %s \n", + opts.device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } } - if (do_list || do_all) { - pg_code = PG_CODE_ALL; - if ((do_list > 1) || (do_all > 1)) - subpg_code = SUBPG_CODE_ALL; + if (opts.do_list || opts.do_all) { + opts.pg_code = ALL_PAGE_LPAGE; + if ((opts.do_list > 1) || (opts.do_all > 1)) + opts.subpg_code = ALL_SUBPG_LOG; + } + if (opts.do_transport) { + if ((opts.pg_code > 0) || (opts.subpg_code > 0) || + opts.do_temperature) { + fprintf(stderr, "'-T' should not be mixed with options " + "implying other pages\n"); + return SG_LIB_FILE_ERROR; + } + opts.pg_code = PORT_SPECIFIC_LPAGE; } pg_len = 0; - if (sg_simple_inquiry(sg_fd, &inq_out, 1, do_verbose)) { - fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n", - file_name); - sg_cmds_close_device(sg_fd); - return SG_LIB_CAT_OTHER; + if (0 == opts.do_raw) { + if (sg_simple_inquiry(sg_fd, &inq_out, 1, opts.do_verbose)) { + fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n", + opts.device_name); + sg_cmds_close_device(sg_fd); + return SG_LIB_CAT_OTHER; + } else if ((0 == opts.do_hex) && (0 == opts.do_name)) + printf(" %.8s %.16s %.4s\n", inq_out.vendor, + inq_out.product, inq_out.revision); } else - printf(" %.8s %.16s %.4s\n", inq_out.vendor, inq_out.product, - inq_out.revision); + memset(&inq_out, 0, sizeof(inq_out)); - if (1 == do_temp) - return fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, do_verbose); + if (1 == opts.do_temperature) + return fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, &opts); - if (do_select) { - k = sg_ll_log_select(sg_fd, !!(do_pcreset), do_sp, pc, pg_code, - subpg_code, NULL, 0, 1, do_verbose); + if (opts.do_select) { + k = sg_ll_log_select(sg_fd, !!(opts.do_pcreset), opts.do_sp, + opts.page_control, opts.pg_code, opts.subpg_code, + NULL, 0, 1, opts.do_verbose); if (k) { if (SG_LIB_CAT_NOT_READY == k) fprintf(stderr, "log_select: device not ready\n"); @@ -2019,9 +2456,8 @@ int main(int argc, char * argv[]) } return (k >= 0) ? k : SG_LIB_CAT_OTHER; } - resp_len = (max_len > 0) ? max_len : MX_ALLOC_LEN; - res = do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, subpg_code, paramp, - rsp_buff, resp_len, 1, do_verbose); + resp_len = (opts.maxlen > 0) ? opts.maxlen : MX_ALLOC_LEN; + res = do_logs(sg_fd, rsp_buff, resp_len, 1, &opts); if (0 == res) { pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; if ((pg_len + 4) > resp_len) { @@ -2040,24 +2476,27 @@ int main(int argc, char * argv[]) fprintf(stderr, "log_sense: unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "log_sense: aborted command\n"); - if ((pg_len > 1) && (0 == do_all)) { - if (do_hex) { - if (rsp_buff[0] & 0x40) - printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, " - "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1], - !!(rsp_buff[0] & 0x80), pg_len); + if (0 == opts.do_all) { + if (opts.do_raw) + dStrRaw((const char *)rsp_buff, pg_len + 4); + else if (pg_len > 1) { + if (opts.do_hex) { + if (rsp_buff[0] & 0x40) + printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, " + "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1], + !!(rsp_buff[0] & 0x80), pg_len); + else + printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n", + rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len); + dStrHex((const char *)rsp_buff, pg_len + 4, 1); + } else - printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n", - rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len); - dStrHex((const char *)rsp_buff, pg_len + 4, 1); + show_ascii_page(rsp_buff, pg_len + 4, &inq_out, &opts); } - else - show_ascii_page(rsp_buff, pg_len + 4, do_pcb, &inq_out, - do_verbose); } ret = res; - if (do_all && (pg_len > 1)) { + if (opts.do_all && (pg_len > 1)) { int my_len = pg_len; int spf; unsigned char parr[1024]; @@ -2071,14 +2510,13 @@ int main(int argc, char * argv[]) memcpy(parr, rsp_buff + 4, my_len); for (k = 0; k < my_len; ++k) { printf("\n"); - pg_code = parr[k] & 0x3f; + opts.pg_code = parr[k] & 0x3f; if (spf) - subpg_code = parr[++k]; + opts.subpg_code = parr[++k]; else - subpg_code = 0; + opts.subpg_code = NOT_SUBPG_LOG; - res = do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, subpg_code, - paramp, rsp_buff, resp_len, 1, do_verbose); + res = do_logs(sg_fd, rsp_buff, resp_len, 1, &opts); if (0 == res) { pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; if ((pg_len + 4) > resp_len) { @@ -2086,7 +2524,7 @@ int main(int argc, char * argv[]) "output\n", resp_len); pg_len = resp_len - 4; } - if (do_hex) { + if (opts.do_hex) { if (rsp_buff[0] & 0x40) printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, page_" "len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1], @@ -2098,16 +2536,15 @@ int main(int argc, char * argv[]) dStrHex((const char *)rsp_buff, pg_len + 4, 1); } else - show_ascii_page(rsp_buff, pg_len + 4, do_pcb, &inq_out, - do_verbose); + show_ascii_page(rsp_buff, pg_len + 4, &inq_out, &opts); } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "log_sense: page=0x%x,0x%x not supported\n", - pg_code, subpg_code); + opts.pg_code, opts.subpg_code); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "log_sense: device not ready\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "log_sense: field in cdb illegal " - "[page=0x%x,0x%x]\n", pg_code, subpg_code); + "[page=0x%x,0x%x]\n", opts.pg_code, opts.subpg_code); else if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "log_sense: unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) |