aboutsummaryrefslogtreecommitdiff
path: root/src/sg_inq.c
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-08-18 19:46:38 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-08-18 19:46:38 +0000
commit7e7308a2dbdec4c900b0805ad94324d3a288a163 (patch)
treec6c84399abcab97cc9bb0657f0734e0aa56a917d /src/sg_inq.c
parent98b99ad2ab348bbba1676b95a8895f12ee48fd31 (diff)
downloadsg3_utils-7e7308a2dbdec4c900b0805ad94324d3a288a163.tar.gz
sg_inq+sg_vpd: more updates but not finished
The sg_inq+sg_inq work is mainly JSON additions. sg_vpd has a new --sinq_inraw=RFN option. Update and place names for the 64 TapeAlert flags in the library. This improves TapeAlert reporting for sg_inq, sg_vpd and sg_logs. Refine the description of the VPD page merge of processing for sg_inq and sg_vpd to only include _T10_ defined pages, so the vendor specific VPD page processings of those utilities are still separate. git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@969 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src/sg_inq.c')
-rw-r--r--src/sg_inq.c435
1 files changed, 299 insertions, 136 deletions
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;