diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2016-03-14 01:10:45 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2016-03-14 01:10:45 +0000 |
commit | b798bfc6514f9dfff87da36456fe15d7e1b53e6f (patch) | |
tree | ff2a7c90888a1f7d1ab21c92f3d3c6af05f1a8fb /src | |
parent | 70cacd5629374ab1a56c4d372aac986f1de09207 (diff) | |
download | sg3_utils-b798bfc6514f9dfff87da36456fe15d7e1b53e6f.tar.gz |
sg_logs: fix volume statistics; add Requested recovery, TapeAlert response, and Service buffer information; sg_opcode: add '--enumerate' and '--pdt=' options; sg_lib: add SSC maintenance in/out sa names
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@685 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r-- | src/sg_logs.c | 296 | ||||
-rw-r--r-- | src/sg_opcodes.c | 267 | ||||
-rw-r--r-- | src/sg_read_attr.c | 4 | ||||
-rw-r--r-- | src/sg_vpd.c | 67 |
4 files changed, 465 insertions, 169 deletions
diff --git a/src/sg_logs.c b/src/sg_logs.c index 74bea70d..ba5f82f8 100644 --- a/src/sg_logs.c +++ b/src/sg_logs.c @@ -31,7 +31,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.40 20160303"; /* spc5r08 + sbc4r10 */ +static const char * version_str = "1.40 20160313"; /* spc5r08 + sbc4r10 */ #define MX_ALLOC_LEN (0xfffc) #define SHORT_RESP_LEN 128 @@ -101,6 +101,7 @@ static struct option long_options[] = { {"paramp", required_argument, 0, 'P'}, {"pcb", no_argument, 0, 'q'}, {"ppc", no_argument, 0, 'Q'}, + {"pdt", required_argument, 0, 'D'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'X'}, {"reset", no_argument, 0, 'R'}, @@ -142,7 +143,7 @@ struct opts_t { int paramp; int opt_new; int no_inq; - int dev_pdt; + int dev_pdt; /* from device or --pdt=DT */ const char * device_name; const char * in_fn; const char * pg_arg; @@ -201,6 +202,10 @@ static bool show_media_stats_page(const uint8_t * resp, int len, const struct opts_t * op); static bool show_dt_device_status_page(const uint8_t * resp, int len, const struct opts_t * op); +static bool show_tapealert_response_page(const uint8_t * resp, int len, + const struct opts_t * op); +static bool show_requested_recovery_page(const uint8_t * resp, int len, + const struct opts_t * op); static bool show_background_scan_results_page(const uint8_t * resp, int len, const struct opts_t * op); static bool show_pending_defects_page(const uint8_t * resp, int len, @@ -211,6 +216,8 @@ static bool show_lps_misalignment_page(const uint8_t * resp, int len, const struct opts_t * op); static bool show_element_stats_page(const uint8_t * resp, int len, const struct opts_t * op); +static bool show_service_buffer_info_page(const uint8_t * resp, int len, + const struct opts_t * op); static bool show_ata_pt_results_page(const uint8_t * resp, int len, const struct opts_t * op); static bool show_tape_diag_data_page(const uint8_t * resp, int len, @@ -295,9 +302,9 @@ static struct log_elem log_arr[] = { {0x11, 0, 0, PDT_TAPE, 0, "DT Device status", "dtds", show_dt_device_status_page}, /* 0x11, 0x0 SSC,ADC */ {0x12, 0, 0, PDT_TAPE, 0, "Tape alert response", "tar", - NULL}, /* 0x12, 0x0 SSC,ADC */ + show_tapealert_response_page}, /* 0x12, 0x0 SSC,ADC */ {0x13, 0, 0, PDT_TAPE, 0, "Requested recovery", "rr", - NULL}, /* 0x13, 0x0 SSC,ADC */ + show_requested_recovery_page}, /* 0x13, 0x0 SSC,ADC */ {0x14, 0, 0, PDT_TAPE, 0, "Device statistics", "ds", show_device_stats_page}, /* 0x14, 0x0 SSC,ADC */ {0x14, 0, 0, PDT_MCHANGER, 0, "Media changer statistics", "mcs", @@ -313,7 +320,7 @@ static struct log_elem log_arr[] = { {0x15, 0, 0, PDT_MCHANGER, 0, "Element statistics", "els", show_element_stats_page}, /* 0x15, 0x0 SMC */ {0x15, 0, 0, PDT_ADC, 0, "Service buffers information", "sbi", - NULL}, /* 0x15, 0x0 ADC */ + show_service_buffer_info_page}, /* 0x15, 0x0 ADC */ {BACKGROUND_SCAN_LPAGE, PENDING_DEFECTS_SUBPG, 0, 0, 0, "Pending defects", "pd", show_pending_defects_page}, /* 0x15, 0x1 SBC */ {SAT_ATA_RESULTS_LPAGE, 0, 0, 0, 0, "ATA pass-through results", "aptr", @@ -404,11 +411,11 @@ usage(int hval) "[--in=FN]\n" " [--list] [--no_inq] [--maxlen=LEN] [--name] " "[--page=PG]\n" - " [--paramp=PP] [--pcb] [--ppc] [--raw] " - "[--readonly]\n" - " [--reset] [--select] [--sp] [--temperature] " - "[--transport]\n" - " [--verbose] [--version] DEVICE\n" + " [--paramp=PP] [--pcb] [--ppc] [--pdt=DT] " + "[--raw]\n" + " [--readonly] [--reset] [--select] [--sp] " + "[--temperature]\n" + " [--transport] [--verbose] [--version] DEVICE\n" " where the main options are:\n" " --All|-A fetch and decode all log pages and " "subpages\n" @@ -479,6 +486,9 @@ usage(int hval) "output\n" " --ppc|-Q set the Parameter Pointer Control (PPC) bit " "(def: 0)\n" + " --pdt=DT|-D DT DT is peripheral device type to use with " + "'--in=FN'\n" + " or when '--no_inq' is used\n" " --readonly|-X open DEVICE read-only (def: first " "read-write then if\n" " fails try open again read-only)\n" @@ -491,17 +501,19 @@ usage(int hval) " --version|-V output version string then exit\n\n" "If DEVICE and --select are given, a LOG SELECT command will be " "issued. If\nDEVICE is not given and '--in=FN' is given then FN " - "will decoded as if it\nwere a log page. Pages defined in SPC " - "are common to all device types.\n"); + "will decoded as if it\nwere a log page. The contents of FN " + "typically generated by a prior\n" + "'sg_logs -HHH ...' invocation.\nPages defined in SPC are common " + "to all device types.\n"); } } static void usage_old() { - printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-e] [-E] [-f=FL] [-h] " - "[-H]\n" - " [-i=FN] [-l] [-L] [-m=LEN] [-n] [-p=PG] " + printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-E] [-f=FL] " + "[-h]\n" + " [-H] [-i=FN] [-l] [-L] [-m=LEN] [-n] [-p=PG] " "[-paramp=PP]\n" " [-pcb] [-ppc] [-r] [-select] [-sp] [-t] [-T] " "[-v] [-V]\n" @@ -711,7 +723,7 @@ process_cl_new(struct opts_t * op, int argc, char * argv[]) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "aAbc:eEf:hHi:lLm:nNOp:P:qQrRsStTvVxX", + c = getopt_long(argc, argv, "aAbc:D:eEf:hHi:lLm:nNOp:P:qQrRsStTvVxX", long_options, &option_index); if (c == -1) break; @@ -735,6 +747,14 @@ process_cl_new(struct opts_t * op, int argc, char * argv[]) } op->page_control = n; break; + case 'D': + n = sg_get_num(optarg); + if ((n < 0) || (n > 31)) { + pr2serr("bad argument to '--pdt='\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->dev_pdt = n; + break; case 'e': ++op->do_enumerate; break; @@ -962,6 +982,14 @@ process_cl_old(struct opts_t * op, int argc, char * argv[]) return SG_LIB_SYNTAX_ERROR; } op->page_control = u; + } else if (0 == strncmp("D=", cp, 2)) { + n = sg_get_num(cp + 2); + if ((n < 0) || (n > 31)) { + pr2serr("Bad argument after '-D=' option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + op->dev_pdt = n; } else if (0 == strncmp("f=", cp, 2)) { n = sg_get_num(cp + 2); if ((n < 0) || (n > 0xffff)) { @@ -4210,6 +4238,162 @@ skip: return true; } +/* TapeAlert response [0x12] (adc,ssc) */ +static bool +show_tapealert_response_page(const uint8_t * resp, int len, + const struct opts_t * op) +{ + int num, pl, pc, pcb, k, mod, div; + const uint8_t * ucp; + char str[PCB_STR_LEN]; + + if (op->verbose || ((0 == op->do_raw) && (0 == op->do_hex))) + printf("TapeAlert response page (ssc-3, adc-3) [0x12]\n"); + num = len - 4; + ucp = &resp[0] + 4; + while (num > 3) { + pc = sg_get_unaligned_be16(ucp + 0); + pcb = ucp[2]; + pl = ucp[3] + 4; + if (op->filter_given) { + if (pc != op->filter) + goto skip; + if (op->do_raw) { + dStrRaw((const char *)ucp, pl); + break; + } else if (op->do_hex) { + dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); + break; + } + } + switch (pc) { + case 0x0: + if (pl < 12) { + + } + for (k = 1; k < 0x41; ++k) { + mod = ((k - 1) % 8); + div = (k - 1) / 8; + if (0 == mod) { + if (div > 0) + printf("\n"); + printf(" Flag%02Xh: %d", k, !! (ucp[4 + div] & 0x80)); + } else + printf(" %02Xh: %d", k, + !! (ucp[4 + div] & (1 << (7 - mod)))); + } + printf("\n"); + break; + default: + if (pc <= 0x8000) { + printf(" Reserved [parameter_code=0x%x]:\n", pc); + dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); + } else { + printf(" Vendor specific [parameter_code=0x%x]:\n", pc); + dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); + } + break; + } + if (op->do_pcb) { + get_pcb_str(pcb, str, sizeof(str)); + printf(" <%s>\n", str); + } + if (op->filter_given) + break; +skip: + num -= pl; + ucp += pl; + } + return true; +} + +#define NUM_REQ_REC_ARR_ELEMS 16 +static const char * req_rec_arr[NUM_REQ_REC_ARR_ELEMS] = { + "Recovery not requested", + "Recovery requested, no recovery procedure defined", + "Instruct operator to push volume", + "Instruct operator to remove and re-insert volume", + "Issue UNLOAD command. Instruct operator to remove and re-insert volume", + "Instruct operator to power cycle target device", + "Issue LOAD command", + "Issue UNLOAD command", + "Issue LOGICAL UNIT RESET task management function", /* 0x8 */ + "No recovery procedure defined. Contact service organization", + "Issue UNLOAD command. Instruct operator to remove and quarantine " + "volume", + "Instruct operator to not insert a volume. Contact service organization", + "Issue UNLOAD command. Instruct operator to remove volume. Contact " + "service organization", + "Request creation of target device error log", + "Retrieve a target device error log", + "Modify configuration to all microcode update and instruct operator to " + "re-insert volume", /* 0xf */ +}; + +/* Requested recovery [0x13] (ssc) */ +static bool +show_requested_recovery_page(const uint8_t * resp, int len, + const struct opts_t * op) +{ + int num, pl, pc, pcb, j, k; + const uint8_t * ucp; + char str[PCB_STR_LEN]; + + if (op->verbose || ((0 == op->do_raw) && (0 == op->do_hex))) + printf("Requested recovery page (ssc-3) [0x13]\n"); + num = len - 4; + ucp = &resp[0] + 4; + while (num > 3) { + pc = sg_get_unaligned_be16(ucp + 0); + pcb = ucp[2]; + pl = ucp[3] + 4; + if (op->filter_given) { + if (pc != op->filter) + goto skip; + if (op->do_raw) { + dStrRaw((const char *)ucp, pl); + break; + } else if (op->do_hex) { + dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); + break; + } + } + switch (pc) { + case 0x0: + printf(" Recovery procedures:\n"); + for (k = 4; k < pl; ++ k) { + j = ucp[k]; + if (j < NUM_REQ_REC_ARR_ELEMS) + printf(" %s\n", req_rec_arr[j]); + else if (j < 0x80) + printf(" Reserved [0x%x]\n", j); + else + printf(" Vendor specific [0x%x]\n", j); + } + break; + default: + if (pc <= 0x8000) { + printf(" Reserved [parameter_code=0x%x]:\n", pc); + dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); + } else { + printf(" Vendor specific [parameter_code=0x%x]:\n", pc); + dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); + } + break; + } + if (op->do_pcb) { + get_pcb_str(pcb, str, sizeof(str)); + printf(" <%s>\n", str); + } + if (op->filter_given) + break; +skip: + num -= pl; + ucp += pl; + } + return true; +} + /* SAT_ATA_RESULTS_LPAGE (SAT-2) [0x16] */ static bool show_ata_pt_results_page(const uint8_t * resp, int len, @@ -4240,23 +4424,28 @@ show_ata_pt_results_page(const uint8_t * resp, int len, } } if ((pc < 0xf) && (pl > 17)) { - int extend, sector_count; + int extend, count; - dp = ucp + 4; printf(" Log_index=0x%x (parameter_code=0x%x)\n", pc + 1, pc); + dp = ucp + 4; /* dp is start of ATA Return descriptor + * which is 14 bytes long */ extend = dp[2] & 1; - sector_count = dp[5] + (extend ? (dp[4] << 8) : 0); - printf(" extend=%d error=0x%x sector_count=0x%x\n", extend, - dp[3], sector_count); + count = dp[5] + (extend ? (dp[4] << 8) : 0); + printf(" extend=%d error=0x%x count=0x%x\n", extend, + dp[3], count); if (extend) printf(" lba=0x%02x%02x%02x%02x%02x%02x\n", dp[10], dp[8], dp[6], dp[11], dp[9], dp[7]); else printf(" lba=0x%02x%02x%02x\n", dp[11], dp[9], dp[7]); printf(" device=0x%x status=0x%x\n", dp[12], dp[13]); - } else { + } else if (pl > 17) { printf(" Reserved [parameter_code=0x%x]:\n", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); + } else { + printf(" short parameter length: %d [parameter_code=0x%x]:\n", + pl, pc); + dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); @@ -4622,6 +4811,63 @@ skip: return true; } +/* Service buffer information [0x15] (adc) */ +static bool +show_service_buffer_info_page(const uint8_t * resp, int len, + const struct opts_t * op) +{ + int num, pl, pc, pcb; + const uint8_t * ucp; + char str[PCB_STR_LEN]; + + if (op->verbose || ((0 == op->do_raw) && (0 == op->do_hex))) + printf("Service buffer information page (adc-3) [0x15]\n"); + num = len - 4; + ucp = &resp[0] + 4; + while (num > 3) { + pc = sg_get_unaligned_be16(ucp + 0); + pcb = ucp[2]; + pl = ucp[3] + 4; + if (op->filter_given) { + if (pc != op->filter) + goto skip; + if (op->do_raw) { + dStrRaw((const char *)ucp, pl); + break; + } else if (op->do_hex) { + dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); + break; + } + } + if (pc < 0x100) { + printf(" Service buffer identifier: 0x%x\n", pc); + printf(" Buffer id: 0x%x, tu=%d, nmp=%d, nmm=%d, " + "offline=%d\n", ucp[4], !!(0x10 & ucp[5]), + !!(0x8 & ucp[5]), !!(0x4 & ucp[5]), !!(0x2 & ucp[5])); + printf(" pd=%d, code_set: %s, Service buffer title:\n", + !!(0x1 & ucp[5]), sg_get_desig_code_set_str(0xf & ucp[6])); + printf(" %*s\n", pl - 8, ucp + 8); + } else if (pc < 0x8000) { + printf(" parameter_code=0x%x, Reserved, parameter in hex:\n", + pc); + dStrHex((const char *)ucp + 4, pl - 4, 0); + } else { + printf(" parameter_code=0x%x, Vendor-specific, parameter in " + "hex:\n", pc); + dStrHex((const char *)ucp + 4, pl - 4, 0); + } + if (op->do_pcb) { + get_pcb_str(pcb, str, sizeof(str)); + printf(" <%s>\n", str); + } + if (op->filter_given) + break; +skip: + num -= pl; + ucp += pl; + } + return true; +} /* Sequential access device page [0xc] for tape */ static bool @@ -5055,7 +5301,7 @@ skip: return true; } -/* 0x15 for media changer */ +/* Element statistics page, 0x15 for SMC */ static bool show_element_stats_page(const uint8_t * resp, int len, const struct opts_t * op) @@ -6039,9 +6285,7 @@ main(int argc, char * argv[]) n); n = in_len - k; } - pdt = (op->filter_given && (op->filter >= 0)) ? - op->filter : -1; - op->dev_pdt = pdt; + pdt = op->dev_pdt; lep = pg_subpg_pdt_search(pg_code, subpg_code, pdt); if (lep) { if (lep->show_pagep) diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c index 1b42f172..eddf65a3 100644 --- a/src/sg_opcodes.c +++ b/src/sg_opcodes.c @@ -1,5 +1,5 @@ /* A utility program originally written for the Linux OS SCSI subsystem. - * Copyright (C) 2004-2015 D. Gilbert + * Copyright (C) 2004-2016 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) @@ -15,6 +15,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <getopt.h> #ifdef HAVE_CONFIG_H @@ -28,7 +29,7 @@ #include "sg_pt.h" -static const char * version_str = "0.45 20151219"; /* spc5r07 */ +static const char * version_str = "0.46 20160313"; /* spc5r08 */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ @@ -44,7 +45,7 @@ static const char * version_str = "0.45 20151219"; /* spc5r07 */ #define NAME_BUFF_SZ 128 -static int peri_type = 0; /* ugly but not easy to pass to alpha compare */ +static int peri_dtype = -1; /* ugly but not easy to pass to alpha compare */ static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode, int rq_servact, void * resp, int mx_resp_len, int noisy, @@ -56,6 +57,7 @@ static int do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len, static struct option long_options[] = { {"alpha", 0, 0, 'a'}, {"compact", 0, 0, 'c'}, + {"enumerate", 0, 0, 'e'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"mask", 0, 0, 'm'}, @@ -77,16 +79,17 @@ static struct option long_options[] = { struct opts_t { int do_alpha; int do_compact; + int do_enumerate; int do_help; int do_hex; int no_inquiry; int do_mask; - int do_opcode; + int opcode; int do_raw; int do_rctd; int do_repd; - int do_servact; - int do_verbose; + int servact; + int verbose; int do_version; int do_unsorted; int do_taskman; @@ -98,17 +101,20 @@ struct opts_t { static void usage() { - pr2serr("Usage: sg_opcodes [--alpha] [--compact] [--help] [--hex] " - "[--mask]\n" - " [--no-inquiry] [--opcode=OP[,SA]] [--raw] " - "[--rctd]\n" - " [--repd] [--sa=SA] [--tmf] [--unsorted] " - "[--verbose]\n" - " [--version] DEVICE\n" + pr2serr("Usage: sg_opcodes [--alpha] [--compact] [--enumerate] " + "[--help] [--hex]\n" + " [--mask] [--no-inquiry] [--opcode=OP[,SA]] " + "[--pdt=DT]\n" + " [--raw] [--rctd] [--repd] [--sa=SA] [--tmf] " + "[--unsorted]\n" + " [--verbose] [--version] DEVICE\n" " where:\n" " --alpha|-a output list of operation codes sorted " "alphabetically\n" " --compact|-c more compact output\n" + " --enumerate|-e use '--opcode=' and '--pdt=' to look up " + "name,\n" + " ignore DEVICE\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex\n" " --mask|-m and show cdb usage data (a mask) when " @@ -120,6 +126,9 @@ usage() "(SA)\n" " (decimal, each prefix with '0x' for " "hex)\n" + " --pdt=DT|-p DT give peripheral device type for " + "'--no-inquiry'\n" + " '--enumerate'\n" " --raw|-r output response in binary to stdout\n" " --rctd|-R set RCTD (return command timeout " "descriptor) bit\n" @@ -141,17 +150,22 @@ usage() static void usage_old() { - pr2serr("Usage: sg_opcodes [-a] [-c] [-H] [-m] [-n] [-o=OP] [-q] [-r] " - "[-R] [-s=SA]\n" - " [-t] [-u] [-v] [-V] DEVICE\n" + pr2serr("Usage: sg_opcodes [-a] [-c] [-e] [-H] [-m] [-n] [-o=OP] " + "[-p=DT] [-q]\n" + " [-r] [-R] [-s=SA] [-t] [-u] [-v] [-V] " + "DEVICE\n" " where:\n" " -a output list of operation codes sorted " "alphabetically\n" " -c more compact output\n" + " -e use '--opcode=' and '--pdt=' to look up name, " + "ignore DEVICE\n" " -H print response in hex\n" " -m and show cdb usage data (a mask) when all listed\n" " -n don't output INQUIRY information\n" " -o=OP first byte of command to query (in hex)\n" + " -p=DT alternate source of pdt (normally obtained from " + "inquiry)\n" " -q set REPD bit for tmf_s\n" " -r output response in binary to stdout\n" " -R set RCTD (return command timeout " @@ -167,7 +181,7 @@ usage_old() } static int -process_cl_new(struct opts_t * optsp, int argc, char * argv[]) +process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c, n; char * cp; @@ -176,30 +190,33 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[]) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "achHmnNo:OqrRs:tuvV", long_options, + c = getopt_long(argc, argv, "acehHmnNo:Op:qrRs:tuvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': - ++optsp->do_alpha; + ++op->do_alpha; break; case 'c': - ++optsp->do_compact; + ++op->do_compact; + break; + case 'e': + ++op->do_enumerate; break; case 'h': case '?': - ++optsp->do_help; + ++op->do_help; break; case 'H': - ++optsp->do_hex; + ++op->do_hex; break; case 'm': - ++optsp->do_mask; + ++op->do_mask; break; case 'n': - ++optsp->no_inquiry; + ++op->no_inquiry; break; case 'N': break; /* ignore */ @@ -217,14 +234,14 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[]) pr2serr("bad OP argument to '--opcode'\n"); return SG_LIB_SYNTAX_ERROR; } - optsp->do_opcode = n; + op->opcode = n; n = sg_get_num(cp + 1); if ((n < 0) || (n > 0xffff)) { pr2serr("bad SA argument to '--opcode'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } - optsp->do_servact = n; + op->servact = n; } else { n = sg_get_num(optarg); if ((n < 0) || (n > 255)) { @@ -232,20 +249,32 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[]) usage(); return SG_LIB_SYNTAX_ERROR; } - optsp->do_opcode = n; + op->opcode = n; } break; case 'O': - optsp->opt_new = 0; + op->opt_new = 0; return 0; + case 'p': + n = -2; + if (isdigit(optarg[0])) + n = sg_get_num(optarg); + else if ((2 == strlen(optarg)) && (0 == strcmp("-1", optarg))) + n = -1; + if ((n < -1) || (n > 0x1f)) { + pr2serr("bad argument to '--pdt=DT', expect -1 to 31\n"); + return SG_LIB_SYNTAX_ERROR; + } + peri_dtype = n; + break; case 'q': - ++optsp->do_repd; + ++op->do_repd; break; case 'r': - ++optsp->do_raw; + ++op->do_raw; break; case 'R': - ++optsp->do_rctd; + ++op->do_rctd; break; case 's': n = sg_get_num(optarg); @@ -254,31 +283,31 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[]) usage(); return SG_LIB_SYNTAX_ERROR; } - optsp->do_servact = n; + op->servact = n; break; case 't': - ++optsp->do_taskman; + ++op->do_taskman; break; case 'u': - ++optsp->do_unsorted; + ++op->do_unsorted; break; case 'v': - ++optsp->do_verbose; + ++op->verbose; break; case 'V': - ++optsp->do_version; + ++op->do_version; break; default: pr2serr("unrecognised option code %c [0x%x]\n", c, c); - if (optsp->do_help) + if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { - if (NULL == optsp->device_name) { - optsp->device_name = argv[optind]; + if (NULL == op->device_name) { + op->device_name = argv[optind]; ++optind; } if (optind < argc) { @@ -292,7 +321,7 @@ process_cl_new(struct opts_t * optsp, int argc, char * argv[]) } static int -process_cl_old(struct opts_t * optsp, int argc, char * argv[]) +process_cl_old(struct opts_t * op, int argc, char * argv[]) { int k, jmp_out, plen, n, num; const char * cp; @@ -306,46 +335,49 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[]) for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) { switch (*cp) { case 'a': - ++optsp->do_alpha; + ++op->do_alpha; break; case 'c': - ++optsp->do_compact; + ++op->do_compact; + break; + case 'e': + ++op->do_enumerate; break; case 'H': - ++optsp->do_hex; + ++op->do_hex; break; case 'm': - ++optsp->do_mask; + ++op->do_mask; break; case 'n': - ++optsp->no_inquiry; + ++op->no_inquiry; break; case 'N': - optsp->opt_new = 1; + op->opt_new = 1; return 0; case 'O': break; case 'q': - ++optsp->do_repd; + ++op->do_repd; break; case 'R': - ++optsp->do_rctd; + ++op->do_rctd; break; case 't': - ++optsp->do_taskman; + ++op->do_taskman; break; case 'u': - ++optsp->do_unsorted; + ++op->do_unsorted; break; case 'v': - ++optsp->do_verbose; + ++op->verbose; break; case 'V': - ++optsp->do_version; + ++op->do_version; break; case 'h': case '?': - ++optsp->do_help; + ++op->do_help; break; default: jmp_out = 1; @@ -363,7 +395,15 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[]) usage_old(); return SG_LIB_SYNTAX_ERROR; } - optsp->do_opcode = n; + op->opcode = n; + } else if (0 == strncmp("p=", cp, 2)) { + num = sscanf(cp + 2, "%d", &n); + if ((1 != num) || (n > 0x1f) || (n < -1)) { + pr2serr("Bad number after 'p=' option, expect -1 to " + "31\n"); + return SG_LIB_SYNTAX_ERROR; + } + peri_dtype = n; } else if (0 == strncmp("s=", cp, 2)) { num = sscanf(cp + 2, "%x", (unsigned int *)&n); if (1 != num) { @@ -371,7 +411,7 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[]) usage_old(); return SG_LIB_SYNTAX_ERROR; } - optsp->do_servact = n; + op->servact = n; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { @@ -379,11 +419,11 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[]) usage_old(); return SG_LIB_SYNTAX_ERROR; } - } else if (NULL == optsp->device_name) - optsp->device_name = cp; + } else if (NULL == op->device_name) + op->device_name = cp; else { pr2serr("too many arguments, got: %s, not expecting: %s\n", - optsp->device_name, cp); + op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } @@ -392,22 +432,22 @@ process_cl_old(struct opts_t * optsp, int argc, char * argv[]) } static int -process_cl(struct opts_t * optsp, int argc, char * argv[]) +process_cl(struct opts_t * op, 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); + op->opt_new = 0; + res = process_cl_old(op, argc, argv); + if ((0 == res) && op->opt_new) + res = process_cl_new(op, 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); + op->opt_new = 1; + res = process_cl_new(op, argc, argv); + if ((0 == res) && (0 == op->opt_new)) + res = process_cl_old(op, argc, argv); } return res; } @@ -472,13 +512,13 @@ opcode_alpha_compare(const void * left, const void * right) if (ll[5] & 1) l_serv_act = sg_get_unaligned_be16(ll + 2); l_name_buff[0] = '\0'; - sg_get_opcode_sa_name(l_opc, l_serv_act, peri_type, + sg_get_opcode_sa_name(l_opc, l_serv_act, peri_dtype, NAME_BUFF_SZ, l_name_buff); r_opc = rr[0]; if (rr[5] & 1) r_serv_act = sg_get_unaligned_be16(rr + 2); r_name_buff[0] = '\0'; - sg_get_opcode_sa_name(r_opc, r_serv_act, peri_type, + sg_get_opcode_sa_name(r_opc, r_serv_act, peri_dtype, NAME_BUFF_SZ, r_name_buff); return strncmp(l_name_buff, r_name_buff, NAME_BUFF_SZ); } @@ -552,14 +592,14 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, serv_act = 0; if (sa_v) { serv_act = sg_get_unaligned_be16(ucp + 2); - sg_get_opcode_sa_name(opcode, serv_act, peri_type, NAME_BUFF_SZ, + sg_get_opcode_sa_name(opcode, serv_act, peri_dtype, NAME_BUFF_SZ, name_buff); if (op->do_compact) snprintf(sa_buff, sizeof(sa_buff), "%-4x", serv_act); else snprintf(sa_buff, sizeof(sa_buff), "%4x", serv_act); } else { - sg_get_opcode_name(opcode, peri_type, NAME_BUFF_SZ, name_buff); + sg_get_opcode_name(opcode, peri_dtype, NAME_BUFF_SZ, name_buff); memset(sa_buff, ' ', sizeof(sa_buff)); } if (op->do_rctd) { @@ -602,7 +642,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, memset(b, 0, sizeof(b)); res = do_rsoc(sg_fd, 0, (sa_v ? 2 : 1), opcode, serv_act, - b, sizeof(b), 1, op->do_verbose); + b, sizeof(b), 1, op->verbose); if (0 == res) { cdb_sz = sg_get_unaligned_be16(b + 2); if ((cdb_sz > 0) && (cdb_sz <= 80)) { @@ -664,13 +704,13 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, int v = 0; - printf("\n Opcode=0x%.2x", op->do_opcode); + printf("\n Opcode=0x%.2x", op->opcode); if (rep_opts > 1) - printf(" Service_action=0x%.4x", op->do_servact); + printf(" Service_action=0x%.4x", op->servact); printf("\n"); - sg_get_opcode_sa_name(((op->do_opcode > 0) ? op->do_opcode : 0), - ((op->do_servact > 0) ? op->do_servact : 0), - peri_type, NAME_BUFF_SZ, name_buff); + sg_get_opcode_sa_name(((op->opcode > 0) ? op->opcode : 0), + ((op->servact > 0) ? op->servact : 0), + peri_dtype, NAME_BUFF_SZ, name_buff); printf(" Command_name: %s\n", name_buff); switch((int)(rsoc_buff[1] & 7)) { case 0: @@ -725,8 +765,8 @@ main(int argc, char * argv[]) op = &opts; memset(op, 0, sizeof(opts)); - op->do_opcode = -1; - op->do_servact = -1; + op->opcode = -1; + op->servact = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; @@ -742,7 +782,7 @@ main(int argc, char * argv[]) return 0; } - if (NULL == op->device_name) { + if ((NULL == op->device_name) && (0 == op->do_enumerate)) { pr2serr("No DEVICE argument given\n"); if (op->opt_new) usage(); @@ -750,7 +790,7 @@ main(int argc, char * argv[]) usage_old(); return SG_LIB_SYNTAX_ERROR; } - if ((-1 != op->do_servact) && (-1 == op->do_opcode)) { + if ((-1 != op->servact) && (-1 == op->opcode)) { pr2serr("When '-s' is chosen, so must '-o' be chosen\n"); if (op->opt_new) usage(); @@ -761,32 +801,59 @@ main(int argc, char * argv[]) if (op->do_unsorted && op->do_alpha) pr2serr("warning: unsorted ('-u') and alpha ('-a') options chosen, " "ignoring alpha\n"); - if (op->do_taskman && ((-1 != op->do_opcode) || op->do_alpha || + if (op->do_taskman && ((-1 != op->opcode) || op->do_alpha || op->do_unsorted)) { pr2serr("warning: task management functions ('-t') chosen so alpha " "('-a'),\n unsorted ('-u') and opcode ('-o') " "options ignored\n"); } + if (op->do_enumerate) { + char name_buff[NAME_BUFF_SZ]; + + if (op->do_taskman) + printf("enumerate not supported with task management " + "functions\n"); + else { /* SCSI command */ + if (op->opcode < 0) + op->opcode = 0; + if (op->servact < 0) + op->servact = 0; + if (peri_dtype < 0) + peri_dtype = 0; + printf("SCSI command:"); + if (op->verbose) + printf(" [opcode=0x%x, sa=0x%x, pdt=0x%x]\n", op->opcode, + op->servact, peri_dtype); + else + printf("\n"); + sg_get_opcode_sa_name(op->opcode, op->servact, peri_dtype, + NAME_BUFF_SZ, name_buff); + printf(" %s\n", name_buff); + } + return 0; + } op_name = op->do_taskman ? "Report supported task management functions" : "Report supported operation codes"; - if (op->do_opcode < 0) { + if (op->opcode < 0) { if ((sg_fd = scsi_pt_open_device(op->device_name, 1 /* RO */, - op->do_verbose)) < 0) { + op->verbose)) < 0) { pr2serr("sg_opcodes: error opening file (ro): %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } - if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, op->do_verbose)) { - peri_type = inq_resp.peripheral_type; + if (op->no_inquiry && (peri_dtype >= 0)) + ; + else if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, op->verbose)) { + peri_dtype = inq_resp.peripheral_type; if (! (op->do_raw || op->no_inquiry)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); - cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); + cp = sg_get_pdt_str(peri_dtype, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else - printf(" Peripheral device type: 0x%x\n", peri_type); + printf(" Peripheral device type: 0x%x\n", peri_dtype); } } else { pr2serr("sg_opcodes: %s doesn't respond to a SCSI INQUIRY\n", @@ -801,23 +868,23 @@ main(int argc, char * argv[]) } if ((sg_fd = scsi_pt_open_device(op->device_name, 0 /* RW */, - op->do_verbose)) < 0) { + op->verbose)) < 0) { pr2serr("sg_opcodes: error opening file (rw): %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } - if (op->do_opcode >= 0) - rep_opts = ((op->do_servact >= 0) ? 2 : 1); + if (op->opcode >= 0) + rep_opts = ((op->servact >= 0) ? 2 : 1); memset(rsoc_buff, 0, sizeof(rsoc_buff)); if (op->do_taskman) res = do_rstmf(sg_fd, op->do_repd, rsoc_buff, - (op->do_repd ? 16 : 4), 1, op->do_verbose); + (op->do_repd ? 16 : 4), 1, op->verbose); else - res = do_rsoc(sg_fd, op->do_rctd, rep_opts, op->do_opcode, - op->do_servact, rsoc_buff, sizeof(rsoc_buff), 1, - op->do_verbose); + res = do_rsoc(sg_fd, op->do_rctd, rep_opts, op->opcode, + op->servact, rsoc_buff, sizeof(rsoc_buff), 1, + op->verbose); if (res) { - sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); + sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("%s: %s\n", op_name, b); goto err_out; } @@ -844,9 +911,9 @@ main(int argc, char * argv[]) if (rsoc_buff[0] & 0x4) printf(" Query task\n"); if (rsoc_buff[0] & 0x2) - printf(" Target reset\n"); + printf(" Target reset (obsolete)\n"); if (rsoc_buff[0] & 0x1) - printf(" Wakeup\n"); + printf(" Wakeup (obsolete)\n"); if (rsoc_buff[1] & 0x4) printf(" Query asynchronous event\n"); if (rsoc_buff[1] & 0x2) @@ -871,9 +938,9 @@ main(int argc, char * argv[]) printf(" QAETS=%d\n", !!(rsoc_buff[7] & 0x4)); printf(" QTSTS=%d\n", !!(rsoc_buff[7] & 0x2)); printf(" ITNRTS=%d\n", !!(rsoc_buff[7] & 0x1)); - printf(" tmf long timeout: %d (100 ms units)\n", + printf(" tmf long timeout: %u (100 ms units)\n", sg_get_unaligned_be32(rsoc_buff + 8)); - printf(" tmf short timeout: %d (100 ms units)\n", + printf(" tmf short timeout: %u (100 ms units)\n", sg_get_unaligned_be32(rsoc_buff + 12)); } } else if (0 == rep_opts) { /* list all supported operation codes */ diff --git a/src/sg_read_attr.c b/src/sg_read_attr.c index bd02a493..5083674b 100644 --- a/src/sg_read_attr.c +++ b/src/sg_read_attr.c @@ -34,7 +34,7 @@ * and decodes the response. Based on spc5r08.pdf */ -static const char * version_str = "1.00 20160207"; +static const char * version_str = "1.01 20160311"; #define MAX_RATTR_BUFF_LEN (1024 * 1024) #define DEF_RATTR_BUFF_LEN (1024 * 8) @@ -189,7 +189,7 @@ usage() pr2serr("Usage: sg_read_attr [--cache] [--element=EA] [--enumerate] " "[--filter=FL]\n" " [--first=FAI] [--help] [--hex] [--in=FN] " - "[--lvn-LVN]\n" + "[--lvn=LVN]\n" " [--maxlen=LEN] [--partition=PN] [--quiet] " "[--raw]\n" " [--readonly] [--sa=SA] [--verbose] " diff --git a/src/sg_vpd.c b/src/sg_vpd.c index 831b0aaf..3a3cb68b 100644 --- a/src/sg_vpd.c +++ b/src/sg_vpd.c @@ -37,7 +37,7 @@ */ -static const char * version_str = "1.14 20160217"; /* spc5r08 + sbc4r10 */ +static const char * version_str = "1.15 20160312"; /* spc5r08 + sbc4r10 */ /* These structures are duplicates of those of the same name in @@ -2166,6 +2166,10 @@ decode_3party_copy_vpd(unsigned char * buff, int len, int do_hex, int verbose) pr2serr("Third-party Copy VPD page length too short=%d\n", len); return; } + if (3 == do_hex) { + dStrHex((const char *)buff, len, -1); + return; + } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { @@ -2318,8 +2322,8 @@ decode_proto_lu_vpd(unsigned char * buff, int len, int do_hex) int k, bump, rel_port, desc_len, proto; unsigned char * ucp; - if (1 == do_hex) { - dStrHex((const char *)buff, len, 0); + if ((1 == do_hex) || (do_hex > 2)) { + dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (len < 4) { @@ -2369,8 +2373,8 @@ decode_proto_port_vpd(unsigned char * buff, int len, int do_hex) unsigned char * ucp; unsigned char * pidp; - if (1 == do_hex) { - dStrHex((const char *)buff, len, 0); + if ((1 == do_hex) || (do_hex > 2)) { + dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (len < 4) { @@ -2586,7 +2590,7 @@ decode_b1_vpd(unsigned char * buff, int len, int do_hex, int pdt) } } -/* VPD_LB_PROVISIONING */ +/* VPD_LB_PROVISIONING 0xb2 */ static int decode_block_lb_prov_vpd(unsigned char * b, int len, const struct opts_t * op) { @@ -2727,7 +2731,7 @@ decode_block_dev_char_ext_vpd(unsigned char * b, int len) printf(" Utilization A: %u\n", sg_get_unaligned_be32(b + 12)); } -/* VPD_LB_PROTECTION (SSC) [added in ssc5r02a] */ +/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */ static void decode_lb_protection_vpd(unsigned char * buff, int len, int do_hex) { @@ -2758,46 +2762,27 @@ decode_lb_protection_vpd(unsigned char * buff, int len, int do_hex) } } -/* VPD_TA_SUPPORTED */ +/* VPD_TA_SUPPORTED 0xb2 */ static int decode_tapealert_supported_vpd(unsigned char * b, int len) { + int k, mod, div; + if (len < 12) { pr2serr("TapeAlert supported flags length too short=%d\n", len); return SG_LIB_CAT_MALFORMED; } - printf(" Flag01h: %d 02h: %d 03h: %d 04h: %d 05h: %d 06h: %d " - "07h: %d 08h: %d\n", !!(b[4] & 0x80), !!(b[4] & 0x40), - !!(b[4] & 0x20), !!(b[4] & 0x10), !!(b[4] & 0x8), !!(b[4] & 0x4), - !!(b[4] & 0x2), !!(b[4] & 0x1)); - printf(" Flag09h: %d 0ah: %d 0bh: %d 0ch: %d 0dh: %d 0eh: %d " - "0fh: %d 10h: %d\n", !!(b[5] & 0x80), !!(b[5] & 0x40), - !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8), !!(b[5] & 0x4), - !!(b[5] & 0x2), !!(b[5] & 0x1)); - printf(" Flag11h: %d 12h: %d 13h: %d 14h: %d 15h: %d 16h: %d " - "17h: %d 18h: %d\n", !!(b[6] & 0x80), !!(b[6] & 0x40), - !!(b[6] & 0x20), !!(b[6] & 0x10), !!(b[6] & 0x8), !!(b[6] & 0x4), - !!(b[6] & 0x2), !!(b[6] & 0x1)); - printf(" Flag19h: %d 1ah: %d 1bh: %d 1ch: %d 1dh: %d 1eh: %d " - "1fh: %d 20h: %d\n", !!(b[7] & 0x80), !!(b[7] & 0x40), - !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x8), !!(b[7] & 0x4), - !!(b[7] & 0x2), !!(b[7] & 0x1)); - printf(" Flag21h: %d 22h: %d 23h: %d 24h: %d 25h: %d 26h: %d " - "27h: %d 28h: %d\n", !!(b[8] & 0x80), !!(b[8] & 0x40), - !!(b[8] & 0x20), !!(b[8] & 0x10), !!(b[8] & 0x8), !!(b[8] & 0x4), - !!(b[8] & 0x2), !!(b[8] & 0x1)); - printf(" Flag29h: %d 2ah: %d 2bh: %d 2ch: %d 2dh: %d 2eh: %d " - "2fh: %d 30h: %d\n", !!(b[9] & 0x80), !!(b[9] & 0x40), - !!(b[9] & 0x20), !!(b[9] & 0x10), !!(b[9] & 0x8), !!(b[9] & 0x4), - !!(b[9] & 0x2), !!(b[9] & 0x1)); - printf(" Flag31h: %d 32h: %d 33h: %d 34h: %d 35h: %d 36h: %d " - "37h: %d 38h: %d\n", !!(b[10] & 0x80), !!(b[10] & 0x40), - !!(b[10] & 0x20), !!(b[10] & 0x10), !!(b[10] & 0x8), - !!(b[10] & 0x4), !!(b[10] & 0x2), !!(b[10] & 0x1)); - printf(" Flag39h: %d 3ah: %d 3bh: %d 3ch: %d 3dh: %d 3eh: %d " - "3fh: %d 40h: %d\n", !!(b[11] & 0x80), !!(b[11] & 0x40), - !!(b[11] & 0x20), !!(b[11] & 0x10), !!(b[11] & 0x8), - !!(b[11] & 0x4), !!(b[11] & 0x2), !!(b[11] & 0x1)); + for (k = 1; k < 0x41; ++k) { + mod = ((k - 1) % 8); + div = (k - 1) / 8; + if (0 == mod) { + if (div > 0) + printf("\n"); + printf(" Flag%02Xh: %d", k, !! (b[4 + div] & 0x80)); + } else + printf(" %02Xh: %d", k, !! (b[4 + div] & (1 << (7 - mod)))); + } + printf("\n"); return 0; } @@ -2913,7 +2898,7 @@ decode_b5_vpd(unsigned char * b, int len, int do_hex, int pdt) } } -/* VPD_ZBC_DEV_CHARS sbc or zbc */ +/* VPD_ZBC_DEV_CHARS 0xb6 sbc or zbc */ static void decode_zbdc_vpd(unsigned char * b, int len, int do_hex) { |