aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2016-06-01 06:26:22 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2016-06-01 06:26:22 +0000
commit2eddb8b0844324f90e413e9ef519e3c1bf65174f (patch)
tree3b2babe16701cfa727d31ac6576aa064ed1fefa5
parent2eb082b82dc3bb4413205a7a0994dae34ecd5db0 (diff)
downloadsg3_utils-2eddb8b0844324f90e413e9ef519e3c1bf65174f.tar.gz
sg_logs: add --vendor=VP; sg_vpd: improve handling of unknown pages; other fixes
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@710 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog5
-rw-r--r--doc/sg_logs.882
-rw-r--r--doc/sg_vpd.810
-rw-r--r--src/sg_inq.c17
-rw-r--r--src/sg_logs.c388
-rw-r--r--src/sg_opcodes.c244
-rw-r--r--src/sg_read_buffer.c4
-rw-r--r--src/sg_sanitize.c4
-rw-r--r--src/sg_vpd.c17
-rw-r--r--src/sg_vpd_vendor.c17
-rw-r--r--src/sg_write_buffer.c4
-rw-r--r--src/sg_write_same.c4
-rw-r--r--src/sg_write_verify.c6
13 files changed, 544 insertions, 258 deletions
diff --git a/ChangeLog b/ChangeLog
index f331e8b0..d59d377d 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.43 [20160528] [svn: r708]
+Changelog for sg3_utils-1.43 [20160531] [svn: r710]
- sg_bg_ctl: new Background control command (spc4r08)
- sg_senddiag: add --timeout=SEC option
- sg_sanitize: add --timeout=SEC option
@@ -16,9 +16,9 @@ Changelog for sg3_utils-1.43 [20160528] [svn: r708]
- accept and output on request "quad dashed" format
- sg_logs: fix volume statistics lpage when subpage
is zero (ssc5r02a); decode mount history log parameter
+ - add --vendor=VP and '--pdt=DT' options
- decode Requested recovery, TapeAlert response, and
Service buffer information lpages for tape
- - add '--pdt=DT' option
- add min+max 'mounted' temperature and rel. humidity
fields to Environmental reporting lpage (spc5r10)
- sg_inq: fix potential unbounded loop in --export
@@ -28,6 +28,7 @@ Changelog for sg3_utils-1.43 [20160528] [svn: r708]
- add --force option to bypass checking supported
vpd pages page and fetch requested page directly
- sg_vpd: 3 party copy VPD page improvements
+ - improve handling of unknown pages
- sg_reassign+sg_write_same: fix ULONG_MAX problem
- sg_rdac: add sanity checks for -f=lun value
- sg_turs+sg_requests: make both accept '--num=NUM'
diff --git a/doc/sg_logs.8 b/doc/sg_logs.8
index 49af4d52..b098b7e1 100644
--- a/doc/sg_logs.8
+++ b/doc/sg_logs.8
@@ -1,21 +1,32 @@
-.TH SG_LOGS "8" "March 2016" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_LOGS "8" "May 2016" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_logs \- access log pages with SCSI LOG SENSE command
.SH SYNOPSIS
.B sg_logs
-[\fI\-\-All\fR] [\fI\-\-all\fR] [\fI\-\-brief\fR] [\fI\-\-control=PC\fR]
-[\fI\-\-enumerate\fR] [\fI\-\-enum_vendor\fR] [\fI\-\-filter=FL\fR]
-[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR] [\fI\-\-list\fR]
-[\fI\-\-maxlen=LEN\fR] [\fI\-\-name\fR] [\fI\-\-no_inq\fR] [\fI\-\-page=PG\fR]
-[\fI\-\-paramp=PP\fR] [\fI\-\-pcb\fR] [\fI\-\-ppc\fR] [\fI\-\-pdt=DT\fR]
-[\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-reset\fR] [\fI\-\-select\fR]
+[\fI\-\-All\fR] [\fI\-\-all\fR] [\fI\-\-brief\fR] [\fI\-\-filter=FL\fR]
+[\fI\-\-hex\fR] [\fI\-\-list\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-name\fR]
+[\fI\-\-no_inq\fR] [\fI\-\-page=PG\fR] [\fI\-\-paramp=PP\fR] [\fI\-\-pcb\fR]
+[\fI\-\-ppc\fR] [\fI\-\-pdt=DT\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR]
[\fI\-\-sp\fR] [\fI\-\-temperature\fR] [\fI\-\-transport\fR]
-[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+[\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR
+.PP
+.B sg_logs
+[\fI\-\-brief\fR] [\fI\-\-filter=FL\fR] [\fI\-\-hex\fR] \fI\-\-in=FN\fR
+[\fI\-\-name\fR] [\fI\-\-pdt=DT\fR] [\fI\-\-raw\fR] [\fI\-\-vendor=VP\fR]
+.PP
+.B sg_logs
+[\fI\-\-control=PC\fR] [\fI\-\-in=FN\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR]
+[\fI\-\-reset\fR] \fI\-\-select\fR [\fI\-\-sp\fR] [\fI\-\-verbose\fR]
+\fIDEVICE\fR
+.PP
+.B sg_logs
+[\fI\-\-enumerate\fR] [\fI\-\-filter=FL\fR] [\fI\-\-help\fR]
+[\fI\-\-vendor=VP\fR] [\fI\-\-version\fR]
.PP
.B sg_logs
[\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-D=DT\fR] [\fI\-c=PC\fR] [\fI\-e\fR]
-[\fI\-E\fR] [\fI\-f=FL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i=FN\fR] [\fI\-l\fR]
-[\fI\-L\fR] [\fI\-m=LEN\fR] [\fI\-n\fR] [\fI\-p=PG\fR] [\fI\-paramp=PP\fR]
+[\fI\-f=FL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i=FN\fR] [\fI\-l\fR] [\fI\-L\fR]
+[\fI\-m=LEN\fR] [\fI\-M=VP\fR] [\fI\-n\fR] [\fI\-p=PG\fR] [\fI\-paramp=PP\fR]
[\fI\-pcb\fR] [\fI\-ppc\fR] [\fI\-r\fR] [\fI\-R\fR] [\fI\-select\fR]
[\fI\-sp\fR] [\fI\-t\fR] [\fI\-T\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR]
[\fI\-x\fR] \fIDEVICE\fR
@@ -24,17 +35,22 @@ sg_logs \- access log pages with SCSI LOG SENSE command
.PP
This utility sends a SCSI LOG SENSE command to the \fIDEVICE\fR and then
outputs the response. The LOG SENSE command is used to fetch log pages. Known
-log pages can be decoded. When the \fI\-\-reset\fR and/or \fI\-\-select\fR
-option is given then a SCSI LOG SELECT command is issued.
+log pages can be decoded. Alternatively when the \fI\-\-reset\fR and/or
+\fI\-\-select\fR option is given then a SCSI LOG SELECT command is issued.
.PP
In SPC\-4 revision 5 a subpage code was introduced to both the LOG SENSE and
LOG SELECT command. At the same time a page code field was introduced to the
to the LOG SELECT command. The log subpage code can range from 0 to 255 (0xff)
inclusive. The subpage code value 255 can be thought of as a wildcard.
.PP
-This utility supports two command line syntaxes, the preferred one is shown
-first in the synopsis and explained in this section. A later section on the
-old command line syntax outlines the second group of options.
+The SYNOPSIS section above is divided into five forms. The first form
+shows the options that can be used to send a LOG SENSE command to the
+\fIDEVICE\fR and decode its response. The second form fetches data from a
+file (named \fIFN\fR) and decodes it as if it were a response from a LOG
+SENSE command. The third form shows the options that can be used to send a
+LOG SELECT command. The fourth form groups various management options.
+The last form shows the older, deprecated command line interface which is
+maintaimed for backward compatibility.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
.TP
@@ -83,20 +99,16 @@ the numeric order.
The \fI\-\-filter=FL\fR and \fI\-\-verbose\fR options modify the output
of the enumeration.
.TP
-\fB\-E\fR, \fB\-\-enum_vendor\fR
-this option is used to output information held in internal tables about
-known vendor specific log pages including their names and acronyms.
-.TP
\fB\-f\fR, \fB\-\-filter\fR=\fIFL\fR
\fIFL\fR is either a parameter code when \fIDEVICE\fR is given, or a
peripheral device type (pdt) (or other) if \fI\-\-enumerate\fR is given.
.br
In the parameter code case \fIFL\fR is a value between 0 and 65535 (0xffff)
-and only the parameter section matching that code is output.
-The \fB\-\-hex\fR option outputs log parameter in hexadecimal rather than
-decoding it. If the \fB\-\-hex\fR option is used twice then the leading
-address on each line of hex is removed. If the \fB\-\-raw\fR option is
-given then the log parameter is output in binary.
+and only the parameter section matching that code is output. If the
+\fB\-\-hex\fR option is given the log parameter is output in hexadecimal
+rather than decoding it. If the \fB\-\-hex\fR option is used twice then the
+leading address on each line of hex is removed. If the \fB\-\-raw\fR option
+is given then the log parameter is output in binary.
Most log pages contain one or more log parameters. Examples of those that
don't are those pages that list supported log pages.
.br
@@ -259,6 +271,21 @@ may also have the current temperature (especially on older disks).
outputs the transport ('Protocol specific port') log page. Equivalent to
setting '\-\-page=18h'.
.TP
+\fB\-M\fR, \fB\-\-vendor\fR=\fIVP\fR
+where \fIVP\fR is a vendor (e.g. "sea" for Seagate) or product (group)
+acronym (e.g. "lto5" for the 5th generation LTO (tape) consortium). Either
+the whole log page is vendor specific (e.g. page numbers 0x30 to 0x3f) or
+part of a T10 defined log page is vendor specific. For example SPC\-5
+defines parameter code 0x0 of page 0x2f (the Informational Exceptions log
+page) and states that the remaining parameter codes (i.e. 0x1 to 0xffff)
+are vendor specific. Using a \fIVP\fR of "xxx" will list the available
+acronyms.
+.br
+If this option is used with \fI\-\-page=PG\fR and \fIPG\fR is an acronym
+then this option is ignored. If \fIPG\fR is a number (e.g. 0xc0) then
+\fIVP\fR is used to choose the which vendor specific page (e.g. sharing
+page number 0xc0) to decode.
+.TP
\fB\-v\fR, \fB\-\-verbose\fR
increase level of verbosity. When used with \fI\-\-enumerate\fR, in the
list of known log page names, those that have no associated decode logic
@@ -344,10 +371,6 @@ Equivalent to \fI\-\-control=PC\fR in the main description.
enumerate internal tables to show information about known log pages.
Equivalent to \fI\-\-enumerate\fR in the main description.
.TP
-\fB\-E\fR
-enumerate internal tables to show information about known vendor specific
-log pages. Equivalent to \fI\-\-enum_vendor\fR in the main description.
-.TP
\fB\-h\fR
suppresses decoding of known log sense pages and prints out the
response in hex instead.
@@ -375,6 +398,9 @@ interpreted as all that is available. \fILEN\fR is decimal unless it has
a leading '0x' or trailing 'h'. Equivalent to \fI\-\-maxlen=LEN\fR in
the main description.
.TP
+\fB\-M\fR=\fIVP\fR
+Equivalent to \fI\-\-vendor=VP\fR in the main description.
+.TP
\fB\-n\fR
Equivalent to \fI\-\-name\fR in the main description.
.TP
diff --git a/doc/sg_vpd.8 b/doc/sg_vpd.8
index 25c6a0e6..4d55b586 100644
--- a/doc/sg_vpd.8
+++ b/doc/sg_vpd.8
@@ -1,12 +1,12 @@
-.TH SG_VPD "8" "April 2016" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_VPD "8" "May 2016" "sg3_utils\-1.43" 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\-\-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\-\-force\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR]
+[\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]
.SH DESCRIPTION
.\" Add any additional description here
.PP
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 8944d456..2be835dc 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -43,7 +43,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.62 20160510"; /* SPC-5 rev 10 */
+static const char * version_str = "1.63 20160531"; /* SPC-5 rev 10 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -3087,7 +3087,7 @@ vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page,
static int
fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
{
- int len, k, res;
+ int len, k, res, c;
unsigned char b[DEF_ALLOC_LEN];
memset(b, 0xff, 4); /* guard against empty response */
@@ -3097,10 +3097,15 @@ fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
len -= 4;
len = (len < (obuff_len - 1)) ? len : (obuff_len - 1);
if (len > 0) {
- /* replace non-printable ASCII characters with space */
- for (k = 0; k < len; ++k)
- obuff[k] = isprint(b[4 + k]) ? b[4 + k] : ' ';
- obuff[len] = '\0';
+ /* replace non-printable characters (except NULL) with space */
+ for (k = 0; k < len; ++k) {
+ c = b[4 + k];
+ if (c)
+ obuff[k] = isprint(c) ? c : ' ';
+ else
+ break;
+ }
+ obuff[k] = '\0';
return 0;
} else {
if (verbose > 2)
diff --git a/src/sg_logs.c b/src/sg_logs.c
index 2bd878b9..51d1bdaf 100644
--- a/src/sg_logs.c
+++ b/src/sg_logs.c
@@ -31,7 +31,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.45 20160519"; /* spc5r10 + sbc4r10 */
+static const char * version_str = "1.46 20160531"; /* spc5r10 + sbc4r10 */
#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
@@ -71,8 +71,30 @@ static const char * version_str = "1.45 20160519"; /* spc5r10 + sbc4r10 */
#define ENV_LIMITS_SUBPG 0x2
#define LPS_MISALIGNMENT_SUBPG 0x3
-#define VENDOR_M 0x1000
-#define LTO5_M 0x2000
+/* Vendor product identifiers followed by associated mask values */
+#define VP_SEAG 0
+#define VP_HITA 1
+#define VP_WDC 2
+#define VP_TOSH 3
+#define VP_SMSTR 4
+#define VP_LTO5 5
+#define VP_LTO6 6
+#define VP_ALL 99
+
+#define MVP_OFFSET 8
+/* shared is T10 defined lpage with vendor specific parameter codes */
+#define MVP_SHARED (1 << (MVP_OFFSET - 1))
+#define MVP_SEAG (1 << (VP_SEAG + MVP_OFFSET))
+#define MVP_HITA (1 << (VP_HITA + MVP_OFFSET))
+#define MVP_WDC (1 << (VP_WDC + MVP_OFFSET))
+#define MVP_TOSH (1 << (VP_TOSH + MVP_OFFSET))
+#define MVP_SMSTR (1 << (VP_SMSTR + MVP_OFFSET))
+#define MVP_LTO5 (1 << (VP_LTO5 + MVP_OFFSET))
+#define MVP_LTO6 (1 << (VP_LTO6 + MVP_OFFSET))
+
+#define OVP_LTO (MVP_LTO5 | MVP_LTO6)
+#define OVP_ALL (~0)
+
#define PCB_STR_LEN 128
@@ -86,7 +108,6 @@ static struct option long_options[] = {
{"brief", no_argument, 0, 'b'},
{"control", required_argument, 0, 'c'},
{"enumerate", no_argument, 0, 'e'},
- {"enum_vendor", no_argument, 0, 'E'},
{"filter", required_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
@@ -109,6 +130,7 @@ static struct option long_options[] = {
{"select", no_argument, 0, 'S'},
{"temperature", no_argument, 0, 't'},
{"transport", no_argument, 0, 'T'},
+ {"vendor", required_argument, 0, 'M'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
@@ -118,7 +140,6 @@ struct opts_t {
int do_all;
int do_brief;
int do_enumerate;
- int do_enum_vendor;
int do_help;
int do_hex;
int do_list;
@@ -132,6 +153,8 @@ struct opts_t {
int do_sp;
int do_temperature;
int do_transport;
+ int vend_prod_num;
+ int deduced_vpn;
int verbose;
int do_version;
int filter;
@@ -147,6 +170,7 @@ struct opts_t {
const char * device_name;
const char * in_fn;
const char * pg_arg;
+ const char * vend_prod;
const struct log_elem * lep;
};
@@ -156,7 +180,7 @@ struct log_elem {
int subpg_code; /* only unless subpg_high>0 then this is only */
int subpg_high; /* when >0 this is high end of subpage range */
int pdt; /* -1 for all */
- int flags; /* bit mask; only VENDOR_M to start with */
+ int flags; /* bit mask; or-ed MVP_* constants */
const char * name;
const char * acron;
bool (*show_pagep)(const uint8_t * resp, int len,
@@ -164,6 +188,14 @@ struct log_elem {
/* Returns true if done */
};
+struct vp_name_t {
+ int vend_prod_num; /* vendor/product identifier */
+ const char * acron;
+ const char * name;
+ const char * t10_vendorp;
+ const char * t10_productp;
+};
+
static bool show_supported_pgs_page(const uint8_t * resp, int len,
const struct opts_t * op);
static bool show_supported_pgs_sub_page(const uint8_t * resp, int len,
@@ -349,51 +381,68 @@ static struct log_elem log_arr[] = {
NULL}, /* 0x2d, 0 SSC */
{TAPE_ALERT_LPAGE, 0, 0, PDT_TAPE, 0, "Tape alert", "ta",
show_tape_alert_ssc_page}, /* 0x2e, 0 SSC */
- {IE_LPAGE, 0, 0, -1, 0, "Informational exceptions", "ie",
- show_ie_page}, /* 0x2f, 0 */
+ {IE_LPAGE, 0, 0, -1, (MVP_SHARED | MVP_SMSTR), "Informational exceptions",
+ "ie", show_ie_page}, /* 0x2f, 0 */
/* vendor specific */
- {0x30, 0, 0, PDT_DISK, VENDOR_M, "Performance counters (Hitachi)",
+ {0x30, 0, 0, PDT_DISK, MVP_HITA, "Performance counters (Hitachi)",
"pc_hi", NULL}, /* 0x30, 0 SBC */
- {0x30, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Tape usage (lto-5, 6)", "tu_",
+ {0x30, 0, 0, PDT_TAPE, OVP_LTO, "Tape usage (lto-5, 6)", "tu_",
show_tape_usage_page}, /* 0x30, 0 SSC */
- {0x31, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Tape capacity (lto-5, 6)",
+ {0x31, 0, 0, PDT_TAPE, OVP_LTO, "Tape capacity (lto-5, 6)",
"tc_", show_tape_capacity_page}, /* 0x31, 0 SSC */
- {0x32, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Data compression (lto-5)",
+ {0x32, 0, 0, PDT_TAPE, MVP_LTO5, "Data compression (lto-5)",
"dc_", show_data_compression_page}, /* 0x32, 0 SSC; redirect to 0x1b */
- {0x33, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Write errors (lto-5)", "we_",
+ {0x33, 0, 0, PDT_TAPE, MVP_LTO5, "Write errors (lto-5)", "we_",
NULL}, /* 0x33, 0 SSC */
- {0x34, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Read forward errors (lto-5)",
+ {0x34, 0, 0, PDT_TAPE, MVP_LTO5, "Read forward errors (lto-5)",
"rfe_", NULL}, /* 0x34, 0 SSC */
- {0x35, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "DT Device Error (lto-5, 6)",
+ {0x35, 0, 0, PDT_TAPE, OVP_LTO, "DT Device Error (lto-5, 6)",
"dtde_", NULL}, /* 0x35, 0 SSC */
- {0x37, 0, 0, PDT_DISK, VENDOR_M, "Cache (seagate)", "c_se",
+ {0x37, 0, 0, PDT_DISK, MVP_SEAG, "Cache (seagate)", "c_se",
show_seagate_cache_page}, /* 0x37, 0 SBC */
- {0x37, 0, 0, PDT_DISK, VENDOR_M, "Miscellaneous (hitachi)", "mi_hi",
+ {0x37, 0, 0, PDT_DISK, MVP_HITA, "Miscellaneous (hitachi)", "mi_hi",
NULL}, /* 0x37, 0 SBC */
- {0x37, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Performance characteristics "
+ {0x37, 0, 0, PDT_TAPE, MVP_LTO5, "Performance characteristics "
"(lto-5)", "pc_", NULL}, /* 0x37, 0 SSC */
- {0x38, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Blocks/bytes transferred "
+ {0x38, 0, 0, PDT_TAPE, MVP_LTO5, "Blocks/bytes transferred "
"(lto-5)", "bbt_", NULL}, /* 0x38, 0 SSC */
- {0x39, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Host port 0 interface errors "
+ {0x39, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 0 interface errors "
"(lto-5)", "hp0_", NULL}, /* 0x39, 0 SSC */
- {0x3a, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Drive control verification "
+ {0x3a, 0, 0, PDT_TAPE, MVP_LTO5, "Drive control verification "
"(lto-5)", "dcv_", NULL}, /* 0x3a, 0 SSC */
- {0x3b, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Host port 1 interface errors "
+ {0x3b, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 1 interface errors "
"(lto-5)", "hp1_", NULL}, /* 0x3b, 0 SSC */
- {0x3c, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Drive usage information "
+ {0x3c, 0, 0, PDT_TAPE, MVP_LTO5, "Drive usage information "
"(lto-5)", "dui_", NULL}, /* 0x3c, 0 SSC */
- {0x3d, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Subsystem statistics (lto-5)",
+ {0x3d, 0, 0, PDT_TAPE, MVP_LTO5, "Subsystem statistics (lto-5)",
"ss_", NULL}, /* 0x3d, 0 SSC */
- {0x3e, 0, 0, PDT_DISK, VENDOR_M, "Factory (seagate)", "f_se",
+ {0x3e, 0, 0, PDT_DISK, MVP_SEAG, "Factory (seagate)", "f_se",
show_seagate_factory_page}, /* 0x3e, 0 SBC */
- {0x3e, 0, 0, PDT_DISK, VENDOR_M, "Factory (hitachi)", "f_hi",
+ {0x3e, 0, 0, PDT_DISK, MVP_HITA, "Factory (hitachi)", "f_hi",
NULL}, /* 0x3e, 0 SBC */
- {0x3e, 0, 0, PDT_TAPE, VENDOR_M | LTO5_M, "Device Status (lto-5, 6)",
+ {0x3e, 0, 0, PDT_TAPE, OVP_LTO, "Device Status (lto-5, 6)",
"ds_", NULL}, /* 0x3e, 0 SSC */
{-1, -1, -1, -1, -1, NULL, "zzzzz", NULL}, /* end sentinel */
};
+/* Supported vendor product codes */
+/* Arrange in alphabetical order by acronym */
+static struct vp_name_t vp_arr[] = {
+ {VP_SEAG, "sea", "Seagate", "SEAGATE", NULL},
+ {VP_HITA, "hit", "Hitachi", "HGST", NULL},
+ {VP_WDC, "wdc", "WDC", "WDC", NULL},
+ {VP_TOSH, "tos", "Toshiba", "TOSHIBA", NULL},
+ {VP_SMSTR, "smstr", "SmrtStor (Sandisk)", "SmrtStor", NULL},
+ {VP_LTO5, "lto5", "LTO-5 (tape drive consortium)", NULL, NULL},
+ {VP_LTO6, "lto6", "LTO-6 (tape drive consortium)", NULL, NULL},
+ {VP_ALL, "all", "enumerate all vendor specific", NULL, NULL},
+ {0, NULL, NULL, NULL, NULL},
+};
+
+static char t10_vendor_str[10];
+static char t10_product_str[18];
+
#ifdef SG_LIB_WIN32
static int win32_spt_init_state = 0;
static int win32_spt_curr_state = 0;
@@ -407,15 +456,16 @@ usage(int hval)
pr2serr(
"Usage: sg_logs [-All] [--all] [--brief] [--control=PC] "
"[--enumerate]\n"
- " [--enum_vendor] [--filter=FL] [--help] [--hex] "
- "[--in=FN]\n"
- " [--list] [--no_inq] [--maxlen=LEN] [--name] "
- "[--page=PG]\n"
+ " [--filter=FL] [--help] [--hex] [--in=FN] "
+ "[--list]\n"
+ " [--no_inq] [--maxlen=LEN] [--name] [--page=PG]\n"
" [--paramp=PP] [--pcb] [--ppc] [--pdt=DT] "
"[--raw]\n"
" [--readonly] [--reset] [--select] [--sp] "
"[--temperature]\n"
- " [--transport] [--verbose] [--version] DEVICE\n"
+ " [--transport] [--vendor=VP] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n"
" where the main options are:\n"
" --All|-A fetch and decode all log pages and "
"subpages\n"
@@ -430,8 +480,6 @@ usage(int hval)
"by acronym;\n"
" '-eee': all numerically; '-eeee': "
"non-v numerically\n"
- " --enum_vendor|-E enumerate known specific vendor pages "
- "only\n"
" --filter=FL|-f FL FL is parameter code to display (def: "
"all);\n"
" with '-e' then FL>=0 enumerate that "
@@ -456,6 +504,8 @@ usage(int hval)
"0x2f)\n"
" --transport|-T decode transport (protocol specific port "
"0x18) page\n"
+ " --vendor=VP|-M VP vendor/product abbreviation [or "
+ "number]\n"
" --verbose|-v increase verbosity\n\n"
"Performs a SCSI LOG SENSE (or LOG SELECT) command and decodes "
"the response.\nIf only DEVICE is given then '-p sp' (supported "
@@ -511,13 +561,13 @@ usage(int hval)
static void
usage_old()
{
- printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-E] [-f=FL] "
+ printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-f=FL] "
"[-h]\n"
- " [-H] [-i=FN] [-l] [-L] [-m=LEN] [-n] [-p=PG] "
- "[-paramp=PP]\n"
- " [-pcb] [-ppc] [-r] [-select] [-sp] [-t] [-T] "
- "[-v] [-V]\n"
- " [-x] [-X] [-?] DEVICE\n"
+ " [-H] [-i=FN] [-l] [-L] [-m=LEN] [-M=VP] [-n] "
+ "[-p=PG]\n"
+ " [-paramp=PP] [-pcb] [-ppc] [-r] [-select] [-sp] "
+ "[-t] [-T]\n"
+ " [-v] [-V] [-x] [-X] [-?] DEVICE\n"
" where:\n"
" -a fetch and decode all log pages\n"
" -A fetch and decode all log pages and subpages\n"
@@ -526,7 +576,6 @@ usage_old()
" 0: current threshhold, 1: current cumulative\n"
" 2: default threshhold, 3: default cumulative\n"
" -e enumerate known log pages\n"
- " -E enumerate known vendor specific log pages only\n"
" -f=FL filter match parameter code or pdt\n"
" -h output in hex (default: decode if known)\n"
" -H output in hex (same as '-h')\n"
@@ -539,6 +588,7 @@ usage_old()
" '-p=0,ff')\n"
" -m=LEN max response length (decimal) (def: 0 "
"-> everything)\n"
+ " -M=VP vendor/product abbreviation [or number]\n"
" -n decode some pages into multiple name=value "
"lines\n"
" -p=PG PG is an acronym (def: 'sp')\n"
@@ -568,6 +618,37 @@ usage_old()
}
static int
+get_vp_mask(int vpn)
+{
+ if (vpn < 0)
+ return 0;
+ else
+ return (vpn > (32 - MVP_OFFSET)) ? OVP_ALL :
+ (1 << (vpn + MVP_OFFSET));
+}
+
+static int
+mask_to_vendor(int vp_mask)
+{
+ if (MVP_SEAG & vp_mask)
+ return VP_SEAG;
+ else if (MVP_HITA & vp_mask)
+ return VP_HITA;
+ else if (MVP_WDC & vp_mask)
+ return VP_WDC;
+ else if (MVP_TOSH & vp_mask)
+ return VP_TOSH;
+ else if (MVP_SMSTR & vp_mask)
+ return VP_SMSTR;
+ else if (MVP_LTO5 & vp_mask)
+ return VP_LTO5;
+ else if (MVP_LTO6 & vp_mask)
+ return VP_LTO6;
+ else
+ return -1;
+}
+
+static int
asort_comp(const void * lp, const void * rp)
{
const struct log_elem * const * lepp =
@@ -585,6 +666,8 @@ enumerate_helper(const struct log_elem * lep, int pos,
char b[80];
char bb[80];
const char * cp;
+ bool mvp = !! lep->flags;
+ bool shared_vp = !!(MVP_SHARED & lep->flags);
if (0 == pos) {
if (1 == op->verbose) {
@@ -595,9 +678,7 @@ enumerate_helper(const struct log_elem * lep, int pos,
printf("===================================================\n");
}
}
- if ((op->do_enum_vendor > 0) && !(VENDOR_M & lep->flags))
- return;
- if ((0 == (op->do_enumerate % 2)) && (VENDOR_M & lep->flags))
+ if ((0 == (op->do_enumerate % 2)) && mvp && ! shared_vp)
return; /* if do_enumerate is even then skip vendor pages */
else if ((! op->filter_given) || (-1 == op->filter))
; /* otherwise enumerate all lpages if no --filter= */
@@ -615,6 +696,10 @@ enumerate_helper(const struct log_elem * lep, int pos,
(lep->pdt != sg_lib_pdt_decay(op->filter)))
return;
}
+ if (op->vend_prod_num >= 0) {
+ if (! (lep->flags & get_vp_mask(op->vend_prod_num)))
+ return;
+ }
if (lep->subpg_high > 0)
snprintf(b, sizeof(b), "0x%x,0x%x->0x%x", lep->pg_code,
lep->subpg_code, lep->subpg_high);
@@ -679,16 +764,51 @@ acron_search(const char * acron)
return NULL;
}
+static int
+find_vp_num_by_acron(const char * vp_ap)
+{
+ size_t len;
+ const struct vp_name_t * vpp;
+
+ for (vpp = vp_arr; vpp->acron; ++vpp) {
+ len = strlen(vpp->acron);
+ if (0 == strncmp(vpp->acron, vp_ap, len))
+ return vpp->vend_prod_num;
+ }
+ return -1;
+}
+
+static void
+enumerate_vp(void)
+{
+ const struct vp_name_t * vpp;
+ bool seen = false;
+
+ for (vpp = vp_arr; vpp->acron; ++vpp) {
+ if (vpp->name) {
+ if (! seen) {
+ printf("\nVendor/product identifiers:\n");
+ seen = true;
+ }
+ printf(" %-10s %d %s\n", vpp->acron,
+ vpp->vend_prod_num, vpp->name);
+ }
+ }
+}
+
static const struct log_elem *
-pg_subpg_pdt_search(int pg_code, int subpg_code, int pdt)
+pg_subpg_pdt_search(int pg_code, int subpg_code, int pdt, int vpn)
{
const struct log_elem * lep;
int d_pdt;
+ int vp_mask = get_vp_mask(vpn);
d_pdt = sg_lib_pdt_decay(pdt);
for (lep = log_arr; lep->pg_code >=0; ++lep) {
if (pg_code == lep->pg_code) {
if (subpg_code == lep->subpg_code) {
+ if (vp_mask && ! (vp_mask & lep->flags))
+ continue;
if ((lep->pdt < 0) || (pdt == lep->pdt) || (pdt < 0))
return lep;
else if (d_pdt == lep->pdt)
@@ -723,8 +843,8 @@ process_cl_new(struct opts_t * op, int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "aAbc:D:eEf:hHi:lLm:nNOp:P:qQrRsStTvVxX",
- long_options, &option_index);
+ c = getopt_long(argc, argv, "aAbc:D:ef:hHi:lLm:M:nNOp:P:qQrRsStTvV"
+ "xX", long_options, &option_index);
if (c == -1)
break;
@@ -758,9 +878,6 @@ process_cl_new(struct opts_t * op, int argc, char * argv[])
case 'e':
++op->do_enumerate;
break;
- case 'E':
- ++op->do_enum_vendor;
- break;
case 'f':
if ('-' == optarg[0]) {
n = sg_get_num(optarg + 1);
@@ -806,6 +923,14 @@ process_cl_new(struct opts_t * op, int argc, char * argv[])
}
op->maxlen = n;
break;
+ case 'M':
+ if (op->vend_prod) {
+ pr2serr("only one '--vendor=' option permitted\n");
+ usage(2);
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ op->vend_prod = optarg;
+ break;
case 'n':
++op->do_name;
break;
@@ -915,9 +1040,6 @@ process_cl_old(struct opts_t * op, int argc, char * argv[])
case 'e':
++op->do_enumerate;
break;
- case 'E':
- ++op->do_enum_vendor;
- break;
case 'h':
case 'H':
++op->do_hex;
@@ -1010,6 +1132,13 @@ process_cl_old(struct opts_t * op, int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
op->maxlen = n;
+ } else if (0 == strncmp("M=", cp, 2)) {
+ if (op->vend_prod) {
+ pr2serr("only one '-M=' option permitted\n");
+ usage(2);
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ op->vend_prod = cp + 2;
} else if (0 == strncmp("p=", cp, 2)) {
const char * ccp = cp + 2;
char * xp;
@@ -1045,6 +1174,8 @@ process_cl_old(struct opts_t * op, int argc, char * argv[])
op->subpg_code = n;
} else
op->subpg_code = lep->subpg_code;
+ if (lep->flags)
+ op->deduced_vpn = mask_to_vendor(lep->flags);
} else {
/* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
if (NULL == strchr(cp + 2, ',')) {
@@ -1475,7 +1606,7 @@ show_supported_pgs_page(const uint8_t * resp, int len,
for (k = 0; k < num; ++k) {
pg_code = bp[k];
snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code);
- lep = pg_subpg_pdt_search(pg_code, 0, op->dev_pdt);
+ lep = pg_subpg_pdt_search(pg_code, 0, op->dev_pdt, -1);
if (lep) {
if (op->do_brief > 1)
printf(" %s\n", lep->name);
@@ -1516,7 +1647,7 @@ show_supported_pgs_sub_page(const uint8_t * resp, int len,
else
snprintf(b, sizeof(b) - 1, " 0x%02x,0x%02x ", pg_code,
subpg_code);
- lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt);
+ lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, -1);
if (lep) {
if (op->do_brief > 1)
printf(" %s\n", lep->name);
@@ -2774,14 +2905,19 @@ show_app_client_page(const uint8_t * resp, int len, const struct opts_t * op)
return true;
}
-/* IE_LPAGE [0x2f] introduced: SPC-3 */
+/* IE_LPAGE [0x2f] "Informational Exceptions" introduced: SPC-3 */
static bool
show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
{
- int k, num, extra, pc, pcb, full;
+ int k, num, extra, pc, pcb;
const uint8_t * bp;
+ const char * cp;
char pcb_str[PCB_STR_LEN];
char b[256];
+ char bb[32];
+ bool full, decoded, has_header;
+ bool is_smstr = op->lep ? (MVP_SMSTR & op->lep->flags) :
+ (VP_SMSTR == op->vend_prod_num);
full = ! op->do_temperature;
num = len - 4;
@@ -2794,7 +2930,7 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
if (full)
printf("Informational Exceptions page [0x2f]\n");
}
- for (k = num; k > 0; k -= extra, bp += extra) {
+ for (k = num, has_header = false; k > 0; k -= extra, bp += extra) {
if (k < 3) {
printf("short Informational Exceptions page\n");
return false;
@@ -2814,8 +2950,10 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
break;
}
}
+ decoded = true;
+ cp = NULL;
switch (pc) {
- case 0:
+ case 0x0:
if (extra > 5) {
if (full) {
printf(" IE asc = 0x%x, ascq = 0x%x", bp[4], bp[5]);
@@ -2825,27 +2963,102 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
}
if (extra > 6) {
if (bp[6] < 0xff)
- printf("\n Current temperature = %d C", bp[6]);
+ printf("\n Current temperature = %d C", bp[6]);
else
- printf("\n Current temperature = <not available>");
+ printf("\n Current temperature = <not available>");
if (extra > 7) {
if (bp[7] < 0xff)
- printf("\n Threshold temperature = %d C [IBM "
- "extension]", bp[7]);
+ printf("\n Threshold temperature = %d C "
+ "[common extension]", bp[7]);
else
- printf("\n Threshold temperature = <not "
+ printf("\n Threshold temperature = <not "
"available>");
}
}
+ decoded = true;
}
break;
default:
- if (full) {
- printf(" parameter code = 0x%x, contents in hex:\n", pc);
- dStrHex((const char *)bp, extra, 1);
+ if (! is_smstr) {
+ decoded = false;
+ break;
+ }
+ switch (pc) {
+ case 0x1:
+ cp = "Read error rate";
+ break;
+ case 0x2:
+ cp = "Flash rom check";
+ break;
+ case 0x5:
+ cp = "Realloc block count";
+ break;
+ case 0x9:
+ cp = "Power on hours";
+ break;
+ case 0xc:
+ cp = "Power cycles";
+ break;
+ case 0xd:
+ cp = "Ecc rate";
+ break;
+ case 0x20:
+ cp = "Write amp";
+ break;
+ case 0xb1: /* 177 */
+ cp = "Percent life remaining";
+ break;
+ case 0xb4: /* 180 */
+ cp = "Unused reserved block count";
+ break;
+ case 0xb5: /* 181 */
+ cp = "Program fail count";
+ break;
+ case 0xb6: /* 182 */
+ cp = "Erase fail count";
+ break;
+ case 0xbe: /* 190 */
+ cp = "Drive temperature warn";
+ break;
+ case 0xc2: /* 194 */
+ cp = "Drive temperature";
+ break;
+ case 0xc3: /* 195 */
+ cp = "Uncorrected error count";
+ break;
+ case 0xc6: /* 198 */
+ cp = "Offline scan uncorrected sector count";
+ break;
+ case 0xe9: /* 233 */
+ cp = "Number of writes";
+ break;
+ default:
+ snprintf(bb, sizeof(bb), "parameter_code=0x%x (%d)",
+ pc, pc);
+ cp = bb;
+ break;
}
break;
}
+ if (cp && (extra >= 24)) {
+ if (! has_header) {
+ has_header = true;
+ printf(" Has|Ever %% to worst %% Current "
+ "Worst Threshold Attribute\n");
+ printf(" tripped fail to fail "
+ "value value\n");
+ }
+ printf(" %2d %2d %4d %4d %10u %10u %10u %s",
+ !!(0x80 & bp[4]), !!(0x40 & bp[4]), bp[5], bp[6],
+ sg_get_unaligned_be32(bp + 8),
+ sg_get_unaligned_be32(bp + 12),
+ sg_get_unaligned_be32(bp + 16),
+ cp);
+ decoded = true;
+ } else if ((! decoded) && full) {
+ printf(" parameter code = 0x%x, contents in hex:\n", pc);
+ dStrHex((const char *)bp, extra, 1);
+ }
if (op->do_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
@@ -6088,9 +6301,9 @@ skip:
}
static void
-show_ascii_page(const uint8_t * resp, int len, const struct opts_t * op)
+decode_page_contents(const uint8_t * resp, int len, const struct opts_t * op)
{
- int pg_code, subpg_code, spf;
+ int pg_code, subpg_code, spf, vpn;
bool done = false;
const struct log_elem * lep;
@@ -6106,7 +6319,8 @@ show_ascii_page(const uint8_t * resp, int len, const struct opts_t * op)
if (done)
return;
}
- lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt);
+ vpn = (op->vend_prod_num >= 0) ? op->vend_prod_num : op->deduced_vpn;
+ lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, vpn);
if (lep && lep->show_pagep)
done = (*lep->show_pagep)(resp, len, op);
@@ -6202,6 +6416,8 @@ decode_pg_arg(struct opts_t * op)
op->subpg_code = nn;
} else
op->subpg_code = lep->subpg_code;
+ if (lep->flags)
+ op->deduced_vpn = mask_to_vendor(lep->flags);
} else { /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */
cp = (char *)strchr(op->pg_arg, ',');
n = sg_get_num_nomult(op->pg_arg);
@@ -6243,6 +6459,8 @@ main(int argc, char * argv[])
/* N.B. some disks only give data for current cumulative */
op->page_control = 1;
op->dev_pdt = -1;
+ op->vend_prod_num = -1;
+ op->deduced_vpn = -1;
res = process_cl(op, argc, argv);
if (res)
return SG_LIB_SYNTAX_ERROR;
@@ -6254,12 +6472,25 @@ main(int argc, char * argv[])
pr2serr("Version string: %s\n", version_str);
return 0;
}
- if ((op->do_enumerate > 0) || (op->do_enum_vendor > 0)) {
+ if (op->vend_prod) {
+ if (isdigit(op->vend_prod[0]))
+ k = sg_get_num_nomult(op->vend_prod);
+ else
+ k = find_vp_num_by_acron(op->vend_prod);
+ op->vend_prod_num = k;
+ if (VP_ALL == k)
+ ;
+ else if ((k < 0) || (k > (32 - MVP_OFFSET))) {
+ pr2serr("Bad vendor/product acronym after '--vendor=' "
+ " ('-M ') option\n");
+ enumerate_vp();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (op->do_enumerate > 0) {
if (op->device_name && op->verbose)
pr2serr("Warning: device: %s is being ignored\n",
op->device_name);
- if ((op->do_enum_vendor > 0) && (0 == op->do_enumerate))
- op->do_enumerate = 1;
enumerate_pages(op);
return 0;
}
@@ -6296,7 +6527,8 @@ main(int argc, char * argv[])
n = in_len - k;
}
pdt = op->dev_pdt;
- lep = pg_subpg_pdt_search(pg_code, subpg_code, pdt);
+ lep = pg_subpg_pdt_search(pg_code, subpg_code, pdt,
+ op->vend_prod_num);
if (lep) {
if (lep->show_pagep)
(*lep->show_pagep)(bp, n, op);
@@ -6417,6 +6649,8 @@ main(int argc, char * argv[])
(0 == op->no_inq) && (0 == op->do_brief))
printf(" %.8s %.16s %.4s\n", inq_out.vendor,
inq_out.product, inq_out.revision);
+ memcpy(t10_vendor_str, inq_out.vendor, 8);
+ memcpy(t10_product_str, inq_out.product, 16);
} else
memset(&inq_out, 0, sizeof(inq_out));
@@ -6471,7 +6705,7 @@ main(int argc, char * argv[])
dStrHex((const char *)rsp_buff, pg_len + 4,
(op->do_hex < 4));
else
- show_ascii_page(rsp_buff, pg_len + 4, op);
+ decode_page_contents(rsp_buff, pg_len + 4, op);
} else if (op->do_raw)
dStrRaw((const char *)rsp_buff, pg_len + 4);
else if (op->do_hex > 1)
@@ -6489,7 +6723,7 @@ main(int argc, char * argv[])
dStrHex((const char *)rsp_buff, pg_len + 4, 1);
}
else
- show_ascii_page(rsp_buff, pg_len + 4, op);
+ decode_page_contents(rsp_buff, pg_len + 4, op);
}
}
ret = res;
@@ -6540,7 +6774,7 @@ main(int argc, char * argv[])
dStrHex((const char *)rsp_buff, pg_len + 4, 1);
}
else
- show_ascii_page(rsp_buff, pg_len + 4, op);
+ decode_page_contents(rsp_buff, pg_len + 4, op);
} else if (SG_LIB_CAT_INVALID_OP == res)
pr2serr("log_sense: page=0x%x,0x%x not supported\n",
op->pg_code, op->subpg_code);
diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c
index 929bffd3..c956c935 100644
--- a/src/sg_opcodes.c
+++ b/src/sg_opcodes.c
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
@@ -29,7 +30,7 @@
#include "sg_pt.h"
-static const char * version_str = "0.48 20160528"; /* spc5r10 */
+static const char * version_str = "0.48 20160531"; /* spc5r10 */
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -47,13 +48,6 @@ static const char * version_str = "0.48 20160528"; /* spc5r10 */
static int peri_dtype = -1; /* ugly but not easy to pass to alpha compare */
-static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
- int rq_servact, void * resp, int mx_resp_len, int noisy,
- int verbose);
-static int do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len,
- int noisy, int verbose);
-
-
static struct option long_options[] = {
{"alpha", 0, 0, 'a'},
{"compact", 0, 0, 'c'},
@@ -180,6 +174,127 @@ usage_old()
"TASK MANAGEMENT\nFUNCTIONS) command\n");
}
+static const char * const rsoc_s = "Report supported operation codes";
+
+static int
+do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode, int rq_servact,
+ void * resp, int mx_resp_len, int noisy, int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rsoc_cdb[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_pt_base * ptvp;
+
+ if (rctd)
+ rsoc_cdb[2] |= 0x80;
+ if (rep_opts)
+ rsoc_cdb[2] |= (rep_opts & 0x7);
+ if (rq_opcode > 0)
+ rsoc_cdb[3] = (rq_opcode & 0xff);
+ if (rq_servact > 0)
+ sg_put_unaligned_be16((uint16_t)rq_servact, rsoc_cdb + 4);
+ sg_put_unaligned_be32((uint32_t)mx_resp_len, rsoc_cdb + 6);
+
+ if (verbose) {
+ pr2serr(" %s cdb: ", rsoc_s);
+ for (k = 0; k < RSOC_CMD_LEN; ++k)
+ pr2serr("%02x ", rsoc_cdb[k]);
+ pr2serr("\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ pr2serr("%s: out of memory\n", rsoc_s);
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rsoc_cdb, sizeof(rsoc_cdb));
+ 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_TIMEOUT_SECS, verbose);
+ ret = sg_cmds_process_resp(ptvp, rsoc_s, res, mx_resp_len, sense_b, noisy,
+ verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = sense_cat;
+ break;
+ }
+ } else {
+ if ((verbose > 2) && (ret > 0)) {
+ pr2serr("%s response:\n", rsoc_s);
+ dStrHexErr((const char *)resp, ret, 1);
+ }
+ ret = 0;
+ }
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+static const char * const rstmf_s = "Report supported task management "
+ "functions";
+
+static int
+do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rstmf_cdb[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_pt_base * ptvp;
+
+ if (repd)
+ rstmf_cdb[2] = 0x80;
+ sg_put_unaligned_be32((uint32_t)mx_resp_len, rstmf_cdb + 6);
+
+ if (verbose) {
+ pr2serr(" %s: ", rstmf_s);
+ for (k = 0; k < RSTMF_CMD_LEN; ++k)
+ pr2serr("%02x ", rstmf_cdb[k]);
+ pr2serr("\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ pr2serr("%s: out of memory\n", rstmf_s);
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rstmf_cdb, sizeof(rstmf_cdb));
+ 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_TIMEOUT_SECS, verbose);
+ ret = sg_cmds_process_resp(ptvp, rstmf_s, res, mx_resp_len, sense_b,
+ noisy, verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = sense_cat;
+ break;
+ }
+ } else {
+ if ((verbose > 2) && (ret > 0)) {
+ pr2serr("%s response:\n", rstmf_s);
+ dStrHexErr((const char *)resp, ret, 1);
+ }
+ ret = 0;
+ }
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
static int
process_cl_new(struct opts_t * op, int argc, char * argv[])
{
@@ -527,7 +642,8 @@ static void
list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op,
int sg_fd)
{
- int k, j, m, cd_len, serv_act, len, sa_v, opcode, res;
+ int k, j, m, cd_len, serv_act, len, opcode, res;
+ bool sa_v;
unsigned int to;
unsigned char * bp;
char name_buff[NAME_BUFF_SZ];
@@ -588,7 +704,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op,
bp = op->do_unsorted ? (rsoc_buff + 4 + k) : sort_arr[j];
len = (bp[5] & 0x2) ? 20 : 8;
opcode = bp[0];
- sa_v = bp[5] & 1;
+ sa_v = !!(bp[5] & 1);
serv_act = 0;
if (sa_v) {
serv_act = sg_get_unaligned_be16(bp + 2);
@@ -977,111 +1093,3 @@ err_out:
scsi_pt_close_device(sg_fd);
return res;
}
-
-static int
-do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode, int rq_servact,
- void * resp, int mx_resp_len, int noisy, int verbose)
-{
- int k, ret, res, sense_cat;
- unsigned char rsoc_cdb[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (rctd)
- rsoc_cdb[2] |= 0x80;
- if (rep_opts)
- rsoc_cdb[2] |= (rep_opts & 0x7);
- if (rq_opcode > 0)
- rsoc_cdb[3] = (rq_opcode & 0xff);
- if (rq_servact > 0)
- sg_put_unaligned_be16((uint16_t)rq_servact, rsoc_cdb + 4);
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rsoc_cdb + 6);
-
- if (verbose) {
- pr2serr(" Report Supported Operation Codes cmd: ");
- for (k = 0; k < RSOC_CMD_LEN; ++k)
- pr2serr("%02x ", rsoc_cdb[k]);
- pr2serr("\n");
- }
- ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp) {
- pr2serr("Report Supported Operation Codes: out of memory\n");
- return -1;
- }
- set_scsi_pt_cdb(ptvp, rsoc_cdb, sizeof(rsoc_cdb));
- 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_TIMEOUT_SECS, verbose);
- ret = sg_cmds_process_resp(ptvp, "Report Supported Operation Codes", res,
- mx_resp_len, sense_b, noisy, verbose,
- &sense_cat);
- if (-1 == ret)
- ;
- else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
-
-static int
-do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len, int noisy,
- int verbose)
-{
- int k, ret, res, sense_cat;
- unsigned char rstmf_cdb[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_pt_base * ptvp;
-
- if (repd)
- rstmf_cdb[2] = 0x80;
- sg_put_unaligned_be32((uint32_t)mx_resp_len, rstmf_cdb + 6);
-
- if (verbose) {
- pr2serr(" Report Supported Task Management Functions cmd: ");
- for (k = 0; k < RSTMF_CMD_LEN; ++k)
- pr2serr("%02x ", rstmf_cdb[k]);
- pr2serr("\n");
- }
- ptvp = construct_scsi_pt_obj();
- if (NULL == ptvp) {
- pr2serr("Report Supported Task Management Functions: out of memory\n");
- return -1;
- }
- set_scsi_pt_cdb(ptvp, rstmf_cdb, sizeof(rstmf_cdb));
- 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_TIMEOUT_SECS, verbose);
- ret = sg_cmds_process_resp(ptvp, "Report Supported Task management "
- "functions", res, mx_resp_len, sense_b, noisy,
- verbose, &sense_cat);
- if (-1 == ret)
- ;
- else if (-2 == ret) {
- switch (sense_cat) {
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- ret = 0;
- break;
- default:
- ret = sense_cat;
- break;
- }
- } else
- ret = 0;
-
- destruct_scsi_pt_obj(ptvp);
- return ret;
-}
diff --git a/src/sg_read_buffer.c b/src/sg_read_buffer.c
index c735d293..e6dc7efb 100644
--- a/src/sg_read_buffer.c
+++ b/src/sg_read_buffer.c
@@ -30,7 +30,7 @@
* device.
*/
-static const char * version_str = "1.16 20160512";
+static const char * version_str = "1.17 20160531";
#ifndef SG_READ_BUFFER_10_CMD
@@ -351,7 +351,7 @@ main(int argc, char * argv[])
break;
}
}
- if (NULL == mp) {
+ if (NULL == mp->mode_string) {
print_modes();
return SG_LIB_SYNTAX_ERROR;
}
diff --git a/src/sg_sanitize.c b/src/sg_sanitize.c
index 8e1aa4d9..7370ab38 100644
--- a/src/sg_sanitize.c
+++ b/src/sg_sanitize.c
@@ -28,7 +28,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.02 20160528";
+static const char * version_str = "1.02 20160531";
/* Not all environments support the Unix sleep() */
#if defined(MSC_VER) || defined(__MINGW32__)
@@ -202,7 +202,7 @@ do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp,
sg_put_unaligned_be16((uint16_t)param_lst_len, san_cdb + 7);
if (op->verbose > 1) {
- pr2serr(" Sanitize cmd: ");
+ pr2serr(" Sanitize cdb: ");
for (k = 0; k < SANITIZE_OP_LEN; ++k)
pr2serr("%02x ", san_cdb[k]);
pr2serr("\n");
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 19473bb0..ad001a08 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -37,7 +37,7 @@
*/
-static const char * version_str = "1.23 20160528"; /* spc5r10 + sbc4r10 */
+static const char * version_str = "1.24 20160531"; /* spc5r10 + sbc4r10 */
/* These structures are duplicates of those of the same name in
@@ -291,8 +291,8 @@ static int
f2hex_arr(const char * fname, int as_binary, 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, fd;
- bool has_stdin;
+ int fn_len, in_len, k, j, m, fd;
+ bool has_stdin, split_line;
unsigned int h;
const char * lcp;
FILE * fp;
@@ -370,9 +370,9 @@ f2hex_arr(const char * fname, int as_binary, int no_space,
if ('\n' == line[in_len - 1]) {
--in_len;
line[in_len] = '\0';
- split_line = 0;
+ split_line = false;
} else
- split_line = 1;
+ split_line = true;
}
if (in_len < 1) {
carry_over[0] = 0;
@@ -2580,7 +2580,6 @@ static int
svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
{
int len, res;
- int alloc_len = op->maxlen;
unsigned char * rp;
rp = rsp_buff + off;
@@ -2595,12 +2594,8 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
else
printf("VPD page code=%d:\n", op->vpd_pn);
}
- if (sg_fd >= 0) {
- if (0 == alloc_len)
- alloc_len = DEF_ALLOC_LEN;
- }
- res = vpd_fetch_page_from_dev(sg_fd, rp, op->vpd_pn, alloc_len,
+ res = vpd_fetch_page_from_dev(sg_fd, rp, op->vpd_pn, op->maxlen,
op->verbose, &len);
if (0 == res) {
if (op->do_raw)
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index a56afca5..3ac9e04b 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -1307,6 +1307,21 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
int alloc_len = op->maxlen;
unsigned char * rp;
+ switch (op->vpd_pn) {
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xd0:
+ break;
+ default: /* not known so return prior to fetching page */
+ return SG_LIB_SYNTAX_ERROR;
+ }
rp = rsp_buff + off;
if (sg_fd >= 0) {
if (0 == alloc_len)
@@ -1417,6 +1432,8 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
dStrHex((const char *)rp, len, 0);
break;
default:
+ pr2serr("%s: logic error, should know can't decode "
+ "pn=0x%x\n", __func__, op->vpd_pn);
return SG_LIB_SYNTAX_ERROR;
}
return 0;
diff --git a/src/sg_write_buffer.c b/src/sg_write_buffer.c
index 184bc484..17fa4852 100644
--- a/src/sg_write_buffer.c
+++ b/src/sg_write_buffer.c
@@ -29,7 +29,7 @@
* This utility issues the SCSI WRITE BUFFER command to the given device.
*/
-static const char * version_str = "1.21 20160528"; /* spc5r10 */
+static const char * version_str = "1.21 20160531"; /* spc5r10 */
#define ME "sg_write_buffer: "
#define DEF_XFER_LEN (8 * 1024 * 1024)
@@ -200,7 +200,7 @@ sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id,
sg_put_unaligned_be24(buffer_offset, wbuf_cdb + 3);
sg_put_unaligned_be24(param_len, wbuf_cdb + 6);
if (verbose) {
- pr2serr(" Write buffer cmd: ");
+ pr2serr(" Write buffer cdb: ");
for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
pr2serr("%02x ", wbuf_cdb[k]);
pr2serr("\n");
diff --git a/src/sg_write_same.c b/src/sg_write_same.c
index 7c9078ac..6055b42e 100644
--- a/src/sg_write_same.c
+++ b/src/sg_write_same.c
@@ -29,7 +29,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.14 20160528";
+static const char * version_str = "1.14 20160531";
#define ME "sg_write_same: "
@@ -247,7 +247,7 @@ do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp,
}
if (op->verbose > 1) {
- pr2serr(" Write same(%d) cmd: ", cdb_len);
+ pr2serr(" Write same(%d) cdb: ", cdb_len);
for (k = 0; k < cdb_len; ++k)
pr2serr("%02x ", ws_cdb[k]);
pr2serr("\n Data-out buffer length=%d\n",
diff --git a/src/sg_write_verify.c b/src/sg_write_verify.c
index e5412fbb..0f94a4cd 100644
--- a/src/sg_write_verify.c
+++ b/src/sg_write_verify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 Douglas Gilbert
+ * Copyright (c) 2014-2016 Douglas Gilbert
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
@@ -35,7 +35,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.08 20151220";
+static const char * version_str = "1.09 20160531";
#define ME "sg_write_verify: "
@@ -129,7 +129,7 @@ run_scsi_transaction(int sg_fd, const unsigned char *cdbp, int cdb_len,
snprintf(b, sizeof(b), "Write and verify(%d)", cdb_len);
if (verbose) {
- pr2serr(" %s cmd: ", b);
+ pr2serr(" %s cdb: ", b);
for (k = 0; k < cdb_len; ++k)
pr2serr("%02x ", cdbp[k]);
pr2serr("\n");