aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-07-27 19:58:23 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-07-27 19:58:23 +0000
commitaac31a343f55c0b40b7d46ba453201fff3430acb (patch)
treec9e35ef76fc2f3130e116a9a06142b8866aace6b /src
parent270cd7304dd379ee490df57120d281641c292398 (diff)
downloadsg3_utils-aac31a343f55c0b40b7d46ba453201fff3430acb.tar.gz
rescan-scsi-bus.sh: fix handling of '-I <secs>' option ; sg_inq+sg_vpd: more JSON work
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@962 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r--src/sg_inq.c453
-rw-r--r--src/sg_vpd.c556
-rw-r--r--src/sg_vpd_common.c763
-rw-r--r--src/sg_vpd_common.h18
4 files changed, 1246 insertions, 544 deletions
diff --git a/src/sg_inq.c b/src/sg_inq.c
index cf7c4064..c35e9343 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.22 20220718"; /* spc6r06 */
+static const char * version_str = "2.24 20220727"; /* spc6r06 */
#define MY_NAME "sg_inq"
@@ -232,6 +232,8 @@ static struct option long_options[] = {
{"only", no_argument, 0, 'o'},
{"page", required_argument, 0, 'p'},
{"raw", no_argument, 0, 'r'},
+ {"sinq_inraw", required_argument, 0, 'Q'},
+ {"sinq-inraw", required_argument, 0, 'Q'},
{"vendor", no_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
@@ -252,9 +254,9 @@ usage()
"[--inhex=FN]\n"
" [--json[=JO]] [--len=LEN] [--long] "
"[--maxlen=LEN]\n"
- " [--only] [--page=PG] [--raw] [--vendor] "
- "[--verbose]\n"
- " [--version] [--vpd] DEVICE\n"
+ " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
+ "[--vendor]\n"
+ " [--verbose] [--version] [--vpd] DEVICE\n"
" where:\n"
" --ata|-a treat DEVICE as (directly attached) ATA "
"device\n");
@@ -265,9 +267,9 @@ usage()
"[--inhex=FN]\n"
" [--json[=JO]] [--len=LEN] [--long] "
"[--maxlen=LEN]\n"
- " [--only] [--page=PG] [--raw] [--verbose] "
- "[--version]\n"
- " [--vpd] DEVICE\n"
+ " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
+ "[--verbose]\n"
+ " [--version] [--vpd] DEVICE\n"
" where:\n");
#endif
pr2serr(" --block=0|1 0-> open(non-blocking); 1-> "
@@ -314,6 +316,9 @@ usage()
" abbreviation (opcode number if "
"'--cmddt' given)\n"
" --raw|-r output response in binary (to stdout)\n"
+ " --sinq_inraw=RFN|-Q RFN read raw (binary) standard "
+ "INQUIRY\n"
+ " response from the RFN filename\n"
" --vendor|-s show vendor specific fields in std "
"inquiry\n"
" --verbose|-v increase verbosity\n"
@@ -420,18 +425,18 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
#ifdef SG_LIB_LINUX
#ifdef SG_SCSI_STRINGS
- c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:NoOp:Q:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:Q:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#else /* SG_LIB_LINUX */
#ifdef SG_SCSI_STRINGS
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:NoOp:Q:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:Q:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#endif /* SG_LIB_LINUX */
@@ -541,6 +546,9 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
op->page_str = optarg;
op->page_given = true;
break;
+ case 'Q':
+ op->sinq_inraw_fn = optarg;
+ break;
case 'r':
++op->do_raw;
break;
@@ -1966,20 +1974,12 @@ decode_b0_vpd(uint8_t * buff, int len, int do_hex)
}
}
-static const char * zoned_strs[] = {
- "",
- " [host-aware]",
- " [host-managed]",
- "",
-};
-
-/* VPD_BLOCK_DEV_CHARS sbc */
+/* 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)
{
- int pdt, zoned;
- unsigned int u;
+ int pdt;
if (do_hex) {
hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
@@ -1988,55 +1988,7 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex)
pdt = PDT_MASK & buff[0];
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 64) {
- pr2serr("Block device characteristics VPD page length too "
- "short=%d\n", len);
- return;
- }
- u = sg_get_unaligned_be16(buff + 4);
- if (0 == u)
- printf(" Medium rotation rate is not reported\n");
- else if (1 == u)
- printf(" Non-rotating medium (e.g. solid state)\n");
- else if ((u < 0x401) || (0xffff == u))
- printf(" Reserved [0x%x]\n", u);
- else
- printf(" Nominal rotation rate: %d rpm\n", u);
- printf(" Product type=%d\n", buff[6]);
- printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
- printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
- u = buff[7] & 0xf;
- printf(" Nominal form factor ");
- switch(u) {
- case 0:
- printf("is not reported\n");
- break;
- case 1:
- printf("5.25 inches\n");
- break;
- case 2:
- printf("3.5 inches\n");
- break;
- case 3:
- printf("2.5 inches\n");
- break;
- case 4:
- printf("1.8 inches\n");
- break;
- case 5:
- printf("less then 1.8 inches\n");
- break;
- default:
- printf("reserved [%u]\n", u);
- break;
- }
- zoned = (buff[8] >> 4) & 0x3; /* added sbc4r04 */
- printf(" ZONED=%d%s\n", zoned, zoned_strs[zoned]);
- /* ZONED field made obsolete in sbc5r01 */
- printf(" FUAB=%d\n", buff[8] & 0x2);
- printf(" VBULS=%d\n", buff[8] & 0x1);
- printf(" DEPOPULATION_TIME=%u (seconds)\n",
- sg_get_unaligned_be32(buff + 12)); /* added sbc4r14 */
+ /* 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",
@@ -2054,7 +2006,6 @@ static void
decode_b3_vpd(uint8_t * buff, int len, int do_hex)
{
int pdt;
- unsigned int s, m;
if (do_hex) {
hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
@@ -2063,19 +2014,7 @@ decode_b3_vpd(uint8_t * buff, int len, int do_hex)
pdt = PDT_MASK & buff[0];
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 0x10) {
- pr2serr("Referrals VPD page length too short=%d\n", len);
- return;
- }
- s = sg_get_unaligned_be32(buff + 8);
- m = sg_get_unaligned_be32(buff + 12);
- if (0 == s)
- printf(" Single user data segment\n");
- else if (0 == m)
- printf(" Segment size specified by user data segment "
- "descriptor\n");
- else
- printf(" Segment size: %u, segment multiplier: %u\n", s, m);
+ /* now done in decode)referrals_vpd() in sg_vpd_common.c */
break;
default:
printf(" Unable to decode pdt=0x%x, in hex:\n", pdt);
@@ -3057,6 +2996,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
sgj_opaque_p jo2p = NULL;
sgj_opaque_p jap = NULL;
const char * np;
+ const char * ep = "";
// const char * pdt_str;
uint8_t * rp;
// char d[80];
@@ -3402,68 +3342,323 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */
res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
+ bool bdc = false;
+ static const char * masn =
+ "Manufactured-assigned serial number VPD page";
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
pdt = rp[0] & PDT_MASK;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("VPD INQUIRY: Block device characteristics page "
- "(SBC)\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Manufactured assigned serial number VPD page "
- "(SSC):\n");
- break;
- case PDT_OSD:
- printf("Security token VPD page (OSD):\n");
- break;
- case PDT_ADC:
- printf("Manufactured assigned serial number VPD page "
- "(ADC):\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics VPD page";
+ ep = "(SBC)";
+ bdc = true;
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = masn;
+ ep = "(SSC)";
+ break;
+ case PDT_OSD:
+ np = "Security token VPD page";
+ ep = "(OSD)";
+ break;
+ case PDT_ADC:
+ np = masn;
+ ep = "(ADC)";
+ break;
+ default:
+ np = NULL;
+ printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
+ break;
}
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (bdc)
+ decode_block_dev_ch_vpd(rp, len, op, jo2p);
else
decode_b1_vpd(rp, len, op->do_hex);
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb1\n");
break;
case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool lbpv = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Logical block provisioning VPD page";
+ ep = "(SBC)";
+ lbpv = true;
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "TapeAlert supported flags VPD page";
+ ep = "(SSC)";
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (lbpv)
+ return decode_block_lb_prov_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);
- case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */
+#endif
+ case 0xb3:
res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
+ bool ref = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
pdt = rp[0] & PDT_MASK;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("VPD INQUIRY: Referrals VPD page (SBC)\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb3, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Referrals VPD page";
+ ep = "(SBC)";
+ ref = true;
+ break;
+ default:
+ np = NULL;
+ break;
}
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (ref)
+ decode_referrals_vpd(rp, len, op, jo2p);
else
decode_b3_vpd(rp, len, op->do_hex);
+ return 0;
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb3\n");
break;
case 0xb4:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool sbl = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Supported block lengths and protection types VPD page";
+ ep = "(SBC)";
+ sbl = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ 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
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb4\n");
+ break;
case 0xb5:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool bdce = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics VPD page";
+ ep = "(SBC)";
+ bdce = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (bdce)
+ decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb5\n");
+ break;
case 0xb6:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool zbdch = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Zoned block device characteristics VPD page";
+ ep = "(SBC, ZBC)";
+ zbdch = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (zbdch)
+ decode_zbdch_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb6\n");
+ break;
case 0xb7:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool ble = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block limits extension VPD page";
+ ep = "(SBC)";
+ ble = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (ble)
+ decode_block_limits_ext_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb7\n");
+ break;
case 0xb8:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool fp = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Format presets VPD page";
+ ep = "(SBC)";
+ fp = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ 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) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_"
+ "descriptor_list");
+ }
+ if (fp)
+ decode_format_presets_vpd(rp, len, op, jap);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb8\n");
+ break;
case 0xb9:
+// yyyyyyyy
bad = true;
pr2serr("Please try the sg_vpd utility which decodes more VPD "
"pages\n\n");
@@ -3918,6 +4113,7 @@ main(int argc, char * argv[])
int sg_fd = -1;
int ret = 0;
int inhex_len = 0;
+ int inraw_len = 0;
const struct svpd_values_name_t * vnp;
sgj_state * jsp;
sgj_opaque_p jop = NULL;
@@ -4042,6 +4238,25 @@ main(int argc, char * argv[])
pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
return sg_convert_errno(ENOMEM);
}
+ if (op->sinq_inraw_fn) {
+ if (op->do_cmddt) {
+ pr2serr("Don't support --cmddt with --sinq-inraw= option\n");
+ ret = SG_LIB_CONTRADICT;
+ goto err_out;
+ }
+ if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff,
+ &inraw_len, rsp_buff_sz))) {
+ goto err_out;
+ }
+ if (inraw_len < 36) {
+ pr2serr("Unable to read 36 or more bytes from %s\n",
+ op->sinq_inraw_fn);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ memcpy(op->std_inq_a, rsp_buff, 36);
+ op->std_inq_a_valid = true;
+ }
if (op->inhex_fn) {
if (op->device_name) {
pr2serr("Cannot have both a DEVICE and --inhex= option\n");
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 8cb231d7..74a2bd95 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -42,7 +42,7 @@
*/
-static const char * version_str = "1.76 20220717"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.78 20220727"; /* spc6r06 + sbc5r01 */
#define MY_NAME "sg_vpd"
@@ -1517,104 +1517,20 @@ decode_b0_vpd(uint8_t * buff, int len, int do_hex, int pdt)
}
}
-static const char * product_type_arr[] =
-{
- "Not specified",
- "CFast",
- "CompactFlash",
- "MemoryStick",
- "MultiMediaCard",
- "Secure Digital Card (SD)",
- "XQD",
- "Universal Flash Storage Card (UFS)",
-};
-
-/* ZONED field here replaced by ZONED BLOCK DEVICE EXTENSION field in the
- * Zoned Block Device Characteristics VPD page. The new field includes
- * Zone Domains and Realms (see ZBC-2) */
-static const char * bdc_zoned_strs[] = {
- "",
- " [host-aware]",
- " [host-managed]",
- "",
-};
-
-/* VPD_BLOCK_DEV_CHARS sbc */
+/* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */
/* VPD_MAN_ASS_SN ssc */
/* 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)
{
- int zoned;
- unsigned int u, k;
-
if (do_hex) {
hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
return;
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 64) {
- pr2serr("Block device characteristics VPD page length too "
- "short=%d\n", len);
- return;
- }
- u = sg_get_unaligned_be16(buff + 4);
- if (0 == u)
- printf(" Medium rotation rate is not reported\n");
- else if (1 == u)
- printf(" Non-rotating medium (e.g. solid state)\n");
- else if ((u < 0x401) || (0xffff == u))
- printf(" Reserved [0x%x]\n", u);
- else
- printf(" Nominal rotation rate: %u rpm\n", u);
- u = buff[6];
- k = SG_ARRAY_SIZE(product_type_arr);
- printf(" Product type: ");
- if (u < k)
- printf("%s\n", product_type_arr[u]);
- else if (u < 0xf0)
- printf("Reserved [0x%x]\n", u);
- else
- printf("Vendor specific [0x%x]\n", u);
- printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
- printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
- u = buff[7] & 0xf;
- printf(" Nominal form factor");
- switch (u) {
- case 0:
- printf(" not reported\n");
- break;
- case 1:
- printf(": 5.25 inch\n");
- break;
- case 2:
- printf(": 3.5 inch\n");
- break;
- case 3:
- printf(": 2.5 inch\n");
- break;
- case 4:
- printf(": 1.8 inch\n");
- break;
- case 5:
- printf(": less then 1.8 inch\n");
- break;
- default:
- printf(": reserved\n");
- break;
- }
- printf(" MACT=%d\n", !!(buff[8] & 0x40)); /* added sbc5r01 */
- zoned = (buff[8] >> 4) & 0x3; /* added sbc4r04, obsolete sbc5r01 */
- printf(" ZONED=%d%s\n", zoned, bdc_zoned_strs[zoned]);
- printf(" RBWZ=%d\n", !!(buff[8] & 0x8)); /* sbc4r12 */
- printf(" BOCS=%d\n", !!(buff[8] & 0x4)); /* sbc4r07 */
- printf(" FUAB=%d\n", !!(buff[8] & 0x2));
- printf(" VBULS=%d\n", !!(buff[8] & 0x1));
- printf(" DEPOPULATION_TIME=%u (seconds)\n",
- sg_get_unaligned_be32(buff + 12)); /* added sbc4r14 */
- break;
+ /* 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);
@@ -1626,108 +1542,7 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt)
}
}
-static const char * prov_type_arr[8] = {
- "not known or fully provisioned",
- "resource provisioned",
- "thin provisioned",
- "reserved [0x3]",
- "reserved [0x4]",
- "reserved [0x5]",
- "reserved [0x6]",
- "reserved [0x7]",
-};
-
-/* VPD_LB_PROVISIONING 0xb2 */
-static int
-decode_block_lb_prov_vpd(uint8_t * b, int len, struct opts_t * op)
-{
- int dp, pt;
- unsigned int u;
- sgj_state * jsp = &op->json_st;
-
- if (len < 4) {
- pr2serr("Logical block provisioning page too short=%d\n", len);
- return SG_LIB_CAT_MALFORMED;
- }
- pt = b[6] & 0x7;
- sgj_pr_hr(jsp, " Unmap command supported (LBPU): %d\n", !!(0x80 & b[5]));
- printf(" Write same (16) with unmap bit supported (LBPWS): %d\n",
- !!(0x40 & b[5]));
- printf(" Write same (10) with unmap bit supported (LBPWS10): %d\n",
- !!(0x20 & b[5]));
- printf(" Logical block provisioning read zeros (LBPRZ): %d\n",
- (0x7 & (b[5] >> 2))); /* expanded from 1 to 3 bits in sbc4r07 */
- printf(" Anchored LBAs supported (ANC_SUP): %d\n", !!(0x2 & b[5]));
- dp = !!(b[5] & 0x1);
- u = b[4];
- printf(" Threshold exponent: ");
- if (0 == u)
- printf("0 [threshold sets not supported]\n");
- else
- printf("%u\n", u);
- printf(" Descriptor present (DP): %d\n", dp);
- printf(" Minimum percentage: ");
- u = 0x1f & (b[6] >> 3);
- if (0 == u)
- printf("0 [not reported]\n");
- else
- printf("%d\n", u);
- printf(" Provisioning type: %d (%s)\n", pt, prov_type_arr[pt]);
- printf(" Threshold percentage: ");
- if (0 == b[7])
- printf("0 [percentages not supported]\n");
- else
- printf("%u\n", b[7]);
- if (dp && (len > 11)) {
- int i_len;
- const uint8_t * bp;
- char bb[1024];
-
- bp = b + 8;
- i_len = bp[3];
- if (0 == i_len) {
- pr2serr("LB provisioning page provisioning group descriptor too "
- "short=%d\n", i_len);
- return 0;
- }
- printf(" Provisioning group descriptor:\n");
- sg_get_designation_descriptor_str(" ", bp, i_len + 4, 0,
- op->do_long, sizeof(bb), bb);
- printf("%s", bb);
- }
- return 0;
-}
-
-/* VPD_SUP_BLOCK_LENS 0xb4 (added sbc4r01) */
-static void
-decode_sup_block_lens_vpd(uint8_t * buff, int len)
-{
- int k;
- unsigned int u;
- uint8_t * bp;
-
- if (len < 4) {
- pr2serr("Supported block lengths and protection types VPD page "
- "length too short=%d\n", len);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0; k < len; k += 8, bp += 8) {
- u = sg_get_unaligned_be32(bp);
- printf(" Logical block length: %u\n", u);
- printf(" P_I_I_SUP: %d\n", !!(bp[4] & 0x40));
- printf(" NO_PI_CHK: %d\n", !!(bp[4] & 0x8)); /* sbc4r05 */
- printf(" GRD_CHK: %d\n", !!(bp[4] & 0x4));
- printf(" APP_CHK: %d\n", !!(bp[4] & 0x2));
- printf(" REF_CHK: %d\n", !!(bp[4] & 0x1));
- printf(" T3PS: %d\n", !!(bp[5] & 0x8));
- printf(" T2PS: %d\n", !!(bp[5] & 0x4));
- printf(" T1PS: %d\n", !!(bp[5] & 0x2));
- printf(" T0PS: %d\n", !!(bp[5] & 0x1));
- }
-}
-
+#if 0
/* VPD_BLOCK_DEV_C_EXTENS 0xb5 (added sbc4r02) */
static void
decode_block_dev_char_ext_vpd(uint8_t * b, int len)
@@ -1791,6 +1606,7 @@ decode_block_dev_char_ext_vpd(uint8_t * b, int len)
printf(" Utilization B: %u\n", sg_get_unaligned_be32(b + 8));
printf(" Utilization A: %u\n", sg_get_unaligned_be32(b + 12));
}
+#endif
/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */
static void
@@ -1858,7 +1674,8 @@ decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op)
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- decode_block_lb_prov_vpd(buff, len, op);
+ /* 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);
@@ -1873,13 +1690,9 @@ 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,
- sgj_opaque_p jop)
+decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op)
{
char obuff[DEF_ALLOC_LEN];
- sgj_state * jsp = &op->json_st;
- unsigned int u;
- char d[64];
if (op->do_hex) {
hex2stdout(b, len, (1 == op->do_hex) ? 0 : -1);
@@ -1887,20 +1700,7 @@ decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op,
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 16) {
- pr2serr("Referrals VPD page length too short=%d\n", len);
- break;
- }
- u = sg_get_unaligned_be32(b + 8);
- snprintf(d, sizeof(d), " User data segment size: ");
- if (0 == u)
- sgj_pr_hr(jsp, "%s0 [per sense descriptor]\n", d);
- else
- sgj_pr_hr(jsp, "%s%u\n", d, u);
- sgj_js_nv_ihex(jsp, jop, "user_data_segment_size", u);
- u = sg_get_unaligned_be32(b + 12);
- sgj_hr_js_vi(jsp, jop, 2, "User data segment multiplier",
- SGJ_SEP_COLON_1_SPACE, u, true);
+ /* now done in decode_referrals_vpd() in sg_vpd_common.c */
break;
case PDT_TAPE: case PDT_MCHANGER:
memset(obuff, 0, sizeof(obuff));
@@ -1917,7 +1717,7 @@ decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op,
}
}
-/* VPD_SUP_BLOCK_LENS sbc */
+/* 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)
@@ -1930,7 +1730,7 @@ decode_b4_vpd(uint8_t * b, int len, int do_hex, int pdt)
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- decode_sup_block_lens_vpd(b, len);
+ /* 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");
@@ -1955,7 +1755,7 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- decode_block_dev_char_ext_vpd(b, len);
+ /* 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);
@@ -1967,138 +1767,7 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
}
}
-/* VPD_ZBC_DEV_CHARS 0xb6 sbc or zbc [zbc2r04] */
-static void
-decode_zbdch_vpd(uint8_t * b, int len, int do_hex)
-{
- uint32_t u;
- char d[32];
-
- if (do_hex) {
- hex2stdout(b, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- if (len < 64) {
- pr2serr("Zoned block device characteristics VPD page length too "
- "short=%d\n", len);
- return;
- }
- printf(" Peripheral device type: %s\n",
- sg_get_pdt_str(PDT_MASK & b[0], sizeof(d), d));
- printf(" Zoned block device extension: ");
- switch ((b[4] >> 4) & 0xf) {
- case 0:
- if (PDT_ZBC == (PDT_MASK & b[0]))
- printf("host managed zoned block device [0, pdt=0x14]\n");
- else
- printf("not reported [0]\n");
- break;
- case 1:
- printf("host aware zoned block device model [1]\n");
- break;
- case 2:
- printf("Domains and realms zoned block device model [2]\n");
- break;
- default:
- printf("Unknown [0x%x]\n", (b[4] >> 4) & 0xf);
- break;
- }
- /* activation aligned on realm boundaries */
- printf(" AAORB: %d\n", !!(b[4] & 0x2));
- printf(" URSWRZ: %d\n", !!(b[4] & 0x1));
- u = sg_get_unaligned_be32(b + 8);
- printf(" Optimal number of open sequential write preferred zones: ");
- if (SG_LIB_UNBOUNDED_32BIT == u)
- printf("not reported\n");
- else
- printf("%" PRIu32 "\n", u);
- u = sg_get_unaligned_be32(b + 12);
- printf(" Optimal number of non-sequentially written sequential write "
- "preferred zones: ");
- if (SG_LIB_UNBOUNDED_32BIT == u)
- printf("not reported\n");
- else
- printf("%" PRIu32 "\n", u);
- u = sg_get_unaligned_be32(b + 16);
- printf(" Maximum number of open sequential write required zones: ");
- if (SG_LIB_UNBOUNDED_32BIT == u)
- printf("no limit\n");
- else
- printf("%" PRIu32 "\n", u);
- printf(" Zone alignment method: "); /* zbc2r11,zbc2r12 */
- switch (b[23] & 0xf) {
- case 0:
- printf("not reported [0]\n");
- break;
- case 1:
- printf("use constant zone lengths\n");
- break;
- case 0x8:
- printf("zone length given by REPORT ZONES\n");
- break;
- default:
- printf("Unknown [0x%x]\n", (b[23] & 0xf));
- break;
- }
- printf(" Zone starting LBA granularity: 0x%" PRIx64 "\n",
- sg_get_unaligned_be64(b + 24));
-}
-
-/* VPD_BLOCK_LIMITS_EXT [0xb7] sbc */
-static void
-decode_b7_vpd(uint8_t * buff, int len, int do_hex, int pdt)
-{
- unsigned int u;
-
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 12) {
- pr2serr("Block limits extension VPD page length too short=%d\n",
- len);
- return;
- }
- u = sg_get_unaligned_be16(buff + 6);
- printf(" Maximum number of streams: ");
- if (0 == u)
- printf("0 [Stream control not supported]\n");
- else
- printf("%u\n", u);
- u = sg_get_unaligned_be16(buff + 8);
- printf(" Optimal stream write size: %u blocks\n", u);
- u = sg_get_unaligned_be32(buff + 10);
- printf(" Stream granularity size: %u\n", u);
- if (len > 27) {
- u = sg_get_unaligned_be32(buff + 16);
- printf(" Maximum scattered LBA range transfer length: ");
- if (0 == u)
- printf("0 blocks [not reported]\n");
- else
- printf("%u blocks\n", u);
- u = sg_get_unaligned_be16(buff + 22);
- printf(" Maximum scattered LBA range descriptor count: ");
- if (0 == u)
- printf("0 [not reported]\n");
- else
- printf("%u\n", u);
- u = sg_get_unaligned_be32(buff + 24);
- printf(" Maximum scattered transfer length: ");
- if (0 == u)
- printf("0 blocks [not reported]\n");
- else
- printf("%u blocks\n", u);
- }
- break;
- default:
- pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stderr(buff, len, 0);
- break;
- }
-}
-
+#if 0
/* VPD_FORMAT_PRESETS 0xb8 (added sbc4r18) */
static void
decode_format_presets_vpd(uint8_t * buff, int len, int do_hex)
@@ -2167,6 +1836,7 @@ decode_format_presets_vpd(uint8_t * buff, int len, int do_hex)
}
}
}
+#endif
/* VPD_CON_POS_RANGE 0xb9 (added sbc5r01) */
static void
@@ -2841,34 +2511,48 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case 0xb1: /* depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool bdc = false;
+ static const char * masn =
+ "Manufactured-assigned serial number VPD page";
+
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Block device characteristics VPD page (SBC):";
+ np = "Block device characteristics VPD page";
+ ep = "(SBC)";
+ bdc = true;
break;
case PDT_TAPE: case PDT_MCHANGER:
- np = "Manufactured-assigned serial number VPD page (SSC):";
+ np = masn;
+ ep = "(SSC)";
break;
case PDT_OSD:
- np = "Security token VPD page (OSD):";
+ np = "Security token VPD page";
+ ep = "(OSD)";
break;
case PDT_ADC:
- np = "Manufactured-assigned serial number VPD page (ADC):";
+ np = masn;
+ ep = "(ADC)";
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_b1_vpd(rp, len, op->do_hex, pdt);
+ 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);
+ if (bdc)
+ decode_block_dev_ch_vpd(rp, len, op, jo2p);
+ else
+ decode_b1_vpd(rp, len, op->do_hex, pdt);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
@@ -2878,12 +2562,17 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
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;
+
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Logical block provisioning VPD page (SBC):";
+ np = "Logical block provisioning VPD page";
+ ep = "(SBC)";
+ lbpv = true;
break;
case PDT_TAPE: case PDT_MCHANGER:
- np = "TapeAlert supported flags VPD page (SSC):";
+ np = "TapeAlert supported flags VPD page";
+ ep = "(SSC)";
break;
default:
np = NULL;
@@ -2892,14 +2581,19 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
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);
- decode_b2_vpd(rp, len, pdt, op);
+ "%s]\n", pqual, pdt_str);
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (lbpv)
+ decode_block_lb_prov_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) &&
@@ -2909,13 +2603,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case 0xb3: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool ref = false;
+
pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Referrals VPD page (SBC):";
+ np = "Referrals VPD page";
+ ep = "(SBC)";
+ ref = true;
break;
case PDT_TAPE: case PDT_MCHANGER:
- np = "Automation device serial number VPD page SSC):";
+ np = "Automation device serial number VPD page";
+ ep = "(SSC)";
break;
default:
np = NULL;
@@ -2924,7 +2623,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2933,7 +2632,10 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
"%s]\n", pqual, pdt_str);
if (as_json)
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- decode_b3_vpd(rp, len, pdt, op, jo2p);
+ if (ref)
+ decode_referrals_vpd(rp, len, op, jo2p);
+ else
+ decode_b3_vpd(rp, len, pdt, op);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
@@ -2943,29 +2645,42 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case 0xb4: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool sbl = false;
+
+ pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Supported block lengths and protection types VPD page "
- "(SBC):";
+ np = "Supported block lengths and protection types VPD page";
+ ep = "(SBC)";
+ sbl = true;
break;
case PDT_TAPE: case PDT_MCHANGER:
- np = "Data transfer device element address (SSC):";
+ np = "Data transfer device element address";
+ ep = "(SSC)";
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_b4_vpd(rp, len, op->do_hex, pdt);
+ 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, "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);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
@@ -2975,85 +2690,115 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
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;
+
+ pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Block device characteristics extension VPD page (SBC):";
+ np = "Block device characteristics extension VPD page";
+ ep = "(SBC)";
+ bdce = true;
break;
case PDT_TAPE: case PDT_MCHANGER:
- np = "Logical block protection VPD page (SSC):";
+ np = "Logical block protection VPD page";
+ ep = "(SSC)";
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_b5_vpd(rp, len, op->do_hex, pdt);
+ 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);
+ if (bdce)
+ decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
+ 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))
- printf("%sVPD page=0xb4\n", pre);
+ printf("%sVPD page=0xb5\n", pre);
break;
case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool zbdch = false;
+
+ pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Zoned block device characteristics VPD page (SBC, "
- "ZBC):";
+ np = "Zoned block device characteristics VPD page";
+ ep = "(SBC, ZBC)";
+ zbdch = true;
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_zbdch_vpd(rp, len, op->do_hex);
+ 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);
+ if (zbdch)
+ decode_zbdch_vpd(rp, len, op, jo2p);
+ else
+ return SG_LIB_CAT_OTHER;
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
(0 == op->examine))
- printf("%sVPD page=0xb5\n", pre);
+ printf("%sVPD page=0xb6\n", pre);
break;
case 0xb7:
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool ble = false;
+
+ pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Block limits extension VPD page (SBC):";
+ np = "Block limits extension VPD page";
+ ep = "(SBC)";
+ ble = true;
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_b7_vpd(rp, len, op->do_hex, pdt);
+ 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);
+ if (ble)
+ decode_block_limits_ext_vpd(rp, len, op, jo2p);
+ else
+ return SG_LIB_CAT_OTHER;
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
@@ -3063,30 +2808,43 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case 0xb8: /* VPD_FORMAT_PRESETS */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
+ bool fp = false;
+
+ pdt = rp[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- np = "Format presets VPD page (SBC):";
+ np = "Format presets VPD page";
+ ep = "(SBC)";
+ fp = true;
break;
default:
np = NULL;
break;
}
if (NULL == np)
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else if (allow_name || allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : "");
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_format_presets_vpd(rp, len, op->do_hex);
+ 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, "format_preset_"
+ "descriptor_list");
+ }
+ if (fp)
+ decode_format_presets_vpd(rp, len, op, jap);
+ else
+ return SG_LIB_CAT_OTHER;
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
(0 == op->examine))
- printf("%sVPD page=0xb7\n", pre);
+ printf("%sVPD page=0xb8\n", pre);
break;
case 0xb9: /* VPD_CON_POS_RANGE */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c
index 111185a1..c7943f45 100644
--- a/src/sg_vpd_common.c
+++ b/src/sg_vpd_common.c
@@ -42,6 +42,14 @@ const char * product_id_hr = "Product_identification";
const char * product_id_js = "product_identification";
const char * product_rev_lev_hr = "Product_revision_level";
const char * product_rev_lev_js = "product_revision_level";
+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";
+static const char * const ns_s = "not supported";
+static const char * const rsv_s = "Reserved";
+static const char * const vs_s = "Vendor specific";
+static const char * const null_s = "";
+static const char * const mn_s = "meaning";
sgj_opaque_p
sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
@@ -286,12 +294,12 @@ decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
cp = "Logical unit group";
break;
default:
- cp = "reserved";
+ cp = rsv_s;
break;
}
jo2p = sgj_hr_js_subo_r(jsp, jop, 2, np, SGJ_SEP_EQUAL_NO_SPACE,
- n);
- sgj_js_nv_s(jsp, jo2p, "meaning", cp);
+ n, false);
+ sgj_js_nv_s(jsp, jo2p, mn_s, cp);
if (jsp->pr_name_ex)
sgj_js_nv_s(jsp, jo2p, "abbreviated_name_expansion", nex_p);
} else
@@ -479,7 +487,7 @@ decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
n = 0;
ppc = (bp[0] & 0x3f);
pspc = bp[1];
- snprintf(b + n, blen - n, " Policy page code: 0x%x", ppc);
+ n = snprintf(b + n, blen - n, " Policy page code: 0x%x", ppc);
if (pspc)
n += snprintf(b + n, blen - n, ", subpage code: 0x%x", pspc);
sgj_pr_hr(jsp, "%s\n", b);
@@ -626,7 +634,7 @@ decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (len < 60)
return;
if (0xec == cc)
- cp = "";
+ cp = null_s;
else if (0xa1 == cc)
cp = "PACKET ";
else
@@ -784,7 +792,7 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (0xff == bp[2])
sgj_pr_hr(jsp, "%sUnknown [0xff]\n", b);
else if (bp[2] >= 0x20)
- sgj_pr_hr(jsp, "%sReserved [0x%x]\n", b, bp[2]);
+ sgj_pr_hr(jsp, "%s%s [0x%x]\n", b, rsv_s, bp[2]);
else
sgj_pr_hr(jsp, "%s%s [0x%x]\n", b,
sg_get_pdt_str(PDT_MASK & bp[2], dlen, d), bp[2]);
@@ -837,8 +845,8 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_pr_hr(jsp, " Vendor specific data (in "
"hex):\n");
else
- sgj_pr_hr(jsp, " Reserved [0x%x] specific "
- "data (in hex):\n", cs_type);
+ sgj_pr_hr(jsp, " %s [0x%x] specific data (in "
+ "hex):\n", rsv_s, cs_type);
if (jsp->pr_as_json)
sgj_js_nv_hex_bytes(jsp, jo3p,
"constituent_specific_data_hex",
@@ -901,7 +909,7 @@ tpgs_str(int tpgs)
return "both explicit and implicit asymmetric logical unit access";
case 0:
default:
- return "not supported";
+ return ns_s;
}
}
@@ -1057,6 +1065,7 @@ decode_power_consumption(uint8_t * buff, int len, struct opts_t * op,
}
}
+
/* VPD_BLOCK_LIMITS 0xb0 ["bl"] */
void
decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
@@ -1071,7 +1080,6 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
static const char * mcawl = "Maximum compare and write length";
static const char * otlg = "Optimal transfer length granularity";
static const char * cni = "command not implemented";
- static const char * nr = "not reported";
static const char * ul = "unlimited";
static const char * mtl = "Maximum transfer length";
static const char * otl = "Optimal transfer length";
@@ -1108,36 +1116,36 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
u = sg_get_unaligned_be16(buff + 6);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otlg, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otlg, nr_s);
sgj_convert_to_snake_name(otlg, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, otlg, SGJ_SEP_COLON_1_SPACE, u,
true, "unit: LB");
u = sg_get_unaligned_be32(buff + 8);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mtl, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mtl, nr_s);
sgj_convert_to_snake_name(mtl, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, mtl, SGJ_SEP_COLON_1_SPACE, u,
true, "unit: LB");
u = sg_get_unaligned_be32(buff + 12);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otl, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otl, nr_s);
sgj_convert_to_snake_name(otl, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, otl, SGJ_SEP_COLON_1_SPACE, u,
true, "unit: LB");
if (len > 19) { /* added in sbc3r09 */
u = sg_get_unaligned_be32(buff + 16);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mpl, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mpl, nr_s);
sgj_convert_to_snake_name(mpl, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, mpl, SGJ_SEP_COLON_1_SPACE, u,
true, "unit: LB");
@@ -1170,9 +1178,9 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (len > 35) { /* added in sbc3r19 */
u = sg_get_unaligned_be32(buff + 28);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", oug, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", oug, nr_s);
sgj_convert_to_snake_name(oug, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, oug, SGJ_SEP_COLON_1_SPACE, u,
true, "unit: LB");
@@ -1189,9 +1197,9 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (len > 43) { /* added in sbc3r26 */
ull = sg_get_unaligned_be64(buff + 36);
if (0 == ull) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mwsl, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mwsl, nr_s);
sgj_convert_to_snake_name(mwsl, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, ull, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, ull, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, mwsl, SGJ_SEP_COLON_1_SPACE,
ull, true, "unit: LB");
@@ -1199,9 +1207,9 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (len > 47) { /* added in sbc4r02 */
u = sg_get_unaligned_be32(buff + 44);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matl, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matl, nr_s);
sgj_convert_to_snake_name(matl, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, matl, SGJ_SEP_COLON_1_SPACE,
u, true, "unit: LB");
@@ -1231,9 +1239,9 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
if (len > 56) {
u = sg_get_unaligned_be32(buff + 56);
if (0 == u) {
- sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matlwab, nr);
+ sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matlwab, nr_s);
sgj_convert_to_snake_name(matlwab, b, blen);
- sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s);
} else
sgj_hr_js_vi_nex(jsp, jop, 2, matlwab, SGJ_SEP_COLON_1_SPACE,
u, true, "unit: LB");
@@ -1250,3 +1258,706 @@ decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op,
u, true, "unit: LB");
}
}
+
+static const char * product_type_arr[] =
+{
+ "Not specified",
+ "CFast",
+ "CompactFlash",
+ "MemoryStick",
+ "MultiMediaCard",
+ "Secure Digital Card (SD)",
+ "XQD",
+ "Universal Flash Storage Card (UFS)",
+};
+
+/* ZONED field here replaced by ZONED BLOCK DEVICE EXTENSION field in the
+ * Zoned Block Device Characteristics VPD page. The new field includes
+ * Zone Domains and Realms (see ZBC-2) */
+static const char * bdc_zoned_strs[] = {
+ nr_s,
+ "host-aware",
+ "host-managed",
+ rsv_s,
+};
+
+/* VPD_BLOCK_DEV_CHARS 0xb1 ["bdc"] */
+void
+decode_block_dev_ch_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ int zoned;
+ unsigned int u, k;
+ sgj_state * jsp = &op->json_st;
+ const char * cp;
+ char b[144];
+ static const int blen = sizeof(b);
+ static const char * mrr_j = "medium_rotation_rate";
+ static const char * mrr_h = "Medium rotation rate";
+ static const char * nrm = "Non-rotating medium (e.g. solid state)";
+ static const char * pt_j = "product_type";
+
+ if (len < 64) {
+ pr2serr("page length too short=%d\n", len);
+ return;
+ }
+ u = sg_get_unaligned_be16(buff + 4);
+ if (0 == u) {
+ sgj_pr_hr(jsp, " %s is %s\n", mrr_h, nr_s);
+ sgj_js_nv_ihexstr(jsp, jop, mrr_j, 0, NULL, nr_s);
+ } else if (1 == u) {
+ sgj_pr_hr(jsp, " %s\n", nrm);
+ sgj_js_nv_ihexstr(jsp, jop, mrr_j, 1, NULL, nrm);
+ } else if ((u < 0x401) || (0xffff == u)) {
+ sgj_pr_hr(jsp, " %s [0x%x]\n", rsv_s, u);
+ sgj_js_nv_ihexstr(jsp, jop, mrr_j, u, NULL, rsv_s);
+ } else {
+ sgj_js_nv_ihex_nex(jsp, jop, mrr_j, u, true,
+ "unit: rpm; nominal rotation rate");
+ }
+ u = buff[6];
+ k = SG_ARRAY_SIZE(product_type_arr);
+ if (u < k) {
+ sgj_pr_hr(jsp, " %s: %s\n", "Product type", product_type_arr[u]);
+ sgj_js_nv_ihexstr(jsp, jop, pt_j, u, NULL, product_type_arr[u]);
+ } else {
+ sgj_pr_hr(jsp, " %s: %s [0x%x]\n", "Product type",
+ (u < 0xf0) ? rsv_s : vs_s, u);
+ sgj_js_nv_ihexstr(jsp, jop, pt_j, u, NULL, (u < 0xf0) ? rsv_s : vs_s);
+ }
+ sgj_hr_js_vi_nex(jsp, jop, 2, "WABEREQ", SGJ_SEP_EQUAL_NO_SPACE,
+ (buff[7] >> 6) & 0x3, false,
+ "Write After Block Erase REQuired");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "WACEREQ", SGJ_SEP_EQUAL_NO_SPACE,
+ (buff[7] >> 4) & 0x3, false,
+ "Write After Cryptographic Erase REQuired");
+ u = buff[7] & 0xf;
+ switch (u) {
+ case 0:
+ snprintf(b, blen, nr_s);
+ break;
+ case 1:
+ snprintf(b, blen, "5.25 inch");
+ break;
+ case 2:
+ snprintf(b, blen, "3.5 inch");
+ break;
+ case 3:
+ snprintf(b, blen, "2.5 inch");
+ break;
+ case 4:
+ snprintf(b, blen, "1.8 inch");
+ break;
+ case 5:
+ snprintf(b, blen, "less then 1.8 inch");
+ break;
+ default:
+ snprintf(b, blen, rsv_s);
+ break;
+ }
+ sgj_pr_hr(jsp, " Nominal form factor: %s\n", b);
+ sgj_js_nv_ihexstr(jsp, jop, "nominal_forn_factor", u, NULL, b);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "MACT", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[8] & 0x40), false, "Multiple ACTuator");
+ printf(" MACT=%d\n", !!(buff[8] & 0x40)); /* added sbc5r01 */
+ zoned = (buff[8] >> 4) & 0x3; /* added sbc4r04, obsolete sbc5r01 */
+ cp = bdc_zoned_strs[zoned];
+ sgj_pr_hr(jsp, " ZONED=%d [%s]\n", zoned, cp);
+ sgj_js_nv_ihexstr_nex(jsp, jop, "zoned", zoned, false, NULL,
+ cp, "Added in SBC-4, obsolete in SBC-5");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "RBWZ", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[8] & 0x4), false,
+ "Background Operation Control Supported");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "FUAB", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[8] & 0x2), false,
+ "Force Unit Access Behaviour");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "VBULS", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[8] & 0x1), false,
+ "Verify Byte check Unmapped Lba Supported");
+ u = sg_get_unaligned_be32(buff + 12);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "DEPOPULATION TIME", SGJ_SEP_COLON_1_SPACE,
+ u, true, "unit: second");
+}
+
+static const char * prov_type_arr[8] = {
+ "not known or fully provisioned",
+ "resource provisioned",
+ "thin provisioned",
+ rsv_s,
+ rsv_s,
+ rsv_s,
+ rsv_s,
+ rsv_s,
+};
+
+/* VPD_LB_PROVISIONING 0xb2 ["lbpv"] */
+int
+decode_block_lb_prov_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ unsigned int u, dp, pt, t_exp;
+ sgj_state * jsp = &op->json_st;
+ const char * cp;
+ char b[1024];
+ static const int blen = sizeof(b);
+ static const char * mp = "Minimum percentage";
+ static const char * tp = "Threshold percentage";
+ static const char * pgd = "Provisioning group descriptor";
+
+ if (len < 4) {
+ pr2serr("page too short=%d\n", len);
+ return SG_LIB_CAT_MALFORMED;
+ }
+ t_exp = buff[4];
+ sgj_js_nv_ihexstr(jsp, jop, "threshold_exponent", t_exp, NULL,
+ (0 == t_exp) ? ns_s : NULL);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "LBPU", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[5] & 0x80), false,
+ "Logical Block Provisioning Unmap command supported");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "LBPWS", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[5] & 0x40), false, "Logical Block Provisioning "
+ "Write Same (16) command supported");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "LBPWS10", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[5] & 0x20), false,
+ "Logical Block Provisioning Write Same (10) command "
+ "supported");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "LBPRZ", SGJ_SEP_EQUAL_NO_SPACE,
+ (0x7 & (buff[5] >> 2)), true,
+ "Logical Block Provisioning Read Zero");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "ANC_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(buff[5] & 0x2), false,
+ "ANChor SUPported");
+ dp = !!(buff[5] & 0x1);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "DP", SGJ_SEP_EQUAL_NO_SPACE,
+ dp, false, "Descriptor Present");
+ u = 0x1f & (buff[6] >> 3); /* minimum percentage */
+ if (0 == u)
+ sgj_pr_hr(jsp, " %s: 0 [%s]\n", mp, nr_s);
+ else
+ sgj_pr_hr(jsp, " %s: %u\n", mp, u);
+ sgj_convert_to_snake_name(mp, b, blen);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, (0 == u) ? nr_s : NULL);
+ pt = buff[6] & 0x7;
+ cp = prov_type_arr[pt];
+ if (pt > 2)
+ snprintf(b, blen, " [%u]]", u);
+ else
+ b[0] = '\0';
+ sgj_pr_hr(jsp, " Provisioning type: %s%s\n", cp, b);
+ sgj_js_nv_ihexstr(jsp, jop, "provisioning_type", pt, NULL, cp);
+ u = buff[7]; /* threshold percentage */
+ snprintf(b, blen, "%s ", tp);
+ if (0 == u)
+ sgj_pr_hr(jsp, " %s: 0 [percentages %s]\n", b, ns_s);
+ else
+ sgj_pr_hr(jsp, " %s: %u", b, u);
+ sgj_convert_to_snake_name(tp, b, blen);
+ sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, (0 == u) ? ns_s : NULL);
+ if (dp && (len > 11)) {
+ int i_len;
+ const uint8_t * bp;
+ sgj_opaque_p jo2p;
+
+ bp = buff + 8;
+ i_len = bp[3];
+ if (0 == i_len) {
+ pr2serr("%s too short=%d\n", pgd, i_len);
+ return 0;
+ }
+ if (jsp->pr_as_json) {
+ jo2p = sgj_snake_named_subobject_r(jsp, jop, pgd);
+ sgj_js_designation_descriptor(jsp, jo2p, bp, i_len + 4);
+ }
+ sgj_pr_hr(jsp, " %s:\n", pgd);
+ sg_get_designation_descriptor_str(" ", bp, i_len + 4, true,
+ op->do_long, blen, b);
+ if (jsp->pr_as_json && jsp->pr_out_hr)
+ sgj_js_str_out(jsp, b, strlen(b));
+ else
+ printf("%s", b);
+ }
+ return 0;
+}
+
+/* VPD_REFERRALS 0xb3 ["ref"] */
+void
+decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ uint32_t u;
+ sgj_state * jsp = &op->json_st;
+ char b[64];
+
+ if (len < 16) {
+ pr2serr("Referrals VPD page length too short=%d\n", len);
+ return;
+ }
+ u = sg_get_unaligned_be32(buff + 8);
+ snprintf(b, sizeof(b), " User data segment size: ");
+ if (0 == u)
+ sgj_pr_hr(jsp, "%s0 [per sense descriptor]\n", b);
+ else
+ sgj_pr_hr(jsp, "%s%u\n", b, u);
+ sgj_js_nv_ihex(jsp, jop, "user_data_segment_size", u);
+ u = sg_get_unaligned_be32(buff + 12);
+ sgj_hr_js_vi(jsp, jop, 2, "User data segment multiplier",
+ SGJ_SEP_COLON_1_SPACE, u, true);
+}
+
+/* VPD_SUP_BLOCK_LENS 0xb4 ["sbl"] (added sbc4r01) */
+void
+decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k;
+ unsigned int u;
+ uint8_t * bp;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p = NULL;
+
+ if (len < 4) {
+ pr2serr("page length too short=%d\n", len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0; k < len; k += 8, bp += 8) {
+ if (jsp->pr_as_json)
+ jo2p = sgj_new_unattached_object_r(jsp);
+ u = sg_get_unaligned_be32(bp);
+ sgj_hr_js_vi(jsp, jo2p, 2, "Logical block length",
+ SGJ_SEP_COLON_1_SPACE, u, true);
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "P_I_I_SUP",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x40), false,
+ "Protection Information Interval SUPported");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "NO_PI_CHK",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x8), false,
+ "NO Protection Information CHecKing");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "GRD_CHK",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x4), false,
+ "GuaRD CHecK");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "APP_CHK",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x2), false,
+ "APPlication tag CHecK");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "REF_CHK",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x1), false,
+ "REFerence tag CHecK");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "T3PS",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x8), false,
+ "Type 3 Protection Supported");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "T2PS",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x4), false,
+ "Type 2 Protection Supported");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "T1PS",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x2), false,
+ "Type 1 Protection Supported");
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "T0PS",
+ SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x1), false,
+ "Type 0 Protection Supported");
+ sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+}
+
+/* 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)
+{
+ bool b_active = false;
+ bool combined = false;
+ int n;
+ uint32_t u;
+ sgj_state * jsp = &op->json_st;
+ const char * utp = null_s;
+ const char * uup = null_s;
+ const char * uip = null_s;
+ char b[128];
+ static const int blen = sizeof(b);
+
+ if (len < 16) {
+ pr2serr("page length too short=%d\n", len);
+ return;
+ }
+ switch (buff[5]) {
+ case 1:
+ utp = "Combined writes and reads";
+ combined = true;
+ break;
+ case 2:
+ utp = "Writes only";
+ break;
+ case 3:
+ utp = "Separate writes and reads";
+ b_active = true;
+ break;
+ default:
+ utp = rsv_s;
+ break;
+ }
+ sgj_hr_js_vistr(jsp, jop, 2, "Utilization type", SGJ_SEP_COLON_1_SPACE,
+ buff[5], true, utp);
+ switch (buff[6]) {
+ case 2:
+ uup = "megabytes";
+ break;
+ case 3:
+ uup = "gigabytes";
+ break;
+ case 4:
+ uup = "terabytes";
+ break;
+ case 5:
+ uup = "petabytes";
+ break;
+ case 6:
+ uup = "exabytes";
+ break;
+ default:
+ uup = rsv_s;
+ break;
+ }
+ sgj_hr_js_vistr(jsp, jop, 2, "Utilization units", SGJ_SEP_COLON_1_SPACE,
+ buff[6], true, uup);
+ switch (buff[7]) {
+ case 0xa:
+ uip = "per day";
+ break;
+ case 0xe:
+ uip = "per year";
+ break;
+ default:
+ uip = rsv_s;
+ break;
+ }
+ sgj_hr_js_vistr(jsp, jop, 2, "Utilization interval",
+ SGJ_SEP_COLON_1_SPACE, buff[7], true, uip);
+ u = sg_get_unaligned_be32(buff + 8);
+ sgj_hr_js_vistr(jsp, jop, 2, "Utilization B", SGJ_SEP_COLON_1_SPACE,
+ u, true, (b_active ? NULL : rsv_s));
+ n = sg_scnpr(b, blen, "%s: ", "Designed utilization");
+ if (b_active)
+ n += sg_scnpr(b + n, blen - n, "%u %s for reads and ", u, uup);
+ u = sg_get_unaligned_be32(buff + 12);
+ sgj_hr_js_vi(jsp, jop, 2, "Utilization A", SGJ_SEP_COLON_1_SPACE, u, true);
+ n += sg_scnpr(b + n, blen - n, "%u %s for %swrites, %s", u, uup,
+ combined ? "reads and " : null_s, uip);
+ sgj_pr_hr(jsp, " %s\n", b);
+ if (jsp->pr_string)
+ sgj_js_nv_s(jsp, jop, "summary", b);
+}
+
+/* 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)
+{
+ uint32_t u, pdt;
+ sgj_state * jsp = &op->json_st;
+ char b[128];
+ static const int blen = sizeof(b);
+
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 64) {
+ pr2serr("Zoned block device characteristics VPD page length too "
+ "short=%d\n", len);
+ return;
+ }
+ pdt = PDT_MASK & buff[0];
+ sgj_pr_hr(jsp, " Peripheral device type: %s\n",
+ sg_get_pdt_str(pdt, blen, b));
+
+ printf(" Zoned block device extension: ");
+ u = (buff[4] >> 4) & 0xf;
+ switch (u) {
+ case 0:
+ if (PDT_ZBC == (PDT_MASK & buff[0]))
+ snprintf(b, blen, "host managed zoned block device");
+ else
+ snprintf(b, blen, "%s", nr_s);
+ break;
+ case 1:
+ snprintf(b, blen, "host aware zoned block device model");
+ break;
+ case 2:
+ snprintf(b, blen, "Domains and realms zoned block device model");
+ break;
+ default:
+ snprintf(b, blen, "%s", rsv_s);
+ break;
+ }
+ sgj_hr_js_vistr(jsp, jop, 2, "Zoned block device extension",
+ SGJ_SEP_COLON_1_SPACE, u, true, b);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "AAORB", SGJ_SEP_COLON_1_SPACE,
+ !!(buff[4] & 0x2), false,
+ "Activation Aligned On Realm Boundaries");
+ sgj_hr_js_vi_nex(jsp, jop, 2, "URSWRZ", SGJ_SEP_COLON_1_SPACE,
+ !!(buff[4] & 0x1), false,
+ "Unrestricted Read in Sequential Write Required Zone");
+ u = sg_get_unaligned_be32(buff + 8);
+ sgj_hr_js_vistr(jsp, jop, 2, "Optimal number of open sequential write "
+ "preferred zones", SGJ_SEP_COLON_1_SPACE, u, true,
+ (SG_LIB_UNBOUNDED_32BIT == u) ? nr_s : NULL);
+ u = sg_get_unaligned_be32(buff + 12);
+ sgj_hr_js_vistr(jsp, jop, 2, "Optimal number of non-sequentially "
+ "written sequential write preferred zones",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (SG_LIB_UNBOUNDED_32BIT == u) ? nr_s : NULL);
+ u = sg_get_unaligned_be32(buff + 16);
+ sgj_hr_js_vistr(jsp, jop, 2, "Maximum number of open sequential write "
+ "required zones", SGJ_SEP_COLON_1_SPACE, u, true,
+ (SG_LIB_UNBOUNDED_32BIT == u) ? nl_s : NULL);
+ u = buff[23] & 0xf;
+ switch (u) {
+ case 0:
+ snprintf(b, blen, "not reported\n");
+ break;
+ case 1:
+ snprintf(b, blen, "Zoned starting LBAs aligned using constant zone "
+ "lengths");
+ break;
+ case 0x8:
+ snprintf(b, blen, "Zoned starting LBAs potentially non-constant (as "
+ "reported by REPORT ZONES)");
+ break;
+ default:
+ snprintf(b, blen, "%s", rsv_s);
+ break;
+ }
+ sgj_hr_js_vistr(jsp, jop, 2, "Zoned alignment method",
+ SGJ_SEP_COLON_1_SPACE, u, true, b);
+ sgj_hr_js_vi(jsp, jop, 2, "Zone starting LBA granularity",
+ SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(buff + 24),
+ true);
+}
+
+/* VPD_BLOCK_LIMITS_EXT 0xb7 ["ble"] SBC */
+void
+decode_block_limits_ext_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ uint32_t u;
+ sgj_state * jsp = &op->json_st;
+
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 12) {
+ pr2serr("page length too short=%d\n", len);
+ return;
+ }
+ u = sg_get_unaligned_be16(buff + 6);
+ sgj_hr_js_vistr(jsp, jop, 2, "Maximum number of streams",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u) ? "Stream control not supported" : NULL);
+ u = sg_get_unaligned_be16(buff + 8);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "Optimal stream write size",
+ SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB");
+ u = sg_get_unaligned_be32(buff + 10);
+ sgj_hr_js_vi_nex(jsp, jop, 2, "Stream granularity size",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ "unit: number of optimal stream write size blocks");
+ if (len < 28)
+ return;
+ u = sg_get_unaligned_be32(buff + 16);
+ sgj_hr_js_vistr_nex(jsp, jop, 2, "Maximum scattered LBA range transfer "
+ "length", SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? nlr_s : NULL),
+ "unit: LB (in a single LBA range descriptor)");
+ u = sg_get_unaligned_be16(buff + 22);
+ sgj_hr_js_vistr(jsp, jop, 2, "Maximum scattered LBA range descriptor "
+ "count", SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? nlr_s : NULL));
+ u = sg_get_unaligned_be32(buff + 24);
+ sgj_hr_js_vistr_nex(jsp, jop, 2, "Maximum scattered transfer length",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? nlr_s : NULL),
+ "unit: LB (per single Write Scattered command)");
+}
+
+static const char * sch_type_arr[8] = {
+ rsv_s,
+ "non-zoned",
+ "host aware zoned",
+ "host managed zoned",
+ "zone domain and realms zoned",
+ rsv_s,
+ rsv_s,
+ rsv_s,
+};
+
+static char *
+get_zone_align_method(uint8_t val, char * b, int blen)
+{
+ switch (val) {
+ case 0:
+ snprintf(b, blen, "%s", nr_s);
+ break;
+ case 1:
+ snprintf(b, blen, "%s", "using constant zone lengths");
+ break;
+ case 8:
+ snprintf(b, blen, "%s", "taking gap zones into account");
+ break;
+ default:
+ snprintf(b, blen, "%s", rsv_s);
+ break;
+ }
+ return b;
+}
+
+/* VPD_FORMAT_PRESETS 0xb8 ["fp"] (added sbc4r18) */
+void
+decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ uint8_t sch_type;
+ int k;
+ uint32_t u;
+ uint64_t ul;
+ sgj_state * jsp = &op->json_st;
+ uint8_t * bp;
+ sgj_opaque_p jo2p, jo3p;
+ const char * cp;
+ char b[128];
+ char d[64];
+ static const int blen = sizeof(b);
+ static const int dlen = sizeof(d);
+ static const char * llczp = "Low LBA conventional zones percentage";
+ static const char * hlczp = "High LBA conventional zones percentage";
+ static const char * ztzd = "Zone type for zone domain";
+
+ 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 += 64, bp += 64) {
+ jo2p = sgj_new_unattached_object_r(jsp);
+ sgj_hr_js_vi(jsp, jo2p, 2, "Preset identifier", SGJ_SEP_COLON_1_SPACE,
+ sg_get_unaligned_be64(bp + 0), true);
+ sch_type = bp[4];
+ if (sch_type < 8) {
+ cp = sch_type_arr[sch_type];
+ if (rsv_s != cp)
+ snprintf(b, blen, "%s block device", cp);
+ else
+ snprintf(b, blen, "%s", cp);
+ } else
+ snprintf(b, blen, "%s", rsv_s);
+ sgj_hr_js_vistr(jsp, jo2p, 4, "Schema type", SGJ_SEP_COLON_1_SPACE,
+ sch_type, true, b);
+ sgj_hr_js_vi(jsp, jo2p, 4, "Logical blocks per physical block "
+ "exponent", SGJ_SEP_COLON_1_SPACE,
+ 0xf & bp[7], true);
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "Logical block length",
+ SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8),
+ true, "unit: byte");
+ sgj_hr_js_vi(jsp, jo2p, 4, "Designed last Logical Block Address",
+ SGJ_SEP_COLON_1_SPACE,
+ sg_get_unaligned_be64(bp + 16), true);
+ sgj_hr_js_vi_nex(jsp, jo2p, 4, "FMTPINFO", SGJ_SEP_COLON_1_SPACE,
+ (bp[38] >> 6) & 0x3, false,
+ "ForMaT Protecion INFOrmation (see Format Unit)");
+ sgj_hr_js_vi(jsp, jo2p, 4, "Protection field usage",
+ SGJ_SEP_COLON_1_SPACE, bp[38] & 0x7, false);
+ sgj_hr_js_vi(jsp, jo2p, 4, "Protection interval exponent",
+ SGJ_SEP_COLON_1_SPACE, bp[39] & 0xf, true);
+ jo3p = sgj_named_subobject_r(jsp, jo2p,
+ "schema_type_specific_information");
+ switch (sch_type) {
+ case 2:
+ sgj_pr_hr(jsp, " Defines zones for host aware device:\n");
+ u = bp[40 + 0];
+ sgj_pr_hr(jsp, " %s: %u.%u %%\n", llczp, u / 10, u % 10);
+ sgj_convert_to_snake_name(llczp, b, blen);
+ sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a "
+ "percent");
+ u = bp[40 + 1];
+ sgj_pr_hr(jsp, " %s: %u.%u %%\n", hlczp, u / 10, u % 10);
+ sgj_convert_to_snake_name(hlczp, b, blen);
+ sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a "
+ "percent");
+ u = sg_get_unaligned_be32(bp + 40 + 12);
+ sgj_hr_js_vistr(jsp, jo3p, 6, "Logical blocks per zone",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? rsv_s : NULL));
+ break;
+ case 3:
+ sgj_pr_hr(jsp, " Defines zones for host managed device:\n");
+ u = bp[40 + 0];
+ sgj_pr_hr(jsp, " %s: %u.%u %%\n", llczp, u / 10, u % 10);
+ sgj_convert_to_snake_name(llczp, b, blen);
+ sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a "
+ "percent");
+ u = bp[40 + 1];
+ sgj_pr_hr(jsp, " %s: %u.%u %%\n", hlczp, u / 10, u % 10);
+ sgj_convert_to_snake_name(hlczp, b, blen);
+ sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a "
+ "percent");
+ u = bp[40 + 3] & 0x7;
+ sgj_hr_js_vistr(jsp, jo3p, 6, "Designed zone alignment method",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ get_zone_align_method(u, b, blen));
+ ul = sg_get_unaligned_be64(bp + 40 + 4);
+ sgj_hr_js_vi_nex(jsp, jo3p, 6, "Designed zone starting LBA "
+ "granularity", SGJ_SEP_COLON_1_SPACE, ul, true,
+ "unit: LB");
+ u = sg_get_unaligned_be32(bp + 40 + 12);
+ sgj_hr_js_vistr(jsp, jo3p, 6, "Logical blocks per zone",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? rsv_s : NULL));
+ break;
+ case 4:
+ sgj_pr_hr(jsp, " Defines zones for zone domains and realms "
+ "device:\n");
+ snprintf(b, blen, "%s 0", ztzd);
+ u = bp[40 + 0];
+ sg_get_zone_type_str((u >> 4) & 0xf, dlen, d);
+ sgj_hr_js_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true,
+ d);
+ snprintf(b, blen, "%s 1", ztzd);
+ sg_get_zone_type_str(u & 0xf, dlen, d);
+ sgj_hr_js_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true,
+ d);
+
+ snprintf(b, blen, "%s 2", ztzd);
+ u = bp[40 + 1];
+ sg_get_zone_type_str((u >> 4) & 0xf, dlen, d);
+ sgj_hr_js_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true,
+ d);
+ snprintf(b, blen, "%s 3", ztzd);
+ sg_get_zone_type_str(u & 0xf, dlen, d);
+ sgj_hr_js_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true,
+ d);
+ u = bp[40 + 3] & 0x7;
+ sgj_hr_js_vistr(jsp, jo3p, 6, "Designed zone alignment method",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ get_zone_align_method(u, d, dlen));
+ ul = sg_get_unaligned_be64(bp + 40 + 4);
+ sgj_hr_js_vi_nex(jsp, jo3p, 6, "Designed zone starting LBA "
+ "granularity", SGJ_SEP_COLON_1_SPACE, ul, true,
+ "unit: LB");
+ u = sg_get_unaligned_be32(bp + 40 + 12);
+ sgj_hr_js_vistr(jsp, jo3p, 6, "Logical blocks per zone",
+ SGJ_SEP_COLON_1_SPACE, u, true,
+ (0 == u ? rsv_s : NULL));
+ ul = sg_get_unaligned_be64(bp + 40 + 16);
+ sgj_hr_js_vi_nex(jsp, jo3p, 6, "Designed zone maximum address",
+ SGJ_SEP_COLON_1_SPACE, ul, true, "unit: LBA");
+ break;
+ default:
+ sgj_pr_hr(jsp, " No schema type specific information\n");
+ break;
+ }
+ sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+}
diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h
index 3f182664..0571ece1 100644
--- a/src/sg_vpd_common.h
+++ b/src/sg_vpd_common.h
@@ -10,6 +10,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+/* This is a common header file for the sg_inq and sg_vpd utilities */
+
#include <stdint.h>
#include <stdbool.h>
@@ -154,6 +156,22 @@ void decode_power_consumption(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,
+ struct opts_t * op, sgj_opaque_p jop);
+void decode_referrals_vpd(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,
+ struct opts_t * op, sgj_opaque_p jop);
+void decode_zbdch_vpd(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);
const char * pqual_str(int pqual);
void svpd_enumerate_vendor(int vend_prod_num);