aboutsummaryrefslogtreecommitdiff
path: root/sg_logs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sg_logs.c')
-rw-r--r--sg_logs.c1299
1 files changed, 868 insertions, 431 deletions
diff --git a/sg_logs.c b/sg_logs.c
index abaa2ad9..88c93168 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -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)