aboutsummaryrefslogtreecommitdiff
path: root/sg_logs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sg_logs.c')
-rw-r--r--sg_logs.c820
1 files changed, 744 insertions, 76 deletions
diff --git a/sg_logs.c b/sg_logs.c
index 88c93168..409a733b 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -22,7 +22,7 @@
*/
-static char * version_str = "0.69 20070129"; /* SPC-4 revision 8 */
+static char * version_str = "0.73 20070419"; /* SPC-4 revision 9 */
#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
@@ -42,41 +42,46 @@ static char * version_str = "0.69 20070129"; /* SPC-4 revision 8 */
#define SELF_TEST_LPAGE 0x10
#define PORT_SPECIFIC_LPAGE 0x18
#define GSP_LPAGE 0x19
+#define TAPE_ALERT_LPAGE 0x2e
#define IE_LPAGE 0x2f
#define NOT_SUBPG_LOG 0x0
#define ALL_SUBPG_LOG 0xff
#define PCB_STR_LEN 128
+#define LOG_SENSE_PROBE_ALLOC_LEN 4
+
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'},
+ {"all", no_argument, 0, 'a'},
+ {"brief", no_argument, 0, 'b'},
+ {"control", required_argument, 0, 'c'},
+ {"help", no_argument, 0, 'h'},
+ {"hex", no_argument, 0, 'H'},
+ {"list", no_argument, 0, 'l'},
+ {"maxlen", required_argument, 0, 'm'},
+ {"name", no_argument, 0, 'n'},
+ {"new", no_argument, 0, 'N'},
+ {"old", no_argument, 0, 'O'},
+ {"page", required_argument, 0, 'p'},
+ {"paramp", required_argument, 0, 'P'},
+ {"pcb", no_argument, 0, 'q'},
+ {"ppc", no_argument, 0, 'Q'},
+ {"raw", no_argument, 0, 'r'},
+ {"reset", no_argument, 0, 'R'},
+ {"sp", no_argument, 0, 's'},
+ {"select", no_argument, 0, 'S'},
+ {"temperature", no_argument, 0, 't'},
+ {"transport", no_argument, 0, 'T'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
};
struct opts_t {
int do_all;
+ int do_brief;
int do_help;
int do_hex;
int do_list;
@@ -102,17 +107,18 @@ struct opts_t {
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] "
+ printf("Usage: sg_logs [--all] [--brief] [--control=PC] [--help] [--hex] "
+ "[--list]\n"
+ " [--maxlen=LEN] [--name] [--page=PG[,SPG]] "
+ "[--paramp=PP] [--pcb]\n"
+ " [--ppc] [--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"
+ " --brief|-b shorten the output of some log pages\n"
" --control=PC|-c PC page control(PC) (default: 1)\n"
" 0: current threshhold, 1: current "
"cumulative\n"
@@ -127,6 +133,7 @@ static void usage()
"subpage names\n"
" --maxlen=LEN|-m LEN max response length (def: 0 "
"-> everything)\n"
+ " when > 1 will request LEN bytes\n"
" --name|-n decode some pages into multiple name=value "
"lines\n"
" --page=PG|-p PG page code (in decimal)\n"
@@ -155,7 +162,7 @@ static void usage()
static void usage_old()
{
- printf("Usage: sg_logs [-a] [-A] [-c=PC] [-h] [-H] [-l] [-L] "
+ printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-h] [-H] [-l] [-L] "
"[-m=LEN] [-n]\n"
" [-p=PG[,SPG]] [-paramp=PP] [-pcb] [-ppc] "
"[-r] [-select]\n"
@@ -163,6 +170,7 @@ static void usage_old()
" where:\n"
" -a fetch and decode all log pages\n"
" -A fetch and decode all log pages and subpages\n"
+ " -b shorten the output of some log pages\n"
" -c=PC page control(PC) (default: 1)\n"
" 0: current threshhold, 1: current cumulative\n"
" 2: default threshhold, 3: default cumulative\n"
@@ -243,7 +251,7 @@ static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "aAc:hHlLm:nNOp:P:qQrRsStTvV",
+ c = getopt_long(argc, argv, "aAbc:hHlLm:nNOp:P:qQrRsStTvV",
long_options, &option_index);
if (c == -1)
break;
@@ -255,6 +263,9 @@ static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
case 'A':
optsp->do_all += 2;
break;
+ case 'b':
+ ++optsp->do_brief;
+ break;
case 'c':
n = sg_get_num(optarg);
if ((n < 0) || (n > 3)) {
@@ -279,7 +290,7 @@ static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
break;
case 'm':
n = sg_get_num(optarg);
- if (n < 0) {
+ if ((n < 0) || (1 == n)) {
fprintf(stderr, "bad argument to '--maxlen='\n");
usage();
return SG_LIB_SYNTAX_ERROR;
@@ -356,7 +367,7 @@ static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
++optsp->do_version;
break;
default:
- fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c);
if (optsp->do_help)
break;
usage();
@@ -399,6 +410,9 @@ static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
case 'A':
optsp->do_all += 2;
break;
+ case 'b':
+ ++optsp->do_brief;
+ break;
case 'h':
case 'H':
++optsp->do_hex;
@@ -568,33 +582,38 @@ static int do_logs(int sg_fd, unsigned char * resp, int mx_resp_len,
int res;
memset(resp, 0, mx_resp_len);
- 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:
- case SG_LIB_CAT_ILLEGAL_REQ:
- case SG_LIB_CAT_UNIT_ATTENTION:
- case SG_LIB_CAT_ABORTED_COMMAND:
- return res;
- default:
- return -1;
+ if (optsp->maxlen > 1)
+ actual_len = mx_resp_len;
+ else {
+ 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, LOG_SENSE_PROBE_ALLOC_LEN,
+ noisy, optsp->do_verbose))) {
+ switch (res) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ return res;
+ default:
+ return -1;
+ }
}
+ actual_len = (resp[2] << 8) + resp[3] + 4;
+ if ((0 == optsp->do_raw) && (optsp->do_verbose > 1)) {
+ fprintf(stderr, " Log sense (find length) response:\n");
+ dStrHex((const char *)resp, LOG_SENSE_PROBE_ALLOC_LEN, 1);
+ fprintf(stderr, " hence calculated response length=%d\n",
+ actual_len);
+ }
+ /* Some HBAs don't like odd transfer lengths */
+ if (actual_len % 2)
+ actual_len += 1;
+ if (actual_len > mx_resp_len)
+ actual_len = mx_resp_len;
}
- actual_len = (resp[2] << 8) + resp[3] + 4;
- 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",
- actual_len);
- }
- /* Some HBAs don't like odd transfer lengths */
- if (actual_len % 2)
- actual_len += 1;
- if (actual_len > mx_resp_len)
- actual_len = mx_resp_len;
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,
@@ -718,7 +737,7 @@ static void show_page_name(int pg_code, int subpg_code,
case 0x16:
printf("%sTape diagnostic (ssc-3)\n", b);
break;
- case 0x2e:
+ case TAPE_ALERT_LPAGE:
printf("%sTapeAlert (ssc-2)\n", b);
break;
default:
@@ -726,6 +745,7 @@ static void show_page_name(int pg_code, int subpg_code,
break;
}
}
+ break;
case 8:
/* medium changer type devices */
{
@@ -733,6 +753,9 @@ static void show_page_name(int pg_code, int subpg_code,
case 0x14:
printf("%sMedia changer statistics (smc-3)\n", b);
break;
+ case 0x15:
+ printf("%sElement statistics (smc-3)\n", b);
+ break;
case 0x2e:
printf("%sTapeAlert (smc-3)\n", b);
break;
@@ -741,6 +764,7 @@ static void show_page_name(int pg_code, int subpg_code,
break;
}
}
+ break;
case 0x12: /* Automation Device interface (ADC) */
{
switch (pg_code) {
@@ -764,12 +788,13 @@ static void show_page_name(int pg_code, int subpg_code,
break;
}
}
-
- default: done = 0; break;
+ break;
+ default:
+ done = 0;
+ break;
}
if (done)
return;
-
printf("%s??\n", b);
}
@@ -1457,14 +1482,15 @@ static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
printf(" phy identifier = %d\n", vcp[1]);
spld_len = vcp[3];
if (spld_len < 44)
- spld_len = 48;
+ spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
else
spld_len += 4;
- t = ((0x70 & vcp[4]) >> 4);
if (optsp->do_name) {
+ t = ((0x70 & vcp[4]) >> 4);
printf(" att_dev_type=%d\n", t);
printf(" att_iport_mask=0x%x\n", vcp[6]);
printf(" att_phy_id=%d\n", vcp[24]);
+ printf(" att_reason=0x%x\n", (vcp[4] & 0xf));
for (n = 0, ull = vcp[16]; n < 8; ++n) {
ull <<= 8; ull |= vcp[16 + n];
}
@@ -1479,11 +1505,13 @@ static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
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);
+ printf(" reason=0x%x\n", (vcp[5] & 0xf0) >> 4);
for (n = 0, ull = vcp[8]; n < 8; ++n) {
ull <<= 8; ull |= vcp[8 + n];
}
printf(" sas_addr=0x%" PRIx64 "\n", ull);
} else {
+ t = ((0x70 & vcp[4]) >> 4);
switch (t) {
case 0: snprintf(s, sz, "no device attached"); break;
case 1: snprintf(s, sz, "end device"); break;
@@ -1492,6 +1520,40 @@ static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
default: snprintf(s, sz, "reserved [%d]", t); break;
}
printf(" attached device type: %s\n", s);
+ t = 0xf & vcp[4];
+ switch (t) {
+ case 0: snprintf(s, sz, "unknown"); break;
+ case 1: snprintf(s, sz, "power on"); break;
+ case 2: snprintf(s, sz, "hard reset"); break;
+ case 3: snprintf(s, sz, "SMP phy control function"); break;
+ case 4: snprintf(s, sz, "loss of dword synchronization"); break;
+ case 5: snprintf(s, sz, "mux mix up"); break;
+ case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
+ break;
+ case 7: snprintf(s, sz, "break timeout timer expired"); break;
+ case 8: snprintf(s, sz, "phy test function stopped"); break;
+ case 9: snprintf(s, sz, "expander device reduced functionality");
+ break;
+ default: snprintf(s, sz, "reserved [0x%x]", t); break;
+ }
+ printf(" attached reason: %s\n", s);
+ t = (vcp[5] & 0xf0) >> 4;
+ switch (t) {
+ case 0: snprintf(s, sz, "unknown"); break;
+ case 1: snprintf(s, sz, "power on"); break;
+ case 2: snprintf(s, sz, "hard reset"); break;
+ case 3: snprintf(s, sz, "SMP phy control function"); break;
+ case 4: snprintf(s, sz, "loss of dword synchronization"); break;
+ case 5: snprintf(s, sz, "mux mix up"); break;
+ case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
+ break;
+ case 7: snprintf(s, sz, "break timeout timer expired"); break;
+ case 8: snprintf(s, sz, "phy test function stopped"); break;
+ case 9: snprintf(s, sz, "expander device reduced functionality");
+ break;
+ default: snprintf(s, sz, "reserved [0x%x]", t); break;
+ }
+ printf(" reason: %s\n", s);
t = (0xf & vcp[5]);
switch (t) {
case 0: snprintf(s, sz, "phy enabled; unknown");
@@ -1505,12 +1567,14 @@ static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
break;
case 5: snprintf(s, sz, "phy enabled; reset in progress");
break;
+ case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
+ break;
case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
default: snprintf(s, sz, "reserved [%d]", t); break;
}
- printf(" negotiated logical link rate: %s\n", s);/* sas2r07 */
+ printf(" negotiated logical link rate: %s\n", s);
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",
@@ -1559,13 +1623,15 @@ static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
}
}
-static int show_protocol_specific_page(unsigned char * resp, int len,
+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;
+ if (optsp->do_name)
+ printf("log_page=0x%x\n", PORT_SPECIFIC_LPAGE);
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
@@ -1582,6 +1648,313 @@ static int show_protocol_specific_page(unsigned char * resp, int len,
return 1;
}
+static int show_stats_perform_page(unsigned char * resp, int len,
+ const struct opts_t * optsp)
+{
+ int k, num, n, param_len, param_code, spf, subpg_code, extra;
+ int pcb, nam;
+ unsigned char * ucp;
+ const char * ccp;
+ unsigned long long ull;
+ char pcb_str[PCB_STR_LEN];
+
+ nam = optsp->do_name;
+ num = len - 4;
+ ucp = resp + 4;
+ spf = !!(resp[0] & 0x40);
+ subpg_code = spf ? resp[1] : 0;
+ if (nam) {
+ printf("log_page=0x%x\n", GSP_LPAGE);
+ if (subpg_code > 0)
+ printf("log_subpage=0x%x\n", subpg_code);
+ }
+ if (subpg_code > 31)
+ return 0;
+ if (0 == subpg_code) { /* General statistics and performance log page */
+ if (num < 0x5c)
+ return 0;
+ for (k = num; k > 0; k -= extra, ucp += extra) {
+ if (k < 3)
+ return 0;
+ param_len = ucp[3];
+ extra = param_len + 4;
+ param_code = (ucp[0] << 8) + ucp[1];
+ pcb = ucp[2];
+ switch (param_code) {
+ case 1: /* Statistics and performance log parameter */
+ ccp = nam ? "parameter_code=1" : "Statistics and performance "
+ "log parameter";
+ printf("%s\n", ccp);
+ for (n = 0, ull = ucp[4]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "read_commands=" : "number of read commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[12]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[12 + n];
+ }
+ ccp = nam ? "write_commands=" : "number of write commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[20]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[20 + n];
+ }
+ ccp = nam ? "lb_received="
+ : "number of logical blocks received = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[28]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[28 + n];
+ }
+ ccp = nam ? "lb_transmitted="
+ : "number of logical blocks transmitted = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[36]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[36 + n];
+ }
+ ccp = nam ? "read_proc_intervals="
+ : "read command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[44]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[44 + n];
+ }
+ ccp = nam ? "write_proc_intervals="
+ : "write command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[52]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[52 + n];
+ }
+ ccp = nam ? "weight_rw_commands=" : "weighted number of "
+ "read commands plus write commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[60]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[60 + n];
+ }
+ ccp = nam ? "weight_rw_processing=" : "weighted read command "
+ "processing plus write command processing = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ case 2: /* Idle time log parameter */
+ ccp = nam ? "parameter_code=2" : "Idle time log parameter";
+ printf("%s\n", ccp);
+ for (n = 0, ull = ucp[4]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "idle_time_intervals=" : "idle time "
+ "intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ case 3: /* Time interval log parameter */
+ ccp = nam ? "parameter_code=3" : "Time interval log "
+ "parameter";
+ printf("%s\n", ccp);
+ for (n = 0, ull = ucp[4]; n < 4; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "time_interval_exp=" : "time interval "
+ "exponent = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[8]; n < 4; ++n) {
+ ull <<= 8; ull |= ucp[8 + n];
+ }
+ ccp = nam ? "time_interval_int=" : "time interval "
+ "integer = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ case 4: /* FUA statistics and performance log parameter */
+ ccp = nam ? "parameter_code=4" : "Force unit access "
+ "statistics and performance log parameter ";
+ printf("%s\n", ccp);
+ for (n = 0, ull = ucp[4]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "read_fua_commands=" : "number of read FUA "
+ "commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[12]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[12 + n];
+ }
+ ccp = nam ? "write_fua_commands=" : "number of write FUA "
+ "commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[20]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[20 + n];
+ }
+ ccp = nam ? "read_fua_nv_commands="
+ : "number of read FUA_NV commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[28]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[28 + n];
+ }
+ ccp = nam ? "write_fua_nv_commands="
+ : "number of write FUA_NV commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[36]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[36 + n];
+ }
+ ccp = nam ? "read_fua_proc_intervals="
+ : "read FUA command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[44]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[44 + n];
+ }
+ ccp = nam ? "write_fua_proc_intervals="
+ : "write FUA command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[52]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[52 + n];
+ }
+ ccp = nam ? "read_fua_nv_proc_intervals="
+ : "read FUA_NV command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[60]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[60 + n];
+ }
+ ccp = nam ? "write_fua_nv_proc_intervals="
+ : "write FUA_NV command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ default:
+ if (nam) {
+ printf("parameter_code=%d\n", param_code);
+ printf(" unknown=1\n");
+ } else
+ fprintf(stderr, "show_performance... unknown parameter "
+ "code %d\n", param_code);
+ if (optsp->do_verbose)
+ dStrHex((const char *)ucp, extra, 1);
+ break;
+ }
+ if ((optsp->do_pcb) && (0 == optsp->do_name)) {
+ get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
+ printf(" <%s>\n", pcb_str);
+ }
+ }
+ } else { /* Group statistics and performance (n) log page */
+ if (num < 0x34)
+ return 0;
+ for (k = num; k > 0; k -= extra, ucp += extra) {
+ if (k < 3)
+ return 0;
+ param_len = ucp[3];
+ extra = param_len + 4;
+ param_code = (ucp[0] << 8) + ucp[1];
+ pcb = ucp[2];
+ switch (param_code) {
+ case 1: /* Group n Statistics and performance log parameter */
+ if (nam)
+ printf("parameter_code=1\n");
+ else
+ printf("Group %d Statistics and performance log "
+ "parameter\n", subpg_code);
+ for (n = 0, ull = ucp[4]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "gn_read_commands=" : "group n number of read "
+ "commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[12]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[12 + n];
+ }
+ ccp = nam ? "gn_write_commands=" : "group n number of write "
+ "commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[20]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[20 + n];
+ }
+ ccp = nam ? "gn_lb_received="
+ : "group n number of logical blocks received = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[28]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[28 + n];
+ }
+ ccp = nam ? "gn_lb_transmitted="
+ : "group n number of logical blocks transmitted = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[36]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[36 + n];
+ }
+ ccp = nam ? "gn_read_proc_intervals="
+ : "group n read command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[44]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[44 + n];
+ }
+ ccp = nam ? "gn_write_proc_intervals="
+ : "group n write command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ case 4: /* Group n FUA statistics and performance log parameter */
+ ccp = nam ? "parameter_code=4" : "Group n force unit access "
+ "statistics and performance log parameter";
+ printf("%s\n", ccp);
+ for (n = 0, ull = ucp[4]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[4 + n];
+ }
+ ccp = nam ? "gn_read_fua_commands="
+ : "group n number of read FUA commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[12]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[12 + n];
+ }
+ ccp = nam ? "gn_write_fua_commands="
+ : "group n number of write FUA commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[20]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[20 + n];
+ }
+ ccp = nam ? "gn_read_fua_nv_commands="
+ : "group n number of read FUA_NV commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[28]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[28 + n];
+ }
+ ccp = nam ? "gn_write_fua_nv_commands="
+ : "group n number of write FUA_NV commands = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[36]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[36 + n];
+ }
+ ccp = nam ? "gn_read_fua_proc_intervals="
+ : "group n read FUA command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[44]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[44 + n];
+ }
+ ccp = nam ? "gn_write_fua_proc_intervals=" : "group n write "
+ "FUA command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[52]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[52 + n];
+ }
+ ccp = nam ? "gn_read_fua_nv_proc_intervals=" : "group n "
+ "read FUA_NV command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ for (n = 0, ull = ucp[60]; n < 8; ++n) {
+ ull <<= 8; ull |= ucp[60 + n];
+ }
+ ccp = nam ? "gn_write_fua_nv_proc_intervals=" : "group n "
+ "write FUA_NV command processing intervals = ";
+ printf(" %s%" PRIu64 "\n", ccp, ull);
+ break;
+ default:
+ if (nam) {
+ printf("parameter_code=%d\n", param_code);
+ printf(" unknown=1\n");
+ } else
+ fprintf(stderr, "show_performance... unknown parameter "
+ "code %d\n", param_code);
+ if (optsp->do_verbose)
+ dStrHex((const char *)ucp, extra, 1);
+ break;
+ }
+ if ((optsp->do_pcb) && (0 == optsp->do_name)) {
+ get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
+ printf(" <%s>\n", pcb_str);
+ }
+ }
+ }
+ return 1;
+}
+
static void show_format_status_page(unsigned char * resp, int len,
int show_pcb)
{
@@ -2046,6 +2419,277 @@ static void show_device_stats_page(unsigned char * resp, int len,
}
}
+static void show_media_stats_page(unsigned char * resp, int len,
+ int show_pcb)
+{
+ int k, j, num, pl, pc, pcb;
+ unsigned char * ucp;
+ unsigned char * xp;
+ unsigned long long ull;
+ char pcb_str[PCB_STR_LEN];
+
+ printf("Media statistics page (smc-3)\n");
+ num = len - 4;
+ ucp = &resp[0] + 4;
+ while (num > 3) {
+ pc = (ucp[0] << 8) | ucp[1];
+ pcb = ucp[2];
+ pl = ucp[3] + 4;
+ k = pl - 4;
+ xp = ucp + 4;
+ if (k > (int)sizeof(ull)) {
+ xp += (k - sizeof(ull));
+ k = sizeof(ull);
+ }
+ ull = 0;
+ for (j = 0; j < k; ++j) {
+ if (j > 0)
+ ull <<= 8;
+ ull |= xp[j];
+ }
+ switch (pc) {
+ case 0:
+ printf(" Number of moves: %" PRIu64 "\n", ull);
+ break;
+ case 1:
+ printf(" Number of picks: %" PRIu64 "\n", ull);
+ break;
+ case 2:
+ printf(" Number of pick retries: %" PRIu64 "\n", ull);
+ break;
+ case 3:
+ printf(" Number of places: %" PRIu64 "\n", ull);
+ break;
+ case 4:
+ printf(" Number of place retries: %" PRIu64 "\n", ull);
+ break;
+ case 5:
+ printf(" Number of volume tags read by volume "
+ "tag reader: %" PRIu64 "\n", ull);
+ break;
+ case 6:
+ printf(" Number of invalid volume tags returned by "
+ "volume tag reader: %" PRIu64 "\n", ull);
+ break;
+ case 7:
+ printf(" Number of library door opens: %" PRIu64 "\n", ull);
+ break;
+ case 8:
+ printf(" Number of import/export door opens: %" PRIu64 "\n",
+ ull);
+ break;
+ case 9:
+ printf(" Number of physical inventory scans: %" PRIu64 "\n",
+ ull);
+ break;
+ case 0xa:
+ printf(" Number of medium transport unrecovered errors: "
+ "%" PRIu64 "\n", ull);
+ break;
+ case 0xb:
+ printf(" Number of medium transport recovered errors: "
+ "%" PRIu64 "\n", ull);
+ break;
+ case 0xc:
+ printf(" Number of medium transport X axis translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0xd:
+ printf(" Number of medium transport X axis translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0xe:
+ printf(" Number of medium transport Y axis translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0xf:
+ printf(" Number of medium transport Y axis translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x10:
+ printf(" Number of medium transport Z axis translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x11:
+ printf(" Number of medium transport Z axis translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x12:
+ printf(" Number of medium transport rotational translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x13:
+ printf(" Number of medium transport rotational translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x14:
+ printf(" Number of medium transport inversion translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x15:
+ printf(" Number of medium transport inversion translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x16:
+ printf(" Number of medium transport auxiliary translation "
+ "unrecovered errors: %" PRIu64 "\n", ull);
+ break;
+ case 0x17:
+ printf(" Number of medium transport auxiliary translation "
+ "recovered errors: %" PRIu64 "\n", ull);
+ break;
+ default:
+ printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n",
+ pc, ull);
+ break;
+ }
+ if (show_pcb) {
+ get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
+ printf("\n <%s>\n", pcb_str);
+ } else
+ printf("\n");
+ num -= pl;
+ ucp += pl;
+ }
+}
+
+static void show_element_stats_page(unsigned char * resp, int len,
+ int show_pcb)
+{
+ int num, pl, pc, pcb;
+ unsigned int v;
+ unsigned char * ucp;
+ char str[PCB_STR_LEN];
+
+ printf("Element statistics page (smc-3) [0x15]\n");
+ num = len - 4;
+ ucp = &resp[0] + 4;
+ while (num > 3) {
+ pc = (ucp[0] << 8) | ucp[1];
+ pcb = ucp[2];
+ pl = ucp[3] + 4;
+ printf(" Element address: %d\n", pc);
+ v = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
+ printf(" Number of places: %u\n", v);
+ v = (ucp[8] << 24) + (ucp[9] << 16) + (ucp[10] << 8) + ucp[11];
+ printf(" Number of place retries: %u\n", v);
+ v = (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) + ucp[15];
+ printf(" Number of picks: %u\n", v);
+ v = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) + ucp[19];
+ printf(" Number of pick retries: %u\n", v);
+ v = (ucp[20] << 24) + (ucp[21] << 16) + (ucp[22] << 8) + ucp[23];
+ printf(" Number of determined volume identifiers: %u\n", v);
+ v = (ucp[24] << 24) + (ucp[25] << 16) + (ucp[26] << 8) + ucp[27];
+ printf(" Number of unreadable volume identifiers: %u\n", v);
+ if (show_pcb) {
+ get_pcb_str(pcb, str, sizeof(str));
+ printf("\n <%s>\n", str);
+ }
+ num -= pl;
+ ucp += pl;
+ }
+}
+
+static char * tape_alert_strs[] = {
+ "<parameter code 0, unknown>", /* 0x0 */
+ "Read warning",
+ "Write warning",
+ "Hard error",
+ "Media",
+ "Read failure",
+ "Write failure",
+ "Media life",
+ "Not data grade", /* 0x8 */
+ "Write protect",
+ "No removal",
+ "Cleaning media",
+ "Unsupported format",
+ "Recoverable mechanical cartridge failure",
+ "Unrecoverable mechanical cartridge failure",
+ "Memory chip in cartridge failure",
+ "Forced eject", /* 0x10 */
+ "Read only format",
+ "Tape directory corrupted on load",
+ "Nearing media life",
+ "Cleaning required",
+ "Cleaning requested",
+ "Expired cleaning media",
+ "Invalid cleaning tape",
+ "Retension requested", /* 0x18 */
+ "Dual port interface error",
+ "Cooling fan failing",
+ "Power supply failure",
+ "Power consumption",
+ "Drive maintenance",
+ "Hardware A",
+ "Hardware B",
+ "Interface", /* 0x20 */
+ "Eject media",
+ "Microcode update fail",
+ "Drive humidity",
+ "Drive temperature",
+ "Drive voltage",
+ "Predictive failure",
+ "Diagnostics required",
+ "Obsolete (28h)", /* 0x28 */
+ "Obsolete (29h)",
+ "Obsolete (2Ah)",
+ "Obsolete (2Bh)",
+ "Obsolete (2Ch)",
+ "Obsolete (2Dh)",
+ "Obsolete (2Eh)",
+ "Reserved (2Fh)",
+ "Reserved (30h)", /* 0x30 */
+ "Reserved (31h)",
+ "Lost statistics",
+ "Tape directory invalid at unload",
+ "Tape system area write failure",
+ "Tape system area read failure",
+ "No start of data",
+ "Loading failure",
+ "Unrecoverable unload failure", /* 0x38 */
+ "Automation interface failure",
+ "Firmware failure",
+ "WORM medium - integrity check failed",
+ "WORM medium - overwrite attempted",
+};
+
+static void show_tape_alert_ssc_page(unsigned char * resp, int len,
+ int show_pcb,
+ const struct opts_t * optsp)
+{
+ int num, pl, pc, pcb, flag;
+ unsigned char * ucp;
+ char str[PCB_STR_LEN];
+
+ /* N.B. the Tape alert log page for smc-3 is different */
+ printf("Tape alert page (ssc-3) [0x2e]\n");
+ num = len - 4;
+ ucp = &resp[0] + 4;
+ while (num > 3) {
+ pc = (ucp[0] << 8) | ucp[1];
+ pcb = ucp[2];
+ pl = ucp[3] + 4;
+ flag = ucp[4] & 1;
+ if (optsp->do_verbose && (0 == optsp->do_brief) && flag)
+ printf(" >>>> ");
+ if ((0 == optsp->do_brief) || optsp->do_verbose || flag) {
+ if (pc < (int)(sizeof(tape_alert_strs) /
+ sizeof(tape_alert_strs[0])))
+ printf(" %s: %d\n", tape_alert_strs[pc], flag);
+ else
+ printf(" Reserved parameter code 0x%x, flag: %d\n", pc,
+ flag);
+ }
+ if (show_pcb) {
+ get_pcb_str(pcb, str, sizeof(str));
+ printf("\n <%s>\n", str);
+ }
+ num -= pl;
+ ucp += pl;
+ }
+}
+
static void show_seagate_cache_page(unsigned char * resp, int len,
int show_pcb)
{
@@ -2219,8 +2863,8 @@ static void show_ascii_page(unsigned char * resp, int len,
case 0xc:
{
switch (inq_dat->peripheral_type) {
- case 1: case 2: case 8:
- /* tape, (printer) and medium changer type devices */
+ case 1: case 2:
+ /* tape and (printer) type devices */
show_sequential_access_page(resp, len, optsp->do_pcb,
optsp->do_verbose);
break;
@@ -2242,10 +2886,13 @@ static void show_ascii_page(unsigned char * resp, int len,
case 0x14:
{
switch (inq_dat->peripheral_type) {
- case 1: case 8: case 0x12:
- /* tape, medium changer and adc type devices */
+ case 1: case 0x12:
+ /* tape and adc type devices */
show_device_stats_page(resp, len, optsp->do_pcb);
break;
+ case 8: /* smc-3 */
+ show_media_stats_page(resp, len, optsp->do_pcb);
+ break;
default:
done = 0;
break;
@@ -2260,6 +2907,9 @@ static void show_ascii_page(unsigned char * resp, int len,
show_background_scan_results_page(resp, len, optsp->do_pcb,
optsp->do_verbose);
break;
+ case 8: /* smc-3 */
+ show_element_stats_page(resp, len, optsp->do_pcb);
+ break;
default:
done = 0;
break;
@@ -2282,6 +2932,21 @@ static void show_ascii_page(unsigned char * resp, int len,
case PORT_SPECIFIC_LPAGE:
done = show_protocol_specific_page(resp, len, optsp);
break;
+ case GSP_LPAGE: /* defined for subpages 0 to 31 inclusive */
+ done = show_stats_perform_page(resp, len, optsp);
+ break;
+ case TAPE_ALERT_LPAGE:
+ {
+ switch (inq_dat->peripheral_type) {
+ case 1: /* ssc only */
+ show_tape_alert_ssc_page(resp, len, optsp->do_pcb, optsp);
+ break;
+ default:
+ done = 0;
+ break;
+ }
+ }
+ break;
case IE_LPAGE:
show_IE_page(resp, len, optsp->do_pcb, 1);
break;
@@ -2305,10 +2970,6 @@ static void show_ascii_page(unsigned char * resp, int len,
/* disk (direct access) type devices */
show_seagate_factory_page(resp, len, optsp->do_pcb);
break;
- case 1: case 2: case 8:
- /* streaming or medium changer devices */
- /* call ssc_device_status_log_page() */
- break;
default:
done = 0;
break;
@@ -2479,6 +3140,8 @@ int main(int argc, char * argv[])
if (0 == opts.do_all) {
if (opts.do_raw)
dStrRaw((const char *)rsp_buff, pg_len + 4);
+ else if (opts.do_hex > 1)
+ dStrHex((const char *)rsp_buff, pg_len + 4, 1);
else if (pg_len > 1) {
if (opts.do_hex) {
if (rsp_buff[0] & 0x40)
@@ -2509,7 +3172,8 @@ int main(int argc, char * argv[])
}
memcpy(parr, rsp_buff + 4, my_len);
for (k = 0; k < my_len; ++k) {
- printf("\n");
+ if (0 == opts.do_raw)
+ printf("\n");
opts.pg_code = parr[k] & 0x3f;
if (spf)
opts.subpg_code = parr[++k];
@@ -2520,11 +3184,15 @@ int main(int argc, char * argv[])
if (0 == res) {
pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
if ((pg_len + 4) > resp_len) {
- printf("Only fetched %d bytes of response, truncate "
- "output\n", resp_len);
+ fprintf(stderr, "Only fetched %d bytes of response, "
+ "truncate output\n", resp_len);
pg_len = resp_len - 4;
}
- if (opts.do_hex) {
+ if (opts.do_raw)
+ dStrRaw((const char *)rsp_buff, pg_len + 4);
+ else if (opts.do_hex > 1)
+ dStrHex((const char *)rsp_buff, pg_len + 4, 1);
+ else 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],