sg_vpd: add --inhex=FN to read response in from a file; other cleanups
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@554 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/ChangeLog b/ChangeLog
index b0d1060..d76ebca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.38 [20140216] [svn: r553]
+Changelog for sg3_utils-1.38 [20140217] [svn: r554]
- sg_ses: add --dev-slot-num= and --sas-addr=
- fix --data=- problem with large buffers
- new --data=@FN to read hex data from file FN
@@ -17,6 +17,7 @@
- sync version descriptors dated 20131126
- fix overflow in encode_whitespaces
- sg_vpd: add LU_CONG to standard inquiry response output
+ - add --inhex=FN to read response in from a file
- decode Third Party Copy (tpc) page
- add LTO and DDS vendor pages
- allow --page=num to restrict --enumerate output
diff --git a/doc/sg_inq.8 b/doc/sg_inq.8
index f5e1f25..4c75952 100644
--- a/doc/sg_inq.8
+++ b/doc/sg_inq.8
@@ -124,6 +124,10 @@
the \fI\-\-ata\fR option, this utility outputs the ATA IDENTIFY (PACKET)
DEVICE response in hexadecimal words suitable for input
to 'hdparm \-\-Istdin'. See note below.
+.br
+To generate output suitable for placing in a file that can be used by a
+later invocation with the \fI\-\-inhex=FN\fR option, use the '\-HHHH'
+option (e.g. 'sg_inq \-p di -HHHH /dev/sg3 > dev_id.hex').
.TP
\fB\-i\fR, \fB\-\-id\fR
prints the device identification VPD page [0x83].
diff --git a/doc/sg_vpd.8 b/doc/sg_vpd.8
index 626c8bd..47b01c4 100644
--- a/doc/sg_vpd.8
+++ b/doc/sg_vpd.8
@@ -1,18 +1,22 @@
.TH SG_VPD "8" "February 2014" "sg3_utils\-1.38" SG3_UTILS
.SH NAME
-sg_vpd \- fetch Vital Product Data (VPD) pages via a SCSI INQUIRY command
+sg_vpd \- fetch SCSI VPD page and/or decode its response
.SH SYNOPSIS
.B sg_vpd
[\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR]
-[\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR]
-[\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
-\fIDEVICE\fR
+[\fI\-\-inhex=FN\fR] [\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR]
+[\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility fetches a Vital Product Data page and decodes it or
-outputs it in ASCII hexadecimal or binary. VPD pages are fetched
-with a SCSI INQUIRY command.
+This utility, when \fIDEVICE\fR is given, fetches a Vital Product Data (VPD)
+page and decodes it or outputs it in ASCII hexadecimal or binary. VPD pages
+are fetched with a SCSI INQUIRY command.
+.PP
+Alternatively the \fI\-\-inhex=FN\fR option can be given. In this case
+\fIFN\fR is assumed to be a file name ('\-' for stdin) containing ASCII
+hexadecimal representing a VPD page response.
.PP
Probably the most important page is the Device Identification
VPD page (page number: 0x83). Since SPC\-3, support for this page
@@ -20,9 +24,8 @@
using the \fI\-\-ident\fR option.
.PP
The reference document used for interpreting VPD pages (and the INQUIRY
-standard response) is T10/1713\-D Revision 36e (SPC\-4, 24 August 2012)
-found at http://www.t10.org . Obsolete and reserved items in the standard
-INQUIRY response output are displayed in square brackets.
+standard response) is T10/1713\-D Revision 36q (SPC\-4, 12 February 2014)
+found at http://www.t10.org .
.PP
When no options are given, other than a \fIDEVICE\fR, then the "Supported
VPD pages" (0x0) VPD page is fetched and decoded.
@@ -46,6 +49,10 @@
\fB\-H\fR, \fB\-\-hex\fR
outputs the requested VPD page in ASCII hexadecimal. Can be used multiple
times, see section on the ATA information vpd page.
+.br
+To generate output suitable for placing in a file that can be used by a
+later invocation with the \fI\-\-inhex=FN\fR option, use the '\-HHHH'
+option (e.g. 'sg_vpd \-p di -HHHH /dev/sg3 > dev_id.hex').
.TP
\fB\-i\fR, \fB\-\-ident\fR
decode the device identification (0x83) VPD page. When used once this option
@@ -53,6 +60,14 @@
the device identification VPD page's logical unit designator is decoded. In
the latter case this option has the same effect as '\-\-quiet \-\-page=di_lu'.
.TP
+\fB\-I\fR, \fB\-\-inhex\fR=\fIFN\fR
+\fIFN\fR is expected to be a file name (or '\-' for stdin) which contains
+ASCII hexadecimal respresenting a VPD page (or a standard INQUIRY) response.
+This utility will then decode that response. The hexadecimal should be
+arranged as 1 or 2 digits representing a byte each of which is whitespace
+or comma separated. Anything from and including a hash mark to the end
+of line is ignored.
+.TP
\fB\-l\fR, \fB\-\-long\fR
when decoding some VPD pages, give a little more output. For example the ATA
Information VPD page only shows the signature (in hex) and the IDENTIFY
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 6b1afbe..5a47f45 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -68,7 +68,7 @@
* information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
*/
-static const char * version_str = "1.28 20140214"; /* SPC-4 rev 36q */
+static const char * version_str = "1.29 20140216"; /* SPC-4 rev 36q */
/* Following VPD pages are in ascending page number order */
@@ -2678,7 +2678,7 @@
printf(" length=%d (0x%x), but only fetched %d bytes", len,
len, act_len);
if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN))
- printf(" [for SCSI>=2, len>=36 is expected]");
+ printf("\n [for SCSI>=2, len>=36 is expected]");
cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
@@ -2778,16 +2778,34 @@
return 0;
}
+/* When sg_fd >= 0 fetch VPD page from device; mxlen is command line
+ * --maxlen=LEN option (def: 0) or -1 for a VPD page with a short length
+ * (1 byte). When sg_fd < 0 then mxlen bytes have been read from
+ * --inhex=FN file. Returns 0 for success. */
static int
vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
- int short_len, int vb, int * rlenp)
+ int mxlen, int vb, int * rlenp)
{
- int res, resid, rlen, len;
+ int res, resid, rlen, len, n;
- res = pt_inquiry(sg_fd, 1, page, rp, DEF_ALLOC_LEN, &resid, 1, vb);
+ if (sg_fd < 0) {
+ len = ((rp[2] << 8) + rp[3]) + 4;
+ if (vb && (len > mxlen))
+ pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN "
+ "file (%d)\n", len , mxlen);
+ if (rlenp)
+ *rlenp = (len < mxlen) ? len : mxlen;
+ return 0;
+ }
+ if (mxlen > MX_ALLOC_LEN) {
+ pr2serr("--maxlen=LEN too long: %d > %d\n", mxlen, MX_ALLOC_LEN);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ n = (mxlen > 0) ? mxlen : DEF_ALLOC_LEN;
+ res = pt_inquiry(sg_fd, 1, page, rp, n, &resid, 1, vb);
if (res)
return res;
- rlen = DEF_ALLOC_LEN - resid;
+ rlen = n - resid;
if (rlen < 4) {
pr2serr("VPD response too short (len=%d)\n", rlen);
return SG_LIB_CAT_MALFORMED;
@@ -2797,7 +2815,7 @@
"response\n");
return SG_LIB_CAT_MALFORMED;
}
- if (short_len)
+ if (mxlen < 0)
len = rp[3] + 4;
else
len = ((rp[2] << 8) + rp[3]) + 4;
@@ -2805,7 +2823,7 @@
if (rlenp)
*rlenp = len;
return 0;
- } else if ((len <= DEF_ALLOC_LEN) && short_len) {
+ } else if (mxlen) {
if (rlenp)
*rlenp = rlen;
return 0;
@@ -2826,7 +2844,7 @@
}
/* Returns 0 if Unit Serial Number VPD page contents found, else see
- sg_ll_inquiry() return values */
+ * sg_ll_inquiry() return values */
static int
fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
{
@@ -2836,7 +2854,7 @@
res = 0;
memset(b, 0xff, 4); /* guard against empty response */
/* first check if unit serial number VPD page is supported */
- res = vpd_fetch_page_from_dev(sg_fd, b, VPD_SUPPORTED_VPDS, 1, verbose,
+ res = vpd_fetch_page_from_dev(sg_fd, b, VPD_SUPPORTED_VPDS, -1, verbose,
&len);
if (0 == res) {
len -= 4;
@@ -2845,7 +2863,7 @@
break;
}
if (k < len) {
- res = vpd_fetch_page_from_dev(sg_fd, b, VPD_UNIT_SERIAL_NUM, 1,
+ res = vpd_fetch_page_from_dev(sg_fd, b, VPD_UNIT_SERIAL_NUM, -1,
verbose, &len);
if (0 == res) {
len -= 4;
@@ -2873,12 +2891,14 @@
/* Process a standard INQUIRY response. Returns 0 if successful */
static int
-std_inq_process(int sg_fd, const struct opts_t * op)
+std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len)
{
int res, len, rlen, act_len;
char buff[48];
int verb, resid;
+ if (sg_fd < 0)
+ return std_inq_response(op, inhex_len);
rlen = (op->resp_len > 0) ? op->resp_len : SAFE_STD_INQ_RESP_LEN;
verb = op->do_verbose;
res = pt_inquiry(sg_fd, 0, 0, rsp_buff, rlen, &resid, 0, verb);
@@ -2945,6 +2965,8 @@
pr2serr("unit attention (?)%s\n", buff);
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
pr2serr("aborted command%s\n", buff);
+ else if (SG_LIB_CAT_MALFORMED == res)
+ pr2serr("malformed response%s\n", buff);
else
pr2serr("res=%d%s\n", res, buff);
return res;
@@ -3081,7 +3103,7 @@
/* Returns 0 if successful */
static int
-vpd_mainly_hex(int sg_fd, const struct opts_t * op)
+vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len)
{
int res, len;
char b[48];
@@ -3089,11 +3111,19 @@
unsigned char * rp;
rp = rsp_buff;
- memset(rp, 0, DEF_ALLOC_LEN);
if ((! op->do_raw) && (op->do_hex < 2))
printf("VPD INQUIRY, page code=0x%.2x:\n", op->page_num);
- res = vpd_fetch_page_from_dev(sg_fd, rp, op->page_num, 0, op->do_verbose,
- &len);
+ if (sg_fd < 0) {
+ len = ((rp[2] << 8) + rp[3]) + 4;
+ if (op->do_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);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, op->page_num, op->resp_len,
+ op->do_verbose, &len);
+ }
if (0 == res) {
if (op->do_raw)
dStrRaw((const char *)rp, len);
@@ -3101,7 +3131,7 @@
if (0 == op->page_num)
decode_supported_vpd(rp, len, op->do_hex);
else {
- if (op->do_hex < 2) {
+ if (op->do_verbose) {
cp = sg_get_pdt_str(rp[0] & 0x1f, sizeof(b), b);
printf(" [PQual=%d Peripheral device type: %s]\n",
(rp[0] & 0xe0) >> 5, cp);
@@ -3131,358 +3161,24 @@
/* Returns 0 if successful */
static int
-vpd_response(const struct opts_t * op, int rlen)
+vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
{
- int len, pdt, pn;
- unsigned char * rp;
- const struct svpd_values_name_t * vnp;
-
- rp = rsp_buff;
- if (rlen < 4) {
- pr2serr("INQUIRY VPD response too short\n");
- return SG_LIB_CAT_MALFORMED;
- }
- pn = op->page_num;
- if (pn != rp[1]) {
- if (op->page_arg) {
- vnp = sdp_find_vpd_by_acron(op->page_arg);
- if (vnp) {
- pr2serr("requested %s VPD page [0x%x]\n but --inhex is "
- "for page number 0x%x\n", vnp->name, vnp->value,
- rp[1]);
- return SG_LIB_CAT_MALFORMED;
- }
- }
- pr2serr("requested VPD page number [0x%x] differs from that in FN "
- "[0x%x]\n", pn, rp[1]);
- return SG_LIB_CAT_MALFORMED;
- }
-
- switch (pn) {
- case VPD_SUPPORTED_VPDS:
- if (! op->do_raw && ! op->do_export && (op->do_hex < 2))
- printf("VPD INQUIRY: Supported VPD pages page\n");
- len = ((rp[2] << 8) + rp[3]) + 4; /* spc4r25 */
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_supported_vpd(rp, len, op->do_hex);
- break;
- case VPD_UNIT_SERIAL_NUM:
- if (! op->do_raw && ! op->do_export && (op->do_hex < 2))
- printf("VPD INQUIRY: Unit serial number page\n");
- len = ((rp[2] << 8) + rp[3]) + 4; /* spc4r25 */
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else if (op->do_hex)
- dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1);
- else {
- char obuff[DEF_ALLOC_LEN];
-
- memset(obuff, 0, sizeof(obuff));
- len -= 4;
- if (len >= (int)sizeof(obuff))
- len = sizeof(obuff) - 1;
- memcpy(obuff, rp + 4, len);
- if (op->do_export) {
- len = encode_whitespaces((unsigned char *)obuff, len);
- printf("SCSI_IDENT_SERIAL=%s\n", obuff);
- } else
- printf(" Unit serial number: %s\n", obuff);
- }
- break;
- case VPD_DEVICE_ID:
- if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
- printf("VPD INQUIRY: Device Identification page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else if (op->do_hex > 2)
- dStrHex((const char *)rp, len, -1);
- else if (op->do_export) {
- if (len < 4) {
- pr2serr("Device identification page length too "
- "short=%d\n", len);
- } else {
- export_dev_ids(rp + 4, len - 4);
- }
- } else
- decode_id_vpd(rp, len, op->do_hex);
- break;
- case VPD_SOFTW_INF_ID:
- if (! op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Software interface identification page\n");
- len = ((rp[2] << 8) + rp[3]) + 4; /* spc4r25 */
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_softw_inf_id(rp, len, op->do_hex);
- break;
- case VPD_MAN_NET_ADDR:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Management network addresses page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_net_man_vpd(rp, len, op->do_hex);
- break;
- case VPD_MODE_PG_POLICY:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Mode page policy\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_mode_policy_vpd(rp, len, op->do_hex);
- break;
- case VPD_EXT_INQ:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: extended INQUIRY data page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_x_inq_vpd(rp, len, op->do_hex);
- break;
- case VPD_ATA_INFO:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: ATA information page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- /* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
- if ((2 == op->do_raw) || (3 == op->do_hex))
- dWordHex((const unsigned short *)(rp + 60),
- 256, -2, sg_is_big_endian());
- else if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_ata_info_vpd(rp, len, op->do_hex);
- break;
- case VPD_POWER_CONDITION:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Power condition page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_power_condition(rp, len, op->do_hex);
- break;
- case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */
- pdt = rp[0] & 0x1f;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
- printf("VPD INQUIRY: Block limits page (SBC)\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("VPD INQUIRY: Sequential access device "
- "capabilities (SSC)\n");
- break;
- case PDT_OSD:
- printf("VPD INQUIRY: OSD information (OSD)\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb0, pdt);
- break;
- }
- }
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_b0_vpd(rp, len, op->do_hex);
- break;
- case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */
- pdt = rp[0] & 0x1f;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
- 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;
- }
- }
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_b1_vpd(rp, len, op->do_hex);
- break;
- case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */
- pr2serr(" Only hex output supported. sg_vpd decodes the B2h page.\n");
- return SG_LIB_CAT_OTHER;
- case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */
- pdt = rp[0] & 0x1f;
- if (! op->do_raw && (op->do_hex < 2)) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
- printf("VPD INQUIRY: Referrals VPD page (SBC)\n");
- break;
- default:
- printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb3, pdt);
- break;
- }
- }
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_b3_vpd(rp, len, op->do_hex);
- break;
- case VPD_UPR_EMC: /* 0xc0 */
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
- len = rp[3] + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_upr_vpd_c0_emc(rp, len, op->do_hex);
- break;
- case VPD_RDAC_VERS: /* 0xc2 */
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Software Version (RDAC)\n");
- len = rp[3] + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_rdac_vpd_c2(rp, len, op->do_hex);
- break;
- case VPD_RDAC_VAC: /* 0xc9 */
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: Volume Access Control (RDAC)\n");
- len = rp[3] + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_rdac_vpd_c9(rp, len, op->do_hex);
- break;
- case VPD_SCSI_PORTS:
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: SCSI Ports page\n");
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n", op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_scsi_ports_vpd(rp, len, op->do_hex);
- break;
- default:
- if ((pn > 0) && (pn < 0x80)) {
- if (!op->do_raw && (op->do_hex < 2))
- printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
- pn);
- len = ((rp[2] << 8) + rp[3]) + 4;
- if (len > rlen) {
- pr2serr("truncated VPD page in inhex file (%s)\n",
- op->inhex_fn);
- len = rlen;
- }
- if (op->do_raw)
- dStrRaw((const char *)rp, len);
- else
- decode_ascii_inf(rp, len, op->do_hex);
- } else {
- pr2serr(" Only hex output supported. sg_vpd and sdparm decode "
- "more VPD pages.\n");
- return SG_LIB_CAT_OTHER;
- }
- }
- return 0;
-}
-
-/* Returns 0 if successful */
-static int
-vpd_get_and_decode(int sg_fd, const struct opts_t * op)
-{
- int len, pdt, pn, vb;
+ int len, pdt, pn, vb, mxlen;
int res = 0;
unsigned char * rp;
pn = op->page_num;
rp = rsp_buff;
vb = op->do_verbose;
+ if (sg_fd >= 0)
+ mxlen = op->resp_len;
+ else
+ mxlen = inhex_len;
switch (pn) {
case VPD_SUPPORTED_VPDS:
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, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3496,7 +3192,7 @@
case VPD_UNIT_SERIAL_NUM:
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, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3523,7 +3219,7 @@
case VPD_DEVICE_ID:
if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
printf("VPD INQUIRY: Device Identification page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3538,7 +3234,7 @@
case VPD_SOFTW_INF_ID:
if (! op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Software interface identification page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3549,7 +3245,7 @@
case VPD_MAN_NET_ADDR:
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Management network addresses page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3560,7 +3256,7 @@
case VPD_MODE_PG_POLICY:
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Mode page policy\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3571,7 +3267,7 @@
case VPD_EXT_INQ:
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: extended INQUIRY data page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3582,7 +3278,7 @@
case VPD_ATA_INFO:
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, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
/* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
@@ -3597,7 +3293,7 @@
case VPD_POWER_CONDITION:
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Power condition page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3606,7 +3302,7 @@
decode_power_condition(rp, len, op->do_hex);
break;
case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3634,7 +3330,7 @@
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, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3670,9 +3366,9 @@
if (!op->do_raw && (op->do_hex < 2))
pr2serr(" Only hex output supported. sg_vpd decodes the B2h "
"page.\n");
- return vpd_mainly_hex(sg_fd, op);
+ return vpd_mainly_hex(sg_fd, op, inhex_len);
case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
if (! op->do_raw && (op->do_hex < 2)) {
@@ -3695,7 +3391,7 @@
case VPD_UPR_EMC: /* 0xc0 */
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 1, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3706,7 +3402,7 @@
case VPD_RDAC_VERS: /* 0xc2 */
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Software Version (RDAC)\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 1, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3717,7 +3413,7 @@
case VPD_RDAC_VAC: /* 0xc9 */
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: Volume Access Control (RDAC)\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 1, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3728,7 +3424,7 @@
case VPD_SCSI_PORTS:
if (!op->do_raw && (op->do_hex < 2))
printf("VPD INQUIRY: SCSI Ports page\n");
- res = vpd_fetch_page_from_dev(sg_fd, rp, pn, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (res)
break;
if (op->do_raw)
@@ -3741,7 +3437,7 @@
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, 0, vb, &len);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len);
if (0 == res) {
if (op->do_raw)
dStrRaw((const char *)rp, len);
@@ -3752,7 +3448,7 @@
if (op->do_hex < 2)
pr2serr(" Only hex output supported. sg_vpd and sdparm "
"decode more VPD pages.\n");
- return vpd_mainly_hex(sg_fd, op);
+ return vpd_mainly_hex(sg_fd, op, inhex_len);
}
}
if (res) {
@@ -3886,21 +3582,20 @@
sizeof(rsp_buff)))
return SG_LIB_FILE_ERROR;
if (-1 == op->page_num) { /* may be able to deduce VPD page */
+ if (op->page_pdt < 0)
+ op->page_pdt = 0x1f & rsp_buff[0];
if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
if (op->do_verbose)
pr2serr("Guessing from --inhex= this is a standard "
"INQUIRY\n");
- if (op->page_pdt < 0)
- op->page_pdt = 0x1f & rsp_buff[0];
- } else if (rsp_buff[2] < 2) {
+ } else if (rsp_buff[2] <= 2) {
if (op->do_verbose)
pr2serr("Guessing from --inhex this is VPD page 0x%x\n",
rsp_buff[1]);
op->page_num = rsp_buff[1];
- if (op->page_pdt < 0)
- op->page_pdt = 0x1f & rsp_buff[0];
- ++op->do_decode;
++op->do_vpd;
+ if ((1 != op->do_hex) && (0 == op->do_raw))
+ ++op->do_decode;
} else {
if (op->do_verbose)
pr2serr("page number unclear from --inhex, hope it's a "
@@ -3976,10 +3671,13 @@
}
}
if (op->inhex_fn) {
- if (op->do_vpd)
- return vpd_response(op, inhex_len);
- else
- return std_inq_response(op, inhex_len);
+ if (op->do_vpd) {
+ if (op->do_decode)
+ return vpd_decode(-1, op, inhex_len);
+ else
+ return vpd_mainly_hex(-1, op, inhex_len);
+ } else
+ return std_inq_process(-1, op, inhex_len);
}
#if defined(O_NONBLOCK) && defined(O_RDONLY)
@@ -4026,7 +3724,7 @@
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);
+ ret = std_inq_process(sg_fd, op, -1);
if (ret)
goto err_out;
} else if (op->do_cmddt) {
@@ -4037,11 +3735,11 @@
goto err_out;
} else if (op->do_vpd) {
if (op->do_decode) {
- ret = vpd_get_and_decode(sg_fd, op);
+ ret = vpd_decode(sg_fd, op, -1);
if (ret)
goto err_out;
} else {
- ret = vpd_mainly_hex(sg_fd, op);
+ ret = vpd_mainly_hex(sg_fd, op, -1);
if (ret)
goto err_out;
}
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 943adca..56ee7eb 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -21,6 +21,7 @@
#endif
#include "sg_lib.h"
#include "sg_cmds_basic.h"
+#include "sg_pt.h"
/* This utility program was originally written for the Linux OS SCSI subsystem.
@@ -31,7 +32,7 @@
*/
-static const char * version_str = "0.79 20140215"; /* spc4r36 + sbc3r35 */
+static const char * version_str = "0.79 20140216"; /* spc4r36 + sbc3r35 */
/* And with sbc3r35, vale Mark Evans */
void svpd_enumerate_vendor(void);
@@ -90,6 +91,11 @@
#define MX_ALLOC_LEN (0xc000 + 0x80)
#define VPD_ATA_INFO_LEN 572
+#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
+#define INQUIRY_CMD 0x12
+#define INQUIRY_CMDLEN 6
+#define DEF_PT_TIMEOUT 60 /* 60 seconds */
+
/* This structure is a duplicate of one of the same name in sg_vpd_vendor.c .
Take care that both have the same fields (and types). */
@@ -116,6 +122,7 @@
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"ident", no_argument, 0, 'i'},
+ {"inhex", required_argument, 0, 'I'},
{"long", no_argument, 0, 'l'},
{"maxlen", required_argument, 0, 'm'},
{"page", required_argument, 0, 'p'},
@@ -206,10 +213,10 @@
usage()
{
pr2serr("Usage: sg_vpd [--enumerate] [--help] [--hex] [--ident] "
- "[--long]\n"
- " [--maxlen=LEN] [--page=PG] [--quiet] [--raw] "
- "[--verbose]\n"
- " [--version] DEVICE\n");
+ "[--inhex=fn]\n"
+ " [--long] [--maxlen=LEN] [--page=PG] [--quiet] "
+ "[--raw]\n"
+ " [--verbose] [--version] DEVICE\n");
pr2serr(" where:\n"
" --enumerate|-e enumerate known VPD pages names (ignore "
"DEVICE),\n"
@@ -220,6 +227,8 @@
"twice for\n"
" short logical unit designator (equiv: "
"'-qp di_lu')\n"
+ " --inhex=FN|-I FN use ASCII hex in file FN instead of "
+ "DEVICE\n"
" --long|-l perform extra decoding\n"
" --maxlen=LEN|-m LEN max response length (allocation "
"length in cdb)\n"
@@ -232,9 +241,294 @@
" --raw|-r output page in binary\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
- "Fetch Vital Product Data (VPD) page using SCSI INQUIRY. To "
- "list available\npages use '-e'. And '-p -1' yields the "
- "standard INQUIRY response.\n");
+ "Fetch Vital Product Data (VPD) page using SCSI INQUIRY or "
+ "decodes VPD\npage response held in file FN. To list available "
+ "pages use '-e'. Also\n'-p -1' yields the standard INQUIRY "
+ "response.\n");
+}
+
+/* Read ASCII hex bytes from fname (a file named '-' taken as stdin).
+ * There should be either one entry per line or a comma, space or tab
+ * separated list of bytes. If no_space is set then a string of ACSII hex
+ * digits is expected, 2 per byte. Everything from and including a '#'
+ * on a line is ignored. Returns 0 if ok, or 1 if error. */
+static int
+f2hex_arr(const char * fname, int no_space, unsigned char * mp_arr,
+ int * mp_arr_len, int max_arr_len)
+{
+ int fn_len, in_len, k, j, m, split_line;
+ unsigned int h;
+ const char * lcp;
+ FILE * fp;
+ char line[512];
+ char carry_over[4];
+ int off = 0;
+
+ if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len))
+ return 1;
+ fn_len = strlen(fname);
+ if (0 == fn_len)
+ return 1;
+ if ((1 == fn_len) && ('-' == fname[0])) /* read from stdin */
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (NULL == fp) {
+ pr2serr("Unable to open %s for reading\n", fname);
+ return 1;
+ }
+ }
+
+ carry_over[0] = 0;
+ for (j = 0; j < 512; ++j) {
+ if (NULL == fgets(line, sizeof(line), fp))
+ break;
+ in_len = strlen(line);
+ if (in_len > 0) {
+ if ('\n' == line[in_len - 1]) {
+ --in_len;
+ line[in_len] = '\0';
+ split_line = 0;
+ } else
+ split_line = 1;
+ }
+ if (in_len < 1) {
+ carry_over[0] = 0;
+ continue;
+ }
+ if (carry_over[0]) {
+ if (isxdigit(line[0])) {
+ carry_over[1] = line[0];
+ carry_over[2] = '\0';
+ if (1 == sscanf(carry_over, "%x", &h))
+ mp_arr[off - 1] = h; /* back up and overwrite */
+ else {
+ pr2serr("f2hex_arr: carry_over error ['%s'] around line "
+ "%d\n", carry_over, j + 1);
+ goto bad;
+ }
+ lcp = line + 1;
+ --in_len;
+ } else
+ lcp = line;
+ carry_over[0] = 0;
+ } else
+ lcp = line;
+
+ m = strspn(lcp, " \t");
+ if (m == in_len)
+ continue;
+ lcp += m;
+ in_len -= m;
+ if ('#' == *lcp)
+ continue;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ if ((k < in_len) && ('#' != lcp[k])) {
+ pr2serr("f2hex_arr: syntax error at line %d, pos %d\n",
+ j + 1, m + k + 1);
+ goto bad;
+ }
+ if (no_space) {
+ for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1));
+ ++k, lcp += 2) {
+ if (1 != sscanf(lcp, "%2x", &h)) {
+ pr2serr("f2hex_arr: bad hex number in line %d, "
+ "pos %d\n", j + 1, (int)(lcp - line + 1));
+ goto bad;
+ }
+ if ((off + k) >= max_arr_len) {
+ pr2serr("f2hex_arr: array length exceeded\n");
+ goto bad;
+ }
+ mp_arr[off + k] = h;
+ }
+ if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1))))
+ carry_over[0] = *lcp;
+ off += k;
+ } else {
+ for (k = 0; k < 1024; ++k) {
+ if (1 == sscanf(lcp, "%x", &h)) {
+ if (h > 0xff) {
+ pr2serr("f2hex_arr: hex number larger than "
+ "0xff in line %d, pos %d\n", j + 1,
+ (int)(lcp - line + 1));
+ goto bad;
+ }
+ if (split_line && (1 == strlen(lcp))) {
+ /* single trailing hex digit might be a split pair */
+ carry_over[0] = *lcp;
+ }
+ if ((off + k) >= max_arr_len) {
+ pr2serr("f2hex_arr: array length exceeded\n");
+ goto bad;
+ }
+ mp_arr[off + k] = h;
+ lcp = strpbrk(lcp, " ,\t");
+ if (NULL == lcp)
+ break;
+ lcp += strspn(lcp, " ,\t");
+ if ('\0' == *lcp)
+ break;
+ } else {
+ if ('#' == *lcp) {
+ --k;
+ break;
+ }
+ pr2serr("f2hex_arr: error in line %d, at pos %d\n", j + 1,
+ (int)(lcp - line + 1));
+ goto bad;
+ }
+ }
+ off += (k + 1);
+ }
+ }
+ *mp_arr_len = off;
+ if (stdin != fp)
+ fclose(fp);
+ return 0;
+bad:
+ if (stdin != fp)
+ fclose(fp);
+ return 1;
+}
+
+/* Local version of sg_ll_inquiry() [found in libsgutils] that additionally
+ * passes back resid. Same return values as sg_ll_inquiry() (0 is good). */
+static int
+pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
+ int * residp, int noisy, int verbose)
+{
+ int res, ret, k, sense_cat;
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ unsigned char * up;
+ struct sg_pt_base * ptvp;
+
+ if (evpd)
+ inqCmdBlk[1] |= 1;
+ inqCmdBlk[2] = (unsigned char)pg_op;
+ /* 16 bit allocation length (was 8) is a recent SPC-3 addition */
+ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ inqCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
+ if (verbose) {
+ pr2serr(" inquiry cdb: ");
+ for (k = 0; k < INQUIRY_CMDLEN; ++k)
+ pr2serr("%02x ", inqCmdBlk[k]);
+ pr2serr("\n");
+ }
+ if (resp && (mx_resp_len > 0)) {
+ up = (unsigned char *)resp;
+ up[0] = 0x7f; /* defensive prefill */
+ if (mx_resp_len > 4)
+ up[4] = 0;
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ pr2serr("inquiry: out of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
+ noisy, verbose, &sense_cat);
+ if (residp)
+ *residp = get_scsi_pt_resid(ptvp);
+ destruct_scsi_pt_obj(ptvp);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else if (ret < 4) {
+ if (verbose)
+ pr2serr("inquiry: got too few bytes (%d)\n", ret);
+ ret = SG_LIB_CAT_MALFORMED;
+ } else
+ ret = 0;
+
+ return ret;
+}
+
+/* mxlen is command line --maxlen=LEN option (def: 0) or -1 for a VPD page
+ * with a short length (1 byte). Returns 0 for success. */
+int /* global: use by sg_vpd_vendor.c */
+vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
+ int mxlen, int vb, int * rlenp)
+{
+ int res, resid, rlen, len, n;
+
+ if (sg_fd < 0) {
+ len = ((rp[2] << 8) + rp[3]) + 4;
+ if (vb && (len > mxlen))
+ pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN "
+ "file (%d)\n", len , mxlen);
+ if (rlenp)
+ *rlenp = (len < mxlen) ? len : mxlen;
+ return 0;
+ }
+ if (mxlen > MX_ALLOC_LEN) {
+ pr2serr("--maxlen=LEN too long: %d > %d\n", mxlen, MX_ALLOC_LEN);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ n = (mxlen > 0) ? mxlen : DEF_ALLOC_LEN;
+ res = pt_inquiry(sg_fd, 1, page, rp, n, &resid, 1, vb);
+ if (res)
+ return res;
+ rlen = n - resid;
+ if (rlen < 4) {
+ pr2serr("VPD response too short (len=%d)\n", rlen);
+ return SG_LIB_CAT_MALFORMED;
+ }
+ if (page != rp[1]) {
+ pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
+ "response\n");
+ n = (rlen < 32) ? rlen : 32;
+ if (vb) {
+ pr2serr("First %d bytes of bad response\n", n);
+ dStrHexErr((const char *)rp, n, 0);
+ }
+ return SG_LIB_CAT_MALFORMED;
+ }
+ if (mxlen < 0)
+ len = rp[3] + 4;
+ else
+ len = ((rp[2] << 8) + rp[3]) + 4;
+ if (len <= rlen) {
+ if (rlenp)
+ *rlenp = len;
+ return 0;
+ } else if (mxlen) {
+ if (rlenp)
+ *rlenp = rlen;
+ return 0;
+ }
+ if (len > MX_ALLOC_LEN) {
+ pr2serr("response length too long: %d > %d\n", len, MX_ALLOC_LEN);
+ return SG_LIB_CAT_MALFORMED;
+ } else {
+ res = pt_inquiry(sg_fd, 1, page, rp, len, &resid, 1, vb);
+ if (res)
+ return res;
+ rlen = len - resid;
+ /* assume it is well behaved: hence page and len still same */
+ if (rlenp)
+ *rlenp = rlen;
+ return 0;
+ }
}
static const struct svpd_values_name_t *
@@ -466,7 +760,7 @@
unsigned char * ucp;
if ((1 == do_hex) || (do_hex > 2)) {
- dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1);
+ dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1);
return;
}
if (len < 4) {
@@ -2236,7 +2530,7 @@
if (do_quiet) { ; } /* unused, dummy to suppress warning */
if ((! do_hex) && (! do_raw))
printf("Only hex output supported\n");
- if (!do_raw) {
+ if ((!do_raw) && (do_hex < 2)) {
if (subvalue)
printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", num_vpd,
subvalue);
@@ -2245,40 +2539,20 @@
else
printf("VPD page code=%d:\n", num_vpd);
}
- if (0 == alloc_len)
- alloc_len = DEF_ALLOC_LEN;
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len,
- 1, verbose);
+ if (sg_fd >= 0) {
+ if (0 == alloc_len)
+ alloc_len = DEF_ALLOC_LEN;
+ }
+
+ res = vpd_fetch_page_from_dev(sg_fd, rsp_buff, num_vpd, alloc_len,
+ verbose, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len, 1,
- verbose);
- if (res) {
- pr2serr("fetching VPD page (2) code=0x%.2x "
- " (alloc_len=%d) failed\n", num_vpd, len);
- return res;
- }
- } else {
- pr2serr("warning: response length (%d) longer than "
- "requested (%d)\n", len, maxlen);
- len = alloc_len;
- }
- }
if (do_raw)
dStrRaw((const char *)rsp_buff, len);
else {
- if (VPD_ASCII_OP_DEF == num_vpd)
+ if (do_hex > 1)
+ dStrHex((const char *)rsp_buff, len, -1);
+ else if (VPD_ASCII_OP_DEF == num_vpd)
dStrHex((const char *)rsp_buff, len, 0);
else
dStrHex((const char *)rsp_buff, len, (do_long ? 0 : 1));
@@ -2295,87 +2569,65 @@
/* Returns 0 if successful, else see sg_ll_inquiry() */
static int
-svpd_decode_t10(int sg_fd, int num_vpd, int subvalue, int maxlen, int do_hex,
- int do_raw, int do_long, int do_quiet, int verbose)
+svpd_decode_t10(int sg_fd, int pn, int subvalue, int maxlen, int do_hex,
+ int do_raw, int do_long, int do_quiet, int vb)
{
- int len, pdt, num, k, pn;
- char buff[48];
- const struct svpd_values_name_t * vnp;
+ int len, pdt, num, k, resid, alloc_len;
int res = 0;
- int alloc_len = maxlen;
+ char b[48];
+ const struct svpd_values_name_t * vnp;
char obuff[DEF_ALLOC_LEN];
+ unsigned char * rp;
-
- if (0 == alloc_len)
- alloc_len = (VPD_ATA_INFO == num_vpd) ?
- VPD_ATA_INFO_LEN : DEF_ALLOC_LEN;
- switch(num_vpd) {
+ rp = rsp_buff;
+ switch(pn) {
case VPD_NO_RATHER_STD_INQ: /* -2 (want standard inquiry response) */
- if (do_long)
- alloc_len = DEF_ALLOC_LEN;
- else if (0 == maxlen)
- alloc_len = 36;
- res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, alloc_len, 1,
- verbose);
+ if (sg_fd >= 0) {
+ if (maxlen > 0)
+ alloc_len = maxlen;
+ else if (do_long)
+ alloc_len = DEF_ALLOC_LEN;
+ else
+ alloc_len = 36;
+ res = pt_inquiry(sg_fd, 0, 0, rp, alloc_len, &resid, 1, vb);
+ } else {
+ alloc_len = maxlen;
+ resid = 0;
+ res = 0;
+ }
if (0 == res) {
+ alloc_len -= resid;
if (do_raw)
- dStrRaw((const char *)rsp_buff, alloc_len);
+ dStrRaw((const char *)rp, alloc_len);
else if (do_hex) {
if (! do_quiet && (do_hex < 3))
printf("Standard Inquiry reponse:\n");
- dStrHex((const char *)rsp_buff, alloc_len,
- (1 == do_hex) ? 0 : -1);
+ dStrHex((const char *)rp, alloc_len, (1 == do_hex) ? 0 : -1);
} else
- decode_std_inq(rsp_buff, alloc_len, verbose);
+ decode_std_inq(rp, alloc_len, vb);
return 0;
}
break;
case VPD_SUPPORTED_VPDS: /* 0x0 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Supported VPD pages VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; /* spc4r25 */
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Supported VPD pages "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else if (do_hex)
- dStrHex((const char *)rsp_buff, len, (1 == do_hex) ? 0 : -1);
+ dStrHex((const char *)rp, len, (1 == do_hex) ? 0 : -1);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- num = rsp_buff[3];
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ num = rp[3];
if (num > (len - 4))
num = (len - 4);
for (k = 0; k < num; ++k) {
- pn = rsp_buff[4 + k];
+ pn = rp[4 + k];
vnp = sdp_get_vpd_detail(pn, -1, pdt);
if (vnp) {
if (do_long)
@@ -2393,49 +2645,23 @@
case VPD_UNIT_SERIAL_NUM: /* 0x80 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Unit serial number VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; /* spc4r25 */
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Unit serial number page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else if (do_hex)
- dStrHex((const char *)rsp_buff, len, (1 == do_hex) ? 0 : -1);
+ dStrHex((const char *)rp, len, (1 == do_hex) ? 0 : -1);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
memset(obuff, 0, sizeof(obuff));
len -= 4;
if (len >= (int)sizeof(obuff))
len = sizeof(obuff) - 1;
- memcpy(obuff, rsp_buff + 4, len);
+ memcpy(obuff, rp + 4, len);
printf(" Unit serial number: %s\n", obuff);
}
return 0;
@@ -2444,45 +2670,19 @@
case VPD_DEVICE_ID: /* 0x83 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Device Identification VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Device Identification page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else if (do_hex)
- dStrHex((const char *)rsp_buff, len, (1 == do_hex) ? 0 : -1);
+ dStrHex((const char *)rp, len, (1 == do_hex) ? 0 : -1);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_id_vpd(rsp_buff, len, subvalue, do_long, do_quiet);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_id_vpd(rp, len, subvalue, do_long, do_quiet);
}
return 0;
}
@@ -2490,43 +2690,17 @@
case VPD_SOFTW_INF_ID: /* 0x84 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Software interface identification VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; /* spc4r25 */
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Software interface id page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_softw_inf_id(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_softw_inf_id(rp, len, do_hex);
}
return 0;
}
@@ -2534,90 +2708,38 @@
case VPD_MAN_NET_ADDR: /* 0x85 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Management network addresses VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Management network addresses page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else
- decode_net_man_vpd(rsp_buff, len, do_hex);
+ decode_net_man_vpd(rp, len, do_hex);
return 0;
}
break;
case VPD_EXT_INQ: /* 0x86 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("extended INQUIRY data VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; /* spc4r25 */
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Extended INQUIRY data page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
int protect = 0;
struct sg_simple_inquiry_resp sir;
if (do_long) {
- res = sg_simple_inquiry(sg_fd, &sir, 0, verbose);
+ res = sg_simple_inquiry(sg_fd, &sir, 0, vb);
if (res)
break;
protect = sir.byte_5 & 0x1; /* SPC-3 and later */
}
- pdt = rsp_buff[0] & 0x1f;
- if (verbose)
+ pdt = rp[0] & 0x1f;
+ if (vb)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_x_inq_vpd(rsp_buff, len, do_hex, do_long, protect);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_x_inq_vpd(rp, len, do_hex, do_long, protect);
}
return 0;
}
@@ -2625,43 +2747,17 @@
case VPD_MODE_PG_POLICY: /* 0x87 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Mode page policy VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Mode page policy page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_mode_policy_vpd(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_mode_policy_vpd(rp, len, do_hex);
}
return 0;
}
@@ -2669,44 +2765,17 @@
case VPD_SCSI_PORTS: /* 0x88 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("SCSI Ports VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching SCSI ports page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) "
- "longer than requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_scsi_ports_vpd(rsp_buff, len, do_hex, do_long,
- do_quiet);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_scsi_ports_vpd(rp, len, do_hex, do_long, do_quiet);
}
return 0;
}
@@ -2714,46 +2783,22 @@
case VPD_ATA_INFO: /* 0x89 */
if ((! do_raw) && (do_hex < 3) && (! do_quiet))
printf("ATA information VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ alloc_len = maxlen ? maxlen : VPD_ATA_INFO_LEN;
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, alloc_len, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching ATA info page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if ((2 == do_raw) || (3 == do_hex)) /* special for hdparm */
- dWordHex((const unsigned short *)(rsp_buff + 60),
+// xxxxxxxxxx check len is long enough
+ dWordHex((const unsigned short *)(rp + 60),
256, -2, sg_is_big_endian());
else if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_ata_info_vpd(rsp_buff, len, do_long, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_ata_info_vpd(rp, len, do_long, do_hex);
}
return 0;
}
@@ -2761,43 +2806,17 @@
case VPD_POWER_CONDITION: /* 0x8a */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Power condition VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching ATA info page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_power_condition(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_power_condition(rp, len, do_hex);
}
return 0;
}
@@ -2805,43 +2824,17 @@
case VPD_POWER_CONSUMPTION: /* 0x8d */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Power consumption VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Power consumption page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_power_consumption_vpd(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_power_consumption_vpd(rp, len, do_hex);
}
return 0;
}
@@ -2849,45 +2842,19 @@
case VPD_3PARTY_COPY: /* 0x8f */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Third party copy VPD page:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; /* spc4r25 */
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Third party copy page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else if (1 == do_hex)
- dStrHex((const char *)rsp_buff, len, 0);
+ dStrHex((const char *)rp, len, 0);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_3party_copy_vpd(rsp_buff, len, do_hex, verbose);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_3party_copy_vpd(rp, len, do_hex, vb);
}
return 0;
}
@@ -2895,43 +2862,17 @@
case VPD_PROTO_LU: /* 0x90 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Protocol-specific logical unit information:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Protocol-specific LU page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_proto_lu_vpd(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_proto_lu_vpd(rp, len, do_hex);
}
return 0;
}
@@ -2939,52 +2880,25 @@
case VPD_PROTO_PORT: /* 0x91 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Protocol-specific port information:\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Protocol-specific port page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_proto_port_vpd(rsp_buff, len, do_hex);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_proto_port_vpd(rp, len, do_hex);
}
return 0;
}
break;
case 0xb0: /* depends on pdt */
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- pdt = rsp_buff[0] & 0x1f;
+ pdt = rp[0] & 0x1f;
if ((! do_raw) && (! do_quiet) && (do_hex < 3)) {
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
@@ -3002,50 +2916,24 @@
break;
}
}
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching 0xb0 page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_b0_vpd(rsp_buff, len, do_hex, pdt);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_b0_vpd(rp, len, do_hex, pdt);
}
return 0;
- } else if (! do_raw)
+ } else if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("VPD page=0xb0\n");
break;
case 0xb1: /* depends on pdt */
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- pdt = rsp_buff[0] & 0x1f;
+ pdt = rp[0] & 0x1f;
if ((! do_raw) && (! do_quiet) && (do_hex < 3)) {
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
@@ -3067,50 +2955,23 @@
break;
}
}
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching 0xb1 page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_b1_vpd(rsp_buff, len, do_hex, pdt);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_b1_vpd(rp, len, do_hex, pdt);
}
return 0;
- } else if (! do_raw)
+ } else if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("VPD page=0xb1\n");
break;
case 0xb2: /* VPD page depends on pdt */
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- pdt = rsp_buff[0] & 0x1f;
+ pdt = rp[0] & 0x1f;
if ((! do_raw) && (! do_quiet) && (do_hex < 3)) {
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
@@ -3124,50 +2985,23 @@
break;
}
}
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching 0xb2 page "
- "(alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_b2_vpd(rsp_buff, len, do_hex, pdt);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_b2_vpd(rp, len, do_hex, pdt);
}
return 0;
- } else if (! do_raw)
+ } else if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("VPD page=0xb2\n");
break;
case 0xb3: /* VPD page depends on pdt */
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- pdt = rsp_buff[0] & 0x1f;
+ pdt = rp[0] & 0x1f;
if ((! do_raw) && (! do_quiet) && (do_hex < 3)) {
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
@@ -3182,87 +3016,35 @@
break;
}
}
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching VPD page 0x%x "
- "(alloc_len=%d) failed\n", num_vpd, len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
- decode_b3_vpd(rsp_buff, len, do_hex, pdt);
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
+ decode_b3_vpd(rp, len, do_hex, pdt);
}
return 0;
- } else if (! do_raw)
+ } else if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("VPD page=0xb3\n");
break;
case VPD_DTDE_ADDRESS: /* 0xb4 */
if ((! do_raw) && (! do_quiet) && (do_hex < 3))
printf("Data transfer device element address (SSC):\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, maxlen, vb, &len);
if (0 == res) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably a STANDARD INQUIRY "
- "response\n");
- if (verbose) {
- pr2serr("First 32 bytes of bad response\n");
- dStrHexErr((const char *)rsp_buff, 32, 0);
- }
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching Data transfer device element "
- "address page (alloc_len=%d) failed\n", len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ dStrRaw((const char *)rp, len);
else {
- pdt = rsp_buff[0] & 0x1f;
- if (verbose || do_long)
+ pdt = rp[0] & 0x1f;
+ if (vb || do_long)
printf(" [PQual=%d Peripheral device type: %s]\n",
- (rsp_buff[0] & 0xe0) >> 5,
- sg_get_pdt_str(pdt, sizeof(buff), buff));
+ (rp[0] & 0xe0) >> 5,
+ sg_get_pdt_str(pdt, sizeof(b), b));
printf(" Data transfer device element address: 0x");
for (k = 4; k < len; ++k)
- printf("%02x", (unsigned int)rsp_buff[k]);
+ printf("%02x", (unsigned int)rp[k]);
printf("\n");
}
return 0;
@@ -3278,10 +3060,11 @@
int
main(int argc, char * argv[])
{
- int sg_fd, c, res, matches;
+ int sg_fd, c, res, matches, inhex_len;
const char * device_name = NULL;
const struct svpd_values_name_t * vnp;
const char * page_str = NULL;
+ const char * inhex_fn = NULL;
const char * cp;
int num_vpd = 0;
int do_enum = 0;
@@ -3294,11 +3077,12 @@
int do_verbose = 0;
int ret = 0;
int subvalue = 0;
+ int page_pdt = -1;
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "ehHilm:p:qrvV", long_options,
+ c = getopt_long(argc, argv, "ehHiI:lm:p:qrvV", long_options,
&option_index);
if (c == -1)
break;
@@ -3317,6 +3101,14 @@
case 'i':
++do_ident;
break;
+ case 'I':
+ if (inhex_fn) {
+ pr2serr("only one '--inhex=' option permitted\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ inhex_fn = optarg;
+ break;
case 'l':
++do_long;
break;
@@ -3413,6 +3205,7 @@
}
num_vpd = vnp->value;
subvalue = vnp->subvalue;
+ page_pdt = vnp->pdt;
} else {
cp = strchr(page_str, ',');
num_vpd = sg_get_num_nomult(page_str);
@@ -3431,6 +3224,39 @@
}
}
}
+ if (inhex_fn) {
+ if (device_name) {
+ pr2serr("Cannot have both a DEVICE and --inhex= option\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (f2hex_arr(inhex_fn, 0, rsp_buff, &inhex_len, sizeof(rsp_buff)))
+ return SG_LIB_FILE_ERROR;
+ if (NULL == page_str) { /* may be able to deduce VPD page */
+ if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) {
+ if (do_verbose)
+ pr2serr("Guessing from --inhex= this is a standard "
+ "INQUIRY\n");
+ if (page_pdt < 0)
+ page_pdt = 0x1f & rsp_buff[0];
+ } else if (rsp_buff[2] <= 2) {
+ if (do_verbose)
+ pr2serr("Guessing from --inhex this is VPD page 0x%x\n",
+ rsp_buff[1]);
+ num_vpd = rsp_buff[1];
+ if (page_pdt < 0)
+ page_pdt = 0x1f & rsp_buff[0];
+ } else {
+ if (do_verbose)
+ pr2serr("page number unclear from --inhex, hope it's a "
+ "standard INQUIRY\n");
+ num_vpd = VPD_NO_RATHER_STD_INQ;
+ }
+ }
+ } else if (NULL == device_name) {
+ pr2serr("No DEVICE argument given\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
if (do_raw && do_hex) {
pr2serr("Can't do hex and raw at the same time\n");
@@ -3445,11 +3271,6 @@
subvalue = VPD_DI_SEL_LU;
}
}
- if (NULL == device_name) {
- pr2serr("No DEVICE argument given\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
if (do_raw) {
if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
perror("sg_set_binary_mode");
@@ -3457,6 +3278,20 @@
}
}
+ if (inhex_fn) {
+ res = svpd_decode_t10(-1, num_vpd, subvalue, inhex_len, do_hex,
+ do_raw, do_long, do_quiet, do_verbose);
+ if (SG_LIB_SYNTAX_ERROR == res) {
+ res = svpd_decode_vendor(-1, num_vpd, subvalue, inhex_len, do_hex,
+ do_raw, do_long, do_quiet, do_verbose);
+ if (SG_LIB_SYNTAX_ERROR == res)
+ res = svpd_unable_to_decode(-1, num_vpd, subvalue, inhex_len,
+ do_hex, do_raw, do_long, do_quiet,
+ do_verbose);
+ }
+ return res;
+ }
+
if ((sg_fd = sg_cmds_open_device(device_name, 1 /* ro */,
do_verbose)) < 0) {
pr2serr("error opening file: %s: %s\n", device_name,
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index 40bb3f5..67500cb 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -84,6 +84,9 @@
};
+int vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
+ int mxlen, int vb, int * rlenp);
+
/* Size of this array must match the array of the same name in sg_vpd.c */
static unsigned char rsp_buff[MX_ALLOC_LEN + 2];
@@ -933,37 +936,19 @@
strcpy(name, vnp->name);
else
snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", num_vpd);
- if (0 == alloc_len)
- alloc_len = DEF_ALLOC_LEN;
+ if (sg_fd >= 0) {
+ if (0 == alloc_len)
+ alloc_len = DEF_ALLOC_LEN;
+ }
if ((! do_raw) && (! do_quiet) && (do_hex < 2))
printf("%s VPD Page:\n", name);
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, alloc_len, 1,
- verbose);
+ res = vpd_fetch_page_from_dev(sg_fd, rsp_buff, num_vpd, alloc_len,
+ verbose, &len);
if (0 == res) {
- len = rsp_buff[3] + 4;
- if (num_vpd != rsp_buff[1]) {
- pr2serr("invalid VPD response; probably not supported\n");
- return SG_LIB_CAT_MALFORMED;
- }
- if (len > alloc_len) {
- if ((0 == maxlen) && (len < MX_ALLOC_LEN)) {
- res = sg_ll_inquiry(sg_fd, 0, 1, num_vpd, rsp_buff, len,
- 1, verbose);
- if (res) {
- pr2serr("fetching 0x%x page (alloc_len=%d) failed\n",
- num_vpd, len);
- return res;
- }
- } else {
- pr2serr(">>> warning: response length (%d) longer than "
- "requested (%d)\n", len, alloc_len);
- len = alloc_len;
- }
- }
if (do_raw)
dStrRaw((const char *)rsp_buff, len);
else if (do_hex)
- dStrHex((const char *)rsp_buff, len, 0);
+ dStrHex((const char *)rsp_buff, len, ((1 == do_hex) ? 0 : -1));
else {
switch(num_vpd) {
case 0xc0: