aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--ChangeLog3
-rw-r--r--doc/sg_decode_sense.830
-rw-r--r--include/sg_pr2serr.h25
-rw-r--r--inhex/vpd_bdce.hex18
-rw-r--r--inhex/vpd_lbpv.hex9
-rw-r--r--inhex/vpd_ref.hex9
-rw-r--r--inhex/vpd_sbl.hex10
-rw-r--r--inhex/vpd_sdeb.hex2
-rw-r--r--inhex/vpd_zbdc.hex4
-rw-r--r--lib/sg_pr2serr.c115
-rwxr-xr-xscripts/rescan-scsi-bus.sh2
-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
15 files changed, 1419 insertions, 598 deletions
diff --git a/ChangeLog b/ChangeLog
index a21aa5d8..8186547f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for pre-release sg3_utils-1.48 [20220718] [svn: r961]
+Changelog for pre-release sg3_utils-1.48 [20220727] [svn: r962]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
@@ -22,6 +22,7 @@ Changelog for pre-release sg3_utils-1.48 [20220718] [svn: r961]
- https://github.com/doug-gilbert/sg3_utils/pull/17
applied with tweaks: add timeout parameter
- clean $norm handling
+ - fix handling of '-I <secs>' option
- sg_rep_zones: add Report zone starting LBA granularity
field in REPORT ZONES response [zbc2r12]
- add --brief option, show part of header and last
diff --git a/doc/sg_decode_sense.8 b/doc/sg_decode_sense.8
index 2deaf0cd..440cb0b5 100644
--- a/doc/sg_decode_sense.8
+++ b/doc/sg_decode_sense.8
@@ -1,4 +1,4 @@
-.TH SG_DECODE_SENSE "8" "November 2021" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_DECODE_SENSE "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_decode_sense \- decode SCSI sense and related data
.SH SYNOPSIS
@@ -40,13 +40,18 @@ Another alternate action is when the \fI\-\-err=ES\fR is given. \fIES\fR
is assumed to be an "exit status" value between 0 and 255 from one of the
utilities in this package. A descriptive string is printed. Other options
are ignored apart from \fI\-\-verbose\fR.
+.PP
+When the \fI\-\-nodecode\fR option is given, this utility may be used to
+convert a binary file to hexadecimal or vice versa. The data converted does
+not need to be sense data.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
.TP
\fB\-b\fR, \fB\-\-binary\fR=\fIBFN\fR
-the sense data is read in binary from a file called \fIBFN\fR. The option
+the data is read in binary from a file called \fIBFN\fR. The option
cannot be given with \fI\-\-file=HFN\fR or \fI\-\-inhex=HFN\fR as they
-contradict.
+contradict. The data is assumed to be sense data unless the
+fI\-\-nodecode\fR is given.
.TP
\fB\-c\fR, \fB\-\-cdb\fR
treat the given string of hex arguments as bytes in a SCSI CDB and
@@ -94,7 +99,7 @@ with other utilities in this package that have a \fI\-\-inhex=\fR option.
.TP
\fB\-N\fR, \fB\-\-nodecode\fR
Do not decode the given data as sense or a cdb. Useful when arbitrary data
-is given (e.g. when converting hex to binary).
+is given (e.g. when converting hex to binary or vice versa).
.TP
\fB\-n\fR, \fB\-\-nospace\fR
expect ASCII hexadecimal to be a string of hexadecimal digits with no
@@ -168,6 +173,21 @@ and for this sense data the output should look like this:
For a medium error the Info field is the logical block address (LBA)
of the lowest numbered block that the associated SCSI command was not
able to read (verify or write).
+.PP
+To convert arbitrary binary data to hex, suitable to be parsed by other
+sg3_utils utilities. The \fI\-\-nodecode\fR option is used in this case:
+.PP
+ sg_decode_sense \-N \-i vpd_zbdc.hex \-w vpd_zbdc.bin
+.PP
+The '\-HHH' will output hex to the console (stdout) in a form suitable for
+other utilities in this package to parse as input. And sg_decode_sense can
+also be used to convert from arbitrary hex to binary with:
+.PP
+ sg_decode_sense \-N \-b vpd_zbdc.raw \-HHH
+.PP
+Note that tools like hexdump and od place a counter (i.e. an index starting
+at 0) at the beginning of each line which is a pain when parsing hex.
+The '/-HHH' option(s) does not output that leading counter on each line.
.SH EXIT STATUS
The exit status of sg_decode_sense is 0 when it is successful. Otherwise
see the sg3_utils(8) man page.
@@ -176,7 +196,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2010\-2021 Douglas Gilbert
+Copyright \(co 2010\-2022 Douglas Gilbert
.br
This software is distributed under a BSD\-2\-Clause license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/include/sg_pr2serr.h b/include/sg_pr2serr.h
index ad3cec94..4fc5b681 100644
--- a/include/sg_pr2serr.h
+++ b/include/sg_pr2serr.h
@@ -102,6 +102,7 @@ char * sgj_convert_to_snake_name(const char * in_name, char * sname,
* sgj_ - prefix of all the functions related to (non-)JSON output
* hr - human readable form (as it was before JSON)
* js - JSON only output (unless 'hr_js' given)
+ * hr_js - human readable and JSON output
* pr - has printf() like variadic arguments
* _r - suffix indicating the return value should/must be used
* nv - adds a name-value JSON field (or several)
@@ -183,8 +184,9 @@ sgj_opaque_p sgj_snake_named_subarray_r(sgj_state * jsp, sgj_opaque_p jop,
* NULL jsp->basep is used. If 'name' is non-NULL a new named JSON object is
* added using 'name' and the associated value is a JSON string formed from
* 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array and
- * a JSON string formed from 'value' is added. If successful returns a
- * a pointer newly formed JSON string. */
+ * a JSON string formed from 'value' is added. Note that the jsp->pr_string
+ * setting is ignored by this function. If successful returns a * a pointer
+ * newly formed JSON string. */
sgj_opaque_p sgj_js_nv_s(sgj_state * jsp, sgj_opaque_p jop,
const char * name, const char * value);
sgj_opaque_p sgj_js_nv_s_len(sgj_state * jsp, sgj_opaque_p jop,
@@ -243,6 +245,10 @@ void sgj_hr_js_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
void sgj_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well);
+void sgj_hr_js_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ int64_t value, bool hex_as_well, const char * val_s);
+
/* The '_nex' refers to a "name_extra" (information) sub-object (a JSON
* string) which explains a bit more about the 'name' entry. This is useful
* when T10 specifies the name as an abbreviation (e.g. SYSV). Whether this
@@ -251,13 +257,18 @@ void sgj_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
void sgj_hr_js_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
int64_t value, bool hex_as_well, const char * nex_s);
+void sgj_hr_js_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ int64_t value, bool hex_as_well,
+ const char * val_s, const char * nex_s);
/* Similar to above '_hr_js_' calls but a named sub-object is always formed
* containing a JSON integer object named "i" whose value is 'value'. The
* returned pointer is to that sub-object. */
sgj_opaque_p sgj_hr_js_subo_r(sgj_state * jsp, sgj_opaque_p jop,
int leadin_sp, const char * name,
- enum sgj_separator_t sep, int64_t value);
+ enum sgj_separator_t sep, int64_t value,
+ bool hex_as_well);
/* Similar to sgj_hr_js_vs()'s description with 'JSON string object'
* replaced by 'JSON boolean object'. */
@@ -295,16 +306,16 @@ void sgj_js_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop,
* if jop is NULL) along with a value. If jsp->pr_name_ex is true then that
* value is two sub-objects, one named 'i' with a 'val_i' as a JSON integer,
* the other one named "abbreviated_name_expansion" with value nex_s rendered
- * as a JSON string. If jsp->pr_hex and 'want_hex' are true, then a
+ * as a JSON string. If jsp->pr_hex and 'hex_as_well' are true, then a
* sub-object named 'hex' with a value rendered as a hex string equal to
- * val_i. If jsp->pr_name_ex is false and either jsp->pr_hex or want_hex are
+ * val_i. If jsp->pr_name_ex is false and either jsp->pr_hex or hex_as_well are
* false then there are no sub-objects and the 'val_i' is rendered as a JSON
* integer. */
void sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- int64_t val_i, bool want_hex, const char * nex_s);
+ int64_t val_i, bool hex_as_well, const char * nex_s);
void sgj_js_nv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, int64_t val_i, bool want_hex,
+ const char * name, int64_t val_i, bool hex_as_well,
const char * str_name, const char * val_s,
const char * nex_s);
diff --git a/inhex/vpd_bdce.hex b/inhex/vpd_bdce.hex
new file mode 100644
index 00000000..d20c5304
--- /dev/null
+++ b/inhex/vpd_bdce.hex
@@ -0,0 +1,18 @@
+#
+# This is a manufactured response to an INQUIRY for the
+# Block device characteristics extension VPD page (0xb5 ["bdce"]).
+# It may have been generated by a call like this:
+# sg_vpd -p bdce /dev/sg3 -HHHH
+
+# Block device characteristics extension VPD page
+00 b5 00 7c
+00 03 05 0e 00 00 00 06 00 00 00 03
+
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/inhex/vpd_lbpv.hex b/inhex/vpd_lbpv.hex
new file mode 100644
index 00000000..a89af17b
--- /dev/null
+++ b/inhex/vpd_lbpv.hex
@@ -0,0 +1,9 @@
+#
+# This is a manufactured response to an INQUIRY for the
+# Logical Block Provisioning VPD page (0xb2 ["lbpv"]). It may
+# have been generated by a call like this:
+# sg_vpd -p lbpv /dev/sg3 -HHHH
+
+# Logical block provisioning VPD page
+00 b2 00 10 00 01 00 00
+01 03 00 08 51 22 33 44 55 66 77 88
diff --git a/inhex/vpd_ref.hex b/inhex/vpd_ref.hex
new file mode 100644
index 00000000..618f911f
--- /dev/null
+++ b/inhex/vpd_ref.hex
@@ -0,0 +1,9 @@
+#
+# This is a manufactured response to an INQUIRY for the
+# Referrals VPD page (0xb3 ["ref"]). It may have been
+# generated by a call like this:
+# sg_vpd -p ref /dev/sg3 -HHHH
+
+# Referrals VPD page
+00 b3 00 0c 00 00 00 00
+11 22 33 44 00 00 10 00
diff --git a/inhex/vpd_sbl.hex b/inhex/vpd_sbl.hex
new file mode 100644
index 00000000..da9e9b1e
--- /dev/null
+++ b/inhex/vpd_sbl.hex
@@ -0,0 +1,10 @@
+#
+# This is a manufactured response to an INQUIRY for the
+# Supported block lengths and protection types VPD page (0xb4 ["sbl"]).
+# It may have been generated by a call like this:
+# sg_vpd -p sbl /dev/sg3 -HHHH
+
+# Supported block lengths and protection types VPD page
+00 b4 00 10
+00 00 02 00 47 07 00 00
+00 00 10 00 47 07 00 00
diff --git a/inhex/vpd_sdeb.hex b/inhex/vpd_sdeb.hex
index ba5cd4ee..2f50c896 100644
--- a/inhex/vpd_sdeb.hex
+++ b/inhex/vpd_sdeb.hex
@@ -1,7 +1,7 @@
#
# The VPD responses in this file where generated from a dummy device
# (ramdisk) associated with the Linux scsi_debug driver as follows:
-# sg_vpd -a /dev/sg0 -HHHH
+# sg_vpd -a /dev/sg3 -HHHH
# Supported VPD pages VPD page
00 00 00 0c 00 80 83 84 85 86 87 88 89 b0 b1 b2
diff --git a/inhex/vpd_zbdc.hex b/inhex/vpd_zbdc.hex
index 371b0c3c..d8d1ad3b 100644
--- a/inhex/vpd_zbdc.hex
+++ b/inhex/vpd_zbdc.hex
@@ -17,8 +17,8 @@
# maximum # of open sequential write required
00 00 00 08
-# Zone alignment mode=0 (therefore no gaps)
-00 00 00 00
+# Zone alignment mode=1 (constant zone lengths)
+00 00 00 01
# Zone starting LBA granularity
00 00 00 02 00 00 00 00
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index 77ee84b4..88e71b02 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -625,14 +625,13 @@ sgj_js_nv_istr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
{
if ((NULL == jsp) || (! jsp->pr_as_json))
return;
- else if (jsp->pr_string) {
+ else if (val_s && jsp->pr_string) {
sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, name);
if (NULL == jo2p)
return;
sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i);
- if (val_s)
- sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
+ sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
} else
sgj_js_nv_i(jsp, jop, name, val_i);
}
@@ -641,9 +640,12 @@ void
sgj_js_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
int64_t val_i, const char * str_name, const char * val_s)
{
+ bool as_str;
+
if ((NULL == jsp) || (! jsp->pr_as_json))
return;
- if ((! jsp->pr_hex) && (! jsp->pr_string))
+ as_str = jsp->pr_string && val_s;
+ if ((! jsp->pr_hex) && (! as_str))
sgj_js_nv_i(jsp, jop, name, val_i);
else {
char b[64];
@@ -651,19 +653,13 @@ sgj_js_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
if (NULL == jo2p)
return;
- if (jsp->pr_string) {
- sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i);
- if (jsp->pr_hex) {
- snprintf(b, sizeof(b), "%" PRIx64, val_i);
- sgj_js_nv_s(jsp, jo2p, "hex", b);
- }
- if (val_s)
- sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
- } else if (jsp->pr_hex) {
- sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (jsp->pr_hex) {
snprintf(b, sizeof(b), "%" PRIx64, val_i);
sgj_js_nv_s(jsp, jo2p, "hex", b);
}
+ if (as_str)
+ sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
}
}
@@ -671,9 +667,9 @@ static const char * sc_nex_s = "name_extra";
void
sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- int64_t val_i, bool want_hex, const char * nex_s)
+ int64_t val_i, bool hex_as_well, const char * nex_s)
{
- bool as_hex = jsp->pr_hex && want_hex;
+ bool as_hex = jsp->pr_hex && hex_as_well;
bool as_nex = jsp->pr_name_ex && nex_s;
if ((NULL == jsp) || (! jsp->pr_as_json))
@@ -688,16 +684,12 @@ sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
if (NULL == jo2p)
return;
sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i);
- if (as_nex) {
- if (jsp->pr_hex && want_hex) {
- snprintf(b, sizeof(b), "%" PRIx64, val_i);
- sgj_js_nv_s(jsp, jo2p, "hex", b);
- }
- sgj_js_nv_s(jsp, jo2p, sc_nex_s, nex_s);
- } else if (as_hex) {
+ if (as_hex) {
snprintf(b, sizeof(b), "%" PRIx64, val_i);
sgj_js_nv_s(jsp, jo2p, "hex", b);
}
+ if (as_nex)
+ sgj_js_nv_s(jsp, jo2p, sc_nex_s, nex_s);
}
}
@@ -721,10 +713,10 @@ sgj_js_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
void
sgj_js_nv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- int64_t val_i, bool want_hex, const char * str_name,
+ int64_t val_i, bool hex_as_well, const char * str_name,
const char * val_s, const char * nex_s)
{
- bool as_hex = jsp->pr_hex && want_hex;
+ bool as_hex = jsp->pr_hex && hex_as_well;
bool as_str = jsp->pr_string && val_s;
bool as_nex = jsp->pr_name_ex && nex_s;
const char * sname = str_name ? str_name : sc_mn_s;
@@ -923,7 +915,8 @@ sgj_hr_js_helper(char * b, int blen_max, const char * name,
static void
sgj_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
- json_value * jvp, bool hex_as_well, const char * nex_s)
+ json_value * jvp, bool hex_as_well, const char * val_s,
+ const char * nex_s)
{
bool eaten = false;
bool as_json = (jsp && jsp->pr_as_json);
@@ -972,19 +965,34 @@ sgj_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
case json_string:
break;
case json_integer:
- sgj_js_nv_ihex_nex(jsp, jop, jname, jvp->u.integer,
- hex_as_well, nex_s);
+ sgj_js_nv_ihexstr_nex(jsp, jop, jname, jvp->u.integer,
+ hex_as_well, sc_mn_s, val_s, nex_s);
done = true;
break;
case json_boolean:
- sgj_js_nv_ihex_nex(jsp, jop, jname, jvp->u.boolean,
- hex_as_well, nex_s);
+ sgj_js_nv_ihexstr_nex(jsp, jop, jname, jvp->u.boolean,
+ false, sc_mn_s, val_s, nex_s);
done = true;
break;
case json_none:
default:
break;
}
+ } else {
+ switch (jtype) {
+ case json_string:
+ break;
+ case json_integer:
+ if (hex_as_well) {
+ sgj_js_nv_ihexstr(jsp, jop, jname, jvp->u.integer,
+ sc_mn_s, val_s);
+ done = true;
+ }
+ break;
+ case json_none:
+ default:
+ break;
+ }
}
if (! done) {
eaten = true;
@@ -1014,7 +1022,7 @@ sgj_hr_js_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
/* make json_value even if jsp->pr_as_json is false */
jvp = value ? json_string_new(value) : NULL;
- sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, false, NULL);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, false, NULL, NULL);
}
void
@@ -1025,18 +1033,45 @@ sgj_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
json_value * jvp;
jvp = json_integer_new(value);
- sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, NULL);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, NULL,
+ NULL);
+}
+
+void
+sgj_hr_js_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, int64_t value,
+ bool hex_as_well, const char * val_s)
+{
+ json_value * jvp;
+
+ jvp = json_integer_new(value);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, val_s,
+ NULL);
}
void
sgj_hr_js_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ int64_t value, bool hex_as_well, const char * nex_s)
+{
+ json_value * jvp;
+
+ jvp = json_integer_new(value);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, NULL,
+ nex_s);
+}
+
+void
+sgj_hr_js_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
const char * name, enum sgj_separator_t sep,
- int64_t value, bool hex_as_well, const char * nex_s)
+ int64_t value, bool hex_as_well,
+ const char * val_s, const char * nex_s)
{
json_value * jvp;
jvp = json_integer_new(value);
- sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, nex_s);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, hex_as_well, val_s,
+ nex_s);
}
void
@@ -1046,12 +1081,13 @@ sgj_hr_js_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
json_value * jvp;
jvp = json_boolean_new(value);
- sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, false, NULL);
+ sgj_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp, false, NULL, NULL);
}
sgj_opaque_p
sgj_hr_js_subo_r(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, int64_t value)
+ const char * name, enum sgj_separator_t sep, int64_t value,
+ bool hex_as_well)
{
bool as_json = (jsp && jsp->pr_as_json);
int n = 0;
@@ -1075,8 +1111,13 @@ sgj_hr_js_subo_r(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
if (as_json) {
sgj_name_to_snake(name, b, blen);
jo2p = sgj_named_subobject_r(jsp, jop, b);
- if (jo2p)
+ if (jo2p) {
sgj_js_nv_i(jsp, jo2p, "i", value);
+ if (hex_as_well && jsp->pr_hex) {
+ snprintf(b, blen, "%" PRIx64, value);
+ sgj_js_nv_s(jsp, jo2p, "hex", b);
+ }
+ }
return jo2p;
}
return NULL;
diff --git a/scripts/rescan-scsi-bus.sh b/scripts/rescan-scsi-bus.sh
index f7e363e8..0c333846 100755
--- a/scripts/rescan-scsi-bus.sh
+++ b/scripts/rescan-scsi-bus.sh
@@ -1229,7 +1229,7 @@ while [ ! -z "$opt" ] && [ -z "${opt##-*}" ] ; do
d) debug=1 ;;
f) flush=1 ;;
i) lipreset=0 ;;
- I) shift; lipreset=$opt ;;
+ I) shift; lipreset=$1 ;;
l) lunsearch=$(seq -s ' ' 0 7) ;;
L) lunsearch=$(seq -s ' ' 0 "$2"); shift ;;
m) mp_enable=1 ;;
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);