diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 2 | ||||
-rw-r--r-- | src/sg_inq.c | 435 | ||||
-rw-r--r-- | src/sg_logs.c | 73 | ||||
-rw-r--r-- | src/sg_ses.c | 13 | ||||
-rw-r--r-- | src/sg_unmap.c | 8 | ||||
-rw-r--r-- | src/sg_vpd.c | 343 | ||||
-rw-r--r-- | src/sg_vpd_common.c | 199 | ||||
-rw-r--r-- | src/sg_vpd_common.h | 59 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 345 |
10 files changed, 926 insertions, 553 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 021100d3..f75bc7cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,6 +62,8 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze +# AM_CFLAGS = -Wall -W -pedantic -std=c++98 +# AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++1z # AM_CFLAGS = -Wall -W -pedantic -std=c++20 diff --git a/src/Makefile.in b/src/Makefile.in index f8b5a25d..c5217b1e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -664,6 +664,8 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze +# AM_CFLAGS = -Wall -W -pedantic -std=c++98 +# AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++1z # AM_CFLAGS = -Wall -W -pedantic -std=c++20 diff --git a/src/sg_inq.c b/src/sg_inq.c index 681073fe..47834743 100644 --- a/src/sg_inq.c +++ b/src/sg_inq.c @@ -53,7 +53,7 @@ #include "sg_vpd_common.h" /* for shared VPD page processing with sg_vpd */ -static const char * version_str = "2.28 20220811"; /* spc6r06, sbc5r03 */ +static const char * version_str = "2.28 20220818"; /* spc6r06, sbc5r03 */ #define MY_NAME "sg_inq" @@ -88,10 +88,6 @@ static const char * version_str = "2.28 20220811"; /* spc6r06, sbc5r03 */ // #undef SG_SCSI_STRINGS // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING -#ifndef SG_NVME_VPD_NICR -#define SG_NVME_VPD_NICR 0xde -#endif - #define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */ /* Vendor specific VPD pages (typically >= 0xc0) */ @@ -146,6 +142,8 @@ static void prepare_ata_identify(const struct opts_t * op, int inhex_len); /* Note that this table is sorted by acronym */ static struct svpd_values_name_t t10_vpd_pg[] = { + {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " + "number (SSC)"}, {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"}, {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics (SBC)"}, @@ -153,6 +151,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = { "extension (SBC)"}, {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"}, + {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"}, {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges " "(SBC)"}, {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"}, @@ -169,6 +168,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = { #endif {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"}, {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"}, + {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"}, {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning " "(SBC)"}, {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"}, @@ -176,12 +176,14 @@ static struct svpd_values_name_t t10_vpd_pg[] = { "Manufacturer assigned serial number (ADC)"}, {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"}, {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"}, - {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"}, + {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},/* "pc" in sg_vpd */ {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"}, {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit " "information"}, {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"}, {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"}, + {VPD_SA_DEV_CAP, 0, 1, "sad", + "Sequential access device capabilities (SSC)"}, {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and " "protection types (SBC)"}, {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"}, @@ -190,6 +192,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = { {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"}, {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"}, {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"}, + {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"}, {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"}, {VPD_ZBC_DEV_CHARS, 0, 0, "zbdch", "Zoned block device " "characteristics"}, @@ -331,9 +334,10 @@ usage() " --version|-V print version string then exit\n" " --vpd|-e vital product data (set page with " "'--page=PG')\n\n" - "Performs a SCSI INQUIRY command on DEVICE or decodes INQUIRY " - "response\nheld in file FN. If no options given then does a " - "'standard' INQUIRY.\nCan list VPD pages with '--vpd' or " + "Sends a SCSI INQUIRY command to the DEVICE and decodes the " + "response.\nAlternatively it decodes the INQUIRY response held " + "in file FN. If no\noptions given then it sends a 'standard' " + "INQUIRY command to DEVICE. Can\nlist VPD pages with '--vpd' or " "'--page=PG' option.\n"); } @@ -344,11 +348,11 @@ usage_old() #ifdef SG_LIB_LINUX pr2serr("Usage: sg_inq [-a] [-A] [-b] [-B=0|1] [-c] [-cl] [-d] [-e] " "[-h]\n" - " [-H] [-i] [I=FN] [-l=LEN] [-L] [-m] [-M] " - "[-o]\n" - " [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] [-V] " - "[-x]\n" - " [-36] [-?] DEVICE\n" + " [-H] [-i] [-I=FN] [-j[=JO]] [-l=LEN] [-L] [-m] " + "[-M]\n" + " [-o] [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] " + "[-V]\n" + " [-x] [-36] [-?] DEVICE\n" " where:\n" " -a decode ATA information VPD page (0x89)\n" " -A treat <device> as (directly attached) ATA device\n"); @@ -374,6 +378,8 @@ usage_old() " -H output in hex (ASCII to the right) [same as '-h']\n" " -i decode device identification VPD page (0x83)\n" " -I=FN use ASCII hex in file FN instead of DEVICE\n" + " -j[=JO] output in JSON instead of human readable " + "text.\n" " -l=LEN requested response length (def: 0 " "-> fetch 36\n" " bytes first, then fetch again as " @@ -395,7 +401,8 @@ usage_old() " -x decode extended INQUIRY data VPD page (0x86)\n" " -36 perform standard INQUIRY with a 36 byte response\n" " -? output this usage message\n\n" - "If no options given then does a standard SCSI INQUIRY\n"); + "If no options given then sends a standard SCSI INQUIRY " + "command and\ndecodes the response.\n"); } static void @@ -749,7 +756,22 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) op->do_block = n; } else if (0 == strncmp("I=", cp, 2)) op->inhex_fn = cp + 2; - else if (0 == strncmp("l=", cp, 2)) { + else if ('j' == *cp) { /* handle either '-j' or '-j=<JO>' */ + const char * c2p = (('=' == *(cp + 1)) ? cp + 2 : NULL); + + if (! sgj_init_state(&op->json_st, c2p)) { + int bad_char = op->json_st.first_bad_char; + char e[1500]; + + if (bad_char) { + pr2serr("bad argument to --json= option, unrecognized " + "character '%c'\n\n", bad_char); + } + sg_json_usage(0, e, sizeof(e)); + pr2serr("%s", e); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strncmp("l=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 1)) { pr2serr("Inappropriate value after 'l=' option\n"); @@ -849,6 +871,7 @@ enumerate_vpds() { const struct svpd_values_name_t * vnp; + printf("T10 defined VPD pages:\n"); for (vnp = t10_vpd_pg; vnp->acron; ++vnp) { if (vnp->name) { if (vnp->value < 0) @@ -858,6 +881,7 @@ enumerate_vpds() vnp->name); } } + printf("Vendor specific VPD pages:\n"); for (vnp = vs_vpd_pg; vnp->acron; ++vnp) { if (vnp->name) { if (vnp->value < 0) @@ -1092,6 +1116,16 @@ svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop) return res; } +static int +no_ascii_4hex(const struct opts_t * op) +{ + if (op->do_hex < 2) + return 1; + else if (2 == op->do_hex) + return 0; + else + return -1; +} static void decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, @@ -1104,7 +1138,7 @@ decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, char b[64]; if (op->do_hex) { - hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { @@ -1165,14 +1199,14 @@ vpd_page_is_supported(uint8_t * vpd_pg0, int v0_len, int pg_num, int vb) /* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */ static void -decode_ascii_inf(uint8_t * buff, int len, int do_hex) +decode_ascii_inf(uint8_t * buff, int len, struct opts_t * op) { int al, k, bump; uint8_t * bp; uint8_t * p; - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 0 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { @@ -1247,8 +1281,7 @@ decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, if (ip_tid_len > 0) { if (op->do_hex) { printf(" Initiator port transport id:\n"); - hex2stdout((bp + 8), ip_tid_len, - (1 == op->do_hex) ? 1 : -1); + hex2stdout((bp + 8), ip_tid_len, no_ascii_4hex(op)); } else { char b[1024]; @@ -1271,8 +1304,7 @@ decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, if (tpd_len > 0) { sgj_pr_hr(jsp, " Target port descriptor(s):\n"); if (op->do_hex) - hex2stdout(bp + bump + 4, tpd_len, - (1 == op->do_hex) ? 1 : -1); + hex2stdout(bp + bump + 4, tpd_len, no_ascii_4hex(op)); else { sgj_opaque_p ja2p = sgj_named_subarray_r(jsp, jo2p, "target_port_descriptor_list"); @@ -1953,7 +1985,8 @@ export_dev_ids(uint8_t * buff, int len, int verbose) "around offset=%d\n", off); } -/* VPD_BLOCK_LIMITS sbc */ +/* VPD_BLOCK_LIMITS 0xb0 ["bl"] (SBC) */ +/* VPD_SA_DEV_CAP 0xb0 ["sad"] (SSC) */ /* Sequential access device characteristics, ssc+smc */ /* OSD information, osd */ static void @@ -1963,7 +1996,7 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) sgj_state * jsp = &op->json_st; if (op->do_hex) { - hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { @@ -1981,8 +2014,8 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) break; case PDT_OSD: default: - printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); - hex2stdout(buff, len, 0); + pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); + hex2stderr(buff, len, 0); break; } } @@ -1990,49 +2023,60 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) /* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */ /* VPD_MAN_ASS_SN ssc */ static void -decode_b1_vpd(uint8_t * buff, int len, int do_hex) +decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; + sgj_state * jsp = &op->json_st; - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 0 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = PDT_MASK & buff[0]; switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: - /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */ - break; - case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: - printf(" Manufacturer-assigned serial number: %.*s\n", - len - 4, buff + 4); - break; - default: - printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); - hex2stdout(buff, len, 0); - break; + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: + /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */ + break; + case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: + sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n", + len - 4, buff + 4); + sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number", + (const char *)buff + 4, len - 4); + break; + default: + pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); + hex2stderr(buff, len, 0); + break; } } -/* VPD_REFERRALS sbc */ +/* VPD_REFERRALS sbc 0xb3 ["ref"] */ +/* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */ static void -decode_b3_vpd(uint8_t * buff, int len, int do_hex) +decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; + sgj_state * jsp = &op->json_st; - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 0 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } - pdt = PDT_MASK & buff[0]; + pdt = buff[0] & PDT_MASK; switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: - /* now done in decode)referrals_vpd() in sg_vpd_common.c */ - break; - default: - printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); - hex2stdout(buff, len, 0); - break; + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: + /* now done in decode_referrals_vpd() in sg_vpd_common.c */ + break; + case PDT_TAPE: case PDT_MCHANGER: + sgj_pr_hr(jsp, " Automation device serial number: %.*s\n", + len - 4, buff + 4); + sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number", + (const char *)buff + 4, len - 4); + break; + default: + pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); + hex2stderr(buff, len, 0); + break; } } @@ -2084,7 +2128,7 @@ static const char * failover_mode_arr[] = }; static void -decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex) +decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op) { int k, ip_mgmt, vpp80, lun_z; @@ -2092,8 +2136,8 @@ decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex) pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); return; } - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 1 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (buff[9] != 0x00) { @@ -2162,14 +2206,14 @@ decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex) } static void -decode_rdac_vpd_c2(uint8_t * buff, int len, int do_hex) +decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op) { if (len < 3) { pr2serr("Software Version VPD page length too short=%d\n", len); return; } - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 1 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { @@ -2260,14 +2304,14 @@ decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor) } static void -decode_rdac_vpd_c9(uint8_t * buff, int len, int do_hex) +decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op) { if (len < 3) { pr2serr("Volume Access Control VPD page length too short=%d\n", len); return; } - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 1 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') { @@ -2398,7 +2442,7 @@ std_inq_decode(struct opts_t * op, sgj_opaque_p jop, int off) return; } else if (op->do_hex) { /* with -H, print with address, -HH without */ - hex2stdout(rp, op->maxlen, ((1 == op->do_hex) ? 0 : -1)); + hex2stdout(rp, op->maxlen, no_ascii_4hex(op)); return; } pqual = (rp[0] & 0xe0) >> 5; @@ -2802,7 +2846,7 @@ cmddt_process(int sg_fd, const struct opts_t * op) len = rsp_buff[5] + 6; reserved_cmddt = rsp_buff[4]; if (op->do_hex) - hex2stdout(rsp_buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rsp_buff, len, no_ascii_4hex(op)); else if (op->do_raw) dStrRaw((const char *)rsp_buff, len); else { @@ -2872,14 +2916,23 @@ cmddt_process(int sg_fd, const struct opts_t * op) static int vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off) { - int res, len; + bool as_json; + bool json_o_hr; + int res, len, n; char b[128]; + sgj_state * jsp = &op->json_st; const char * cp; uint8_t * rp; + as_json = jsp->pr_as_json; + json_o_hr = as_json && jsp->pr_out_hr; rp = rsp_buff + off; - if ((! op->do_raw) && (op->do_hex < 2)) - printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn); + if ((! op->do_raw) && (op->do_hex < 3)) { + if (op->do_hex) + printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn); + else + sgj_pr_hr(jsp, "VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn); + } if (sg_fd < 0) { len = sg_get_unaligned_be16(rp + 2) + 4; res = 0; @@ -2892,15 +2945,32 @@ vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off) if (op->do_raw) dStrRaw((const char *)rp, len); else { + int pdt = pdt = rp[0] & PDT_MASK; + if (0 == op->vpd_pn) decode_supported_vpd_4inq(rp, len, op, jap); else { if (op->verbose) { - cp = sg_get_pdt_str(rp[0] & PDT_MASK, sizeof(b), b); - printf(" [PQual=%d Peripheral device type: %s]\n", - (rp[0] & 0xe0) >> 5, cp); + cp = sg_get_pdt_str(pdt, sizeof(b), b); + if (op->do_hex) + printf(" [PQual=%d Peripheral device type: %s]\n", + (rp[0] & 0xe0) >> 5, cp); + else + sgj_pr_hr(jsp, " [PQual=%d Peripheral device " + "type: %s]\n", (rp[0] & 0xe0) >> 5, cp); } - hex2stdout(rp, len, ((1 == op->do_hex) ? 0 : -1)); + if (json_o_hr && (0 == op->do_hex) && (len > 0) && + (len < UINT16_MAX)) { + char * p; + + n = len * 4; + p = malloc(n); + if (p) { + n = hex2str(rp, len, NULL, 1, n - 1, p); + sgj_js_str_out(jsp, p, n); + } + } else + hex2stdout(rp, len, no_ascii_4hex(op)); } } } else { @@ -2959,7 +3029,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) switch (pn) { case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */ np = "Supported VPD pages VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -2967,7 +3037,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) - hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rp, len, no_ascii_4hex(op)); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); @@ -2979,7 +3049,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */ np = "Unit serial number VPD page"; - if (! op->do_raw && ! op->do_export && (op->do_hex < 2)) + if (! op->do_raw && ! op->do_export && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -2987,7 +3057,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) - hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rp, len, no_ascii_4hex(op)); else { char obuff[DEF_ALLOC_LEN]; int k, m; @@ -3048,7 +3118,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */ np = "Software interface identification VPD page"; - if (! op->do_raw && (op->do_hex < 2)) + if (! op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3066,7 +3136,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */ np = "Management network addresses page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3087,7 +3157,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_EXT_INQ: /* 0x86 ["ei"] */ np = "Extended INQUIRY data"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3095,14 +3165,30 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (op->do_raw) dStrRaw((const char *)rp, len); else { + bool protect = false; + + op->protect_not_sure = false; + if ((sg_fd >= 0) && (! op->do_force)) { + struct sg_simple_inquiry_resp sir; + + res = sg_simple_inquiry(sg_fd, &sir, false, vb); + if (res) { + if (op->verbose) + pr2serr("%s: sg_simple_inquiry() failed, res=%d\n", + __func__, res); + op->protect_not_sure = true; + } else + protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */ + } else + op->protect_not_sure = true; if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); - decode_x_inq_vpd(rp, len, false /* protect */, op, jo2p); + decode_x_inq_vpd(rp, len, protect, op, jo2p); } break; case VPD_MODE_PG_POLICY: /* 0x87 ["mpp"] */ np = "Mode page policy"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3120,7 +3206,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_SCSI_PORTS: /* 0x88 ["sp"] */ np = "SCSI Ports VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3138,7 +3224,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_ATA_INFO: /* 0x89 ["ai"] */ np = "ATA information VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3159,7 +3245,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_POWER_CONDITION: /* 0x8a ["pc"] */ np = "Power condition VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3172,9 +3258,9 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) decode_power_condition(rp, len, op, jo2p); } break; - case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */ - np = "Power consumption VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */ + np = "Device constituents page VPD page"; + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3185,14 +3271,32 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, - "power_consumption_descriptor_list"); + "constituent_descriptor_list"); } - decode_power_consumption(rp, len, op, jap); + decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode); } break; - case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */ - np = "Device constituents page VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */ + np = "CFA profile information VPD page"; + if (!op->do_raw && (op->do_hex < 3)) + sgj_pr_hr(jsp, "%s:\n", np); + res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); + if (0 == res) { + if (op->do_raw) + dStrRaw((const char *)rp, len); + else { + if (as_json) { + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); + jap = sgj_named_subarray_r(jsp, jo2p, + "cfa_profile_descriptor_list"); + } + decode_cga_profile_vpd(rp, len, op, jap); + } + } + break; + case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */ + np = "Power consumption VPD page"; + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3203,14 +3307,14 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, - "constituent_descriptor_list"); + "power_consumption_descriptor_list"); } - decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode); + decode_power_consumption(rp, len, op, jap); } break; case VPD_3PARTY_COPY: /* 0x8f ["tpc"] */ np = "Third party copy VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3228,7 +3332,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_PROTO_LU: /* 0x90 ["pslu"] */ np = "Protocol specific logical unit information VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3246,7 +3350,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_PROTO_PORT: /* 0x91 ["pspo"] */ np = "Protocol specific port information VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3264,7 +3368,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */ np = "SCSI Feature sets VPD page"; - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (res) @@ -3314,7 +3418,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3364,7 +3468,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt); break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3375,7 +3479,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) if (bdc) decode_block_dev_ch_vpd(rp, len, op, jo2p); else - decode_b1_vpd(rp, len, op->do_hex); + decode_b1_vpd(rp, len, op, jo2p); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb1\n"); break; @@ -3383,6 +3487,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool lbpv = false; + bool tas = false; if (op->do_raw) { dStrRaw((const char *)rp, len); @@ -3398,12 +3503,13 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) case PDT_TAPE: case PDT_MCHANGER: np = "TapeAlert supported flags VPD page"; ep = "(SSC)"; + tas = true; break; default: np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3413,18 +3519,13 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (lbpv) return decode_block_lb_prov_vpd(rp, len, op, jo2p); + else if (tas) + decode_tapealert_supported_vpd(rp, len, op, jo2p); else return vpd_mainly_hex(sg_fd, op, NULL, off); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb2\n"); break; -#if 0 -xxxxx - if (!op->do_raw && (op->do_hex < 2)) - pr2serr(" Only hex output supported. The sg_vpd utility decodes " - "the B2h page.\n"); - return vpd_mainly_hex(sg_fd, op, NULL, off); -#endif case 0xb3: res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { @@ -3445,7 +3546,7 @@ xxxxx np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3456,7 +3557,7 @@ xxxxx if (ref) decode_referrals_vpd(rp, len, op, jo2p); else - decode_b3_vpd(rp, len, op->do_hex); + decode_b3_vpd(rp, len, op, jo2p); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb3\n"); @@ -3465,6 +3566,7 @@ xxxxx res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool sbl = false; + bool dtde = false; if (op->do_raw) { dStrRaw((const char *)rp, len); @@ -3477,24 +3579,34 @@ xxxxx ep = "(SBC)"; sbl = true; break; + case PDT_TAPE: case PDT_MCHANGER: + np = "Device transfer data element VPD page"; + ep = "(SSC)"; + dtde = true; + break; default: np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } - if (as_json) { + if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); - jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" + if (sbl) { + if (as_json) + jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" "length_and_protection_types_descriptor_list"); - } - if (sbl) decode_sup_block_lens_vpd(rp, len, op, jap); - else + } else if (dtde) { + if (! jsp->pr_as_json) + hex2stdout(rp + 4, len - 4, 1); + sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element", + rp + 4, len - 4); + } else return vpd_mainly_hex(sg_fd, op, NULL, off); return 0; } else if (! op->do_raw) @@ -3504,6 +3616,7 @@ xxxxx res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdce = false; + bool lbp = false; if (op->do_raw) { dStrRaw((const char *)rp, len); @@ -3516,11 +3629,16 @@ xxxxx ep = "(SBC)"; bdce = true; break; + case PDT_TAPE: case PDT_MCHANGER: + np = "Logical block protection VPD page"; + ep = "(SSC)"; + lbp = true; + break; default: np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3530,7 +3648,12 @@ xxxxx jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdce) decode_block_dev_char_ext_vpd(rp, len, op, jo2p); - else + else if (lbp) { /* VPD_LB_PROTECTION 0xb5 ["lbpro"] (SSC) */ + if (as_json) + jap = sgj_named_subarray_r(jsp, jo2p, + "logical_block_protection_method_descriptor_list"); + decode_lb_protection_vpd(rp, len, op, jap); + } else return vpd_mainly_hex(sg_fd, op, NULL, off); return 0; } else if (! op->do_raw) @@ -3556,7 +3679,7 @@ xxxxx np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3592,7 +3715,7 @@ xxxxx np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3628,7 +3751,7 @@ xxxxx np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3667,7 +3790,7 @@ xxxxx np = NULL; break; } - if (op->do_hex < 2) { + if (op->do_hex < 3) { if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else @@ -3686,9 +3809,9 @@ xxxxx } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb8\n"); break; -// yyyyyyyy + /* Vendor specific VPD pages (>= 0xc0) */ case VPD_UPR_EMC: /* 0xc0 */ - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) printf("VPD INQUIRY: Unit Path Report Page (EMC)\n"); res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len); if (res) @@ -3696,10 +3819,10 @@ xxxxx if (op->do_raw) dStrRaw((const char *)rp, len); else - decode_upr_vpd_c0_emc(rp, len, op->do_hex); + decode_upr_vpd_c0_emc(rp, len, op); break; case VPD_RDAC_VERS: /* 0xc2 */ - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) printf("VPD INQUIRY: Software Version (RDAC)\n"); res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len); if (res) @@ -3707,10 +3830,10 @@ xxxxx if (op->do_raw) dStrRaw((const char *)rp, len); else - decode_rdac_vpd_c2(rp, len, op->do_hex); + decode_rdac_vpd_c2(rp, len, op); break; case VPD_RDAC_VAC: /* 0xc9 */ - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) printf("VPD INQUIRY: Volume Access Control (RDAC)\n"); res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len); if (res) @@ -3718,7 +3841,47 @@ xxxxx if (op->do_raw) dStrRaw((const char *)rp, len); else - decode_rdac_vpd_c9(rp, len, op->do_hex); + decode_rdac_vpd_c9(rp, len, op); + break; + case SG_NVME_VPD_NICR: /* 0xde */ + np = "NVMe Identify Controller Response VPD page"; + /* NVMe: Identify Controller data structure (CNS 01h) */ + ep = "(sg3_utils)"; + res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); + if (res) { + sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); + break; + } + if (op->do_raw) { + dStrRaw((const char *)rp, len); + break; + } + pdt = rp[0] & PDT_MASK; + if (op->do_hex < 3) { + if (NULL == np) + sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); + else + sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); + } + if (len < 16) { + pr2serr("%s expected to be > 15 bytes long (got: %d)\n", ep, len); + break; + } else { + int n = len - 16; + + if (n > 4096) { + pr2serr("NVMe Identify response expected to be <= 4096 " + "bytes (got: %d)\n", n); + break; + } + if (op->do_hex) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (as_json) { + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); + sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n); + } else + hex2stdout(rp + 16, n, 1); + } break; default: bad = true; @@ -3726,7 +3889,7 @@ xxxxx } if (bad) { if ((pn > 0) && (pn < 0x80)) { - if (!op->do_raw && (op->do_hex < 2)) + if (!op->do_raw && (op->do_hex < 3)) printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n", pn); res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); @@ -3734,12 +3897,11 @@ xxxxx if (op->do_raw) dStrRaw((const char *)rp, len); else - decode_ascii_inf(rp, len, op->do_hex); + decode_ascii_inf(rp, len, op); } } else { - if (op->do_hex < 2) - pr2serr(" Only hex output supported. The sg_vpd and sdparm " - "utilities decode more VPD pages.\n"); + if (op->do_hex < 3) + pr2serr(" Only hex output supported.\n"); return vpd_mainly_hex(sg_fd, op, NULL, off); } } @@ -4212,7 +4374,8 @@ main(int argc, char * argv[]) enumerate_vpds(); return SG_LIB_SYNTAX_ERROR; } - if ((1 != op->do_hex) && (0 == op->do_raw)) + // if ((1 != op->do_hex) && (0 == op->do_raw)) + if (0 == op->do_raw) op->do_decode = true; op->vpd_pn = vnp->value; subvalue = vnp->subvalue; diff --git a/src/sg_logs.c b/src/sg_logs.c index 32bfc721..6f5edd48 100644 --- a/src/sg_logs.c +++ b/src/sg_logs.c @@ -37,7 +37,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.99 20220729"; /* spc6r06 + sbc5r01 */ +static const char * version_str = "2.00 20220816"; /* spc6r06 + sbc5r03 */ #define MX_ALLOC_LEN (0xfffc) #define MX_INLEN_ALLOC_LEN (0x800000) @@ -6711,70 +6711,6 @@ skip: return true; } -static const 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", -}; - /* TAPE_ALERT_LPAGE [0x2e] <ta> */ static bool show_tape_alert_ssc_page(const uint8_t * resp, int len, @@ -6807,8 +6743,11 @@ show_tape_alert_ssc_page(const uint8_t * resp, int len, if (op->verbose && (0 == op->do_brief) && flag) printf(" >>>> "); if ((0 == op->do_brief) || op->verbose || flag) { - if (pc < (int)SG_ARRAY_SIZE(tape_alert_strs)) - printf(" %s: %d\n", tape_alert_strs[pc], flag); + if (NULL == sg_lib_tapealert_strs[0]) + printf(" No string available for code 0x%x, flag: %d\n", + pc, flag); + else if (pc <= 0x40) + printf(" %s: %d\n", sg_lib_tapealert_strs[pc], flag); else printf(" Reserved parameter code 0x%x, flag: %d\n", pc, flag); diff --git a/src/sg_ses.c b/src/sg_ses.c index e6e1270b..cc1ce78d 100644 --- a/src/sg_ses.c +++ b/src/sg_ses.c @@ -38,7 +38,7 @@ * commands tailored for SES (enclosure) devices. */ -static const char * version_str = "2.57 20220309"; /* ses4r04 */ +static const char * version_str = "2.58 20220813"; /* ses4r04 */ #define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */ #define MX_ELEM_HDR 1024 @@ -1084,6 +1084,8 @@ parse_index(struct opts_t *op) } element_type_by_code.elem_type_code = n; mallcp = (char *)malloc(8); /* willfully forget about freeing this */ + if (NULL == mallcp) + return sg_convert_errno(ENOMEM); mallcp[0] = '_'; snprintf(mallcp + 1, 6, "%d", n); element_type_by_code.abbrev = mallcp; @@ -5686,12 +5688,13 @@ main(int argc, char * argv[]) if (SET_OPT == cgs_clp->cgs_sel) tavp->val = DEF_SET_VAL; } - if (!strcmp(cgs_clp->cgs_str, "sas_addr") && op->dev_slot_num < 0) { - pr2serr("--get=sas_addr requires --dev-slot-num. For expander " - "SAS address, use exp_sas_addr instead.\n"); + if (!strcmp(cgs_clp->cgs_str, "sas_addr") && + op->dev_slot_num < 0) { + pr2serr("--get=sas_addr requires --dev-slot-num. For " + "expander SAS address, use exp_sas_addr instead.\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; - } + } tavp->cgs_sel = cgs_clp->cgs_sel; } /* keep this descending for loop directly after ascending for loop */ diff --git a/src/sg_unmap.c b/src/sg_unmap.c index c24c676a..2bfb12d6 100644 --- a/src/sg_unmap.c +++ b/src/sg_unmap.c @@ -36,7 +36,7 @@ * logical blocks. Note that DATA MAY BE LOST. */ -static const char * version_str = "1.18 20220608"; +static const char * version_str = "1.19 20220813"; #define DEF_TIMEOUT_SECS 60 @@ -253,7 +253,7 @@ build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr, int64_t ll; char line[1024]; char * lcp; - FILE * fp; + FILE * fp = NULL; have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0])); if (have_stdin) @@ -336,12 +336,12 @@ build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr, goto bad_exit; } *arr_len = off >> 1; - if (fp && (stdin != fp)) + if (fp && (! have_stdin)) fclose(fp); return 0; bad_exit: - if (fp && (stdin != fp)) + if (fp && (! have_stdin)) fclose(fp); return 1; } diff --git a/src/sg_vpd.c b/src/sg_vpd.c index 0cb6f7ed..9aae8a72 100644 --- a/src/sg_vpd.c +++ b/src/sg_vpd.c @@ -42,7 +42,7 @@ */ -static const char * version_str = "1.80 20220811"; /* spc6r06 + sbc5r03 */ +static const char * version_str = "1.81 20220818"; /* spc6r06 + sbc5r03 */ #define MY_NAME "sg_vpd" @@ -110,17 +110,17 @@ static struct option long_options[] = { /* arranged in alphabetical order by acronym */ static struct svpd_values_name_t standard_vpd_pg[] = { + {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " + "number (SSC)"}, {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"}, {VPD_ASCII_OP_DEF, 0, -1, "aod", "ASCII implemented operating definition (obsolete)"}, - {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " - "number (SSC)"}, - {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, - {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"}, {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics " "(SBC)"}, {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics " "extension (SBC)"}, + {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, + {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"}, {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"}, {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges"}, {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"}, @@ -147,7 +147,7 @@ static struct svpd_values_name_t standard_vpd_pg[] = { {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"}, {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"}, {VPD_OSD_INFO, 0, 0x11, "oi", "OSD information"}, - {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"}, + {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},/* "po" in sg_inq */ {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"}, {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit " "information"}, @@ -444,6 +444,17 @@ device_id_vpd_variants(uint8_t * buff, int len, int subvalue, } } +static int +no_ascii_4hex(const struct opts_t * op) +{ + if (op->do_hex < 2) + return 1; + else if (2 == op->do_hex) + return 0; + else + return -1; +} + static void /* VPD_SUPPORTED_VPDS ["sv"] */ decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) @@ -459,7 +470,7 @@ decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op, static const char * svps = "Supported VPD pages"; if ((1 == op->do_hex) || (op->do_hex > 2)) { - hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = PDT_MASK & buff[0]; @@ -525,7 +536,7 @@ decode_scsi_ports_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op, uint8_t * bp; if ((1 == op->do_hex) || (op->do_hex > 2)) { - hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { @@ -876,7 +887,7 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) sgj_state * jsp = &op->json_st; if (op->do_hex) { - hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { @@ -904,18 +915,24 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) /* VPD_SECURITY_TOKEN osd */ /* VPD_ES_DEV_CHARS ses-4 */ static void -decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt) +decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { - if (do_hex) { - hex2stdout(buff, len, (1 == do_hex) ? 0 : -1); + int pdt; + sgj_state * jsp = &op->json_st; + + pdt = buff[0] & PDT_MASK; + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */ case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: - printf(" Manufacturer-assigned serial number: %.*s\n", - len - 4, buff + 4); + sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n", + len - 4, buff + 4); + sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number", + (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); @@ -924,77 +941,21 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt) } } -/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */ -static void -decode_lb_protection_vpd(uint8_t * buff, int len, int do_hex) -{ - int k, bump; - uint8_t * bp; - - if ((1 == do_hex) || (do_hex > 2)) { - hex2stdout(buff, len, (1 == do_hex) ? 0 : -1); - return; - } - if (len < 8) { - pr2serr("Logical block protection VPD page length too short=%d\n", - len); - return; - } - len -= 8; - bp = buff + 8; - for (k = 0; k < len; k += bump, bp += bump) { - bump = 1 + bp[0]; - printf(" method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, " - "RBDP_C=%d\n", bp[1], 0x3f & bp[2], !!(0x80 & bp[3]), - !!(0x40 & bp[3]), !!(0x20 & bp[3])); - if ((k + bump) > len) { - pr2serr("Logical block protection VPD page, short " - "descriptor length=%d, left=%d\n", bump, (len - k)); - return; - } - } -} - -/* VPD_TA_SUPPORTED 0xb2 */ -static int -decode_tapealert_supported_vpd(uint8_t * 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; - } - 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; -} - /* VPD_LB_PROVISIONING sbc */ /* VPD_TA_SUPPORTED ssc */ static void decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op) { if (op->do_hex) { - hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* decode_block_lb_prov_vpd() is now in sg_vpd_common.c */ - // decode_block_lb_prov_vpd(buff, len, op); break; case PDT_TAPE: case PDT_MCHANGER: - decode_tapealert_supported_vpd(buff, len); + /* decode_tapealert_supported_vpd() is now in sg_vpd_common.c */ break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); @@ -1006,29 +967,29 @@ decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op) /* VPD_REFERRALS sbc 0xb3 ["ref"] */ /* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */ static void -decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op) +decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { - char obuff[DEF_ALLOC_LEN]; + int pdt; + sgj_state * jsp = &op->json_st; if (op->do_hex) { - hex2stdout(b, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(buff, len, no_ascii_4hex(op)); return; } + pdt = buff[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done in decode_referrals_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: - memset(obuff, 0, sizeof(obuff)); - len -= 4; - if (len >= (int)sizeof(obuff)) - len = sizeof(obuff) - 1; - memcpy(obuff, b + 4, len); - printf(" Automation device serial number: %s\n", obuff); + sgj_pr_hr(jsp, " Automation device serial number: %.*s\n", + len - 4, buff + 4); + sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number", + (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); - hex2stderr(b, len, 0); + hex2stderr(buff, len, 0); break; } } @@ -1036,12 +997,13 @@ decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op) /* VPD_SUP_BLOCK_LENS sbc ["sbl"] */ /* VPD_DTDE_ADDRESS ssc */ static void -decode_b4_vpd(uint8_t * b, int len, int do_hex, int pdt) +decode_b4_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { - int k; + int pdt = buff[0] & PDT_MASK; + sgj_state * jsp = &op->json_st; - if (do_hex) { - hex2stdout(b, len, (1 == do_hex) ? 0 : -1); + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { @@ -1049,19 +1011,21 @@ decode_b4_vpd(uint8_t * b, int len, int do_hex, int pdt) /* now done by decode_sup_block_lens_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: - printf(" Data transfer device element address: 0x"); - for (k = 4; k < len; ++k) - printf("%02x", (unsigned int)b[k]); - printf("\n"); + sgj_pr_hr(jsp, " Device transfer data element:\n"); + if (! jsp->pr_as_json) + hex2stdout(buff + 4, len - 4, 1); + sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element", + buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); - hex2stderr(b, len, 0); + hex2stderr(buff, len, 0); break; } } /* VPD_BLOCK_DEV_C_EXTENS sbc */ +/* VPD_LB_PROTECTION 0xb5 ["lbpro"] ssc */ static void decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt) { @@ -1074,7 +1038,7 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt) /* now done by decode_block_dev_char_ext_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: - decode_lb_protection_vpd(b, len, do_hex); + /* now done by decode_lb_protection_vpd() in sg_vpd_common.c */ break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); @@ -1087,20 +1051,36 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt) static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off) { - int len, res; + bool as_json, json_o_hr, hex0; + int res, len, n; + sgj_state * jsp = &op->json_st; uint8_t * rp; + as_json = jsp->pr_as_json; + json_o_hr = as_json && jsp->pr_out_hr; + hex0 = (0 == op->do_hex); rp = rsp_buff + off; - if ((! op->do_hex) && (! op->do_raw) && (0 == op->examine)) - printf("Only hex output supported\n"); - if ((!op->do_raw) && (op->do_hex < 2) && (0 == op->examine)) { - if (subvalue) - printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn, - subvalue); - else if (op->vpd_pn >= 0) - printf("VPD page code=0x%.2x:\n", op->vpd_pn); - else - printf("VPD page code=%d:\n", op->vpd_pn); + if (hex0 && (! op->do_raw) && (! op->examine_given)) + sgj_pr_hr(jsp, "Only hex output supported\n"); + if ((!op->do_raw) && (op->do_hex < 2) && (! op->examine_given)) { + if (subvalue) { + if (hex0) + sgj_pr_hr(jsp, "VPD page code=0x%.2x, subvalue=0x%.2x:\n", + op->vpd_pn, subvalue); + else + printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn, + subvalue); + } else if (op->vpd_pn >= 0) { + if (hex0) + sgj_pr_hr(jsp, "VPD page code=0x%.2x:\n", op->vpd_pn); + else + printf("VPD page code=0x%.2x:\n", op->vpd_pn); + } else { + if (hex0) + sgj_pr_hr(jsp, "VPD page code=%d:\n", op->vpd_pn); + else + printf("VPD page code=%d:\n", op->vpd_pn); + } } res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, op->maxlen, op->do_quiet, @@ -1109,6 +1089,18 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off) if (op->do_raw) dStrRaw(rp, len); else { + if (json_o_hr && hex0 && (len > 0) && (len < UINT16_MAX)) { + char * p; + + n = len * 4; + p = malloc(n); + if (p) { + n = hex2str(rp, len, NULL, 1, n - 1, p); + sgj_js_str_out(jsp, p, n); + } + } else + hex2stdout(rp, len, no_ascii_4hex(op)); +#if 0 if (op->do_hex > 1) hex2stdout(rp, len, -1); else if (VPD_ASCII_OP_DEF == op->vpd_pn) @@ -1117,8 +1109,9 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off) hex2stdout(rp, len, (op->do_long ? 0 : 1)); else hex2stdout(rp, len, 0); +#endif } - } else if ((! op->do_quiet) && (0 == op->examine)) { + } else if ((! op->do_quiet) && (! op->examine_given)) { if (op->vpd_pn >= 0) pr2serr("fetching VPD page code=0x%.2x: failed\n", op->vpd_pn); else @@ -1133,7 +1126,7 @@ recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off) int res = svpd_decode_t10(-1, op, jop, 0, off, NULL); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(-1, op, off); + res = svpd_decode_vendor(-1, op, jop, off); if (SG_LIB_CAT_OTHER == res) svpd_unable_to_decode(-1, op, 0, off); } @@ -1149,6 +1142,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, bool allow_name, allow_if_found, long_notquiet, qt; bool vpd_supported = false; bool inhex_active = (-1 == sg_fd); + bool exam_not_given = ! op->examine_given; int len, pdt, pqual, num, k, resid, alloc_len, pn, vb; int res = 0; sgj_state * jsp = &op->json_st; @@ -1157,7 +1151,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, sgj_opaque_p jo2p = NULL; const char * np; const char * ep; - const char * pre = (prefix ? prefix : "");; + const char * pre = (prefix ? prefix : ""); const char * pdt_str; bool as_json = jsp->pr_as_json; bool not_json = ! as_json; @@ -1168,18 +1162,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, qt = op->do_quiet; long_notquiet = op->do_long && (! op->do_quiet); if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) || - (op->do_hex >= 3) || (op->examine > 0)) + (op->do_hex >= 3) || op->examine_given) allow_name = false; else allow_name = true; - allow_if_found = (op->examine > 0) && (! op->do_quiet); + allow_if_found = op->examine_given && (! op->do_quiet); rp = rsp_buff + off; pn = op->vpd_pn; if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn)) pn = rp[1]; else pn = op->vpd_pn; - if (!inhex_active && !op->do_force && 0 == op->examine && + if (!inhex_active && !op->do_force && exam_not_given && pn != VPD_NOPE_WANT_STD_INQ && pn != VPD_SUPPORTED_VPDS) { res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt, @@ -1251,7 +1245,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (op->do_raw) dStrRaw(rp, len); else if (op->do_hex) - hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rp, len, no_ascii_4hex(op)); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " @@ -1280,7 +1274,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (op->do_raw) dStrRaw(rp, len); else if (op->do_hex) - hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rp, len, no_ascii_4hex(op)); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " @@ -1307,7 +1301,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (op->do_raw) dStrRaw(rp, len); else if (op->do_hex) - hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1); + hex2stdout(rp, len, no_ascii_4hex(op)); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " @@ -1379,17 +1373,23 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, dStrRaw(rp, len); else { bool protect = false; - struct sg_simple_inquiry_resp sir; - if ((sg_fd >= 0) && long_notquiet) { + op->protect_not_sure = false; + if (op->std_inq_a_valid) + protect = !! (0x1 & op->std_inq_a[5]); + else if ((sg_fd >= 0) && (! op->do_force)) { + struct sg_simple_inquiry_resp sir; + res = sg_simple_inquiry(sg_fd, &sir, false, vb); if (res) { if (op->verbose) pr2serr("%s: sg_simple_inquiry() failed, " "res=%d\n", __func__, res); + op->protect_not_sure = true; } else protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */ - } + } else + op->protect_not_sure = true; if (vb || long_notquiet) sgj_pr_hr(jsp," [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); @@ -1523,6 +1523,30 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, return 0; } break; + case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */ + np = "CFA profile information VPD page"; + if (allow_name) + sgj_pr_hr(jsp, "%s%s:\n", pre, np); + res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); + if (0 == res) { + if (! allow_name && allow_if_found) + sgj_pr_hr(jsp, "%s%s\n", pre, np); + if (op->do_raw) + dStrRaw(rp, len); + else { + if (vb || long_notquiet) + sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " + "%s]\n", pqual, pdt_str); + if (as_json) { + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); + jap = sgj_named_subarray_r(jsp, jo2p, + "cfa_profile_descriptor_list"); + } + decode_cga_profile_vpd(rp, len, op, jap); + } + return 0; + } + break; case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */ np = "Power consumption VPD page"; if (allow_name) @@ -1614,7 +1638,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, jap = sgj_named_subarray_r(jsp, jo2p, "port_information_descriptor_list"); } - decode_proto_port_vpd(rp, len, op, jsp); + decode_proto_port_vpd(rp, len, op, jap); } return 0; } @@ -1694,7 +1718,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb0\n", pre); break; case 0xb1: /* depends on pdt */ @@ -1741,17 +1765,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (bdc) decode_block_dev_ch_vpd(rp, len, op, jo2p); else - decode_b1_vpd(rp, len, op->do_hex, pdt); + decode_b1_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb1\n", pre); break; case 0xb2: /* VPD page depends on pdt */ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool lbpv = false; + bool tas = false; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: @@ -1762,6 +1787,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, case PDT_TAPE: case PDT_MCHANGER: np = "TapeAlert supported flags VPD page"; ep = "(SSC)"; + tas = true; break; default: np = NULL; @@ -1781,12 +1807,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (lbpv) decode_block_lb_prov_vpd(rp, len, op, jo2p); + else if (tas) + decode_tapealert_supported_vpd(rp, len, op, jo2p); else decode_b2_vpd(rp, len, pdt, op); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb2\n", pre); break; case 0xb3: /* VPD page depends on pdt */ @@ -1824,11 +1852,11 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (ref) decode_referrals_vpd(rp, len, op, jo2p); else - decode_b3_vpd(rp, len, pdt, op); + decode_b3_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb3\n", pre); break; case 0xb4: /* VPD page depends on pdt */ @@ -1861,25 +1889,26 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); - if (as_json) { + if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); - jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" + if (sbl) { + if (as_json) + jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" "length_and_protection_types_descriptor_list"); - } - if (sbl) decode_sup_block_lens_vpd(rp, len, op, jap); - else - decode_b4_vpd(rp, len, op->do_hex, pdt); + } else + decode_b4_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb4\n", pre); break; case 0xb5: /* VPD page depends on pdt */ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdce = false; + bool lbp = false; pdt = rp[0] & PDT_MASK; switch (pdt) { @@ -1891,6 +1920,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, case PDT_TAPE: case PDT_MCHANGER: np = "Logical block protection VPD page"; ep = "(SSC)"; + lbp = true; break; default: np = NULL; @@ -1910,12 +1940,17 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdce) decode_block_dev_char_ext_vpd(rp, len, op, jo2p); - else + else if (lbp) { + if (as_json) + jap = sgj_named_subarray_r(jsp, jo2p, + "logical_block_protection_method_descriptor_list"); + decode_lb_protection_vpd(rp, len, op, jap); + } else decode_b5_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb5\n", pre); break; case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */ @@ -1953,7 +1988,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb6\n", pre); break; case 0xb7: @@ -1991,7 +2026,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb7\n", pre); break; case 0xb8: /* VPD_FORMAT_PRESETS */ @@ -2032,7 +2067,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb8\n", pre); break; case 0xb9: /* VPD_CON_POS_RANGE */ @@ -2073,7 +2108,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop, } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) && - (0 == op->examine)) + exam_not_given) printf("%sVPD page=0xb8\n", pre); break; default: @@ -2129,7 +2164,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop) res = svpd_decode_t10(sg_fd, op, jop, 0, 0, NULL); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(sg_fd, op, 0); + res = svpd_decode_vendor(sg_fd, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(sg_fd, op, 0, 0); } @@ -2185,7 +2220,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop) res = svpd_decode_t10(-1, op, jop, 0, off, NULL); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(-1, op, off); + res = svpd_decode_vendor(-1, op, jop, off); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(-1, op, 0, off); } @@ -2199,14 +2234,29 @@ svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop) { bool first = true; bool got_one = false; - int k, res; - int max_pn = 255; + int k, res, start; + int max_pn; int any_err = 0; char b[80]; - if (op->vpd_pn > 0) - max_pn = op->vpd_pn; - for (k = op->examine > 1 ? 0 : 0x80; k <= max_pn; ++k) { + max_pn = (op->page_given ? op->vpd_pn : 0xff); + switch (op->examine) { + case 1: + start = 0x80; + break; + case 2: + start = 0x0; + break; + default: + start = 0xc0; + break; + } + if (start > max_pn) { /* swap them around */ + k = start; + start = max_pn; + max_pn = k; + } + for (k = start; k <= max_pn; ++k) { op->vpd_pn = k; if (first) first = false; @@ -2220,7 +2270,7 @@ svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop) b[0] = '\0'; res = svpd_decode_t10(sg_fd, op, jop, 0, 0, b); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(sg_fd, op, 0); + res = svpd_decode_vendor(sg_fd, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(sg_fd, op, 0, 0); } @@ -2279,6 +2329,7 @@ main(int argc, char * argv[]) break; case 'E': ++op->examine; + op->examine_given = true; break; case 'f': op->do_force = true; @@ -2646,7 +2697,7 @@ main(int argc, char * argv[]) else { res = svpd_decode_t10(-1, op, jop, subvalue, 0, NULL); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(-1, op, 0); + res = svpd_decode_vendor(-1, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(-1, op, subvalue, 0); } @@ -2679,7 +2730,7 @@ main(int argc, char * argv[]) goto err_out; } - if (op->examine > 0) { + if (op->examine_given) { ret = svpd_examine_all(sg_fd, op, jop); } else if (op->do_all) ret = svpd_decode_all(sg_fd, op, jop); @@ -2688,7 +2739,7 @@ main(int argc, char * argv[]) res = svpd_decode_t10(sg_fd, op, jop, subvalue, 0, NULL); if (SG_LIB_CAT_OTHER == res) { - res = svpd_decode_vendor(sg_fd, op, 0); + res = svpd_decode_vendor(sg_fd, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(sg_fd, op, subvalue, 0); } diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c index 98e798fb..14b1bd2d 100644 --- a/src/sg_vpd_common.c +++ b/src/sg_vpd_common.c @@ -28,6 +28,7 @@ #endif #include "sg_lib.h" +#include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" @@ -47,9 +48,13 @@ static const char * const y_s = "yes"; static const char * const n_s = "no"; static const char * const nl_s = "no limit"; static const char * const nlr_s = "no limit reported"; -static const char * const nr_s = "not reported"; +/* Earlier gcc compilers (e.g. 6.4) don't accept this first form when it is + * used in another array of strings initialization (e.g. bdc_zoned_strs) */ +// static const char * const nr_s = "not reported"; +static char nr_s[] = "not reported"; static const char * const ns_s = "not supported"; -static const char * const rsv_s = "Reserved"; +// static const char * const rsv_s = "Reserved"; +static char rsv_s[] = "Reserved"; static const char * const vs_s = "Vendor specific"; static const char * const null_s = ""; static const char * const mn_s = "meaning"; @@ -310,13 +315,13 @@ static const char * network_service_type_arr[] = /* VPD_MAN_NET_ADDR 0x85 ["mna"] */ void -decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_net_man_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, na_len, assoc, nst; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; - uint8_t * bp; + const uint8_t * bp; const char * assoc_str; const char * nst_str; @@ -366,7 +371,7 @@ decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_EXT_INQ Extended Inquiry VPD ["ei"] */ void -decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op, +decode_x_inq_vpd(const uint8_t * b, int len, bool protect, struct opts_t * op, sgj_opaque_p jop) { bool do_long_nq = op->do_long && (! op->do_quiet); @@ -431,6 +436,10 @@ decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op, cp = "protection types 1, 2 and 3 supported"; break; } + } else if (op->protect_not_sure) { + cp = "Unsure because unable to read PROTECT bit in standard " + "INQUIRY response"; + d[0] = '\0'; } else { cp = "none"; d[0] = '\0'; @@ -620,7 +629,7 @@ decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op, /* VPD_SOFTW_INF_ID 0x84 */ void -decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op, +decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { sgj_state * jsp = &op->json_st; @@ -654,13 +663,13 @@ static const char * mode_page_policy_arr[] = /* VPD_MODE_PG_POLICY 0x87 ["mpp"] */ void -decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, n, bump, ppc, pspc; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; - uint8_t * bp; + const uint8_t * bp; char b[128]; static const int blen = sizeof(b); @@ -712,7 +721,7 @@ decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_POWER_CONDITION 0x8a ["pc"] */ void -decode_power_condition(uint8_t * buff, int len, struct opts_t * op, +decode_power_condition(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { sgj_state * jsp = &op->json_st; @@ -884,13 +893,13 @@ decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op, /* VPD_SCSI_FEATURE_SETS 0x92 ["sfs"] */ void -decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump; uint16_t sf_code; bool found; - uint8_t * bp; + const uint8_t * bp; sgj_opaque_p jo2p; sgj_state * jsp = &op->json_st; char b[256]; @@ -1061,6 +1070,38 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op, } /* end Constituent descriptor loop */ } +/* VPD_CFA_PROFILE_INFO 0x8c ["cfa"] */ +void +decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jap) +{ + int k; + uint32_t u; + sgj_state * jsp = &op->json_st; + const uint8_t * bp; + sgj_opaque_p jo2p; + + if (op->do_hex) { + hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + return; + } + if (len < 4) { + pr2serr("VPD page length too short=%d\n", len); + return; + } + len -= 4; + bp = buff + 4; + for (k = 0; k < len; k += 4, bp += 4) { + jo2p = sgj_new_unattached_object_r(jsp); + sgj_haj_vi(jsp, jo2p, 0, "CGA profile supported", + SGJ_SEP_COLON_1_SPACE, bp[0], true); + u = sg_get_unaligned_be16(bp + 2); + sgj_haj_vi_nex(jsp, jo2p, 2, "Sequential write data size", + SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); + sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); + } +} + /* Assume index is less than 16 */ static const char * sg_ansi_version_arr[16] = { @@ -1205,14 +1246,14 @@ static const char * power_unit_arr[] = /* VPD_POWER_CONSUMPTION 0x8d ["psm"] */ void -decode_power_consumption(uint8_t * buff, int len, struct opts_t * op, +decode_power_consumption(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, pcmp_id, pcmp_unit; unsigned int pcmp_val; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; - uint8_t * bp; + const uint8_t * bp; char b[128]; static const int blen = sizeof(b); static const char * pcmp = "power_consumption"; @@ -1590,7 +1631,7 @@ static const char * prov_type_arr[8] = { /* VPD_LB_PROVISIONING 0xb2 ["lbpv"] */ int -decode_block_lb_prov_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_block_lb_prov_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { unsigned int u, dp, pt, t_exp; @@ -1678,7 +1719,7 @@ decode_block_lb_prov_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_REFERRALS 0xb3 ["ref"] */ void -decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint32_t u; @@ -1703,12 +1744,12 @@ decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_SUP_BLOCK_LENS 0xb4 ["sbl"] (added sbc4r01) */ void -decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_sup_block_lens_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k; unsigned int u; - uint8_t * bp; + const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; @@ -1750,8 +1791,8 @@ decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_BLOCK_DEV_C_EXTENS 0xb5 ["bdce"] (added sbc4r02) */ void -decode_block_dev_char_ext_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jop) +decode_block_dev_char_ext_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jop) { bool b_active = false; bool combined = false; @@ -1838,8 +1879,8 @@ decode_block_dev_char_ext_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_ZBC_DEV_CHARS 0xb6 ["zdbch"] sbc or zbc [zbc2r04] */ void -decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jop) +decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop) { uint32_t u, pdt; sgj_state * jsp = &op->json_st; @@ -1923,7 +1964,7 @@ decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_BLOCK_LIMITS_EXT 0xb7 ["ble"] SBC */ void -decode_block_limits_ext_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_block_limits_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint32_t u; @@ -2000,7 +2041,7 @@ get_zone_align_method(uint8_t val, char * b, int blen) /* VPD_FORMAT_PRESETS 0xb8 ["fp"] (added sbc4r18) */ void -decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_format_presets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { uint8_t sch_type; @@ -2008,7 +2049,7 @@ decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op, uint32_t u; uint64_t ul; sgj_state * jsp = &op->json_st; - uint8_t * bp; + const uint8_t * bp; sgj_opaque_p jo2p, jo3p; const char * cp; char b[128]; @@ -2149,13 +2190,13 @@ decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op, /* VPD_CON_POS_RANGE 0xb9 (added sbc5r01) */ void -decode_con_pos_range_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_con_pos_range_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k; uint32_t u; sgj_state * jsp = &op->json_st; - uint8_t * bp; + const uint8_t * bp; sgj_opaque_p jo2p; if (op->do_hex) { @@ -2426,8 +2467,8 @@ get_tpc_desc_type_s(uint32_t desc_type) /* VPD_3PARTY_COPY 3PC, third party copy 0x8f ["tpc"] */ void -decode_3party_copy_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jap) +decode_3party_copy_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jap) { int j, k, m, bump, desc_type, desc_len, sa_len, pdt; uint32_t u, v; @@ -2726,11 +2767,11 @@ skip: /* VPD_PROTO_LU 0x90 ["pslu"] */ void -decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, rel_port, desc_len, proto; - uint8_t * bp; + const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[128]; @@ -2764,10 +2805,10 @@ decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op, return; } if (0 == desc_len) - goto again;; + goto again; if (2 == op->do_hex) { hex2stdout(bp + 8, desc_len, 1); - goto again;; + goto again; } switch (proto) { case TPROTO_SAS: @@ -2786,13 +2827,13 @@ again: /* VPD_PROTO_PORT 0x91 ["pspo"] */ void -decode_proto_port_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { bool pds, ssp_pers; int k, j, bump, rel_port, desc_len, proto, phy; - uint8_t * bp; - uint8_t * pidp; + const uint8_t * bp; + const uint8_t * pidp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p ja2p = NULL; @@ -2862,3 +2903,91 @@ again: sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } + +/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */ +void +decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jap) +{ + int k, bump; + const uint8_t * bp; + sgj_state * jsp = &op->json_st; + sgj_opaque_p jo2p = NULL; + + if ((1 == op->do_hex) || (op->do_hex > 2)) { + hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1); + return; + } + if (len < 8) { + pr2serr("VPD page length too short=%d\n", len); + return; + } + len -= 8; + bp = buff + 8; + for (k = 0; k < len; k += bump, bp += bump) { + jo2p = sgj_new_unattached_object_r(jsp); + bump = 1 + bp[0]; + sgj_pr_hr(jsp, " method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, " + "RBDP_C=%d\n", bp[1], 0x3f & bp[2], !!(0x80 & bp[3]), + !!(0x40 & bp[3]), !!(0x20 & bp[3])); + sgj_js_nv_ihex(jsp, jo2p, "logical_block_protection_method", bp[1]); + sgj_js_nv_ihex_nex(jsp, jo2p, + "logical_block_protection_information_length", + 0x3f & bp[2], true, "unit: byte"); + sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_w_c", !!(0x80 & bp[3]), false, + "Logical Blocks Protected during Write supported"); + sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_r_c", !!(0x40 & bp[3]), false, + "Logical Blocks Protected during Read supported"); + sgj_js_nv_ihex_nex(jsp, jo2p, "rbdp_c", !!(0x20 & bp[3]), false, + "Recover Buffered Data Protected supported"); + if ((k + bump) > len) { + pr2serr("Logical block protection VPD page, short " + "descriptor length=%d, left=%d\n", bump, (len - k)); + sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); + return; + } + sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); + } +} + +/* VPD_TA_SUPPORTED 0xb2 ["tas"] */ +void +decode_tapealert_supported_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jop) +{ + bool have_ta_strs = !! sg_lib_tapealert_strs[0]; + int k, mod, div, n; + unsigned int supp; + sgj_state * jsp = &op->json_st; + char b[144]; + char d[64]; + static const int blen = sizeof(b); + + if (len < 12) { + pr2serr("VPD page length too short=%d\n", len); + return; + } + b[0] ='\0'; + for (k = 1, n = 0; k < 0x41; ++k) { + mod = ((k - 1) % 8); + div = (k - 1) / 8; + supp = !! (buff[4 + div] & (1 << (7 - mod))); + if (jsp->pr_as_json) { + snprintf(d, sizeof(d), "flag%02xh", k); + if (have_ta_strs) + sgj_js_nv_ihex_nex(jsp, jop, d, supp, false, + sg_lib_tapealert_strs[k]); + else + sgj_js_nv_i(jsp, jop, d, supp); + } + if (0 == mod) { + if (div > 0) { + sgj_pr_hr(jsp, "%s\n", b); + n = 0; + } + n += sg_scnpr(b + n, blen - n, " Flag%02Xh: %d", k, supp); + } else + n += sg_scnpr(b + n, blen - n, " %02Xh: %d", k, supp); + } + sgj_pr_hr(jsp, "%s\n", b); +} diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h index 722da1fd..50cdb48a 100644 --- a/src/sg_vpd_common.h +++ b/src/sg_vpd_common.h @@ -136,8 +136,10 @@ struct opts_t { bool do_force; /* sg_inq + sg_vpd */ bool do_only; /* sg_inq: --only after stdinq: don't fetch VPD page 0x80 */ bool do_quiet; /* sg_vpd */ + bool examine_given; /* sg_vpd */ bool page_given; /* sg_inq + sg_vpd */ bool possible_nvme; /* sg_inq */ + bool protect_not_sure; /* sg_vpd */ bool verbose_given; /* sg_inq + sg_vpd */ bool version_given; /* sg_inq + sg_vpd */ bool do_vpd; /* sg_inq */ @@ -189,62 +191,71 @@ typedef int (*recurse_vpd_decodep)(struct opts_t *, sgj_opaque_p jop, int off); sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name, const uint8_t * vpd_hdrp); -void decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_net_man_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); -void decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op, - sgj_opaque_p jop); -void decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op, +void decode_x_inq_vpd(const uint8_t * b, int len, bool protect, + struct opts_t * op, sgj_opaque_p jop); +void decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); -void decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); -void decode_power_condition(uint8_t * buff, int len, struct opts_t * op, +void decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jap); +void decode_power_condition(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); int filter_json_dev_ids(uint8_t * buff, int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap); void decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap, recurse_vpd_decodep fp); sgj_opaque_p std_inq_decode_js(const uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_power_consumption(uint8_t * buff, int len, +void decode_power_consumption(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_block_dev_ch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -int decode_block_lb_prov_vpd(uint8_t * buff, int len, +int decode_block_lb_prov_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jap); -void decode_block_dev_char_ext_vpd(uint8_t * buff, int len, +void decode_sup_block_lens_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jap); +void decode_block_dev_char_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); -void decode_block_limits_ext_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jop); -void decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jap); -void decode_con_pos_range_vpd(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jap); -void decode_3party_copy_vpd(uint8_t * buff, int len, struct opts_t * op, +void decode_block_limits_ext_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jop); +void decode_format_presets_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jap); +void decode_con_pos_range_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jap); +void decode_3party_copy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void -decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void -decode_proto_port_vpd(uint8_t * buff, int len, struct opts_t * op, +decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); +void +decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jap); +void +decode_tapealert_supported_vpd(const uint8_t * buff, int len, + struct opts_t * op, sgj_opaque_p jop); const char * pqual_str(int pqual); void svpd_enumerate_vendor(int vend_prod_num); int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num); -int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off); +int svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, + int off); const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap); int svpd_find_vp_num_by_acron(const char * vp_ap); const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num, diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c index 23df1442..5cfc7ee3 100644 --- a/src/sg_vpd_vendor.c +++ b/src/sg_vpd_vendor.c @@ -92,10 +92,6 @@ #define VPD_V_HIT_PG_D1 0xd1 #define VPD_V_HIT_PG_D2 0xd2 -#ifndef SG_NVME_VPD_NICR -#define SG_NVME_VPD_NICR 0xde /* NVME Identify Controller Response */ -#endif - #define DEF_ALLOC_LEN 252 #define MX_ALLOC_LEN (0xc000 + 0x80) @@ -115,6 +111,17 @@ dup_sanity_chk(int sz_opts_t, int sz_values_name_t) sz_values_name_t); } +static int +no_ascii_4hex(const struct opts_t * op) +{ + if (op->do_hex < 2) + return 1; + else if (2 == op->do_hex) + return 0; + else + return -1; +} + static bool is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp) { @@ -1227,15 +1234,20 @@ decode_vpd_d2_hit(uint8_t * b, int blen) /* Returns 0 if successful, see sg_ll_inquiry() plus SG_LIB_CAT_OTHER for unsupported page */ int -svpd_decode_vendor(int sg_fd, struct opts_t * op, int off) +svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) { - int len, res; - char name[64]; - const struct svpd_values_name_t * vnp; + bool hex0 = (0 == op->do_hex); + int len, pdt, plen, pn; int alloc_len = op->maxlen; + int res = 0; + const struct svpd_values_name_t * vnp; + sgj_state * jsp = &op->json_st; + sgj_opaque_p jo2p; uint8_t * rp; + char name[80]; - switch (op->vpd_pn) { + pn = op->vpd_pn; + switch (pn) { /* VPD codes that we support vendor pages for */ case 0x3: case 0xc0: case 0xc1: @@ -1249,6 +1261,7 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off) case 0xd0: case 0xd1: case 0xd2: + case 0xde: break; default: /* not known so return prior to fetching page */ return SG_LIB_CAT_OTHER; @@ -1258,135 +1271,195 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off) if (0 == alloc_len) alloc_len = DEF_ALLOC_LEN; } - res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, alloc_len, op->do_quiet, - op->verbose, &len); - if (0 == res) { - vnp = svpd_get_v_detail(op->vpd_pn, op->vend_prod_num, 0xf & rp[0]); - if (vnp && vnp->name) - snprintf(name, sizeof(name), "%s", vnp->name); - else - snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", - op->vpd_pn); - if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 2)) - printf("%s VPD Page:\n", name); - if (op->do_raw) - dStrRaw(rp, len); - else if (op->do_hex) - hex2stdout(rp, len, ((1 == op->do_hex) ? 0 : -1)); - else { - switch(op->vpd_pn) { - case 0x3: - if (VPD_VP_WDC_HITACHI == op->vend_prod_num) - decode_vpd_3_hit(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xc0: - if (VPD_VP_SEAGATE == op->vend_prod_num) - decode_firm_vpd_c0_sea(rp, len); - else if (VPD_VP_EMC == op->vend_prod_num) - decode_upr_vpd_c0_emc(rp, len); - else if (VPD_VP_HP3PAR == op->vend_prod_num) - decode_vpd_c0_hp3par(rp, len); - else if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c0(rp, len); - else if (VPD_VP_DDS == op->vend_prod_num) - decode_dds_vpd_c0(rp, len); - else if (VPD_VP_IBM_LTO == op->vend_prod_num) - decode_ibm_lto_dcrl(rp, len); - else if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc1: - if (VPD_VP_SEAGATE == op->vend_prod_num) - decode_date_code_vpd_c1_sea(rp, len); - else if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c1(rp, len); - else if (VPD_VP_IBM_LTO == op->vend_prod_num) - decode_ibm_lto_dsn(rp, len); - else if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc2: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c2(rp, len); - else if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc3: - if (VPD_VP_SEAGATE == op->vend_prod_num) - decode_dev_beh_vpd_c3_sea(rp, len); - else if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c3(rp, len); - else if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc4: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c4(rp, len); - else if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc5: - if (VPD_VP_HP_LTO == op->vend_prod_num) - decode_hp_lto_vpd_cx(rp, len, op->vpd_pn); - else - hex2stdout(rp, len, 0); - break; - case 0xc8: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c8(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xc9: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_c9(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xca: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_ca(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xd0: - if (VPD_VP_RDAC == op->vend_prod_num) - decode_rdac_vpd_d0(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xd1: - if (VPD_VP_WDC_HITACHI == op->vend_prod_num) - decode_vpd_d1_hit(rp, len); - else - hex2stdout(rp, len, 0); - break; - case 0xd2: - if (VPD_VP_WDC_HITACHI == op->vend_prod_num) - decode_vpd_d2_hit(rp, len); - else - hex2stdout(rp, len, 0); + res = vpd_fetch_page(sg_fd, rp, pn, alloc_len, op->do_quiet, op->verbose, + &len); + if (res) { + pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn); + return res; + } + pdt = rp[0] & PDT_MASK; + vnp = svpd_get_v_detail(pn, op->vend_prod_num, pdt); + if (vnp && vnp->name) + snprintf(name, sizeof(name), "%s", vnp->name); + else + snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", pn); + if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) + sgj_pr_hr(jsp, "%s VPD Page:\n", name); + if (op->do_raw) + dStrRaw(rp, len); + else { + switch(pn) { + case 0x3: + if (hex0 && (VPD_VP_WDC_HITACHI == op->vend_prod_num)) + decode_vpd_3_hit(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc0: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_SEAGATE == op->vend_prod_num) + decode_firm_vpd_c0_sea(rp, len); + else if (VPD_VP_EMC == op->vend_prod_num) + decode_upr_vpd_c0_emc(rp, len); + else if (VPD_VP_HP3PAR == op->vend_prod_num) + decode_vpd_c0_hp3par(rp, len); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c0(rp, len); + else if (VPD_VP_DDS == op->vend_prod_num) + decode_dds_vpd_c0(rp, len); + else if (VPD_VP_IBM_LTO == op->vend_prod_num) + decode_ibm_lto_dcrl(rp, len); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc1: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_SEAGATE == op->vend_prod_num) + decode_date_code_vpd_c1_sea(rp, len); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c1(rp, len); + else if (VPD_VP_IBM_LTO == op->vend_prod_num) + decode_ibm_lto_dsn(rp, len); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc2: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c2(rp, len); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc3: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_SEAGATE == op->vend_prod_num) + decode_dev_beh_vpd_c3_sea(rp, len); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c3(rp, len); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc4: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c4(rp, len); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc5: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_HP_LTO == op->vend_prod_num) + decode_hp_lto_vpd_cx(rp, len, pn); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc8: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c8(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xc9: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_c9(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xca: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_ca(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xd0: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_RDAC == op->vend_prod_num) + decode_rdac_vpd_d0(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xd1: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_WDC_HITACHI == op->vend_prod_num) + decode_vpd_d1_hit(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case 0xd2: + if (! hex0) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (VPD_VP_WDC_HITACHI == op->vend_prod_num) + decode_vpd_d2_hit(rp, len); + else + res = SG_LIB_CAT_OTHER; + break; + case SG_NVME_VPD_NICR: /* 0xde */ + if (VPD_VP_SG != op->vend_prod_num) { + res = SG_LIB_CAT_OTHER; + break; + } + /* NVMe: Identify Controller data structure (CNS 01h) */ + plen = sg_get_unaligned_be16(rp + 2) + 4; + if (plen > len) { /* fetch the whole page */ + res = vpd_fetch_page(sg_fd, rp, pn, plen, + op->do_quiet, op->verbose, &len); + if (res) { + pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn); + return res; + } + } + if (len < 16) { + pr2serr("%s expected to be > 15 bytes long (got: %d)\n", + name, len); + break; + } else { + int n = len - 16; + + if (n > 4096) { + pr2serr("NVMe Identify response expected to be " + "<= 4096 bytes (got: %d)\n", n); break; - default: - pr2serr("%s: logic error, should know can't decode " - "pn=0x%x\n", __func__, op->vpd_pn); - return SG_LIB_CAT_OTHER; + } + if (op->do_hex) + hex2stdout(rp, len, no_ascii_4hex(op)); + else if (jsp->pr_as_json) { + jo2p = sg_vpd_js_hdr(jsp, jop, name, rp); + sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", + rp + 16, n); + } else + hex2stdout(rp + 16, n, 1); } - return 0; + break; + default: + res = SG_LIB_CAT_OTHER; } - } else - pr2serr("Vendor VPD page=0x%x failed to fetch\n", op->vpd_pn); + } + if (res && op->verbose) + pr2serr("%s: can't decode pn=0x%x, vend_prod_num=%d\n", __func__, + pn, op->vend_prod_num); return res; } |