aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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