aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-07-15 04:28:12 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-07-15 04:28:12 +0000
commitf1c4468bc5353fa361029e790b3ab370d22d5101 (patch)
treea54fd4eff8a43d3aa764fd3de14897e5f2517e19
parenta51fa77e373d1e4a1be10e8e4ef9a87547d26e86 (diff)
downloadsg3_utils-f1c4468bc5353fa361029e790b3ab370d22d5101.tar.gz
sg_inq+sg_vpd: JSON work continues
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@960 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog2
-rw-r--r--doc/sg3_utils_json.861
-rw-r--r--doc/sg_inq.812
-rw-r--r--include/sg_lib.h8
-rw-r--r--inhex/vpd_consistuents.hex32
-rw-r--r--lib/sg_pr2serr.c2
-rw-r--r--src/sg_inq.c698
-rw-r--r--src/sg_vpd.c526
-rw-r--r--src/sg_vpd_common.c414
-rw-r--r--src/sg_vpd_common.h63
10 files changed, 935 insertions, 883 deletions
diff --git a/ChangeLog b/ChangeLog
index 6f009755..478481a3 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 [20220711] [svn: r959]
+Changelog for pre-release sg3_utils-1.48 [20220714] [svn: r960]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
diff --git a/doc/sg3_utils_json.8 b/doc/sg3_utils_json.8
index 0d437470..e8080b59 100644
--- a/doc/sg3_utils_json.8
+++ b/doc/sg3_utils_json.8
@@ -231,35 +231,46 @@ character (ASCII zero and C string terminator) somehow finds its way
into a field that should (according to the spec) be space padded, then
the JSON output may appear truncated.
.PP
-Note that this JSON processing means that if a utility is aborted for
-whatever reason then no JSON output will appear. With the normal,
-human readable output processing, some output may appear before
-the utility aborts in such bad situations.
+Note that this JSON processing means that if a utility is aborted for whatever
+reason then no JSON output will appear. With the normal, human readable output
+processing, some output may appear before the utility aborts in such bad
+situations.
.SH ERRORS
-No attempts has been made to translate errors into JSON form, apart
-from the final "exit_status" JSON object where a value of 0
-means "no errors". Exit status values indicating a problem range
-from 1 to 255.
+No attempts has been made to translate errors into JSON form, apart from the
+final "exit_status" JSON object where a value of 0 means "no errors". Exit
+status values indicating a problem range from 1 to 255.
.PP
-The sg_decode_sense utility will parse SCSI sense data into JSON
-form if requested. So if another utility is failing with a sense
-data report (most often seen when the \fI\-\-verbose\fR option is
-used). That sense data (in hex bytes) could be cut\-and\-paste
-onto the command line following 'sg_decode_sense \-j ' which should
-then render that sense data in JSON.
+The sg_decode_sense utility will parse SCSI sense data into JSON form if
+requested. So if another utility is failing with a sense data report (most
+often seen when the \fI\-\-verbose\fR option is used). That sense data (in
+hex bytes) could be cut\-and\-paste onto the command line
+following 'sg_decode_sense \-j ' which should then render that sense data
+in JSON.
.PP
-Otherwise, when a error is detected while JSON output is selected,
-the error message is sent to stderr in human readable form. Typically
-once an error is detected the utility will exit, first dumping
-the JSON in\-memory tree as discussed above and a non\-zero exit
-status will be set. The JSON output will be well formed but missing
-any fields or list elements following the point that the error
-was detected.
+Otherwise, when a error is detected while JSON output is selected, the error
+message is sent to stderr in human readable form. Typically once an error is
+detected the utility will exit, first dumping the JSON in\-memory tree as
+discussed above and a non\-zero exit status will be set. The JSON output will
+be well formed but missing any fields or list elements following the point
+that the error was detected.
.PP
-The summary is that when JSON output is selected and an error occurs
-each utility will process the error the same way as it would if JSON
-output had not been selected. In all cases error messages, in human
-readable form, are sent to stderr.
+The summary is that when JSON output is selected and an error occurs each
+utility will process the error the same way as it would if JSON output had
+not been selected. In all cases error messages, in human readable form,
+are sent to stderr.
+.SH INTERACTION WITH OTHER OPTIONS
+As stated above, the default output is in human readable form using 7 bit
+ASCII. The \fI\-\-json[=JO]\fR option is designed to be an alternative
+to that human readable form. There are other alternative output formats
+such as the response output as a hexadecimal sequence of bytes or
+in "raw" binary; both of those take precedence over the \fI\-\-json[=JO]\fR
+option. Other specialized output format (e.g. 'sg_inq \-\-export') will
+usually take precedence over JSON output.
+.PP
+When the \fI\-\-raw\fR option is used together with the \fI\-\-inhex=FN\fR
+option only the data input to the utility is interpreted as binary. So the
+output format defaults to human readable form and thus can be changed to
+JSON if the \fI\-\-json[=JO]\fR option is also used.
.SH AUTHORS
Written by Douglas Gilbert. Some utilities have been contributed, see the
CREDITS file and individual source files (in the 'src' directory).
diff --git a/doc/sg_inq.8 b/doc/sg_inq.8
index 9ae5c550..759d7165 100644
--- a/doc/sg_inq.8
+++ b/doc/sg_inq.8
@@ -6,10 +6,10 @@ sg_inq \- issue SCSI INQUIRY command and/or decode its response
[\fI\-\-ata\fR] [\fI\-\-block=0|1\fR] [\fI\-\-cmddt\fR]
[\fI\-\-descriptors\fR] [\fI\-\-export\fR] [\fI\-\-extended\fR]
[\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id\fR]
-[\fI\-\-inhex=FN\fR] [\fI\-\-len=LEN\fR] [\fI\-\-long\fR]
-[\fI\-\-maxlen=LEN\fR] [\fI\-\-only\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR]
-[\fI\-\-vendor\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-vpd\fR]
-\fIDEVICE\fR
+[\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-len=LEN\fR]
+[\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-only\fR] [\fI\-\-page=PG\fR]
+[\fI\-\-raw\fR] [\fI\-\-vendor\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+[\fI\-\-vpd\fR] \fIDEVICE\fR
.PP
.B sg_inq
[\fI\-36\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-\-B=0|1\fR]
@@ -158,6 +158,10 @@ byte each of which is whitespace or comma separated. Anything from and
including a hash mark to the end of a line is ignored. If the \fI\-\-raw\fR
option is also given then \fIFN\fR is treated as binary.
.TP
+\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
+output is in JSON format instead of human readable form. This is an
+EXPERIMENTAL feature; see sg3_utils_json manpage.
+.TP
\fB\-l\fR, \fB\-\-len\fR=\fILEN\fR
the number \fILEN\fR is the "allocation length" field in the INQUIRY cdb.
This is the (maximum) length of the response returned by the device. The
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 8e2f541d..0e2d842c 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -317,10 +317,10 @@ char * sg_get_pdt_str(int pdt, int buff_len, char * buff);
/* Some lesser used PDTs share a lot in common with a more used PDT.
* Examples are PDT_ADC decaying to PDT_TAPE and PDT_ZBC to PDT_DISK.
- * If such a lesser used 'pdt' is given to this function, then it will
- * return the more used PDT (i.e. "decays to"); otherwise 'pdt' is returned.
- * Valid for 'pdt' 0 to 31, for other values returns 0. */
-int sg_lib_pdt_decay(int pdt);
+ * If such a lesser used 'dev_pdt' is given to this function, then it will
+ * return the more used PDT (i.e. "decays to"); otherwise 'dev_pdt' is
+ * returned. Valid for 'pdt' 0 to 31, for other values returns 0. */
+int sg_lib_pdt_decay(int dev_pdt);
/* Yield string associated with transport protocol identifier (tpi). Returns
* 'buff'. If 'tpi' out of range yields "bad tpi" string. */
diff --git a/inhex/vpd_consistuents.hex b/inhex/vpd_consistuents.hex
index 169ebbaa..4a67b74d 100644
--- a/inhex/vpd_consistuents.hex
+++ b/inhex/vpd_consistuents.hex
@@ -3,39 +3,43 @@
# sg_vpd --inhex=vpd_consistuents.hex
-00 8b 00 c6
+# Device constituent VPD page header
+00 8b 00 c2
+# First constituent descriptor, fixed part
00 03 00 00
-
41 42 43 44 20 20 00 00
41 42 43 44 45 46 47 48 41 42 43 44 44 44 44 44
30 31 32 33
+00 00
+00 2a
-00 00 00 2e
-
-01 00 00 14
-
-01 b5 00 10 00 00 00 00
-03 01 20 e0
-07 02 10 80 00 00 00 00
+# inner constituent specific descriptor (for VPD page)
+01 00 00 10
+# ... the VPD page
+00 b3 00 0c 00 00 00 00
+00 20 00 00
+00 00 00 04
+# another inner constituent specific descriptor (for VPD page)
01 00 00 12
-
+# ... the VPD page
00 92 00 0e 00 00 00 00
00 01 01 01 01 02 02 01
09 09
+# Second constituent descriptor, fixed part
00 03 00 00
-
53 45 41 47 41 54 45 20
53 54 32 30 30 46 4d 30 30 37 33 20 20 20 20 20
30 30 30 37
+00 00
+00 50
-00 00 00 50
-
+# inner constituent specific descriptor ("di" VPD page)
01 00 00 4c
-
+# ... the VPD page
00 83 00 48 01 03 00 08 50 00 c5 00 30 11 cb 2b
61 93 00 08 50 00 c5 00 30 11 cb 29 61 94 00 04
00 00 00 01 61 a3 00 08 50 00 c5 00 30 11 cb 28
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index a7bdeaf2..05ea8e31 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -1256,7 +1256,7 @@ sgj_pr_js_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
if (jsp->pr_hex)
sgj_add_nv_hex_bytes(jsp, jop, "scsi_name_string_hexbytes",
ip, dlen);
- snprintf(b, blen, "%s", ip);
+ snprintf(b, blen, "%.*s", dlen, ip);
sgj_add_nv_s(jsp, jop, "scsi_name_string", b);
break;
case 9: /* Protocol specific port identifier */
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 8e5b48d7..98f505d6 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.18 20220511"; /* spc6r06 */
+static const char * version_str = "2.21 20220714"; /* spc6r06 */
#define MY_NAME "sg_inq"
@@ -126,7 +126,10 @@ static const char * find_version_descriptor_str(int value);
static void decode_dev_ids(const char * leadin, uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jop);
static int vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
- int inhex_len);
+ int off);
+
+// Testing <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+#undef SG_SCSI_STRINGS
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
defined(HDIO_GET_IDENTITY)
@@ -136,17 +139,6 @@ struct opts_t;
static void prepare_ata_identify(const struct opts_t * op, int inhex_len);
#endif
-#if 0
-struct svpd_values_name_t {
- int value;
- int subvalue;
- int pdt; /* peripheral device type id, -1 is the default */
- /* (all or not applicable) value */
- int vendor; /* vendor flag */
- const char * acron;
- const char * name;
-};
-#endif
/* Note that this table is sorted by acronym */
static struct svpd_values_name_t t10_vpd_pg[] = {
@@ -159,6 +151,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
{VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
{VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges "
"(SBC)"},
+ {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
{VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
#if 0 /* following found in sg_vpd */
{VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
@@ -178,25 +171,27 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
{VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
{VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},
{VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
- {VPD_PROTO_LU, 0, 0x0, "pslu", "Protocol-specific logical unit "
+ {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
"information"},
- {VPD_PROTO_PORT, 0, 0x0, "pspo", "Protocol-specific port information"},
+ {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
{VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
{VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
"protection types (SBC)"},
{VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"},
{VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
- {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry response"},
+ {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"},
{VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
{VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
{VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
{VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
- {VPD_ZBC_DEV_CHARS, 0, -1, "zbdch", "Zoned block device "
+ {VPD_ZBC_DEV_CHARS, 0, 0, "zbdch", "Zoned block device "
"characteristics"},
{0, 0, 0, NULL, NULL},
};
+/* Some alternate acronyms for T10 VPD pages (compatibility with sg_vpd) */
static struct svpd_values_name_t alt_t10_vpd_pg[] = {
+ {VPD_NOPE_WANT_STD_INQ, 0, -1, "stdinq", "Standard inquiry data format"},
{VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
{0, 0, 0, NULL, NULL},
};
@@ -965,84 +960,60 @@ encode_string(char *out, const uint8_t *in, int inlen)
return j;
}
-struct vpd_name {
- int number;
- int peri_type;
- const char * name;
-};
-
-/* In numerical order */
-static struct vpd_name vpd_name_arr[] = {
- {VPD_SUPPORTED_VPDS, 0, "Supported VPD pages"}, /* 0x0 */
- {VPD_UNIT_SERIAL_NUM, 0, "Unit serial number"}, /* 0x80 */
- {0x81, 0, "Implemented operating definitions (obsolete)"},
- {0x82, 0, "ASCII implemented operating definition (obsolete)"},
- {VPD_DEVICE_ID, 0, "Device identification"},
- {VPD_SOFTW_INF_ID, 0, "Software interface identification"},
- {VPD_MAN_NET_ADDR, 0, "Management network addresses"},
- {VPD_EXT_INQ, 0, "Extended INQUIRY data"},
- {VPD_MODE_PG_POLICY, 0, "Mode page policy"},
- {VPD_SCSI_PORTS, 0, "SCSI ports"},
- {VPD_ATA_INFO, 0, "ATA information"},
- {VPD_POWER_CONDITION, 0, "Power condition"},
- {VPD_DEVICE_CONSTITUENTS, 0, "Device constituents"},
- {VPD_CFA_PROFILE_INFO, 0, "CFA profile information"}, /* 0x8c */
- {VPD_POWER_CONSUMPTION, 0, "Power consumption"}, /* 0x8d */
- {VPD_3PARTY_COPY, 0, "Third party copy"}, /* 0x8f */
- {VPD_PROTO_LU, 0, "Protocol-specific logical unit information"}, /* 0x90 */
- {VPD_PROTO_PORT, 0, "Protocol-specific port information"}, /* 0x91 */
- {VPD_SCSI_FEATURE_SETS, 0, "SCSI Feature sets"}, /* 0x92 */
- /* 0xb0 to 0xbf are per peripheral device type */
- {VPD_BLOCK_LIMITS, 0, "Block limits (sbc2)"}, /* 0xb0 */
- {VPD_BLOCK_DEV_CHARS, 0, "Block device characteristics (sbc3)"},
- {VPD_LB_PROVISIONING, 0, "Logical block provisioning (sbc3)"},
- {VPD_REFERRALS, 0, "Referrals (sbc3)"},
- {0xb0, PDT_TAPE, "Sequential access device capabilities (ssc3)"},
- {0xb2, PDT_TAPE, "TapeAlert supported flags (ssc3)"},
- {0xb0, PDT_OSD, "OSD information (osd)"},
- {0xb1, PDT_OSD, "Security token (osd)"},
- /* 0xc0 to 0xff are vendor specific */
- {0xc0, 0, "vendor: Firmware numbers (seagate); Unit path report (EMC)"},
- {0xc1, 0, "vendor: Date code (seagate)"},
- {0xc2, 0, "vendor: Jumper settings (seagate); Software version (RDAC)"},
- {0xc3, 0, "vendor: Device behavior (seagate)"},
- {0xc9, 0, "Volume Access Control (RDAC)"},
-};
-
-static const char *
-get_vpd_page_str(int vpd_page_num, int scsi_ptype)
+static const struct svpd_values_name_t *
+get_vpd_page_info(int vpd_page_num, int dev_pdt)
{
- int k;
- int vpd_name_arr_sz = (int)SG_ARRAY_SIZE(vpd_name_arr);
+ int decay_pdt;
+ const struct svpd_values_name_t * vnp;
+ const struct svpd_values_name_t * prev_vnp;
- if ((vpd_page_num >= 0xb0) && (vpd_page_num < 0xc0)) {
- /* peripheral device type relevant for 0xb0..0xbf range */
- for (k = 0; k < vpd_name_arr_sz; ++k) {
- if ((vpd_name_arr[k].number == vpd_page_num) &&
- (vpd_name_arr[k].peri_type == scsi_ptype))
+ if (vpd_page_num < 0xb0) { /* take T10 first match */
+ for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
+ if (vnp->value == vpd_page_num)
+ return vnp;
+ }
+ return NULL;
+ } else if (vpd_page_num < 0xc0) {
+ for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
+ if (vnp->value == vpd_page_num)
break;
}
- if (k < vpd_name_arr_sz)
- return vpd_name_arr[k].name;
- for (k = 0; k < vpd_name_arr_sz; ++k) {
- if ((vpd_name_arr[k].number == vpd_page_num) &&
- (vpd_name_arr[k].peri_type == 0))
+ if (NULL == vnp->acron)
+ return NULL;
+ if (vnp->pdt == dev_pdt) /* exact match */
+ return vnp;
+ prev_vnp = vnp;
+
+ for (++vnp; vnp->acron; ++vnp) {
+ if (vnp->value == vpd_page_num)
break;
}
- if (k < vpd_name_arr_sz)
- return vpd_name_arr[k].name;
- else
+ decay_pdt = sg_lib_pdt_decay(dev_pdt);
+ if (NULL == vnp->acron) {
+ if (decay_pdt == prev_vnp->pdt)
+ return prev_vnp;
return NULL;
- } else {
- /* rest of 0x0..0xff range doesn't depend on peripheral type */
- for (k = 0; k < vpd_name_arr_sz; ++k) {
- if (vpd_name_arr[k].number == vpd_page_num)
+ }
+ if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
+ return vnp;
+ if (decay_pdt == prev_vnp->pdt)
+ return prev_vnp;
+
+ for (++vnp; vnp->acron; ++vnp) {
+ if (vnp->value == vpd_page_num)
break;
}
- if (k < vpd_name_arr_sz)
- return vpd_name_arr[k].name;
- else
+ if (NULL == vnp->acron)
return NULL;
+ if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt))
+ return vnp;
+ return NULL; /* give up */
+ } else { /* vendor specific: vpd >= 0xc0 */
+ for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
+ if (vnp->pdt == dev_pdt)
+ return vnp;
+ }
+ return NULL;
}
}
@@ -1062,7 +1033,7 @@ svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
res = 0;
if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn))
- return vpd_decode(-1, op, jop, in_len);
+ return vpd_decode(-1, op, jop, 0);
for (k = 0, off = 0; off < in_len; ++k, off += bump) {
rp = rsp_buff + off;
@@ -1091,8 +1062,7 @@ svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
if (op->do_long)
printf("[0x%x] ", pn);
- op->inhex_off = off;
- res = vpd_decode(-1, op, jop, in_len);
+ res = vpd_decode(-1, op, jop, off);
if (SG_LIB_CAT_OTHER == res) {
; // xxxxx
}
@@ -1102,13 +1072,17 @@ svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
static void
-decode_supported_vpd(uint8_t * buff, int len, int do_hex)
+decode_supported_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
{
int vpd, k, rlen, pdt;
- const char * cp;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
+ const struct svpd_values_name_t * vnp;
+ char b[64];
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
return;
}
if (len < 4) {
@@ -1122,14 +1096,23 @@ decode_supported_vpd(uint8_t * buff, int len, int do_hex)
"%d\n", rlen, len);
else
len = rlen;
- printf(" Supported VPD pages:\n");
+ sgj_pr_hr(jsp, " Supported VPD pages:\n");
for (k = 0; k < len - 4; ++k) {
vpd = buff[4 + k];
- cp = get_vpd_page_str(vpd, pdt);
- if (cp)
- printf(" 0x%x\t%s\n", vpd, cp);
+ snprintf(b, sizeof(b), "0x%x", vpd);
+ vnp = get_vpd_page_info(vpd, pdt);
+ if (jsp->pr_as_json && jap) {
+ jo2p = sgj_new_unattached_object(jsp);
+ sgj_add_nv_i(jsp, jo2p, "i", vpd);
+ sgj_add_nv_s(jsp, jo2p, "hex", b + 2);
+ sgj_add_nv_s(jsp, jo2p, "name", vnp ? vnp->name : "unknown");
+ sgj_add_nv_s(jsp, jo2p, "acronym", vnp ? vnp->acron : "unknown");
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ if (vnp)
+ sgj_pr_hr(jsp, " %s\t%s\n", b, vnp->name);
else
- printf(" 0x%x\n", vpd);
+ sgj_pr_hr(jsp, " %s\n", b);
}
}
@@ -1212,7 +1195,7 @@ decode_id_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap)
decode_dev_ids("Device identification", buff + 4, len - 4, op, jap);
}
-/* VPD_SCSI_PORTS */
+/* VPD_SCSI_PORTS 0x88 ["sp"] */
static void
decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
@@ -1954,112 +1937,6 @@ export_dev_ids(uint8_t * buff, int len, int verbose)
"around offset=%d\n", off);
}
-/* VPD_ATA_INFO [0x89] */
-static void
-decode_ata_info_vpd(uint8_t * buff, int len, int do_hex)
-{
- char b[80];
- int is_be, num;
-
- if (len < 36) {
- pr2serr("ATA information VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex && (2 != do_hex)) {
- hex2stdout(buff, len, (3 == do_hex) ? 0 : -1);
- return;
- }
- memcpy(b, buff + 8, 8);
- b[8] = '\0';
- printf(" SAT Vendor identification: %s\n", b);
- memcpy(b, buff + 16, 16);
- b[16] = '\0';
- printf(" SAT Product identification: %s\n", b);
- memcpy(b, buff + 32, 4);
- b[4] = '\0';
- printf(" SAT Product revision level: %s\n", b);
- if (len < 56)
- return;
- printf(" Signature (Device to host FIS):\n");
- hex2stdout(buff + 36, 20, 1);
- if (len < 60)
- return;
- is_be = sg_is_big_endian();
- if ((0xec == buff[56]) || (0xa1 == buff[56])) {
- printf(" ATA command IDENTIFY %sDEVICE response summary:\n",
- ((0xa1 == buff[56]) ? "PACKET " : ""));
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20,
- is_be, b);
- b[num] = '\0';
- printf(" model: %s\n", b);
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10,
- is_be, b);
- b[num] = '\0';
- printf(" serial number: %s\n", b);
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4,
- is_be, b);
- b[num] = '\0';
- printf(" firmware revision: %s\n", b);
- printf(" response in hex:\n");
- } else
- printf(" ATA command 0x%x got following response:\n",
- (unsigned int)buff[56]);
- if (len < 572)
- return;
- if (2 == do_hex)
- hex2stdout(buff + 60, 512, 0);
- else
- dWordHex((const unsigned short *)(buff + 60), 256, 0,
- sg_is_big_endian());
-}
-
-/* VPD_SCSI_FEATURE_SETS [0x92] (sfs) */
-static void
-decode_feature_sets_vpd(uint8_t * buff, int len,
- const struct opts_t * op)
-{
- int k, bump;
- uint16_t sf_code;
- bool found;
- uint8_t * bp;
- char b[64];
-
- if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1);
- return;
- }
- if (len < 4) {
- pr2serr("SCSI Feature sets VPD page length too short=%d\n", len);
- return;
- }
- len -= 8;
- bp = buff + 8;
- for (k = 0; k < len; k += bump, bp += bump) {
- sf_code = sg_get_unaligned_be16(bp);
- bump = 2;
- if ((k + bump) > len) {
- pr2serr("SCSI Feature sets, short descriptor length=%d, "
- "left=%d\n", bump, (len - k));
- return;
- }
- if (2 == op->do_hex)
- hex2stdout(bp + 8, 2, 1);
- else if (op->do_hex > 2)
- hex2stdout(bp, 2, 1);
- else {
- printf(" %s", sg_get_sfs_str(sf_code, -2, sizeof(b), b,
- &found, op->verbose));
- if (op->verbose == 1)
- printf(" [0x%x]\n", (unsigned int)sf_code);
- else if (op->verbose > 1)
- printf(" [0x%x] found=%s\n", (unsigned int)sf_code,
- found ? "true" : "false");
- else
- printf("\n");
- }
- }
-}
-
/* VPD_BLOCK_LIMITS sbc */
/* Sequential access device characteristics, ssc+smc */
/* OSD information, osd */
@@ -2655,99 +2532,108 @@ decode_rdac_vpd_c9(uint8_t * buff, int len, int do_hex)
extern const char * sg_ansi_version_arr[];
static const char *
-get_ansi_version_str(int version, char * buff, int buff_len)
+get_ansi_version_str(int version, char * b, int blen)
{
version &= 0xf;
- buff[buff_len - 1] = '\0';
- strncpy(buff, sg_ansi_version_arr[version], buff_len - 1);
- return buff;
+ b[blen - 1] = '\0';
+ strncpy(b, sg_ansi_version_arr[version], blen - 1);
+ return b;
}
static void
-std_inq_decode(const struct opts_t * op, int act_len)
+std_inq_decode(struct opts_t * op, sgj_opaque_p jop, int off)
{
- int len, pqual, peri_type, ansi_version, k, j;
+ int len, pqual, pdt, ansi_version, k, j;
+ sgj_state * jsp = &op->json_st;
+ bool as_json = jsp->pr_as_json;
const char * cp;
- int vdesc_arr[8];
- char buff[48];
const uint8_t * rp;
+ int vdesc_arr[8];
+ char b[128];
+ static const int blen = sizeof(b);
- rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
+ rp = rsp_buff + off;
memset(vdesc_arr, 0, sizeof(vdesc_arr));
if (op->do_raw) {
- dStrRaw((const char *)rp, act_len);
+ dStrRaw((const char *)rp, op->maxlen);
return;
} else if (op->do_hex) {
/* with -H, print with address, -HH without */
- hex2stdout(rp, act_len, ((1 == op->do_hex) ? 0 : -1));
+ hex2stdout(rp, op->maxlen, ((1 == op->do_hex) ? 0 : -1));
return;
}
pqual = (rp[0] & 0xe0) >> 5;
if (! op->do_raw && ! op->do_export) {
- printf("standard INQUIRY:");
+ snprintf(b, blen, "standard INQUIRY:");
if (0 == pqual)
- printf("\n");
+ sgj_pr_hr(jsp, "%s\n", b);
else if (1 == pqual)
- printf(" [PQ indicates LU temporarily unavailable]\n");
+ sgj_pr_hr(jsp, "%s [PQ indicates LU temporarily unavailable]\n",
+ b);
else if (3 == pqual)
- printf(" [PQ indicates LU not accessible via this port]\n");
+ sgj_pr_hr(jsp, "%s [PQ indicates LU not accessible via this "
+ "port]\n", b);
else
- printf(" [reserved or vendor specific qualifier [%d]]\n", pqual);
+ sgj_pr_hr(jsp, "%s [reserved or vendor specific qualifier "
+ "[%d]]\n", b, pqual);
}
len = rp[4] + 5;
/* N.B. rp[2] full byte is 'version' in SPC-2,3,4 but in SPC
* [spc-r11a (1997)] bits 6,7: ISO/IEC version; bits 3-5: ECMA
* version; bits 0-2: SCSI version */
ansi_version = rp[2] & 0x7; /* Only take SCSI version */
- peri_type = rp[0] & PDT_MASK;
+ pdt = rp[0] & PDT_MASK;
if (op->do_export) {
printf("SCSI_TPGS=%d\n", (rp[5] & 0x30) >> 4);
- cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
+ cp = sg_get_pdt_str(pdt, blen, b);
if (strlen(cp) > 0)
printf("SCSI_TYPE=%s\n", cp);
} else {
- printf(" PQual=%d PDT=%d RMB=%d LU_CONG=%d hot_pluggable=%d "
- "version=0x%02x ", pqual, peri_type, !!(rp[1] & 0x80),
- !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3, (unsigned int)rp[2]);
- printf(" [%s]\n", get_ansi_version_str(ansi_version, buff,
- sizeof(buff)));
- printf(" [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d "
- " Resp_data_format=%d\n SCCS=%d ", !!(rp[3] & 0x80),
- !!(rp[3] & 0x40), !!(rp[3] & 0x20), !!(rp[3] & 0x10),
- rp[3] & 0x0f, !!(rp[5] & 0x80));
- printf("ACC=%d TPGS=%d 3PC=%d Protect=%d ", !!(rp[5] & 0x40),
- ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08), !!(rp[5] & 0x01));
- printf(" [BQue=%d]\n EncServ=%d ", !!(rp[6] & 0x80),
- !!(rp[6] & 0x40));
+ sgj_pr_hr(jsp, " PQual=%d PDT=%d RMB=%d LU_CONG=%d "
+ "hot_pluggable=%d version=0x%02x ", pqual, pdt,
+ !!(rp[1] & 0x80), !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3,
+ (unsigned int)rp[2]);
+ sgj_pr_hr(jsp, " [%s]\n", get_ansi_version_str(ansi_version, b,
+ blen));
+ sgj_pr_hr(jsp, " [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d "
+ " Resp_data_format=%d\n SCCS=%d ", !!(rp[3] & 0x80),
+ !!(rp[3] & 0x40), !!(rp[3] & 0x20), !!(rp[3] & 0x10),
+ rp[3] & 0x0f, !!(rp[5] & 0x80));
+ sgj_pr_hr(jsp, "ACC=%d TPGS=%d 3PC=%d Protect=%d ",
+ !!(rp[5] & 0x40), ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08),
+ !!(rp[5] & 0x01));
+ sgj_pr_hr(jsp, " [BQue=%d]\n EncServ=%d ", !!(rp[6] & 0x80),
+ !!(rp[6] & 0x40));
if (rp[6] & 0x10)
- printf("MultiP=1 (VS=%d) ", !!(rp[6] & 0x20));
+ sgj_pr_hr(jsp, "MultiP=1 (VS=%d) ", !!(rp[6] & 0x20));
else
- printf("MultiP=0 ");
- printf("[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n [RelAdr=%d] ",
- !!(rp[6] & 0x08), !!(rp[6] & 0x04), !!(rp[6] & 0x01),
- !!(rp[7] & 0x80));
- printf("WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ",
- !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08),
- !!(rp[7] & 0x04));
- printf("CmdQue=%d\n", !!(rp[7] & 0x02));
- if (act_len > 56)
- printf(" [SPI: Clocking=0x%x QAS=%d IUS=%d]\n",
- (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2), !!(rp[56] & 0x1));
- if (act_len >= len)
- printf(" length=%d (0x%x)", len, len);
+ sgj_pr_hr(jsp, "MultiP=0 ");
+ sgj_pr_hr(jsp, "[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n "
+ "[RelAdr=%d] ", !!(rp[6] & 0x08), !!(rp[6] & 0x04),
+ !!(rp[6] & 0x01), !!(rp[7] & 0x80));
+ sgj_pr_hr(jsp, "WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ",
+ !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08),
+ !!(rp[7] & 0x04));
+ sgj_pr_hr(jsp, "CmdQue=%d\n", !!(rp[7] & 0x02));
+ if (op->maxlen > 56)
+ sgj_pr_hr(jsp, " [SPI: Clocking=0x%x QAS=%d IUS=%d]\n",
+ (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2),
+ !!(rp[56] & 0x1));
+ if (op->maxlen >= len)
+ sgj_pr_hr(jsp, " length=%d (0x%x)", len, len);
else
- printf(" length=%d (0x%x), but only fetched %d bytes", len,
- len, act_len);
+ sgj_pr_hr(jsp, " length=%d (0x%x), but only fetched %d bytes",
+ len, len, op->maxlen);
if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN))
- printf("\n [for SCSI>=2, len>=36 is expected]");
- cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
+ sgj_pr_hr(jsp, "\n [for SCSI>=2, len>=36 is expected]");
+ cp = sg_get_pdt_str(pdt, blen, b);
if (strlen(cp) > 0)
- printf(" Peripheral device type: %s\n", cp);
+ sgj_pr_hr(jsp, " Peripheral device type: %s\n", cp);
}
- if (act_len <= 8) {
+ if (op->maxlen <= 8) {
if (! op->do_export)
- printf(" Inquiry response length=%d, no vendor, product or "
- "revision data\n", act_len);
+ sgj_pr_hr(jsp, " Inquiry response length=%d, no vendor, product "
+ "or revision data\n", op->maxlen);
} else {
int i;
@@ -2765,10 +2651,10 @@ std_inq_decode(const struct opts_t * op, int act_len)
printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
}
} else
- printf(" Vendor identification: %s\n", xtra_buff);
- if (act_len <= 16) {
+ sgj_pr_hr(jsp, " Vendor identification: %s\n", xtra_buff);
+ if (op->maxlen <= 16) {
if (! op->do_export)
- printf(" Product identification: <none>\n");
+ sgj_pr_hr(jsp, " Product identification: <none>\n");
} else {
memcpy(xtra_buff, &rp[16], 16);
xtra_buff[16] = '\0';
@@ -2780,11 +2666,11 @@ std_inq_decode(const struct opts_t * op, int act_len)
printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
}
} else
- printf(" Product identification: %s\n", xtra_buff);
+ sgj_pr_hr(jsp, " Product identification: %s\n", xtra_buff);
}
- if (act_len <= 32) {
+ if (op->maxlen <= 32) {
if (! op->do_export)
- printf(" Product revision level: <none>\n");
+ sgj_pr_hr(jsp, " Product revision level: <none>\n");
} else {
memcpy(xtra_buff, &rp[32], 4);
xtra_buff[4] = '\0';
@@ -2793,35 +2679,35 @@ std_inq_decode(const struct opts_t * op, int act_len)
if (len > 0)
printf("SCSI_REVISION=%s\n", xtra_buff);
} else
- printf(" Product revision level: %s\n", xtra_buff);
+ sgj_pr_hr(jsp, " Product revision level: %s\n", xtra_buff);
}
- if (op->do_vendor && (act_len > 36) && ('\0' != rp[36]) &&
+ if (op->do_vendor && (op->maxlen > 36) && ('\0' != rp[36]) &&
(' ' != rp[36])) {
- memcpy(xtra_buff, &rp[36], act_len < 56 ? act_len - 36 :
+ memcpy(xtra_buff, &rp[36], op->maxlen < 56 ? op->maxlen - 36 :
20);
if (op->do_export) {
len = encode_whitespaces((uint8_t *)xtra_buff, 20);
if (len > 0)
printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
} else
- printf(" Vendor specific: %s\n", xtra_buff);
+ sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
}
if (op->do_descriptors) {
- for (j = 0, k = 58; ((j < 8) && ((k + 1) < act_len));
+ for (j = 0, k = 58; ((j < 8) && ((k + 1) < op->maxlen));
k +=2, ++j)
vdesc_arr[j] = sg_get_unaligned_be16(rp + k);
}
- if ((op->do_vendor > 1) && (act_len > 96)) {
- memcpy(xtra_buff, &rp[96], act_len - 96);
+ if ((op->do_vendor > 1) && (op->maxlen > 96)) {
+ memcpy(xtra_buff, &rp[96], op->maxlen - 96);
if (op->do_export) {
len = encode_whitespaces((uint8_t *)xtra_buff,
- act_len - 96);
+ op->maxlen - 96);
if (len > 0)
printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
} else
- printf(" Vendor specific: %s\n", xtra_buff);
+ sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff);
}
- if (op->do_vendor && (act_len > 243) &&
+ if (op->do_vendor && (op->maxlen > 243) &&
(0 == strncmp("OPEN-V", (const char *)&rp[16], 6))) {
memcpy(xtra_buff, &rp[212], 32);
if (op->do_export) {
@@ -2829,26 +2715,41 @@ std_inq_decode(const struct opts_t * op, int act_len)
if (len > 0)
printf("VENDOR_SPECIFIC_OPEN-V_LDEV_NAME=%s\n", xtra_buff);
} else
- printf(" Vendor specific OPEN-V LDEV Name: %s\n", xtra_buff);
+ sgj_pr_hr(jsp, " Vendor specific OPEN-V LDEV Name: %s\n",
+ xtra_buff);
}
}
if (! op->do_export) {
+ sgj_opaque_p jo2p = NULL;
+
+ if (as_json)
+ jo2p = std_inq_decode_js(rp, op->maxlen, op, jop);
if ((0 == op->maxlen) && usn_buff[0])
- printf(" Unit serial number: %s\n", usn_buff);
+ sgj_pr_hr(jsp, " Unit serial number: %s\n", usn_buff);
if (op->do_descriptors) {
- if (0 == vdesc_arr[0])
- printf("\n No version descriptors available\n");
- else {
- printf("\n Version descriptors:\n");
+ sgj_opaque_p jap = sgj_new_named_array(jsp, jo2p,
+ "version_descriptor_list");
+ if (0 == vdesc_arr[0]) {
+ sgj_pr_hr(jsp, "\n");
+ sgj_pr_hr(jsp, " No version descriptors available\n");
+ } else {
+ sgj_pr_hr(jsp, "\n");
+ sgj_pr_hr(jsp, " Version descriptors:\n");
for (k = 0; k < 8; ++k) {
- if (0 == vdesc_arr[k])
+ sgj_opaque_p jo3p = sgj_new_unattached_object(jsp);
+ int vdv = vdesc_arr[k];
+
+ if (0 == vdv)
break;
- cp = find_version_descriptor_str(vdesc_arr[k]);
+ cp = find_version_descriptor_str(vdv);
if (cp)
- printf(" %s\n", cp);
+ sgj_pr_hr(jsp, " %s\n", cp);
else
- printf(" [unrecognised version descriptor "
- "code: 0x%x]\n", vdesc_arr[k]);
+ sgj_pr_hr(jsp, " [unrecognised version descriptor "
+ "code: 0x%x]\n", vdv);
+ sgj_add_nv_ihexstr(jsp, jo3p, "version_descriptor", vdv,
+ NULL, cp ? cp : "unknown");
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo3p);
}
}
}
@@ -2993,16 +2894,17 @@ fini:
}
-/* Process a standard INQUIRY response. Returns 0 if successful */
+/* Process a standard INQUIRY data format (response).
+ * Returns 0 if successful */
static int
-std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
+std_inq_process(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
{
int res, len, rlen, act_len;
- char buff[48];
int vb, resid;
+ char buff[48];
if (sg_fd < 0) { /* assume --inhex=FD usage */
- std_inq_decode(op, inhex_len);
+ std_inq_decode(op, jop, off);
return 0;
}
rlen = (op->maxlen > 0) ? op->maxlen : SAFE_STD_INQ_RESP_LEN;
@@ -3043,7 +2945,8 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
if (fetch_unit_serial_num(sg_fd, usn_buff, sizeof(usn_buff), vb))
usn_buff[0] = '\0';
}
- std_inq_decode(op, act_len);
+ op->maxlen = act_len;
+ std_inq_decode(op, jop, 0);
return 0;
} else if (res < 0) { /* could be an ATA device */
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
@@ -3082,7 +2985,7 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
static int
cmddt_process(int sg_fd, const struct opts_t * op)
{
- int k, j, num, len, peri_type, reserved_cmddt, support_num, res;
+ int k, j, num, len, pdt, reserved_cmddt, support_num, res;
char op_name[128];
memset(rsp_buff, 0, rsp_buff_sz);
@@ -3092,7 +2995,7 @@ cmddt_process(int sg_fd, const struct opts_t * op)
res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, k, rsp_buff,
DEF_ALLOC_LEN, true, op->verbose);
if (0 == res) {
- peri_type = rsp_buff[0] & PDT_MASK;
+ pdt = rsp_buff[0] & PDT_MASK;
support_num = rsp_buff[1] & 7;
reserved_cmddt = rsp_buff[4];
if ((3 == support_num) || (5 == support_num)) {
@@ -3101,7 +3004,7 @@ cmddt_process(int sg_fd, const struct opts_t * op)
printf(" %.2x", (int)rsp_buff[6 + j]);
if (5 == support_num)
printf(" [vendor specific manner (5)]");
- sg_get_opcode_name((uint8_t)k, peri_type,
+ sg_get_opcode_name((uint8_t)k, pdt,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf(" %s\n", op_name);
@@ -3125,10 +3028,10 @@ cmddt_process(int sg_fd, const struct opts_t * op)
res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, op->vpd_pn,
rsp_buff, DEF_ALLOC_LEN, true, op->verbose);
if (0 == res) {
- peri_type = rsp_buff[0] & PDT_MASK;
+ pdt = rsp_buff[0] & PDT_MASK;
if (! op->do_raw) {
printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn);
- sg_get_opcode_name((uint8_t)op->vpd_pn, peri_type,
+ sg_get_opcode_name((uint8_t)op->vpd_pn, pdt,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf("%s]\n", op_name);
@@ -3204,21 +3107,18 @@ cmddt_process(int sg_fd, const struct opts_t * op)
/* Returns 0 if successful */
static int
-vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
+vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off)
{
int res, len;
char b[128];
const char * cp;
uint8_t * rp;
- rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
+ rp = rsp_buff + off;
if ((! op->do_raw) && (op->do_hex < 2))
printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
if (sg_fd < 0) {
len = sg_get_unaligned_be16(rp + 2) + 4;
- if (op->verbose && (len > inhex_len))
- pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN "
- "file (%d)\n", len , inhex_len);
res = 0;
} else {
memset(rp, 0, DEF_ALLOC_LEN);
@@ -3230,7 +3130,7 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
dStrRaw((const char *)rp, len);
else {
if (0 == op->vpd_pn)
- decode_supported_vpd(rp, len, op->do_hex);
+ decode_supported_vpd(rp, len, op, jap);
else {
if (op->verbose) {
cp = sg_get_pdt_str(rp[0] & PDT_MASK, sizeof(b), b);
@@ -3252,12 +3152,18 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
return res;
}
+static int
+recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
+{
+ return vpd_decode(-1, op, jop, off);
+}
+
/* Returns 0 if successful */
static int
-vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
+vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
{
bool bad = false;
- int len, pdt, pn, vb, mxlen /*, pqual */;
+ int len, pdt, pn, vb /*, pqual */;
int res = 0;
sgj_state * jsp = &op->json_st;
bool as_json = jsp->pr_as_json;
@@ -3268,16 +3174,15 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
uint8_t * rp;
// char d[80];
- pn = op->vpd_pn;
- rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
+ rp = rsp_buff + off;
vb = op->verbose;
- if (sg_fd >= 0)
- mxlen = op->maxlen;
+ if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
+ pn = rp[1];
else
- mxlen = inhex_len;
+ pn = op->vpd_pn;
if (sg_fd != -1 && !op->do_force && pn != VPD_SUPPORTED_VPDS) {
- res = vpd_fetch_page_from_dev(sg_fd, rp, VPD_SUPPORTED_VPDS, mxlen,
- vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, VPD_SUPPORTED_VPDS,
+ op->maxlen, vb, &len);
if (res)
goto out;
if (vpd_page_not_supported(rp, len, pn, vb)) {
@@ -3289,23 +3194,31 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
}
}
switch (pn) {
- case VPD_SUPPORTED_VPDS:
+ case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */
+ np = "Supported VPD pages VPD page";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Supported VPD pages page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
dStrRaw((const char *)rp, len);
else if (op->do_hex)
hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
- else
- decode_supported_vpd(rp, len, op->do_hex);
+ else {
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "supported_vpd_page_list");
+ }
+ decode_supported_vpd(rp, len, op, jap);
+ }
break;
- case VPD_UNIT_SERIAL_NUM:
+ case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */
+ np = "Unit serial number VPD page";
if (! op->do_raw && ! op->do_export && (op->do_hex < 2))
- printf("VPD INQUIRY: Unit serial number page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3338,17 +3251,21 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
printf("\n");
}
} else {
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
k = encode_unicode((uint8_t *)obuff, len);
- if (k > 0)
- printf(" Unit serial number: %s\n", obuff);
+ if (k > 0) {
+ sgj_pr_hr(jsp, " Unit serial number: %s\n", obuff);
+ sgj_add_nv_s(jsp, jo2p, "unit_serial_number", obuff);
+ }
}
}
break;
- case VPD_DEVICE_ID:
+ case VPD_DEVICE_ID: /* 0x83 ["di"] */
np = "Device Identification VPD page";
if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3369,8 +3286,8 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
np = "Software interface identification VPD page";
if (! op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3384,11 +3301,11 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
decode_softw_inf_id(rp, len, op, jap);
}
break;
- case VPD_MAN_NET_ADDR: /* 0x86 ["mna"] */
+ case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */
np = "Management network addresses page";
if (!op->do_raw && (op->do_hex < 2))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3405,11 +3322,26 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
decode_net_man_vpd(rp, len, op, jap);
}
break;
- case VPD_MODE_PG_POLICY:
+ case VPD_EXT_INQ: /* 0x86 ["ei"] */
+ np = "Extended INQUIRY data";
+ if (!op->do_raw && (op->do_hex < 2))
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (res)
+ break;
+ if (op->do_raw)
+ dStrRaw((const char *)rp, len);
+ else {
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ decode_x_inq_vpd(rp, len, false /* protect */, op, jo2p);
+ }
+ break;
+ case VPD_MODE_PG_POLICY: /* 0x87 ["mpp"] */
np = "Mode page policy";
if (!op->do_raw && (op->do_hex < 2))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3423,25 +3355,29 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
decode_mode_policy_vpd(rp, len, op, jap);
}
break;
- case VPD_EXT_INQ:
- np = "Extended INQUIRY data";
+ case VPD_SCSI_PORTS: /* 0x88 ["sp"] */
+ np = "SCSI Ports VPD page";
if (!op->do_raw && (op->do_hex < 2))
- sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
dStrRaw((const char *)rp, len);
else {
- if (as_json)
+ if (as_json) {
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- decode_x_inq_vpd(rp, len, false /* protect */, op, jo2p);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "scsi_ports_descriptor_list");
+ }
+ decode_scsi_ports_vpd(rp, len, op, jap);
}
break;
- case VPD_ATA_INFO:
+ case VPD_ATA_INFO: /* 0x89 ["ai"] */
+ np = "ATA information VPD page";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: ATA information page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
/* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
@@ -3450,14 +3386,19 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
sg_is_big_endian());
else if (op->do_raw)
dStrRaw((const char *)rp, len);
- else
- decode_ata_info_vpd(rp, len, op->do_hex);
+ else {
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ else
+ op->do_long = true;
+ decode_ata_info_vpd(rp, len, op, jo2p);
+ }
break;
case VPD_POWER_CONDITION: /* 0x8a ["pc"] */
np = "Power condition page VPD page";
if (!op->do_raw && (op->do_hex < 2))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3468,19 +3409,44 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
decode_power_condition(rp, len, op, jo2p);
}
break;
- case VPD_SCSI_FEATURE_SETS: /* 0x92 */
+ case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */
+ np = "Device constituents page VPD page";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: SCSI Feature sets\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (res)
break;
if (op->do_raw)
dStrRaw((const char *)rp, len);
- else
- decode_feature_sets_vpd(rp, len, op);
+ else {
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "constituent_descriptor_list");
+ }
+ decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
+ }
+ break;
+ case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */
+ np = "SCSI Feature sets VPD page";
+ if (!op->do_raw && (op->do_hex < 2))
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (res)
+ break;
+ if (op->do_raw)
+ dStrRaw((const char *)rp, len);
+ else {
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "feature_set_code_list");
+ }
+ decode_feature_sets_vpd(rp, len, op, jap);
+ }
break;
case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3508,7 +3474,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
pr2serr("VPD INQUIRY: page=0xb0\n");
break;
case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3544,9 +3510,9 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
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, inhex_len);
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3609,24 +3575,6 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
else
decode_rdac_vpd_c9(rp, len, op->do_hex);
break;
- case VPD_SCSI_PORTS:
- np = "SCSI Ports VPD page";
- if (!op->do_raw && (op->do_hex < 2))
- sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
- if (res)
- break;
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else {
- if (as_json) {
- jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- jap = sgj_new_named_array(jsp, jo2p,
- "scsi_ports_descriptor_list");
- }
- decode_scsi_ports_vpd(rp, len, op, jap);
- }
- break;
default:
bad = true;
break;
@@ -3636,7 +3584,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
pn);
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
if (op->do_raw)
dStrRaw((const char *)rp, len);
@@ -3647,7 +3595,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
if (op->do_hex < 2)
pr2serr(" Only hex output supported. The sg_vpd and sdparm "
"utilities decode more VPD pages.\n");
- return vpd_mainly_hex(sg_fd, op, inhex_len);
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
}
}
out:
@@ -4188,7 +4136,6 @@ main(int argc, char * argv[])
goto err_out;
}
op->do_raw = 0; /* don't want raw on output with --inhex= */
- op->inhex_off = 0;
if (-1 == op->vpd_pn) { /* may be able to deduce VPD page */
if (op->page_pdt < 0)
op->page_pdt = PDT_MASK & rsp_buff[0];
@@ -4316,9 +4263,9 @@ main(int argc, char * argv[])
if (op->inhex_fn) {
if (op->do_vpd) {
if (op->do_decode)
- ret = vpd_decode(-1, op, jop, inhex_len);
+ ret = vpd_decode(-1, op, jop, 0);
else
- ret = vpd_mainly_hex(-1, op, inhex_len);
+ ret = vpd_mainly_hex(-1, op, NULL, 0);
goto err_out;
}
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
@@ -4330,7 +4277,8 @@ main(int argc, char * argv[])
}
#endif
else {
- ret = std_inq_process(-1, op, inhex_len);
+ op->maxlen = inhex_len;
+ ret = std_inq_process(-1, op, jop, 0);
goto err_out;
}
}
@@ -4403,7 +4351,7 @@ main(int argc, char * argv[])
if ((! op->do_cmddt) && (! op->do_vpd)) {
/* So it's a standard INQUIRY, try ATA IDENTIFY if that fails */
- ret = std_inq_process(sg_fd, op, -1);
+ ret = std_inq_process(sg_fd, op, jop, 0);
if (ret)
goto err_out;
} else if (op->do_cmddt) {
@@ -4414,11 +4362,11 @@ main(int argc, char * argv[])
goto err_out;
} else if (op->do_vpd) {
if (op->do_decode) {
- ret = vpd_decode(sg_fd, op, jop, -1);
+ ret = vpd_decode(sg_fd, op, jop, 0);
if (ret)
goto err_out;
} else {
- ret = vpd_mainly_hex(sg_fd, op, -1);
+ ret = vpd_mainly_hex(sg_fd, op, NULL, 0);
if (ret)
goto err_out;
}
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 122111d2..206fe91d 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -31,7 +31,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-#include "sg_vpd_common.h" /* shared with sg_inq */
+#include "sg_vpd_common.h" /* shared with sg_inq */
/* This utility program was originally written for the Linux OS SCSI subsystem.
@@ -42,7 +42,7 @@
*/
-static const char * version_str = "1.74 20220711"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.75 20220714"; /* spc6r06 + sbc5r01 */
#define MY_NAME "sg_vpd"
@@ -409,46 +409,12 @@ static const char * sg_ansi_version_arr[16] =
"reserved [Fh]",
};
-static const char * vpd_p_s = "VPD page";
-
-static const char *
-hot_pluggable_str(int hp)
-{
- switch (hp) {
- case 0:
- return "No information";
- case 1:
- return "target device designed to be removed from SCSI domain";
- case 2:
- return "target device not designed to be removed from SCSI domain";
- default:
- return "value reserved by T10";
- }
-}
-
-static const char *
-tpgs_str(int tpgs)
-{
- switch (tpgs) {
- case 1:
- return "only implicit asymmetric logical unit access";
- case 2:
- return "only explicit asymmetric logical unit access";
- case 3:
- return "both explicit and implicit asymmetric logical unit access";
- case 0:
- default:
- return "not supported";
- }
-}
-
static void
std_inq_decode(uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop)
{
uint8_t ver;
- int pqual, pdt, hp, tpgs, j, n;
+ int pqual, pdt, hp, j, n;
sgj_state * jsp = &op->json_st;
- sgj_opaque_p jo2p;
const char * cp;
char c[256];
static const int clen = sizeof(c);
@@ -504,73 +470,13 @@ std_inq_decode(uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop)
!!(b[7] & 0x02));
if (len < 36)
goto skip1;
- sgj_pr_hr(jsp, " Vendor_identification: %.8s\n", b + 8);
- sgj_pr_hr(jsp, " Product_identification: %.16s\n", b + 16);
- sgj_pr_hr(jsp, " Product_revision_level: %.4s\n", b + 32);
+ sgj_pr_hr(jsp, " %s: %.8s\n", t10_vendor_id_hr, b + 8);
+ sgj_pr_hr(jsp, " %s: %.16s\n", product_id_hr, b + 16);
+ sgj_pr_hr(jsp, " %s: %.4s\n", product_rev_lev_hr, b + 32);
skip1:
if (! jsp->pr_as_json || (len < 8))
return;
- jo2p = sgj_new_snake_named_object(jsp, jop, np);
- sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_qualifier", pqual, NULL,
- pqual_str(pqual));
- sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_device_type", pdt, NULL,
- sg_get_pdt_str(pdt, clen, c));
- sgj_add_nv_ihex_nex(jsp, jo2p, "rmb", !!(b[1] & 0x80), false,
- "Removable Medium Bit");
- sgj_add_nv_ihex_nex(jsp, jo2p, "lu_cong", !!(b[1] & 0x40), false,
- "Logical Unit Conglomerate");
- sgj_add_nv_ihexstr(jsp, jo2p, "hot_pluggable", hp, NULL,
- hot_pluggable_str(hp));
- snprintf(c, clen, "%s", (ver > 0xf) ? "old or reserved version code" :
- sg_ansi_version_arr[ver]);
- sgj_add_nv_ihexstr(jsp, jo2p, "version", ver, NULL, c);
- sgj_add_nv_ihex_nex(jsp, jo2p, "aerc", !!(b[3] & 0x80), false,
- "Asynchronous Event Reporting Capability (obsolete "
- "SPC-3)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "trmtsk", !!(b[3] & 0x40), false,
- "Terminate Task (obsolete SPC-2)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "normaca", !!(b[3] & 0x20), false,
- "Normal ACA (Auto Contingent Allegiance)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "hisup", !!(b[3] & 0x10), false,
- "Hierarchial Support");
- sgj_add_nv_ihex(jsp, jo2p, "response_data_format", b[3] & 0xf);
- sgj_add_nv_ihex_nex(jsp, jo2p, "sccs", !!(b[5] & 0x80), false,
- "SCC (SCSI Storage Commands) Supported");
- sgj_add_nv_ihex_nex(jsp, jo2p, "acc", !!(b[5] & 0x40), false,
- "Access Commands Coordinator (obsolete SPC-5)");
- tpgs = (b[5] >> 4) & 0x3;
- sgj_add_nv_ihexstr_nex(jsp, jo2p, "tpgs", tpgs, false, NULL,
- tpgs_str(tpgs), "Target Port Group Support");
- sgj_add_nv_ihex_nex(jsp, jo2p, "3pc", !!(b[5] & 0x8), false,
- "Third Party Copy");
- sgj_add_nv_ihex(jsp, jo2p, "protect", !!(b[5] & 0x1));
- /* Skip SPI specific flags which have been obsolete for a while) */
- sgj_add_nv_ihex_nex(jsp, jo2p, "bque", !!(b[6] & 0x80), false,
- "Basic task management model (obsolete SPC-4)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "encserv", !!(b[6] & 0x40), false,
- "Enclousure Services supported");
- sgj_add_nv_ihex_nex(jsp, jo2p, "multip", !!(b[6] & 0x10), false,
- "Multiple SCSI port");
- sgj_add_nv_ihex_nex(jsp, jo2p, "mchngr", !!(b[6] & 0x8), false,
- "Medium changer (obsolete SPC-4)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "reladr", !!(b[7] & 0x80), false,
- "Relative Addressing (obsolete in SPC-4)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "linked", !!(b[7] & 0x8), false,
- "Linked Commands (obsolete in SPC-4)");
- sgj_add_nv_ihex_nex(jsp, jo2p, "cmdque", !!(b[7] & 0x2), false,
- "Command Management Model (command queuing)");
- if (len < 16)
- return;
- snprintf(c, clen, "%.8s", b + 8);
- sgj_add_nv_s(jsp, jo2p, "t10_vendor_identification", c);
- if (len < 32)
- return;
- snprintf(c, clen, "%.16s", b + 16);
- sgj_add_nv_s(jsp, jo2p, "product_identification", c);
- if (len < 36)
- return;
- snprintf(c, clen, "%.4s", b + 32);
- sgj_add_nv_s(jsp, jo2p, "product_revision_level", c);
+ std_inq_decode_js(b, len, op, jop);
}
/* VPD_DEVICE_ID 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
@@ -650,10 +556,10 @@ decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
} else {
char b[1024];
- sg_decode_transportid_str(" ", bp + 8, ip_tid_len,
- true, sizeof(b), b);
- if (jsp->pr_as_json)
- sgj_add_nv_s(jsp, jo2p, "initiator_port_transport_id", b);
+ sg_decode_transportid_str(" ", bp + 8, ip_tid_len,
+ true, sizeof(b), b);
+ if (jsp->pr_as_json)
+ sgj_add_nv_s(jsp, jo2p, "initiator_port_transport_id", b);
sgj_pr_hr(jsp, "%s",
sg_decode_transportid_str(" ", bp + 8,
ip_tid_len, true, sizeof(b), b));
@@ -963,202 +869,6 @@ filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
return 0;
}
-/* VPD_ATA_INFO 0x89 ['ai"] */
-static void
-decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jop)
-{
- bool do_long_nq = op->do_long && (! op->do_quiet);
- int num, is_be, cc, n;
- sgj_state * jsp = &op->json_st;
- const char * cp;
- const char * ata_transp;
- char b[144];
- char d[80];
- static const int blen = sizeof(b);
- static const int dlen = sizeof(d);
- static const char * sat_vip = "SAT Vendor identification";
- static const char * sat_pip = "SAT Product identification";
- static const char * sat_prlp = "SAT Product revision level";
-
- if (len < 36) {
- pr2serr("ATA information VPD page length too short=%d\n", len);
- return;
- }
- if (op->do_hex && (2 != op->do_hex)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
- return;
- }
- memcpy(b, buff + 8, 8);
- b[8] = '\0';
- sgj_pr_hr(jsp, " %s: %s\n", sat_vip, b);
- memcpy(b, buff + 16, 16);
- b[16] = '\0';
- sgj_pr_hr(jsp, " %s: %s\n", sat_pip, b);
- memcpy(b, buff + 32, 4);
- b[4] = '\0';
- sgj_pr_hr(jsp, " %s: %s\n", sat_prlp, b);
- if (len < 56)
- return;
- ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA";
- if (do_long_nq) {
- sgj_pr_hr(jsp, " Device signature [%s] (in hex):\n", ata_transp);
- hex2stdout(buff + 36, 20, 0);
- } else
- sgj_pr_hr(jsp, " Device signature indicates %s transport\n",
- ata_transp);
- cc = buff[56]; /* 0xec for IDENTIFY DEVICE and 0xa1 for IDENTIFY
- * PACKET DEVICE (obsolete) */
- n = snprintf(b, blen, " Command code: 0x%x\n", cc);
- if (len < 60)
- return;
- if (0xec == cc)
- cp = "";
- else if (0xa1 == cc)
- cp = "PACKET ";
- else
- cp = NULL;
- is_be = sg_is_big_endian();
- if (cp) {
- n += sg_scnpr(b + n, blen - n, " ATA command IDENTIFY %sDEVICE "
- "response summary:\n", cp);
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20,
- is_be, d);
- d[num] = '\0';
- n += sg_scnpr(b + n, blen - n, " model: %s\n", d);
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10,
- is_be, d);
- d[num] = '\0';
- n += sg_scnpr(b + n, blen - n, " serial number: %s\n", d);
- num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4,
- is_be, d);
- d[num] = '\0';
- n += sg_scnpr(b + n, blen - n, " firmware revision: %s\n", d);
- sgj_pr_hr(jsp, "%s", b);
- if (do_long_nq)
- sgj_pr_hr(jsp, " ATA command IDENTIFY %sDEVICE response in "
- "hex:\n", cp);
- } else if (do_long_nq)
- sgj_pr_hr(jsp, " ATA command 0x%x got following response:\n",
- (unsigned int)cc);
- if (jsp->pr_as_json) {
- sgj_convert_to_snake_name(sat_vip, d, dlen);
- sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 8), 8);
- sgj_convert_to_snake_name(sat_pip, d, dlen);
- sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 16), 16);
- sgj_convert_to_snake_name(sat_prlp, d, dlen);
- sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 32), 4);
- sgj_add_nv_hex_bytes(jsp, jop, "ata_device_signature", buff + 36, 20);
- sgj_add_nv_ihex(jsp, jop, "command_code", buff[56]);
- sgj_add_nv_s(jsp, jop, "ata_identify_device_data_example",
- "sg_vpd -p ai -HHH /dev/sdc | hdparm --Istdin");
- }
- if (len < 572)
- return;
- if (2 == op->do_hex)
- hex2stdout((buff + 60), 512, 0);
- else if (do_long_nq)
- dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be);
-}
-
-static const char * constituent_type_arr[] = {
- "Reserved",
- "Virtual tape library",
- "Virtual tape drive",
- "Direct access block device",
-};
-
-/* VPD_DEVICE_CONSTITUENTS 0x8b */
-static void
-decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jop)
-{
- int k, j, res, bump, csd_len;
- uint16_t constit_type;
- const uint8_t * bp;
- char b[64];
- static const char * dcp = "Device constituents VPD page";
-
- if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
- return;
- }
- if (len < 4) {
- pr2serr("%s length too short=%d\n", dcp, len);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0, j = 0; k < len; k += bump, bp += bump, ++j) {
- if (j > 0)
- printf("\n");
- printf(" Constituent descriptor %d:\n", j + 1);
- if ((k + 36) > len) {
- pr2serr("%s, short descriptor length=36, left=%d\n", dcp,
- (len - k));
- return;
- }
- constit_type = sg_get_unaligned_be16(bp + 0);
- if (constit_type >= SG_ARRAY_SIZE(constituent_type_arr))
- printf(" Constituent type: unknown [0x%x]\n", constit_type);
- else
- printf(" Constituent type: %s [0x%x]\n",
- constituent_type_arr[constit_type], constit_type);
- printf(" Constituent device type: ");
- if (0xff == bp[2])
- printf("Unknown [0xff]\n");
- else if (bp[2] >= 0x20)
- printf("Reserved [0x%x]\n", bp[2]);
- else
- printf("%s [0x%x]\n",
- sg_get_pdt_str(PDT_MASK & bp[2], sizeof(b), b), bp[2]);
- printf(" Vendor_identification: %.8s\n", bp + 4);
- printf(" Product_identification: %.16s\n", bp + 12);
- printf(" Product_revision_level: %.4s\n", bp + 28);
- csd_len = sg_get_unaligned_be16(bp + 34);
- bump = 36 + csd_len;
- if ((k + bump) > len) {
- pr2serr("%s, short descriptor length=%d, left=%d\n", dcp, bump,
- (len - k));
- return;
- }
- if (csd_len > 0) {
- int m, q, cs_bump;
- uint8_t cs_type;
- uint8_t cs_len;
- const uint8_t * cs_bp;
-
- printf(" Constituent specific descriptors:\n");
- for (m = 0, q = 0, cs_bp = bp + 36; m < csd_len;
- m += cs_bump, ++q, cs_bp += cs_bump) {
- cs_type = cs_bp[0];
- cs_len = sg_get_unaligned_be16(cs_bp + 2);
- cs_bump = cs_len + 4;
- if (1 == cs_type) { /* VPD page */
- int off = cs_bp + 4 - buff;
-
- printf(" Constituent VPD page %d:\n", q + 1);
- /* SPC-5 says these shall _not_ themselves be Device
- * Constituent VPD pages. So no infinite recursion. */
- res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
- if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(-1, op, off);
- if (SG_LIB_CAT_OTHER == res)
- svpd_unable_to_decode(-1, op, 0, off);
- }
- } else {
- if (0xff == cs_type)
- printf(" Vendor specific data (in hex):\n");
- else
- printf(" Reserved [0x%x] specific data (in "
- "hex):\n", cs_type);
- hex2stdout(cs_bp + 4, cs_len, 0 /* plus ASCII */);
- }
- } /* end of Constituent specific descriptor loop */
- }
- } /* end Constituent descriptor loop */
-}
-
static const char * power_unit_arr[] =
{
"Gigawatts",
@@ -1715,53 +1425,6 @@ decode_proto_port_vpd(uint8_t * buff, int len, int do_hex)
}
}
-/* VPD_SCSI_FEATURE_SETS [0x92] (sfs) */
-static void
-decode_feature_sets_vpd(uint8_t * buff, int len, const struct opts_t * op)
-{
- int k, bump;
- uint16_t sf_code;
- bool found;
- uint8_t * bp;
- char b[64];
-
- if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1);
- return;
- }
- if (len < 4) {
- pr2serr("SCSI Feature sets VPD page length too short=%d\n", len);
- return;
- }
- len -= 8;
- bp = buff + 8;
- for (k = 0; k < len; k += bump, bp += bump) {
- sf_code = sg_get_unaligned_be16(bp);
- bump = 2;
- if ((k + bump) > len) {
- pr2serr("SCSI Feature sets, short descriptor length=%d, "
- "left=%d\n", bump, (len - k));
- return;
- }
- if (2 == op->do_hex)
- hex2stdout(bp + 8, 2, 1);
- else if (op->do_hex > 2)
- hex2stdout(bp, 2, 1);
- else {
- printf(" %s", sg_get_sfs_str(sf_code, -2, sizeof(b), b,
- &found, op->verbose));
- if (op->verbose == 1)
- printf(" [0x%x]\n", (unsigned int)sf_code);
- else if (op->verbose > 1)
- printf(" [0x%x] found=%s\n", (unsigned int)sf_code,
- found ? "true" : "false");
- else
- printf("\n");
- }
- }
-}
-
-
/* VPD_BLOCK_LIMITS sbc */
/* VPD_SA_DEV_CAP ssc */
/* VPD_OSD_INFO osd */
@@ -2025,17 +1688,18 @@ static const char * prov_type_arr[8] = {
/* VPD_LB_PROVISIONING 0xb2 */
static int
-decode_block_lb_prov_vpd(uint8_t * b, int len, const struct opts_t * op)
+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;
- printf(" Unmap command supported (LBPU): %d\n", !!(0x80 & b[5]));
+ 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",
@@ -2235,7 +1899,7 @@ decode_tapealert_supported_vpd(uint8_t * b, int len)
/* VPD_LB_PROVISIONING sbc */
/* VPD_TA_SUPPORTED ssc */
static void
-decode_b2_vpd(uint8_t * buff, int len, int pdt, const struct opts_t * op)
+decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op)
{
if (op->do_hex) {
hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
@@ -2255,16 +1919,19 @@ decode_b2_vpd(uint8_t * buff, int len, int pdt, const struct opts_t * op)
}
}
-/* VPD_REFERRALS sbc */
-/* VPD_AUTOMATION_DEV_SN ssc */
+/* VPD_REFERRALS sbc 0xb3 ["ref"] */
+/* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */
static void
-decode_b3_vpd(uint8_t * b, int len, int do_hex, int pdt)
+decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op,
+ sgj_opaque_p jop)
{
char obuff[DEF_ALLOC_LEN];
+ sgj_state * jsp = &op->json_st;
unsigned int u;
+ char d[64];
- if (do_hex) {
- hex2stdout(b, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(b, len, (1 == op->do_hex) ? 0 : -1);
return;
}
switch (pdt) {
@@ -2274,13 +1941,15 @@ decode_b3_vpd(uint8_t * b, int len, int do_hex, int pdt)
break;
}
u = sg_get_unaligned_be32(b + 8);
- printf(" User data segment size: ");
+ snprintf(d, sizeof(d), " User data segment size: ");
if (0 == u)
- printf("0 [per sense descriptor]\n");
+ sgj_pr_hr(jsp, "%s0 [per sense descriptor]\n", d);
else
- printf("%u\n", u);
+ sgj_pr_hr(jsp, "%s%u\n", d, u);
+ sgj_add_nv_ihex(jsp, jop, "user_data_segment_size", u);
u = sg_get_unaligned_be32(b + 12);
- printf(" User data segment multiplier: %u\n", u);
+ sgj_pr_hr_js_vi(jsp, jop, 2, "User data segment multiplier",
+ SGJ_SEP_COLON_1_SPACE, u);
break;
case PDT_TAPE: case PDT_MCHANGER:
memset(obuff, 0, sizeof(obuff));
@@ -2621,6 +2290,19 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
return res;
}
+static int
+recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
+{
+ int res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
+
+ if (SG_LIB_CAT_OTHER == res) {
+ res = svpd_decode_vendor(-1, op, off);
+ if (SG_LIB_CAT_OTHER == res)
+ svpd_unable_to_decode(-1, op, 0, off);
+ }
+ return res;
+}
+
/* Returns 0 if successful. If don't know how to decode, returns
* SG_LIB_CAT_OTHER else see sg_ll_inquiry(). */
static int
@@ -2658,8 +2340,10 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
allow_if_found = (op->examine > 0) && (! op->do_quiet);
rp = rsp_buff + off;
pn = op->vpd_pn;
- if (inhex_active && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
+ if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
pn = rp[1];
+ else
+ pn = op->vpd_pn;
if (!inhex_active && !op->do_force && 0 == op->examine &&
pn != VPD_NOPE_WANT_STD_INQ &&
pn != VPD_SUPPORTED_VPDS) {
@@ -2722,13 +2406,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */
- np = "Supported VPD pages";
+ np = "Supported VPD pages VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -2788,13 +2472,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */
- np = "Unit serial number";
+ np = "Unit serial number VPD page";
if (allow_name && not_json)
- sgj_pr_hr(jsp, "%s%s VPD page:\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -2816,13 +2500,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_DEVICE_ID: /* 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
- np = "Device Identification";
+ np = "Device Identification VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -2842,13 +2526,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
- np = "Software interface identification";
+ np = "Software interface identification VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2866,13 +2550,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */
- np= "Management network addresses";
+ np= "Management network addresses VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2887,13 +2571,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_EXT_INQ: /* 0x86 ["ei"] */
- np = "extended INQUIRY data";
+ np = "extended INQUIRY data VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2920,14 +2604,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_MODE_PG_POLICY: /* 0x87 */
- np = "Mode page policy";
+ np = "Mode page policy VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", (prefix ? prefix : ""), np,
- vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2945,13 +2628,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_SCSI_PORTS: /* 0x88 ["sp"] */
- np = "SCSI Ports";
+ np = "SCSI Ports VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -2969,15 +2652,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
break;
case VPD_ATA_INFO: /* 0x89 ['ai"] */
- np = "ATA information";
+ np = "ATA information VPD page";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
alloc_len = op->maxlen ? op->maxlen : VPD_ATA_INFO_LEN;
res = vpd_fetch_page(sg_fd, rp, pn, alloc_len, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- sgj_pr_hr(jsp, "%s%s %s:\n", (prefix ? prefix : ""), np,
- vpd_p_s);
+ sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np);
if ((2 == op->do_raw) || (3 == op->do_hex)) { /* for hdparm */
if (len < (60 + 512))
pr2serr("ATA_INFO VPD page len (%d) less than expected "
@@ -2999,7 +2681,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_POWER_CONDITION: /* 0x8a ["pc"\ */
+ case VPD_POWER_CONDITION: /* 0x8a ["pc"] */
np = "Power condition VPD page:";
if (allow_name)
sgj_pr_hr(jsp, "%s%s\n", pre, np);
@@ -3013,23 +2695,34 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (vb || long_notquiet)
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
- decode_power_condition(rp, len, op, jop);
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ decode_power_condition(rp, len, op, jo2p);
}
return 0;
}
break;
- case VPD_DEVICE_CONSTITUENTS: /* 0x8b */
- np = "Device constituents VPD page:";
+ case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */
+ np = "Device constituents VPD page";
if (allow_name)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
- else
- decode_dev_constit_vpd(rp, len, op, jop);
+ else {
+ if (vb || long_notquiet)
+ sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
+ "%s]\n", pqual, pdt_str);
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "constituent_descriptor_list");
+ }
+ decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
+ }
return 0;
}
break;
@@ -3111,10 +2804,10 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_SCSI_FEATURE_SETS: /* 0x92 */
- np = "SCSI Feature sets:";
+ case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */
+ np = "SCSI Feature sets VPD page";
if (allow_name)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
if (! allow_name && allow_if_found)
@@ -3123,9 +2816,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_feature_sets_vpd(rp, len, op);
+ 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_new_named_array(jsp, jo2p,
+ "feature_set_code_list");
+ }
+ decode_feature_sets_vpd(rp, len, op, jap);
}
return 0;
}
@@ -3216,15 +2914,15 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
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\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
+ sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
+ "%s]\n", pqual, pdt_str);
decode_b2_vpd(rp, len, pdt, op);
}
return 0;
@@ -3248,16 +2946,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
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\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_b3_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);
+ decode_b3_vpd(rp, len, pdt, op, jo2p);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c
index 49d18670..7f168c5b 100644
--- a/src/sg_vpd_common.c
+++ b/src/sg_vpd_common.c
@@ -36,6 +36,13 @@
/* This file holds common code for sg_inq and sg_vpd as both those utilities
* decode SCSI VPD pages. */
+const char * t10_vendor_id_hr = "T10_vendor_identification";
+const char * t10_vendor_id_js = "t10_vendor_identification";
+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";
+
sgj_opaque_p
sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
const uint8_t * vpd_hdrp)
@@ -556,3 +563,410 @@ filter_json_dev_ids(uint8_t * buff, int len, int m_assoc, struct opts_t * op,
}
return 0;
}
+
+/* VPD_ATA_INFO 0x89 ['ai"] */
+void
+decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ bool do_long_nq = op->do_long && (! op->do_quiet);
+ int num, is_be, cc, n;
+ sgj_state * jsp = &op->json_st;
+ const char * cp;
+ const char * ata_transp;
+ char b[512];
+ char d[80];
+ static const int blen = sizeof(b);
+ static const int dlen = sizeof(d);
+ static const char * sat_vip = "SAT Vendor identification";
+ static const char * sat_pip = "SAT Product identification";
+ static const char * sat_prlp = "SAT Product revision level";
+
+ if (len < 36) {
+ pr2serr("ATA information VPD page length too short=%d\n", len);
+ return;
+ }
+ if (op->do_hex && (2 != op->do_hex)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ memcpy(b, buff + 8, 8);
+ b[8] = '\0';
+ sgj_pr_hr(jsp, " %s: %s\n", sat_vip, b);
+ memcpy(b, buff + 16, 16);
+ b[16] = '\0';
+ sgj_pr_hr(jsp, " %s: %s\n", sat_pip, b);
+ memcpy(b, buff + 32, 4);
+ b[4] = '\0';
+ sgj_pr_hr(jsp, " %s: %s\n", sat_prlp, b);
+ if (len < 56)
+ return;
+ ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA";
+ if (do_long_nq) {
+ sgj_pr_hr(jsp, " Device signature [%s] (in hex):\n", ata_transp);
+ hex2stdout(buff + 36, 20, 0);
+ } else
+ sgj_pr_hr(jsp, " Device signature indicates %s transport\n",
+ ata_transp);
+ cc = buff[56]; /* 0xec for IDENTIFY DEVICE and 0xa1 for IDENTIFY
+ * PACKET DEVICE (obsolete) */
+ n = snprintf(b, blen, " Command code: 0x%x\n", cc);
+ if (len < 60)
+ return;
+ if (0xec == cc)
+ cp = "";
+ else if (0xa1 == cc)
+ cp = "PACKET ";
+ else
+ cp = NULL;
+ is_be = sg_is_big_endian();
+ if (cp) {
+ n += sg_scnpr(b + n, blen - n, " ATA command IDENTIFY %sDEVICE "
+ "response summary:\n", cp);
+ num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20,
+ is_be, d);
+ d[num] = '\0';
+ n += sg_scnpr(b + n, blen - n, " model: %s\n", d);
+ num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10,
+ is_be, d);
+ d[num] = '\0';
+ n += sg_scnpr(b + n, blen - n, " serial number: %s\n", d);
+ num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4,
+ is_be, d);
+ d[num] = '\0';
+ n += sg_scnpr(b + n, blen - n, " firmware revision: %s\n", d);
+ sgj_pr_hr(jsp, "%s", b);
+ if (do_long_nq)
+ sgj_pr_hr(jsp, " ATA command IDENTIFY %sDEVICE response in "
+ "hex:\n", cp);
+ } else if (do_long_nq)
+ sgj_pr_hr(jsp, " ATA command 0x%x got following response:\n",
+ (unsigned int)cc);
+ if (jsp->pr_as_json) {
+ sgj_convert_to_snake_name(sat_vip, d, dlen);
+ sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 8), 8);
+ sgj_convert_to_snake_name(sat_pip, d, dlen);
+ sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 16), 16);
+ sgj_convert_to_snake_name(sat_prlp, d, dlen);
+ sgj_add_nv_s_len(jsp, jop, d, (const char *)(buff + 32), 4);
+ sgj_add_nv_hex_bytes(jsp, jop, "ata_device_signature", buff + 36, 20);
+ sgj_add_nv_ihex(jsp, jop, "command_code", buff[56]);
+ sgj_add_nv_s(jsp, jop, "ata_identify_device_data_example",
+ "sg_vpd -p ai -HHH /dev/sdc | hdparm --Istdin");
+ }
+ if (len < 572)
+ return;
+ if (2 == op->do_hex)
+ hex2stdout((buff + 60), 512, 0);
+ else if (do_long_nq)
+ dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be);
+}
+
+/* VPD_SCSI_FEATURE_SETS 0x92 ["sfs"] */
+void
+decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k, bump;
+ uint16_t sf_code;
+ bool found;
+ uint8_t * bp;
+ sgj_opaque_p jo2p;
+ sgj_state * jsp = &op->json_st;
+ char b[256];
+ char d[80];
+
+ if ((1 == op->do_hex) || (op->do_hex > 2)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("SCSI Feature sets VPD page length too short=%d\n", len);
+ return;
+ }
+ len -= 8;
+ bp = buff + 8;
+ for (k = 0; k < len; k += bump, bp += bump) {
+ jo2p = sgj_new_unattached_object(jsp);
+ sf_code = sg_get_unaligned_be16(bp);
+ bump = 2;
+ if ((k + bump) > len) {
+ pr2serr("SCSI Feature sets, short descriptor length=%d, "
+ "left=%d\n", bump, (len - k));
+ return;
+ }
+ if (2 == op->do_hex)
+ hex2stdout(bp + 8, 2, 1);
+ else if (op->do_hex > 2)
+ hex2stdout(bp, 2, 1);
+ else {
+ sg_scnpr(b, sizeof(b), " %s",
+ sg_get_sfs_str(sf_code, -2, sizeof(d), d, &found,
+ op->verbose));
+ if (op->verbose == 1)
+ sgj_pr_hr(jsp, "%s [0x%x]\n", b, (unsigned int)sf_code);
+ else if (op->verbose > 1)
+ sgj_pr_hr(jsp, "%s [0x%x] found=%s\n", b,
+ (unsigned int)sf_code, found ? "true" : "false");
+ else
+ sgj_pr_hr(jsp, "%s\n", b);
+ sgj_add_nv_ihexstr(jsp, jo2p, "feature_set_code", sf_code, NULL,
+ d);
+ if (jsp->verbose)
+ sgj_add_nv_b(jsp, jo2p, "meaning_is_match", found);
+ }
+ sgj_add_nv_o(jsp, jap, NULL, jo2p);
+ }
+}
+
+static const char * constituent_type_arr[] = {
+ "Reserved",
+ "Virtual tape library",
+ "Virtual tape drive",
+ "Direct access block device",
+};
+
+/* VPD_DEVICE_CONSTITUENTS 0x8b ["dc"] */
+void
+decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap, recurse_vpd_decodep fp)
+{
+ uint16_t constit_type;
+ int k, j, res, bump, csd_len;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p, jo3p, ja2p;
+ const uint8_t * bp;
+ char b[256];
+ char d[64];
+ static const int blen = sizeof(b);
+ static const int dlen = sizeof(d);
+
+ if ((1 == op->do_hex) || (op->do_hex > 2)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("page length too short=%d\n", len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0, j = 0; k < len; k += bump, bp += bump, ++j) {
+ jo2p = sgj_new_unattached_object(jsp);
+ if (j > 0)
+ sgj_pr_hr(jsp, "\n");
+ sgj_pr_hr(jsp, " Constituent descriptor %d:\n", j + 1);
+ if ((k + 36) > len) {
+ pr2serr("short descriptor length=36, left=%d\n", (len - k));
+ sgj_add_nv_o(jsp, jap, NULL, jo2p);
+ return;
+ }
+ constit_type = sg_get_unaligned_be16(bp + 0);
+ if (constit_type >= SG_ARRAY_SIZE(constituent_type_arr))
+ sgj_pr_hr(jsp," Constituent type: unknown [0x%x]\n",
+ constit_type);
+ else
+ sgj_pr_hr(jsp, " Constituent type: %s [0x%x]\n",
+ constituent_type_arr[constit_type], constit_type);
+ sg_scnpr(b, blen, " Constituent device type: ");
+ 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]);
+ else
+ sgj_pr_hr(jsp, "%s%s [0x%x]\n", b,
+ sg_get_pdt_str(PDT_MASK & bp[2], dlen, d), bp[2]);
+ snprintf(b, blen, "%.8s", bp + 4);
+ sgj_pr_hr(jsp, " %s: %s\n", t10_vendor_id_hr, b);
+ sgj_add_nv_s(jsp, jo2p, t10_vendor_id_js, b);
+ snprintf(b, blen, "%.16s", bp + 12);
+ sgj_pr_hr(jsp, " %s: %s\n", product_id_hr, b);
+ sgj_add_nv_s(jsp, jo2p, product_id_js, b);
+ snprintf(b, blen, "%.4s", bp + 28);
+ sgj_pr_hr(jsp, " %s: %s\n", product_rev_lev_hr, b);
+ sgj_add_nv_s(jsp, jo2p, product_rev_lev_js, b);
+ csd_len = sg_get_unaligned_be16(bp + 34);
+ bump = 36 + csd_len;
+ if ((k + bump) > len) {
+ pr2serr("short descriptor length=%d, left=%d\n", bump, (len - k));
+ sgj_add_nv_o(jsp, jap, NULL, jo2p);
+ return;
+ }
+ if (csd_len > 0) {
+ int m, q, cs_bump;
+ uint8_t cs_type;
+ uint8_t cs_len;
+ const uint8_t * cs_bp;
+
+ sgj_pr_hr(jsp, " Constituent specific descriptors:\n");
+ ja2p = sgj_new_named_array(jsp, jo2p,
+ "constituent_specific_descriptor_list");
+ for (m = 0, q = 0, cs_bp = bp + 36; m < csd_len;
+ m += cs_bump, ++q, cs_bp += cs_bump) {
+ jo3p = sgj_new_unattached_object(jsp);
+ cs_type = cs_bp[0];
+ cs_len = sg_get_unaligned_be16(cs_bp + 2);
+ cs_bump = cs_len + 4;
+ sgj_add_nv_ihex(jsp, jo3p, "constituent_specific_type",
+ cs_type);
+ if (1 == cs_type) { /* VPD page */
+ int off = cs_bp + 4 - buff;
+
+ sgj_pr_hr(jsp, " Constituent specific VPD page "
+ "%d:\n", q + 1);
+ /* SPC-5 says these shall _not_ themselves be Device
+ * Constituent VPD pages. So no infinite recursion. */
+ res = (*fp)(op, jo3p, off);
+ if (res)
+ pr2serr("%s: recurse_vpd_decode() failed, res=%d\n",
+ __func__, res);
+ } else {
+ if (0xff == cs_type)
+ 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);
+ if (jsp->pr_as_json)
+ sgj_add_nv_hex_bytes(jsp, jo3p,
+ "constituent_specific_data_hex",
+ cs_bp + 4, cs_len);
+ else
+ hex2stdout(cs_bp + 4, cs_len, 0 /* plus ASCII */);
+ }
+ sgj_add_nv_o(jsp, ja2p, NULL, jo3p);
+ } /* end of Constituent specific descriptor loop */
+ }
+ sgj_add_nv_o(jsp, jap, NULL, jo2p);
+ } /* end Constituent descriptor loop */
+}
+
+/* Assume index is less than 16 */
+static const char * sg_ansi_version_arr[16] =
+{
+ "no conformance claimed",
+ "SCSI-1", /* obsolete, ANSI X3.131-1986 */
+ "SCSI-2", /* obsolete, ANSI X3.131-1994 */
+ "SPC", /* withdrawn, ANSI INCITS 301-1997 */
+ "SPC-2", /* ANSI INCITS 351-2001, ISO/IEC 14776-452 */
+ "SPC-3", /* ANSI INCITS 408-2005, ISO/IEC 14776-453 */
+ "SPC-4", /* ANSI INCITS 513-2015 */
+ "SPC-5", /* ANSI INCITS 502-2020 */
+ "ecma=1, [8h]",
+ "ecma=1, [9h]",
+ "ecma=1, [Ah]",
+ "ecma=1, [Bh]",
+ "reserved [Ch]",
+ "reserved [Dh]",
+ "reserved [Eh]",
+ "reserved [Fh]",
+};
+
+static const char *
+hot_pluggable_str(int hp)
+{
+ switch (hp) {
+ case 0:
+ return "No information";
+ case 1:
+ return "target device designed to be removed from SCSI domain";
+ case 2:
+ return "target device not designed to be removed from SCSI domain";
+ default:
+ return "value reserved by T10";
+ }
+}
+
+static const char *
+tpgs_str(int tpgs)
+{
+ switch (tpgs) {
+ case 1:
+ return "only implicit asymmetric logical unit access";
+ case 2:
+ return "only explicit asymmetric logical unit access";
+ case 3:
+ return "both explicit and implicit asymmetric logical unit access";
+ case 0:
+ default:
+ return "not supported";
+ }
+}
+
+sgj_opaque_p
+std_inq_decode_js(const uint8_t * b, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ int tpgs;
+ int pqual = (b[0] & 0xe0) >> 5;
+ int pdt = b[0] & PDT_MASK;
+ int hp = (b[1] >> 4) & 0x3;
+ int ver = b[2];
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p = NULL;
+ char c[256];
+ static const int clen = sizeof(c);
+
+ jo2p = sgj_new_named_object(jsp, jop, "standard_inquiry_data_format");
+ sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_qualifier", pqual, NULL,
+ pqual_str(pqual));
+ sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_device_type", pdt, NULL,
+ sg_get_pdt_str(pdt, clen, c));
+ sgj_add_nv_ihex_nex(jsp, jo2p, "rmb", !!(b[1] & 0x80), false,
+ "Removable Medium Bit");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "lu_cong", !!(b[1] & 0x40), false,
+ "Logical Unit Conglomerate");
+ sgj_add_nv_ihexstr(jsp, jo2p, "hot_pluggable", hp, NULL,
+ hot_pluggable_str(hp));
+ snprintf(c, clen, "%s", (ver > 0xf) ? "old or reserved version code" :
+ sg_ansi_version_arr[ver]);
+ sgj_add_nv_ihexstr(jsp, jo2p, "version", ver, NULL, c);
+ sgj_add_nv_ihex_nex(jsp, jo2p, "aerc", !!(b[3] & 0x80), false,
+ "Asynchronous Event Reporting Capability (obsolete "
+ "SPC-3)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "trmtsk", !!(b[3] & 0x40), false,
+ "Terminate Task (obsolete SPC-2)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "normaca", !!(b[3] & 0x20), false,
+ "Normal ACA (Auto Contingent Allegiance)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "hisup", !!(b[3] & 0x10), false,
+ "Hierarchial Support");
+ sgj_add_nv_ihex(jsp, jo2p, "response_data_format", b[3] & 0xf);
+ sgj_add_nv_ihex_nex(jsp, jo2p, "sccs", !!(b[5] & 0x80), false,
+ "SCC (SCSI Storage Commands) Supported");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "acc", !!(b[5] & 0x40), false,
+ "Access Commands Coordinator (obsolete SPC-5)");
+ tpgs = (b[5] >> 4) & 0x3;
+ sgj_add_nv_ihexstr_nex(jsp, jo2p, "tpgs", tpgs, false, NULL,
+ tpgs_str(tpgs), "Target Port Group Support");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "3pc", !!(b[5] & 0x8), false,
+ "Third Party Copy");
+ sgj_add_nv_ihex(jsp, jo2p, "protect", !!(b[5] & 0x1));
+ /* Skip SPI specific flags which have been obsolete for a while) */
+ sgj_add_nv_ihex_nex(jsp, jo2p, "bque", !!(b[6] & 0x80), false,
+ "Basic task management model (obsolete SPC-4)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "encserv", !!(b[6] & 0x40), false,
+ "Enclousure Services supported");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "multip", !!(b[6] & 0x10), false,
+ "Multiple SCSI port");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "mchngr", !!(b[6] & 0x8), false,
+ "Medium changer (obsolete SPC-4)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "reladr", !!(b[7] & 0x80), false,
+ "Relative Addressing (obsolete in SPC-4)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "linked", !!(b[7] & 0x8), false,
+ "Linked Commands (obsolete in SPC-4)");
+ sgj_add_nv_ihex_nex(jsp, jo2p, "cmdque", !!(b[7] & 0x2), false,
+ "Command Management Model (command queuing)");
+ if (len < 16)
+ return jo2p;
+ snprintf(c, clen, "%.8s", b + 8);
+ sgj_add_nv_s(jsp, jo2p, t10_vendor_id_js, c);
+ if (len < 32)
+ return jo2p;
+ snprintf(c, clen, "%.16s", b + 16);
+ sgj_add_nv_s(jsp, jo2p, product_id_js, c);
+ if (len < 36)
+ return jo2p;
+ snprintf(c, clen, "%.4s", b + 32);
+ sgj_add_nv_s(jsp, jo2p, product_rev_lev_js, c);
+ return jo2p;
+}
diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h
index 485418f3..7cb56293 100644
--- a/src/sg_vpd_common.h
+++ b/src/sg_vpd_common.h
@@ -99,7 +99,6 @@ struct opts_t {
int do_raw; /* sg_inq + sg_vpd */
int do_vendor; /* sg_inq */
int examine; /* sg_vpd */
- int inhex_off; /* sg_inq (for decoding multiple VPD pages) */
int maxlen; /* sg_inq[was: resp_len] + sg_vpd */
int num_pages; /* sg_inq */
int page_pdt; /* sg_inq */
@@ -113,40 +112,6 @@ struct opts_t {
sgj_state json_st;
};
-#if 0
-struct opts_t {
- bool do_ata;
- bool do_decode;
- bool do_descriptors;
- bool do_export;
- bool do_force;
- bool do_only; /* --only after standard inq don't fetch VPD page 0x80 */
- bool verbose_given;
- bool version_given;
- bool do_vpd;
- bool page_given;
- bool possible_nvme;
- int do_block;
- int do_cmddt;
- int do_help;
- int do_hex;
- int do_long;
- int do_raw;
- int do_vendor;
- int verbose;
- int resp_len;
- int page_num;
- int page_pdt;
- int num_pages;
- const char * page_arg;
- const char * device_name;
- const char * inhex_fn;
-#ifdef SG_SCSI_STRINGS
- bool opt_new;
-#endif
-};
-#endif
-
struct svpd_values_name_t {
int value; /* VPD page number */
int subvalue; /* to differentiate if value+pdt are not unique */
@@ -156,17 +121,8 @@ struct svpd_values_name_t {
const char * name;
};
-#if 0
-struct svpd_values_name_t {
- int value;
- int subvalue;
- int pdt; /* peripheral device type id, -1 is the default */
- /* (all or not applicable) value */
- int vendor; /* vendor flag */
- const char * acron;
- const char * name;
-};
-#endif
+typedef int (*recurse_vpd_decodep)(struct opts_t *, sgj_opaque_p jop, int off);
+
sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop,
const char * name, const uint8_t * vpd_hdrp);
@@ -182,6 +138,15 @@ void decode_power_condition(uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop);
int filter_json_dev_ids(uint8_t * buff, int len, int m_assoc,
struct opts_t * op, sgj_opaque_p jap);
+void decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop);
+void decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+void decode_dev_constit_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap,
+ recurse_vpd_decodep fp);
+sgj_opaque_p std_inq_decode_js(const uint8_t * b, int len,
+ struct opts_t * op, sgj_opaque_p jop);
const char * pqual_str(int pqual);
void svpd_enumerate_vendor(int vend_prod_num);
@@ -196,6 +161,12 @@ int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
void dup_sanity_chk(int sz_opts_t, int sz_values_name_t);
extern uint8_t * rsp_buff;
+extern const char * t10_vendor_id_hr;
+extern const char * t10_vendor_id_js;
+extern const char * product_id_hr;
+extern const char * product_id_js;
+extern const char * product_rev_lev_hr;
+extern const char * product_rev_lev_js;
#ifdef __cplusplus