diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2022-09-18 02:14:13 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2022-09-18 02:14:13 +0000 |
commit | ccefa8190c1f38cb71384bcdd786599db7de570a (patch) | |
tree | a4f0c0db16e15ce55ed98460635040b755a26cf3 /src | |
parent | eda37108f2a83c7944b1c0f63162647eddc9960d (diff) | |
download | sg3_utils-ccefa8190c1f38cb71384bcdd786599db7de570a.tar.gz |
sg_inq+sg_vpd: ongoing JSON updates
Probably at the end of the JSON work for sg_inq since
it only has four vendor specific VPD pages. sg_vpd has
a lot more vendor specific VPD pages which are yet to
be 'jsonified'.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@971 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.in | 4 | ||||
-rw-r--r-- | src/sg_inq.c | 218 | ||||
-rw-r--r-- | src/sg_sat_read_gplog.c | 4 | ||||
-rw-r--r-- | src/sg_vpd.c | 23 | ||||
-rw-r--r-- | src/sg_vpd_common.c | 512 | ||||
-rw-r--r-- | src/sg_vpd_common.h | 12 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 227 |
8 files changed, 576 insertions, 426 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f75bc7cb..95144625 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -93,7 +93,7 @@ sg_ident_LDADD = ../lib/libsgutils2.la sginfo_LDADD = ../lib/libsgutils2.la -sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_vendor.c sg_vpd_common.c +sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c sg_inq_LDADD = ../lib/libsgutils2.la sg_logs_LDADD = ../lib/libsgutils2.la diff --git a/src/Makefile.in b/src/Makefile.in index c5217b1e..96880766 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -188,7 +188,7 @@ sg_ident_SOURCES = sg_ident.c sg_ident_OBJECTS = sg_ident.$(OBJEXT) sg_ident_DEPENDENCIES = ../lib/libsgutils2.la am_sg_inq_OBJECTS = sg_inq.$(OBJEXT) sg_inq_data.$(OBJEXT) \ - sg_vpd_vendor.$(OBJEXT) sg_vpd_common.$(OBJEXT) + sg_vpd_common.$(OBJEXT) sg_inq_OBJECTS = $(am_sg_inq_OBJECTS) sg_inq_DEPENDENCIES = ../lib/libsgutils2.la sg_logs_SOURCES = sg_logs.c @@ -682,7 +682,7 @@ sg_get_elem_status_LDADD = ../lib/libsgutils2.la sg_get_lba_status_LDADD = ../lib/libsgutils2.la sg_ident_LDADD = ../lib/libsgutils2.la sginfo_LDADD = ../lib/libsgutils2.la -sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_vendor.c sg_vpd_common.c +sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c sg_inq_LDADD = ../lib/libsgutils2.la sg_logs_LDADD = ../lib/libsgutils2.la sg_luns_LDADD = ../lib/libsgutils2.la diff --git a/src/sg_inq.c b/src/sg_inq.c index edd571c7..8a9b43e2 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.30 20220904"; /* spc6r06, sbc5r03 */ +static const char * version_str = "2.31 20220915"; /* spc6r06, sbc5r03 */ #define MY_NAME "sg_inq" @@ -1122,17 +1122,6 @@ 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, sgj_opaque_p jap) @@ -2089,185 +2078,7 @@ decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) } } -static const char * lun_state_arr[] = -{ - "LUN not bound or LUN_Z report", - "LUN bound, but not owned by this SP", - "LUN bound and owned by this SP", -}; - -static const char * ip_mgmt_arr[] = -{ - "No IP access", - "Reserved (undefined)", - "via IPv4", - "via IPv6", -}; - -static const char * sp_arr[] = -{ - "SP A", - "SP B", -}; - -static const char * lun_op_arr[] = -{ - "Normal operations", - "I/O Operations being rejected, SP reboot or NDU in progress", -}; - -static const char * failover_mode_arr[] = -{ - "Legacy mode 0", - "Unknown mode (1)", - "Unknown mode (2)", - "Unknown mode (3)", - "Active/Passive (PNR) mode 1", - "Unknown mode (5)", - "Active/Active (ALUA) mode 4", - "Unknown mode (7)", - "Legacy mode 2", - "Unknown mode (9)", - "Unknown mode (10)", - "Unknown mode (11)", - "Unknown mode (12)", - "Unknown mode (13)", - "AIX Active/Passive (PAR) mode 3", - "Unknown mode (15)", -}; - -static void -decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op, - sgj_opaque_p jop) -{ - uint8_t uc; - int k, n, ip_mgmt, vpp80, lun_z; - sgj_state * jsp = &op->json_st; - const char * cp; - char b[256]; - static const int blen = sizeof(b); - - if (len < 3) { - pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); - return; - } - if (op->do_hex) { - hex2stdout(buff, len, no_ascii_4hex(op)); - return; - } - if (buff[9] != 0x00) { - pr2serr("Unsupported page revision %d, decoding not possible.\n", - buff[9]); - return; - } - for (k = 0, n = 0; k < 16; ++k) - n += sg_scnpr(b + n, blen - n, "%02x", buff[10 + k]); - sgj_haj_vs(jsp, jop, 2, "LUN WWN", SGJ_SEP_COLON_1_SPACE, b); - snprintf(b, blen, "%.*s", buff[49], buff + 50); - sgj_haj_vs(jsp, jop, 2, "Array Serial Number", SGJ_SEP_COLON_1_SPACE, b); - - if (buff[4] > 0x02) - snprintf(b, blen, "Unknown (%x)", buff[4]); - else - snprintf(b, blen, "%s", lun_state_arr[buff[4]]); - sgj_haj_vistr(jsp, jop, 2, "LUN State", SGJ_SEP_COLON_1_SPACE, - buff[4], true, b); - - uc = buff[8]; - n = 0; - if (uc > 0x01) - n += sg_scnpr(b + n, blen - n, "Unknown SP (%x)", uc); - else - n += sg_scnpr(b + n, blen - n, "%s", sp_arr[uc]); - sgj_js_nv_ihexstr(jsp, jop, "path_connects_to", uc, NULL, b); - n += sg_scnpr(b + n, blen - n, ", Port Number: %u", buff[7]); - sgj_pr_hr(jsp, " This path connects to: %s\n", b); - sgj_js_nv_ihex(jsp, jop, "port_number", buff[7]); - - if (buff[5] > 0x01) - snprintf(b, blen, "Unknown (%x)\n", buff[5]); - else - snprintf(b, blen, "%s\n", sp_arr[buff[5]]); - sgj_haj_vistr(jsp, jop, 2, "Default owner", SGJ_SEP_COLON_1_SPACE, - buff[5], true, b); - - cp = (buff[6] & 0x40) ? "supported" : "not supported"; - sgj_pr_hr(jsp, " NO_ATF: %s, Access Logix: %s\n", - buff[6] & 0x80 ? "set" : "not set", cp); - sgj_js_nv_i(jsp, jop, "no_atf", !! (buff[6] & 0x80)); - sgj_js_nv_istr(jsp, jop, "access_logix", !! (buff[6] & 0x40), - NULL, cp); - - ip_mgmt = (buff[6] >> 4) & 0x3; - cp = ip_mgmt_arr[ip_mgmt]; - sgj_pr_hr(jsp, " SP IP Management Mode: %s\n", cp); - sgj_js_nv_istr(jsp, jop, "sp_ip_management_mode", !! ip_mgmt, - NULL, cp); - if (ip_mgmt == 2) { - snprintf(b, blen, "%u.%u.%u.%u", buff[44], buff[45], buff[46], - buff[47]); - sgj_pr_hr(jsp, " SP IPv4 address: %s\n", b); - sgj_js_nv_s(jsp, jop, "sp_ipv4_address", b); - } else if (ip_mgmt == 3) { - printf(" SP IPv6 address: "); - n = 0; - for (k = 0; k < 16; ++k) - n += sg_scnpr(b + n, blen - n, "%02x", buff[32 + k]); - sgj_pr_hr(jsp, " SP IPv6 address: %s\n", b); - sgj_js_nv_hex_bytes(jsp, jop, "sp_ipv6_address", buff + 32, 16); - } - -// yyyyyyy more conversion work needed below this point - vpp80 = buff[30] & 0x08; - lun_z = buff[30] & 0x04; - - printf(" System Type: %x, Failover mode: %s\n", - buff[27], failover_mode_arr[buff[28] & 0x0f]); - - printf(" Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", - vpp80 ? "array serial#" : "LUN serial#", - lun_z ? "Set to 1" : "Unknown"); - - printf(" Lun operations: %s\n", - buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]); - - return; -} - -static void -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 (op->do_hex) { - hex2stdout(buff, len, no_ascii_4hex(op)); - return; - } - if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { - pr2serr("Invalid page identifier %c%c%c%c, decoding " - "not possible.\n" , buff[4], buff[5], buff[6], buff[7]); - return; - } - printf(" Software Version: %02x.%02x.%02x\n", buff[8], buff[9], buff[10]); - printf(" Software Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); - printf(" Features:"); - if (buff[14] & 0x01) - printf(" Dual Active,"); - if (buff[14] & 0x02) - printf(" Series 3,"); - if (buff[14] & 0x04) - printf(" Multiple Sub-enclosures,"); - if (buff[14] & 0x08) - printf(" DCE/DRM/DSS/DVE,"); - if (buff[14] & 0x10) - printf(" Asymmetric Logical Unit Access,"); - printf("\n"); - printf(" Max. #of LUNS: %d\n", buff[15]); - return; -} - +#if 0 static void decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor) { @@ -2440,6 +2251,7 @@ decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op) return; } +#endif extern const char * sg_ansi_version_arr[]; @@ -3840,7 +3652,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; /* Vendor specific VPD pages (>= 0xc0) */ case VPD_UPR_EMC: /* 0xc0 */ - np = "Block device characteristics VPD page"; + np = "Unit path report VPD page"; ep = "(EMC)"; if (!op->do_raw && (op->do_hex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); @@ -3856,26 +3668,36 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) } break; case VPD_RDAC_VERS: /* 0xc2 */ + np = "Software Version VPD page"; + ep = "(RDAC)"; if (!op->do_raw && (op->do_hex < 3)) - printf("VPD INQUIRY: Software Version (RDAC)\n"); + sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); - else - decode_rdac_vpd_c2(rp, len, op); + else { + if (as_json) + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); + decode_rdac_vpd_c2(rp, len, op, jo2p); + } break; case VPD_RDAC_VAC: /* 0xc9 */ + np = "Volume access control VPD page"; + ep = "(RDAC)"; if (!op->do_raw && (op->do_hex < 3)) - printf("VPD INQUIRY: Volume Access Control (RDAC)\n"); + sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); - else - decode_rdac_vpd_c9(rp, len, op); + else { + if (as_json) + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); + decode_rdac_vpd_c9(rp, len, op, jo2p); + } break; case SG_NVME_VPD_NICR: /* 0xde */ np = "NVMe Identify Controller Response VPD page"; diff --git a/src/sg_sat_read_gplog.c b/src/sg_sat_read_gplog.c index a1afc828..55c164eb 100644 --- a/src/sg_sat_read_gplog.c +++ b/src/sg_sat_read_gplog.c @@ -54,7 +54,7 @@ #define DEF_TIMEOUT 20 -static const char * version_str = "1.22 20220425"; +static const char * version_str = "1.23 20220917"; struct opts_t { bool ck_cond; @@ -124,7 +124,7 @@ usage() } static int -do_read_gplog(int sg_fd, int ata_cmd, uint8_t *inbuff, +do_read_gplog(int sg_fd, int ata_cmd, uint8_t * inbuff, const struct opts_t * op) { const bool extend = true; diff --git a/src/sg_vpd.c b/src/sg_vpd.c index 707d3e12..35de6ca4 100644 --- a/src/sg_vpd.c +++ b/src/sg_vpd.c @@ -42,7 +42,7 @@ */ -static const char * version_str = "1.82 20220826"; /* spc6r06 + sbc5r03 */ +static const char * version_str = "1.83 20220915"; /* spc6r06 + sbc5r03 */ #define MY_NAME "sg_vpd" @@ -444,17 +444,6 @@ 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) @@ -1100,16 +1089,6 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off) } } 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) - hex2stdout(rp, len, 0); - else if (1 == op->do_hex) - hex2stdout(rp, len, (op->do_long ? 0 : 1)); - else - hex2stdout(rp, len, 0); -#endif } } else if ((! op->do_quiet) && (! op->examine_given)) { if (op->vpd_pn >= 0) diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c index dcc7727b..31c74ea0 100644 --- a/src/sg_vpd_common.c +++ b/src/sg_vpd_common.c @@ -132,6 +132,17 @@ struct svpd_values_name_t vendor_vpd_pg[] = { 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; +} + +int svpd_find_vp_num_by_acron(const char * vp_ap) { size_t len; @@ -696,9 +707,9 @@ decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op, n = 0; ppc = (bp[0] & 0x3f); pspc = bp[1]; - n = snprintf(b + n, blen - n, " Policy page code: 0x%x", ppc); + n = sg_scnpr(b + n, blen - n, " Policy page code: 0x%x", ppc); if (pspc) - n += snprintf(b + n, blen - n, ", subpage code: 0x%x", pspc); + n += sg_scnpr(b + n, blen - n, ", subpage code: 0x%x", pspc); sgj_pr_hr(jsp, "%s\n", b); if ((0 == k) && (0x3f == (0x3f & bp[0])) && (0xff == bp[1])) sgj_pr_hr(jsp, " therefore the policy applies to all modes " @@ -839,7 +850,7 @@ decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op, ata_transp); cc = buff[56]; /* 0xec for IDENTIFY DEVICE and 0xa1 for IDENTIFY * PACKET DEVICE (obsolete) */ - n = snprintf(b, blen, " Command code: 0x%x\n", cc); + n = sg_scnpr(b, blen, " Command code: 0x%x\n", cc); if (len < 60) return; if (0xec == cc) @@ -2993,3 +3004,498 @@ decode_tapealert_supported_vpd(const uint8_t * buff, int len, } sgj_pr_hr(jsp, "%s\n", b); } + +/* + * Some of the vendor specific VPD pages are common as well. So place them here + * to save on code duplication. + */ + +static const char * lun_state_arr[] = +{ + "LUN not bound or LUN_Z report", + "LUN bound, but not owned by this SP", + "LUN bound and owned by this SP", +}; + +static const char * ip_mgmt_arr[] = +{ + "No IP access", + "Reserved (undefined)", + "via IPv4", + "via IPv6", +}; + +static const char * sp_arr[] = +{ + "SP A", + "SP B", +}; + +static const char * lun_op_arr[] = +{ + "Normal operations", + "I/O Operations being rejected, SP reboot or NDU in progress", +}; + +static const char * failover_mode_arr[] = +{ + "Legacy mode 0", + "Unknown mode (1)", + "Unknown mode (2)", + "Unknown mode (3)", + "Active/Passive (PNR) mode 1", + "Unknown mode (5)", + "Active/Active (ALUA) mode 4", + "Unknown mode (7)", + "Legacy mode 2", + "Unknown mode (9)", + "Unknown mode (10)", + "Unknown mode (11)", + "Unknown mode (12)", + "Unknown mode (13)", + "AIX Active/Passive (PAR) mode 3", + "Unknown mode (15)", +}; + +/* VPD_UPR_EMC,VPD_V_UPR_EMC 0xc0 ["upr","upr"] */ +void +decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop) +{ + uint8_t uc; + int k, n, ip_mgmt, vpp80, lun_z; + sgj_state * jsp = &op->json_st; + const char * cp; + const char * c2p; + char b[256]; + static const int blen = sizeof(b); + + if (len < 3) { + pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); + return; + } + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); + return; + } + if (buff[9] != 0x00) { + pr2serr("Unsupported page revision %d, decoding not possible.\n", + buff[9]); + return; + } + for (k = 0, n = 0; k < 16; ++k) + n += sg_scnpr(b + n, blen - n, "%02x", buff[10 + k]); + sgj_haj_vs(jsp, jop, 2, "LUN WWN", SGJ_SEP_COLON_1_SPACE, b); + snprintf(b, blen, "%.*s", buff[49], buff + 50); + sgj_haj_vs(jsp, jop, 2, "Array Serial Number", SGJ_SEP_COLON_1_SPACE, b); + + if (buff[4] > 0x02) + snprintf(b, blen, "Unknown (%x)", buff[4]); + else + snprintf(b, blen, "%s", lun_state_arr[buff[4]]); + sgj_haj_vistr(jsp, jop, 2, "LUN State", SGJ_SEP_COLON_1_SPACE, + buff[4], true, b); + + uc = buff[8]; + n = 0; + if (uc > 0x01) + n += sg_scnpr(b + n, blen - n, "Unknown SP (%x)", uc); + else + n += sg_scnpr(b + n, blen - n, "%s", sp_arr[uc]); + sgj_js_nv_ihexstr(jsp, jop, "path_connects_to", uc, NULL, b); + n += sg_scnpr(b + n, blen - n, ", Port Number: %u", buff[7]); + sgj_pr_hr(jsp, " This path connects to: %s\n", b); + sgj_js_nv_ihex(jsp, jop, "port_number", buff[7]); + + if (buff[5] > 0x01) + snprintf(b, blen, "Unknown (%x)\n", buff[5]); + else + snprintf(b, blen, "%s\n", sp_arr[buff[5]]); + sgj_haj_vistr(jsp, jop, 2, "Default owner", SGJ_SEP_COLON_1_SPACE, + buff[5], true, b); + + cp = (buff[6] & 0x40) ? "supported" : "not supported"; + sgj_pr_hr(jsp, " NO_ATF: %s, Access Logix: %s\n", + buff[6] & 0x80 ? "set" : "not set", cp); + sgj_js_nv_i(jsp, jop, "no_atf", !! (buff[6] & 0x80)); + sgj_js_nv_istr(jsp, jop, "access_logix", !! (buff[6] & 0x40), + NULL, cp); + + ip_mgmt = (buff[6] >> 4) & 0x3; + cp = ip_mgmt_arr[ip_mgmt]; + sgj_pr_hr(jsp, " SP IP Management Mode: %s\n", cp); + sgj_js_nv_istr(jsp, jop, "sp_ip_management_mode", !! ip_mgmt, + NULL, cp); + if (ip_mgmt == 2) { + snprintf(b, blen, "%u.%u.%u.%u", buff[44], buff[45], buff[46], + buff[47]); + sgj_pr_hr(jsp, " SP IPv4 address: %s\n", b); + sgj_js_nv_s(jsp, jop, "sp_ipv4_address", b); + } else if (ip_mgmt == 3) { + printf(" SP IPv6 address: "); + n = 0; + for (k = 0; k < 16; ++k) + n += sg_scnpr(b + n, blen - n, "%02x", buff[32 + k]); + sgj_pr_hr(jsp, " SP IPv6 address: %s\n", b); + sgj_js_nv_hex_bytes(jsp, jop, "sp_ipv6_address", buff + 32, 16); + } + + k = buff[28] & 0x0f; + sgj_pr_hr(jsp, " System Type: %x, Failover mode: %s\n", + buff[27], failover_mode_arr[k]); + sgj_js_nv_ihex(jsp, jop, "system_type", buff[27]); + sgj_js_nv_ihexstr(jsp, jop, "failover_mode", k, NULL, + failover_mode_arr[k]); + + vpp80 = buff[30] & 0x08; + lun_z = buff[30] & 0x04; + cp = vpp80 ? "array serial#" : "LUN serial#"; + c2p = lun_z ? "Set to 1" : "Unknown"; + sgj_pr_hr(jsp, " Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", + cp, c2p); + sgj_js_nv_istr(jsp, jop, "inquiry_vpp_0x80_returns", !! vpp80, NULL, cp); + sgj_js_nv_istr(jsp, jop, "arraycommpath", !! lun_z, NULL, c2p); + + cp = buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]; + sgj_pr_hr(jsp, " Lun operations: %s\n", cp); + sgj_js_nv_istr(jsp, jop, "lun_operations", 0x1 & buff[48], NULL, cp); + + return; +} + +/* VPD_RDAC_VERS,VPD_V_SVER_RDAC 0xc2 ["rdac_vers", "swr4"] */ +void +decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop) +{ + int i, n, v, r, m, p, d, y, num_part; + sgj_state * jsp = &op->json_st; + sgj_opaque_p jo2p = NULL; + sgj_opaque_p jap = NULL; + // const char * cp; + // const char * c2p; + char b[256]; + static const int blen = sizeof(b); + char part[5]; + + if (len < 3) { + pr2serr("Software Version VPD page length too short=%d\n", len); + return; + } + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); + return; + } + if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { + pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", + buff[4], buff[5], buff[6], buff[7]); + return; + } + snprintf(b, blen, "%02x.%02x.%02x", buff[8], buff[9], buff[10]); + sgj_haj_vs(jsp, jop, 2, "Software Version", SGJ_SEP_COLON_1_SPACE, b); + snprintf(b, blen, "%02d/%02d/%02d\n", buff[11], buff[12], buff[13]); + sgj_haj_vs(jsp, jop, 2, "Software Date", SGJ_SEP_COLON_1_SPACE, b); + n = 0; + n += sg_scnpr(b + n, blen - n, " Features:"); + if (buff[14] & 0x01) + n += sg_scnpr(b + n, blen - n, " Dual Active,"); + if (buff[14] & 0x02) + n += sg_scnpr(b + n, blen - n, " Series 3,"); + if (buff[14] & 0x04) + n += sg_scnpr(b + n, blen - n, " Multiple Sub-enclosures,"); + if (buff[14] & 0x08) + n += sg_scnpr(b + n, blen - n, " DCE/DRM/DSS/DVE,"); + if (buff[14] & 0x10) + n += sg_scnpr(b + n, blen - n, " Asymmetric Logical Unit Access,"); + sgj_pr_hr(jsp, "%s\n", b); + if (jsp->pr_as_json) { + jo2p = sgj_snake_named_subobject_r(jsp, jop, "features"); + sgj_js_nv_i(jsp, jo2p, "dual_active", !! (buff[14] & 0x01)); + sgj_js_nv_i(jsp, jo2p, "series_3", !! (buff[14] & 0x02)); + sgj_js_nv_i(jsp, jo2p, "multiple_sub_enclosures", + !! (buff[14] & 0x04)); + sgj_js_nv_i(jsp, jo2p, "dcm_drm_dss_dve", !! (buff[14] & 0x08)); + sgj_js_nv_i(jsp, jo2p, "asymmetric_logical_unit_access", + !! (buff[14] & 0x10)); + } + sgj_haj_vi(jsp, jop, 2, "Maximum number of LUNS", + SGJ_SEP_COLON_1_SPACE, buff[15], true); + + num_part = (len - 12) / 16; + n = 16; + printf(" Partitions: %d\n", num_part); + sgj_haj_vi(jsp, jop, 2, "Partitions", SGJ_SEP_COLON_1_SPACE, num_part, + true); + if (num_part > 0) + jap = sgj_named_subarray_r(jsp, jop, "partition_list"); + for (i = 0; i < num_part; i++) { + memset(part,0, 5); + memcpy(part, &buff[n], 4); + sgj_pr_hr(jsp, " Name: %s\n", part); + if (jsp->pr_as_json) { + jo2p = sgj_new_unattached_object_r(jsp); + sgj_js_nv_s(jsp, jo2p, "name", part); + } + n += 4; + v = buff[n++]; + r = buff[n++]; + m = buff[n++]; + p = buff[n++]; + snprintf(b, blen, "%d.%d.%d.%d", v, r, m, p); + sgj_pr_hr(jsp, " Version: %s\n", b); + if (jsp->pr_as_json) + sgj_js_nv_s(jsp, jo2p, "version", b); + m = buff[n++]; + d = buff[n++]; + y = buff[n++]; + snprintf(b, blen, "%d/%d/%d\n", m, d, y); + sgj_pr_hr(jsp, " Date: %s\n", b); + if (jsp->pr_as_json) { + sgj_js_nv_s(jsp, jo2p, "date", b); + sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); + } + + n += 5; + } + return; +} + +static char * +decode_rdac_vpd_c9_aas_s(uint8_t aas, char * b, int blen) +{ + // snprintf(" Asymmetric Access State:"); + switch(aas & 0x0F) { + case 0x0: + snprintf(b, blen, "Active/Optimized"); + break; + case 0x1: + snprintf(b, blen, "Active/Non-Optimized"); + break; + case 0x2: + snprintf(b, blen, "Standby"); + break; + case 0x3: + snprintf(b, blen, "Unavailable"); + break; + case 0xE: + snprintf(b, blen, "Offline"); + break; + case 0xF: + snprintf(b, blen, "Transitioning"); + break; + default: + snprintf(b, blen, "(unknown)"); + break; + } + return b; +} + +static char * +decode_rdac_vpd_c9_vs_s(uint8_t vendor, char * b, int blen) +{ + // printf(" Vendor Specific Field:"); + switch(vendor) { + case 0x01: + snprintf(b, blen, "Operating normally"); + break; + case 0x02: + snprintf(b, blen, "Non-responsive to queries"); + break; + case 0x03: + snprintf(b, blen, "Controller being held in reset"); + break; + case 0x04: + snprintf(b, blen, "Performing controller firmware download (1st " + "controller)"); + break; + case 0x05: + snprintf(b, blen, "Performing controller firmware download (2nd " + "controller)"); + break; + case 0x06: + snprintf(b, blen, + "Quiesced as a result of an administrative request"); + break; + case 0x07: + snprintf(b, blen, + "Service mode as a result of an administrative request"); + break; + case 0xFF: + snprintf(b, blen, "Details are not available"); + break; + default: + snprintf(b, blen, "(unknown)"); + break; + } + return b; +} + +/* VPD_RDAC_VAC,VPD_V_VAC_RDAC 0xc9 ["rdac_vac", "vac1"] */ +void +decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop) +{ + bool vav; + int n, n_hold; + sgj_state * jsp = &op->json_st; + char b[196]; + static const int blen = sizeof(b); + + if (len < 3) { + pr2serr("Volume Access Control VPD page length too short=%d\n", len); + return; + } + if (op->do_hex) { + hex2stdout(buff, len, no_ascii_4hex(op)); + return; + } + if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') { + pr2serr("Invalid page identifier %c%c%c%c, decoding " + "not possible.\n" , buff[4], buff[5], buff[6], buff[7]); + return; + } + if (buff[7] != '1') { + pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]); + } + n = ((buff[8] & 0xE0) == 0xE0 ); + if (n) { + sgj_pr_hr(jsp, " IOShipping (ALUA): Enabled\n"); + sgj_js_nv_ihexstr_nex(jsp, jop, "ioshipping", n, true, NULL, + "Enabled", + "a.k.a. ALUA (Asymmetric Logical Unit Access)"); + } else { + n = 0; + n = snprintf(b, blen, " AVT:"); + n_hold = n; + if (buff[8] & 0x80) { + n += sg_scnpr(b + n, blen - n, " Enabled"); + if (buff[8] & 0x40) + n += sg_scnpr(b + n, blen - n, " (Allow reads on sector 0)"); + sgj_pr_hr(jsp, "%s\n", b); + sgj_js_nv_ihexstr(jsp, jop, "avt", buff[8], NULL, b + n_hold); + + } else { + sgj_pr_hr(jsp, "%s: Disabled\n", b); + sgj_js_nv_ihexstr(jsp, jop, "avt", buff[8], NULL, "Disabled"); + } + } + vav = !! (0x1 & buff[8]); + sgj_haj_vistr(jsp, jop, 2, "Volume access via", SGJ_SEP_COLON_1_SPACE, + (int)vav, false, + (vav ? "primary controller" : "alternate controller")); + + if (buff[8] & 0x08) { + n = buff[15] & 0xf; + // printf(" Path priority: %d ", n); + switch (n) { + case 0x1: + snprintf(b, blen, "(preferred path)"); + break; + case 0x2: + snprintf(b, blen, "(secondary path)"); + break; + default: + snprintf(b, blen, "(unknown)"); + break; + } + sgj_haj_vistr(jsp, jop, 2, "Path priority", SGJ_SEP_COLON_1_SPACE, n, + true, b); + + // printf(" Preferred Path Auto Changeable:"); + n = buff[14] & 0x3C; + switch (n) { + case 0x14: + snprintf(b, blen, "No (User Disabled and Host Type Restricted)"); + break; + case 0x18: + snprintf(b, blen, "No (User Disabled)"); + break; + case 0x24: + snprintf(b, blen, "No (Host Type Restricted)"); + break; + case 0x28: + snprintf(b, blen, "Yes"); + break; + default: + snprintf(b, blen, "(Unknown)"); + break; + } + sgj_haj_vistr(jsp, jop, 2, "Preferred path auto changeable", + SGJ_SEP_COLON_1_SPACE, n, true, b); + + n = buff[14] & 0x03; + // printf(" Implicit Failback:"); + switch (n) { + case 0x1: + snprintf(b, blen, "Disabled"); + break; + case 0x2: + snprintf(b, blen, "Enabled"); + break; + default: + snprintf(b, blen, "(Unknown)"); + break; + } + sgj_haj_vistr(jsp, jop, 2, "Implicit failback", + SGJ_SEP_COLON_1_SPACE, n, false, b); + } else { + n = buff[9] & 0xf; + // printf(" Path priority: %d ", buff[9] & 0xf); + switch (n) { + case 0x1: + snprintf(b, blen, "(preferred path)"); + break; + case 0x2: + snprintf(b, blen, "(secondary path)"); + break; + default: + snprintf(b, blen, "(unknown)"); + break; + } + sgj_haj_vistr(jsp, jop, 2, "Path priority", + SGJ_SEP_COLON_1_SPACE, n, false, b); + } + + n = !! (buff[8] & 0x80); + sgj_haj_vi(jsp, jop, 2, "Target port group present", + SGJ_SEP_COLON_1_SPACE, n, false); + if (n) { + sgj_opaque_p jo2p = NULL; + sgj_opaque_p jo3p = NULL; + static const char * tpg_s = "Target port group data"; + static const char * aas_s = "Asymmetric access state"; + static const char * vs_s = "Vendor specific field"; + char d1[80]; + char d2[80]; + + sgj_pr_hr(jsp, " Target Port Group Data (This controller):\n"); + decode_rdac_vpd_c9_aas_s(buff[10], d1, sizeof(d1)); + decode_rdac_vpd_c9_vs_s(buff[11], d2, sizeof(d2)); + sgj_pr_hr(jsp, " %s: %s\n", aas_s, d1); + sgj_pr_hr(jsp, " %s: %s\n", vs_s, d2); + if (jsp->pr_as_json) { + jo2p = sgj_snake_named_subobject_r(jsp, jop, tpg_s); + jo3p = sgj_snake_named_subobject_r(jsp, jo2p, "this_controller"); + sgj_convert_to_snake_name(aas_s, b, blen); + sgj_js_nv_ihexstr(jsp, jo3p, b, buff[10], NULL, d1); + sgj_convert_to_snake_name(vs_s, b, blen); + sgj_js_nv_ihexstr(jsp, jo3p, b, buff[11], NULL, d2); + } + sgj_pr_hr(jsp, " Target Port Group Data (Alternate controller):\n"); + // decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); + + decode_rdac_vpd_c9_aas_s(buff[12], d1, sizeof(d1)); + decode_rdac_vpd_c9_vs_s(buff[13], d2, sizeof(d2)); + sgj_pr_hr(jsp, " %s: %s\n", aas_s, d1); + sgj_pr_hr(jsp, " %s: %s\n", vs_s, d2); + if (jsp->pr_as_json) { + jo2p = sgj_snake_named_subobject_r(jsp, jop, tpg_s); + jo3p = sgj_snake_named_subobject_r(jsp, jo2p, + "alternate_controller"); + sgj_convert_to_snake_name(aas_s, b, blen); + sgj_js_nv_ihexstr(jsp, jo3p, b, buff[12], NULL, d1); + sgj_convert_to_snake_name(vs_s, b, blen); + sgj_js_nv_ihexstr(jsp, jo3p, b, buff[13], NULL, d2); + } + } +} diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h index 50cdb48a..13134336 100644 --- a/src/sg_vpd_common.h +++ b/src/sg_vpd_common.h @@ -250,7 +250,19 @@ decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op, void decode_tapealert_supported_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); +/* Share some vendor specific VPD pages as well */ +void +decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop); +void +decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop); +void +decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op, + sgj_opaque_p jop); + const char * pqual_str(int pqual); +int no_ascii_4hex(const struct opts_t * op); void svpd_enumerate_vendor(int vend_prod_num); int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num); diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c index 5cfc7ee3..156dd83b 100644 --- a/src/sg_vpd_vendor.c +++ b/src/sg_vpd_vendor.c @@ -111,17 +111,6 @@ 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) { @@ -350,127 +339,6 @@ decode_dev_beh_vpd_c3_sea(uint8_t * buff, int len) printf(" Default number of cache segments: %d\n", buff[24]); } -static const char * lun_state_arr[] = -{ - "LUN not bound or LUN_Z report", - "LUN bound, but not owned by this SP", - "LUN bound and owned by this SP", -}; - -static const char * ip_mgmt_arr[] = -{ - "No IP access", - "Reserved (undefined)", - "via IPv4", - "via IPv6", -}; - -static const char * sp_arr[] = -{ - "SP A", - "SP B", -}; - -static const char * lun_op_arr[] = -{ - "Normal operations", - "I/O Operations being rejected, SP reboot or NDU in progress", -}; - -static const char * failover_mode_arr[] = -{ - "Legacy mode 0", - "Unknown mode (1)", - "Unknown mode (2)", - "Unknown mode (3)", - "Active/Passive (PNR) mode 1", - "Unknown mode (5)", - "Active/Active (ALUA) mode 4", - "Unknown mode (7)", - "Legacy mode 2", - "Unknown mode (9)", - "Unknown mode (10)", - "Unknown mode (11)", - "Unknown mode (12)", - "Unknown mode (13)", - "AIX Active/Passive (PAR) mode 3", - "Unknown mode (15)", -}; - -static void -decode_upr_vpd_c0_emc(uint8_t * buff, int len) -{ - int k, ip_mgmt, vpp80, lun_z; - - if (len < 3) { - pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); - return; - } - if (buff[9] != 0x00) { - pr2serr("Unsupported page revision %d, decoding not possible.\n", - buff[9]); - return; - } - printf(" LUN WWN: "); - for (k = 0; k < 16; ++k) - printf("%02x", buff[10 + k]); - printf("\n"); - printf(" Array Serial Number: "); - dStrRaw(&buff[50], buff[49]); - printf("\n"); - - printf(" LUN State: "); - if (buff[4] > 0x02) - printf("Unknown (%x)\n", buff[4]); - else - printf("%s\n", lun_state_arr[buff[4]]); - - printf(" This path connects to: "); - if (buff[8] > 0x01) - printf("Unknown SP (%x)", buff[8]); - else - printf("%s", sp_arr[buff[8]]); - printf(", Port Number: %u\n", buff[7]); - - printf(" Default Owner: "); - if (buff[5] > 0x01) - printf("Unknown (%x)\n", buff[5]); - else - printf("%s\n", sp_arr[buff[5]]); - - printf(" NO_ATF: %s, Access Logix: %s\n", - buff[6] & 0x80 ? "set" : "not set", - buff[6] & 0x40 ? "supported" : "not supported"); - - ip_mgmt = (buff[6] >> 4) & 0x3; - - printf(" SP IP Management Mode: %s\n", ip_mgmt_arr[ip_mgmt]); - if (ip_mgmt == 2) - printf(" SP IPv4 address: %u.%u.%u.%u\n", - buff[44], buff[45], buff[46], buff[47]); - else { - printf(" SP IPv6 address: "); - for (k = 0; k < 16; ++k) - printf("%02x", buff[32 + k]); - printf("\n"); - } - - vpp80 = buff[30] & 0x08; - lun_z = buff[30] & 0x04; - - printf(" System Type: %x, Failover mode: %s\n", - buff[27], failover_mode_arr[buff[28] & 0x0f]); - - printf(" Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", - vpp80 ? "array serial#" : "LUN serial#", - lun_z ? "Set to 1" : "Unknown"); - - printf(" Lun operations: %s\n", - buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]); - - return; -} - static void decode_rdac_vpd_c0(uint8_t * buff, int len) { @@ -560,61 +428,6 @@ decode_rdac_vpd_c1(uint8_t * buff, int len) } static void -decode_rdac_vpd_c2(uint8_t * buff, int len) -{ - int i, n, v, r, m, p, d, y, num_part; - char part[5]; - - if (len < 3) { - pr2serr("Software Version VPD page length too short=%d\n", len); - return; - } - if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { - pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", - buff[4], buff[5], buff[6], buff[7]); - return; - } - printf(" Software Version: %02x.%02x.%02x\n", buff[8], buff[9], buff[10]); - printf(" Software Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); - printf(" Features:"); - if (buff[14] & 0x01) - printf(" Dual Active,"); - if (buff[14] & 0x02) - printf(" Series 3,"); - if (buff[14] & 0x04) - printf(" Multiple Sub-enclosures,"); - if (buff[14] & 0x08) - printf(" DCE/DRM/DSS/DVE,"); - if (buff[14] & 0x10) - printf(" Asymmetric Logical Unit Access,"); - printf("\n"); - printf(" Max. #of LUNS: %d\n", buff[15]); - - num_part = (len - 12) / 16; - n = 16; - printf(" Partitions: %d\n", num_part); - for (i = 0; i < num_part; i++) { - memset(part,0, 5); - memcpy(part, &buff[n], 4); - printf(" Name: %s\n", part); - n += 4; - v = buff[n++]; - r = buff[n++]; - m = buff[n++]; - p = buff[n++]; - printf(" Version: %d.%d.%d.%d\n", v, r, m, p); - m = buff[n++]; - d = buff[n++]; - y = buff[n++]; - printf(" Date: %d/%d/%d\n", m, d, y); - - n += 5; - } - - return; -} - -static void decode_rdac_vpd_c3(uint8_t * buff, int len) { if (len < 0x2c) { @@ -827,6 +640,7 @@ decode_rdac_vpd_c8(uint8_t * buff, int len) return; } +#if 0 static void decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor) { @@ -992,6 +806,7 @@ decode_rdac_vpd_c9(uint8_t * buff, int len) decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); } } +#endif static void decode_rdac_vpd_ca(uint8_t * buff, int len) @@ -1237,15 +1052,17 @@ int svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) { bool hex0 = (0 == op->do_hex); + bool as_json; 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; + sgj_opaque_p jo2p = NULL; uint8_t * rp; char name[80]; + as_json = jsp->pr_as_json; pn = op->vpd_pn; switch (pn) { /* VPD codes that we support vendor pages for */ case 0x3: @@ -1300,9 +1117,12 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) 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) + else if (VPD_VP_EMC == op->vend_prod_num) { + if (as_json) + jo2p = sg_vpd_js_hdr(jsp, jop, + "Unit serial number VPD page", rp); + decode_upr_vpd_c0_emc(rp, len, op, jo2p); + } 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); @@ -1332,9 +1152,12 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) 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) + else if (VPD_VP_RDAC == op->vend_prod_num) { + if (as_json) + jo2p = sg_vpd_js_hdr(jsp, jop, + "Software version VPD page", rp); + decode_rdac_vpd_c2(rp, len, op, jo2p); + } else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; @@ -1380,9 +1203,12 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) 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 + else if (VPD_VP_RDAC == op->vend_prod_num) { + if (as_json) + jo2p = sg_vpd_js_hdr(jsp, jop, + "Volume access control VPD page", rp); + decode_rdac_vpd_c9(rp, len, op, jo2p); + } else res = SG_LIB_CAT_OTHER; break; case 0xca: @@ -1438,16 +1264,21 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off) break; } else { int n = len - 16; + const char * np = "NVMe Identify Controller Response VPD page"; + /* NVMe: Identify Controller data structure (CNS 01h) */ + const char * ep = "(sg3_utils)"; if (n > 4096) { pr2serr("NVMe Identify response expected to be " "<= 4096 bytes (got: %d)\n", n); break; } + if (op->do_hex < 3) + sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); 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); + jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n); } else |