aboutsummaryrefslogtreecommitdiff
path: root/src/sg_inq.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sg_inq.c')
-rw-r--r--src/sg_inq.c453
1 files changed, 334 insertions, 119 deletions
diff --git a/src/sg_inq.c b/src/sg_inq.c
index cf7c4064..c35e9343 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.22 20220718"; /* spc6r06 */
+static const char * version_str = "2.24 20220727"; /* spc6r06 */
#define MY_NAME "sg_inq"
@@ -232,6 +232,8 @@ static struct option long_options[] = {
{"only", no_argument, 0, 'o'},
{"page", required_argument, 0, 'p'},
{"raw", no_argument, 0, 'r'},
+ {"sinq_inraw", required_argument, 0, 'Q'},
+ {"sinq-inraw", required_argument, 0, 'Q'},
{"vendor", no_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
@@ -252,9 +254,9 @@ usage()
"[--inhex=FN]\n"
" [--json[=JO]] [--len=LEN] [--long] "
"[--maxlen=LEN]\n"
- " [--only] [--page=PG] [--raw] [--vendor] "
- "[--verbose]\n"
- " [--version] [--vpd] DEVICE\n"
+ " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
+ "[--vendor]\n"
+ " [--verbose] [--version] [--vpd] DEVICE\n"
" where:\n"
" --ata|-a treat DEVICE as (directly attached) ATA "
"device\n");
@@ -265,9 +267,9 @@ usage()
"[--inhex=FN]\n"
" [--json[=JO]] [--len=LEN] [--long] "
"[--maxlen=LEN]\n"
- " [--only] [--page=PG] [--raw] [--verbose] "
- "[--version]\n"
- " [--vpd] DEVICE\n"
+ " [--only] [--page=PG] [--raw] [--sinq_inraw=RFN] "
+ "[--verbose]\n"
+ " [--version] [--vpd] DEVICE\n"
" where:\n");
#endif
pr2serr(" --block=0|1 0-> open(non-blocking); 1-> "
@@ -314,6 +316,9 @@ usage()
" abbreviation (opcode number if "
"'--cmddt' given)\n"
" --raw|-r output response in binary (to stdout)\n"
+ " --sinq_inraw=RFN|-Q RFN read raw (binary) standard "
+ "INQUIRY\n"
+ " response from the RFN filename\n"
" --vendor|-s show vendor specific fields in std "
"inquiry\n"
" --verbose|-v increase verbosity\n"
@@ -420,18 +425,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:j::l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "aB:cdeEfhHiI:j::l:Lm:NoOp:Q:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:Q:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#else /* SG_LIB_LINUX */
#ifdef SG_SCSI_STRINGS
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:NoOp:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:NoOp:Q:rsuvVx",
long_options, &option_index);
#else
- c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:rsuvVx",
+ c = getopt_long(argc, argv, "B:cdeEfhHiI:j::l:Lm:op:Q:rsuvVx",
long_options, &option_index);
#endif /* SG_SCSI_STRINGS */
#endif /* SG_LIB_LINUX */
@@ -541,6 +546,9 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
op->page_str = optarg;
op->page_given = true;
break;
+ case 'Q':
+ op->sinq_inraw_fn = optarg;
+ break;
case 'r':
++op->do_raw;
break;
@@ -1966,20 +1974,12 @@ decode_b0_vpd(uint8_t * buff, int len, int do_hex)
}
}
-static const char * zoned_strs[] = {
- "",
- " [host-aware]",
- " [host-managed]",
- "",
-};
-
-/* VPD_BLOCK_DEV_CHARS sbc */
+/* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */
/* VPD_MAN_ASS_SN ssc */
static void
decode_b1_vpd(uint8_t * buff, int len, int do_hex)
{
- int pdt, zoned;
- unsigned int u;
+ int pdt;
if (do_hex) {
hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
@@ -1988,55 +1988,7 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex)
pdt = PDT_MASK & buff[0];
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 64) {
- pr2serr("Block device characteristics VPD page length too "
- "short=%d\n", len);
- return;
- }
- u = sg_get_unaligned_be16(buff + 4);
- if (0 == u)
- printf(" Medium rotation rate is not reported\n");
- else if (1 == u)
- printf(" Non-rotating medium (e.g. solid state)\n");
- else if ((u < 0x401) || (0xffff == u))
- printf(" Reserved [0x%x]\n", u);
- else
- printf(" Nominal rotation rate: %d rpm\n", u);
- printf(" Product type=%d\n", buff[6]);
- printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
- printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
- u = buff[7] & 0xf;
- printf(" Nominal form factor ");
- switch(u) {
- case 0:
- printf("is not reported\n");
- break;
- case 1:
- printf("5.25 inches\n");
- break;
- case 2:
- printf("3.5 inches\n");
- break;
- case 3:
- printf("2.5 inches\n");
- break;
- case 4:
- printf("1.8 inches\n");
- break;
- case 5:
- printf("less then 1.8 inches\n");
- break;
- default:
- printf("reserved [%u]\n", u);
- break;
- }
- zoned = (buff[8] >> 4) & 0x3; /* added sbc4r04 */
- printf(" ZONED=%d%s\n", zoned, zoned_strs[zoned]);
- /* ZONED field made obsolete in sbc5r01 */
- printf(" FUAB=%d\n", buff[8] & 0x2);
- printf(" VBULS=%d\n", buff[8] & 0x1);
- printf(" DEPOPULATION_TIME=%u (seconds)\n",
- sg_get_unaligned_be32(buff + 12)); /* added sbc4r14 */
+ /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
break;
case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
printf(" Manufacturer-assigned serial number: %.*s\n",
@@ -2054,7 +2006,6 @@ static void
decode_b3_vpd(uint8_t * buff, int len, int do_hex)
{
int pdt;
- unsigned int s, m;
if (do_hex) {
hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
@@ -2063,19 +2014,7 @@ decode_b3_vpd(uint8_t * buff, int len, int do_hex)
pdt = PDT_MASK & buff[0];
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- if (len < 0x10) {
- pr2serr("Referrals VPD page length too short=%d\n", len);
- return;
- }
- s = sg_get_unaligned_be32(buff + 8);
- m = sg_get_unaligned_be32(buff + 12);
- if (0 == s)
- printf(" Single user data segment\n");
- else if (0 == m)
- printf(" Segment size specified by user data segment "
- "descriptor\n");
- else
- printf(" Segment size: %u, segment multiplier: %u\n", s, m);
+ /* now done in decode)referrals_vpd() in sg_vpd_common.c */
break;
default:
printf(" Unable to decode pdt=0x%x, in hex:\n", pdt);
@@ -3057,6 +2996,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
sgj_opaque_p jo2p = NULL;
sgj_opaque_p jap = NULL;
const char * np;
+ const char * ep = "";
// const char * pdt_str;
uint8_t * rp;
// char d[80];
@@ -3402,68 +3342,323 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */
res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
+ bool bdc = false;
+ static const char * masn =
+ "Manufactured-assigned serial number VPD page";
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
pdt = rp[0] & PDT_MASK;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("VPD INQUIRY: Block device characteristics page "
- "(SBC)\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Manufactured assigned serial number VPD page "
- "(SSC):\n");
- break;
- case PDT_OSD:
- printf("Security token VPD page (OSD):\n");
- break;
- case PDT_ADC:
- printf("Manufactured assigned serial number VPD page "
- "(ADC):\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics VPD page";
+ ep = "(SBC)";
+ bdc = true;
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = masn;
+ ep = "(SSC)";
+ break;
+ case PDT_OSD:
+ np = "Security token VPD page";
+ ep = "(OSD)";
+ break;
+ case PDT_ADC:
+ np = masn;
+ ep = "(ADC)";
+ break;
+ default:
+ np = NULL;
+ printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
+ break;
}
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (bdc)
+ decode_block_dev_ch_vpd(rp, len, op, jo2p);
else
decode_b1_vpd(rp, len, op->do_hex);
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb1\n");
break;
case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool lbpv = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Logical block provisioning VPD page";
+ ep = "(SBC)";
+ lbpv = true;
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "TapeAlert supported flags VPD page";
+ ep = "(SSC)";
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (lbpv)
+ return decode_block_lb_prov_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb2\n");
+ break;
+#if 0
+xxxxx
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, NULL, off);
- case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */
+#endif
+ case 0xb3:
res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
if (0 == res) {
+ bool ref = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
pdt = rp[0] & PDT_MASK;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("VPD INQUIRY: Referrals VPD page (SBC)\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb3, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Referrals VPD page";
+ ep = "(SBC)";
+ ref = true;
+ break;
+ default:
+ np = NULL;
+ break;
}
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (ref)
+ decode_referrals_vpd(rp, len, op, jo2p);
else
decode_b3_vpd(rp, len, op->do_hex);
+ return 0;
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb3\n");
break;
case 0xb4:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool sbl = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Supported block lengths and protection types VPD page";
+ ep = "(SBC)";
+ sbl = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
+ "length_and_protection_types_descriptor_list");
+ }
+ if (sbl)
+ decode_sup_block_lens_vpd(rp, len, op, jap);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb4\n");
+ break;
case 0xb5:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool bdce = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics VPD page";
+ ep = "(SBC)";
+ bdce = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (bdce)
+ decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb5\n");
+ break;
case 0xb6:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool zbdch = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Zoned block device characteristics VPD page";
+ ep = "(SBC, ZBC)";
+ zbdch = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (zbdch)
+ decode_zbdch_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb6\n");
+ break;
case 0xb7:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool ble = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block limits extension VPD page";
+ ep = "(SBC)";
+ ble = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json)
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ if (ble)
+ decode_block_limits_ext_vpd(rp, len, op, jo2p);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb7\n");
+ break;
case 0xb8:
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len);
+ if (0 == res) {
+ bool fp = false;
+
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Format presets VPD page";
+ ep = "(SBC)";
+ fp = true;
+ break;
+ default:
+ np = NULL;
+ break;
+ }
+ if (op->do_hex < 2) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_"
+ "descriptor_list");
+ }
+ if (fp)
+ decode_format_presets_vpd(rp, len, op, jap);
+ else
+ return vpd_mainly_hex(sg_fd, op, NULL, off);
+ return 0;
+ } else if (! op->do_raw)
+ pr2serr("VPD INQUIRY: page=0xb8\n");
+ break;
case 0xb9:
+// yyyyyyyy
bad = true;
pr2serr("Please try the sg_vpd utility which decodes more VPD "
"pages\n\n");
@@ -3918,6 +4113,7 @@ main(int argc, char * argv[])
int sg_fd = -1;
int ret = 0;
int inhex_len = 0;
+ int inraw_len = 0;
const struct svpd_values_name_t * vnp;
sgj_state * jsp;
sgj_opaque_p jop = NULL;
@@ -4042,6 +4238,25 @@ main(int argc, char * argv[])
pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz);
return sg_convert_errno(ENOMEM);
}
+ if (op->sinq_inraw_fn) {
+ if (op->do_cmddt) {
+ pr2serr("Don't support --cmddt with --sinq-inraw= option\n");
+ ret = SG_LIB_CONTRADICT;
+ goto err_out;
+ }
+ if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff,
+ &inraw_len, rsp_buff_sz))) {
+ goto err_out;
+ }
+ if (inraw_len < 36) {
+ pr2serr("Unable to read 36 or more bytes from %s\n",
+ op->sinq_inraw_fn);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ memcpy(op->std_inq_a, rsp_buff, 36);
+ op->std_inq_a_valid = true;
+ }
if (op->inhex_fn) {
if (op->device_name) {
pr2serr("Cannot have both a DEVICE and --inhex= option\n");