aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--doc/sg_modes.87
-rw-r--r--doc/sg_vpd.833
-rw-r--r--scripts/40-usb-blacklist.rules8
-rw-r--r--src/sg_dd.c22
-rw-r--r--src/sg_read.c18
-rw-r--r--src/sg_vpd.c453
-rw-r--r--src/sg_xcopy.c14
-rw-r--r--src/sgm_dd.c16
-rw-r--r--src/sgp_dd.c14
-rw-r--r--testing/sg_tst_async.cpp6
-rw-r--r--testing/sg_tst_ioctl.c8
-rw-r--r--testing/sgh_dd.cpp105
-rw-r--r--testing/sgs_dd.c20
-rw-r--r--testing/uapi_sg.h3
15 files changed, 494 insertions, 237 deletions
diff --git a/ChangeLog b/ChangeLog
index 19ac84c1..308990ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
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.45 [20190429] [svn: r820]
+Changelog for sg3_utils-1.45 [20190501] [svn: r821]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (spc5r20)
@@ -12,6 +12,7 @@ Changelog for sg3_utils-1.45 [20190429] [svn: r820]
- sg_format: add --dcrt used twice (FOV=1 DCRT=0)
- sg_raw: fix --send bug when using stdin
- sg_vpd: 3pc VPD page add copy group descriptor
+ - add --examine option
- sg_xcopy: add --fco (fast copy only) (spc5r20)
- implement --app=1 (append) on regular OFILE type
- sg_scan (win32): expand limits for big arrays
@@ -49,6 +50,7 @@ Changelog for sg3_utils-1.45 [20190429] [svn: r820]
- add sg_linux_get_sg_version() function
- add: 'SPDX-License-Identifier: BSD-2-Clause'
or a small number of 'GPL-2.0-or-later'
+ - gcc-9: suppress (pointless) warnings
Changelog for sg3_utils-1.44 [20180912] [svn: r791]
- same code as release 1.43 20180911 svn rev 789;
diff --git a/doc/sg_modes.8 b/doc/sg_modes.8
index ed2d2e33..d5cadc51 100644
--- a/doc/sg_modes.8
+++ b/doc/sg_modes.8
@@ -1,4 +1,4 @@
-.TH SG_MODES "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_MODES "8" "April 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_modes \- reads mode pages with SCSI MODE SENSE command
.SH SYNOPSIS
@@ -82,6 +82,9 @@ descriptors are present in the response or not, they are not output.
examine each mode page in the range 0 through to 62 (inclusive).
If some response is given then print out the mode page name or
number (in hex) if the name is not known.
+.br
+The sdparm utility which lists mode and VPD pages also has a \fB\-\-examine\fR
+option will similar functionility.
.TP
\fB\-f\fR, \fB\-\-flexible\fR
Some devices, bridges and/or drivers attempt crude translations between
@@ -298,7 +301,7 @@ Written by Douglas Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000\-2018 Douglas Gilbert
+Copyright \(co 2000\-201p Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sg_vpd.8 b/doc/sg_vpd.8
index 1bbdc7c2..08c371d9 100644
--- a/doc/sg_vpd.8
+++ b/doc/sg_vpd.8
@@ -1,12 +1,13 @@
-.TH SG_VPD "8" "March 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_VPD "8" "April 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_vpd \- fetch SCSI VPD page and/or decode its response
.SH SYNOPSIS
.B sg_vpd
-[\fI\-\-all\fR] [\fI\-\-enumerate\fR] [\fI\-\-force\fR] [\fI\-\-help\fR]
-[\fI\-\-hex\fR] [\fI\-\-ident\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-long\fR]
-[\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR]
-[\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR]
+[\fI\-\-all\fR] [\fI\-\-enumerate\fR] [\fI\-\-examine\fR] [\fI\-\-force\fR]
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR] [\fI\-\-inhex=FN\fR]
+[\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR]
+[\fI\-\-raw\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+[\fIDEVICE\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -25,8 +26,8 @@ has been flagged as mandatory. This page can be fetched by
using the \fI\-\-ident\fR option.
.PP
The reference document used for interpreting VPD pages (and the INQUIRY
-standard response) is T10/BSR INCITS 502 Revision 19 which is draft SPC\-5
-revision 19, 14 February 2018). It can be found at http://www.t10.org .
+standard response) is T10/BSR INCITS 502 Revision 22 which is draft SPC\-5
+revision 19, 22 April 2019. It can be 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.
@@ -60,6 +61,22 @@ summary lines of all VPD pages whose number matches \fIPG\fR. May be used
with \fI\-\-vendor=VP\fR to restrict output to known vendor specific pages
for vendor/product \fIVP\fR.
.TP
+\fB\-E\fR, \fB\-\-examine\fR
+scan part of all of the VPD space (from 0x0 to 0xff) and output any pages
+found. This option ignores the contents of VPD page 0x0 which should contain
+a list of all supported VPD pages. However some vendors either forget to
+list some standard pages or perhaps purposely don't list vendor specific
+pages which are in the range 0xc0 to 0xff.
+.br
+If the \fI\-\-page=PG\fR option is not given and this option is given once
+then the scan is from VPD page number 0x80 to 0xff inclusive. If the
+\fI\-\-page=PG\fR option is given then the scan is from 0x80 to
+\fIPG\fR inclusive. If this option is given twice then the scan starts at
+VPD page 0x0.
+.br
+The sdparm utility which lists mode and VPD pages also has a \fB\-\-examine\fR
+option will similar functionility.
+.TP
\fB\-f\fR, \fB\-\-force\fR
As a sanity check, the normal action when fetching VPD pages other than
page 0x0 (the "Supported VPD pages" VPD page), is to first fetch page 0x0
@@ -304,7 +321,7 @@ Written by Douglas Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2006\-2018 Douglas Gilbert
+Copyright \(co 2006\-2019 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/scripts/40-usb-blacklist.rules b/scripts/40-usb-blacklist.rules
index fd821f1e..6cce3e6b 100644
--- a/scripts/40-usb-blacklist.rules
+++ b/scripts/40-usb-blacklist.rules
@@ -3,8 +3,12 @@
#
# don't inquire sn and di on broken devices (https://bugzilla.suse.com/show_bug.cgi?id=840054)
+ACTION!="add|change", GOTO="usb_blacklist_end"
+KERNEL!="sd*[!0-9]|sr*", GOTO="usb_blacklist_end"
+
# unkown device
-ATTRS{idVendor}=="0aec", ATTRS{idProduct}=="3260", ENV{ID_SCSI_DI}="1"
+ATTRS{idVendor}=="0aec", ATTRS{idProduct}=="3260", ENV{ID_SCSI_INQUIRY}="1"
# Sony/JMicron port replicator
-ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06a0", ENV{ID_SCSI_DI}="1"
+ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06a0", ENV{ID_SCSI_INQUIRY}="1"
+LABEL="usb_blacklist_end"
diff --git a/src/sg_dd.c b/src/sg_dd.c
index 0dadc6c0..a005ad28 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -1,7 +1,7 @@
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
- * Copyright (C) 1999 - 2018 D. Gilbert and P. Allworth
+ * Copyright (C) 1999 - 2019 D. Gilbert and P. Allworth
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -66,7 +66,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "6.05 20181213";
+static const char * version_str = "6.06 20190501";
#define ME "sg_dd: "
@@ -1609,8 +1609,10 @@ main(int argc, char * argv[])
if ('\0' != inf[0]) {
pr2serr("Second IFILE argument??\n");
return SG_LIB_SYNTAX_ERROR;
- } else
- strncpy(inf, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(inf, buf, INOUTF_SZ - 1);
+ inf[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &iflag)) {
pr2serr(ME "bad argument to 'iflag='\n");
@@ -1625,14 +1627,18 @@ main(int argc, char * argv[])
if ('\0' != outf[0]) {
pr2serr("Second OFILE argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(outf, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(outf, buf, INOUTF_SZ - 1);
+ outf[INOUTF_SZ - 1] = '\0';
+ }
} else if (strcmp(key, "of2") == 0) {
if ('\0' != out2f[0]) {
pr2serr("Second OFILE2 argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(out2f, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(out2f, buf, INOUTF_SZ - 1);
+ out2f[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &oflag)) {
pr2serr(ME "bad argument to 'oflag='\n");
diff --git a/src/sg_read.c b/src/sg_read.c
index a356aa35..0c6b9825 100644
--- a/src/sg_read.c
+++ b/src/sg_read.c
@@ -1,6 +1,6 @@
/*
* A utility program for the Linux OS SCSI generic ("sg") device driver.
- * Copyright (C) 2001 - 2018 D. Gilbert
+ * Copyright (C) 2001 - 2019 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -58,7 +58,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.34 20180811";
+static const char * version_str = "1.35 20190501";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -491,17 +491,19 @@ main(int argc, char * argv[])
dpo = !! sg_get_num(buf);
else if (0 == strcmp(key,"fua"))
fua = !! sg_get_num(buf);
- else if (strcmp(key,"if") == 0)
- strncpy(inf, buf, INF_SZ - 1);
- else if (0 == strcmp(key,"mmap"))
+ else if (strcmp(key,"if") == 0) {
+ memcpy(inf, buf, INF_SZ - 1);
+ inf[INF_SZ - 1] = '\0';
+ } else if (0 == strcmp(key,"mmap"))
do_mmap = !! sg_get_num(buf);
else if (0 == strcmp(key,"no_dxfer"))
no_dxfer = !! sg_get_num(buf);
else if (0 == strcmp(key,"odir"))
do_odir = !! sg_get_num(buf);
- else if (strcmp(key,"of") == 0)
- strncpy(outf, buf, INF_SZ - 1);
- else if (0 == strcmp(key,"skip")) {
+ else if (strcmp(key,"of") == 0) {
+ memcpy(outf, buf, INF_SZ - 1);
+ outf[INF_SZ - 1] = '\0';
+ } else if (0 == strcmp(key,"skip")) {
skip = sg_get_llnum(buf);
if (-1 == skip) {
pr2serr( ME "bad argument to 'skip'\n");
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 45a6e176..bf5c448f 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.52 20190210"; /* spc5r20 + sbc4r15 */
+static const char * version_str = "1.53 20190429"; /* spc5r20 + sbc4r15 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -113,12 +113,13 @@ struct opts_t {
bool verbose_given;
bool version_given;
int do_hex;
- int vpd_pn;
int do_ident;
- int maxlen;
int do_raw;
+ int examine;
+ int maxlen;
int vend_prod_num;
int verbose;
+ int vpd_pn;
const char * device_name;
const char * page_str;
const char * inhex_fn;
@@ -148,7 +149,7 @@ 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);
static int svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue,
- int off);
+ int off, const char * prefix);
static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue,
int off);
@@ -164,6 +165,7 @@ static uint8_t * free_rsp_buff;
static struct option long_options[] = {
{"all", no_argument, 0, 'a'},
{"enumerate", no_argument, 0, 'e'},
+ {"examine", no_argument, 0, 'E'},
{"force", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
@@ -246,12 +248,13 @@ static struct svpd_values_name_t standard_vpd_pg[] = {
static void
usage()
{
- pr2serr("Usage: sg_vpd [--all] [--enumerate] [--force] [--help] [--hex] "
- "[--ident]\n"
- " [--inhex=FN] [--long] [--maxlen=LEN] "
- "[--page=PG] [--quiet]\n"
- " [--raw] [--vendor=VP] [--verbose] [--version] "
- "DEVICE\n");
+ pr2serr("Usage: sg_vpd [--all] [--enumerate] [--examine] [--force] "
+ "[--help] [--hex]\n"
+ " [--ident] [--inhex=FN] [--long] [--maxlen=LEN] "
+ "[--page=PG]\n"
+ " [--quiet] [--raw] [--vendor=VP] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n");
pr2serr(" where:\n"
" --all|-a output all pages listed in the supported "
"pages VPD\n"
@@ -259,6 +262,7 @@ usage()
" --enumerate|-e enumerate known VPD pages names (ignore "
"DEVICE),\n"
" can be used with --page=num to search\n"
+ " --examine|-E starting at 0x80 scan pages code to 0xff\n"
" --force|-f skip VPD page 0 (supported VPD pages) "
"checking\n"
" --help|-h output this usage message then exit\n"
@@ -293,7 +297,7 @@ usage()
"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' or '-p sinq' yields the standard "
- "INQUIRY response.\n");
+ "INQUIRY response.\n");
}
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
@@ -1532,7 +1536,7 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op)
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, 0, off);
+ res = svpd_decode_t10(-1, op, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, off);
if (SG_LIB_CAT_OTHER == res)
@@ -2822,9 +2826,9 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
uint8_t * rp;
rp = rsp_buff + off;
- if ((! op->do_hex) && (! op->do_raw))
+ if ((! op->do_hex) && (! op->do_raw) && (0 == op->examine))
printf("Only hex output supported\n");
- if ((!op->do_raw) && (op->do_hex < 2)) {
+ if ((!op->do_raw) && (op->do_hex < 2) && (0 == op->examine)) {
if (subvalue)
printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn,
subvalue);
@@ -2849,7 +2853,7 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
else
hex2stdout(rp, len, 0);
}
- } else if (! op->do_quiet) {
+ } else if ((! op->do_quiet) && (0 == op->examine)) {
if (op->vpd_pn >= 0)
pr2serr("fetching VPD page code=0x%.2x: failed\n", op->vpd_pn);
else
@@ -2861,14 +2865,17 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
/* Returns 0 if successful. If don't know how to decode, returns
* SG_LIB_CAT_OTHER else see sg_ll_inquiry(). */
static int
-svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
+svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off,
+ const char * prefix)
{
- bool allow_name, long_notquiet, qt;
+ bool allow_name, allow_if_found, long_notquiet, qt;
bool vpd_supported = false;
int len, pdt, num, k, resid, alloc_len, pn, vb;
int res = 0;
const struct svpd_values_name_t * vnp;
uint8_t * rp;
+ const char * np;
+ const char * pre = (prefix ? prefix : "");;
char obuff[DEF_ALLOC_LEN];
char b[48];
@@ -2876,13 +2883,15 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
qt = op->do_quiet;
long_notquiet = op->do_long && (! op->do_quiet);
if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) ||
- (op->do_hex >= 3))
+ (op->do_hex >= 3) || (op->examine > 0))
allow_name = false;
else
allow_name = true;
+ allow_if_found = (op->examine > 0) && (! op->do_quiet);
rp = rsp_buff + off;
pn = (-1 == sg_fd) ? rp[1] : op->vpd_pn;
if (sg_fd != -1 && !op->do_force &&
+ 0 == op->examine &&
pn != VPD_NOPE_WANT_STD_INQ &&
pn != VPD_SUPPORTED_VPDS) {
res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt,
@@ -2940,10 +2949,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_SUPPORTED_VPDS: /* 0x0 */
+ np = "Supported VPD pages VPD page:";
if (allow_name)
- printf("Supported VPD pages VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -2984,10 +2996,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_UNIT_SERIAL_NUM: /* 0x80 */
+ np = "Unit serial number VPD page:";
if (allow_name)
- printf("Unit serial number VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -3009,10 +3024,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_DEVICE_ID: /* 0x83 */
+ np = "Device Identification VPD page:";
if (allow_name)
- printf("Device Identification VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
@@ -3029,10 +3047,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_SOFTW_INF_ID: /* 0x84 */
+ np = "Software interface identification VPD page:";
if (allow_name)
- printf("Software interface identification VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3047,10 +3068,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_MAN_NET_ADDR: /* 0x85 */
+ np= "Management network addresses VPD page:";
if (allow_name)
- printf("Management network addresses VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else
@@ -3059,10 +3083,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_EXT_INQ: /* 0x86 */
+ np = "extended INQUIRY data VPD page:";
if (allow_name)
- printf("extended INQUIRY data VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3089,10 +3116,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_MODE_PG_POLICY: /* 0x87 */
+ np = "Mode page policy VPD page:";
if (allow_name)
- printf("Mode page policy VPD page:\n");
+ printf("%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", (prefix ? prefix : ""), np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3107,10 +3137,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_SCSI_PORTS: /* 0x88 */
+ np = "SCSI Ports VPD page:";
if (allow_name)
- printf("SCSI Ports VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3125,11 +3158,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_ATA_INFO: /* 0x89 */
+ np = "ATA information VPD page:";
if (allow_name)
- printf("ATA information VPD page:\n");
+ printf("%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)
+ printf("%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 "
@@ -3152,10 +3188,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_POWER_CONDITION: /* 0x8a */
+ np = "Power condition VPD page:";
if (allow_name)
- printf("Power condition VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3170,10 +3209,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_DEVICE_CONSTITUENTS: /* 0x8b */
+ np = "Device constituents VPD page:";
if (allow_name)
- printf("Device constituents VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else
@@ -3182,10 +3224,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_POWER_CONSUMPTION: /* 0x8d */
+ np = "Power consumption VPD page:";
if (allow_name)
- printf("Power consumption VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3200,10 +3245,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_3PARTY_COPY: /* 0x8f */
+ np = "Third party copy VPD page:";
if (allow_name)
- printf("Third party copy VPD page:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else if (1 == op->do_hex)
@@ -3220,10 +3268,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_PROTO_LU: /* 0x90 */
+ np = "Protocol-specific logical unit information:";
if (allow_name)
- printf("Protocol-specific logical unit information:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3238,10 +3289,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_PROTO_PORT: /* 0x91 */
+ np = "Protocol-specific port information:";
if (allow_name)
- printf("Protocol-specific port information:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3256,10 +3310,13 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
}
break;
case VPD_SCSI_FEATURE_SETS: /* 0x92 */
+ np = "SCSI Feature sets:";
if (allow_name)
- printf("SCSI Feature sets:\n");
+ printf("%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);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3277,23 +3334,24 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Block limits VPD page (SBC):\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Sequential-access device capabilities VPD page "
- "(SSC):\n");
- break;
- case PDT_OSD:
- printf("OSD information VPD page (OSD):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block limits VPD page (SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Sequential-access device capabilities VPD page (SSC):";
+ break;
+ case PDT_OSD:
+ np = "OSD information VPD page (OSD):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3305,34 +3363,35 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b0_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb0\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb0\n", pre);
break;
case 0xb1: /* depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Block device characteristics VPD 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 page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics VPD page (SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Manufactured-assigned serial number VPD page (SSC):";
+ break;
+ case PDT_OSD:
+ np = "Security token VPD page (OSD):";
+ break;
+ case PDT_ADC:
+ np = "Manufactured-assigned serial number VPD page (ADC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3343,26 +3402,29 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b1_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb1\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb1\n", pre);
break;
case 0xb2: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Logical block provisioning VPD page (SBC):\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("TapeAlert supported flags VPD page (SSC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Logical block provisioning VPD page (SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "TapeAlert supported flags VPD page (SSC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3373,27 +3435,29 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b2_vpd(rp, len, pdt, op);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb2\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb2\n", pre);
break;
case 0xb3: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Referrals VPD page (SBC):\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Automation device serial number VPD page "
- "(SSC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Referrals VPD page (SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Automation device serial number VPD page SSC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3404,27 +3468,30 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b3_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb3\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb3\n", pre);
break;
case 0xb4: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Supported block lengths and protection types "
- "VPD page (SBC):\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Data transfer device element address (SSC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Supported block lengths and protection types VPD page "
+ "(SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Data transfer device element address (SSC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3435,27 +3502,29 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b4_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb4\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb4\n", pre);
break;
case 0xb5: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Block device characteristics extension VPD page "
- "(SBC):\n");
- break;
- case PDT_TAPE: case PDT_MCHANGER:
- printf("Logical block protection VPD page (SSC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block device characteristics extension VPD page (SBC):";
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Logical block protection VPD page (SSC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3466,24 +3535,27 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b5_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb5\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb4\n", pre);
break;
case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Zoned block device characteristics VPD page "
- "(SBC, ZBC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Zoned block device characteristics VPD page (SBC, "
+ "ZBC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3494,23 +3566,26 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_zbdc_vpd(rp, len, op->do_hex);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb5\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb5\n", pre);
break;
case 0xb7:
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
pdt = rp[0] & 0x1f;
- if (allow_name) {
- switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- printf("Block limits extension VPD page (SBC):\n");
- break;
- default:
- printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
- break;
- }
+ switch (pdt) {
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ np = "Block limits extension VPD page (SBC):";
+ break;
+ default:
+ np = NULL;
+ break;
}
+ if (NULL == np)
+ printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else if (allow_name || allow_if_found)
+ printf("%s%s\n", pre, np);
if (op->do_raw)
dStrRaw(rp, len);
else {
@@ -3522,8 +3597,9 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
decode_b7_vpd(rp, len, op->do_hex, pdt);
}
return 0;
- } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
- printf("VPD page=0xb7\n");
+ } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
+ (0 == op->examine))
+ printf("%sVPD page=0xb7\n", pre);
break;
default:
return SG_LIB_CAT_OTHER;
@@ -3576,7 +3652,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
if (op->do_long)
printf("[0x%x] ", pn);
- res = svpd_decode_t10(sg_fd, op, 0, 0);
+ res = svpd_decode_t10(sg_fd, op, 0, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(sg_fd, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -3627,7 +3703,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
if (op->do_long)
printf("[0x%x] ", pn);
- res = svpd_decode_t10(-1, op, 0, off);
+ res = svpd_decode_t10(-1, op, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, off);
if (SG_LIB_CAT_OTHER == res)
@@ -3638,6 +3714,54 @@ svpd_decode_all(int sg_fd, struct opts_t * op)
return res;
}
+static int
+svpd_examine_all(int sg_fd, struct opts_t * op)
+{
+ bool first = true;
+ bool got_one = false;
+ int k, res;
+ int max_pn = 255;
+ int any_err = 0;
+ char b[64];
+
+ if (op->vpd_pn > 0)
+ max_pn = op->vpd_pn;
+ for (k = op->examine > 1 ? 0 : 0x80; k <= max_pn; ++k) {
+ op->vpd_pn = k;
+ if (first)
+ first = false;
+ else if (got_one) {
+ printf("\n");
+ got_one = false;
+ }
+ if (op->do_long)
+ snprintf(b, sizeof(b), "[0x%x] ", k);
+
+ res = svpd_decode_t10(sg_fd, op, 0, 0, b);
+ if (SG_LIB_CAT_OTHER == res) {
+ res = svpd_decode_vendor(sg_fd, op, 0);
+ if (SG_LIB_CAT_OTHER == res)
+ res = svpd_unable_to_decode(sg_fd, op, 0, 0);
+ }
+ if (! op->do_quiet) {
+ if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ pr2serr("fetching VPD page failed, aborted command\n");
+ else if (res && (SG_LIB_CAT_ILLEGAL_REQ != res)) {
+ char b[80];
+
+ /* SG_LIB_CAT_ILLEGAL_REQ expected as well examine all */
+ sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
+ pr2serr("fetching VPD page failed: %s\n", b);
+ }
+ }
+ if (res && (SG_LIB_CAT_ILLEGAL_REQ != res))
+ any_err = res;
+ if (0 == res)
+ got_one = true;
+ }
+ return any_err;
+}
+
int
main(int argc, char * argv[])
@@ -3659,7 +3783,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "aefhHiI:lm:M:p:qrvV", long_options,
+ c = getopt_long(argc, argv, "aeEfhHiI:lm:M:p:qrvV", long_options,
&option_index);
if (c == -1)
break;
@@ -3671,6 +3795,9 @@ main(int argc, char * argv[])
case 'e':
op->do_enum = true;
break;
+ case 'E':
+ ++op->examine;
+ break;
case 'f':
op->do_force = true;
break;
@@ -3979,7 +4106,7 @@ main(int argc, char * argv[])
if (op->do_all)
res = svpd_decode_all(-1, op);
else {
- res = svpd_decode_t10(-1, op, subvalue, 0);
+ res = svpd_decode_t10(-1, op, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(-1, op, 0);
if (SG_LIB_CAT_OTHER == res)
@@ -4001,12 +4128,14 @@ main(int argc, char * argv[])
goto err_out;
}
- if (op->do_all)
+ if (op->examine > 0) {
+ ret = svpd_examine_all(sg_fd, op);
+ } else if (op->do_all)
ret = svpd_decode_all(sg_fd, op);
else {
memset(rsp_buff, 0, rsp_buff_sz);
- res = svpd_decode_t10(sg_fd, op, subvalue, 0);
+ res = svpd_decode_t10(sg_fd, op, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
res = svpd_decode_vendor(sg_fd, op, 0);
if (SG_LIB_CAT_OTHER == res)
diff --git a/src/sg_xcopy.c b/src/sg_xcopy.c
index c0b53a88..984dda5d 100644
--- a/src/sg_xcopy.c
+++ b/src/sg_xcopy.c
@@ -69,7 +69,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "0.69 20190120";
+static const char * version_str = "0.70 20190501";
#define ME "sg_xcopy: "
@@ -1428,8 +1428,10 @@ main(int argc, char * argv[])
if ('\0' != ixcf.fname[0]) {
pr2serr("Second IFILE argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(ixcf.fname, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(ixcf.fname, buf, INOUTF_SZ - 1);
+ ixcf.fname[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &ixcf)) {
pr2serr(ME "bad argument to 'iflag='\n");
@@ -1441,8 +1443,10 @@ main(int argc, char * argv[])
if ('\0' != oxcf.fname[0]) {
pr2serr("Second OFILE argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(oxcf.fname, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(oxcf.fname, buf, INOUTF_SZ - 1);
+ oxcf.fname[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &oxcf)) {
pr2serr(ME "bad argument to 'oflag='\n");
diff --git a/src/sgm_dd.c b/src/sgm_dd.c
index 76bba41d..03f1a4c5 100644
--- a/src/sgm_dd.c
+++ b/src/sgm_dd.c
@@ -1,7 +1,7 @@
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
- * Copyright (C) 1999 - 2018 D. Gilbert and P. Allworth
+ * Copyright (C) 1999 - 2019 D. Gilbert and P. Allworth
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -69,7 +69,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.61 20181030";
+static const char * version_str = "1.62 20190501";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -812,8 +812,10 @@ main(int argc, char * argv[])
if ('\0' != inf[0]) {
pr2serr("Second 'if=' argument??\n");
return SG_LIB_CONTRADICT;
- } else
- snprintf(inf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(inf, buf, INOUTF_SZ);
+ inf[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &in_flags)) {
pr2serr(ME "bad argument to 'iflag'\n");
@@ -823,8 +825,10 @@ main(int argc, char * argv[])
if ('\0' != outf[0]) {
pr2serr("Second 'of=' argument??\n");
return SG_LIB_CONTRADICT;
- } else
- snprintf(outf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(outf, buf, INOUTF_SZ);
+ outf[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &out_flags)) {
pr2serr(ME "bad argument to 'oflag'\n");
diff --git a/src/sgp_dd.c b/src/sgp_dd.c
index 9321b9af..5b0cfaa4 100644
--- a/src/sgp_dd.c
+++ b/src/sgp_dd.c
@@ -68,7 +68,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "5.72 20190324";
+static const char * version_str = "5.72 20190501";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -1263,8 +1263,10 @@ main(int argc, char * argv[])
if ('\0' != inf[0]) {
pr2serr("Second 'if=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
- } else
- snprintf(inf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(inf, buf, INOUTF_SZ);
+ inf[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &clp->in_flags)) {
pr2serr("%sbad argument to 'iflag='\n", my_name);
@@ -1280,8 +1282,10 @@ main(int argc, char * argv[])
if ('\0' != outf[0]) {
pr2serr("Second 'of=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
- } else
- snprintf(outf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(outf, buf, INOUTF_SZ);
+ outf[INOUTF_SZ - 1] = '\0';
+ }
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &clp->out_flags)) {
pr2serr("%sbad argument to 'oflag='\n", my_name);
diff --git a/testing/sg_tst_async.cpp b/testing/sg_tst_async.cpp
index 8638ceec..c1067d0b 100644
--- a/testing/sg_tst_async.cpp
+++ b/testing/sg_tst_async.cpp
@@ -217,7 +217,7 @@ struct opts_t {
myQDiscipline myqd; /* --qfav= value (def: 2 --> MYQD_HIGH) */
};
-static struct opts_t a_opts;
+static struct opts_t a_opts; /* Expect zero fill on simple types */
#if 0
class Rand_uint {
@@ -1685,7 +1685,9 @@ main(int argc, char * argv[])
const char * dev_name;
op = &a_opts;
- memset(op, 0, sizeof(*op));
+#if 0
+ memset(op, 0, sizeof(*op)); // C++ doesn't like this
+#endif
op->direct = DEF_DIRECT;
op->lba = DEF_LBA;
op->hi_lba = 0;
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index 063fe94a..2dd23c2d 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -56,7 +56,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 1.08 20190419";
+static const char * version_str = "Version: 1.09 20190430";
#define INQ_REPLY_LEN 128
#define INQ_CMD_LEN 6
@@ -256,7 +256,10 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_UNSHARE;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_MASTER_FINI;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_MASTER_ERR;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
+ seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_NO_DURATION;
seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -301,6 +304,9 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
if (SG_CTL_FLAGM_MASTER_ERR & seip->ctl_flags_rd_mask)
printf(" %sMASTER_ERR: %s\n", cp,
(SG_CTL_FLAGM_MASTER_ERR & cflags) ? "true" : "false");
+ if (SG_CTL_FLAGM_NO_DURATION & seip->ctl_flags_rd_mask)
+ printf(" %sNO_DURATION: %s\n", cp,
+ (SG_CTL_FLAGM_NO_DURATION & cflags) ? "true" : "false");
}
if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask)
printf(" %sminor_index: %u\n", cp, seip->minor_index);
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 27438036..2fefc2c2 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -103,7 +103,7 @@
using namespace std;
-static const char * version_str = "1.28 20190419";
+static const char * version_str = "1.29 20190430";
#ifdef __GNUC__
#ifndef __clang__
@@ -162,6 +162,7 @@ struct flags_t {
bool excl;
bool fua;
bool mmap;
+ bool no_dur;
bool noshare;
bool noxfer;
bool same_fds;
@@ -249,6 +250,7 @@ typedef struct request_element
int cdbsz_in;
int cdbsz_out;
int aen;
+ int rd_p_id;
int rep_count;
int rq_id;
int mmap_len;
@@ -592,7 +594,9 @@ dd_filetype(const char * filename)
static void
usage(int pg_num)
{
- if (pg_num > 2)
+ if (pg_num > 3)
+ goto page4;
+ else if (pg_num > 2)
goto page3;
else if (pg_num > 1)
goto page2;
@@ -636,7 +640,8 @@ usage(int pg_num)
"specialized for\nSCSI devices and uses multiple POSIX threads. "
"It expects one or both IFILE\nand OFILE to be sg devices. It "
"is Linux specific and uses the v4 sg driver\n'share' capability "
- "if available. Use '-hh' or '-hhh' for more information.\n"
+ "if available. Use '-hh', '-hhh' or '-hhhh' for more\n"
+ "information.\n"
#ifdef SGH_DD_READ_COMPLET_AFTER
"\nIn this version oflag=swait does read completion _after_ "
"write completion\n"
@@ -680,7 +685,7 @@ page2:
" verbose same as 'deb=VERB': increase verbosity\n"
" --dry-run|-d prepare but bypass copy/read\n"
" --verbose|-v increase verbosity of utility\n\n"
- "Use '-hhh' for more information about flags.\n"
+ "Use '-hhh' or '-hhhh' for more information about flags.\n"
);
return;
page3:
@@ -701,6 +706,7 @@ page3:
"and WRITEs\n"
" mmap setup mmap IO on IFILE or OFILE; OFILE only "
"with noshare\n"
+ " nodur turns off command duration calculations\n"
" noshare if IFILE and OFILE are sg devices, don't set "
"up sharing\n"
" (def: do)\n"
@@ -722,8 +728,38 @@ page3:
"'noshare' is given to 'iflag=' or\n'oflag='. of2=OFILE2 uses "
"'oflag=FLAGS'. When sharing, the data stays in a\nsingle "
"in-kernel buffer which is copied (or mmap-ed) to the user "
- "space\nif the 'ofreg=OFREG' is given.\n"
+ "space\nif the 'ofreg=OFREG' is given. Use '-hhhh' for more "
+ "information.\n"
);
+ return;
+page4:
+ pr2serr("pack_id:\n"
+ "These are ascending integers, starting at 1, associated with "
+ "each issued\nSCSI command. When both IFILE and OFILE are sg "
+ "devices, then the READ in\neach read-write pair is issued an "
+ "even pack_id and its WRITE pair is\ngiven the pack_id one "
+ "higher (i.e. an odd number). This enables a\n'cat '"
+ "/proc/scsi/sg/debug' user to see associated commands.\n\n");
+ pr2serr("Debugging:\n"
+ "Apart from using one or more '--verbose' options which gets a "
+ "bit noisy\n'cat /proc/scsi/sg/debug' can give a good overview "
+ "of what is happening.\nThat does a sg driver object tree "
+ "traversal that does minimal locking\nto make sure that each "
+ "traversal is 'safe'. So it is important to note\nthe whole "
+ "tree is not locked. This means for fast devices the overall\n"
+ "tree state may change while the traversal is occurring. For "
+ "example,\nit has been observed that both the master and slave "
+ "sides of a request\nshare show they are in 'active' state "
+ "which should not be possible.\nIt occurs because the master "
+ "probably jumped out of active state and\nthe slave request "
+ "entered it while some other nodes were being printed.\n\n");
+ pr2serr("Busy state:\n"
+ "Busy state (abreviated to 'bsy' in the /proc/scsi/sg/debug "
+ "output)\nis entered during request setup and completion. It "
+ "is intended to be\na temporary state. It should not block "
+ "but does sometimes (e.g. in\nblock_get_request()). Even so "
+ "that block should be short and\nif not there is a problem.\n");
+ return;
}
static void
@@ -1695,7 +1731,15 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
cp = (wr ? " slave active" : " master active");
} else
cp = (wr ? " slave not sharing" : " master not sharing");
- pack_id = atomic_fetch_add(&mono_pack_id, 1); /* fetch before */
+ if (rep->both_sg) {
+ if (wr)
+ pack_id = rep->rd_p_id + 1;
+ else {
+ pack_id = 2 * atomic_fetch_add(&mono_pack_id, 1);
+ rep->rd_p_id = pack_id;
+ }
+ } else
+ pack_id = atomic_fetch_add(&mono_pack_id, 1); /* fetch before */
rep->rq_id = pack_id;
if (rep->debug > 3) {
pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s%s%s, blk=%" PRId64
@@ -2110,7 +2154,7 @@ write_complet:
/* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
static int
sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
- bool unit_nano, uint8_t **mmpp)
+ bool unit_nano, bool no_dur, uint8_t **mmpp)
{
int res, t, num;
uint8_t *mmp;
@@ -2126,6 +2170,12 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
if (elem_sz >= 4096) {
memset(seip, 0, sizeof(*seip));
seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
+ if (no_dur) {
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
+ }
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd "
@@ -2139,6 +2189,15 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) "
"wr error: %s\n", __func__, strerror(errno));
}
+ } else if (no_dur) {
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
+ res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
+ if (res < 0)
+ pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(NO_DURATION) "
+ "error: %s\n", __func__, strerror(errno));
}
if (! def_res) {
num = bs * bpt;
@@ -2211,6 +2270,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->fua = true;
else if (0 == strcmp(cp, "mmap"))
fp->mmap = true;
+ else if (0 == strcmp(cp, "nodur"))
+ fp->no_dur = true;
else if (0 == strcmp(cp, "noshare"))
fp->noshare = true;
else if (0 == strcmp(cp, "noxfer"))
@@ -2271,7 +2332,8 @@ sg_in_open(Gbl_coll *clp, const char *inf, uint8_t **mmpp, int * mmap_lenp)
return -sg_convert_errno(err);
}
n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->in_flags.defres,
- clp->elem_sz, clp->unit_nanosec, mmpp);
+ clp->elem_sz, clp->unit_nanosec,
+ clp->in_flags.no_dur, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -2301,7 +2363,8 @@ sg_out_open(Gbl_coll *clp, const char *outf, uint8_t **mmpp, int * mmap_lenp)
return -sg_convert_errno(err);
}
n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->out_flags.defres,
- clp->elem_sz, clp->unit_nanosec, mmpp);
+ clp->elem_sz, clp->unit_nanosec,
+ clp->out_flags.no_dur, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -2445,8 +2508,10 @@ main(int argc, char * argv[])
if ('\0' != inf[0]) {
pr2serr("Second 'if=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
- } else
- snprintf(inf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(inf, buf, INOUTF_SZ);
+ inf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
+ }
} else if (0 == strcmp(key, "iflag")) {
if (! process_flags(buf, &clp->in_flags)) {
pr2serr("%sbad argument to 'iflag='\n", my_name);
@@ -2472,20 +2537,26 @@ main(int argc, char * argv[])
if ('\0' != out2f[0]) {
pr2serr("Second OFILE2 argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(out2f, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(out2f, buf, INOUTF_SZ);
+ out2f[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
+ }
} else if (strcmp(key, "ofreg") == 0) {
if ('\0' != outregf[0]) {
pr2serr("Second OFREG argument??\n");
return SG_LIB_CONTRADICT;
- } else
- strncpy(outregf, buf, INOUTF_SZ - 1);
+ } else {
+ memcpy(outregf, buf, INOUTF_SZ);
+ outregf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
+ }
} else if (strcmp(key, "of") == 0) {
if ('\0' != outf[0]) {
pr2serr("Second 'of=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
- } else
- snprintf(outf, INOUTF_SZ, "%s", buf);
+ } else {
+ memcpy(outf, buf, INOUTF_SZ);
+ outf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
+ }
} else if (0 == strcmp(key, "oflag")) {
if (! process_flags(buf, &clp->out_flags)) {
pr2serr("%sbad argument to 'oflag='\n", my_name);
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index d4dabcab..f806e610 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -78,7 +78,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "4.05 20190412";
+static const char * version_str = "4.06 20190501";
static const char * my_name = "sgs_dd";
#define DEF_BLOCK_SIZE 512
@@ -106,8 +106,8 @@ static const char * my_name = "sgs_dd";
#define STR_SZ 1024
-#define INOUTF_SZ 512
-#define EBUFF_SZ 512
+#define INOUTF_SZ 900
+#define EBUFF_SZ 1024
struct flags_t {
bool dio;
@@ -972,18 +972,20 @@ main(int argc, char * argv[])
clp->debug = sg_get_num(buf);
else if (0 == strcmp(key,"ibs"))
ibs = sg_get_num(buf);
- else if (strcmp(key,"if") == 0)
- strncpy(inf, buf, INOUTF_SZ);
- else if (0 == strcmp(key, "iflag")) {
+ else if (strcmp(key,"if") == 0) {
+ memcpy(inf, buf, INOUTF_SZ);
+ inf[INOUTF_SZ - 1] = '\0';
+ } else if (0 == strcmp(key, "iflag")) {
if (! process_flags(buf, &clp->iflag)) {
pr2serr("%sbad argument to 'iflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"obs"))
obs = sg_get_num(buf);
- else if (strcmp(key,"of") == 0)
- strncpy(outf, buf, INOUTF_SZ);
- else if (0 == strcmp(key, "oflag")) {
+ else if (strcmp(key,"of") == 0) {
+ memcpy(outf, buf, INOUTF_SZ);
+ outf[INOUTF_SZ - 1] = '\0';
+ } else if (0 == strcmp(key, "oflag")) {
if (! process_flags(buf, &clp->oflag)) {
pr2serr("%sbad argument to 'oflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index cea58f13..87700c3c 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -201,7 +201,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
/* rd> 1: master finished 0: not; wr> 1: finish share post master */
#define SG_CTL_FLAGM_MASTER_FINI 0x100 /* wr> 0: setup for repeat slave req */
#define SG_CTL_FLAGM_MASTER_ERR 0x200 /* rd: sharing, master got error */
-#define SG_CTL_FLAGM_ALL_BITS 0x3ff /* should be OR of previous items */
+#define SG_CTL_FLAGM_NO_DURATION 0x400 /* don't calc command duration */
+#define SG_CTL_FLAGM_ALL_BITS 0x7ff /* should be OR of previous items */
/* Write one of the following values to sg_extended_info::read_value, get... */
#define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */