aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-09-11 23:13:21 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-09-11 23:13:21 +0000
commit23b8f9c3a44e6be249911b97c4cf02da601be519 (patch)
treed475856169c8a08001e1f8813408ed71bdc14197
parent38a3773e8ef84bd18fcf266df4e697e431c73882 (diff)
downloadsg3_utils-23b8f9c3a44e6be249911b97c4cf02da601be519.tar.gz
sg_vpd: decode some WDC/Hitachi vendor VPD pages; sg_modes: accept acronym for page/subpage codes; attempted 1.43 release
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@789 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog5
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg3_utils.82
-rw-r--r--doc/sg_format.817
-rw-r--r--doc/sg_modes.813
-rw-r--r--doc/sg_seek.820
-rw-r--r--include/sg_cmds_basic.h6
-rw-r--r--include/sg_lib.h6
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/Makefile.in5
-rw-r--r--lib/sg_lib.c5
-rw-r--r--lib/sg_lib_data.c2
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.in5
-rw-r--r--src/sg_logs.c190
-rw-r--r--src/sg_modes.c569
-rw-r--r--src/sg_readcap.c28
-rw-r--r--src/sg_seek.c10
-rw-r--r--src/sg_ses.c6
-rw-r--r--src/sg_timestamp.c4
-rw-r--r--src/sg_vpd.c9
-rw-r--r--src/sg_vpd_vendor.c105
23 files changed, 737 insertions, 283 deletions
diff --git a/ChangeLog b/ChangeLog
index cb7093b8..bda6b26e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,8 @@ 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 [20180831] [svn: r788]
+Changelog for sg3_utils-1.43 [20180911] [svn: r789]
+ - release 1.43 20180911 svn rev 789
- sg_write_x: where x can be normal, atomic, or(write),
same, scattered, or stream writes with 16 or 32 byte
cdbs (sbc4r04 for atomic, sbc4r11 for scattered)
@@ -85,6 +86,7 @@ Changelog for sg3_utils-1.43 [20180831] [svn: r788]
Vpd Pages page and fetch requested page directly
- sg_vpd: 3 party copy VPD page improvements
- fully implement Device constituents VPD page
+ - decode some WDC/Hitachi vendor VPD pages
- improve handling of unknown pages
- sg_reassign+sg_write_same: fix ULONG_MAX problem
- sg_rdac: add sanity checks for -f=lun value
@@ -124,6 +126,7 @@ Changelog for sg3_utils-1.43 [20180831] [svn: r788]
statuses and the additional status (sbc4r12)
- decode completion condition (sbc4r14)
- sg_modes: add Out of band management control mpage
+ - accept acronym for page/subpage codes
- sg_rep_zones: expand --help option information
- sg_unmap: add --all=ST,RN[,LA] option to unmap
large contiguous segments of a disk/ssd
diff --git a/debian/changelog b/debian/changelog
index 4a553fe7..da0a526c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.43-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Fri, 31 Aug 2018 21:00:00 +0200
+ -- Douglas Gilbert <dgilbert@interlog.com> Tue, 11 Sep 2018 09:00:00 -0400
sg3-utils (1.42-0.1) unstable; urgency=low
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 1c5ba619..a4034dac 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "July 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG3_UTILS "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
diff --git a/doc/sg_format.8 b/doc/sg_format.8
index f25a2283..d1d3fdef 100644
--- a/doc/sg_format.8
+++ b/doc/sg_format.8
@@ -1,4 +1,4 @@
-.TH SG_FORMAT "8" "August 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_FORMAT "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_format \- format, resize a SCSI disk or format a tape
.SH SYNOPSIS
@@ -406,6 +406,15 @@ default value of \fIPFU\fR (in \fI\-\-pfu=PFU\fR) is 0. So if neither
\fI\-\-fmtpinfo=FPI\fR nor \fI\-\-pfu=PFU\fR are given then protection
type 0 (i.e. no protection information) is chosen.
.SH NOTES
+After a format that changes the logical block size or the number of logical
+blocks on a disk, the operating system may need to be told to re\-initialize
+its setting for that disk. In Linux that can be done with:
+.br
+ echo 1 > /sys/block/sd{letter(s)}/device/rescan
+.br
+where "letter(s)" will be between 'a' and 'zzz'. The lsscsi utility in Linux
+can be used to check the various namings of a disk.
+.PP
The SBC\-2 standard states that the REQUEST SENSE command should be used
for obtaining progress indication when the format command is underway.
However, tests on a selection of disks shows that TEST UNIT READY
@@ -614,11 +623,11 @@ quickly switch between 512 and 4096 byte logical block size. Assume disk
starts with 4096 byte logical block size and all important data has been
backed up.
.PP
- # sg_format \-\-format \-\-ffmt=1 \-\-size=512 \-\-count=\-1 /dev/sdd
+ # sg_format \-\-format \-\-ffmt=1 \-\-size=512 /dev/sdd
.PP
Now /dev/sdd should have 512 byte logical block size. And to switch it back:
.PP
- # sg_format \-\-format \-\-ffmt=1 \-\-size=4096 \-\-count=\-1 /dev/sdd
+ # sg_format \-\-format \-\-ffmt=1 \-\-size=4096 /dev/sdd
.SH EXIT STATUS
The exit status of sg_format is 0 when it is successful. Otherwise see
the sg3_utils(8) man page. Unless the \fI\-\-wait\fR option is given, the
@@ -637,4 +646,4 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.B sg_turs(8), sg_requests(8), sg_inq(8), sg_modes(8), sg_vpd(8),
.B sg_reassign(8), sg_readcap(8), sg3_utils(8),
.B sg_sanitize(8) [all in sg3_utils],
-.B mt(mt\-st), sdparm(8), scsiformat (old), hdparm(8)
+.B lsscsi(8), mt(mt\-st), sdparm(8), scsiformat (old), hdparm(8)
diff --git a/doc/sg_modes.8 b/doc/sg_modes.8
index ce970e96..ed2d2e33 100644
--- a/doc/sg_modes.8
+++ b/doc/sg_modes.8
@@ -1,4 +1,4 @@
-.TH SG_MODES "8" "November 2017" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_MODES "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_modes \- reads mode pages with SCSI MODE SENSE command
.SH SYNOPSIS
@@ -143,6 +143,10 @@ page code to fetch. The \fIPG\fR is assumed to be a decimal value unless
prefixed by '0x' or has a trailing 'h'. It should be a value between 0
and 63 (inclusive). When not given and a default is required then
a value of 63 (0x3f), which fetches all mode pages, is used.
+.br
+Alternatively an acronym for the mode page can be given. The available
+acronyms can be listed out with the \fI\-\-page=xxx\fR option. They are
+almost the same as the acronyms used for mode pages in the sdparm utility.
.TP
\fB\-p\fR, \fB\-\-page\fR=\fIPG,SPG\fR
page code and subpage code values to fetch. Both arguments are assumed
@@ -253,7 +257,10 @@ see \fB\-\-maxlen\fR=\fILEN\fR in the main description.
\fB\-p\fR=\fIPG\fR
\fIPG\fR is page code to fetch. Should be a hexadecimal number between 0
and 3f inclusive (0 to 63 decimal). The default value when required is
-3f (fetch all mode pages).
+3f (fetch all mode pages). Note that an acronym for the page and/or
+subpage values is not accepted in this older format (because any acronym
+starting with the letters 'a' to 'f' is ambiguous; it could either be a hex
+number or an acronym).
.TP
\fB\-p\fR=\fIPG,SPG\fR
page code and subpage code values to fetch. The page code should be a
@@ -291,7 +298,7 @@ Written by Douglas Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000\-2017 Douglas Gilbert
+Copyright \(co 2000\-2018 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_seek.8 b/doc/sg_seek.8
index 99685003..1b11f751 100644
--- a/doc/sg_seek.8
+++ b/doc/sg_seek.8
@@ -1,4 +1,4 @@
-.TH SG_SEEK "8" "January 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_SEEK "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_seek \- send SCSI SEEK, PRE-FETCH(10) or PRE-FETCH(16) command
.SH SYNOPSIS
@@ -29,7 +29,7 @@ blocks did not fit (IMMED=0) or would not fit (IMMED=1) then status GOOD
is returned. So if a disk has a large cache and PRE\-FETCH is used sparingly
then the command is more likely to return CONDITION MET than GOOD. This
presents some SCSI sub\-systems with problems as due to its rareness they
-mishandle CONDITION MET and treat it as an error.
+mishandle CONDITION MET and treat it as an error (see NOTES section below).
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
.TP
@@ -119,10 +119,20 @@ set the next command's logical block address back to \fILBA\fR. Whether
this "reset\-to\-LBA" action occurs depends on the values \fINC\fR and
\fISB\fR.
.SH NOTES
-As of Linux kernel 4.15 the CONDITION MET status is logged as an error.
+Prior to Linux kernel 4.17 the CONDITION MET status was logged as an error.
+Recent versions of FreeBSD handle the CONDITION MET status properly.
+.PP
+If either the \fI\-\-count=NC\fR or \fI\-\-verbose\fR option is given then
+a summary line like the following is output:
+.PP
+ Command count=5, number of condition_mets=3, number of goods=2
+.PP
+before the utility exits.
.SH EXIT STATUS
-The exit status of sg_stream_ctl is 0 when it is successful. Otherwise see
-the sg3_utils(8) man page.
+The exit status of sg_seek is 0 (GOOD) or 25 (CONDITION_MET) when this
+utility is successful. If multiple commands are executed (e.g. when \fINC\fR
+is greater than 1) then the result of the last executed SEEK or PRE\-FETCH
+command sets the exit status. Otherwise see the sg3_utils(8) man page.
.SH AUTHORS
Written by Douglas Gilbert.
.SH "REPORTING BUGS"
diff --git a/include/sg_cmds_basic.h b/include/sg_cmds_basic.h
index fe194fce..4fb0ddf7 100644
--- a/include/sg_cmds_basic.h
+++ b/include/sg_cmds_basic.h
@@ -107,7 +107,7 @@ int sg_ll_mode_select6_v2(int sg_fd, bool pf, bool rtd, bool sp,
* -1 -> other failure */
int sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp,
int param_len, bool noisy, int verbose);
-/* v2 adds RTD (revert to defaults) bi, added in spc5r11 */
+/* v2 adds RTD (revert to defaults) bit, added in spc5r11 */
int sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp,
void * paramp, int param_len, bool noisy,
int verbose);
@@ -291,8 +291,8 @@ int sg_msense_calc_length(const uint8_t * resp, int resp_len,
/* Fetches current, changeable, default and/or saveable modes pages as
* indicated by pcontrol_arr for given pg_code and sub_pg_code. If
- * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If
- * flexible set and mode data length seems wrong then try and
+ * mode6 is true then use MODE SENSE (6) else use MODE SENSE (10). If
+ * flexible true and mode data length seems wrong then try and
* fix (compensating hack for bad device or driver). pcontrol_arr
* should have 4 elements for output of current, changeable, default
* and saved values respectively. Each element should be NULL or
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 83eeb72c..e860b926 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -332,7 +332,7 @@ const char * sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len,
* structures that are sent across the wire. The 'FIS register' structure is
* used to move a command from a SATA host to device, but the ATA 'command'
* is not the first byte. So it is harder to say what will happen if a
- * FIS structure is presented as a SCSI command, hopfully there is a low
+ * FIS structure is presented as a SCSI command, hopefully there is a low
* probability this function will yield true in that case. */
bool sg_is_scsi_cdb(const uint8_t * cdbp, int clen);
@@ -364,7 +364,7 @@ extern FILE * sg_warnings_strm;
void sg_set_warnings_strm(FILE * warnings_strm);
-/* The following "print" functions send ACSII to 'sg_warnings_strm' file
+/* The following "print" functions send ASCII to 'sg_warnings_strm' file
* descriptor (default value is stderr). 'leadin' is string prepended to
* each line printed out, NULL treated as "". */
void sg_print_command(const uint8_t * command);
@@ -560,7 +560,7 @@ bool sg_is_big_endian();
/* Returns true if byte sequence starting at bp with a length of b_len is
* all zeros (for sg_all_zeros()) or all 0xff_s (for sg_all_ffs());
- * otherwise returns false. If bp is NULL ir b_len <= 0 returns false. */
+ * otherwise returns false. If bp is NULL or b_len <= 0 returns false. */
bool sg_all_zeros(const uint8_t * bp, int b_len);
bool sg_all_ffs(const uint8_t * bp, int b_len);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 09cef059..f90fed95 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -35,8 +35,9 @@ libsgutils2_la_SOURCES += sg_pt_osf1.c
endif
if DEBUG
-# This does nothing at the moment but may be useful for adding
-DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
+# This is active if --enable-debug given to ./configure
+# removed -Wduplicated-branches because needs gcc-8
+DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
DBG_CPPFLAGS = -DDEBUG
else
DBG_CFLAGS =
diff --git a/lib/Makefile.in b/lib/Makefile.in
index bd1c658f..1b28ad22 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -350,8 +350,9 @@ libsgutils2_la_SOURCES = sg_lib.c sg_lib_data.c sg_cmds_basic.c \
$(am__append_4) $(am__append_5) $(am__append_6)
@DEBUG_FALSE@DBG_CFLAGS =
-# This does nothing at the moment but may be useful for adding
-@DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
+# This is active if --enable-debug given to ./configure
+# removed -Wduplicated-branches because needs gcc-8
+@DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
@DEBUG_FALSE@DBG_CPPFLAGS =
@DEBUG_TRUE@DBG_CPPFLAGS = -DDEBUG
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 3e67fda3..c2c58916 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -1334,7 +1334,10 @@ sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
switch (descp[0]) {
case 0:
n += sg_scnpr(b + n, blen - n, "Information: ");
- if ((add_d_len >= 10) && (0x80 & descp[2])) {
+ if (add_d_len >= 10) {
+ if (! (0x80 & descp[2]))
+ n += sg_scnpr(b + n, blen - n, "Valid=0 (-> vendor "
+ "specific) ");
n += sg_scnpr(b + n, blen - n, "0x");
for (j = 0; j < 8; ++j)
n += sg_scnpr(b + n, blen - n, "%02x", descp[4 + j]);
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 5055f357..d5ca380b 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -17,7 +17,7 @@
#include "sg_lib_data.h"
-const char * sg_lib_version_str = "2.56 20180831";/* spc5r19, sbc4r15 */
+const char * sg_lib_version_str = "2.58 20180911";/* spc5r19, sbc4r15 */
/* indexed by pdt; those that map to own index do not decay */
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 00fd21e1..440f0efa 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Fri Aug 31 2018 - dgilbert at interlog dot com
+* Tue Sep 11 2018 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.43
diff --git a/src/Makefile.am b/src/Makefile.am
index 97f58e16..881cf296 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,8 +33,10 @@ bin_PROGRAMS += sg_scan
sg_scan_SOURCES += sg_scan_win32.c
endif
+# This is active if --enable-debug given to ./configure
+# removed -Wduplicated-branches because needs gcc-8
if DEBUG
-DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
+DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
DBG_CPPFLAGS = -DDEBUG
else
DBG_CFLAGS =
diff --git a/src/Makefile.in b/src/Makefile.in
index 22cc987e..59d11661 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -569,7 +569,10 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
sg_scan_SOURCES = $(am__append_2) $(am__append_4) $(am__append_6)
@DEBUG_FALSE@DBG_CFLAGS =
-@DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
+
+# This is active if --enable-debug given to ./configure
+# removed -Wduplicated-branches because needs gcc-8
+@DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
@DEBUG_FALSE@DBG_CPPFLAGS =
@DEBUG_TRUE@DBG_CPPFLAGS = -DDEBUG
diff --git a/src/sg_logs.c b/src/sg_logs.c
index 0e5b5be3..61443ff1 100644
--- a/src/sg_logs.c
+++ b/src/sg_logs.c
@@ -34,7 +34,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.68 20180626"; /* spc5r19 + sbc4r11 */
+static const char * version_str = "1.69 20180911"; /* spc5r19 + sbc4r11 */
#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
@@ -79,11 +79,10 @@ static const char * version_str = "1.68 20180626"; /* spc5r19 + sbc4r11 */
#define VP_NONE (-1)
#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_TOSH 2
+#define VP_SMSTR 3
+#define VP_LTO5 4
+#define VP_LTO6 5
#define VP_ALL 99
#define MVP_OFFSET 8
@@ -92,7 +91,6 @@ static const char * version_str = "1.68 20180626"; /* spc5r19 + sbc4r11 */
#define MVP_STD (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))
@@ -110,6 +108,7 @@ static const char * version_str = "1.68 20180626"; /* spc5r19 + sbc4r11 */
static uint8_t * rsp_buff;
static uint8_t * free_rsp_buff;
static const int rsp_buff_sz = MX_ALLOC_LEN + 4;
+static const int parr_sz = 4096;
static struct option long_options[] = {
{"All", no_argument, 0, 'A'}, /* equivalent to '-aa' */
@@ -303,6 +302,10 @@ static bool show_seagate_cache_page(const uint8_t * resp, int len,
const struct opts_t * op);
static bool show_seagate_factory_page(const uint8_t * resp, int len,
const struct opts_t * op);
+static bool show_hgst_perf_page(const uint8_t * resp, int len,
+ const struct opts_t * op);
+static bool show_hgst_misc_page(const uint8_t * resp, int len,
+ const struct opts_t * op);
/* elements in page_number/subpage_number order */
static struct log_elem log_arr[] = {
@@ -410,7 +413,7 @@ static struct log_elem log_arr[] = {
"ie", show_ie_page}, /* 0x2f, 0 */
/* vendor specific */
{0x30, 0, 0, PDT_DISK, MVP_HITA, "Performance counters (Hitachi)",
- "pc_hi", NULL}, /* 0x30, 0 SBC */
+ "pc_hi", show_hgst_perf_page}, /* 0x30, 0 SBC */
{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, OVP_LTO, "Tape capacity (lto-5, 6)",
@@ -426,7 +429,7 @@ static struct log_elem log_arr[] = {
{0x37, 0, 0, PDT_DISK, MVP_SEAG, "Cache (seagate)", "c_se",
show_seagate_cache_page}, /* 0x37, 0 SBC */
{0x37, 0, 0, PDT_DISK, MVP_HITA, "Miscellaneous (hitachi)", "mi_hi",
- NULL}, /* 0x37, 0 SBC */
+ show_hgst_misc_page}, /* 0x37, 0 SBC */
{0x37, 0, 0, PDT_TAPE, MVP_LTO5, "Performance characteristics "
"(lto-5)", "pc_", NULL}, /* 0x37, 0 SSC */
{0x38, 0, 0, PDT_TAPE, MVP_LTO5, "Blocks/bytes transferred "
@@ -456,7 +459,7 @@ static struct log_elem log_arr[] = {
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_HITA, "wdc", "WDC/Hitachi", "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},
@@ -2343,6 +2346,82 @@ show_tape_usage_page(const uint8_t * resp, int len, const struct opts_t * op)
return true;
}
+/* 0x30 */
+static bool
+show_hgst_perf_page(const uint8_t * resp, int len, const struct opts_t * op)
+{
+ bool valid = false;
+ int num, pl, pc;
+ const uint8_t * bp;
+ char str[PCB_STR_LEN];
+
+ if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
+ printf("HGST/WDC performance counters page [0x30]\n");
+ num = len - 4;
+ if (num < 0x30) {
+ printf("HGST/WDC performance counters page too short (%d) < 48\n",
+ num);
+ return valid;
+ }
+ bp = &resp[0] + 4;
+ while (num > 3) {
+ pc = sg_get_unaligned_be16(bp + 0);
+ pl = bp[3] + 4;
+ if (op->filter_given) {
+ if (pc != op->filter)
+ goto skip;
+ if (op->do_raw) {
+ dStrRaw(bp, pl);
+ break;
+ } else if (op->do_hex) {
+ hex2stdout(bp, pl, ((1 == op->do_hex) ? 1 : -1));
+ break;
+ }
+ }
+ switch (pc) {
+ case 0:
+ valid = true;
+ printf(" Zero Seeks = %u\n", sg_get_unaligned_be16(bp + 4));
+ printf(" Seeks >= 2/3 = %u\n", sg_get_unaligned_be16(bp + 6));
+ printf(" Seeks >= 1/3 and < 2/3 = %u\n",
+ sg_get_unaligned_be16(bp + 8));
+ printf(" Seeks >= 1/6 and < 1/3 = %u\n",
+ sg_get_unaligned_be16(bp + 10));
+ printf(" Seeks >= 1/12 and < 1/6 = %u\n",
+ sg_get_unaligned_be16(bp + 12));
+ printf(" Seeks > 0 and < 1/12 = %u\n",
+ sg_get_unaligned_be16(bp + 14));
+ printf(" Overrun Counter = %u\n",
+ sg_get_unaligned_be16(bp + 20));
+ printf(" Underrun Counter = %u\n",
+ sg_get_unaligned_be16(bp + 22));
+ printf(" Device Cache Full Read Hits = %u\n",
+ sg_get_unaligned_be32(bp + 24));
+ printf(" Device Cache Partial Read Hits = %u\n",
+ sg_get_unaligned_be32(bp + 28));
+ printf(" Device Cache Write Hits = %u\n",
+ sg_get_unaligned_be32(bp + 32));
+ printf(" Device Cache Fast Writes = %u\n",
+ sg_get_unaligned_be32(bp + 36));
+ printf(" Device Cache Read Misses = %u\n",
+ sg_get_unaligned_be32(bp + 40));
+ break;
+ default:
+ valid = false;
+ printf(" Unknown HGST/WDC parameter code = 0x%x", pc);
+ break;
+ }
+ if (op->do_pcb)
+ printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
+ if (op->filter_given)
+ break;
+skip:
+ num -= pl;
+ bp += pl;
+ }
+ return valid;
+}
+
/* Tape capacity: vendor specific (LTO-5 and LTO-6 ?): 0x31 */
static bool
show_tape_capacity_page(const uint8_t * resp, int len,
@@ -6497,6 +6576,73 @@ skip:
return true;
}
+/* 0x37 */
+static bool
+show_hgst_misc_page(const uint8_t * resp, int len, const struct opts_t * op)
+{
+ bool valid = false;
+ int num, pl, pc;
+ const uint8_t * bp;
+ char str[PCB_STR_LEN];
+
+ if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
+ printf("HGST/WDC miscellaneous page [0x37]\n");
+ num = len - 4;
+ if (num < 0x30) {
+ printf("HGST/WDC miscellaneous page too short (%d) < 48\n", num);
+ return valid;
+ }
+ bp = &resp[0] + 4;
+ while (num > 3) {
+ pc = sg_get_unaligned_be16(bp + 0);
+ pl = bp[3] + 4;
+ if (op->filter_given) {
+ if (pc != op->filter)
+ goto skip;
+ if (op->do_raw) {
+ dStrRaw(bp, pl);
+ break;
+ } else if (op->do_hex) {
+ hex2stdout(bp, pl, ((1 == op->do_hex) ? 1 : -1));
+ break;
+ }
+ }
+ switch (pc) {
+ case 0:
+ valid = true;
+ printf(" Power on hours = %u\n", sg_get_unaligned_be32(bp + 4));
+ printf(" Total Bytes Read = %" PRIu64 "\n",
+ sg_get_unaligned_be64(bp + 8));
+ printf(" Total Bytes Written = %" PRIu64 "\n",
+ sg_get_unaligned_be64(bp + 16));
+ printf(" Max Drive Temp (Celsius) = %u\n", bp[24]);
+ printf(" GList Size = %u\n", sg_get_unaligned_be16(bp + 25));
+ printf(" Number of Information Exceptions = %u\n", bp[27]);
+ printf(" MED EXC = %u\n", !! (0x80 & bp[28]));
+ printf(" HDW EXC = %u\n", !! (0x40 & bp[28]));
+ printf(" Total Read Commands = %" PRIu64 "\n",
+ sg_get_unaligned_be64(bp + 29));
+ printf(" Total Write Commands = %" PRIu64 "\n",
+ sg_get_unaligned_be64(bp + 37));
+ printf(" Flash Correction Count = %u\n",
+ sg_get_unaligned_be16(bp + 46));
+ break;
+ default:
+ valid = false;
+ printf(" Unknown HGST/WDC parameter code = 0x%x", pc);
+ break;
+ }
+ if (op->do_pcb)
+ printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
+ if (op->filter_given)
+ break;
+skip:
+ num -= pl;
+ bp += pl;
+ }
+ return valid;
+}
+
/* 0x3e */
static bool
show_seagate_factory_page(const uint8_t * resp, int len,
@@ -6704,6 +6850,8 @@ main(int argc, char * argv[])
int in_len = -1;
int sg_fd = -1;
int ret = 0;
+ uint8_t * parr;
+ uint8_t * free_parr = NULL;
struct sg_simple_inquiry_resp inq_out;
struct opts_t opts;
struct opts_t * op;
@@ -7024,24 +7172,32 @@ main(int argc, char * argv[])
if (op->do_all && (pg_len > 1)) {
int my_len = pg_len;
bool spf;
- uint8_t parr[1024];
+ parr = sg_memalign(parr_sz, 0, &free_parr, false);
+ if (NULL == parr) {
+ pr2serr("Unable to allocate heap for parr\n");
+ ret = sg_convert_errno(ENOMEM);
+ goto err_out;
+ }
spf = !!(rsp_buff[0] & 0x40);
- if (my_len > (int)sizeof(parr)) {
+ if (my_len > parr_sz) {
pr2serr("Unexpectedly large page_len=%d, trim to %d\n", my_len,
- (int)sizeof(parr));
- my_len = sizeof(parr);
+ parr_sz);
+ my_len = parr_sz;
}
memcpy(parr, rsp_buff + 4, my_len);
for (k = 0; k < my_len; ++k) {
- if (! op->do_raw)
- printf("\n");
op->pg_code = parr[k] & 0x3f;
if (spf)
op->subpg_code = parr[++k];
else
op->subpg_code = NOT_SPG_SUBPG;
+ /* Some devices include [pg_code, 0xff] for all pg_code > 0 */
+ if ((op->pg_code > 0) && (SUPP_SPGS_SUBPG == op->subpg_code))
+ continue; /* skip since no new information */
+ if (! op->do_raw)
+ printf("\n");
res = do_logs(sg_fd, rsp_buff, resp_len, op);
if (0 == res) {
pg_len = sg_get_unaligned_be16(rsp_buff + 2);
@@ -7087,6 +7243,8 @@ main(int argc, char * argv[])
err_out:
if (free_rsp_buff)
free(free_rsp_buff);
+ if (free_parr)
+ free(free_parr);
if (sg_fd >= 0)
sg_cmds_close_device(sg_fd);
if (0 == vb) {
diff --git a/src/sg_modes.c b/src/sg_modes.c
index cae8477e..babb05d2 100644
--- a/src/sg_modes.c
+++ b/src/sg_modes.c
@@ -30,10 +30,11 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.64 20180626";
+static const char * version_str = "1.66 20180909";
#define DEF_ALLOC_LEN (1024 * 4)
#define DEF_6_ALLOC_LEN 252
+#define UNLIKELY_ABOVE_LEN 512
#define PG_CODE_ALL 0x3f
#define PG_CODE_MASK 0x3f
#define PG_CODE_MAX 0x3f
@@ -44,6 +45,44 @@ static const char * version_str = "1.64 20180626";
#define EBUFF_SZ 256
+struct opts_t {
+ bool do_dbd;
+ bool do_dbout;
+ bool do_examine;
+ bool do_flexible;
+ bool do_list;
+ bool do_llbaa;
+ bool do_six;
+ bool o_readwrite;
+ bool subpg_code_given;
+ bool opt_new;
+ bool verbose_given;
+ bool version_given;
+ int do_all;
+ int do_help;
+ int do_hex;
+ int maxlen;
+ int do_raw;
+ int verbose;
+ int page_control;
+ int pg_code;
+ int subpg_code;
+ const char * device_name;
+ const char * page_acron;
+};
+
+struct page_code_desc {
+ int page_code;
+ int subpage_code;
+ const char * acron;
+ const char * desc;
+};
+
+struct pc_desc_group {
+ struct page_code_desc * pcdp;
+ const char * group_name;
+};
+
static struct option long_options[] = {
{"all", no_argument, 0, 'a'},
{"control", required_argument, 0, 'c'},
@@ -69,31 +108,166 @@ static struct option long_options[] = {
{0, 0, 0, 0},
};
-struct opts_t {
- bool do_dbd;
- bool do_dbout;
- bool do_examine;
- bool do_flexible;
- bool do_list;
- bool do_llbaa;
- bool do_six;
- bool o_readwrite;
- bool subpg_code_given;
- bool opt_new;
- bool verbose_given;
- bool version_given;
- int do_all;
- int do_help;
- int do_hex;
- int maxlen;
- int do_raw;
- int verbose;
- int page_control;
- int pg_code;
- int subpg_code;
- const char * device_name;
+static struct page_code_desc pc_desc_common[] = {
+ {0x0, 0x0, "ua", "Unit Attention condition [vendor specific format]"},
+ {0x2, 0x0, "dr", "Disconnect-Reconnect"},
+ {0x9, 0x0, "pd", "Peripheral device (obsolete)"},
+ {0xa, 0x0, "co", "Control"},
+ {0xa, 0x1, "coe", "Control extension"},
+ {0xa, 0x3, "cdla", "Command duration limit A"},
+ {0xa, 0x4, "cdlb", "Command duration limit B"},
+ {0x15, 0x0, "ext_", "Extended"},
+ {0x16, 0x0, "edts", "Extended device-type specific"},
+ {0x18, 0x0, "pslu", "Protocol specific lu"},
+ {0x19, 0x0, "pspo", "Protocol specific port"},
+ {0x1a, 0x0, "po", "Power condition"},
+ {0x1a, 0x1, "ps", "Power consumption"},
+ {0x1c, 0x0, "ie", "Informational exceptions control"},
+ {PG_CODE_ALL, 0x0, "asmp", "[yields all supported pages]"},
+ {PG_CODE_ALL, SPG_CODE_ALL,"asmsp",
+ "[yields all supported pages and subpages]"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_disk[] = {
+ {0x1, 0x0, "rw", "Read-Write error recovery"},
+ {0x3, 0x0, "fo", "Format (obsolete)"},
+ {0x4, 0x0, "rd", "Rigid disk geometry (obsolete)"},
+ {0x5, 0x0, "fg", "Flexible geometry (obsolete)"},
+ {0x7, 0x0, "ve", "Verify error recovery"},
+ {0x8, 0x0, "ca", "Caching"},
+ {0xa, 0x2, "atag", "Application tag"},
+ {0xa, 0x5, "ioad", "IO advice hints grouping"}, /* added sbc4r06 */
+ {0xa, 0x6, "bop", "Background operation control"}, /* added sbc4r07 */
+ {0xa, 0xf1, "pat", "Parallel ATA control (SAT)"},
+ {0xb, 0x0, "mts", "Medium types supported (obsolete)"},
+ {0xc, 0x0, "not", "Notch and partition (obsolete)"},
+ {0xd, 0x0, "pco", "Power condition (obsolete, moved to 0x1a)"},
+ {0x10, 0x0, "xo", "XOR control"}, /* obsolete in sbc3r32 */
+ {0x1a, 0xf1, "apo", "ATA Power condition"},
+ {0x1c, 0x1, "bc", "Background control"},
+ {0x1c, 0x2, "lbp", "Logical block provisioning"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_tape[] = {
+ {0x1, 0x0, "rw", "Read-Write error recovery"},
+ {0xa, 0xf0, "cdp", "Control data protection"},
+ {0xf, 0x0, "dac", "Data Compression"},
+ {0x10, 0x0, "dc", "Device configuration"},
+ {0x10, 0x1, "dcs", "Device configuration extension"},
+ {0x11, 0x0, "mpa", "Medium Partition [1]"},
+ {0x12, 0x0, "mpa2", "Medium Partition [2]"},
+ {0x13, 0x0, "mpa3", "Medium Partition [3]"},
+ {0x14, 0x0, "mpar", "Medium Partition [4]"},
+ {0x1c, 0x0, "ie", "Informational exceptions control (tape version)"},
+ {0x1d, 0x0, "mco", "Medium configuration"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_cddvd[] = {
+ {0x1, 0x0, "rw", "Read-Write error recovery"},
+ {0x3, 0x0, "mrw", "Mount Rainer rewritable"},
+ {0x5, 0x0, "wp", "Write parameters"},
+ {0x7, 0x0, "ve", "Verify error recovery"},
+ {0x8, 0x0, "ca", "Caching"},
+ {0xd, 0x0, "cddp", "CD device parameters (obsolete)"},
+ {0xe, 0x0, "cda", "CD audio"},
+ {0x1a, 0x0, "po", "Power condition (mmc)"},
+ {0x1c, 0x0, "ffrc", "Fault/failure reporting control (mmc)"},
+ {0x1d, 0x0, "tp", "Timeout and protect"},
+ {0x2a, 0x0, "cms", "MM capabilities and mechanical status (obsolete)"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_smc[] = {
+ {0x1d, 0x0, "eaa", "Element address assignment"},
+ {0x1e, 0x0, "tgp", "Transport geometry parameters"},
+ {0x1f, 0x0, "dcs", "Device capabilities"},
+ {0x1f, 0x41, "edc", "Extended device capabilities"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_scc[] = {
+ {0x1b, 0x0, "sslm", "LUN mapping"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_ses[] = {
+ {0x14, 0x0, "esm", "Enclosure services management"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_rbc[] = {
+ {0x6, 0x0, "rbc", "RBC device parameters"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_adc[] = {
+ /* {0xe, 0x0, "ADC device configuration"}, */
+ {0xe, 0x1, "adtd", "Target device"},
+ {0xe, 0x2, "addp", "DT device primary port"},
+ {0xe, 0x3, "adlu", "Logical unit"},
+ {0xe, 0x4, "adts", "Target device serial number"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+
+/* Transport reated mode pages */
+static struct page_code_desc pc_desc_t_fcp[] = {
+ {0x18, 0x0, "pl", "LU control"},
+ {0x19, 0x0, "pp", "Port control"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_t_spi4[] = {
+ {0x18, 0x0, "luc", "LU control"},
+ {0x19, 0x0, "pp", "Port control short format"},
+ {0x19, 0x1, "mc", "Margin control"},
+ {0x19, 0x2, "stc", "Saved training configuration value"},
+ {0x19, 0x3, "ns", "Negotiated settings"},
+ {0x19, 0x4, "rtc", "Report transfer capabilities"},
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_t_sas[] = {
+ {0x18, 0x0, "pslu", "Protocol specific logical unit (SAS)"},
+ {0x19, 0x0, "pspo", "Protocol specific port (SAS)"},
+ {0x19, 0x1, "pcd", "Phy control and discover (SAS)"},
+ {0x19, 0x2, "spc", "Shared port control (SAS)"},
+ {0x19, 0x3, "sep", "Enhanced phy control (SAS)"},
+ {0x19, 0x4, "oobm", "Out of band management control (SAS)"}, /* spl5r01 */
+ {0x0, 0x0, NULL, NULL},
+};
+
+static struct page_code_desc pc_desc_t_adc[] = {
+ {0xe, 0x1, "addt", "Target device"},
+ {0xe, 0x2, "addp", "DT device primary port"},
+ {0xe, 0x3, "adlu", "Logical unit"},
+ {0x18, 0x0, "pslu", "Protocol specific lu"},
+ {0x19, 0x0, "pspo", "Protocol specific port"},
+ {0x0, 0x0, NULL, NULL},
};
+struct pc_desc_group pcd_gr_arr[] = {
+ {pc_desc_common, "common"},
+ {pc_desc_disk, "disk"},
+ {pc_desc_tape, "tape"},
+ {pc_desc_cddvd, "cd/dvd"},
+ {pc_desc_smc, "media changer"},
+ {pc_desc_scc, "scsi controller"},
+ {pc_desc_ses, "enclosure"},
+ {pc_desc_rbc, "reduced block"},
+ {pc_desc_adc, "adc"},
+ {pc_desc_t_fcp, "transport: FCP"},
+ {pc_desc_t_spi4, "transport: SPI"},
+ {pc_desc_t_sas, "transport: SAS"},
+ {pc_desc_t_adc, "transport: ADC"},
+
+ {NULL, NULL},
+};
+
+
static void
usage()
@@ -130,7 +304,8 @@ usage()
"length in cdb)\n"
" (def: 0 -> 4096 or 252 (for MODE "
"SENSE 6) bytes)\n"
- " --page=PG|-p PG page code to fetch (def: 63)\n"
+ " --page=PG|-p PG page code to fetch (def: 63). May be "
+ "acronym\n"
" --page=PG,SPG|-p PG,SPG\n"
" page code and subpage code to fetch "
"(defs: 63,0)\n"
@@ -176,7 +351,7 @@ usage_old()
"10 cdb)\n"
" -m=LEN max response length (allocation length in cdb)\n"
" (def: 0 -> 4096 or 252 (for MODE SENSE 6) bytes)\n"
- " -p=PG page code in hex (def: 3f)\n"
+ " -p=PG page code in hex (def: 3f). No acronym allowed\n"
" -p=PG,SPG both in hex, (defs: 3f,0)\n"
" -r mode page output to stdout, a byte per line in "
"ASCII hex\n"
@@ -190,6 +365,48 @@ usage_old()
}
static void
+enum_pc_desc(void)
+{
+ bool first = true;
+ const struct pc_desc_group * pcd_grp = pcd_gr_arr;
+ char b[128];
+
+ for ( ; pcd_grp->pcdp; ++pcd_grp) {
+ const struct page_code_desc * pcdp = pcd_grp->pcdp;
+
+ if (first)
+ first = false;
+ else
+ printf("\n");
+ printf("Mode pages group: %s:\n", pcd_grp->group_name);
+ for ( ; pcdp->acron; ++pcdp) {
+ if (pcdp->subpage_code > 0)
+ snprintf(b, sizeof(b), "[0x%x,0x%x]", pcdp->page_code,
+ pcdp->subpage_code);
+ else
+ snprintf(b, sizeof(b), "[0x%x]", pcdp->page_code);
+ printf(" %s: %s %s\n", pcdp->acron, pcdp->desc, b);
+ }
+ }
+}
+
+static const struct page_code_desc *
+find_pc_desc(const char * acron)
+{
+ const struct pc_desc_group * pcd_grp = pcd_gr_arr;
+
+ for ( ; pcd_grp->pcdp; ++pcd_grp) {
+ const struct page_code_desc * pcdp = pcd_grp->pcdp;
+
+ for ( ; pcdp->acron; ++pcdp) {
+ if (0 == strcmp(acron, pcdp->acron))
+ return pcdp;
+ }
+ }
+ return NULL;
+}
+
+static void
usage_for(const struct opts_t * op)
{
if (op->opt_new)
@@ -273,24 +490,47 @@ new_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
op->opt_new = false;
return 0;
case 'p':
- cp = strchr(optarg, ',');
- n = sg_get_num_nomult(optarg);
- if ((n < 0) || (n > 63)) {
- pr2serr("Bad argument to '--page='\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- if (cp) {
- nn = sg_get_num_nomult(cp + 1);
- if ((nn < 0) || (nn > 255)) {
- pr2serr("Bad second value in argument to '--page='\n");
+ if (isalpha(optarg[0])) {
+ const struct page_code_desc * pcdp;
+
+ op->page_acron = optarg;
+ if (0 == memcmp("xxx", optarg, 3)) {
+ enum_pc_desc();
+ return SG_LIB_OK_FALSE; /* for quick exit */
+ }
+ pcdp = find_pc_desc(optarg);
+ if (pcdp) {
+ if (pcdp->subpage_code > 0) {
+ op->subpg_code = pcdp->subpage_code;
+ op->subpg_code_given = true;
+ }
+ op->pg_code = pcdp->page_code;
+ } else {
+ pr2serr(" Couldn't match acronym '%s', try '-p xxx' for "
+ "list\n", optarg);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else {
+ cp = strchr(optarg, ',');
+ n = sg_get_num_nomult(optarg);
+ if ((n < 0) || (n > 63)) {
+ pr2serr("Bad argument to '--page='\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
- op->subpg_code = nn;
- op->subpg_code_given = true;
+ if (cp) {
+ nn = sg_get_num_nomult(cp + 1);
+ if ((nn < 0) || (nn > 255)) {
+ pr2serr("Bad second value in argument to "
+ "'--page='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ op->subpg_code = nn;
+ op->subpg_code_given = true;
+ }
+ op->pg_code = n;
}
- op->pg_code = n;
break;
case 'r':
++op->do_raw;
@@ -342,6 +582,7 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
{
bool jmp_out;
int k, plen, num, n;
+ char pc1;
unsigned int u, uu;
const char * cp;
@@ -428,6 +669,13 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
}
op->maxlen = n;
} else if (0 == strncmp("p=", cp, 2)) {
+ pc1 = *(cp + 2);
+ if (isalpha(pc1) && ((islower(pc1) && (pc1 > 'f')) ||
+ (isupper(pc1) && (pc1 > 'F')))) {
+ pr2serr("Old format doesn't accept mode page acronyms: "
+ "%s\n", cp + 2);
+ return SG_LIB_SYNTAX_ERROR;
+ }
if (NULL == strchr(cp + 2, ',')) {
num = sscanf(cp + 2, "%x", &u);
if ((1 != num) || (u > 63)) {
@@ -517,107 +765,18 @@ dStrRaw(const uint8_t * str, int len)
printf("%c", str[k]);
}
+static int
+count_desc_elems(const struct page_code_desc * pcdp)
+{
+ int k;
-struct page_code_desc {
- int page_code;
- int subpage_code;
- const char * desc;
-};
-
-static struct page_code_desc pc_desc_common[] = {
- {0x0, 0x0, "Unit Attention condition [vendor specific format]"},
- {0x2, 0x0, "Disconnect-Reconnect"},
- {0x9, 0x0, "Peripheral device (obsolete)"},
- {0xa, 0x0, "Control"},
- {0xa, 0x1, "Control extension"},
- {0xa, 0x3, "Command duration limit A"},
- {0xa, 0x4, "Command duration limit B"},
- {0x15, 0x0, "Extended"},
- {0x16, 0x0, "Extended device-type specific"},
- {0x18, 0x0, "Protocol specific lu"},
- {0x19, 0x0, "Protocol specific port"},
- {0x1a, 0x0, "Power condition"},
- {0x1a, 0x1, "Power consumption"},
- {0x1c, 0x0, "Informational exceptions control"},
- {PG_CODE_ALL, 0x0, "[yields all supported pages]"},
- {PG_CODE_ALL, SPG_CODE_ALL, "[yields all supported pages and subpages]"},
-};
-
-static struct page_code_desc pc_desc_disk[] = {
- {0x1, 0x0, "Read-Write error recovery"},
- {0x3, 0x0, "Format (obsolete)"},
- {0x4, 0x0, "Rigid disk geometry (obsolete)"},
- {0x5, 0x0, "Flexible geometry (obsolete)"},
- {0x7, 0x0, "Verify error recovery"},
- {0x8, 0x0, "Caching"},
- {0xa, 0x2, "Application tag"},
- {0xa, 0x5, "IO advice hints grouping"}, /* added sbc4r06 */
- {0xa, 0x6, "Background operation control"}, /* added sbc4r07 */
- {0xa, 0xf1, "Parallel ATA control (SAT)"},
-/* {0xa, 0xf2, "Reserved (SATA control) (SAT)"}, // proposed + dropped ?? */
- {0xb, 0x0, "Medium types supported (obsolete)"},
- {0xc, 0x0, "Notch and partition (obsolete)"},
- {0xd, 0x0, "Power condition (obsolete, moved to 0x1a)"},
- {0x10, 0x0, "XOR control"}, /* obsolete in sbc3r32 */
- {0x1a, 0xf1, "ATA Power condition"},
- {0x1c, 0x1, "Background control"},
- {0x1c, 0x2, "Logical block provisioning"},
-};
-
-static struct page_code_desc pc_desc_tape[] = {
- {0x1, 0x0, "Read-Write error recovery"},
- {0xa, 0xf0, "Control data protection"},
- {0xf, 0x0, "Data Compression"},
- {0x10, 0x0, "Device configuration"},
- {0x10, 0x1, "Device configuration extension"},
- {0x11, 0x0, "Medium Partition [1]"},
- {0x12, 0x0, "Medium Partition [2]"},
- {0x13, 0x0, "Medium Partition [3]"},
- {0x14, 0x0, "Medium Partition [4]"},
- {0x1c, 0x0, "Informational exceptions control (tape version)"},
- {0x1d, 0x0, "Medium configuration"},
-};
-
-static struct page_code_desc pc_desc_cddvd[] = {
- {0x1, 0x0, "Read-Write error recovery"},
- {0x3, 0x0, "MRW"},
- {0x5, 0x0, "Write parameters"},
- {0x7, 0x0, "Verify error recovery"},
- {0x8, 0x0, "Caching"},
- {0xd, 0x0, "CD device parameters (obsolete)"},
- {0xe, 0x0, "CD audio"},
- {0x1a, 0x0, "Power condition (mmc)"},
- {0x1c, 0x0, "Fault/failure reporting control (mmc)"},
- {0x1d, 0x0, "Timeout and protect"},
- {0x2a, 0x0, "MM capabilities and mechanical status (obsolete)"},
-};
-
-static struct page_code_desc pc_desc_smc[] = {
- {0x1d, 0x0, "Element address assignment"},
- {0x1e, 0x0, "Transport geometry parameters"},
- {0x1f, 0x0, "Device capabilities"},
- {0x1f, 0x41, "Extended device capabilities"},
-};
-
-static struct page_code_desc pc_desc_scc[] = {
- {0x1b, 0x0, "LUN mapping"},
-};
-
-static struct page_code_desc pc_desc_ses[] = {
- {0x14, 0x0, "Enclosure services management"},
-};
-
-static struct page_code_desc pc_desc_rbc[] = {
- {0x6, 0x0, "RBC device parameters"},
-};
-
-static struct page_code_desc pc_desc_adc[] = {
- /* {0xe, 0x0, "ADC device configuration"}, */
- {0xe, 0x1, "Target device"},
- {0xe, 0x2, "DT device primary port"},
- {0xe, 0x3, "Logical unit"},
- {0xe, 0x4, "Target device serial number"},
-};
+ for (k = 0; k < 1024; ++k, ++pcdp) {
+ if (NULL == pcdp->acron)
+ return k;
+ }
+ pr2serr("%s: sanity check trip, invalid pc_desc table\n", __func__);
+ return k;
+}
/* Returns pointer to base of table for scsi_ptype or pointer to common
* table if scsi_ptype is -1. Yields numbers of elements in returned
@@ -629,70 +788,40 @@ get_mpage_tbl_size(int scsi_ptype, int * sizep)
switch (scsi_ptype)
{
case -1: /* common list */
- *sizep = SG_ARRAY_SIZE(pc_desc_common);
+ *sizep = count_desc_elems(pc_desc_common);
return &pc_desc_common[0];
case PDT_DISK: /* disk (direct access) type devices */
case PDT_WO:
case PDT_OPTICAL:
- *sizep = SG_ARRAY_SIZE(pc_desc_disk);
+ *sizep = count_desc_elems(pc_desc_disk);
return &pc_desc_disk[0];
case PDT_TAPE: /* tape devices */
case PDT_PRINTER:
- *sizep = SG_ARRAY_SIZE(pc_desc_tape);
+ *sizep = count_desc_elems(pc_desc_tape);
return &pc_desc_tape[0];
case PDT_MMC: /* cd/dvd/bd devices */
- *sizep = SG_ARRAY_SIZE(pc_desc_cddvd);
+ *sizep = count_desc_elems(pc_desc_cddvd);
return &pc_desc_cddvd[0];
case PDT_MCHANGER: /* medium changer devices */
- *sizep = SG_ARRAY_SIZE(pc_desc_smc);
+ *sizep = count_desc_elems(pc_desc_smc);
return &pc_desc_smc[0];
case PDT_SAC: /* storage array devices */
- *sizep = SG_ARRAY_SIZE(pc_desc_scc);
+ *sizep = count_desc_elems(pc_desc_scc);
return &pc_desc_scc[0];
case PDT_SES: /* enclosure services devices */
- *sizep = SG_ARRAY_SIZE(pc_desc_ses);
+ *sizep = count_desc_elems(pc_desc_ses);
return &pc_desc_ses[0];
case PDT_RBC: /* simplified direct access device */
- *sizep = SG_ARRAY_SIZE(pc_desc_rbc);
+ *sizep = count_desc_elems(pc_desc_rbc);
return &pc_desc_rbc[0];
case PDT_ADC: /* automation device/interface */
- *sizep = SG_ARRAY_SIZE(pc_desc_adc);
+ *sizep = count_desc_elems(pc_desc_adc);
return &pc_desc_adc[0];
}
*sizep = 0;
return NULL;
}
-static struct page_code_desc pc_desc_t_fcp[] = {
- {0x18, 0x0, "LU control"},
- {0x19, 0x0, "Port control"},
-};
-
-static struct page_code_desc pc_desc_t_spi4[] = {
- {0x18, 0x0, "LU control"},
- {0x19, 0x0, "Port control short format"},
- {0x19, 0x1, "Margin control"},
- {0x19, 0x2, "Saved training configuration value"},
- {0x19, 0x3, "Negotiated settings"},
- {0x19, 0x4, "Report transfer capabilities"},
-};
-
-static struct page_code_desc pc_desc_t_sas[] = {
- {0x18, 0x0, "Protocol specific logical unit (SAS)"},
- {0x19, 0x0, "Protocol specific port (SAS)"},
- {0x19, 0x1, "Phy control and discover (SAS)"},
- {0x19, 0x2, "Shared port control (SAS)"},
- {0x19, 0x3, "Enhanced phy control (SAS)"},
- {0x19, 0x4, "Out of band management control (SAS)"}, /* spl5r01 */
-};
-
-static struct page_code_desc pc_desc_t_adc[] = {
- {0xe, 0x1, "Target device"},
- {0xe, 0x2, "DT device primary port"},
- {0xe, 0x3, "Logical unit"},
- {0x18, 0x0, "Protocol specific lu"},
- {0x19, 0x0, "Protocol specific port"},
-};
static struct page_code_desc *
get_mpage_trans_tbl_size(int t_proto, int * sizep)
@@ -700,16 +829,16 @@ get_mpage_trans_tbl_size(int t_proto, int * sizep)
switch (t_proto)
{
case TPROTO_FCP:
- *sizep = SG_ARRAY_SIZE(pc_desc_t_fcp);
+ *sizep = count_desc_elems(pc_desc_t_fcp);
return &pc_desc_t_fcp[0];
case TPROTO_SPI:
- *sizep = SG_ARRAY_SIZE(pc_desc_t_spi4);
+ *sizep = count_desc_elems(pc_desc_t_spi4);
return &pc_desc_t_spi4[0];
case TPROTO_SAS:
- *sizep = SG_ARRAY_SIZE(pc_desc_t_sas);
+ *sizep = count_desc_elems(pc_desc_t_sas);
return &pc_desc_t_sas[0];
case TPROTO_ADT:
- *sizep = SG_ARRAY_SIZE(pc_desc_t_adc);
+ *sizep = count_desc_elems(pc_desc_t_adc);
return &pc_desc_t_adc[0];
}
*sizep = 0;
@@ -893,11 +1022,19 @@ examine_pages(int sg_fd, int inq_pdt, bool encserv, bool mchngr,
const struct opts_t * op)
{
bool header_printed;
- int k, res, mresp_len, len, resid;
+ int k, mresp_len, len, resid;
+ int res = 0;
+ const int mx_len = op->do_six ? DEF_6_ALLOC_LEN : DEF_ALLOC_LEN;
const char * cp;
- uint8_t rbuf[256];
+ uint8_t * rbuf;
+ uint8_t * free_rbuf = NULL;
- mresp_len = (op->do_raw || op->do_hex) ? sizeof(rbuf) : 4;
+ rbuf = sg_memalign(mx_len, 0, &free_rbuf, false);
+ if (NULL == rbuf) {
+ pr2serr("%s: out of heap\n", __func__);
+ return sg_convert_errno(ENOMEM);
+ }
+ mresp_len = (op->do_raw || op->do_hex) ? mx_len : 4;
for (header_printed = false, k = 0; k < PG_CODE_MAX; ++k) {
resid = 0;
if (op->do_six) {
@@ -906,10 +1043,10 @@ examine_pages(int sg_fd, int inq_pdt, bool encserv, bool mchngr,
if (SG_LIB_CAT_INVALID_OP == res) {
pr2serr(">>>>>> try again without the '-6' switch for a 10 "
"byte MODE SENSE command\n");
- return res;
+ goto out;
} else if (SG_LIB_CAT_NOT_READY == res) {
pr2serr("MODE SENSE (6) failed, device not ready\n");
- return res;
+ goto out;
}
} else {
res = sg_ll_mode_sense10_v2(sg_fd, 0, 0, 0, k, 0, rbuf, mresp_len,
@@ -917,22 +1054,22 @@ examine_pages(int sg_fd, int inq_pdt, bool encserv, bool mchngr,
if (SG_LIB_CAT_INVALID_OP == res) {
pr2serr(">>>>>> try again with a '-6' switch for a 6 byte "
"MODE SENSE command\n");
- return res;
+ goto out;
} else if (SG_LIB_CAT_NOT_READY == res) {
pr2serr("MODE SENSE (10) failed, device not ready\n");
- return res;
+ goto out;
}
}
if (0 == res) {
len = sg_msense_calc_length(rbuf, mresp_len, op->do_six, NULL);
if (resid > 0) {
- mresp_len -= resid;
- if (mresp_len < 0) {
- pr2serr("%s: MS(10) resid=%d implies negative "
- "response length (%d)\n", __func__,
- resid, mresp_len);
- return SG_LIB_WILD_RESID;
- }
+ mresp_len -= resid;
+ if (mresp_len < 0) {
+ pr2serr("%s: MS(10) resid=%d implies negative response "
+ "length (%d)\n", __func__, resid, mresp_len);
+ res = SG_LIB_WILD_RESID;
+ goto out;
+ }
}
if (len > mresp_len)
len = mresp_len;
@@ -963,6 +1100,9 @@ examine_pages(int sg_fd, int inq_pdt, bool encserv, bool mchngr,
b);
}
}
+out:
+ if (free_rbuf)
+ free(free_rbuf);
return res;
}
@@ -982,7 +1122,7 @@ main(int argc, char * argv[])
bool mchngr = false;
uint8_t uc;
int k, num, len, res, md_len, bd_len, page_num, resid;
- int density_code_off, t_proto, inq_pdt, num_ua_pages;
+ int density_code_off, t_proto, inq_pdt, num_ua_pages, vb;
int sg_fd = -1;
int ret = 0;
int rsp_buff_sz = DEF_ALLOC_LEN;
@@ -1003,7 +1143,7 @@ main(int argc, char * argv[])
op->pg_code = -1;
res = parse_cmd_line(op, argc, argv);
if (res)
- return res;
+ return (SG_LIB_OK_FALSE == res) ? 0 : res;
if (op->do_help) {
usage_for(op);
return 0;
@@ -1028,6 +1168,15 @@ main(int argc, char * argv[])
pr2serr("Version string: %s\n", version_str);
return 0;
}
+ vb = op->verbose;
+ if (vb && op->page_acron) {
+ pr2serr("page acronynm: '%s' maps to page_code=0x%x",
+ op->page_acron, op->pg_code);
+ if (op->subpg_code > 0)
+ pr2serr(", subpage_code=0x%x\n", op->subpg_code);
+ else
+ pr2serr("\n");
+ }
if (NULL == op->device_name) {
if (op->do_list) {
@@ -1046,7 +1195,7 @@ main(int argc, char * argv[])
}
return 0;
}
- pr2serr("No DEVICE argument given\n");
+ pr2serr("No DEVICE argument given\n\n");
usage_for(op);
return SG_LIB_SYNTAX_ERROR;
}
@@ -1089,14 +1238,14 @@ main(int argc, char * argv[])
}
if ((sg_fd = sg_cmds_open_device(op->device_name, ! op->o_readwrite,
- op->verbose)) < 0) {
+ vb)) < 0) {
pr2serr("error opening file: %s: %s\n", op->device_name,
safe_strerror(-sg_fd));
ret = sg_convert_errno(-sg_fd);
goto fini;
}
- if ((res = sg_simple_inquiry(sg_fd, &inq_out, true, op->verbose))) {
+ if ((res = sg_simple_inquiry(sg_fd, &inq_out, true, vb))) {
pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->device_name);
ret = (res > 0) ? res : sg_convert_errno(-res);
goto fini;
@@ -1143,7 +1292,7 @@ main(int argc, char * argv[])
if (op->do_six) {
res = sg_ll_mode_sense6(sg_fd, op->do_dbd, op->page_control,
op->pg_code, op->subpg_code, rsp_buff,
- rsp_buff_sz, true, op->verbose);
+ rsp_buff_sz, true, vb);
if (SG_LIB_CAT_INVALID_OP == res)
pr2serr(">>>>>> try again without the '-6' switch for a 10 byte "
"MODE SENSE command\n");
@@ -1151,7 +1300,7 @@ main(int argc, char * argv[])
res = sg_ll_mode_sense10_v2(sg_fd, op->do_llbaa, op->do_dbd,
op->page_control, op->pg_code,
op->subpg_code, rsp_buff, rsp_buff_sz,
- 0, &resid, true, op->verbose);
+ 0, &resid, true, vb);
if (SG_LIB_CAT_INVALID_OP == res)
pr2serr(">>>>>> try again with a '-6' switch for a 6 byte MODE "
"SENSE command\n");
@@ -1167,7 +1316,7 @@ main(int argc, char * argv[])
pr2serr("invalid field in cdb (perhaps page 0x%x not "
"supported)\n", op->pg_code);
} else if (res) {
- sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
+ sg_get_category_sense_str(res, sizeof(b), b, vb);
pr2serr("%s\n", b);
}
ret = res;
@@ -1368,10 +1517,10 @@ main(int argc, char * argv[])
pg_control_str_arr[op->page_control]);
}
num = (len > md_len) ? md_len : len;
- if ((k > 0) && (num > 256)) {
- num = 256;
- pr2serr(">>> page length (%d) > 256 bytes, unlikely trim\n"
- " Try '-f' option\n", len);
+ if ((k > 0) && (num > UNLIKELY_ABOVE_LEN)) {
+ num = UNLIKELY_ABOVE_LEN;
+ pr2serr(">>> page length (%d) > %d bytes, unlikely, trim\n"
+ " Try '-f' option\n", len, num);
}
hex2stdout(bp, num , 1);
bp += len;
@@ -1384,7 +1533,7 @@ fini:
sg_cmds_close_device(sg_fd);
if (free_rsp_buff)
free(free_rsp_buff);
- if (0 == op->verbose) {
+ if (0 == vb) {
if (! sg_if_can2stderr("sg_modes failed: ", ret))
pr2serr("Some error occurred, try again with '-v' or '-vv' for "
"more information\n");
diff --git a/src/sg_readcap.c b/src/sg_readcap.c
index 9f6b5995..70b40bf3 100644
--- a/src/sg_readcap.c
+++ b/src/sg_readcap.c
@@ -34,7 +34,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "4.03 20180627";
+static const char * version_str = "4.04 20180911";
#define ME "sg_readcap: "
@@ -512,9 +512,9 @@ main(int argc, char * argv[])
"before delay=0x%" PRIx32 "\n", op->llba,
last_blk_addr);
else
- printf(" Last logical block address=%" PRIu32 " (0x%"
- PRIx32 "), Number of blocks=%" PRIu32 "\n",
- last_blk_addr, last_blk_addr, last_blk_addr + 1);
+ printf(" Last LBA=%" PRIu32 " (0x%" PRIx32 "), Number "
+ "of logical blocks=%" PRIu32 "\n", last_blk_addr,
+ last_blk_addr, last_blk_addr + 1);
printf(" Logical block length=%u bytes\n", block_size);
if (! op->do_pmi) {
uint64_t total_sz = last_blk_addr + 1;
@@ -609,9 +609,9 @@ main(int argc, char * argv[])
"before delay=0x%" PRIx64 "\n", op->llba,
llast_blk_addr);
else
- printf(" Last logical block address=%" PRIu64 " (0x%"
- PRIx64 "), Number of logical blocks=%" PRIu64 "\n",
- llast_blk_addr, llast_blk_addr, llast_blk_addr + 1);
+ printf(" Last LBA=%" PRIu64 " (0x%" PRIx64 "), Number of "
+ "logical blocks=%" PRIu64 "\n", llast_blk_addr,
+ llast_blk_addr, llast_blk_addr + 1);
printf(" Logical block length=%" PRIu32 " bytes\n", block_size);
lbppbe = resp_buff[13] & 0xf;
printf(" Logical blocks per physical block exponent=%d",
@@ -621,7 +621,7 @@ main(int argc, char * argv[])
block_size * (1 << lbppbe));
else
printf("\n");
- printf(" Lowest aligned logical block address=%d\n",
+ printf(" Lowest aligned LBA=%d\n",
((resp_buff[14] & 0x3f) << 8) + resp_buff[15]);
if (! op->do_pmi) {
uint64_t total_sz = llast_blk_addr + 1;
@@ -634,12 +634,20 @@ main(int argc, char * argv[])
(double)(1000000000L);
printf("Hence:\n");
#ifdef SG_LIB_MINGW
- printf(" Device size: %" PRIu64 " bytes, %g MiB, %g GB\n",
+ printf(" Device size: %" PRIu64 " bytes, %g MiB, %g GB",
total_sz, sz_mb, sz_gb);
#else
printf(" Device size: %" PRIu64 " bytes, %.1f MiB, %.2f "
- "GB\n", total_sz, sz_mb, sz_gb);
+ "GB", total_sz, sz_mb, sz_gb);
#endif
+ if (sz_gb > 2000) {
+#ifdef SG_LIB_MINGW
+ printf(", %g TB", sz_gb / 1000);
+#else
+ printf(", %.2f TB", sz_gb / 1000);
+#endif
+ }
+ printf("\n");
}
goto fini;
} else if (SG_LIB_CAT_ILLEGAL_REQ == res)
diff --git a/src/sg_seek.c b/src/sg_seek.c
index cee2112b..093c6b79 100644
--- a/src/sg_seek.c
+++ b/src/sg_seek.c
@@ -47,7 +47,7 @@
* to that LBA ...
*/
-static const char * version_str = "1.06 20180628";
+static const char * version_str = "1.07 20180911";
#define BACKGROUND_CONTROL_SA 0x15
@@ -131,6 +131,7 @@ int
main(int argc, char * argv[])
{
bool cdb10 = false;
+ bool count_given = false;
bool do_time = false;
bool immed = false;
bool prefetch = false;
@@ -184,6 +185,7 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
count = (uint32_t)l;
+ count_given = true;
break;
case 'g':
l = sg_get_num(optarg);
@@ -339,6 +341,7 @@ main(int argc, char * argv[])
lba_n = lba;
res = sg_ll_pre_fetch_x(sg_fd, ! prefetch, ! cdb10, immed, lba_n,
numblocks, grpnum, 0, (verbose > 0), verbose);
+ ret = res; /* last command executed sets exit status */
if (SG_LIB_CAT_CONDITION_MET == res)
++num_cond_met;
else if (res) {
@@ -385,8 +388,9 @@ main(int argc, char * argv[])
"%" PRId64 "\n", elapsed_usecs, b, elapsed_usecs / count);
}
- printf("Command count=%u, number of condition_mets=%u, number of "
- "goods=%u\n", count, num_cond_met, num_good);
+ if (count_given && verbose_given)
+ printf("Command count=%u, number of condition_mets=%u, number of "
+ "goods=%u\n", count, num_cond_met, num_good);
if (first_err) {
bool printed;
diff --git a/src/sg_ses.c b/src/sg_ses.c
index 2b05f4aa..abb1feac 100644
--- a/src/sg_ses.c
+++ b/src/sg_ses.c
@@ -1082,11 +1082,11 @@ parse_index(struct opts_t *op)
if (NULL == cp)
op->ind_indiv = -1;
} else { /* element type abbreviation perhaps followed by <num> */
- int blen = strlen(b);
+ int b_len = strlen(b);
for (etp = element_type_arr; etp->desc; ++etp) {
n = strlen(etp->abbrev);
- if ((n == blen) && (0 == strncmp(b, etp->abbrev, n)))
+ if ((n == b_len) && (0 == strncmp(b, etp->abbrev, n)))
break;
}
if (NULL == etp->desc) {
@@ -1094,7 +1094,7 @@ parse_index(struct opts_t *op)
"use '--enumerate' to see possibles\n", b);
return SG_LIB_SYNTAX_ERROR;
}
- if ((int)strlen(b) > n) {
+ if (b_len > n) {
n = sg_get_num_nomult(b + n);
if ((n < 0) || (n > 255)) {
pr2serr("bad element type abbreviation <num> for '--index', "
diff --git a/src/sg_timestamp.c b/src/sg_timestamp.c
index cd1bd759..3168997c 100644
--- a/src/sg_timestamp.c
+++ b/src/sg_timestamp.c
@@ -35,7 +35,7 @@
* to the given SCSI device. Based on spc5r07.pdf .
*/
-static const char * version_str = "1.11 20180628";
+static const char * version_str = "1.12 20180910";
#define REP_TIMESTAMP_CMDLEN 12
#define SET_TIMESTAMP_CMDLEN 12
@@ -97,7 +97,7 @@ usage(int num)
" DEVICE\n"
);
pr2serr(" where:\n"
- " --elapsed|-e show time as '<n> days hh.mm.ss.xxx' "
+ " --elapsed|-e show time as '<n> days hh:mm:ss.xxx' "
"where\n"
" '.xxx' is the remainder milliseconds. "
"Don't show\n"
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index a79a96ad..a15ed742 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -38,7 +38,7 @@
*/
-static const char * version_str = "1.46 20180828"; /* spc5r19 + sbc4r15 */
+static const char * version_str = "1.48 20180910"; /* spc5r19 + sbc4r15 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -2294,12 +2294,13 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt)
printf(" Nominal rotation rate: %u rpm\n", u);
u = buff[6];
k = SG_ARRAY_SIZE(product_type_arr);
+ printf(" Product type: ");
if (u < k)
- printf(" Product type: %s\n", product_type_arr[u]);
+ printf("%s\n", product_type_arr[u]);
else if (u < 0xf0)
- printf(" Product type: Reserved [0x%x]\n", u);
+ printf("Reserved [0x%x]\n", u);
else
- printf(" Product type: Vendor specific [0x%x]\n", u);
+ printf("Vendor specific [0x%x]\n", u);
printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
u = buff[7] & 0xf;
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index 9798f122..3c751775 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -51,11 +51,13 @@
#define VPD_VP_HP3PAR 4
#define VPD_VP_IBM_LTO 5
#define VPD_VP_HP_LTO 6
-#define VPD_VP_NVME 7
-#define VPD_VP_SG 8 /* this package/library as a vendor */
+#define VPD_VP_WDC_HITACHI 7
+#define VPD_VP_NVME 8
+#define VPD_VP_SG 9 /* this package/library as a vendor */
/* vendor VPD pages */
+#define VPD_V_HIT_PG3 0x3
#define VPD_V_HP3PAR 0xc0
#define VPD_V_FIRM_SEA 0xc0
#define VPD_V_UPR_EMC 0xc0
@@ -82,6 +84,8 @@
#define VPD_V_VAC_RDAC 0xc9
#define VPD_V_RVSI_RDAC 0xca
#define VPD_V_SAID_RDAC 0xd0
+#define VPD_V_HIT_PG_D1 0xd1
+#define VPD_V_HIT_PG_D2 0xd2
#ifndef SG_NVME_VPD_NICR
#define SG_NVME_VPD_NICR 0xde /* NVME Identify Controller Response */
@@ -142,13 +146,15 @@ struct svpd_vp_name_t {
static struct svpd_vp_name_t vp_arr[] = {
{VPD_VP_DDS, "dds", "DDS tape family from IBM"},
{VPD_VP_EMC, "emc", "EMC (company)"},
+ {VPD_VP_WDC_HITACHI, "hit", "WDC/Hitachi disk"},
{VPD_VP_HP3PAR, "hp3par", "3PAR array (HP was Left Hand)"},
- {VPD_VP_IBM_LTO, "ibm_lto", "IBM LTO tape/systems"},
{VPD_VP_HP_LTO, "hp_lto", "HP LTO tape/systems"},
+ {VPD_VP_IBM_LTO, "ibm_lto", "IBM LTO tape/systems"},
+ {VPD_VP_NVME, "nvme", "NVMe related"},
{VPD_VP_RDAC, "rdac", "RDAC array (NetApp E-Series)"},
{VPD_VP_SEAGATE, "sea", "Seagate disk"},
- {VPD_VP_NVME, "nvme", "NVMe related"},
{VPD_VP_SG, "sg", "sg3_utils extensions"},
+ {VPD_VP_WDC_HITACHI, "wdc", "WDC/Hitachi disk"},
{0, NULL, NULL},
};
@@ -169,7 +175,6 @@ static struct svpd_values_name_t vendor_vpd_pg[] = {
"configuration data (IBM LTO)"},
{VPD_V_EDID_RDAC, VPD_VP_RDAC, 0, "edid", "Extended device "
"identification (RDAC)"},
- {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "prm4", "Feature Parameters (RDAC)"},
{VPD_V_FIRM_SEA, VPD_VP_SEAGATE, 0, "firm", "Firmware numbers "
"(Seagate)"},
{VPD_V_FVER_LTO, VPD_VP_HP_LTO, 0, "frl", "Firmware revision level "
@@ -190,6 +195,7 @@ static struct svpd_values_name_t vendor_vpd_pg[] = {
{SG_NVME_VPD_NICR, VPD_VP_SG, 0, "nicr",
"NVMe Identify Controller Response (sg3_utils)"},
{VPD_V_PCA_LTO, VPD_VP_HP_LTO, 1, "pca", "PCA revision level (HP LTO)"},
+ {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "prm4", "Feature Parameters (RDAC)"},
{VPD_V_RVSI_RDAC, VPD_VP_RDAC, 0, "rvsi", "Replicated volume source "
"identifier (RDAC)"},
{VPD_V_SAID_RDAC, VPD_VP_RDAC, 0, "said", "Storage array world wide "
@@ -198,6 +204,11 @@ static struct svpd_values_name_t vendor_vpd_pg[] = {
{VPD_V_SVER_RDAC, VPD_VP_RDAC, 0, "swr4", "Software version (RDAC)"},
{VPD_V_UPR_EMC, VPD_VP_EMC, 0, "upr", "Unit path report (EMC)"},
{VPD_V_VAC_RDAC, VPD_VP_RDAC, 0, "vac1", "Volume access control (RDAC)"},
+ {VPD_V_HIT_PG3, VPD_VP_WDC_HITACHI, 0, "wp3", "Page 0x3 (WDC/Hitachi)"},
+ {VPD_V_HIT_PG_D1, VPD_VP_WDC_HITACHI, 0, "wpd1",
+ "Page 0xd1 (WDC/Hitachi)"},
+ {VPD_V_HIT_PG_D2, VPD_VP_WDC_HITACHI, 0, "wpd2",
+ "Page 0xd2 (WDC/Hitachi)"},
{0, 0, 0, NULL, NULL},
};
@@ -1307,6 +1318,69 @@ decode_ibm_lto_dsn(uint8_t * buff, int len)
printf(" Reported serial number: %.12s\n", buff + 16);
}
+static void
+decode_vpd_3_hit(uint8_t * b, int blen)
+{
+ uint16_t plen = sg_get_unaligned_be16(b + 2);
+
+ if ((plen < 184) || (blen < 184)) {
+ pr2serr("Hitachi VPD page 0x3 length (%u) shorter than %u\n",
+ plen + 4, 184 + 4);
+ return;
+ }
+ printf(" ASCII uCode Identifier: %.12s\n", b + 24);
+ printf(" ASCII servo P/N: %.4s\n", b + 36);
+ printf(" Major Version: %.2s\n", b + 40);
+ printf(" Minor Version: %.2s\n", b + 42);
+ printf(" User Count: %.4s\n", b + 44);
+ printf(" Build Number: %.4s\n", b + 48);
+ printf(" Build Date String: %.32s\n", b + 52);
+ printf(" Product ID: %.8s\n", b + 84);
+ printf(" Interface ID: %.8s\n", b + 92);
+ printf(" Code Type: %.8s\n", b + 100);
+ printf(" User Name: %.12s\n", b + 108);
+ printf(" Machine Name: %.16s\n", b + 120);
+ printf(" Directory Name: %.32s\n", b + 136);
+ printf(" Operating state: %u\n", sg_get_unaligned_be32(b + 168));
+ printf(" Functional Mode: %u\n", sg_get_unaligned_be32(b + 172));
+ printf(" Degraded Reason: %u\n", sg_get_unaligned_be32(b + 176));
+ printf(" Broken Reason: %u\n", sg_get_unaligned_be32(b + 180));
+ printf(" Code Mode: %u\n", sg_get_unaligned_be32(b + 184));
+ printf(" Revision: %.4s\n", b + 188);
+}
+
+static void
+decode_vpd_d1_hit(uint8_t * b, int blen)
+{
+ uint16_t plen = sg_get_unaligned_be16(b + 2);
+
+ if ((plen < 80) || (blen < 80)) {
+ pr2serr("Hitachi VPD page 0xd1 length (%u) shorter than %u\n",
+ plen + 4, 80 + 4);
+ return;
+ }
+ printf(" ASCII Media Disk Definition: %.16s\n", b + 4);
+ printf(" ASCII Motor Serial Number: %.16s\n", b + 20);
+ printf(" ASCII Flex Assembly Serial Number: %.16s\n", b + 36);
+ printf(" ASCII Actuator Serial Number: %.16s\n", b + 52);
+ printf(" ASCII Device Enclosure Serial Number: %.16s\n", b + 68);
+}
+
+static void
+decode_vpd_d2_hit(uint8_t * b, int blen)
+{
+ uint16_t plen = sg_get_unaligned_be16(b + 2);
+
+ if ((plen < 52) || (blen < 52)) {
+ pr2serr("Hitachi VPD page 0xd2 length (%u) shorter than %u\n",
+ plen + 4, 52 + 4);
+ return;
+ }
+ printf(" ASCII HDC Version: %.16s\n", b + 5);
+ printf(" ASCII Card Serial Number: %.16s\n", b + 22);
+ printf(" ASCII Card Assembly Part Number: %.16s\n", b + 39);
+}
+
/* Returns 0 if successful, see sg_ll_inquiry() plus SG_LIB_CAT_OTHER for
unsupported page */
int
@@ -1319,6 +1393,7 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
uint8_t * rp;
switch (op->vpd_pn) {
+ case 0x3:
case 0xc0:
case 0xc1:
case 0xc2:
@@ -1329,6 +1404,8 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
case 0xc9:
case 0xca:
case 0xd0:
+ case 0xd1:
+ case 0xd2:
break;
default: /* not known so return prior to fetching page */
return SG_LIB_CAT_OTHER;
@@ -1355,6 +1432,12 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
hex2stdout(rp, len, ((1 == op->do_hex) ? 0 : -1));
else {
switch(op->vpd_pn) {
+ case 0x3:
+ if (VPD_VP_WDC_HITACHI == op->vend_prod_num)
+ decode_vpd_3_hit(rp, len);
+ else
+ hex2stdout(rp, len, 0);
+ break;
case 0xc0:
if (VPD_VP_SEAGATE == op->vend_prod_num)
decode_firm_vpd_c0_sea(rp, len);
@@ -1441,6 +1524,18 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
else
hex2stdout(rp, len, 0);
break;
+ case 0xd1:
+ if (VPD_VP_WDC_HITACHI == op->vend_prod_num)
+ decode_vpd_d1_hit(rp, len);
+ else
+ hex2stdout(rp, len, 0);
+ break;
+ case 0xd2:
+ if (VPD_VP_WDC_HITACHI == op->vend_prod_num)
+ decode_vpd_d2_hit(rp, len);
+ else
+ hex2stdout(rp, len, 0);
+ break;
default:
pr2serr("%s: logic error, should know can't decode "
"pn=0x%x\n", __func__, op->vpd_pn);