aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-07-11 18:16:30 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-07-11 18:16:30 +0000
commita51fa77e373d1e4a1be10e8e4ef9a87547d26e86 (patch)
tree88b59744783292c3f8ec8d8906cd723c5900e375 /src
parent5e6f4a6ba05f122b39407f2bdb8d8bea194b8990 (diff)
downloadsg3_utils-a51fa77e373d1e4a1be10e8e4ef9a87547d26e86.tar.gz
sg_inq+sg_vpd: merge VPD page processing
This is being done so that ongoing JSON work is not duplicated for both sg_vpd and sg_inq. This might lead to small changes in formatting of VPD (and standard INQUIRY) output. That in turn might break parsing code expecting the former output. Hopefully this will push folks who are parsing to try out JSON output. However JSON output format may not be that stable, hoping for feedback on that front. git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@959 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.in27
-rw-r--r--src/sg_decode_sense.c4
-rw-r--r--src/sg_inq.c998
-rw-r--r--src/sg_vpd.c731
-rw-r--r--src/sg_vpd.h80
-rw-r--r--src/sg_vpd_common.c558
-rw-r--r--src/sg_vpd_common.h205
-rw-r--r--src/sg_vpd_vendor.c2
9 files changed, 1446 insertions, 1163 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 034f171d..b4b6bc71 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -90,7 +90,7 @@ sg_ident_LDADD = ../lib/libsgutils2.la
sginfo_LDADD = ../lib/libsgutils2.la
-sg_inq_SOURCES = sg_inq.c sg_inq_data.c
+sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c
sg_inq_LDADD = ../lib/libsgutils2.la
sg_logs_LDADD = ../lib/libsgutils2.la
@@ -190,7 +190,7 @@ sg_unmap_LDADD = ../lib/libsgutils2.la
sg_verify_LDADD = ../lib/libsgutils2.la
-sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c
+sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_common.c
sg_vpd_LDADD = ../lib/libsgutils2.la
sg_wr_mode_LDADD = ../lib/libsgutils2.la
diff --git a/src/Makefile.in b/src/Makefile.in
index a71b2ca7..9fb93bf7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -187,7 +187,8 @@ sg_get_lba_status_DEPENDENCIES = ../lib/libsgutils2.la
sg_ident_SOURCES = sg_ident.c
sg_ident_OBJECTS = sg_ident.$(OBJEXT)
sg_ident_DEPENDENCIES = ../lib/libsgutils2.la
-am_sg_inq_OBJECTS = sg_inq.$(OBJEXT) sg_inq_data.$(OBJEXT)
+am_sg_inq_OBJECTS = sg_inq.$(OBJEXT) sg_inq_data.$(OBJEXT) \
+ sg_vpd_common.$(OBJEXT)
sg_inq_OBJECTS = $(am_sg_inq_OBJECTS)
sg_inq_DEPENDENCIES = ../lib/libsgutils2.la
sg_logs_SOURCES = sg_logs.c
@@ -340,7 +341,8 @@ sg_unmap_DEPENDENCIES = ../lib/libsgutils2.la
sg_verify_SOURCES = sg_verify.c
sg_verify_OBJECTS = sg_verify.$(OBJEXT)
sg_verify_DEPENDENCIES = ../lib/libsgutils2.la
-am_sg_vpd_OBJECTS = sg_vpd.$(OBJEXT) sg_vpd_vendor.$(OBJEXT)
+am_sg_vpd_OBJECTS = sg_vpd.$(OBJEXT) sg_vpd_vendor.$(OBJEXT) \
+ sg_vpd_common.$(OBJEXT)
sg_vpd_OBJECTS = $(am_sg_vpd_OBJECTS)
sg_vpd_DEPENDENCIES = ../lib/libsgutils2.la
sg_wr_mode_SOURCES = sg_wr_mode.c
@@ -429,13 +431,13 @@ am__depfiles_remade = ./$(DEPDIR)/sg_bg_ctl.Po \
./$(DEPDIR)/sg_test_rwbuf.Po ./$(DEPDIR)/sg_timestamp.Po \
./$(DEPDIR)/sg_turs.Po ./$(DEPDIR)/sg_unmap.Po \
./$(DEPDIR)/sg_verify.Po ./$(DEPDIR)/sg_vpd.Po \
- ./$(DEPDIR)/sg_vpd_vendor.Po ./$(DEPDIR)/sg_wr_mode.Po \
- ./$(DEPDIR)/sg_write_buffer.Po ./$(DEPDIR)/sg_write_long.Po \
- ./$(DEPDIR)/sg_write_same.Po ./$(DEPDIR)/sg_write_verify.Po \
- ./$(DEPDIR)/sg_write_x.Po ./$(DEPDIR)/sg_xcopy.Po \
- ./$(DEPDIR)/sg_z_act_query.Po ./$(DEPDIR)/sg_zone.Po \
- ./$(DEPDIR)/sginfo.Po ./$(DEPDIR)/sgm_dd.Po \
- ./$(DEPDIR)/sgp_dd.Po
+ ./$(DEPDIR)/sg_vpd_common.Po ./$(DEPDIR)/sg_vpd_vendor.Po \
+ ./$(DEPDIR)/sg_wr_mode.Po ./$(DEPDIR)/sg_write_buffer.Po \
+ ./$(DEPDIR)/sg_write_long.Po ./$(DEPDIR)/sg_write_same.Po \
+ ./$(DEPDIR)/sg_write_verify.Po ./$(DEPDIR)/sg_write_x.Po \
+ ./$(DEPDIR)/sg_xcopy.Po ./$(DEPDIR)/sg_z_act_query.Po \
+ ./$(DEPDIR)/sg_zone.Po ./$(DEPDIR)/sginfo.Po \
+ ./$(DEPDIR)/sgm_dd.Po ./$(DEPDIR)/sgp_dd.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -676,7 +678,7 @@ sg_get_elem_status_LDADD = ../lib/libsgutils2.la
sg_get_lba_status_LDADD = ../lib/libsgutils2.la
sg_ident_LDADD = ../lib/libsgutils2.la
sginfo_LDADD = ../lib/libsgutils2.la
-sg_inq_SOURCES = sg_inq.c sg_inq_data.c
+sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c
sg_inq_LDADD = ../lib/libsgutils2.la
sg_logs_LDADD = ../lib/libsgutils2.la
sg_luns_LDADD = ../lib/libsgutils2.la
@@ -728,7 +730,7 @@ sg_timestamp_LDADD = ../lib/libsgutils2.la
sg_turs_LDADD = ../lib/libsgutils2.la @RT_LIB@
sg_unmap_LDADD = ../lib/libsgutils2.la
sg_verify_LDADD = ../lib/libsgutils2.la
-sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c
+sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_common.c
sg_vpd_LDADD = ../lib/libsgutils2.la
sg_wr_mode_LDADD = ../lib/libsgutils2.la
sg_write_buffer_LDADD = ../lib/libsgutils2.la
@@ -1183,6 +1185,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_unmap.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_verify.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_common.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_vendor.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_wr_mode.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_buffer.Po@am__quote@ # am--include-marker
@@ -1419,6 +1422,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/sg_unmap.Po
-rm -f ./$(DEPDIR)/sg_verify.Po
-rm -f ./$(DEPDIR)/sg_vpd.Po
+ -rm -f ./$(DEPDIR)/sg_vpd_common.Po
-rm -f ./$(DEPDIR)/sg_vpd_vendor.Po
-rm -f ./$(DEPDIR)/sg_wr_mode.Po
-rm -f ./$(DEPDIR)/sg_write_buffer.Po
@@ -1540,6 +1544,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/sg_unmap.Po
-rm -f ./$(DEPDIR)/sg_verify.Po
-rm -f ./$(DEPDIR)/sg_vpd.Po
+ -rm -f ./$(DEPDIR)/sg_vpd_common.Po
-rm -f ./$(DEPDIR)/sg_vpd_vendor.Po
-rm -f ./$(DEPDIR)/sg_wr_mode.Po
-rm -f ./$(DEPDIR)/sg_write_buffer.Po
diff --git a/src/sg_decode_sense.c b/src/sg_decode_sense.c
index 83f1d1fa..8950cdbd 100644
--- a/src/sg_decode_sense.c
+++ b/src/sg_decode_sense.c
@@ -30,7 +30,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "1.28 20220626";
+static const char * version_str = "1.29 20220711";
#define MY_NAME "sg_decode_sense"
@@ -504,7 +504,7 @@ main(int argc, char *argv[])
printf("%s\n", b);
} else {
if (as_json) {
- sgj_get_sense(jsp, jop, op->sense, op->sense_len);
+ sgj_pr_js_sense(jsp, jop, op->sense, op->sense_len);
if (jsp->pr_out_hr) {
sg_get_sense_str(NULL, op->sense, op->sense_len,
op->verbose, blen, b);
diff --git a/src/sg_inq.c b/src/sg_inq.c
index c9022516..8e5b48d7 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -51,7 +51,11 @@
#include "sg_pt_nvme.h"
#endif
-static const char * version_str = "2.17 20220504"; /* spc6r06 */
+#include "sg_vpd_common.h" /* for shared VPD page processing with sg_vpd */
+
+static const char * version_str = "2.18 20220511"; /* spc6r06 */
+
+#define MY_NAME "sg_inq"
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -81,36 +85,6 @@ static const char * version_str = "2.17 20220504"; /* spc6r06 */
*/
-/* Following VPD pages are in ascending page number order */
-#define VPD_SUPPORTED_VPDS 0x0
-#define VPD_UNIT_SERIAL_NUM 0x80
-#define VPD_DEVICE_ID 0x83
-#define VPD_SOFTW_INF_ID 0x84
-#define VPD_MAN_NET_ADDR 0x85
-#define VPD_EXT_INQ 0x86 /* Extended Inquiry */
-#define VPD_MODE_PG_POLICY 0x87
-#define VPD_SCSI_PORTS 0x88
-#define VPD_ATA_INFO 0x89
-#define VPD_POWER_CONDITION 0x8a
-#define VPD_DEVICE_CONSTITUENTS 0x8b
-#define VPD_CFA_PROFILE_INFO 0x8c
-#define VPD_POWER_CONSUMPTION 0x8d
-#define VPD_3PARTY_COPY 0x8f
-#define VPD_PROTO_LU 0x90
-#define VPD_PROTO_PORT 0x91
-#define VPD_SCSI_FEATURE_SETS 0x92 /* spc5r11 */
-#define VPD_BLOCK_LIMITS 0xb0
-#define VPD_BLOCK_DEV_CHARS 0xb1
-#define VPD_MAN_ASS_SN 0xb1
-#define VPD_LB_PROVISIONING 0xb2
-#define VPD_REFERRALS 0xb3
-#define VPD_SUP_BLOCK_LENS 0xb4 /* sbc4r01 */
-#define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* sbc4r02 */
-#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
-#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
-#define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */
-#define VPD_CON_POS_RANGE 0xb9 /* sbc5r01 */
-
#ifndef SG_NVME_VPD_NICR
#define SG_NVME_VPD_NICR 0xde
#endif
@@ -140,7 +114,8 @@ static const char * version_str = "2.17 20220504"; /* spc6r06 */
#define DEF_PT_TIMEOUT 60 /* 60 seconds */
-static uint8_t * rsp_buff;
+uint8_t * rsp_buff;
+
static uint8_t * free_rsp_buff;
static const int rsp_buff_sz = MX_ALLOC_LEN + 1;
@@ -148,8 +123,10 @@ static char xtra_buff[MX_ALLOC_LEN + 1];
static char usn_buff[MX_ALLOC_LEN + 1];
static const char * find_version_descriptor_str(int value);
-static void decode_dev_ids(const char * leadin, uint8_t * buff,
- int len, int do_hex, int verbose);
+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);
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \
defined(HDIO_GET_IDENTITY)
@@ -159,6 +136,7 @@ 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;
@@ -168,59 +146,69 @@ struct svpd_values_name_t {
const char * acron;
const char * name;
};
+#endif
/* Note that this table is sorted by acronym */
-static struct svpd_values_name_t vpd_pg[] = {
- {VPD_ATA_INFO, 0, -1, 0, "ai", "ATA information (SAT)"},
- {VPD_BLOCK_DEV_CHARS, 0, 0, 0, "bdc",
+static struct svpd_values_name_t t10_vpd_pg[] = {
+ {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
+ {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc",
"Block device characteristics (SBC)"},
- {VPD_BLOCK_DEV_C_EXTENS, 0, 0, 0, "bdce", "Block device characteristics "
+ {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
"extension (SBC)"},
- {VPD_BLOCK_LIMITS, 0, 0, 0, "bl", "Block limits (SBC)"},
- {VPD_BLOCK_LIMITS_EXT, 0, 0, 0, "ble", "Block limits extension (SBC)"},
- {VPD_CON_POS_RANGE, 0, 0, 0, "cpr", "Concurrent positioning ranges "
+ {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
+ {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
+ {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges "
"(SBC)"},
- {VPD_DEVICE_ID, 0, -1, 0, "di", "Device identification"},
+ {VPD_DEVICE_ID, 0, -1, "di", "Device identification"},
#if 0 /* following found in sg_vpd */
- {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, 0, "di_asis", "Like 'di' "
+ {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' "
"but designators ordered as found"},
- {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, 0, "di_lu", "Device identification, "
+ {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, "
"lu only"},
- {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, 0, "di_port", "Device "
+ {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device "
"identification, target port only"},
- {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, 0, "di_target", "Device "
+ {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device "
"identification, target device only"},
#endif
- {VPD_EXT_INQ, 0, -1, 0, "ei", "Extended inquiry data"},
- {VPD_FORMAT_PRESETS, 0, 0, 0, "fp", "Format presets"},
- {VPD_LB_PROVISIONING, 0, 0, 0, "lbpv", "Logical block provisioning "
+ {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
+ {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"},
+ {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning "
"(SBC)"},
- {VPD_MAN_NET_ADDR, 0, -1, 0, "mna", "Management network addresses"},
- {VPD_MODE_PG_POLICY, 0, -1, 0, "mpp", "Mode page policy"},
- {VPD_POWER_CONDITION, 0, -1, 0, "po", "Power condition"},
- {VPD_POWER_CONSUMPTION, 0, -1, 0, "psm", "Power consumption"},
- {VPD_PROTO_LU, 0, 0x0, 0, "pslu", "Protocol-specific logical unit "
+ {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
+ {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
+ {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},
+ {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
+ {VPD_PROTO_LU, 0, 0x0, "pslu", "Protocol-specific logical unit "
"information"},
- {VPD_PROTO_PORT, 0, 0x0, 0, "pspo", "Protocol-specific port information"},
- {VPD_REFERRALS, 0, 0, 0, "ref", "Referrals (SBC)"},
- {VPD_SUP_BLOCK_LENS, 0, 0, 0, "sbl", "Supported block lengths and "
+ {VPD_PROTO_PORT, 0, 0x0, "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, 0, "sfs", "SCSI Feature sets"},
- {VPD_SOFTW_INF_ID, 0, -1, 0, "sii", "Software interface identification"},
- {VPD_NOPE_WANT_STD_INQ, 0, -1, 0, "sinq", "Standard inquiry response"},
- {VPD_UNIT_SERIAL_NUM, 0, -1, 0, "sn", "Unit serial number"},
- {VPD_SCSI_PORTS, 0, -1, 0, "sp", "SCSI ports"},
- {VPD_SUPPORTED_VPDS, 0, -1, 0, "sv", "Supported VPD pages"},
- {VPD_3PARTY_COPY, 0, -1, 0, "tpc", "Third party copy"},
- {VPD_ZBC_DEV_CHARS, 0, -1, 0, "zbdch", "Zoned block device "
+ {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_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 "
"characteristics"},
+ {0, 0, 0, NULL, NULL},
+};
+
+static struct svpd_values_name_t alt_t10_vpd_pg[] = {
+ {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
+ {0, 0, 0, NULL, NULL},
+};
+
+static struct svpd_values_name_t vs_vpd_pg[] = {
/* Following are vendor specific */
- {SG_NVME_VPD_NICR, 0, -1, 1, "nicr",
+ {SG_NVME_VPD_NICR, 0, -1, "nicr",
"NVMe Identify Controller Response (sg3_utils)"},
- {VPD_RDAC_VAC, 0, -1, 1, "rdac_vac", "RDAC volume access control (RDAC)"},
- {VPD_RDAC_VERS, 0, -1, 1, "rdac_vers", "RDAC software version (RDAC)"},
- {VPD_UPR_EMC, 0, -1, 1, "upr", "Unit path report (EMC)"},
- {0, 0, 0, 0, NULL, NULL},
+ {VPD_RDAC_VAC, 0, -1, "rdac_vac", "RDAC volume access control (RDAC)"},
+ {VPD_RDAC_VERS, 0, -1, "rdac_vers", "RDAC software version (RDAC)"},
+ {VPD_UPR_EMC, 0, -1, "upr", "Unit path report (EMC)"},
+ {0, 0, 0, NULL, NULL},
};
static struct option long_options[] = {
@@ -255,38 +243,6 @@ static struct option long_options[] = {
{0, 0, 0, 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
-};
-
static void
usage()
@@ -296,23 +252,26 @@ usage()
pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] "
"[--export]\n"
- " [--extended] [--help] [--hex] [--id] [--inhex=FN] "
- "[--len=LEN]\n"
- " [--long] [--maxlen=LEN] [--only] [--page=PG] "
- "[--raw]\n"
- " [--vendor] [--verbose] [--version] [--vpd] "
- "DEVICE\n"
+ " [--extended] [--help] [--hex] [--id] "
+ "[--inhex=FN]\n"
+ " [--json[=JO]] [--len=LEN] [--long] "
+ "[--maxlen=LEN]\n"
+ " [--only] [--page=PG] [--raw] [--vendor] "
+ "[--verbose]\n"
+ " [--version] [--vpd] DEVICE\n"
" where:\n"
" --ata|-a treat DEVICE as (directly attached) ATA "
"device\n");
#else
pr2serr("Usage: sg_inq [--block=0|1] [--cmddt] [--descriptors] "
"[--export]\n"
- " [--extended] [--help] [--hex] [--id] [--inhex=FN] "
- "[--len=LEN]\n"
- " [--long] [--maxlen=LEN] [--only] [--page=PG] "
- "[--raw]\n"
- " [--verbose] [--version] [--vpd] DEVICE\n"
+ " [--extended] [--help] [--hex] [--id] "
+ "[--inhex=FN]\n"
+ " [--json[=JO]] [--len=LEN] [--long] "
+ "[--maxlen=LEN]\n"
+ " [--only] [--page=PG] [--raw] [--verbose] "
+ "[--version]\n"
+ " [--vpd] DEVICE\n"
" where:\n");
#endif
pr2serr(" --block=0|1 0-> open(non-blocking); 1-> "
@@ -340,6 +299,9 @@ usage()
"DEVICE;\n"
" if used with --raw then read binary "
"from FN\n"
+ " --json[=JO]|-j[JO] output in JSON instead of human "
+ "readable text.\n"
+ " Use --json=? for JSON help\n"
" --len=LEN|-l LEN requested response length (def: 0 "
"-> fetch 36\n"
" bytes first, then fetch again as "
@@ -462,18 +424,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:l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:NoOp:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#else /* SG_LIB_LINUX */
#ifdef SG_SCSI_STRINGS
- c = getopt_long(argc, argv, "B:cdeEfhHiI:l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:NoOp:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#endif /* SG_LIB_LINUX */
@@ -513,7 +475,7 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
case 'x':
op->do_decode = true;
op->do_vpd = true;
- op->page_num = VPD_EXT_INQ;
+ op->vpd_pn = VPD_EXT_INQ;
op->page_given = true;
break;
case 'f':
@@ -522,6 +484,20 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
case 'h':
++op->do_help;
break;
+ case 'j':
+ if (! sgj_init_state(&op->json_st, optarg)) {
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
case 'o':
op->do_only = true;
break;
@@ -535,7 +511,7 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
case 'i':
op->do_decode = true;
op->do_vpd = true;
- op->page_num = VPD_DEVICE_ID;
+ op->vpd_pn = VPD_DEVICE_ID;
op->page_given = true;
break;
case 'I':
@@ -553,7 +529,7 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
pr2serr("Changing that '--maxlen=' value to 4\n");
n = 4;
}
- op->resp_len = n;
+ op->maxlen = n;
break;
case 'L':
++op->do_long;
@@ -566,7 +542,7 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
return 0;
#endif
case 'p':
- op->page_arg = optarg;
+ op->page_str = optarg;
op->page_given = true;
break;
case 'r':
@@ -628,14 +604,14 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
switch (*cp) {
case '3':
if ('6' == *(cp + 1)) {
- op->resp_len = 36;
+ op->maxlen = 36;
--plen;
++cp;
} else
jmp_out = true;
break;
case 'a':
- op->page_num = VPD_ATA_INFO;
+ op->vpd_pn = VPD_ATA_INFO;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -646,7 +622,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
break;
#endif
case 'b':
- op->page_num = VPD_BLOCK_LIMITS;
+ op->vpd_pn = VPD_BLOCK_LIMITS;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -674,7 +650,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
++op->do_hex;
break;
case 'i':
- op->page_num = VPD_DEVICE_ID;
+ op->vpd_pn = VPD_DEVICE_ID;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -683,13 +659,13 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
++op->do_long;
break;
case 'm':
- op->page_num = VPD_MAN_NET_ADDR;
+ op->vpd_pn = VPD_MAN_NET_ADDR;
op->do_vpd = true;
++op->num_pages;
op->page_given = true;
break;
case 'M':
- op->page_num = VPD_MODE_PG_POLICY;
+ op->vpd_pn = VPD_MODE_PG_POLICY;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -703,7 +679,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
case 'O':
break;
case 'P':
- op->page_num = VPD_UPR_EMC;
+ op->vpd_pn = VPD_UPR_EMC;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -712,7 +688,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
++op->do_raw;
break;
case 's':
- op->page_num = VPD_SCSI_PORTS;
+ op->vpd_pn = VPD_SCSI_PORTS;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -728,7 +704,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
op->version_given = true;
break;
case 'x':
- op->page_num = VPD_EXT_INQ;
+ op->vpd_pn = VPD_EXT_INQ;
op->do_vpd = true;
op->page_given = true;
++op->num_pages;
@@ -770,9 +746,9 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
pr2serr("Changing that '-l=' value to 4\n");
n = 4;
}
- op->resp_len = n;
+ op->maxlen = n;
} else if (0 == strncmp("p=", cp, 2)) {
- op->page_arg = cp + 2;
+ op->page_str = cp + 2;
op->page_given = true;
} else if (0 == strncmp("-old", cp, 4))
;
@@ -836,7 +812,15 @@ sdp_find_vpd_by_acron(const char * ap)
{
const struct svpd_values_name_t * vnp;
- for (vnp = vpd_pg; vnp->acron; ++vnp) {
+ for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
+ if (0 == strcmp(vnp->acron, ap))
+ return vnp;
+ }
+ for (vnp = alt_t10_vpd_pg; vnp->acron; ++vnp) {
+ if (0 == strcmp(vnp->acron, ap))
+ return vnp;
+ }
+ for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
if (0 == strcmp(vnp->acron, ap))
return vnp;
}
@@ -848,7 +832,16 @@ enumerate_vpds()
{
const struct svpd_values_name_t * vnp;
- for (vnp = vpd_pg; vnp->acron; ++vnp) {
+ for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
+ if (vnp->name) {
+ if (vnp->value < 0)
+ printf(" %-10s -1 %s\n", vnp->acron, vnp->name);
+ else
+ printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
+ vnp->name);
+ }
+ }
+ for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
if (vnp->name) {
if (vnp->value < 0)
printf(" %-10s -1 %s\n", vnp->acron, vnp->name);
@@ -1053,6 +1046,61 @@ get_vpd_page_str(int vpd_page_num, int scsi_ptype)
}
}
+static int
+svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
+{
+ int k, res, pn;
+ int max_pn = 255;
+ int bump, off;
+ int in_len = op->maxlen;
+ int prev_pn = -1;
+ uint8_t vpd0_buff[512];
+ uint8_t * rp = vpd0_buff;
+
+ if (op->vpd_pn > 0)
+ max_pn = op->vpd_pn;
+
+ res = 0;
+ if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn))
+ return vpd_decode(-1, op, jop, in_len);
+
+ for (k = 0, off = 0; off < in_len; ++k, off += bump) {
+ rp = rsp_buff + off;
+ pn = rp[1];
+ bump = sg_get_unaligned_be16(rp + 2) + 4;
+ if ((off + bump) > in_len) {
+ pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__,
+ pn, bump);
+ bump = in_len - off;
+ }
+ if (op->page_given && (pn != op->vpd_pn))
+ continue;
+ if (pn <= prev_pn) {
+ pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so "
+ "exit\n", __func__, prev_pn, pn);
+ break;
+ }
+ prev_pn = pn;
+ op->vpd_pn = pn;
+ if (pn > max_pn) {
+ if (op->verbose > 2)
+ pr2serr("%s: skipping as this pn=0x%x exceeds "
+ "max_pn=0x%x\n", __func__, pn, max_pn);
+ continue;
+ }
+ if (op->do_long)
+ printf("[0x%x] ", pn);
+
+ op->inhex_off = off;
+ res = vpd_decode(-1, op, jop, in_len);
+ if (SG_LIB_CAT_OTHER == res) {
+ ; // xxxxx
+ }
+ }
+ return res;
+}
+
+
static void
decode_supported_vpd(uint8_t * buff, int len, int do_hex)
{
@@ -1154,196 +1202,115 @@ decode_ascii_inf(uint8_t * buff, int len, int do_hex)
}
static void
-decode_id_vpd(uint8_t * buff, int len, int do_hex, int verbose)
+decode_id_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap)
{
if (len < 4) {
pr2serr("Device identification VPD page length too "
"short=%d\n", len);
return;
}
- decode_dev_ids("Device identification", buff + 4, len - 4, do_hex,
- verbose);
-}
-
-static const char * assoc_arr[] =
-{
- "addressed logical unit",
- "target port", /* that received request; unless SCSI ports VPD */
- "target device that contains addressed lu",
- "reserved [0x3]",
-};
-
-static const char * network_service_type_arr[] =
-{
- "unspecified",
- "storage configuration service",
- "diagnostics",
- "status",
- "logging",
- "code download",
- "copy service",
- "administrative configuration service",
- "[0x8]", "[0x9]", "[0xa]", "[0xb]", "[0xc]", "[0xd]",
- "[0xe]", "[0xf]", "[0x10]", "[0x11]", "[0x12]", "[0x13]", "[0x14]",
- "[0x15]", "[0x16]", "[0x17]", "[0x18]", "[0x19]", "[0x1a]",
- "[0x1b]", "[0x1c]", "[0x1d]", "[0x1e]", "[0x1f]",
-};
-
-/* VPD_MAN_NET_ADDR */
-static void
-decode_net_man_vpd(uint8_t * buff, int len, int do_hex)
-{
- int k, bump, na_len;
- uint8_t * bp;
-
- if (len < 4) {
- pr2serr("Management network addresses VPD page length too short=%d\n",
- len);
- return;
- }
- if (do_hex > 2) {
- hex2stdout(buff, len, -1);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0; k < len; k += bump, bp += bump) {
- printf(" %s, Service type: %s\n",
- assoc_arr[(bp[0] >> 5) & 0x3],
- network_service_type_arr[bp[0] & 0x1f]);
- na_len = sg_get_unaligned_be16(bp + 2);
- bump = 4 + na_len;
- if ((k + bump) > len) {
- pr2serr("Management network addresses VPD page, short "
- "descriptor length=%d, left=%d\n", bump, (len - k));
- return;
- }
- if (na_len > 0) {
- if (do_hex) {
- printf(" Network address:\n");
- hex2stdout(bp + 4, na_len, 0);
- } else
- printf(" %s\n", bp + 4);
- }
- }
-}
-
-static const char * mode_page_policy_arr[] =
-{
- "shared",
- "per target port",
- "per initiator port",
- "per I_T nexus",
-};
-
-/* VPD_MODE_PG_POLICY */
-static void
-decode_mode_policy_vpd(uint8_t * buff, int len, int do_hex)
-{
- int k, bump;
- uint8_t * bp;
-
- if (len < 4) {
- pr2serr("Mode page policy VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex > 2) {
- hex2stdout(buff, len, -1);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0; k < len; k += bump, bp += bump) {
- bump = 4;
- if ((k + bump) > len) {
- pr2serr("Mode page policy VPD page, short "
- "descriptor length=%d, left=%d\n", bump, (len - k));
- return;
- }
- if (do_hex)
- hex2stdout(bp, 4, (1 == do_hex) ? 1 : -1);
- else {
- printf(" Policy page code: 0x%x", (bp[0] & 0x3f));
- if (bp[1])
- printf(", subpage code: 0x%x\n", bp[1]);
- else
- printf("\n");
- printf(" MLUS=%d, Policy: %s\n", !!(bp[2] & 0x80),
- mode_page_policy_arr[bp[2] & 0x3]);
- }
- }
+ decode_dev_ids("Device identification", buff + 4, len - 4, op, jap);
}
/* VPD_SCSI_PORTS */
static void
-decode_scsi_ports_vpd(uint8_t * buff, int len, int do_hex, int verbose)
+decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
{
int k, bump, rel_port, ip_tid_len, tpd_len;
uint8_t * bp;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
if (len < 4) {
pr2serr("SCSI Ports VPD page length too short=%d\n", len);
return;
}
- if (do_hex > 2) {
+ if (op->do_hex > 2) {
hex2stdout(buff, len, -1);
return;
}
len -= 4;
bp = buff + 4;
for (k = 0; k < len; k += bump, bp += bump) {
+ jo2p = sgj_new_unattached_object(jsp);
rel_port = sg_get_unaligned_be16(bp + 2);
- printf("Relative port=%d\n", rel_port);
+ sgj_pr_hr(jsp, "Relative port=%d\n", rel_port);
+ sgj_add_nv_i(jsp, jo2p, "relative_port", rel_port);
ip_tid_len = sg_get_unaligned_be16(bp + 6);
bump = 8 + ip_tid_len;
if ((k + bump) > len) {
pr2serr("SCSI Ports VPD page, short descriptor "
"length=%d, left=%d\n", bump, (len - k));
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
return;
}
if (ip_tid_len > 0) {
- if (do_hex) {
+ if (op->do_hex) {
printf(" Initiator port transport id:\n");
- hex2stdout((bp + 8), ip_tid_len, (1 == do_hex) ? 1 : -1);
+ hex2stdout((bp + 8), ip_tid_len,
+ (1 == op->do_hex) ? 1 : -1);
} else {
char b[1024];
- printf("%s", sg_decode_transportid_str(" ", bp + 8,
- ip_tid_len, true, sizeof(b), 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));
}
}
tpd_len = sg_get_unaligned_be16(bp + bump + 2);
if ((k + bump + tpd_len + 4) > len) {
pr2serr("SCSI Ports VPD page, short descriptor(tgt) "
"length=%d, left=%d\n", bump, (len - k));
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
return;
}
if (tpd_len > 0) {
- printf(" Target port descriptor(s):\n");
- if (do_hex)
- hex2stdout(bp + bump + 4, tpd_len, (1 == do_hex) ? 1 : -1);
- else
+ sgj_pr_hr(jsp, " Target port descriptor(s):\n");
+ if (op->do_hex)
+ hex2stdout(bp + bump + 4, tpd_len,
+ (1 == op->do_hex) ? 1 : -1);
+ else {
+ sgj_opaque_p ja2p = sgj_new_named_array(jsp, jo2p,
+ "target_port_descriptor_list");
+
decode_dev_ids("SCSI Ports", bp + bump + 4, tpd_len,
- do_hex, verbose);
+ op, ja2p);
+ }
}
bump += tpd_len + 4;
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
}
}
/* These are target port, device server (i.e. target) and LU identifiers */
static void
-decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
- int verbose)
+decode_dev_ids(const char * leadin, uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap)
{
int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len;
- int off, ci_off, c_id, d_id, naa, vsi, k;
+ int off, ci_off, c_id, d_id, naa, vsi, k, n;
uint64_t vsei, id_ext, ccc_id;
const uint8_t * bp;
const uint8_t * ip;
const char * cp;
- char b[64];
+ sgj_state * jsp = &op->json_st;
+ char b[256];
+ char d[64];
+ static const int blen = sizeof(b);
+ static const int dlen = sizeof(d);
- if (buff[2] != 0) {
+ if (jsp->pr_as_json) {
+ int ret = filter_json_dev_ids(buff, len, -1, op, jap);
+
+ if (ret || (! jsp->pr_out_hr))
+ return;
+ }
+ if (buff[2] > 2) { /* SPC-3,4,5 buff[2] is upper byte of length */
/*
* Reference the 3rd byte of the first Identification descriptor
* of a page 83 reply to determine whether the reply is compliant
@@ -1363,7 +1330,8 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
desig_type = 3;
j = 1;
off = 16;
- printf(" Pre-SPC descriptor, descriptor length: %d\n", i_len);
+ sgj_pr_hr(jsp, " Pre-SPC descriptor, descriptor length: %d\n",
+ i_len);
goto decode;
}
@@ -1373,8 +1341,8 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
bp = buff + off;
i_len = bp[3];
id_len = i_len + 4;
- printf(" Designation descriptor number %d, "
- "descriptor length: %d\n", j, id_len);
+ sgj_pr_hr(jsp, " Designation descriptor number %d, "
+ "descriptor length: %d\n", j, id_len);
if ((off + id_len) > len) {
pr2serr("%s VPD page error: designator length longer "
"than\n remaining response length=%d\n", leadin,
@@ -1389,18 +1357,20 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
desig_type = (bp[1] & 0xf);
decode:
if (piv && ((1 == assoc) || (2 == assoc)))
- printf(" transport: %s\n",
- sg_get_trans_proto_str(p_id, sizeof(b), b));
+ sgj_pr_hr(jsp, " transport: %s\n",
+ sg_get_trans_proto_str(p_id, dlen, d));
+ n = 0;
cp = sg_get_desig_type_str(desig_type);
- printf(" designator_type: %s, ", cp ? cp : "-");
+ n += sg_scnpr(b + n, blen - n, " designator_type: %s, ",
+ cp ? cp : "-");
cp = sg_get_desig_code_set_str(c_set);
- printf("code_set: %s\n", cp ? cp : "-");
+ sgj_pr_hr(jsp, "%scode_set: %s\n", b, cp ? cp : "-");
cp = sg_get_desig_assoc_str(assoc);
- printf(" associated with the %s\n", cp ? cp : "-");
- if (do_hex) {
- printf(" designator header(hex): %.2x %.2x %.2x %.2x\n",
+ sgj_pr_hr(jsp, " associated with the %s\n", cp ? cp : "-");
+ if (op->do_hex) {
+ sgj_pr_hr(jsp, " designator header(hex): %.2x %.2x %.2x %.2x\n",
bp[0], bp[1], bp[2], bp[3]);
- printf(" designator:\n");
+ sgj_pr_hr(jsp, " designator:\n");
hex2stdout(ip, i_len, 0);
continue;
}
@@ -1414,37 +1384,44 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
k = 1;
}
if (k)
- printf(" vendor specific: %.*s\n", i_len, ip);
+ sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len, ip);
else {
- printf(" vendor specific:\n");
+ sgj_pr_hr(jsp, " vendor specific:\n");
hex2stdout(ip, i_len, -1);
}
break;
case 1: /* T10 vendor identification */
- printf(" vendor id: %.8s\n", ip);
+ sgj_pr_hr(jsp, " vendor id: %.8s\n", ip);
if (i_len > 8) {
if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
- printf(" vendor specific: %.*s\n", i_len - 8, ip + 8);
+ sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len - 8,
+ ip + 8);
} else {
- printf(" vendor specific: 0x");
+ n = 0;
+ n += sg_scnpr(b + n, blen - n,
+ " vendor specific: 0x");
for (m = 8; m < i_len; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s\n", b);
}
}
break;
case 2: /* EUI-64 based */
- printf(" EUI-64 based %d byte identifier\n", i_len);
+ sgj_pr_hr(jsp, " EUI-64 based %d byte identifier\n", i_len);
if (1 != c_set) {
pr2serr(" << expected binary code_set (1)>>\n");
hex2stderr(ip, i_len, -1);
break;
}
ci_off = 0;
+ n = 0;
+ b[0] = '\0';
if (16 == i_len) {
ci_off = 8;
id_ext = sg_get_unaligned_be64(ip);
- printf(" Identifier extension: 0x%" PRIx64 "\n", id_ext);
+ n += sg_scnpr(b + n, blen - n,
+ " Identifier extension: 0x%" PRIx64 "\n",
+ id_ext);
} else if ((8 != i_len) && (12 != i_len)) {
pr2serr(" << can only decode 8, 12 and 16 "
"byte ids>>\n");
@@ -1452,15 +1429,17 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
break;
}
ccc_id = sg_get_unaligned_be64(ip + ci_off);
- printf(" IEEE identifier: 0x%" PRIx64 "\n", ccc_id);
+ sgj_pr_hr(jsp, "%s IEEE identifier: 0x%" PRIx64 "\n", b,
+ ccc_id);
if (12 == i_len) {
d_id = sg_get_unaligned_be32(ip + 8);
- printf(" Directory ID: 0x%x\n", d_id);
+ sgj_pr_hr(jsp, " Directory ID: 0x%x\n", d_id);
}
- printf(" [0x");
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " [0x");
for (m = 0; m < i_len; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("]\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s]\n", b);
break;
case 3: /* NAA <n> */
naa = (ip[0] >> 4) & 0xff;
@@ -1481,14 +1460,16 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
d_id = (((ip[0] & 0xf) << 8) | ip[1]);
c_id = sg_get_unaligned_be24(ip + 2);
vsi = sg_get_unaligned_be24(ip + 5);
- printf(" NAA 2, vendor specific identifier A: 0x%x\n",
- d_id);
- printf(" AOI: 0x%x\n", c_id);
- printf(" vendor specific identifier B: 0x%x\n", vsi);
- printf(" [0x");
+ sgj_pr_hr(jsp, " NAA 2, vendor specific identifier A: "
+ "0x%x\n", d_id);
+ sgj_pr_hr(jsp, " AOI: 0x%x\n", c_id);
+ sgj_pr_hr(jsp, " vendor specific identifier B: 0x%x\n",
+ vsi);
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " [0x");
for (m = 0; m < 8; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("]\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s]\n", b);
break;
case 3: /* NAA 3: Locally assigned */
if (8 != i_len) {
@@ -1497,11 +1478,12 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
hex2stderr(ip, i_len, -1);
break;
}
- printf(" NAA 3, Locally assigned:\n");
- printf(" [0x");
+ sgj_pr_hr(jsp, " NAA 3, Locally assigned:\n");
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " [0x");
for (m = 0; m < 8; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("]\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s]\n", b);
break;
case 5: /* NAA 5: IEEE Registered */
if (8 != i_len) {
@@ -1517,13 +1499,14 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
vsei <<= 8;
vsei |= ip[3 + m];
}
- printf(" NAA 5, AOI: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%" PRIx64
- "\n", vsei);
- printf(" [0x");
+ sgj_pr_hr(jsp, " NAA 5, AOI: 0x%x\n", c_id);
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " Vendor Specific "
+ "Identifier: 0x%" PRIx64 "\n", vsei);
+ n += sg_scnpr(b + n, blen - n, " [0x");
for (m = 0; m < 8; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("]\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s]\n", b);
break;
case 6: /* NAA 6: IEEE Registered extended */
if (16 != i_len) {
@@ -1539,16 +1522,17 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
vsei <<= 8;
vsei |= ip[3 + m];
}
- printf(" NAA 6, AOI: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n",
- vsei);
+ sgj_pr_hr(jsp, " NAA 6, AOI: 0x%x\n", c_id);
+ sgj_pr_hr(jsp, " Vendor Specific Identifier: 0x%"
+ PRIx64 "\n", vsei);
vsei = sg_get_unaligned_be64(ip + 8);
- printf(" Vendor Specific Identifier Extension: "
- "0x%" PRIx64 "\n", vsei);
- printf(" [0x");
+ sgj_pr_hr(jsp, " Vendor Specific Identifier Extension: "
+ "0x%" PRIx64 "\n", vsei);
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " [0x");
for (m = 0; m < 16; ++m)
- printf("%02x", (unsigned int)ip[m]);
- printf("]\n");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[m]);
+ sgj_pr_hr(jsp, "%s]\n", b);
break;
default:
pr2serr(" << bad NAA nibble , expect 2, 3, 5 or 6, "
@@ -1565,7 +1549,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
break;
}
d_id = sg_get_unaligned_be16(ip + 2);
- printf(" Relative target port: 0x%x\n", d_id);
+ sgj_pr_hr(jsp, " Relative target port: 0x%x\n", d_id);
break;
case 5: /* (primary) Target port group */
if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
@@ -1575,7 +1559,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
break;
}
d_id = sg_get_unaligned_be16(ip + 2);
- printf(" Target port group: 0x%x\n", d_id);
+ sgj_pr_hr(jsp, " Target port group: 0x%x\n", d_id);
break;
case 6: /* Logical unit group */
if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
@@ -1585,7 +1569,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
break;
}
d_id = sg_get_unaligned_be16(ip + 2);
- printf(" Logical unit group: 0x%x\n", d_id);
+ sgj_pr_hr(jsp, " Logical unit group: 0x%x\n", d_id);
break;
case 7: /* MD5 logical unit identifier */
if ((1 != c_set) || (0 != assoc)) {
@@ -1594,13 +1578,16 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
hex2stderr(ip, i_len, -1);
break;
}
- printf(" MD5 logical unit identifier:\n");
- hex2stdout(ip, i_len, -1);
+ sgj_pr_hr(jsp, " MD5 logical unit identifier:\n");
+ if (jsp->pr_out_hr)
+ sgj_pr_str_out_hr(jsp, (const char *)ip, i_len);
+ else
+ hex2stdout(ip, i_len, -1);
break;
case 8: /* SCSI name string */
if (3 != c_set) {
if (2 == c_set) {
- if (verbose)
+ if (op->verbose)
pr2serr(" << expected UTF-8, use ASCII>>\n");
} else {
pr2serr(" << expected UTF-8 code_set>>\n");
@@ -1608,33 +1595,36 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
break;
}
}
- printf(" SCSI name string:\n");
+ sgj_pr_hr(jsp, " SCSI name string:\n");
/* does %s print out UTF-8 ok??
* Seems to depend on the locale. Looks ok here with my
* locale setting: en_AU.UTF-8
*/
- printf(" %.*s\n", i_len, (const char *)ip);
+ sgj_pr_hr(jsp, " %.*s\n", i_len, (const char *)ip);
break;
case 9: /* Protocol specific port identifier */
/* added in spc4r36, PIV must be set, proto_id indicates */
/* whether UAS (USB) or SOP (PCIe) or ... */
if (! piv)
- printf(" >>>> Protocol specific port identifier "
- "expects protocol\n"
- " identifier to be valid and it is not\n");
+ pr2serr(" >>>> Protocol specific port identifier "
+ "expects protocol\n"
+ " identifier to be valid and it is not\n");
if (TPROTO_UAS == p_id) {
- printf(" USB device address: 0x%x\n", 0x7f & ip[0]);
- printf(" USB interface number: 0x%x\n", ip[2]);
+ sgj_pr_hr(jsp, " USB device address: 0x%x\n",
+ 0x7f & ip[0]);
+ sgj_pr_hr(jsp, " USB interface number: 0x%x\n", ip[2]);
} else if (TPROTO_SOP == p_id) {
- printf(" PCIe routing ID, bus number: 0x%x\n", ip[0]);
- printf(" function number: 0x%x\n", ip[1]);
- printf(" [or device number: 0x%x, function number: "
- "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
+ sgj_pr_hr(jsp, " PCIe routing ID, bus number: 0x%x\n",
+ ip[0]);
+ sgj_pr_hr(jsp, " function number: 0x%x\n", ip[1]);
+ sgj_pr_hr(jsp, " [or device number: 0x%x, function "
+ "number: 0x%x]\n", (0x1f & (ip[1] >> 3)),
+ 0x7 & ip[1]);
} else
- printf(" >>>> unexpected protocol identifier: %s\n"
- " with Protocol specific port "
- "identifier\n",
- sg_get_trans_proto_str(p_id, sizeof(b), b));
+ sgj_pr_hr(jsp, " >>>> unexpected protocol identifier: "
+ "%s\n with Protocol specific port "
+ "identifier\n", sg_get_trans_proto_str(p_id, dlen,
+ d));
break;
case 0xa: /* UUID identifier [spc5r08] RFC 4122 */
if (1 != c_set) {
@@ -1648,13 +1638,14 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
hex2stderr(ip, i_len, 0);
break;
}
- printf(" Locally assigned UUID: ");
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, " Locally assigned UUID: ");
for (m = 0; m < 16; ++m) {
if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
- printf("-");
- printf("%02x", (unsigned int)ip[2 + m]);
+ n += sg_scnpr(b + n, blen - n, "-");
+ n += sg_scnpr(b + n, blen - n, "%02x", ip[2 + m]);
}
- printf("\n");
+ sgj_pr_hr(jsp, "%s\n", b);
break;
default: /* reserved */
pr2serr(" reserved designator=0x%x\n", desig_type);
@@ -1963,75 +1954,6 @@ export_dev_ids(uint8_t * buff, int len, int verbose)
"around offset=%d\n", off);
}
-/* VPD_EXT_INQ Extended Inquiry [0x86] */
-static void
-decode_x_inq_vpd(uint8_t * buff, int len, int do_hex)
-{
- if (len < 7) {
- pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- printf(" ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d "
- "REF_CHK=%d\n", ((buff[4] >> 6) & 0x3), ((buff[4] >> 3) & 0x7),
- !!(buff[4] & 0x4), !!(buff[4] & 0x2), !!(buff[4] & 0x1));
- printf(" UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d "
- "SIMPSUP=%d\n", !!(buff[5] & 0x20), !!(buff[5] & 0x10),
- !!(buff[5] & 0x8), !!(buff[5] & 0x4), !!(buff[5] & 0x2),
- !!(buff[5] & 0x1));
- /* CRD_SUP made obsolete in spc5r04 */
- printf(" WU_SUP=%d [CRD_SUP=%d] NV_SUP=%d V_SUP=%d\n",
- !!(buff[6] & 0x8), !!(buff[6] & 0x4), !!(buff[6] & 0x2),
- !!(buff[6] & 0x1));
- /* NO_PI_CHK and HSSRELEF added in spc5r02 */
- printf(" NO_PI_CHK=%d P_I_I_SUP=%d LUICLR=%d\n", !!(buff[7] & 0x20),
- !!(buff[7] & 0x10), !!(buff[7] & 0x1));
- /* RTD_SUP added in spc5r11, LU_COLL_TYPE added in spc5r09,
- * HSSRELEF added in spc5r02; CBCS obsolete in spc5r01 */
- printf(" LU_COLL_TYPE=%d R_SUP=%d RTD_SUP=%d HSSRELEF=%d [CBCS=%d]\n",
- (buff[8] >> 5) & 0x7, !!(buff[8] & 0x10), !!(buff[8] & 0x8),
- !!(buff[8] & 0x2), !!(buff[8] & 0x1));
- printf(" Multi I_T nexus microcode download=%d\n", buff[9] & 0xf);
- printf(" Extended self-test completion minutes=%d\n",
- sg_get_unaligned_be16(buff + 10)); /* spc4r27 */
- printf(" POA_SUP=%d HRA_SUP=%d VSA_SUP=%d DMS_VALID=%d\n",
- !!(buff[12] & 0x80), !!(buff[12] & 0x40), !!(buff[12] & 0x20),
- !!(buff[12] & 0x10)); /* spc5r20 */
- printf(" Maximum supported sense data length=%d\n",
- buff[13]); /* spc4r34 */
- /* All byte 14 bits added in spc5r09 */
- printf(" IBS=%d IAS=%d SAC=%d NRD1=%d NRD0=%d\n",
- !!(buff[14] & 0x80), !!(buff[14] & 0x40), !!(buff[14] & 0x4),
- !!(buff[14] & 0x2), !!(buff[14] & 0x1));
- printf(" Maximum inquiry change logs=%u\n",
- sg_get_unaligned_be16(buff + 15)); /* spc5r17 */
- printf(" Maximum mode page change logs=%u\n",
- sg_get_unaligned_be16(buff + 17)); /* spc5r17 */
- printf(" DM_MD_4=%d DM_MD_5=%d DM_MD_6=%d DM_MD_7=%d\n",
- !!(buff[19] & 0x80), !!(buff[19] & 0x40), !!(buff[19] & 0x20),
- !!(buff[19] & 0x10)); /* spc5r20 */
- printf(" DM_MD_D=%d DM_MD_E=%d DM_MD_F=%d\n",
- !!(buff[19] & 0x8), !!(buff[19] & 0x4), !!(buff[19] & 0x2));
-}
-
-/* VPD_SOFTW_INF_ID [0x84] */
-static void
-decode_softw_inf_id(uint8_t * buff, int len, int do_hex)
-{
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- len -= 4;
- buff += 4;
- for ( ; len > 5; len -= 6, buff += 6)
- printf(" IEEE identifier: 0x%" PRIx64 "\n",
- sg_get_unaligned_be48(buff + 0));
-}
-
/* VPD_ATA_INFO [0x89] */
static void
decode_ata_info_vpd(uint8_t * buff, int len, int do_hex)
@@ -2091,35 +2013,6 @@ decode_ata_info_vpd(uint8_t * buff, int len, int do_hex)
sg_is_big_endian());
}
-/* VPD_POWER_CONDITION [0x8a] */
-static void
-decode_power_condition(uint8_t * buff, int len, int do_hex)
-{
- if (len < 18) {
- pr2serr("Power condition VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- printf(" Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d Idle_a=%d\n",
- !!(buff[4] & 0x2), !!(buff[4] & 0x1),
- !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1));
- printf(" Stopped condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 6));
- printf(" Standby_z condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 8));
- printf(" Standby_y condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 10));
- printf(" Idle_a condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 12));
- printf(" Idle_b condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 14));
- printf(" Idle_c condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 16));
-}
-
/* VPD_SCSI_FEATURE_SETS [0x92] (sfs) */
static void
decode_feature_sets_vpd(uint8_t * buff, int len,
@@ -2779,7 +2672,7 @@ std_inq_decode(const struct opts_t * op, int act_len)
char buff[48];
const uint8_t * rp;
- rp = rsp_buff;
+ rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
memset(vdesc_arr, 0, sizeof(vdesc_arr));
if (op->do_raw) {
dStrRaw((const char *)rp, act_len);
@@ -2940,7 +2833,7 @@ std_inq_decode(const struct opts_t * op, int act_len)
}
}
if (! op->do_export) {
- if ((0 == op->resp_len) && usn_buff[0])
+ if ((0 == op->maxlen) && usn_buff[0])
printf(" Unit serial number: %s\n", usn_buff);
if (op->do_descriptors) {
if (0 == vdesc_arr[0])
@@ -3112,7 +3005,7 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
std_inq_decode(op, inhex_len);
return 0;
}
- rlen = (op->resp_len > 0) ? op->resp_len : SAFE_STD_INQ_RESP_LEN;
+ rlen = (op->maxlen > 0) ? op->maxlen : SAFE_STD_INQ_RESP_LEN;
vb = op->verbose;
res = sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen, DEF_PT_TIMEOUT,
&resid, false, vb);
@@ -3123,7 +3016,7 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
}
len = rsp_buff[4] + 5;
if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) &&
- (0 == op->resp_len)) {
+ (0 == op->maxlen)) {
rlen = len;
memset(rsp_buff, 0, rlen);
if (sg_ll_inquiry_v2(sg_fd, false, 0, rsp_buff, rlen,
@@ -3137,7 +3030,7 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
len = rsp_buff[4] + 5;
}
}
- if (op->resp_len > 0)
+ if (op->maxlen > 0)
act_len = rlen;
else
act_len = (rlen < len) ? rlen : len;
@@ -3146,7 +3039,7 @@ std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
act_len = rlen - resid;
if (act_len < SAFE_STD_INQ_RESP_LEN)
rsp_buff[act_len] = '\0';
- if ((! op->do_only) && (! op->do_export) && (0 == op->resp_len)) {
+ if ((! op->do_only) && (! op->do_export) && (0 == op->maxlen)) {
if (fetch_unit_serial_num(sg_fd, usn_buff, sizeof(usn_buff), vb))
usn_buff[0] = '\0';
}
@@ -3229,13 +3122,13 @@ cmddt_process(int sg_fd, const struct opts_t * op)
}
}
else {
- res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, op->page_num,
+ 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;
if (! op->do_raw) {
- printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->page_num);
- sg_get_opcode_name((uint8_t)op->page_num, peri_type,
+ printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn);
+ sg_get_opcode_name((uint8_t)op->vpd_pn, peri_type,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf("%s]\n", op_name);
@@ -3282,13 +3175,13 @@ cmddt_process(int sg_fd, const struct opts_t * op)
}
} else if (SG_LIB_CAT_ILLEGAL_REQ != res) {
if (! op->do_raw) {
- printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->page_num);
- sg_get_opcode_name((uint8_t)op->page_num, 0,
+ printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn);
+ sg_get_opcode_name((uint8_t)op->vpd_pn, 0,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf("%s]\n", op_name);
}
- pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", op->page_num);
+ pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", op->vpd_pn);
}
}
return res;
@@ -3318,9 +3211,9 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
const char * cp;
uint8_t * rp;
- rp = rsp_buff;
+ rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
if ((! op->do_raw) && (op->do_hex < 2))
- printf("VPD INQUIRY, page code=0x%.2x:\n", op->page_num);
+ 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))
@@ -3329,14 +3222,14 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
res = 0;
} else {
memset(rp, 0, DEF_ALLOC_LEN);
- res = vpd_fetch_page_from_dev(sg_fd, rp, op->page_num, op->resp_len,
+ res = vpd_fetch_page_from_dev(sg_fd, rp, op->vpd_pn, op->maxlen,
op->verbose, &len);
}
if (0 == res) {
if (op->do_raw)
dStrRaw((const char *)rp, len);
else {
- if (0 == op->page_num)
+ if (0 == op->vpd_pn)
decode_supported_vpd(rp, len, op->do_hex);
else {
if (op->verbose) {
@@ -3361,18 +3254,25 @@ vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
/* Returns 0 if successful */
static int
-vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
+vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int inhex_len)
{
bool bad = false;
- int len, pdt, pn, vb, mxlen;
+ int len, pdt, pn, vb, mxlen /*, pqual */;
int res = 0;
+ sgj_state * jsp = &op->json_st;
+ bool as_json = jsp->pr_as_json;
+ sgj_opaque_p jo2p = NULL;
+ sgj_opaque_p jap = NULL;
+ const char * np;
+ // const char * pdt_str;
uint8_t * rp;
+ // char d[80];
- pn = op->page_num;
- rp = rsp_buff;
+ pn = op->vpd_pn;
+ rp = rsp_buff + (op->inhex_fn ? op->inhex_off : 0);
vb = op->verbose;
if (sg_fd >= 0)
- mxlen = op->resp_len;
+ mxlen = op->maxlen;
else
mxlen = inhex_len;
if (sg_fd != -1 && !op->do_force && pn != VPD_SUPPORTED_VPDS) {
@@ -3400,7 +3300,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
else if (op->do_hex)
hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
else
- decode_supported_vpd(rp, len, PDT_MASK & rp[0]);
+ decode_supported_vpd(rp, len, op->do_hex);
break;
case VPD_UNIT_SERIAL_NUM:
if (! op->do_raw && ! op->do_export && (op->do_hex < 2))
@@ -3445,8 +3345,9 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
}
break;
case VPD_DEVICE_ID:
+ np = "Device Identification VPD page";
if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
- printf("VPD INQUIRY: Device Identification page\n");
+ 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;
@@ -3454,54 +3355,88 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
dStrRaw((const char *)rp, len);
else if (op->do_hex > 2)
hex2stdout(rp, len, -1);
- else if (op->do_export)
+ else if (op->do_export && (! as_json))
export_dev_ids(rp + 4, len - 4, op->verbose);
- else
- decode_id_vpd(rp, len, op->do_hex, op->verbose);
+ else {
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "designation_descriptor_list");
+ }
+ decode_id_vpd(rp, len, op, jap);
+ }
break;
- case VPD_SOFTW_INF_ID:
+ case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
+ np = "Software interface identification VPD page";
if (! op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Software interface identification page\n");
+ printf("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
- decode_softw_inf_id(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,
+ "software_interface_identifier_list");
+ }
+ decode_softw_inf_id(rp, len, op, jap);
+ }
break;
- case VPD_MAN_NET_ADDR:
+ case VPD_MAN_NET_ADDR: /* 0x86 ["mna"] */
+ np = "Management network addresses page";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Management network addresses page\n");
+ 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
- decode_net_man_vpd(rp, len, op->do_hex);
+ else {
+ // pdt = rp[0] & PDT_MASK;
+ // pdt_str = sg_get_pdt_str(pdt, sizeof(d), d);
+ // pqual = (rp[0] & 0xe0) >> 5;
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_new_named_array(jsp, jo2p,
+ "network_services_descriptor_list");
+ }
+ decode_net_man_vpd(rp, len, op, jap);
+ }
break;
case VPD_MODE_PG_POLICY:
+ np = "Mode page policy";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Mode page policy\n");
+ 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
- decode_mode_policy_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,
+ "mode_page_policy_descriptor_list");
+ }
+ decode_mode_policy_vpd(rp, len, op, jap);
+ }
break;
case VPD_EXT_INQ:
+ np = "Extended INQUIRY data";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: extended INQUIRY data page\n");
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s page\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
- decode_x_inq_vpd(rp, len, op->do_hex);
+ 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_ATA_INFO:
if (!op->do_raw && (op->do_hex < 2))
@@ -3518,16 +3453,20 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
else
decode_ata_info_vpd(rp, len, op->do_hex);
break;
- case VPD_POWER_CONDITION:
+ case VPD_POWER_CONDITION: /* 0x8a ["pc"] */
+ np = "Power condition page VPD page";
if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Power condition page\n");
+ 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
- decode_power_condition(rp, len, op->do_hex);
+ else {
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ decode_power_condition(rp, len, op, jo2p);
+ }
break;
case VPD_SCSI_FEATURE_SETS: /* 0x92 */
if (!op->do_raw && (op->do_hex < 2))
@@ -3671,15 +3610,22 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
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))
- printf("VPD INQUIRY: SCSI Ports page\n");
+ 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
- decode_scsi_ports_vpd(rp, len, op->do_hex, op->verbose);
+ 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;
@@ -4093,17 +4039,21 @@ err_out:
int
main(int argc, char * argv[])
{
+ bool as_json;
int res, n, err;
int sg_fd = -1;
int ret = 0;
int inhex_len = 0;
const struct svpd_values_name_t * vnp;
+ sgj_state * jsp;
+ sgj_opaque_p jop = NULL;
struct opts_t opts;
struct opts_t * op;
op = &opts;
memset(op, 0, sizeof(opts));
- op->page_num = -1;
+ op->invoker = SG_VPD_INV_SG_INQ;
+ op->vpd_pn = -1;
op->page_pdt = -1;
op->do_block = -1; /* use default for OS */
res = parse_cmd_line(op, argc, argv);
@@ -4138,25 +4088,25 @@ main(int argc, char * argv[])
pr2serr("Version string: %s\n", version_str);
return 0;
}
- if (op->page_arg) {
- if (op->page_num >= 0) {
+ if (op->page_str) {
+ if (op->vpd_pn >= 0) {
pr2serr("Given '-p' option and another option that "
"implies a page\n");
return SG_LIB_CONTRADICT;
}
- if (isalpha((uint8_t)op->page_arg[0])) {
- vnp = sdp_find_vpd_by_acron(op->page_arg);
+ if (isalpha((uint8_t)op->page_str[0])) {
+ vnp = sdp_find_vpd_by_acron(op->page_str);
if (NULL == vnp) {
#ifdef SG_SCSI_STRINGS
if (op->opt_new)
pr2serr("abbreviation %s given to '--page=' "
- "not recognized\n", op->page_arg);
+ "not recognized\n", op->page_str);
else
pr2serr("abbreviation %s given to '-p=' "
- "not recognized\n", op->page_arg);
+ "not recognized\n", op->page_str);
#else
pr2serr("abbreviation %s given to '--page=' "
- "not recognized\n", op->page_arg);
+ "not recognized\n", op->page_str);
#endif
pr2serr(">>> Available abbreviations:\n");
enumerate_vpds();
@@ -4164,14 +4114,14 @@ main(int argc, char * argv[])
}
if ((1 != op->do_hex) && (0 == op->do_raw))
op->do_decode = true;
- op->page_num = vnp->value;
+ op->vpd_pn = vnp->value;
op->page_pdt = vnp->pdt;
- } else if ('-' == op->page_arg[0])
- op->page_num = VPD_NOPE_WANT_STD_INQ;
+ } else if ('-' == op->page_str[0])
+ op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
else {
#ifdef SG_SCSI_STRINGS
if (op->opt_new) {
- n = sg_get_num(op->page_arg);
+ n = sg_get_num(op->page_str);
if ((n < 0) || (n > 255)) {
pr2serr("Bad argument to '--page=', "
"expecting 0 to 255 inclusive\n");
@@ -4184,7 +4134,7 @@ main(int argc, char * argv[])
int num;
unsigned int u;
- num = sscanf(op->page_arg, "%x", &u);
+ num = sscanf(op->page_str, "%x", &u);
if ((1 != num) || (u > 255)) {
pr2serr("Inappropriate value after '-o=' "
"or '-p=' option\n");
@@ -4194,7 +4144,7 @@ main(int argc, char * argv[])
n = u;
}
#else
- n = sg_get_num(op->page_arg);
+ n = sg_get_num(op->page_str);
if ((n < 0) || (n > 255)) {
pr2serr("Bad argument to '--page=', "
"expecting 0 to 255 inclusive\n");
@@ -4204,9 +4154,14 @@ main(int argc, char * argv[])
if ((1 != op->do_hex) && (0 == op->do_raw))
op->do_decode = true;
#endif /* SG_SCSI_STRINGS */
- op->page_num = n;
+ op->vpd_pn = n;
}
}
+ jsp = &op->json_st;
+ as_json = jsp->pr_as_json;
+ if (as_json)
+ jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
+
rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff,
false);
if (NULL == rsp_buff) {
@@ -4233,7 +4188,8 @@ main(int argc, char * argv[])
goto err_out;
}
op->do_raw = 0; /* don't want raw on output with --inhex= */
- if (-1 == op->page_num) { /* may be able to deduce VPD page */
+ 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];
if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
@@ -4260,7 +4216,7 @@ main(int argc, char * argv[])
if (op->verbose)
pr2serr("Guessing from --inhex= this is VPD "
"page 0x%x\n", rsp_buff[1]);
- op->page_num = rsp_buff[1];
+ op->vpd_pn = rsp_buff[1];
op->do_vpd = true;
if ((1 != op->do_hex) && (0 == op->do_raw))
op->do_decode = true;
@@ -4270,6 +4226,12 @@ main(int argc, char * argv[])
pr2serr("page number unclear from --inhex, hope it's a "
"standard INQUIRY\n");
}
+ } else
+ op->do_vpd = true;
+ if (op->do_vpd) { /* Allow for multiple VPD pages from 'sg_vpd -a' */
+ op->maxlen = inhex_len;
+ ret = svpd_inhex_decode_all(op, jop);
+ goto fini2;
}
} else if (0 == op->device_name) {
pr2serr("No DEVICE argument given\n\n");
@@ -4277,13 +4239,13 @@ main(int argc, char * argv[])
ret = SG_LIB_SYNTAX_ERROR;
goto err_out;
}
- if (VPD_NOPE_WANT_STD_INQ == op->page_num)
- op->page_num = -1; /* now past guessing, set to normal indication */
+ if (VPD_NOPE_WANT_STD_INQ == op->vpd_pn)
+ op->vpd_pn = -1; /* now past guessing, set to normal indication */
if (op->do_export) {
- if (op->page_num != -1) {
- if (op->page_num != VPD_DEVICE_ID &&
- op->page_num != VPD_UNIT_SERIAL_NUM) {
+ if (op->vpd_pn != -1) {
+ if (op->vpd_pn != VPD_DEVICE_ID &&
+ op->vpd_pn != VPD_UNIT_SERIAL_NUM) {
pr2serr("Option '--export' only supported for VPD pages 0x80 "
"and 0x83\n");
usage_for(op);
@@ -4295,7 +4257,7 @@ main(int argc, char * argv[])
}
}
- if ((0 == op->do_cmddt) && (op->page_num >= 0) && op->page_given)
+ if ((0 == op->do_cmddt) && (op->vpd_pn >= 0) && op->page_given)
op->do_vpd = true;
if (op->do_raw && op->do_hex) {
@@ -4317,8 +4279,8 @@ main(int argc, char * argv[])
ret = SG_LIB_CONTRADICT;
goto err_out;
}
- if (((op->do_vpd || op->do_cmddt)) && (op->page_num < 0))
- op->page_num = 0;
+ if (((op->do_vpd || op->do_cmddt)) && (op->vpd_pn < 0))
+ op->vpd_pn = 0;
if (op->num_pages > 1) {
pr2serr("Can only fetch one page (VPD or Cmd) at a time\n");
usage_for(op);
@@ -4326,7 +4288,7 @@ main(int argc, char * argv[])
goto err_out;
}
if (op->do_descriptors) {
- if ((op->resp_len > 0) && (op->resp_len < 60)) {
+ if ((op->maxlen > 0) && (op->maxlen < 60)) {
pr2serr("version descriptors need INQUIRY response "
"length >= 60 bytes\n");
ret = SG_LIB_SYNTAX_ERROR;
@@ -4354,7 +4316,7 @@ main(int argc, char * argv[])
if (op->inhex_fn) {
if (op->do_vpd) {
if (op->do_decode)
- ret = vpd_decode(-1, op, inhex_len);
+ ret = vpd_decode(-1, op, jop, inhex_len);
else
ret = vpd_mainly_hex(-1, op, inhex_len);
goto err_out;
@@ -4445,14 +4407,14 @@ main(int argc, char * argv[])
if (ret)
goto err_out;
} else if (op->do_cmddt) {
- if (op->page_num < 0)
- op->page_num = 0;
+ if (op->vpd_pn < 0)
+ op->vpd_pn = 0;
ret = cmddt_process(sg_fd, op);
if (ret)
goto err_out;
} else if (op->do_vpd) {
if (op->do_decode) {
- ret = vpd_decode(sg_fd, op, -1);
+ ret = vpd_decode(sg_fd, op, jop, -1);
if (ret)
goto err_out;
} else {
@@ -4482,9 +4444,15 @@ err_out:
if (res < 0) {
pr2serr("close error: %s\n", safe_strerror(-res));
if (0 == ret)
- return sg_convert_errno(-res);
+ ret = sg_convert_errno(-res);
}
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ if (as_json) {
+ if (0 == op->do_hex)
+ sgj_pr2file(jsp, NULL, ret, stdout);
+ sgj_finish(jsp);
+ }
+ return ret;
}
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 89c982e4..122111d2 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.h"
+#include "sg_vpd_common.h" /* shared with sg_inq */
/* This utility program was originally written for the Linux OS SCSI subsystem.
@@ -42,49 +42,9 @@
*/
-static const char * version_str = "1.73 20220705"; /* spc6r06 + sbc5r01 */
-
-#define MY_NAME "sg_decode_sense"
-
-/* standard VPD pages, in ascending page number order */
-#define VPD_SUPPORTED_VPDS 0x0
-#define VPD_UNIT_SERIAL_NUM 0x80
-#define VPD_IMP_OP_DEF 0x81 /* obsolete in SPC-2 */
-#define VPD_ASCII_OP_DEF 0x82 /* obsolete in SPC-2 */
-#define VPD_DEVICE_ID 0x83
-#define VPD_SOFTW_INF_ID 0x84
-#define VPD_MAN_NET_ADDR 0x85
-#define VPD_EXT_INQ 0x86 /* Extended Inquiry */
-#define VPD_MODE_PG_POLICY 0x87
-#define VPD_SCSI_PORTS 0x88
-#define VPD_ATA_INFO 0x89
-#define VPD_POWER_CONDITION 0x8a
-#define VPD_DEVICE_CONSTITUENTS 0x8b
-#define VPD_CFA_PROFILE_INFO 0x8c
-#define VPD_POWER_CONSUMPTION 0x8d
-#define VPD_3PARTY_COPY 0x8f /* 3PC, XCOPY, SPC-4, SBC-3 */
-#define VPD_PROTO_LU 0x90
-#define VPD_PROTO_PORT 0x91
-#define VPD_SCSI_FEATURE_SETS 0x92 /* spc5r11 */
-#define VPD_BLOCK_LIMITS 0xb0 /* SBC-3 */
-#define VPD_SA_DEV_CAP 0xb0 /* SSC-3 */
-#define VPD_OSD_INFO 0xb0 /* OSD */
-#define VPD_BLOCK_DEV_CHARS 0xb1 /* SBC-3 */
-#define VPD_MAN_ASS_SN 0xb1 /* SSC-3, ADC-2 */
-#define VPD_SECURITY_TOKEN 0xb1 /* OSD */
-#define VPD_TA_SUPPORTED 0xb2 /* SSC-3 */
-#define VPD_LB_PROVISIONING 0xb2 /* SBC-3 */
-#define VPD_REFERRALS 0xb3 /* SBC-3 */
-#define VPD_AUTOMATION_DEV_SN 0xb3 /* SSC-3 */
-#define VPD_SUP_BLOCK_LENS 0xb4 /* sbc4r01 */
-#define VPD_DTDE_ADDRESS 0xb4 /* SSC-4 */
-#define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* sbc4r02 */
-#define VPD_LB_PROTECTION 0xb5 /* SSC-5 */
-#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
-#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
-#define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */
-#define VPD_CON_POS_RANGE 0xb9 /* sbc5r01 */
-#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
+static const char * version_str = "1.74 20220711"; /* spc6r06 + sbc5r01 */
+
+#define MY_NAME "sg_vpd"
/* Device identification VPD page associations */
#define VPD_ASSOC_LU 0
@@ -118,7 +78,6 @@ static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue,
static int filter_dev_ids(const char * print_if_found, int num_leading,
uint8_t * buff, int len, int m_assoc,
- int m_desig_type, int m_code_set,
struct opts_t * op, sgj_opaque_p jop);
static const int rsp_buff_sz = MX_ALLOC_LEN + 2;
@@ -450,20 +409,7 @@ static const char * sg_ansi_version_arr[16] =
"reserved [Fh]",
};
-static const char *
-pqual_str(int pqual)
-{
- switch (pqual) {
- case 0:
- return "LU accessible";
- case 1:
- return "LU temporarily unavailable";
- case 3:
- return "LU not accessible via this port";
- default:
- return "value reserved by T10";
- }
-}
+static const char * vpd_p_s = "VPD page";
static const char *
hot_pluggable_str(int hp)
@@ -569,49 +515,49 @@ skip1:
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_ane(jsp, jo2p, "rmb", !!(b[1] & 0x80), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "rmb", !!(b[1] & 0x80), false,
"Removable Medium Bit");
- sgj_add_nv_ihex_ane(jsp, jo2p, "lu_cong", !!(b[1] & 0x40), false,
+ 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_ane(jsp, jo2p, "aerc", !!(b[3] & 0x80), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "aerc", !!(b[3] & 0x80), false,
"Asynchronous Event Reporting Capability (obsolete "
"SPC-3)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "trmtsk", !!(b[3] & 0x40), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "trmtsk", !!(b[3] & 0x40), false,
"Terminate Task (obsolete SPC-2)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "normaca", !!(b[3] & 0x20), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "normaca", !!(b[3] & 0x20), false,
"Normal ACA (Auto Contingent Allegiance)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "hisup", !!(b[3] & 0x10), false,
+ 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_ane(jsp, jo2p, "sccs", !!(b[5] & 0x80), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "sccs", !!(b[5] & 0x80), false,
"SCC (SCSI Storage Commands) Supported");
- sgj_add_nv_ihex_ane(jsp, jo2p, "acc", !!(b[5] & 0x40), false,
+ 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_ane(jsp, jo2p, "tpgs", tpgs, false, NULL,
+ sgj_add_nv_ihexstr_nex(jsp, jo2p, "tpgs", tpgs, false, NULL,
tpgs_str(tpgs), "Target Port Group Support");
- sgj_add_nv_ihex_ane(jsp, jo2p, "3pc", !!(b[5] & 0x8), false,
+ 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_ane(jsp, jo2p, "bque", !!(b[6] & 0x80), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "bque", !!(b[6] & 0x80), false,
"Basic task management model (obsolete SPC-4)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "encserv", !!(b[6] & 0x40), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "encserv", !!(b[6] & 0x40), false,
"Enclousure Services supported");
- sgj_add_nv_ihex_ane(jsp, jo2p, "multip", !!(b[6] & 0x10), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "multip", !!(b[6] & 0x10), false,
"Multiple SCSI port");
- sgj_add_nv_ihex_ane(jsp, jo2p, "mchngr", !!(b[6] & 0x8), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "mchngr", !!(b[6] & 0x8), false,
"Medium changer (obsolete SPC-4)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "reladr", !!(b[7] & 0x80), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "reladr", !!(b[7] & 0x80), false,
"Relative Addressing (obsolete in SPC-4)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "linked", !!(b[7] & 0x8), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "linked", !!(b[7] & 0x8), false,
"Linked Commands (obsolete in SPC-4)");
- sgj_add_nv_ihex_ane(jsp, jo2p, "cmdque", !!(b[7] & 0x2), false,
+ sgj_add_nv_ihex_nex(jsp, jo2p, "cmdque", !!(b[7] & 0x2), false,
"Command Management Model (command queuing)");
if (len < 16)
return;
@@ -627,11 +573,12 @@ skip1:
sgj_add_nv_s(jsp, jo2p, "product_revision_level", c);
}
+/* VPD_DEVICE_ID 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
static void
device_id_vpd_variants(uint8_t * buff, int len, int subvalue,
struct opts_t * op, sgj_opaque_p jap)
{
- int m_a, m_d, m_cs, blen;
+ int m_a, blen;
uint8_t * b;
if (len < 4) {
@@ -641,155 +588,29 @@ device_id_vpd_variants(uint8_t * buff, int len, int subvalue,
blen = len - 4;
b = buff + 4;
m_a = -1;
- m_d = -1;
- m_cs = -1;
if (0 == subvalue) {
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
- VPD_ASSOC_LU, m_d, m_cs, op, jap);
+ VPD_ASSOC_LU, op, jap);
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b, blen,
- VPD_ASSOC_TPORT, m_d, m_cs, op, jap);
+ VPD_ASSOC_TPORT, op, jap);
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0, b, blen,
- VPD_ASSOC_TDEVICE, m_d, m_cs, op, jap);
+ VPD_ASSOC_TDEVICE, op, jap);
} else if (VPD_DI_SEL_AS_IS == subvalue)
- filter_dev_ids(NULL, 0, b, blen, m_a, m_d, m_cs, op, jap);
+ filter_dev_ids(NULL, 0, b, blen, m_a, op, jap);
else {
if (VPD_DI_SEL_LU & subvalue)
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen,
- VPD_ASSOC_LU, m_d, m_cs, op, jap);
+ VPD_ASSOC_LU, op, jap);
if (VPD_DI_SEL_TPORT & subvalue)
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b,
- blen, VPD_ASSOC_TPORT, m_d, m_cs, op, jap);
+ blen, VPD_ASSOC_TPORT, op, jap);
if (VPD_DI_SEL_TARGET & subvalue)
filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0,
- b, blen, VPD_ASSOC_TDEVICE, m_d, m_cs, op, jap);
+ b, blen, VPD_ASSOC_TDEVICE, op, jap);
}
}
-static const char * network_service_type_arr[] =
-{
- "unspecified",
- "storage configuration service",
- "diagnostics",
- "status",
- "logging",
- "code download",
- "copy service",
- "administrative configuration service",
- "reserved[0x8]", "reserved[0x9]",
- "reserved[0xa]", "reserved[0xb]", "reserved[0xc]", "reserved[0xd]",
- "reserved[0xe]", "reserved[0xf]", "reserved[0x10]", "reserved[0x11]",
- "reserved[0x12]", "reserved[0x13]", "reserved[0x14]", "reserved[0x15]",
- "reserved[0x16]", "reserved[0x17]", "reserved[0x18]", "reserved[0x19]",
- "reserved[0x1a]", "reserved[0x1b]", "reserved[0x1c]", "reserved[0x1d]",
- "reserved[0x1e]", "reserved[0x1f]",
-};
-
-/* VPD_MAN_NET_ADDR */
-static void
-decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap)
-{
- int k, bump, na_len, assoc, nst;
- sgj_state * jsp = &op->json_st;
- sgj_opaque_p jo2p;
- uint8_t * bp;
- const char * assoc_str;
- const char * nst_str;
-
- if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
- return;
- }
- if (len < 4) {
- pr2serr("Management network addresses VPD page length too short=%d\n",
- len);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0; k < len; k += bump, bp += bump) {
- assoc = (bp[0] >> 5) & 0x3;
- assoc_str = sg_get_desig_assoc_str(assoc);
- nst = bp[0] & 0x1f;
- nst_str = network_service_type_arr[nst];
- sgj_pr_hr(jsp, " %s, Service type: %s\n", assoc_str, nst_str);
- na_len = sg_get_unaligned_be16(bp + 2);
- if (jsp->pr_as_json) {
- jo2p = sgj_new_unattached_object(jsp);
- sgj_add_nv_ihexstr(jsp, jo2p, "association", assoc, NULL,
- assoc_str);
- sgj_add_nv_ihexstr(jsp, jo2p, "service_type", nst, NULL,
- nst_str);
- sgj_add_nv_s_len(jsp, jo2p, "network_address",
- (const char *)(bp + 4), na_len);
- sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
- }
- if (na_len > 0) {
- if (op->do_hex > 1) {
- printf(" Network address:\n");
- hex2stdout((bp + 4), na_len, 0);
- } else
- sgj_pr_hr(jsp, " %s\n", bp + 4);
- }
- bump = 4 + na_len;
- if ((k + bump) > len) {
- pr2serr("Management network addresses VPD page, short "
- "descriptor length=%d, left=%d\n", bump, (len - k));
- return;
- }
- }
-}
-
-static const char * mode_page_policy_arr[] =
-{
- "shared",
- "per target port",
- "per initiator port",
- "per I_T nexus",
-};
-
-/* VPD_MODE_PG_POLICY */
-static void
-decode_mode_policy_vpd(uint8_t * buff, int len, int do_hex)
-{
- int k, bump;
- uint8_t * bp;
-
- if ((1 == do_hex) || (do_hex > 2)) {
- hex2stdout(buff, len, (1 == do_hex) ? 1 : -1);
- return;
- }
- if (len < 4) {
- pr2serr("Mode page policy VPD page length too short=%d\n", len);
- return;
- }
- len -= 4;
- bp = buff + 4;
- for (k = 0; k < len; k += bump, bp += bump) {
- bump = 4;
- if ((k + bump) > len) {
- pr2serr("Mode page policy VPD page, short "
- "descriptor length=%d, left=%d\n", bump, (len - k));
- return;
- }
- if (do_hex > 1)
- hex2stdout(bp, 4, 1);
- else {
- printf(" Policy page code: 0x%x", (bp[0] & 0x3f));
- if (bp[1])
- printf(", subpage code: 0x%x\n", bp[1]);
- else
- printf("\n");
- if ((0 == k) && (0x3f == (0x3f & bp[0])) && (0xff == bp[1]))
- printf(" therefore the policy applies to all modes pages "
- "and subpages\n");
- printf(" MLUS=%d, Policy: %s\n", !!(bp[2] & 0x80),
- mode_page_policy_arr[bp[2] & 0x3]);
- }
- }
-}
-
-/* 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)
@@ -829,6 +650,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);
sgj_pr_hr(jsp, "%s",
sg_decode_transportid_str(" ", bp + 8,
ip_tid_len, true, sizeof(b), b));
@@ -855,7 +680,7 @@ decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
"designation_descriptor_list");
}
filter_dev_ids("", 2 /* leading spaces */, bp + bump + 4,
- tpd_len, VPD_ASSOC_TPORT, -1, -1, op, ja2p);
+ tpd_len, VPD_ASSOC_TPORT, op, ja2p);
}
}
bump += tpd_len + 4;
@@ -864,10 +689,10 @@ decode_scsi_ports_vpd(uint8_t * buff, int len, struct opts_t * op,
}
/* Prints outs an abridged set of device identification designators
- selected by association, designator type and/or code set. */
+ selected by association, designator type and/or code set. Not used
+ for JSON output. */
static int
-filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc,
- int m_desig_type, int m_code_set)
+filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc)
{
int k, m, p_id, c_set, piv, desig_type, i_len, naa, off, u;
int assoc, is_sas, rtp;
@@ -889,8 +714,7 @@ filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc,
desig_type = 3;
i_len = 16;
} else {
- u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type,
- m_code_set);
+ u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1);
if (0 != u)
break;
bp = buff + off;
@@ -1061,11 +885,10 @@ filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc,
}
/* Prints outs designation descriptors (dd_s) selected by association,
- designator type and/or code set. */
+ designator type and/or code set. VPD_DEVICE_ID and VPD_SCSI_PORTS */
static int
filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
- int len, int m_assoc, int m_desig_type, int m_code_set,
- struct opts_t * op, sgj_opaque_p jap)
+ int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap)
{
bool printed, sgj_out_hr;
int assoc, off, u, i_len;
@@ -1076,8 +899,15 @@ filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
static const int blen = sizeof(b);
if (op->do_quiet && (! jsp->pr_as_json))
- return filter_dev_ids_quiet(buff, len, m_assoc, m_desig_type,
- m_code_set);
+ return filter_dev_ids_quiet(buff, len, m_assoc);
+ sgj_out_hr = false;
+ if (jsp->pr_as_json) {
+ int ret = filter_json_dev_ids(buff, len, m_assoc, op, jap);
+
+ if (ret || (! jsp->pr_out_hr))
+ return ret;
+ sgj_out_hr = true;
+ }
if (num_leading > (int)(sizeof(sp) - 2))
num_leading = sizeof(sp) - 2;
if (num_leading > 0)
@@ -1093,8 +923,7 @@ filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
}
off = -1;
printed = false;
- while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type,
- m_code_set)) == 0) {
+ while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1)) == 0) {
bp = buff + off;
i_len = bp[3];
if ((off + i_len + 4) > len) {
@@ -1102,18 +931,6 @@ filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
" remaining response length=%d\n", (len - off));
return SG_LIB_CAT_MALFORMED;
}
- sgj_out_hr = false;
- if (jsp->pr_as_json) {
- sgj_opaque_p jo2p;
-
- jo2p = sgj_new_unattached_object(jsp);
- sgj_get_designation_descriptor(jsp, jo2p, bp, i_len + 4);
- sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
- if (jsp->pr_out_hr)
- sgj_out_hr = true;
- else
- continue;
- }
assoc = ((bp[1] >> 4) & 0x3);
if (print_if_found && (! printed)) {
printed = true;
@@ -1146,210 +963,53 @@ filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff,
return 0;
}
-/* VPD_EXT_INQ Extended Inquiry VPD */
+/* VPD_ATA_INFO 0x89 ['ai"] */
static void
-decode_x_inq_vpd(uint8_t * b, int len, int do_hex, bool do_long,
- bool protect)
-{
- int n;
-
- if (len < 7) {
- pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex) {
- hex2stdout(b, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- if (do_long) {
- n = (b[4] >> 6) & 0x3;
- printf(" ACTIVATE_MICROCODE=%d", n);
- if (1 == n)
- printf(" [before final WRITE BUFFER]\n");
- else if (2 == n)
- printf(" [after power on or hard reset]\n");
- else
- printf("\n");
- n = (b[4] >> 3) & 0x7;
- printf(" SPT=%d", n);
- if (protect) {
- switch (n)
- {
- case 0:
- printf(" [protection type 1 supported]\n");
- break;
- case 1:
- printf(" [protection types 1 and 2 supported]\n");
- break;
- case 2:
- printf(" [protection type 2 supported]\n");
- break;
- case 3:
- printf(" [protection types 1 and 3 supported]\n");
- break;
- case 4:
- printf(" [protection type 3 supported]\n");
- break;
- case 5:
- printf(" [protection types 2 and 3 supported]\n");
- break;
- case 6:
- printf(" [see Supported block lengths and protection types "
- "VPD page]\n");
- break;
- case 7:
- printf(" [protection types 1, 2 and 3 supported]\n");
- break;
- }
- } else
- printf("\n");
- printf(" GRD_CHK=%d\n", !!(b[4] & 0x4));
- printf(" APP_CHK=%d\n", !!(b[4] & 0x2));
- printf(" REF_CHK=%d\n", !!(b[4] & 0x1));
- printf(" UASK_SUP=%d\n", !!(b[5] & 0x20));
- printf(" GROUP_SUP=%d\n", !!(b[5] & 0x10));
- printf(" PRIOR_SUP=%d\n", !!(b[5] & 0x8));
- printf(" HEADSUP=%d\n", !!(b[5] & 0x4));
- printf(" ORDSUP=%d\n", !!(b[5] & 0x2));
- printf(" SIMPSUP=%d\n", !!(b[5] & 0x1));
- printf(" WU_SUP=%d\n", !!(b[6] & 0x8));
- printf(" CRD_SUP=%d\n", !!(b[6] & 0x4));
- printf(" NV_SUP=%d\n", !!(b[6] & 0x2));
- printf(" V_SUP=%d\n", !!(b[6] & 0x1));
- printf(" NO_PI_CHK=%d\n", !!(b[7] & 0x10)); /* spc5r02 */
- printf(" P_I_I_SUP=%d\n", !!(b[7] & 0x10));
- printf(" LUICLR=%d\n", !!(b[7] & 0x1));
- printf(" LU_COLL_TYPE=%d\n", (b[8] >> 5) & 0x7); /* spc5r09 */
- printf(" R_SUP=%d\n", !!(b[8] & 0x10));
- printf(" RTD_SUP=%d\n", !!(b[8] & 0x8)); /* spc5r11 */
- printf(" HSSRELEF=%d\n", !!(b[8] & 0x2)); /* spc5r02 */
- printf(" CBCS=%d\n", !!(b[8] & 0x1)); /* obsolete in spc5r01 */
- printf(" Multi I_T nexus microcode download=%d\n", b[9] & 0xf);
- printf(" Extended self-test completion minutes=%d\n",
- sg_get_unaligned_be16(b + 10));
- printf(" POA_SUP=%d\n", !!(b[12] & 0x80)); /* spc4r32 */
- printf(" HRA_SUP=%d\n", !!(b[12] & 0x40)); /* spc4r32 */
- printf(" VSA_SUP=%d\n", !!(b[12] & 0x20)); /* spc4r32 */
- printf(" DMS_VALID=%d\n", !!(b[12] & 0x10)); /* spc5r20 */
- printf(" Maximum supported sense data length=%d\n",
- b[13]); /* spc4r34 */
- printf(" IBS=%d\n", !!(b[14] & 0x80)); /* spc5r09 */
- printf(" IAS=%d\n", !!(b[14] & 0x40)); /* spc5r09 */
- printf(" SAC=%d\n", !!(b[14] & 0x4)); /* spc5r09 */
- printf(" NRD1=%d\n", !!(b[14] & 0x2)); /* spc5r09 */
- printf(" NRD0=%d\n", !!(b[14] & 0x1)); /* spc5r09 */
- printf(" Maximum inquiry change logs=%u\n",
- sg_get_unaligned_be16(b + 15)); /* spc5r17 */
- printf(" Maximum mode page change logs=%u\n",
- sg_get_unaligned_be16(b + 17)); /* spc5r17 */
- printf(" DM_MD_4=%d\n", !!(b[19] & 0x80)); /* spc5r20 */
- printf(" DM_MD_5=%d\n", !!(b[19] & 0x40)); /* spc5r20 */
- printf(" DM_MD_6=%d\n", !!(b[19] & 0x20)); /* spc5r20 */
- printf(" DM_MD_7=%d\n", !!(b[19] & 0x10)); /* spc5r20 */
- printf(" DM_MD_D=%d\n", !!(b[19] & 0x8)); /* spc5r20 */
- printf(" DM_MD_E=%d\n", !!(b[19] & 0x4)); /* spc5r20 */
- printf(" DM_MD_F=%d\n", !!(b[19] & 0x2)); /* spc5r20 */
- return;
- }
- printf(" ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d "
- "REF_CHK=%d\n", ((b[4] >> 6) & 0x3), ((b[4] >> 3) & 0x7),
- !!(b[4] & 0x4), !!(b[4] & 0x2), !!(b[4] & 0x1));
- printf(" UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d "
- "SIMPSUP=%d\n", !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8),
- !!(b[5] & 0x4), !!(b[5] & 0x2), !!(b[5] & 0x1));
- printf(" WU_SUP=%d [CRD_SUP=%d] NV_SUP=%d V_SUP=%d\n",
- !!(b[6] & 0x8), !!(b[6] & 0x4), !!(b[6] & 0x2), !!(b[6] & 0x1));
- printf(" NO_PI_CHK=%d P_I_I_SUP=%d LUICLR=%d\n", !!(b[7] & 0x20),
- !!(b[7] & 0x10), !!(b[7] & 0x1));
- /* RTD_SUP added in spc5r11, LU_COLL_TYPE added in spc5r09,
- * HSSRELEF added in spc5r02; CBCS obsolete in spc5r01 */
- printf(" LU_COLL_TYPE=%d R_SUP=%d RTD_SUP=%d HSSRELEF=%d [CBCS=%d]\n",
- (b[8] >> 5) & 0x7, !!(b[8] & 0x10), !!(b[8] & 0x8),
- !!(b[8] & 0x2), !!(b[8] & 0x1));
- printf(" Multi I_T nexus microcode download=%d\n", b[9] & 0xf);
- printf(" Extended self-test completion minutes=%d\n",
- sg_get_unaligned_be16(b + 10)); /* spc4r27 */
- printf(" POA_SUP=%d HRA_SUP=%d VSA_SUP=%d DMS_VALID=%d\n",
- !!(b[12] & 0x80), !!(b[12] & 0x40), !!(b[12] & 0x20),
- !!(b[12] & 0x10)); /* spc5r20 */
- printf(" Maximum supported sense data length=%d\n", b[13]); /* spc4r34 */
- printf(" IBS=%d IAS=%d SAC=%d NRD1=%d NRD0=%d\n", !!(b[14] & 0x80),
- !!(b[14] & 0x40), !!(b[14] & 0x4), !!(b[14] & 0x2),
- !!(b[14] & 0x1)); /* added in spc5r09 */
- printf(" Maximum inquiry change logs=%u\n",
- sg_get_unaligned_be16(b + 15)); /* spc5r17 */
- printf(" Maximum mode page change logs=%u\n",
- sg_get_unaligned_be16(b + 17)); /* spc5r17 */
- printf(" DM_MD_4=%d DM_MD_5=%d DM_MD_6=%d DM_MD_7=%d\n",
- !!(b[19] & 0x80), !!(b[19] & 0x40), !!(b[19] & 0x20),
- !!(b[19] & 0x10)); /* spc5r20 */
- printf(" DM_MD_D=%d DM_MD_E=%d DM_MD_F=%d\n",
- !!(b[19] & 0x8), !!(b[19] & 0x4), !!(b[19] & 0x2));
-}
-
-/* VPD_SOFTW_INF_ID */
-static void
-decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap)
+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;
- sgj_opaque_p jop;
- uint64_t ieee_id;
-
- if (op->do_hex) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
- return;
- }
- len -= 4;
- buff += 4;
- for ( ; len > 5; len -= 6, buff += 6) {
- ieee_id = sg_get_unaligned_be48(buff + 0);
- sgj_pr_hr(jsp, " IEEE identifier: 0x%" PRIx64 "\n", ieee_id);
- if (jsp->pr_as_json) {
- jop = sgj_new_unattached_object(jsp);
- sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ieee_id);
- sgj_add_nv_o(jsp, jap, NULL /* name */, jop);
- }
- }
-}
-
-/* VPD_ATA_INFO */
-static void
-decode_ata_info_vpd(uint8_t * buff, int len, int do_long, int do_hex)
-{
- char b[80];
- int num, is_be, cc;
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 (do_hex && (2 != do_hex)) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ 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';
- printf(" SAT Vendor identification: %s\n", b);
+ sgj_pr_hr(jsp, " %s: %s\n", sat_vip, b);
memcpy(b, buff + 16, 16);
b[16] = '\0';
- printf(" SAT Product identification: %s\n", b);
+ sgj_pr_hr(jsp, " %s: %s\n", sat_pip, b);
memcpy(b, buff + 32, 4);
b[4] = '\0';
- printf(" SAT Product revision level: %s\n", b);
+ sgj_pr_hr(jsp, " %s: %s\n", sat_prlp, b);
if (len < 56)
return;
ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA";
- if (do_long) {
- printf(" Device signature [%s] (in hex):\n", ata_transp);
+ if (do_long_nq) {
+ sgj_pr_hr(jsp, " Device signature [%s] (in hex):\n", ata_transp);
hex2stdout(buff + 36, 20, 0);
} else
- printf(" Device signature indicates %s transport\n", ata_transp);
+ 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) */
- printf(" Command code: 0x%x\n", cc);
+ n = snprintf(b, blen, " Command code: 0x%x\n", cc);
if (len < 60)
return;
if (0xec == cc)
@@ -1360,62 +1020,47 @@ decode_ata_info_vpd(uint8_t * buff, int len, int do_long, int do_hex)
cp = NULL;
is_be = sg_is_big_endian();
if (cp) {
- printf(" ATA command IDENTIFY %sDEVICE response summary:\n", 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, b);
- b[num] = '\0';
- printf(" model: %s\n", b);
+ 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, b);
- b[num] = '\0';
- printf(" serial number: %s\n", b);
+ 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, b);
- b[num] = '\0';
- printf(" firmware revision: %s\n", b);
- if (do_long)
- printf(" ATA command IDENTIFY %sDEVICE response in hex:\n", cp);
- } else if (do_long)
- printf(" ATA command 0x%x got following response:\n",
- (unsigned int)cc);
+ 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 == do_hex)
+ if (2 == op->do_hex)
hex2stdout((buff + 60), 512, 0);
- else if (do_long)
+ else if (do_long_nq)
dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be);
}
-
-/* VPD_POWER_CONDITION 0x8a */
-static void
-decode_power_condition(uint8_t * buff, int len, int do_hex)
-{
- if (len < 18) {
- pr2serr("Power condition VPD page length too short=%d\n", len);
- return;
- }
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- printf(" Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d Idle_a=%d\n",
- !!(buff[4] & 0x2), !!(buff[4] & 0x1),
- !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1));
- printf(" Stopped condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 6));
- printf(" Standby_z condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 8));
- printf(" Standby_y condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 10));
- printf(" Idle_a condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 12));
- printf(" Idle_b condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 14));
- printf(" Idle_c condition recovery time (ms) %d\n",
- sg_get_unaligned_be16(buff + 16));
-}
-
static const char * constituent_type_arr[] = {
"Reserved",
"Virtual tape library",
@@ -3076,14 +2721,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_SUPPORTED_VPDS: /* 0x0 */
- np = "Supported VPD pages VPD page:";
+ case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */
+ np = "Supported VPD pages";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -3096,12 +2741,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (num > (len - 4))
num = (len - 4);
if (as_json) {
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_new_named_array(jsp, jo2p,
"supported_vpd_page_list");
}
@@ -3147,14 +2787,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_UNIT_SERIAL_NUM: /* 0x80 */
- np = "Unit serial number VPD page:";
+ case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */
+ np = "Unit serial number";
if (allow_name && not_json)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s VPD page:\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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -3168,26 +2808,21 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (len >= (int)sizeof(obuff))
len = sizeof(obuff) - 1;
memcpy(obuff, rp + 4, len);
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
- sgj_pr_hr_js_vs(jsp, jo2p, 2, "unit_serial_number",
- SGJ_SEP_COLON_1_SPACE, obuff);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ sgj_pr_hr_js_vs(jsp, jo2p, 2, np, SGJ_SEP_COLON_1_SPACE,
+ obuff);
}
return 0;
}
break;
- case VPD_DEVICE_ID: /* 0x83 */
- np = "Device Identification VPD page:";
+ case VPD_DEVICE_ID: /* 0x83 ["di, di_asis, di_lu, di_port, di_target"] */
+ np = "Device Identification";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -3197,12 +2832,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
if (as_json) {
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_new_named_array(jsp, jo2p,
"designation_descriptor_list");
}
@@ -3211,14 +2841,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_SOFTW_INF_ID: /* 0x84 */
- np = "Software interface identification VPD page:";
+ case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
+ np = "Software interface identification";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3226,12 +2856,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
if (as_json) {
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_new_named_array(jsp, jo2p,
"software_interface_identifier_list");
}
@@ -3240,24 +2865,19 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_MAN_NET_ADDR: /* 0x85 */
- np= "Management network addresses VPD page:";
+ case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */
+ np= "Management network addresses";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else {
if (as_json) {
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_new_named_array(jsp, jo2p,
"network_services_descriptor_list");
}
@@ -3266,14 +2886,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
- case VPD_EXT_INQ: /* 0x86 */
- np = "extended INQUIRY data VPD page:";
+ case VPD_EXT_INQ: /* 0x86 ["ei"] */
+ np = "extended INQUIRY data";
if (allow_name)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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 %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3290,40 +2910,48 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
}
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_x_inq_vpd(rp, len, op->do_hex, long_notquiet, protect);
+ 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_x_inq_vpd(rp, len, protect, op, jo2p);
}
return 0;
}
break;
case VPD_MODE_PG_POLICY: /* 0x87 */
- np = "Mode page policy VPD page:";
+ np = "Mode page policy";
if (allow_name)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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", (prefix ? prefix : ""), np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", (prefix ? prefix : ""), np,
+ vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_mode_policy_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_new_named_array(jsp, jo2p,
+ "mode_page_policy_descriptor_list");
+ }
+ decode_mode_policy_vpd(rp, len, op, jap);
}
return 0;
}
break;
- case VPD_SCSI_PORTS: /* 0x88 */
- np = "SCSI Ports VPD page:";
+ case VPD_SCSI_PORTS: /* 0x88 ["sp"] */
+ np = "SCSI Ports";
if (allow_name)
- sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3331,29 +2959,25 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
if (as_json) {
- 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, pdt_str);
- sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_new_named_array(jsp, jo2p,
- "scsi_port_descriptor_list");
+ "scsi_ports_descriptor_list");
}
decode_scsi_ports_vpd(rp, len, op, jap);
}
return 0;
}
break;
- case VPD_ATA_INFO: /* 0x89 */
- np = "ATA information VPD page:";
+ case VPD_ATA_INFO: /* 0x89 ['ai"] */
+ np = "ATA information";
if (allow_name)
- printf("%s%s\n", pre, np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, vpd_p_s);
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)
- printf("%s%s\n", (prefix ? prefix : ""), np);
+ sgj_pr_hr(jsp, "%s%s %s:\n", (prefix ? prefix : ""), np,
+ vpd_p_s);
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 "
@@ -3366,28 +2990,30 @@ 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_ata_info_vpd(rp, len, long_notquiet, 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);
+ decode_ata_info_vpd(rp, len, op, jo2p);
}
return 0;
}
break;
- case VPD_POWER_CONDITION: /* 0x8a */
+ case VPD_POWER_CONDITION: /* 0x8a ["pc"\ */
np = "Power condition 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 {
if (vb || long_notquiet)
- printf(" [PQual=%d Peripheral device type: %s]\n",
- pqual, pdt_str);
- decode_power_condition(rp, len, op->do_hex);
+ sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
+ "%s]\n", pqual, pdt_str);
+ decode_power_condition(rp, len, op, jop);
}
return 0;
}
@@ -3996,6 +3622,7 @@ main(int argc, char * argv[])
struct opts_t opts = {0};
struct opts_t * op = &opts;
+ op->invoker = SG_VPD_INV_SG_VPD;
dup_sanity_chk((int)sizeof(opts), (int)sizeof(*vnp));
op->vend_prod_num = -1;
while (1) {
@@ -4189,8 +3816,8 @@ main(int argc, char * argv[])
return 0;
}
- as_json = op->json_st.pr_as_json;
jsp = &op->json_st;
+ as_json = jsp->pr_as_json;
if (as_json)
jop = sgj_start(MY_NAME, version_str, argc, argv, jsp);
diff --git a/src/sg_vpd.h b/src/sg_vpd.h
deleted file mode 100644
index f01ef122..00000000
--- a/src/sg_vpd.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef SG_VPD_H
-#define SG_VPD_H
-
-/*
- * Copyright (c) 2022 Douglas Gilbert.
- * All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the BSD_LICENSE file.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sg_lib.h"
-#include "sg_pr2serr.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These two structures are duplicates of those of the same name in
- * sg_vpd_vendor.c . <<< Take care that both are the same. >>> */
-struct opts_t {
- bool do_all;
- bool do_enum;
- bool do_force;
- bool do_long;
- bool do_quiet;
- bool page_given;
- bool verbose_given;
- bool version_given;
- int do_hex;
- int do_ident;
- int do_raw;
- int examine;
- int maxlen;
- int vend_prod_num;
- int verbose;
- int vpd_pn;
- const char * device_name;
- const char * page_str;
- const char * inhex_fn;
- const char * vend_prod;
- sgj_state json_st;
-};
-
-struct svpd_values_name_t {
- int value; /* VPD page number */
- int subvalue; /* to differentiate if value+pdt are not unique */
- int pdt; /* peripheral device type id, -1 is the default */
- /* (all or not applicable) value */
- const char * acron;
- const char * name;
-};
-
-void svpd_enumerate_vendor(int vend_prod_num);
-int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num);
-int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
-const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
-int svpd_find_vp_num_by_acron(const char * vp_ap);
-const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
- int vend_prod_num);
-int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
- bool qt, int vb, int * rlenp);
-void dup_sanity_chk(int sz_opts_t, int sz_values_name_t);
-
-extern uint8_t * rsp_buff;
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* end of SG_VPD_H */
diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c
new file mode 100644
index 00000000..49d18670
--- /dev/null
+++ b/src/sg_vpd_common.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2006-2022 Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
+
+#include "sg_vpd_common.h"
+
+/* This file holds common code for sg_inq and sg_vpd as both those utilities
+ * decode SCSI VPD pages. */
+
+sgj_opaque_p
+sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const uint8_t * vpd_hdrp)
+{
+ int pdt = vpd_hdrp[0] & PDT_MASK;
+ int pqual = (vpd_hdrp[0] & 0xe0) >> 5;
+ int pn = vpd_hdrp[1];
+ const char * pdt_str;
+ sgj_opaque_p jo2p = sgj_new_snake_named_object(jsp, jop, name);
+ char d[64];
+
+ pdt_str = sg_get_pdt_str(pdt, sizeof(d), d);
+ sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_qualifier",
+ pqual, NULL, pqual_str(pqual));
+ sgj_add_nv_ihexstr(jsp, jo2p, "peripheral_device_type",
+ pdt, NULL, pdt_str);
+ sgj_add_nv_ihex(jsp, jo2p, "page_code", pn);
+ return jo2p;
+}
+
+const char *
+pqual_str(int pqual)
+{
+ switch (pqual) {
+ case 0:
+ return "LU accessible";
+ case 1:
+ return "LU temporarily unavailable";
+ case 3:
+ return "LU not accessible via this port";
+ default:
+ return "value reserved by T10";
+ }
+}
+
+static const char * network_service_type_arr[] =
+{
+ "unspecified",
+ "storage configuration service",
+ "diagnostics",
+ "status",
+ "logging",
+ "code download",
+ "copy service",
+ "administrative configuration service",
+ "reserved[0x8]", "reserved[0x9]",
+ "reserved[0xa]", "reserved[0xb]", "reserved[0xc]", "reserved[0xd]",
+ "reserved[0xe]", "reserved[0xf]", "reserved[0x10]", "reserved[0x11]",
+ "reserved[0x12]", "reserved[0x13]", "reserved[0x14]", "reserved[0x15]",
+ "reserved[0x16]", "reserved[0x17]", "reserved[0x18]", "reserved[0x19]",
+ "reserved[0x1a]", "reserved[0x1b]", "reserved[0x1c]", "reserved[0x1d]",
+ "reserved[0x1e]", "reserved[0x1f]",
+};
+
+/* VPD_MAN_NET_ADDR 0x85 ["mna"] */
+void
+decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k, bump, na_len, assoc, nst;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
+ uint8_t * bp;
+ const char * assoc_str;
+ const char * nst_str;
+
+ if ((1 == op->do_hex) || (op->do_hex > 2)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("Management network addresses VPD page length too short=%d\n",
+ len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0; k < len; k += bump, bp += bump) {
+ assoc = (bp[0] >> 5) & 0x3;
+ assoc_str = sg_get_desig_assoc_str(assoc);
+ nst = bp[0] & 0x1f;
+ nst_str = network_service_type_arr[nst];
+ sgj_pr_hr(jsp, " %s, Service type: %s\n", assoc_str, nst_str);
+ na_len = sg_get_unaligned_be16(bp + 2);
+ if (jsp->pr_as_json) {
+ jo2p = sgj_new_unattached_object(jsp);
+ sgj_add_nv_ihexstr(jsp, jo2p, "association", assoc, NULL,
+ assoc_str);
+ sgj_add_nv_ihexstr(jsp, jo2p, "service_type", nst, NULL,
+ nst_str);
+ sgj_add_nv_s_len(jsp, jo2p, "network_address",
+ (const char *)(bp + 4), na_len);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ if (na_len > 0) {
+ if (op->do_hex > 1) {
+ sgj_pr_hr(jsp, " Network address:\n");
+ hex2stdout((bp + 4), na_len, 0);
+ } else
+ sgj_pr_hr(jsp, " %s\n", bp + 4);
+ }
+ bump = 4 + na_len;
+ if ((k + bump) > len) {
+ pr2serr("Management network addresses VPD page, short "
+ "descriptor length=%d, left=%d\n", bump, (len - k));
+ return;
+ }
+ }
+}
+
+/* VPD_EXT_INQ Extended Inquiry VPD ["ei"] */
+void
+decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ bool do_long_nq = op->do_long && (! op->do_quiet);
+ int n;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
+ const char * cp;
+ const char * np;
+ const char * nex_p;
+ char d[128];
+ static const int dlen = sizeof(d);
+
+ if (len < 7) {
+ pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len);
+ return;
+ }
+ if (op->do_hex) {
+ hex2stdout(b, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (do_long_nq || jsp->pr_as_json) {
+ n = (b[4] >> 6) & 0x3;
+ if (1 == n)
+ cp = "before final WRITE BUFFER";
+ else if (2 == n)
+ cp = "after power on or hard reset";
+ else {
+ cp = "none";
+ d[0] = '\0';
+ }
+ if (cp[0])
+ snprintf(d, dlen, " [%s]", cp);
+ sgj_pr_hr(jsp, " ACTIVATE_MICROCODE=%d%s\n", n, d);
+ sgj_add_nv_ihexstr(jsp, jop, "activate_microcode", n, NULL, cp);
+ n = (b[4] >> 3) & 0x7;
+ if (protect) {
+ switch (n)
+ {
+ case 0:
+ cp = "protection type 1 supported";
+ break;
+ case 1:
+ cp = "protection types 1 and 2 supported";
+ break;
+ case 2:
+ cp = "protection type 2 supported";
+ break;
+ case 3:
+ cp = "protection types 1 and 3 supported";
+ break;
+ case 4:
+ cp = "protection type 3 supported";
+ break;
+ case 5:
+ cp = "protection types 2 and 3 supported";
+ break;
+ case 6:
+ cp = "see Supported block lengths and protection types "
+ "VPD page";
+ break;
+ case 7:
+ cp = "protection types 1, 2 and 3 supported";
+ break;
+ }
+ } else {
+ cp = "none";
+ d[0] = '\0';
+ }
+ if (cp[0])
+ snprintf(d, dlen, " [%s]", cp);
+ sgj_pr_hr(jsp, " SPT=%d%s\n", n, d);
+ sgj_add_nv_ihexstr_nex(jsp, jop, "spt", n, false, NULL,
+ cp, "Supported Protection Type");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "GRD_CHK", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[4] & 0x4), "guard check");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "APP_CHK", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[4] & 0x2), "application tag check");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "REF_CHK", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[4] & 0x1), "reference tag check");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "UASK_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x20), "Unit Attention condition Sense "
+ "Key specific data Supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "GROUP_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x10), "grouping function supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "PRIOR_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x8), "priority supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "HEADSUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x4), "head of queue supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "ORDSUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x2), "ordered (task attribute) "
+ "supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "SIMPSUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[5] & 0x1), "simple (task attribute) "
+ "supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "WU_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[6] & 0x8), "Write uncorrectable supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "CRD_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[6] & 0x4), "Correction disable supported "
+ "(obsolete SPC-5)");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "NV_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[6] & 0x2), "Nonvolatile cache supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "V_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[6] & 0x1), "Volatile cache supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "NO_PI_CHK", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[7] & 0x20), "No protection information "
+ "checking"); /* spc5r02 */
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "P_I_I_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[7] & 0x10), "Protection information "
+ "interval supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "LUICLR", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[7] & 0x1), "Logical unit I_T nexus clear");
+ np = "LU_COLL_TYPE";
+ n = (b[8] >> 5) & 0x7;
+ nex_p = "Logical unit collection type";
+ if (jsp && (jsp->pr_string)) {
+ switch (n) {
+ case 0:
+ cp = "not reported";
+ break;
+ case 1:
+ cp = "Conglomerate";
+ break;
+ case 2:
+ cp = "Logical unit group";
+ break;
+ default:
+ cp = "reserved";
+ break;
+ }
+ jo2p = sgj_pr_hr_js_subo(jsp, jop, 2, np, SGJ_SEP_EQUAL_NO_SPACE,
+ n);
+ sgj_add_nv_s(jsp, jo2p, "meaning", cp);
+ if (jsp->pr_name_ex)
+ sgj_add_nv_s(jsp, jo2p, "abbreviated_name_expansion", nex_p);
+ } else
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, np, SGJ_SEP_EQUAL_NO_SPACE, n,
+ nex_p);
+
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "R_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[8] & 0x10), "Referrals supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "RTD_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[8] & 0x8), "Revert to defaults supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "HSSRELEF", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[8] & 0x2),
+ "History snapshots release effects");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "CBCS", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[8] & 0x1), "Capability-based command "
+ "security (obsolete SPC-5)");
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Multi I_T nexus microcode download",
+ SGJ_SEP_EQUAL_NO_SPACE, b[9] & 0xf);
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Extended self-test completion minutes",
+ SGJ_SEP_EQUAL_NO_SPACE,
+ sg_get_unaligned_be16(b + 10));
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "POA_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[12] & 0x80),
+ "Power on activation supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "HRA_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[12] & 0x40),
+ "Hard reset activation supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "VSA_SUP", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[12] & 0x20),
+ "Vendor specific activation supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DMS_VALID", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[12] & 0x10),
+ "Download microcode support byte valid");
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Maximum supported sense data length",
+ SGJ_SEP_EQUAL_NO_SPACE, b[13]);
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "IBS", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[14] & 0x80), "Implicit bind supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "IAS", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[14] & 0x40),
+ "Implicit affiliation supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "SAC", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[14] & 0x4),
+ "Set affiliation command supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "NRD1", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[14] & 0x2),
+ "No redirect one supported (BIND)");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "NRD0", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[14] & 0x1),
+ "No redirect zero supported (BIND)");
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Maximum inquiry change logs",
+ SGJ_SEP_EQUAL_NO_SPACE,
+ sg_get_unaligned_be16(b + 15));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Maximum mode page change logs",
+ SGJ_SEP_EQUAL_NO_SPACE,
+ sg_get_unaligned_be16(b + 17));
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_4", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x80),
+ "Download microcode mode 4 supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_5", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x40),
+ "Download microcode mode 5 supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_6", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x20),
+ "Download microcode mode 6 supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_7", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x10),
+ "Download microcode mode 7 supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_D", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x8),
+ "Download microcode mode 0xd supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_E", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x4),
+ "Download microcode mode 0xe supported");
+ sgj_pr_hr_js_vi_nex(jsp, jop, 2, "DM_MD_F", SGJ_SEP_EQUAL_NO_SPACE,
+ !!(b[19] & 0x2),
+ "Download microcode mode 0xf supported");
+ if (do_long_nq || (! jsp->pr_out_hr))
+ return;
+ }
+ sgj_pr_hr(jsp, " ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d "
+ "REF_CHK=%d\n", ((b[4] >> 6) & 0x3), ((b[4] >> 3) & 0x7),
+ !!(b[4] & 0x4), !!(b[4] & 0x2), !!(b[4] & 0x1));
+ sgj_pr_hr(jsp, " UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d "
+ "ORDSUP=%d SIMPSUP=%d\n", !!(b[5] & 0x20), !!(b[5] & 0x10),
+ !!(b[5] & 0x8), !!(b[5] & 0x4), !!(b[5] & 0x2), !!(b[5] & 0x1));
+ sgj_pr_hr(jsp, " WU_SUP=%d [CRD_SUP=%d] NV_SUP=%d V_SUP=%d\n",
+ !!(b[6] & 0x8), !!(b[6] & 0x4), !!(b[6] & 0x2), !!(b[6] & 0x1));
+ sgj_pr_hr(jsp, " NO_PI_CHK=%d P_I_I_SUP=%d LUICLR=%d\n", !!(b[7] & 0x20),
+ !!(b[7] & 0x10), !!(b[7] & 0x1));
+ /* RTD_SUP added in spc5r11, LU_COLL_TYPE added in spc5r09,
+ * HSSRELEF added in spc5r02; CBCS obsolete in spc5r01 */
+ sgj_pr_hr(jsp, " LU_COLL_TYPE=%d R_SUP=%d RTD_SUP=%d HSSRELEF=%d "
+ "[CBCS=%d]\n", (b[8] >> 5) & 0x7, !!(b[8] & 0x10),
+ !!(b[8] & 0x8), !!(b[8] & 0x2), !!(b[8] & 0x1));
+ sgj_pr_hr(jsp, " Multi I_T nexus microcode download=%d\n", b[9] & 0xf);
+ sgj_pr_hr(jsp, " Extended self-test completion minutes=%d\n",
+ sg_get_unaligned_be16(b + 10)); /* spc4r27 */
+ sgj_pr_hr(jsp, " POA_SUP=%d HRA_SUP=%d VSA_SUP=%d DMS_VALID=%d\n",
+ !!(b[12] & 0x80), !!(b[12] & 0x40), !!(b[12] & 0x20),
+ !!(b[12] & 0x10)); /* spc5r20 */
+ sgj_pr_hr(jsp, " Maximum supported sense data length=%d\n",
+ b[13]); /* spc4r34 */
+ sgj_pr_hr(jsp, " IBS=%d IAS=%d SAC=%d NRD1=%d NRD0=%d\n",
+ !!(b[14] & 0x80), !!(b[14] & 0x40), !!(b[14] & 0x4),
+ !!(b[14] & 0x2), !!(b[14] & 0x1)); /* added in spc5r09 */
+ sgj_pr_hr(jsp, " Maximum inquiry change logs=%u\n",
+ sg_get_unaligned_be16(b + 15)); /* spc5r17 */
+ sgj_pr_hr(jsp, " Maximum mode page change logs=%u\n",
+ sg_get_unaligned_be16(b + 17)); /* spc5r17 */
+ sgj_pr_hr(jsp, " DM_MD_4=%d DM_MD_5=%d DM_MD_6=%d DM_MD_7=%d\n",
+ !!(b[19] & 0x80), !!(b[19] & 0x40), !!(b[19] & 0x20),
+ !!(b[19] & 0x10)); /* spc5r20 */
+ sgj_pr_hr(jsp, " DM_MD_D=%d DM_MD_E=%d DM_MD_F=%d\n",
+ !!(b[19] & 0x8), !!(b[19] & 0x4), !!(b[19] & 0x2));
+}
+
+/* VPD_SOFTW_INF_ID 0x84 */
+void
+decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jop;
+ uint64_t ieee_id;
+
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ len -= 4;
+ buff += 4;
+ for ( ; len > 5; len -= 6, buff += 6) {
+ ieee_id = sg_get_unaligned_be48(buff + 0);
+ sgj_pr_hr(jsp, " IEEE identifier: 0x%" PRIx64 "\n", ieee_id);
+ if (jsp->pr_as_json) {
+ jop = sgj_new_unattached_object(jsp);
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ieee_id);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jop);
+ }
+ }
+}
+
+static const char * mode_page_policy_arr[] =
+{
+ "shared",
+ "per target port",
+ "per initiator port",
+ "per I_T nexus",
+};
+
+/* VPD_MODE_PG_POLICY 0x87 ["mpp"] */
+void
+decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k, n, bump, ppc, pspc;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
+ uint8_t * bp;
+ char b[128];
+ static const int blen = sizeof(b);
+
+ if ((1 == op->do_hex) || (op->do_hex > 2)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("Mode page policy VPD page length too short=%d\n", len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0; k < len; k += bump, bp += bump) {
+ bump = 4;
+ if ((k + bump) > len) {
+ pr2serr("Mode page policy VPD page, short "
+ "descriptor length=%d, left=%d\n", bump, (len - k));
+ return;
+ }
+ if (op->do_hex > 1)
+ hex2stdout(bp, 4, 1);
+ else {
+ n = 0;
+ ppc = (bp[0] & 0x3f);
+ pspc = bp[1];
+ 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);
+ if ((0 == k) && (0x3f == (0x3f & bp[0])) && (0xff == bp[1]))
+ sgj_pr_hr(jsp, " therefore the policy applies to all modes "
+ "pages and subpages\n");
+ sgj_pr_hr(jsp, " MLUS=%d, Policy: %s\n", !!(bp[2] & 0x80),
+ mode_page_policy_arr[bp[2] & 0x3]);
+ if (jsp->pr_as_json) {
+ jo2p = sgj_new_unattached_object(jsp);
+ sgj_add_nv_ihex(jsp, jo2p, "policy_page_code", ppc);
+ sgj_add_nv_ihex(jsp, jo2p, "policy_subpage_code", pspc);
+ sgj_add_nv_ihex_nex(jsp, jo2p, "mlus", !!(bp[2] & 0x80), false,
+ "Multiple logical units share");
+ sgj_add_nv_ihexstr(jsp, jo2p, "mode_page_policy", bp[2] & 0x3,
+ NULL, mode_page_policy_arr[bp[2] & 0x3]);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ }
+ }
+}
+
+/* VPD_POWER_CONDITION 0x8a ["pc"] */
+void
+decode_power_condition(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
+{
+ sgj_state * jsp = &op->json_st;
+
+ if (len < 18) {
+ pr2serr("Power condition VPD page length too short=%d\n", len);
+ return;
+ }
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ sgj_pr_hr(jsp, " Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d "
+ "Idle_a=%d\n", !!(buff[4] & 0x2), !!(buff[4] & 0x1),
+ !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1));
+ if (jsp->pr_as_json) {
+ sgj_add_nv_ihex(jsp, jop, "standby_y", !!(buff[4] & 0x2));
+ sgj_add_nv_ihex(jsp, jop, "standby_z", !!(buff[4] & 0x1));
+ sgj_add_nv_ihex(jsp, jop, "idle_c", !!(buff[5] & 0x4));
+ sgj_add_nv_ihex(jsp, jop, "idle_b", !!(buff[5] & 0x2));
+ sgj_add_nv_ihex(jsp, jop, "idle_a", !!(buff[5] & 0x1));
+ }
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Stopped condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 6));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Standby_z condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 8));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Standby_y condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 10));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Idle_a condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 12));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Idle_b condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 14));
+ sgj_pr_hr_js_vi(jsp, jop, 2, "Idle_c condition recovery time (ms)",
+ SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 16));
+}
+
+int
+filter_json_dev_ids(uint8_t * buff, int len, int m_assoc, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int u, off, i_len;
+ sgj_opaque_p jo2p;
+ const uint8_t * bp;
+ sgj_state * jsp = &op->json_st;
+
+ off = -1;
+ while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1)) == 0) {
+ bp = buff + off;
+ i_len = bp[3];
+ if ((off + i_len + 4) > len) {
+ pr2serr(" VPD page error: designator length longer than\n"
+ " remaining response length=%d\n", (len - off));
+ return SG_LIB_CAT_MALFORMED;
+ }
+ jo2p = sgj_new_unattached_object(jsp);
+ sgj_pr_js_designation_descriptor(jsp, jo2p, bp, i_len + 4);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ if (-2 == u) {
+ pr2serr("VPD page error: short designator around offset %d\n", off);
+ return SG_LIB_CAT_MALFORMED;
+ }
+ return 0;
+}
diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h
new file mode 100644
index 00000000..485418f3
--- /dev/null
+++ b/src/sg_vpd_common.h
@@ -0,0 +1,205 @@
+#ifndef SG_VPD_H
+#define SG_VPD_H
+
+/*
+ * Copyright (c) 2022 Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sg_lib.h"
+#include "sg_pr2serr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* standard VPD pages, in ascending page number order */
+#define VPD_SUPPORTED_VPDS 0x0
+#define VPD_UNIT_SERIAL_NUM 0x80
+#define VPD_IMP_OP_DEF 0x81 /* obsolete in SPC-2 */
+#define VPD_ASCII_OP_DEF 0x82 /* obsolete in SPC-2 */
+#define VPD_DEVICE_ID 0x83
+#define VPD_SOFTW_INF_ID 0x84
+#define VPD_MAN_NET_ADDR 0x85
+#define VPD_EXT_INQ 0x86 /* Extended Inquiry */
+#define VPD_MODE_PG_POLICY 0x87
+#define VPD_SCSI_PORTS 0x88
+#define VPD_ATA_INFO 0x89
+#define VPD_POWER_CONDITION 0x8a
+#define VPD_DEVICE_CONSTITUENTS 0x8b
+#define VPD_CFA_PROFILE_INFO 0x8c
+#define VPD_POWER_CONSUMPTION 0x8d
+#define VPD_3PARTY_COPY 0x8f /* 3PC, XCOPY, SPC-4, SBC-3 */
+#define VPD_PROTO_LU 0x90
+#define VPD_PROTO_PORT 0x91
+#define VPD_SCSI_FEATURE_SETS 0x92 /* spc5r11 */
+#define VPD_BLOCK_LIMITS 0xb0 /* SBC-3 */
+#define VPD_SA_DEV_CAP 0xb0 /* SSC-3 */
+#define VPD_OSD_INFO 0xb0 /* OSD */
+#define VPD_BLOCK_DEV_CHARS 0xb1 /* SBC-3 */
+#define VPD_MAN_ASS_SN 0xb1 /* SSC-3, ADC-2 */
+#define VPD_SECURITY_TOKEN 0xb1 /* OSD */
+#define VPD_TA_SUPPORTED 0xb2 /* SSC-3 */
+#define VPD_LB_PROVISIONING 0xb2 /* SBC-3 */
+#define VPD_REFERRALS 0xb3 /* SBC-3 */
+#define VPD_AUTOMATION_DEV_SN 0xb3 /* SSC-3 */
+#define VPD_SUP_BLOCK_LENS 0xb4 /* sbc4r01 */
+#define VPD_DTDE_ADDRESS 0xb4 /* SSC-4 */
+#define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* sbc4r02 */
+#define VPD_LB_PROTECTION 0xb5 /* SSC-5 */
+#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
+#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
+#define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */
+#define VPD_CON_POS_RANGE 0xb9 /* sbc5r01 */
+#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
+
+enum sg_vpd_invoker_e {
+ SG_VPD_INV_NONE = 0,
+ SG_VPD_INV_SG_INQ,
+ SG_VPD_INV_SG_VPD,
+};
+
+/* This structure holds the union of options available in sg_inq and sg_vpd */
+struct opts_t {
+ enum sg_vpd_invoker_e invoker; /* indicates if for sg_inq or sg_vpd */
+ bool do_all; /* sg_vpd */
+ bool do_ata; /* sg_inq */
+ bool do_decode; /* sg_inq */
+ bool do_descriptors; /* sg_inq */
+ bool do_enum; /* sg_enum */
+ bool do_export; /* sg_inq */
+ bool do_force; /* sg_inq + sg_vpd */
+ bool do_only; /* sg_inq: --only after stdinq: don't fetch VPD page 0x80 */
+ bool do_quiet; /* sg_vpd */
+ bool page_given; /* sg_inq + sg_vpd */
+ bool possible_nvme; /* sg_inq */
+ bool verbose_given; /* sg_inq + sg_vpd */
+ bool version_given; /* sg_inq + sg_vpd */
+ bool do_vpd; /* sg_inq */
+#ifdef SG_SCSI_STRINGS
+ bool opt_new; /* sg_inq */
+#endif
+ int do_block; /* do_block */
+ int do_cmddt; /* sg_inq */
+ int do_help; /* sg_inq */
+ int do_hex; /* sg_inq + sg_vpd */
+ int do_ident; /* sg_vpd */
+ int do_long; /* sg_inq[int] + sg_vpd[bool] */
+ 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 */
+ int vend_prod_num; /* sg_vpd */
+ int verbose; /* sg_inq + sg_vpd */
+ int vpd_pn; /* sg_vpd */
+ const char * device_name; /* sg_inq + sg_vpd */
+ const char * page_str; /* sg_inq + sg_vpd */
+ const char * inhex_fn; /* sg_inq + sg_vpd */
+ const char * vend_prod; /* sg_vpd */
+ 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 */
+ int pdt; /* peripheral device type id, -1 is the default */
+ /* (all or not applicable) value */
+ const char * acron;
+ 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
+
+sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop,
+ const char * name, const uint8_t * vpd_hdrp);
+void decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+void decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
+ sgj_opaque_p jop);
+void decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+void decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+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);
+const char * pqual_str(int pqual);
+
+void svpd_enumerate_vendor(int vend_prod_num);
+int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num);
+int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
+const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
+int svpd_find_vp_num_by_acron(const char * vp_ap);
+const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
+ int vend_prod_num);
+int vpd_fetch_page(int sg_fd, uint8_t * rp, int page, int mxlen,
+ bool qt, int vb, int * rlenp);
+void dup_sanity_chk(int sz_opts_t, int sz_values_name_t);
+
+extern uint8_t * rsp_buff;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of SG_VPD_H */
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index 1a607404..2f9dc10f 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -28,7 +28,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-#include "sg_vpd.h"
+#include "sg_vpd_common.h"
/* This is a companion file to sg_vpd.c . It contains logic to output and
decode vendor specific VPD pages