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