diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.in | 27 | ||||
-rw-r--r-- | src/sg_decode_sense.c | 4 | ||||
-rw-r--r-- | src/sg_inq.c | 998 | ||||
-rw-r--r-- | src/sg_vpd.c | 731 | ||||
-rw-r--r-- | src/sg_vpd.h | 80 | ||||
-rw-r--r-- | src/sg_vpd_common.c | 558 | ||||
-rw-r--r-- | src/sg_vpd_common.h | 205 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 2 |
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 |