aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-08-18 19:46:38 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-08-18 19:46:38 +0000
commit7e7308a2dbdec4c900b0805ad94324d3a288a163 (patch)
treec6c84399abcab97cc9bb0657f0734e0aa56a917d
parent98b99ad2ab348bbba1676b95a8895f12ee48fd31 (diff)
downloadsg3_utils-7e7308a2dbdec4c900b0805ad94324d3a288a163.tar.gz
sg_inq+sg_vpd: more updates but not finished
The sg_inq+sg_inq work is mainly JSON additions. sg_vpd has a new --sinq_inraw=RFN option. Update and place names for the 64 TapeAlert flags in the library. This improves TapeAlert reporting for sg_inq, sg_vpd and sg_logs. Refine the description of the VPD page merge of processing for sg_inq and sg_vpd to only include _T10_ defined pages, so the vendor specific VPD page processings of those utilities are still separate. git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@969 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog7
-rw-r--r--README.details10
-rw-r--r--doc/sg3_utils_json.825
-rw-r--r--doc/sg_decode_sense.814
-rw-r--r--doc/sg_get_elem_status.86
-rw-r--r--doc/sg_get_lba_status.86
-rw-r--r--doc/sg_inq.813
-rw-r--r--doc/sg_opcodes.86
-rw-r--r--doc/sg_rep_zones.86
-rw-r--r--doc/sg_vpd.854
-rw-r--r--include/sg_lib_data.h5
-rw-r--r--include/sg_pr2serr.h5
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/Makefile.in1
-rw-r--r--lib/sg_lib.c6
-rw-r--r--lib/sg_lib_data.c75
-rw-r--r--lib/sg_pr2serr.c5
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in2
-rw-r--r--src/sg_inq.c435
-rw-r--r--src/sg_logs.c73
-rw-r--r--src/sg_ses.c13
-rw-r--r--src/sg_unmap.c8
-rw-r--r--src/sg_vpd.c343
-rw-r--r--src/sg_vpd_common.c199
-rw-r--r--src/sg_vpd_common.h59
-rw-r--r--src/sg_vpd_vendor.c345
-rw-r--r--testing/sgs_dd.c4
28 files changed, 1114 insertions, 614 deletions
diff --git a/ChangeLog b/ChangeLog
index d844a7a3..ed818950 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 pre-release sg3_utils-1.48 [20220812] [svn: r968]
+Changelog for pre-release sg3_utils-1.48 [20220818] [svn: r969]
- some utilities: add experimental --json[=JO] option
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
@@ -47,12 +47,15 @@ Changelog for pre-release sg3_utils-1.48 [20220812] [svn: r968]
the left hand side of each line of hex
- improve 'last_n' log pages; supply VPD and mode pages
with their name (if T10 defined)
+ - update names for TapeAlert lpage
- sg_modes: improve handling of zbc disks with pdt=0x14
- - sg_inq, sg_vpd: merge VPD page processing
+ - sg_inq, sg_vpd: merge VPD page processing for T10
+ defined pages, VS pages still differ
- Device Identication VPD page, change
"IEEE Company_id" to "AOI" as per spc6r06.pdf
- add support for Hitachi/HP open-v ldev names
- sg_vpd: apply github pull 18 (missing LF)
+ - add --sinq_inraw=RFN option
- sg_opcodes: cleanup error reporting
- add --inhex=FN to process earlier -HHH
- sg_format: allow disk formats on ZBC (zoned) disks
diff --git a/README.details b/README.details
index 47fc2e27..96cac8b5 100644
--- a/README.details
+++ b/README.details
@@ -170,7 +170,13 @@ favours POSIX system and library calls over OS specific calls.
The C code is written in a C++ friendly way and is checked from time to
time that it compiles clean with C++. To accommodate C++ certain C99
-constructs such as designated initializers cannot be used.
+constructs such as designated initializers cannot be used. To build
+with C++, C++11 (i.e. the C++ standard from 2011) or later is required.
+Finding a common C and C++ syntax for zeroing stack variables (including
+aggregates) may need to wait until C23 allows this syntax:
+ struct example_t ex1 {};
+which C++ introduced in C++11. In the meantime the SG_C_CPP_ZERO_INIT
+define (hack) does this.
The author has not seriously attempted to build this code on MSVC (aka
Visual Studio). There are a few roadblocks (that may be overcome in the
@@ -542,4 +548,4 @@ See https://sg.danny.cz/sg/tools.html
Douglas Gilbert dgilbert@interlog.com
-10th June 2022
+12th August 2022
diff --git a/doc/sg3_utils_json.8 b/doc/sg3_utils_json.8
index d24ebb06..e8cdb62f 100644
--- a/doc/sg3_utils_json.8
+++ b/doc/sg3_utils_json.8
@@ -14,9 +14,10 @@ returned by SCSI commands (e.g. sg_vpd) can optionally provide JSON
output, rather than simple, human-readable output. The default remains
human-readable output.
.PP
-JSON is an open standard file format that can be used for data exchange
-between systems. See https://en.wikipedia.org/wiki/JSON . JSON comes in many
-flavours and this one uses the json-builder C implementation found at
+JavaScript Object Notation (JSON) is an open standard file format that can be
+used for data exchange between programs including across a network. See
+https://en.wikipedia.org/wiki/JSON . JSON comes in many flavours and this one
+uses the json-builder C implementation found at
https://github.com/json-parser/json-builder which implements four simple JSON
data types: string, integer, boolean and null. Its other data types are JSON
object and JSON array.
@@ -210,11 +211,17 @@ human readable form. Errors are reported to stderr and may cause the early
termination of a utility (e.g. command line option syntax error).
.PP
When the \fI\-\-json\fR option is given and no errors are detected, then
-only JSON is sent to stdout. If the 'o' control character is in the \fIJO\fR
-argument to the \fI\-\-json\fR option, then the former "human readable"
-output is placed in a JSON array named "output" within a JSON object
-named "utility_invoked". Each line of the former "human readable" output
-is placed in its own element of the JSON array named "output".
+only JSON is normally sent to stdout. As the SCSI response is parsed, a JSON
+representation is built as a tree in memory. After all other actions (perhaps
+apart from the final exit status report) that JSON tree is "dumped" to
+stdout. This means if there is any non-JSON output sent to stdout that
+it will appear _before_ the JSON output.
+.PP
+If the 'o' control character is in the \fIJO\fR argument to the
+\fI\-\-json\fR option, then the former "human readable" output is placed in
+a JSON array named "output" within a JSON object named "utility_invoked".
+Each line of the former "human readable" output is placed in its own
+element of the JSON array named "output".
.PP
A JSON tree is built in memory as the utility parses the data returned
from the SCSI device (e.g. sg_vpd parsing a VPD page returned from a
@@ -236,7 +243,7 @@ reason then no JSON output will appear. With the normal, human readable output
processing, some output may appear before the utility aborts in such bad
situations.
.SH ERRORS
-No attempts has been made to translate errors into JSON form, apart from the
+No attempts have been made to translate errors into JSON form, apart from the
final "exit_status" JSON object where a value of 0 means "no errors". Exit
status values indicating a problem range from 1 to 255.
.PP
diff --git a/doc/sg_decode_sense.8 b/doc/sg_decode_sense.8
index ea68eb16..e91d6892 100644
--- a/doc/sg_decode_sense.8
+++ b/doc/sg_decode_sense.8
@@ -1,13 +1,13 @@
-.TH SG_DECODE_SENSE "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_DECODE_SENSE "8" "August 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_decode_sense \- decode SCSI sense and related data
.SH SYNOPSIS
.B sg_decode_sense
[\fI\-\-binary=BFN\fR] [\fI\-\-cdb\fR] [\fI\-\-err=ES\fR] [\fI\-\-file=HFN\fR]
[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=HFN\fR]
-[\fI\-\-ignore\-first\fR] [\fI\-\-nodecode\fR] [\fI\-\-nospace\fR]
-[\fI\-\-status=SS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
-[\fI\-\-write=WFN\fR] [H1 H2 H3 ...]
+[\fI\-\-ignore\-first\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-nodecode\fR]
+[\fI\-\-nospace\fR] [\fI\-\-status=SS\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fI\-\-write=WFN\fR] [H1 H2 H3 ...]
.SH DESCRIPTION
.\" Add any additional description here
This utility takes SCSI sense data in binary or as a sequence of ASCII
@@ -106,6 +106,12 @@ first hexadecimal value on each line. This option has no effect if
character from and after "#" on a line are ignored. Useful with the
\fI\-\-file=HFN\fR and \fI\-\-nodecode\fR options.
.TP
+\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
+.br
+This option is designed to parse sense data into JSON output.
+.TP
\fB\-N\fR, \fB\-\-nodecode\fR
Do not decode the given data as sense or a cdb. Useful when arbitrary data
is given (e.g. when converting hex to binary or vice versa).
diff --git a/doc/sg_get_elem_status.8 b/doc/sg_get_elem_status.8
index 8baad4fc..e6ec8448 100644
--- a/doc/sg_get_elem_status.8
+++ b/doc/sg_get_elem_status.8
@@ -1,4 +1,4 @@
-.TH SG_GET_ELEM_STATUS "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_GET_ELEM_STATUS "8" "August 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_get_elem_status \- send SCSI GET PHYSICAL ELEMENT STATUS command
.SH SYNOPSIS
@@ -72,8 +72,8 @@ sg3_utils manpage for more information. If the \fI\-\-raw\fR option is
also given then the contents of \fIFN\fR are treated as binary.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see the sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR
where \fILEN\fR is the (maximum) response length in bytes. It is placed in
diff --git a/doc/sg_get_lba_status.8 b/doc/sg_get_lba_status.8
index 3f887aa3..0ccc70e4 100644
--- a/doc/sg_get_lba_status.8
+++ b/doc/sg_get_lba_status.8
@@ -1,4 +1,4 @@
-.TH SG_GET_LBA_STATUS "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_GET_LBA_STATUS "8" "August 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_get_lba_status \- send SCSI GET LBA STATUS(16 or 32) command
.SH SYNOPSIS
@@ -87,8 +87,8 @@ given then it is ignored. If the \fI\-\-raw\fR option is also given then
the contents of \fIFN\fR are treated as binary.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
where \fILBA\fR is the starting Logical Block Address (LBA) to check the
diff --git a/doc/sg_inq.8 b/doc/sg_inq.8
index 76a5d97f..d01d35c7 100644
--- a/doc/sg_inq.8
+++ b/doc/sg_inq.8
@@ -1,4 +1,4 @@
-.TH SG_INQ "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_INQ "8" "August 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_inq \- issue SCSI INQUIRY command and/or decode its response
.SH SYNOPSIS
@@ -13,8 +13,8 @@ sg_inq \- issue SCSI INQUIRY command and/or decode its response
.PP
.B sg_inq
[\fI\-36\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-\-B=0|1\fR]
-[\fI\-c\fR] [\fI\-cl\fR] [\fI\-d\fR] [\fI\-e\fR] [\fI\-f\fR]
-[\fI\-h\fR] [\fI\-H\fR] [\fI\-i\fR] [\fI\-I=FN\fR] [\fI\-l=LEN\fR]
+[\fI\-c\fR] [\fI\-cl\fR] [\fI\-d\fR] [\fI\-e\fR] [\fI\-f\fR] [\fI\-h\fR]
+[\fI\-H\fR] [\fI\-i\fR] [\fI\-I=FN\fR] [\fI\-j[=LEN]\fR] [\fI\-l=LEN\fR]
[\fI\-L\fR] [\fI\-m\fR] [\fI\-M\fR] [\fI\-o\fR] [\fI\-p=VPD_PG\fR]
[\fI\-P\fR] [\fI\-r\fR] [\fI\-s\fR] [\fI\-u\fR] [\fI\-v\fR]
[\fI\-V\fR] [\fI\-x\fR] [\fI\-36\fR] [\fI\-?\fR] \fIDEVICE\fR
@@ -166,8 +166,8 @@ including a hash mark to the end of a line is ignored. If the \fI\-\-raw\fR
option is also given then \fIFN\fR is treated as binary.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-l\fR, \fB\-\-len\fR=\fILEN\fR
the number \fILEN\fR is the "allocation length" field in the INQUIRY cdb.
@@ -433,6 +433,9 @@ response in hex use '\-p=83 \-h'.
\fB\-I\fR=\fIFN\fR
equivalent to \fI\-\-inhex=FN\fR in the OPTIONS section.
.TP
+\fB\-j[\fR=\fIJO]\fR
+equivalent to \fI\-\-json[=JO]\fR in the OPTIONS section.
+.TP
\fB\-l\fR=\fILEN\fR
equivalent to \fI\-\-len=LEN\fR in the OPTIONS section.
.TP
diff --git a/doc/sg_opcodes.8 b/doc/sg_opcodes.8
index f4ea0cbf..26cfd1fb 100644
--- a/doc/sg_opcodes.8
+++ b/doc/sg_opcodes.8
@@ -1,4 +1,4 @@
-.TH SG_OPCODES "8" "April 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_OPCODES "8" "August 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_opcodes \- report supported SCSI commands or task management functions
.SH SYNOPSIS
@@ -94,8 +94,8 @@ sg3_utils manpage for more information. If the \fI\-\-raw\fR option is
also given then the contents of \fIFN\fR are treated as binary.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see the sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-m\fR, \fB\-\-mask\fR
additionally prints out the cdb mask in hex. So a 12 byte cdb will have
diff --git a/doc/sg_rep_zones.8 b/doc/sg_rep_zones.8
index 8ab9feb5..49ee070a 100644
--- a/doc/sg_rep_zones.8
+++ b/doc/sg_rep_zones.8
@@ -1,4 +1,4 @@
-.TH SG_REP_ZONES "8" "July 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_REP_ZONES "8" "AUGUST 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_rep_zones \- send SCSI REPORT ZONES, REALMS or ZONE DOMAINS command
.SH SYNOPSIS
@@ -103,8 +103,8 @@ from a REPORT ZONES command. Use the \fI\-\-domain\fR or \fI\-\-realm\fR
option for decoding the other two commands.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see the sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-l\fR, \fB\-\-locator\fR=\fILBA\fR
where \fILBA\fR plays a similar role as it does in \fI\-\-start=LBA\fR.
diff --git a/doc/sg_vpd.8 b/doc/sg_vpd.8
index 45f496c3..8bb88eef 100644
--- a/doc/sg_vpd.8
+++ b/doc/sg_vpd.8
@@ -6,8 +6,9 @@ sg_vpd \- fetch SCSI VPD page and/or decode its response
[\fI\-\-all\fR] [\fI\-\-enumerate\fR] [\fI\-\-examine\fR] [\fI\-\-force\fR]
[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR] [\fI\-\-inhex=FN\fR]
[\fI\-\-json[=JO]\fR] [\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR]
-[\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-vendor=VP\fR]
-[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR]
+[\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR]
+[\fI\-\-sinq_inraw=RFN\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fIDEVICE\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -62,20 +63,24 @@ with \fI\-\-vendor=VP\fR to restrict output to known vendor specific pages
for vendor/product \fIVP\fR.
.TP
\fB\-E\fR, \fB\-\-examine\fR
-scan part of all of the VPD space (from 0x0 to 0xff) and output any pages
-found. This option ignores the contents of VPD page 0x0 which should contain
-a list of all supported VPD pages. However some vendors either forget to
-list some standard pages or perhaps purposely don't list vendor specific
-pages which are in the range 0xc0 to 0xff.
-.br
-If the \fI\-\-page=PG\fR option is not given and this option is given once
-then the scan is from VPD page number 0x80 to 0xff inclusive. If the
-\fI\-\-page=PG\fR option is given then the scan is from 0x80 to
-\fIPG\fR inclusive. If this option is given twice then the scan starts at
-VPD page 0x0.
+scan part of all of the VPD space (page numbers 0x0 to 0xff) and output any
+pages found. If this option is given once, the scan starts at page 0x80;
+if it is given twice, the scan starts at 0x0; and if given three times the
+scan starts at 0xc0. This option takes no notice of the contents of VPD page
+0x0 which should contain a list of all supported VPD pages. Some vendors
+either forget to list some standard pages or perhaps purposely don't list
+vendor specific pages which are in the range 0xc0 to 0xff.
+.br
+If the \fI\-\-page=PG\fR option is not given then the scan finishes at page
+0xff. if the \fI\-\-page=PG\fR option is given then the scan finishes at
+page \fIPG\fR. A check is made before the scan to make sure the start page
+is less than or equal to the finish page; if not the start and finish page
+numbers are swapped.
.br
The sdparm utility which lists mode and VPD pages also has a \fB\-\-examine\fR
-option will similar functionility.
+option will similar functionility. Note that T10 has changed most of the
+pages that list supported pages (e.g. VPD, mode and log pages; supported
+commands) to add the weasel words "may or may not list all ...".
.TP
\fB\-f\fR, \fB\-\-force\fR
As a sanity check, the normal action when fetching VPD pages other than
@@ -119,8 +124,8 @@ including a hash mark to the end of line is ignored. If the \fI\-\-raw\fR
option is also given then \fIFN\fR is treated as binary.
.TP
\fB\-j\fR, \fB\-\-json[\fR=\fIJO\fR]
-output is in JSON format instead of human readable form. This is an
-EXPERIMENTAL feature; see sg3_utils_json manpage.
+output is in JSON format instead of human readable form. See sg3_utils_json
+manpage or use '?' for \fIJO\fR for a summary.
.TP
\fB\-l\fR, \fB\-\-long\fR
when decoding some VPD pages, give a little more output. For example the ATA
@@ -166,6 +171,23 @@ used. The binary is sent to stdout, and errors are sent to stderr.
if used with \fI\-\-inhex=FN\fR then the contents of \fIFN\fR is treated as
binary.
.TP
+\fB\-Q\fR, \fB\-\-sinq_inraw\fR=\fIRFN\fR
+where \fIRFN\fR is a filename containing binary standard INQUIRY response
+data that matches either \fIDEVICE\fR or \fIFN\fR. Linux places this
+standard INQUIRY response in its sysfs pseudo filesystem. A typical
+location is at /sys/class/scsi_disk/<hctl>/device/inquiry where <hctl> is
+a four part numeric tuple separated by colons. This tuple distinguishes
+the device from any others on the system. Linux also places some VPD page
+responses in binary in the same directory with names like "vpd_pg83" where
+the last two digits form the hexadecimal VPD page number whose binary
+contents are therein.
+.br
+Some VPD pages (e.g. the Extended Inquiry VPD page) depend on knowing
+the settings in the standard INQUIRY response to interpret the fields
+in that VPD page. This option together with the \fI\-\-all\fR,
+\fI\-\-examine\fR or \fI\-\-page=PG\fR allows this utility to process
+both the standard INQUIRY response and VPD pages in the same invocation.
+.TP
\fB\-M\fR, \fB\-\-vendor\fR=\fIVP\fR
where \fIVP\fR is a vendor (e.g. "sea" for Seagate) or vendor/product
acronym (e.g. "hp3par" for the 3PAR array from HP). Many vendors have
diff --git a/include/sg_lib_data.h b/include/sg_lib_data.h
index 1e427043..b27b7c8d 100644
--- a/include/sg_lib_data.h
+++ b/include/sg_lib_data.h
@@ -46,9 +46,9 @@ extern "C" {
#define SG_VARIABLE_LENGTH_CMD 0x7f
#define SG_WRITE_BUFFER 0x3b
#define SG_ZONING_OUT 0x94
-#define SG_ZBC_OUT SG_ZONING_OUT /* as SPC calls them */
+#define SG_ZBC_OUT SG_ZONING_OUT /* as SPC calls them */
#define SG_ZONING_IN 0x95
-#define SG_ZBC_IN SG_ZONING_IN /* as SPC calls them */
+#define SG_ZBC_IN SG_ZONING_IN /* as SPC calls them */
@@ -128,6 +128,7 @@ extern struct sg_lib_value_name_t sg_lib_scsi_feature_sets[];
extern const char * sg_lib_sense_key_desc[];
extern const char * sg_lib_pdt_strs[];
extern const char * sg_lib_transport_proto_strs[];
+extern const char * sg_lib_tapealert_strs[];
extern int sg_lib_pdt_decay_arr[];
extern struct sg_lib_simple_value_name_t sg_lib_nvme_admin_cmd_arr[];
diff --git a/include/sg_pr2serr.h b/include/sg_pr2serr.h
index 5119f003..54b8150c 100644
--- a/include/sg_pr2serr.h
+++ b/include/sg_pr2serr.h
@@ -320,7 +320,10 @@ void sgj_js_nv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop,
const char * str_name, const char * val_s,
const char * nex_s);
-/* Add hex byte strings irrespective of jsp->pr_hex setting. */
+/* Add named field whose value is a (large) JSON string made up of num_bytes
+ * ASCII hexadecimal bytes (each two hex digits seperated by a space) starting
+ * at byte_arr. The heap is used for intermediate storage so num_bytes can
+ * be arbitrarily large. */
void sgj_js_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
const uint8_t * byte_arr, int num_bytes);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 3f98edfb..69c64aff 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -91,6 +91,7 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
# AM_CFLAGS = -Wall -W -pedantic -std=c11
# AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze
+# AM_CFLAGS = -Wall -W -pedantic -std=c++11
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 5f07c745..88ba65b9 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -404,6 +404,7 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
# AM_CFLAGS = -Wall -W -pedantic -std=c11
# AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze
+# AM_CFLAGS = -Wall -W -pedantic -std=c++11
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 827a96b3..e1fbea6b 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -3580,7 +3580,7 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
int ret = 0;
unsigned int h;
const char * lcp;
- FILE * fp;
+ FILE * fp = NULL;
struct stat a_stat;
char line[512];
char carry_over[4];
@@ -3791,11 +3791,11 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
return SG_LIB_LBA_OUT_OF_RANGE;
}
*mp_arr_len = off;
- if (stdin != fp)
+ if (fp && (! has_stdin))
fclose(fp);
return 0;
fini:
- if (fp && (stdin != fp))
+ if (fp && (! has_stdin))
fclose(fp);
return ret;
}
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 92884b38..66c9e98d 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -19,7 +19,7 @@
#include "sg_lib_data.h"
-const char * sg_lib_version_str = "2.92 20220809";
+const char * sg_lib_version_str = "2.93 20220816";
/* spc6r06, sbc5r03, zbc2r13 */
@@ -557,6 +557,75 @@ struct sg_lib_value_name_t sg_lib_zoning_in_arr[] = {
{0xffff, 0, NULL},
};
+const char * sg_lib_tapealert_strs[] = {
+ "<parameter code 0, unknown>", /* 0x0 */
+ "Read warning",
+ "Write warning",
+ "Hard error",
+ "Media",
+ "Read failure",
+ "Write failure",
+ "Media life",
+ "Not data grade", /* 0x8 */
+ "Write protect",
+ "No removal",
+ "Cleaning media",
+ "Unsupported format",
+ "Recoverable mechanical cartridge failure",
+ "Unrecoverable mechanical cartridge failure",
+ "Memory chip in cartridge failure",
+ "Forced eject", /* 0x10 */
+ "Read only format",
+ "Tape directory corrupted on load",
+ "Nearing media life",
+ "Cleaning required",
+ "Cleaning requested",
+ "Expired cleaning media",
+ "Invalid cleaning tape",
+ "Retension requested", /* 0x18 */
+ "Dual port interface error",
+ "Cooling fan failing",
+ "Power supply failure",
+ "Power consumption",
+ "Drive maintenance",
+ "Hardware A",
+ "Hardware B",
+ "Interface", /* 0x20 */
+ "Eject media",
+ "Microcode update fail",
+ "Drive humidity",
+ "Drive temperature",
+ "Drive voltage",
+ "Predictive failure",
+ "Diagnostics required",
+ "Reserved (28h)", /* 0x28 */
+ "Reserved (29h)",
+ "Reserved (2Ah)",
+ "Reserved (2Bh)",
+ "Reserved (2Ch)",
+ "Reserved (2Dh)",
+ "Reserved (2Eh)",
+ "External data encryption control - communications failure",
+ "External data encryption control - key manager returned error",/* 0x30 */
+ "Diminished native capacity",
+ "Lost statistics",
+ "Tape directory invalid at unload",
+ "Tape system area write failure",
+ "Tape system area read failure",
+ "No start of data",
+ "Loading failure",
+ "Unrecoverable unload failure", /* 0x38 */
+ "Automation interface failure",
+ "Firmware failure",
+ "WORM medium - integrity check failed",
+ "WORM medium - overwrite attempted",
+ "Encryption policy violation",
+ "Reserved (3Eh)",
+ "Reserved (3Fh)",
+ "Reserved (40h)", /* 0x40 */
+ NULL,
+};
+
/* Read attribute [0x8c] service actions */
struct sg_lib_value_name_t sg_lib_read_attr_arr[] = {
{0x0, PDT_ALL, "attribute values"},
@@ -649,6 +718,10 @@ struct sg_lib_value_name_t sg_lib_read_attr_arr[] = {
{0xffff, 0, NULL},
};
+const char * sg_lib_tapealert_strs[] = {
+ NULL,
+};
+
#endif /* SG_SCSI_STRINGS */
/* A conveniently formatted list of SCSI ASC/ASCQ codes and their
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index 52a4d000..5112fbfb 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -669,11 +669,12 @@ void
sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
int64_t val_i, bool hex_as_well, const char * nex_s)
{
- bool as_hex = jsp->pr_hex && hex_as_well;
- bool as_nex = jsp->pr_name_ex && nex_s;
+ bool as_hex, as_nex;
if ((NULL == jsp) || (! jsp->pr_as_json))
return;
+ as_hex = jsp->pr_hex && hex_as_well;
+ as_nex = jsp->pr_name_ex && nex_s;
if (! (as_hex || as_nex))
sgj_js_nv_i(jsp, jop, name, val_i);
else {
diff --git a/src/Makefile.am b/src/Makefile.am
index 021100d3..f75bc7cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,6 +62,8 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
# AM_CFLAGS = -Wall -W -pedantic -std=c11
# AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze
+# AM_CFLAGS = -Wall -W -pedantic -std=c++98
+# AM_CFLAGS = -Wall -W -pedantic -std=c++11
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
diff --git a/src/Makefile.in b/src/Makefile.in
index f8b5a25d..c5217b1e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -664,6 +664,8 @@ AM_CFLAGS = -Wall -W $(DBG_CFLAGS)
# AM_CFLAGS = -Wall -W -Wextra -Wmisleading-indentation -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init
# AM_CFLAGS = -Wall -W -pedantic -std=c11
# AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze
+# AM_CFLAGS = -Wall -W -pedantic -std=c++98
+# AM_CFLAGS = -Wall -W -pedantic -std=c++11
# AM_CFLAGS = -Wall -W -pedantic -std=c++14
# AM_CFLAGS = -Wall -W -pedantic -std=c++1z
# AM_CFLAGS = -Wall -W -pedantic -std=c++20
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 681073fe..47834743 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -53,7 +53,7 @@
#include "sg_vpd_common.h" /* for shared VPD page processing with sg_vpd */
-static const char * version_str = "2.28 20220811"; /* spc6r06, sbc5r03 */
+static const char * version_str = "2.28 20220818"; /* spc6r06, sbc5r03 */
#define MY_NAME "sg_inq"
@@ -88,10 +88,6 @@ static const char * version_str = "2.28 20220811"; /* spc6r06, sbc5r03 */
// #undef SG_SCSI_STRINGS
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING
-#ifndef SG_NVME_VPD_NICR
-#define SG_NVME_VPD_NICR 0xde
-#endif
-
#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
/* Vendor specific VPD pages (typically >= 0xc0) */
@@ -146,6 +142,8 @@ static void prepare_ata_identify(const struct opts_t * op, int inhex_len);
/* Note that this table is sorted by acronym */
static struct svpd_values_name_t t10_vpd_pg[] = {
+ {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
+ "number (SSC)"},
{VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
{VPD_BLOCK_DEV_CHARS, 0, 0, "bdc",
"Block device characteristics (SBC)"},
@@ -153,6 +151,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
"extension (SBC)"},
{VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
{VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
+ {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
{VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges "
"(SBC)"},
{VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
@@ -169,6 +168,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
#endif
{VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"},
{VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"},
+ {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"},
{VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning "
"(SBC)"},
{VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"},
@@ -176,12 +176,14 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
"Manufacturer assigned serial number (ADC)"},
{VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
{VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
- {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},
+ {VPD_POWER_CONDITION, 0, -1, "po", "Power condition"},/* "pc" in sg_vpd */
{VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
{VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
"information"},
{VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"},
{VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"},
+ {VPD_SA_DEV_CAP, 0, 1, "sad",
+ "Sequential access device capabilities (SSC)"},
{VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and "
"protection types (SBC)"},
{VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"},
@@ -190,6 +192,7 @@ static struct svpd_values_name_t t10_vpd_pg[] = {
{VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
{VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
{VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"},
+ {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"},
{VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"},
{VPD_ZBC_DEV_CHARS, 0, 0, "zbdch", "Zoned block device "
"characteristics"},
@@ -331,9 +334,10 @@ usage()
" --version|-V print version string then exit\n"
" --vpd|-e vital product data (set page with "
"'--page=PG')\n\n"
- "Performs a SCSI INQUIRY command on DEVICE or decodes INQUIRY "
- "response\nheld in file FN. If no options given then does a "
- "'standard' INQUIRY.\nCan list VPD pages with '--vpd' or "
+ "Sends a SCSI INQUIRY command to the DEVICE and decodes the "
+ "response.\nAlternatively it decodes the INQUIRY response held "
+ "in file FN. If no\noptions given then it sends a 'standard' "
+ "INQUIRY command to DEVICE. Can\nlist VPD pages with '--vpd' or "
"'--page=PG' option.\n");
}
@@ -344,11 +348,11 @@ usage_old()
#ifdef SG_LIB_LINUX
pr2serr("Usage: sg_inq [-a] [-A] [-b] [-B=0|1] [-c] [-cl] [-d] [-e] "
"[-h]\n"
- " [-H] [-i] [I=FN] [-l=LEN] [-L] [-m] [-M] "
- "[-o]\n"
- " [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] [-V] "
- "[-x]\n"
- " [-36] [-?] DEVICE\n"
+ " [-H] [-i] [-I=FN] [-j[=JO]] [-l=LEN] [-L] [-m] "
+ "[-M]\n"
+ " [-o] [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] "
+ "[-V]\n"
+ " [-x] [-36] [-?] DEVICE\n"
" where:\n"
" -a decode ATA information VPD page (0x89)\n"
" -A treat <device> as (directly attached) ATA device\n");
@@ -374,6 +378,8 @@ usage_old()
" -H output in hex (ASCII to the right) [same as '-h']\n"
" -i decode device identification VPD page (0x83)\n"
" -I=FN use ASCII hex in file FN instead of DEVICE\n"
+ " -j[=JO] output in JSON instead of human readable "
+ "text.\n"
" -l=LEN requested response length (def: 0 "
"-> fetch 36\n"
" bytes first, then fetch again as "
@@ -395,7 +401,8 @@ usage_old()
" -x decode extended INQUIRY data VPD page (0x86)\n"
" -36 perform standard INQUIRY with a 36 byte response\n"
" -? output this usage message\n\n"
- "If no options given then does a standard SCSI INQUIRY\n");
+ "If no options given then sends a standard SCSI INQUIRY "
+ "command and\ndecodes the response.\n");
}
static void
@@ -749,7 +756,22 @@ old_parse_cmd_line(struct opts_t * op, int argc, char * argv[])
op->do_block = n;
} else if (0 == strncmp("I=", cp, 2))
op->inhex_fn = cp + 2;
- else if (0 == strncmp("l=", cp, 2)) {
+ else if ('j' == *cp) { /* handle either '-j' or '-j=<JO>' */
+ const char * c2p = (('=' == *(cp + 1)) ? cp + 2 : NULL);
+
+ if (! sgj_init_state(&op->json_st, c2p)) {
+ int bad_char = op->json_st.first_bad_char;
+ char e[1500];
+
+ if (bad_char) {
+ pr2serr("bad argument to --json= option, unrecognized "
+ "character '%c'\n\n", bad_char);
+ }
+ sg_json_usage(0, e, sizeof(e));
+ pr2serr("%s", e);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strncmp("l=", cp, 2)) {
num = sscanf(cp + 2, "%d", &n);
if ((1 != num) || (n < 1)) {
pr2serr("Inappropriate value after 'l=' option\n");
@@ -849,6 +871,7 @@ enumerate_vpds()
{
const struct svpd_values_name_t * vnp;
+ printf("T10 defined VPD pages:\n");
for (vnp = t10_vpd_pg; vnp->acron; ++vnp) {
if (vnp->name) {
if (vnp->value < 0)
@@ -858,6 +881,7 @@ enumerate_vpds()
vnp->name);
}
}
+ printf("Vendor specific VPD pages:\n");
for (vnp = vs_vpd_pg; vnp->acron; ++vnp) {
if (vnp->name) {
if (vnp->value < 0)
@@ -1092,6 +1116,16 @@ svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop)
return res;
}
+static int
+no_ascii_4hex(const struct opts_t * op)
+{
+ if (op->do_hex < 2)
+ return 1;
+ else if (2 == op->do_hex)
+ return 0;
+ else
+ return -1;
+}
static void
decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
@@ -1104,7 +1138,7 @@ decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
char b[64];
if (op->do_hex) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (len < 4) {
@@ -1165,14 +1199,14 @@ vpd_page_is_supported(uint8_t * vpd_pg0, int v0_len, int pg_num, int vb)
/* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */
static void
-decode_ascii_inf(uint8_t * buff, int len, int do_hex)
+decode_ascii_inf(uint8_t * buff, int len, struct opts_t * op)
{
int al, k, bump;
uint8_t * bp;
uint8_t * p;
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (len < 4) {
@@ -1247,8 +1281,7 @@ decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
if (ip_tid_len > 0) {
if (op->do_hex) {
printf(" Initiator port transport id:\n");
- hex2stdout((bp + 8), ip_tid_len,
- (1 == op->do_hex) ? 1 : -1);
+ hex2stdout((bp + 8), ip_tid_len, no_ascii_4hex(op));
} else {
char b[1024];
@@ -1271,8 +1304,7 @@ decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op,
if (tpd_len > 0) {
sgj_pr_hr(jsp, " Target port descriptor(s):\n");
if (op->do_hex)
- hex2stdout(bp + bump + 4, tpd_len,
- (1 == op->do_hex) ? 1 : -1);
+ hex2stdout(bp + bump + 4, tpd_len, no_ascii_4hex(op));
else {
sgj_opaque_p ja2p = sgj_named_subarray_r(jsp, jo2p,
"target_port_descriptor_list");
@@ -1953,7 +1985,8 @@ export_dev_ids(uint8_t * buff, int len, int verbose)
"around offset=%d\n", off);
}
-/* VPD_BLOCK_LIMITS sbc */
+/* VPD_BLOCK_LIMITS 0xb0 ["bl"] (SBC) */
+/* VPD_SA_DEV_CAP 0xb0 ["sad"] (SSC) */
/* Sequential access device characteristics, ssc+smc */
/* OSD information, osd */
static void
@@ -1963,7 +1996,7 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
sgj_state * jsp = &op->json_st;
if (op->do_hex) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
switch (pdt) {
@@ -1981,8 +2014,8 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
break;
case PDT_OSD:
default:
- printf(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stdout(buff, len, 0);
+ pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
+ hex2stderr(buff, len, 0);
break;
}
}
@@ -1990,49 +2023,60 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
/* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */
/* VPD_MAN_ASS_SN ssc */
static void
-decode_b1_vpd(uint8_t * buff, int len, int do_hex)
+decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
{
int pdt;
+ sgj_state * jsp = &op->json_st;
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
pdt = PDT_MASK & buff[0];
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
- break;
- case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
- printf(" Manufacturer-assigned serial number: %.*s\n",
- len - 4, buff + 4);
- break;
- default:
- printf(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stdout(buff, len, 0);
- break;
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
+ break;
+ case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
+ sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n",
+ len - 4, buff + 4);
+ sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number",
+ (const char *)buff + 4, len - 4);
+ break;
+ default:
+ pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
+ hex2stderr(buff, len, 0);
+ break;
}
}
-/* VPD_REFERRALS sbc */
+/* VPD_REFERRALS sbc 0xb3 ["ref"] */
+/* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */
static void
-decode_b3_vpd(uint8_t * buff, int len, int do_hex)
+decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
{
int pdt;
+ sgj_state * jsp = &op->json_st;
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
- pdt = PDT_MASK & buff[0];
+ pdt = buff[0] & PDT_MASK;
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
- /* now done in decode)referrals_vpd() in sg_vpd_common.c */
- break;
- default:
- printf(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stdout(buff, len, 0);
- break;
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
+ /* now done in decode_referrals_vpd() in sg_vpd_common.c */
+ break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ sgj_pr_hr(jsp, " Automation device serial number: %.*s\n",
+ len - 4, buff + 4);
+ sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number",
+ (const char *)buff + 4, len - 4);
+ break;
+ default:
+ pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
+ hex2stderr(buff, len, 0);
+ break;
}
}
@@ -2084,7 +2128,7 @@ static const char * failover_mode_arr[] =
};
static void
-decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex)
+decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op)
{
int k, ip_mgmt, vpp80, lun_z;
@@ -2092,8 +2136,8 @@ decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex)
pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len);
return;
}
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 1 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (buff[9] != 0x00) {
@@ -2162,14 +2206,14 @@ decode_upr_vpd_c0_emc(uint8_t * buff, int len, int do_hex)
}
static void
-decode_rdac_vpd_c2(uint8_t * buff, int len, int do_hex)
+decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op)
{
if (len < 3) {
pr2serr("Software Version VPD page length too short=%d\n", len);
return;
}
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 1 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') {
@@ -2260,14 +2304,14 @@ decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor)
}
static void
-decode_rdac_vpd_c9(uint8_t * buff, int len, int do_hex)
+decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op)
{
if (len < 3) {
pr2serr("Volume Access Control VPD page length too short=%d\n", len);
return;
}
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 1 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') {
@@ -2398,7 +2442,7 @@ std_inq_decode(struct opts_t * op, sgj_opaque_p jop, int off)
return;
} else if (op->do_hex) {
/* with -H, print with address, -HH without */
- hex2stdout(rp, op->maxlen, ((1 == op->do_hex) ? 0 : -1));
+ hex2stdout(rp, op->maxlen, no_ascii_4hex(op));
return;
}
pqual = (rp[0] & 0xe0) >> 5;
@@ -2802,7 +2846,7 @@ cmddt_process(int sg_fd, const struct opts_t * op)
len = rsp_buff[5] + 6;
reserved_cmddt = rsp_buff[4];
if (op->do_hex)
- hex2stdout(rsp_buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rsp_buff, len, no_ascii_4hex(op));
else if (op->do_raw)
dStrRaw((const char *)rsp_buff, len);
else {
@@ -2872,14 +2916,23 @@ cmddt_process(int sg_fd, const struct opts_t * op)
static int
vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off)
{
- int res, len;
+ bool as_json;
+ bool json_o_hr;
+ int res, len, n;
char b[128];
+ sgj_state * jsp = &op->json_st;
const char * cp;
uint8_t * rp;
+ as_json = jsp->pr_as_json;
+ json_o_hr = as_json && jsp->pr_out_hr;
rp = rsp_buff + off;
- if ((! op->do_raw) && (op->do_hex < 2))
- printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
+ if ((! op->do_raw) && (op->do_hex < 3)) {
+ if (op->do_hex)
+ printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn);
+ }
if (sg_fd < 0) {
len = sg_get_unaligned_be16(rp + 2) + 4;
res = 0;
@@ -2892,15 +2945,32 @@ vpd_mainly_hex(int sg_fd, struct opts_t * op, sgj_opaque_p jap, int off)
if (op->do_raw)
dStrRaw((const char *)rp, len);
else {
+ int pdt = pdt = rp[0] & PDT_MASK;
+
if (0 == op->vpd_pn)
decode_supported_vpd_4inq(rp, len, op, jap);
else {
if (op->verbose) {
- cp = sg_get_pdt_str(rp[0] & PDT_MASK, sizeof(b), b);
- printf(" [PQual=%d Peripheral device type: %s]\n",
- (rp[0] & 0xe0) >> 5, cp);
+ cp = sg_get_pdt_str(pdt, sizeof(b), b);
+ if (op->do_hex)
+ printf(" [PQual=%d Peripheral device type: %s]\n",
+ (rp[0] & 0xe0) >> 5, cp);
+ else
+ sgj_pr_hr(jsp, " [PQual=%d Peripheral device "
+ "type: %s]\n", (rp[0] & 0xe0) >> 5, cp);
}
- hex2stdout(rp, len, ((1 == op->do_hex) ? 0 : -1));
+ if (json_o_hr && (0 == op->do_hex) && (len > 0) &&
+ (len < UINT16_MAX)) {
+ char * p;
+
+ n = len * 4;
+ p = malloc(n);
+ if (p) {
+ n = hex2str(rp, len, NULL, 1, n - 1, p);
+ sgj_js_str_out(jsp, p, n);
+ }
+ } else
+ hex2stdout(rp, len, no_ascii_4hex(op));
}
}
} else {
@@ -2959,7 +3029,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
switch (pn) {
case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */
np = "Supported VPD pages VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -2967,7 +3037,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (op->do_raw)
dStrRaw((const char *)rp, len);
else if (op->do_hex)
- hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rp, len, no_ascii_4hex(op));
else {
if (as_json) {
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
@@ -2979,7 +3049,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */
np = "Unit serial number VPD page";
- if (! op->do_raw && ! op->do_export && (op->do_hex < 2))
+ if (! op->do_raw && ! op->do_export && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -2987,7 +3057,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (op->do_raw)
dStrRaw((const char *)rp, len);
else if (op->do_hex)
- hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rp, len, no_ascii_4hex(op));
else {
char obuff[DEF_ALLOC_LEN];
int k, m;
@@ -3048,7 +3118,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */
np = "Software interface identification VPD page";
- if (! op->do_raw && (op->do_hex < 2))
+ if (! op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3066,7 +3136,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */
np = "Management network addresses page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3087,7 +3157,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_EXT_INQ: /* 0x86 ["ei"] */
np = "Extended INQUIRY data";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3095,14 +3165,30 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (op->do_raw)
dStrRaw((const char *)rp, len);
else {
+ bool protect = false;
+
+ op->protect_not_sure = false;
+ if ((sg_fd >= 0) && (! op->do_force)) {
+ struct sg_simple_inquiry_resp sir;
+
+ res = sg_simple_inquiry(sg_fd, &sir, false, vb);
+ if (res) {
+ if (op->verbose)
+ pr2serr("%s: sg_simple_inquiry() failed, res=%d\n",
+ __func__, res);
+ op->protect_not_sure = true;
+ } else
+ protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
+ } else
+ op->protect_not_sure = true;
if (as_json)
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- decode_x_inq_vpd(rp, len, false /* protect */, op, jo2p);
+ decode_x_inq_vpd(rp, len, protect, op, jo2p);
}
break;
case VPD_MODE_PG_POLICY: /* 0x87 ["mpp"] */
np = "Mode page policy";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3120,7 +3206,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_SCSI_PORTS: /* 0x88 ["sp"] */
np = "SCSI Ports VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3138,7 +3224,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_ATA_INFO: /* 0x89 ["ai"] */
np = "ATA information VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3159,7 +3245,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_POWER_CONDITION: /* 0x8a ["pc"] */
np = "Power condition VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3172,9 +3258,9 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
decode_power_condition(rp, len, op, jo2p);
}
break;
- case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */
- np = "Power consumption VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */
+ np = "Device constituents page VPD page";
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3185,14 +3271,32 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (as_json) {
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_named_subarray_r(jsp, jo2p,
- "power_consumption_descriptor_list");
+ "constituent_descriptor_list");
}
- decode_power_consumption(rp, len, op, jap);
+ decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
}
break;
- case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */
- np = "Device constituents page VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */
+ np = "CFA profile information VPD page";
+ if (!op->do_raw && (op->do_hex < 3))
+ sgj_pr_hr(jsp, "%s:\n", np);
+ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
+ if (0 == res) {
+ if (op->do_raw)
+ dStrRaw((const char *)rp, len);
+ else {
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_named_subarray_r(jsp, jo2p,
+ "cfa_profile_descriptor_list");
+ }
+ decode_cga_profile_vpd(rp, len, op, jap);
+ }
+ }
+ break;
+ case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */
+ np = "Power consumption VPD page";
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3203,14 +3307,14 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (as_json) {
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
jap = sgj_named_subarray_r(jsp, jo2p,
- "constituent_descriptor_list");
+ "power_consumption_descriptor_list");
}
- decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode);
+ decode_power_consumption(rp, len, op, jap);
}
break;
case VPD_3PARTY_COPY: /* 0x8f ["tpc"] */
np = "Third party copy VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3228,7 +3332,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_PROTO_LU: /* 0x90 ["pslu"] */
np = "Protocol specific logical unit information VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3246,7 +3350,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_PROTO_PORT: /* 0x91 ["pspo"] */
np = "Protocol specific port information VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3264,7 +3368,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
break;
case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */
np = "SCSI Feature sets VPD page";
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (res)
@@ -3314,7 +3418,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3364,7 +3468,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt);
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3375,7 +3479,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
if (bdc)
decode_block_dev_ch_vpd(rp, len, op, jo2p);
else
- decode_b1_vpd(rp, len, op->do_hex);
+ decode_b1_vpd(rp, len, op, jo2p);
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb1\n");
break;
@@ -3383,6 +3487,7 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
bool lbpv = false;
+ bool tas = false;
if (op->do_raw) {
dStrRaw((const char *)rp, len);
@@ -3398,12 +3503,13 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
case PDT_TAPE: case PDT_MCHANGER:
np = "TapeAlert supported flags VPD page";
ep = "(SSC)";
+ tas = true;
break;
default:
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3413,18 +3519,13 @@ vpd_decode(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
if (lbpv)
return decode_block_lb_prov_vpd(rp, len, op, jo2p);
+ else if (tas)
+ decode_tapealert_supported_vpd(rp, len, op, jo2p);
else
return vpd_mainly_hex(sg_fd, op, NULL, off);
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb2\n");
break;
-#if 0
-xxxxx
- if (!op->do_raw && (op->do_hex < 2))
- pr2serr(" Only hex output supported. The sg_vpd utility decodes "
- "the B2h page.\n");
- return vpd_mainly_hex(sg_fd, op, NULL, off);
-#endif
case 0xb3:
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
@@ -3445,7 +3546,7 @@ xxxxx
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3456,7 +3557,7 @@ xxxxx
if (ref)
decode_referrals_vpd(rp, len, op, jo2p);
else
- decode_b3_vpd(rp, len, op->do_hex);
+ decode_b3_vpd(rp, len, op, jo2p);
return 0;
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb3\n");
@@ -3465,6 +3566,7 @@ xxxxx
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
bool sbl = false;
+ bool dtde = false;
if (op->do_raw) {
dStrRaw((const char *)rp, len);
@@ -3477,24 +3579,34 @@ xxxxx
ep = "(SBC)";
sbl = true;
break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Device transfer data element VPD page";
+ ep = "(SSC)";
+ dtde = true;
+ break;
default:
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
}
- if (as_json) {
+ if (as_json)
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
+ if (sbl) {
+ if (as_json)
+ jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
"length_and_protection_types_descriptor_list");
- }
- if (sbl)
decode_sup_block_lens_vpd(rp, len, op, jap);
- else
+ } else if (dtde) {
+ if (! jsp->pr_as_json)
+ hex2stdout(rp + 4, len - 4, 1);
+ sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element",
+ rp + 4, len - 4);
+ } else
return vpd_mainly_hex(sg_fd, op, NULL, off);
return 0;
} else if (! op->do_raw)
@@ -3504,6 +3616,7 @@ xxxxx
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
bool bdce = false;
+ bool lbp = false;
if (op->do_raw) {
dStrRaw((const char *)rp, len);
@@ -3516,11 +3629,16 @@ xxxxx
ep = "(SBC)";
bdce = true;
break;
+ case PDT_TAPE: case PDT_MCHANGER:
+ np = "Logical block protection VPD page";
+ ep = "(SSC)";
+ lbp = true;
+ break;
default:
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3530,7 +3648,12 @@ xxxxx
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
if (bdce)
decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
- else
+ else if (lbp) { /* VPD_LB_PROTECTION 0xb5 ["lbpro"] (SSC) */
+ if (as_json)
+ jap = sgj_named_subarray_r(jsp, jo2p,
+ "logical_block_protection_method_descriptor_list");
+ decode_lb_protection_vpd(rp, len, op, jap);
+ } else
return vpd_mainly_hex(sg_fd, op, NULL, off);
return 0;
} else if (! op->do_raw)
@@ -3556,7 +3679,7 @@ xxxxx
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3592,7 +3715,7 @@ xxxxx
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3628,7 +3751,7 @@ xxxxx
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3667,7 +3790,7 @@ xxxxx
np = NULL;
break;
}
- if (op->do_hex < 2) {
+ if (op->do_hex < 3) {
if (NULL == np)
sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
else
@@ -3686,9 +3809,9 @@ xxxxx
} else if (! op->do_raw)
pr2serr("VPD INQUIRY: page=0xb8\n");
break;
-// yyyyyyyy
+ /* Vendor specific VPD pages (>= 0xc0) */
case VPD_UPR_EMC: /* 0xc0 */
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
if (res)
@@ -3696,10 +3819,10 @@ xxxxx
if (op->do_raw)
dStrRaw((const char *)rp, len);
else
- decode_upr_vpd_c0_emc(rp, len, op->do_hex);
+ decode_upr_vpd_c0_emc(rp, len, op);
break;
case VPD_RDAC_VERS: /* 0xc2 */
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
printf("VPD INQUIRY: Software Version (RDAC)\n");
res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
if (res)
@@ -3707,10 +3830,10 @@ xxxxx
if (op->do_raw)
dStrRaw((const char *)rp, len);
else
- decode_rdac_vpd_c2(rp, len, op->do_hex);
+ decode_rdac_vpd_c2(rp, len, op);
break;
case VPD_RDAC_VAC: /* 0xc9 */
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
printf("VPD INQUIRY: Volume Access Control (RDAC)\n");
res = vpd_fetch_page(sg_fd, rp, pn, -1, qt, vb, &len);
if (res)
@@ -3718,7 +3841,47 @@ xxxxx
if (op->do_raw)
dStrRaw((const char *)rp, len);
else
- decode_rdac_vpd_c9(rp, len, op->do_hex);
+ decode_rdac_vpd_c9(rp, len, op);
+ break;
+ case SG_NVME_VPD_NICR: /* 0xde */
+ np = "NVMe Identify Controller Response VPD page";
+ /* NVMe: Identify Controller data structure (CNS 01h) */
+ ep = "(sg3_utils)";
+ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
+ if (res) {
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ break;
+ }
+ if (op->do_raw) {
+ dStrRaw((const char *)rp, len);
+ break;
+ }
+ pdt = rp[0] & PDT_MASK;
+ if (op->do_hex < 3) {
+ if (NULL == np)
+ sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt);
+ else
+ sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep);
+ }
+ if (len < 16) {
+ pr2serr("%s expected to be > 15 bytes long (got: %d)\n", ep, len);
+ break;
+ } else {
+ int n = len - 16;
+
+ if (n > 4096) {
+ pr2serr("NVMe Identify response expected to be <= 4096 "
+ "bytes (got: %d)\n", n);
+ break;
+ }
+ if (op->do_hex)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n);
+ } else
+ hex2stdout(rp + 16, n, 1);
+ }
break;
default:
bad = true;
@@ -3726,7 +3889,7 @@ xxxxx
}
if (bad) {
if ((pn > 0) && (pn < 0x80)) {
- if (!op->do_raw && (op->do_hex < 2))
+ if (!op->do_raw && (op->do_hex < 3))
printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n",
pn);
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
@@ -3734,12 +3897,11 @@ xxxxx
if (op->do_raw)
dStrRaw((const char *)rp, len);
else
- decode_ascii_inf(rp, len, op->do_hex);
+ decode_ascii_inf(rp, len, op);
}
} else {
- if (op->do_hex < 2)
- pr2serr(" Only hex output supported. The sg_vpd and sdparm "
- "utilities decode more VPD pages.\n");
+ if (op->do_hex < 3)
+ pr2serr(" Only hex output supported.\n");
return vpd_mainly_hex(sg_fd, op, NULL, off);
}
}
@@ -4212,7 +4374,8 @@ main(int argc, char * argv[])
enumerate_vpds();
return SG_LIB_SYNTAX_ERROR;
}
- if ((1 != op->do_hex) && (0 == op->do_raw))
+ // if ((1 != op->do_hex) && (0 == op->do_raw))
+ if (0 == op->do_raw)
op->do_decode = true;
op->vpd_pn = vnp->value;
subvalue = vnp->subvalue;
diff --git a/src/sg_logs.c b/src/sg_logs.c
index 32bfc721..6f5edd48 100644
--- a/src/sg_logs.c
+++ b/src/sg_logs.c
@@ -37,7 +37,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.99 20220729"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "2.00 20220816"; /* spc6r06 + sbc5r03 */
#define MX_ALLOC_LEN (0xfffc)
#define MX_INLEN_ALLOC_LEN (0x800000)
@@ -6711,70 +6711,6 @@ skip:
return true;
}
-static const char * tape_alert_strs[] = {
- "<parameter code 0, unknown>", /* 0x0 */
- "Read warning",
- "Write warning",
- "Hard error",
- "Media",
- "Read failure",
- "Write failure",
- "Media life",
- "Not data grade", /* 0x8 */
- "Write protect",
- "No removal",
- "Cleaning media",
- "Unsupported format",
- "Recoverable mechanical cartridge failure",
- "Unrecoverable mechanical cartridge failure",
- "Memory chip in cartridge failure",
- "Forced eject", /* 0x10 */
- "Read only format",
- "Tape directory corrupted on load",
- "Nearing media life",
- "Cleaning required",
- "Cleaning requested",
- "Expired cleaning media",
- "Invalid cleaning tape",
- "Retension requested", /* 0x18 */
- "Dual port interface error",
- "Cooling fan failing",
- "Power supply failure",
- "Power consumption",
- "Drive maintenance",
- "Hardware A",
- "Hardware B",
- "Interface", /* 0x20 */
- "Eject media",
- "Microcode update fail",
- "Drive humidity",
- "Drive temperature",
- "Drive voltage",
- "Predictive failure",
- "Diagnostics required",
- "Obsolete (28h)", /* 0x28 */
- "Obsolete (29h)",
- "Obsolete (2Ah)",
- "Obsolete (2Bh)",
- "Obsolete (2Ch)",
- "Obsolete (2Dh)",
- "Obsolete (2Eh)",
- "Reserved (2Fh)",
- "Reserved (30h)", /* 0x30 */
- "Reserved (31h)",
- "Lost statistics",
- "Tape directory invalid at unload",
- "Tape system area write failure",
- "Tape system area read failure",
- "No start of data",
- "Loading failure",
- "Unrecoverable unload failure", /* 0x38 */
- "Automation interface failure",
- "Firmware failure",
- "WORM medium - integrity check failed",
- "WORM medium - overwrite attempted",
-};
-
/* TAPE_ALERT_LPAGE [0x2e] <ta> */
static bool
show_tape_alert_ssc_page(const uint8_t * resp, int len,
@@ -6807,8 +6743,11 @@ show_tape_alert_ssc_page(const uint8_t * resp, int len,
if (op->verbose && (0 == op->do_brief) && flag)
printf(" >>>> ");
if ((0 == op->do_brief) || op->verbose || flag) {
- if (pc < (int)SG_ARRAY_SIZE(tape_alert_strs))
- printf(" %s: %d\n", tape_alert_strs[pc], flag);
+ if (NULL == sg_lib_tapealert_strs[0])
+ printf(" No string available for code 0x%x, flag: %d\n",
+ pc, flag);
+ else if (pc <= 0x40)
+ printf(" %s: %d\n", sg_lib_tapealert_strs[pc], flag);
else
printf(" Reserved parameter code 0x%x, flag: %d\n", pc,
flag);
diff --git a/src/sg_ses.c b/src/sg_ses.c
index e6e1270b..cc1ce78d 100644
--- a/src/sg_ses.c
+++ b/src/sg_ses.c
@@ -38,7 +38,7 @@
* commands tailored for SES (enclosure) devices.
*/
-static const char * version_str = "2.57 20220309"; /* ses4r04 */
+static const char * version_str = "2.58 20220813"; /* ses4r04 */
#define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */
#define MX_ELEM_HDR 1024
@@ -1084,6 +1084,8 @@ parse_index(struct opts_t *op)
}
element_type_by_code.elem_type_code = n;
mallcp = (char *)malloc(8); /* willfully forget about freeing this */
+ if (NULL == mallcp)
+ return sg_convert_errno(ENOMEM);
mallcp[0] = '_';
snprintf(mallcp + 1, 6, "%d", n);
element_type_by_code.abbrev = mallcp;
@@ -5686,12 +5688,13 @@ main(int argc, char * argv[])
if (SET_OPT == cgs_clp->cgs_sel)
tavp->val = DEF_SET_VAL;
}
- if (!strcmp(cgs_clp->cgs_str, "sas_addr") && op->dev_slot_num < 0) {
- pr2serr("--get=sas_addr requires --dev-slot-num. For expander "
- "SAS address, use exp_sas_addr instead.\n");
+ if (!strcmp(cgs_clp->cgs_str, "sas_addr") &&
+ op->dev_slot_num < 0) {
+ pr2serr("--get=sas_addr requires --dev-slot-num. For "
+ "expander SAS address, use exp_sas_addr instead.\n");
ret = SG_LIB_SYNTAX_ERROR;
goto err_out;
- }
+ }
tavp->cgs_sel = cgs_clp->cgs_sel;
}
/* keep this descending for loop directly after ascending for loop */
diff --git a/src/sg_unmap.c b/src/sg_unmap.c
index c24c676a..2bfb12d6 100644
--- a/src/sg_unmap.c
+++ b/src/sg_unmap.c
@@ -36,7 +36,7 @@
* logical blocks. Note that DATA MAY BE LOST.
*/
-static const char * version_str = "1.18 20220608";
+static const char * version_str = "1.19 20220813";
#define DEF_TIMEOUT_SECS 60
@@ -253,7 +253,7 @@ build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr,
int64_t ll;
char line[1024];
char * lcp;
- FILE * fp;
+ FILE * fp = NULL;
have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0]));
if (have_stdin)
@@ -336,12 +336,12 @@ build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr,
goto bad_exit;
}
*arr_len = off >> 1;
- if (fp && (stdin != fp))
+ if (fp && (! have_stdin))
fclose(fp);
return 0;
bad_exit:
- if (fp && (stdin != fp))
+ if (fp && (! have_stdin))
fclose(fp);
return 1;
}
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 0cb6f7ed..9aae8a72 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -42,7 +42,7 @@
*/
-static const char * version_str = "1.80 20220811"; /* spc6r06 + sbc5r03 */
+static const char * version_str = "1.81 20220818"; /* spc6r06 + sbc5r03 */
#define MY_NAME "sg_vpd"
@@ -110,17 +110,17 @@ static struct option long_options[] = {
/* arranged in alphabetical order by acronym */
static struct svpd_values_name_t standard_vpd_pg[] = {
+ {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
+ "number (SSC)"},
{VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"},
{VPD_ASCII_OP_DEF, 0, -1, "aod",
"ASCII implemented operating definition (obsolete)"},
- {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial "
- "number (SSC)"},
- {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
- {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
{VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics "
"(SBC)"},
{VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics "
"extension (SBC)"},
+ {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"},
+ {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"},
{VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"},
{VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges"},
{VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"},
@@ -147,7 +147,7 @@ static struct svpd_values_name_t standard_vpd_pg[] = {
{VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"},
{VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"},
{VPD_OSD_INFO, 0, 0x11, "oi", "OSD information"},
- {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},
+ {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"},/* "po" in sg_inq */
{VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"},
{VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit "
"information"},
@@ -444,6 +444,17 @@ device_id_vpd_variants(uint8_t * buff, int len, int subvalue,
}
}
+static int
+no_ascii_4hex(const struct opts_t * op)
+{
+ if (op->do_hex < 2)
+ return 1;
+ else if (2 == op->do_hex)
+ return 0;
+ else
+ return -1;
+}
+
static void /* VPD_SUPPORTED_VPDS ["sv"] */
decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
@@ -459,7 +470,7 @@ decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op,
static const char * svps = "Supported VPD pages";
if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
pdt = PDT_MASK & buff[0];
@@ -525,7 +536,7 @@ decode_scsi_ports_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op,
uint8_t * bp;
if ((1 == op->do_hex) || (op->do_hex > 2)) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 1 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
if (len < 4) {
@@ -876,7 +887,7 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
sgj_state * jsp = &op->json_st;
if (op->do_hex) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
switch (pdt) {
@@ -904,18 +915,24 @@ decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
/* VPD_SECURITY_TOKEN osd */
/* VPD_ES_DEV_CHARS ses-4 */
static void
-decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt)
+decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
{
- if (do_hex) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
+ int pdt;
+ sgj_state * jsp = &op->json_st;
+
+ pdt = buff[0] & PDT_MASK;
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
/* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */
case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
- printf(" Manufacturer-assigned serial number: %.*s\n",
- len - 4, buff + 4);
+ sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n",
+ len - 4, buff + 4);
+ sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number",
+ (const char *)buff + 4, len - 4);
break;
default:
pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
@@ -924,77 +941,21 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex, int pdt)
}
}
-/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */
-static void
-decode_lb_protection_vpd(uint8_t * buff, int len, int do_hex)
-{
- int k, bump;
- uint8_t * bp;
-
- if ((1 == do_hex) || (do_hex > 2)) {
- hex2stdout(buff, len, (1 == do_hex) ? 0 : -1);
- return;
- }
- if (len < 8) {
- pr2serr("Logical block protection VPD page length too short=%d\n",
- len);
- return;
- }
- len -= 8;
- bp = buff + 8;
- for (k = 0; k < len; k += bump, bp += bump) {
- bump = 1 + bp[0];
- printf(" method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, "
- "RBDP_C=%d\n", bp[1], 0x3f & bp[2], !!(0x80 & bp[3]),
- !!(0x40 & bp[3]), !!(0x20 & bp[3]));
- if ((k + bump) > len) {
- pr2serr("Logical block protection VPD page, short "
- "descriptor length=%d, left=%d\n", bump, (len - k));
- return;
- }
- }
-}
-
-/* VPD_TA_SUPPORTED 0xb2 */
-static int
-decode_tapealert_supported_vpd(uint8_t * b, int len)
-{
- int k, mod, div;
-
- if (len < 12) {
- pr2serr("TapeAlert supported flags length too short=%d\n", len);
- return SG_LIB_CAT_MALFORMED;
- }
- for (k = 1; k < 0x41; ++k) {
- mod = ((k - 1) % 8);
- div = (k - 1) / 8;
- if (0 == mod) {
- if (div > 0)
- printf("\n");
- printf(" Flag%02Xh: %d", k, !! (b[4 + div] & 0x80));
- } else
- printf(" %02Xh: %d", k, !! (b[4 + div] & (1 << (7 - mod))));
- }
- printf("\n");
- return 0;
-}
-
/* VPD_LB_PROVISIONING sbc */
/* VPD_TA_SUPPORTED ssc */
static void
decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op)
{
if (op->do_hex) {
- hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
/* decode_block_lb_prov_vpd() is now in sg_vpd_common.c */
- // decode_block_lb_prov_vpd(buff, len, op);
break;
case PDT_TAPE: case PDT_MCHANGER:
- decode_tapealert_supported_vpd(buff, len);
+ /* decode_tapealert_supported_vpd() is now in sg_vpd_common.c */
break;
default:
pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
@@ -1006,29 +967,29 @@ decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op)
/* VPD_REFERRALS sbc 0xb3 ["ref"] */
/* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */
static void
-decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op)
+decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
{
- char obuff[DEF_ALLOC_LEN];
+ int pdt;
+ sgj_state * jsp = &op->json_st;
if (op->do_hex) {
- hex2stdout(b, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
+ pdt = buff[0] & PDT_MASK;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
/* now done in decode_referrals_vpd() in sg_vpd_common.c */
break;
case PDT_TAPE: case PDT_MCHANGER:
- memset(obuff, 0, sizeof(obuff));
- len -= 4;
- if (len >= (int)sizeof(obuff))
- len = sizeof(obuff) - 1;
- memcpy(obuff, b + 4, len);
- printf(" Automation device serial number: %s\n", obuff);
+ sgj_pr_hr(jsp, " Automation device serial number: %.*s\n",
+ len - 4, buff + 4);
+ sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number",
+ (const char *)buff + 4, len - 4);
break;
default:
pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stderr(b, len, 0);
+ hex2stderr(buff, len, 0);
break;
}
}
@@ -1036,12 +997,13 @@ decode_b3_vpd(uint8_t * b, int len, int pdt, struct opts_t * op)
/* VPD_SUP_BLOCK_LENS sbc ["sbl"] */
/* VPD_DTDE_ADDRESS ssc */
static void
-decode_b4_vpd(uint8_t * b, int len, int do_hex, int pdt)
+decode_b4_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop)
{
- int k;
+ int pdt = buff[0] & PDT_MASK;
+ sgj_state * jsp = &op->json_st;
- if (do_hex) {
- hex2stdout(b, len, (1 == do_hex) ? 0 : -1);
+ if (op->do_hex) {
+ hex2stdout(buff, len, no_ascii_4hex(op));
return;
}
switch (pdt) {
@@ -1049,19 +1011,21 @@ decode_b4_vpd(uint8_t * b, int len, int do_hex, int pdt)
/* now done by decode_sup_block_lens_vpd() in sg_vpd_common.c */
break;
case PDT_TAPE: case PDT_MCHANGER:
- printf(" Data transfer device element address: 0x");
- for (k = 4; k < len; ++k)
- printf("%02x", (unsigned int)b[k]);
- printf("\n");
+ sgj_pr_hr(jsp, " Device transfer data element:\n");
+ if (! jsp->pr_as_json)
+ hex2stdout(buff + 4, len - 4, 1);
+ sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element",
+ buff + 4, len - 4);
break;
default:
pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
- hex2stderr(b, len, 0);
+ hex2stderr(buff, len, 0);
break;
}
}
/* VPD_BLOCK_DEV_C_EXTENS sbc */
+/* VPD_LB_PROTECTION 0xb5 ["lbpro"] ssc */
static void
decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
{
@@ -1074,7 +1038,7 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
/* now done by decode_block_dev_char_ext_vpd() in sg_vpd_common.c */
break;
case PDT_TAPE: case PDT_MCHANGER:
- decode_lb_protection_vpd(b, len, do_hex);
+ /* now done by decode_lb_protection_vpd() in sg_vpd_common.c */
break;
default:
pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt);
@@ -1087,20 +1051,36 @@ decode_b5_vpd(uint8_t * b, int len, int do_hex, int pdt)
static int
svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
{
- int len, res;
+ bool as_json, json_o_hr, hex0;
+ int res, len, n;
+ sgj_state * jsp = &op->json_st;
uint8_t * rp;
+ as_json = jsp->pr_as_json;
+ json_o_hr = as_json && jsp->pr_out_hr;
+ hex0 = (0 == op->do_hex);
rp = rsp_buff + off;
- if ((! op->do_hex) && (! op->do_raw) && (0 == op->examine))
- printf("Only hex output supported\n");
- if ((!op->do_raw) && (op->do_hex < 2) && (0 == op->examine)) {
- if (subvalue)
- printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn,
- subvalue);
- else if (op->vpd_pn >= 0)
- printf("VPD page code=0x%.2x:\n", op->vpd_pn);
- else
- printf("VPD page code=%d:\n", op->vpd_pn);
+ if (hex0 && (! op->do_raw) && (! op->examine_given))
+ sgj_pr_hr(jsp, "Only hex output supported\n");
+ if ((!op->do_raw) && (op->do_hex < 2) && (! op->examine_given)) {
+ if (subvalue) {
+ if (hex0)
+ sgj_pr_hr(jsp, "VPD page code=0x%.2x, subvalue=0x%.2x:\n",
+ op->vpd_pn, subvalue);
+ else
+ printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->vpd_pn,
+ subvalue);
+ } else if (op->vpd_pn >= 0) {
+ if (hex0)
+ sgj_pr_hr(jsp, "VPD page code=0x%.2x:\n", op->vpd_pn);
+ else
+ printf("VPD page code=0x%.2x:\n", op->vpd_pn);
+ } else {
+ if (hex0)
+ sgj_pr_hr(jsp, "VPD page code=%d:\n", op->vpd_pn);
+ else
+ printf("VPD page code=%d:\n", op->vpd_pn);
+ }
}
res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, op->maxlen, op->do_quiet,
@@ -1109,6 +1089,18 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
if (op->do_raw)
dStrRaw(rp, len);
else {
+ if (json_o_hr && hex0 && (len > 0) && (len < UINT16_MAX)) {
+ char * p;
+
+ n = len * 4;
+ p = malloc(n);
+ if (p) {
+ n = hex2str(rp, len, NULL, 1, n - 1, p);
+ sgj_js_str_out(jsp, p, n);
+ }
+ } else
+ hex2stdout(rp, len, no_ascii_4hex(op));
+#if 0
if (op->do_hex > 1)
hex2stdout(rp, len, -1);
else if (VPD_ASCII_OP_DEF == op->vpd_pn)
@@ -1117,8 +1109,9 @@ svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off)
hex2stdout(rp, len, (op->do_long ? 0 : 1));
else
hex2stdout(rp, len, 0);
+#endif
}
- } else if ((! op->do_quiet) && (0 == op->examine)) {
+ } else if ((! op->do_quiet) && (! op->examine_given)) {
if (op->vpd_pn >= 0)
pr2serr("fetching VPD page code=0x%.2x: failed\n", op->vpd_pn);
else
@@ -1133,7 +1126,7 @@ recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off)
int res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(-1, op, off);
+ res = svpd_decode_vendor(-1, op, jop, off);
if (SG_LIB_CAT_OTHER == res)
svpd_unable_to_decode(-1, op, 0, off);
}
@@ -1149,6 +1142,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
bool allow_name, allow_if_found, long_notquiet, qt;
bool vpd_supported = false;
bool inhex_active = (-1 == sg_fd);
+ bool exam_not_given = ! op->examine_given;
int len, pdt, pqual, num, k, resid, alloc_len, pn, vb;
int res = 0;
sgj_state * jsp = &op->json_st;
@@ -1157,7 +1151,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
sgj_opaque_p jo2p = NULL;
const char * np;
const char * ep;
- const char * pre = (prefix ? prefix : "");;
+ const char * pre = (prefix ? prefix : "");
const char * pdt_str;
bool as_json = jsp->pr_as_json;
bool not_json = ! as_json;
@@ -1168,18 +1162,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
qt = op->do_quiet;
long_notquiet = op->do_long && (! op->do_quiet);
if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) ||
- (op->do_hex >= 3) || (op->examine > 0))
+ (op->do_hex >= 3) || op->examine_given)
allow_name = false;
else
allow_name = true;
- allow_if_found = (op->examine > 0) && (! op->do_quiet);
+ allow_if_found = op->examine_given && (! op->do_quiet);
rp = rsp_buff + off;
pn = op->vpd_pn;
if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn))
pn = rp[1];
else
pn = op->vpd_pn;
- if (!inhex_active && !op->do_force && 0 == op->examine &&
+ if (!inhex_active && !op->do_force && exam_not_given &&
pn != VPD_NOPE_WANT_STD_INQ &&
pn != VPD_SUPPORTED_VPDS) {
res = vpd_fetch_page(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt,
@@ -1251,7 +1245,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
- hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rp, len, no_ascii_4hex(op));
else {
if (vb || long_notquiet)
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
@@ -1280,7 +1274,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
- hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rp, len, no_ascii_4hex(op));
else {
if (vb || long_notquiet)
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
@@ -1307,7 +1301,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (op->do_raw)
dStrRaw(rp, len);
else if (op->do_hex)
- hex2stdout(rp, len, (1 == op->do_hex) ? 0 : -1);
+ hex2stdout(rp, len, no_ascii_4hex(op));
else {
if (vb || long_notquiet)
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
@@ -1379,17 +1373,23 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
dStrRaw(rp, len);
else {
bool protect = false;
- struct sg_simple_inquiry_resp sir;
- if ((sg_fd >= 0) && long_notquiet) {
+ op->protect_not_sure = false;
+ if (op->std_inq_a_valid)
+ protect = !! (0x1 & op->std_inq_a[5]);
+ else if ((sg_fd >= 0) && (! op->do_force)) {
+ struct sg_simple_inquiry_resp sir;
+
res = sg_simple_inquiry(sg_fd, &sir, false, vb);
if (res) {
if (op->verbose)
pr2serr("%s: sg_simple_inquiry() failed, "
"res=%d\n", __func__, res);
+ op->protect_not_sure = true;
} else
protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */
- }
+ } else
+ op->protect_not_sure = true;
if (vb || long_notquiet)
sgj_pr_hr(jsp," [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
@@ -1523,6 +1523,30 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
return 0;
}
break;
+ case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */
+ np = "CFA profile information VPD page";
+ if (allow_name)
+ sgj_pr_hr(jsp, "%s%s:\n", pre, np);
+ res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
+ if (0 == res) {
+ if (! allow_name && allow_if_found)
+ sgj_pr_hr(jsp, "%s%s\n", pre, np);
+ if (op->do_raw)
+ dStrRaw(rp, len);
+ else {
+ if (vb || long_notquiet)
+ sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
+ "%s]\n", pqual, pdt_str);
+ if (as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
+ jap = sgj_named_subarray_r(jsp, jo2p,
+ "cfa_profile_descriptor_list");
+ }
+ decode_cga_profile_vpd(rp, len, op, jap);
+ }
+ return 0;
+ }
+ break;
case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */
np = "Power consumption VPD page";
if (allow_name)
@@ -1614,7 +1638,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
jap = sgj_named_subarray_r(jsp, jo2p,
"port_information_descriptor_list");
}
- decode_proto_port_vpd(rp, len, op, jsp);
+ decode_proto_port_vpd(rp, len, op, jap);
}
return 0;
}
@@ -1694,7 +1718,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb0\n", pre);
break;
case 0xb1: /* depends on pdt */
@@ -1741,17 +1765,18 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (bdc)
decode_block_dev_ch_vpd(rp, len, op, jo2p);
else
- decode_b1_vpd(rp, len, op->do_hex, pdt);
+ decode_b1_vpd(rp, len, op, jo2p);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb1\n", pre);
break;
case 0xb2: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
bool lbpv = false;
+ bool tas = false;
switch (pdt) {
case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
@@ -1762,6 +1787,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case PDT_TAPE: case PDT_MCHANGER:
np = "TapeAlert supported flags VPD page";
ep = "(SSC)";
+ tas = true;
break;
default:
np = NULL;
@@ -1781,12 +1807,14 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
if (lbpv)
decode_block_lb_prov_vpd(rp, len, op, jo2p);
+ else if (tas)
+ decode_tapealert_supported_vpd(rp, len, op, jo2p);
else
decode_b2_vpd(rp, len, pdt, op);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb2\n", pre);
break;
case 0xb3: /* VPD page depends on pdt */
@@ -1824,11 +1852,11 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (ref)
decode_referrals_vpd(rp, len, op, jo2p);
else
- decode_b3_vpd(rp, len, pdt, op);
+ decode_b3_vpd(rp, len, op, jo2p);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb3\n", pre);
break;
case 0xb4: /* VPD page depends on pdt */
@@ -1861,25 +1889,26 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
if (vb || long_notquiet)
sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: "
"%s]\n", pqual, pdt_str);
- if (as_json) {
+ if (as_json)
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
- jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
+ if (sbl) {
+ if (as_json)
+ jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_"
"length_and_protection_types_descriptor_list");
- }
- if (sbl)
decode_sup_block_lens_vpd(rp, len, op, jap);
- else
- decode_b4_vpd(rp, len, op->do_hex, pdt);
+ } else
+ decode_b4_vpd(rp, len, op, jo2p);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb4\n", pre);
break;
case 0xb5: /* VPD page depends on pdt */
res = vpd_fetch_page(sg_fd, rp, pn, op->maxlen, qt, vb, &len);
if (0 == res) {
bool bdce = false;
+ bool lbp = false;
pdt = rp[0] & PDT_MASK;
switch (pdt) {
@@ -1891,6 +1920,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
case PDT_TAPE: case PDT_MCHANGER:
np = "Logical block protection VPD page";
ep = "(SSC)";
+ lbp = true;
break;
default:
np = NULL;
@@ -1910,12 +1940,17 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
jo2p = sg_vpd_js_hdr(jsp, jop, np, rp);
if (bdce)
decode_block_dev_char_ext_vpd(rp, len, op, jo2p);
- else
+ else if (lbp) {
+ if (as_json)
+ jap = sgj_named_subarray_r(jsp, jo2p,
+ "logical_block_protection_method_descriptor_list");
+ decode_lb_protection_vpd(rp, len, op, jap);
+ } else
decode_b5_vpd(rp, len, op->do_hex, pdt);
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb5\n", pre);
break;
case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */
@@ -1953,7 +1988,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb6\n", pre);
break;
case 0xb7:
@@ -1991,7 +2026,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb7\n", pre);
break;
case 0xb8: /* VPD_FORMAT_PRESETS */
@@ -2032,7 +2067,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb8\n", pre);
break;
case 0xb9: /* VPD_CON_POS_RANGE */
@@ -2073,7 +2108,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
}
return 0;
} else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3) &&
- (0 == op->examine))
+ exam_not_given)
printf("%sVPD page=0xb8\n", pre);
break;
default:
@@ -2129,7 +2164,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
res = svpd_decode_t10(sg_fd, op, jop, 0, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(sg_fd, op, 0);
+ res = svpd_decode_vendor(sg_fd, op, jop, 0);
if (SG_LIB_CAT_OTHER == res)
res = svpd_unable_to_decode(sg_fd, op, 0, 0);
}
@@ -2185,7 +2220,7 @@ svpd_decode_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
res = svpd_decode_t10(-1, op, jop, 0, off, NULL);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(-1, op, off);
+ res = svpd_decode_vendor(-1, op, jop, off);
if (SG_LIB_CAT_OTHER == res)
res = svpd_unable_to_decode(-1, op, 0, off);
}
@@ -2199,14 +2234,29 @@ svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
{
bool first = true;
bool got_one = false;
- int k, res;
- int max_pn = 255;
+ int k, res, start;
+ int max_pn;
int any_err = 0;
char b[80];
- if (op->vpd_pn > 0)
- max_pn = op->vpd_pn;
- for (k = op->examine > 1 ? 0 : 0x80; k <= max_pn; ++k) {
+ max_pn = (op->page_given ? op->vpd_pn : 0xff);
+ switch (op->examine) {
+ case 1:
+ start = 0x80;
+ break;
+ case 2:
+ start = 0x0;
+ break;
+ default:
+ start = 0xc0;
+ break;
+ }
+ if (start > max_pn) { /* swap them around */
+ k = start;
+ start = max_pn;
+ max_pn = k;
+ }
+ for (k = start; k <= max_pn; ++k) {
op->vpd_pn = k;
if (first)
first = false;
@@ -2220,7 +2270,7 @@ svpd_examine_all(int sg_fd, struct opts_t * op, sgj_opaque_p jop)
b[0] = '\0';
res = svpd_decode_t10(sg_fd, op, jop, 0, 0, b);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(sg_fd, op, 0);
+ res = svpd_decode_vendor(sg_fd, op, jop, 0);
if (SG_LIB_CAT_OTHER == res)
res = svpd_unable_to_decode(sg_fd, op, 0, 0);
}
@@ -2279,6 +2329,7 @@ main(int argc, char * argv[])
break;
case 'E':
++op->examine;
+ op->examine_given = true;
break;
case 'f':
op->do_force = true;
@@ -2646,7 +2697,7 @@ main(int argc, char * argv[])
else {
res = svpd_decode_t10(-1, op, jop, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(-1, op, 0);
+ res = svpd_decode_vendor(-1, op, jop, 0);
if (SG_LIB_CAT_OTHER == res)
res = svpd_unable_to_decode(-1, op, subvalue, 0);
}
@@ -2679,7 +2730,7 @@ main(int argc, char * argv[])
goto err_out;
}
- if (op->examine > 0) {
+ if (op->examine_given) {
ret = svpd_examine_all(sg_fd, op, jop);
} else if (op->do_all)
ret = svpd_decode_all(sg_fd, op, jop);
@@ -2688,7 +2739,7 @@ main(int argc, char * argv[])
res = svpd_decode_t10(sg_fd, op, jop, subvalue, 0, NULL);
if (SG_LIB_CAT_OTHER == res) {
- res = svpd_decode_vendor(sg_fd, op, 0);
+ res = svpd_decode_vendor(sg_fd, op, jop, 0);
if (SG_LIB_CAT_OTHER == res)
res = svpd_unable_to_decode(sg_fd, op, subvalue, 0);
}
diff --git a/src/sg_vpd_common.c b/src/sg_vpd_common.c
index 98e798fb..14b1bd2d 100644
--- a/src/sg_vpd_common.c
+++ b/src/sg_vpd_common.c
@@ -28,6 +28,7 @@
#endif
#include "sg_lib.h"
+#include "sg_lib_data.h"
#include "sg_cmds_basic.h"
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
@@ -47,9 +48,13 @@ static const char * const y_s = "yes";
static const char * const n_s = "no";
static const char * const nl_s = "no limit";
static const char * const nlr_s = "no limit reported";
-static const char * const nr_s = "not reported";
+/* Earlier gcc compilers (e.g. 6.4) don't accept this first form when it is
+ * used in another array of strings initialization (e.g. bdc_zoned_strs) */
+// static const char * const nr_s = "not reported";
+static char nr_s[] = "not reported";
static const char * const ns_s = "not supported";
-static const char * const rsv_s = "Reserved";
+// static const char * const rsv_s = "Reserved";
+static char rsv_s[] = "Reserved";
static const char * const vs_s = "Vendor specific";
static const char * const null_s = "";
static const char * const mn_s = "meaning";
@@ -310,13 +315,13 @@ static const char * network_service_type_arr[] =
/* VPD_MAN_NET_ADDR 0x85 ["mna"] */
void
-decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_net_man_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k, bump, na_len, assoc, nst;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p;
- uint8_t * bp;
+ const uint8_t * bp;
const char * assoc_str;
const char * nst_str;
@@ -366,7 +371,7 @@ decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_EXT_INQ Extended Inquiry VPD ["ei"] */
void
-decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
+decode_x_inq_vpd(const uint8_t * b, int len, bool protect, struct opts_t * op,
sgj_opaque_p jop)
{
bool do_long_nq = op->do_long && (! op->do_quiet);
@@ -431,6 +436,10 @@ decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
cp = "protection types 1, 2 and 3 supported";
break;
}
+ } else if (op->protect_not_sure) {
+ cp = "Unsure because unable to read PROTECT bit in standard "
+ "INQUIRY response";
+ d[0] = '\0';
} else {
cp = "none";
d[0] = '\0';
@@ -620,7 +629,7 @@ decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
/* VPD_SOFTW_INF_ID 0x84 */
void
-decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op,
+decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
sgj_state * jsp = &op->json_st;
@@ -654,13 +663,13 @@ static const char * mode_page_policy_arr[] =
/* VPD_MODE_PG_POLICY 0x87 ["mpp"] */
void
-decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k, n, bump, ppc, pspc;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p;
- uint8_t * bp;
+ const uint8_t * bp;
char b[128];
static const int blen = sizeof(b);
@@ -712,7 +721,7 @@ decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_POWER_CONDITION 0x8a ["pc"] */
void
-decode_power_condition(uint8_t * buff, int len, struct opts_t * op,
+decode_power_condition(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop)
{
sgj_state * jsp = &op->json_st;
@@ -884,13 +893,13 @@ decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
/* VPD_SCSI_FEATURE_SETS 0x92 ["sfs"] */
void
-decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k, bump;
uint16_t sf_code;
bool found;
- uint8_t * bp;
+ const uint8_t * bp;
sgj_opaque_p jo2p;
sgj_state * jsp = &op->json_st;
char b[256];
@@ -1061,6 +1070,38 @@ decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op,
} /* end Constituent descriptor loop */
}
+/* VPD_CFA_PROFILE_INFO 0x8c ["cfa"] */
+void
+decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k;
+ uint32_t u;
+ sgj_state * jsp = &op->json_st;
+ const uint8_t * bp;
+ sgj_opaque_p jo2p;
+
+ if (op->do_hex) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 4) {
+ pr2serr("VPD page length too short=%d\n", len);
+ return;
+ }
+ len -= 4;
+ bp = buff + 4;
+ for (k = 0; k < len; k += 4, bp += 4) {
+ jo2p = sgj_new_unattached_object_r(jsp);
+ sgj_haj_vi(jsp, jo2p, 0, "CGA profile supported",
+ SGJ_SEP_COLON_1_SPACE, bp[0], true);
+ u = sg_get_unaligned_be16(bp + 2);
+ sgj_haj_vi_nex(jsp, jo2p, 2, "Sequential write data size",
+ SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB");
+ sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+}
+
/* Assume index is less than 16 */
static const char * sg_ansi_version_arr[16] =
{
@@ -1205,14 +1246,14 @@ static const char * power_unit_arr[] =
/* VPD_POWER_CONSUMPTION 0x8d ["psm"] */
void
-decode_power_consumption(uint8_t * buff, int len, struct opts_t * op,
+decode_power_consumption(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k, bump, pcmp_id, pcmp_unit;
unsigned int pcmp_val;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p;
- uint8_t * bp;
+ const uint8_t * bp;
char b[128];
static const int blen = sizeof(b);
static const char * pcmp = "power_consumption";
@@ -1590,7 +1631,7 @@ static const char * prov_type_arr[8] = {
/* VPD_LB_PROVISIONING 0xb2 ["lbpv"] */
int
-decode_block_lb_prov_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_block_lb_prov_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop)
{
unsigned int u, dp, pt, t_exp;
@@ -1678,7 +1719,7 @@ decode_block_lb_prov_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_REFERRALS 0xb3 ["ref"] */
void
-decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop)
{
uint32_t u;
@@ -1703,12 +1744,12 @@ decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_SUP_BLOCK_LENS 0xb4 ["sbl"] (added sbc4r01) */
void
-decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_sup_block_lens_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k;
unsigned int u;
- uint8_t * bp;
+ const uint8_t * bp;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p = NULL;
@@ -1750,8 +1791,8 @@ decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_BLOCK_DEV_C_EXTENS 0xb5 ["bdce"] (added sbc4r02) */
void
-decode_block_dev_char_ext_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jop)
+decode_block_dev_char_ext_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jop)
{
bool b_active = false;
bool combined = false;
@@ -1838,8 +1879,8 @@ decode_block_dev_char_ext_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_ZBC_DEV_CHARS 0xb6 ["zdbch"] sbc or zbc [zbc2r04] */
void
-decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jop)
+decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jop)
{
uint32_t u, pdt;
sgj_state * jsp = &op->json_st;
@@ -1923,7 +1964,7 @@ decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_BLOCK_LIMITS_EXT 0xb7 ["ble"] SBC */
void
-decode_block_limits_ext_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_block_limits_ext_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop)
{
uint32_t u;
@@ -2000,7 +2041,7 @@ get_zone_align_method(uint8_t val, char * b, int blen)
/* VPD_FORMAT_PRESETS 0xb8 ["fp"] (added sbc4r18) */
void
-decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_format_presets_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
uint8_t sch_type;
@@ -2008,7 +2049,7 @@ decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op,
uint32_t u;
uint64_t ul;
sgj_state * jsp = &op->json_st;
- uint8_t * bp;
+ const uint8_t * bp;
sgj_opaque_p jo2p, jo3p;
const char * cp;
char b[128];
@@ -2149,13 +2190,13 @@ decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op,
/* VPD_CON_POS_RANGE 0xb9 (added sbc5r01) */
void
-decode_con_pos_range_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_con_pos_range_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k;
uint32_t u;
sgj_state * jsp = &op->json_st;
- uint8_t * bp;
+ const uint8_t * bp;
sgj_opaque_p jo2p;
if (op->do_hex) {
@@ -2426,8 +2467,8 @@ get_tpc_desc_type_s(uint32_t desc_type)
/* VPD_3PARTY_COPY 3PC, third party copy 0x8f ["tpc"] */
void
-decode_3party_copy_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap)
+decode_3party_copy_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap)
{
int j, k, m, bump, desc_type, desc_len, sa_len, pdt;
uint32_t u, v;
@@ -2726,11 +2767,11 @@ skip:
/* VPD_PROTO_LU 0x90 ["pslu"] */
void
-decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
int k, bump, rel_port, desc_len, proto;
- uint8_t * bp;
+ const uint8_t * bp;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p = NULL;
char b[128];
@@ -2764,10 +2805,10 @@ decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op,
return;
}
if (0 == desc_len)
- goto again;;
+ goto again;
if (2 == op->do_hex) {
hex2stdout(bp + 8, desc_len, 1);
- goto again;;
+ goto again;
}
switch (proto) {
case TPROTO_SAS:
@@ -2786,13 +2827,13 @@ again:
/* VPD_PROTO_PORT 0x91 ["pspo"] */
void
-decode_proto_port_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap)
{
bool pds, ssp_pers;
int k, j, bump, rel_port, desc_len, proto, phy;
- uint8_t * bp;
- uint8_t * pidp;
+ const uint8_t * bp;
+ const uint8_t * pidp;
sgj_state * jsp = &op->json_st;
sgj_opaque_p jo2p = NULL;
sgj_opaque_p ja2p = NULL;
@@ -2862,3 +2903,91 @@ again:
sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
}
}
+
+/* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */
+void
+decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap)
+{
+ int k, bump;
+ const uint8_t * bp;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p = NULL;
+
+ if ((1 == op->do_hex) || (op->do_hex > 2)) {
+ hex2stdout(buff, len, (1 == op->do_hex) ? 0 : -1);
+ return;
+ }
+ if (len < 8) {
+ pr2serr("VPD page length too short=%d\n", len);
+ return;
+ }
+ len -= 8;
+ bp = buff + 8;
+ for (k = 0; k < len; k += bump, bp += bump) {
+ jo2p = sgj_new_unattached_object_r(jsp);
+ bump = 1 + bp[0];
+ sgj_pr_hr(jsp, " method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, "
+ "RBDP_C=%d\n", bp[1], 0x3f & bp[2], !!(0x80 & bp[3]),
+ !!(0x40 & bp[3]), !!(0x20 & bp[3]));
+ sgj_js_nv_ihex(jsp, jo2p, "logical_block_protection_method", bp[1]);
+ sgj_js_nv_ihex_nex(jsp, jo2p,
+ "logical_block_protection_information_length",
+ 0x3f & bp[2], true, "unit: byte");
+ sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_w_c", !!(0x80 & bp[3]), false,
+ "Logical Blocks Protected during Write supported");
+ sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_r_c", !!(0x40 & bp[3]), false,
+ "Logical Blocks Protected during Read supported");
+ sgj_js_nv_ihex_nex(jsp, jo2p, "rbdp_c", !!(0x20 & bp[3]), false,
+ "Recover Buffered Data Protected supported");
+ if ((k + bump) > len) {
+ pr2serr("Logical block protection VPD page, short "
+ "descriptor length=%d, left=%d\n", bump, (len - k));
+ sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
+ return;
+ }
+ sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+}
+
+/* VPD_TA_SUPPORTED 0xb2 ["tas"] */
+void
+decode_tapealert_supported_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jop)
+{
+ bool have_ta_strs = !! sg_lib_tapealert_strs[0];
+ int k, mod, div, n;
+ unsigned int supp;
+ sgj_state * jsp = &op->json_st;
+ char b[144];
+ char d[64];
+ static const int blen = sizeof(b);
+
+ if (len < 12) {
+ pr2serr("VPD page length too short=%d\n", len);
+ return;
+ }
+ b[0] ='\0';
+ for (k = 1, n = 0; k < 0x41; ++k) {
+ mod = ((k - 1) % 8);
+ div = (k - 1) / 8;
+ supp = !! (buff[4 + div] & (1 << (7 - mod)));
+ if (jsp->pr_as_json) {
+ snprintf(d, sizeof(d), "flag%02xh", k);
+ if (have_ta_strs)
+ sgj_js_nv_ihex_nex(jsp, jop, d, supp, false,
+ sg_lib_tapealert_strs[k]);
+ else
+ sgj_js_nv_i(jsp, jop, d, supp);
+ }
+ if (0 == mod) {
+ if (div > 0) {
+ sgj_pr_hr(jsp, "%s\n", b);
+ n = 0;
+ }
+ n += sg_scnpr(b + n, blen - n, " Flag%02Xh: %d", k, supp);
+ } else
+ n += sg_scnpr(b + n, blen - n, " %02Xh: %d", k, supp);
+ }
+ sgj_pr_hr(jsp, "%s\n", b);
+}
diff --git a/src/sg_vpd_common.h b/src/sg_vpd_common.h
index 722da1fd..50cdb48a 100644
--- a/src/sg_vpd_common.h
+++ b/src/sg_vpd_common.h
@@ -136,8 +136,10 @@ struct opts_t {
bool do_force; /* sg_inq + sg_vpd */
bool do_only; /* sg_inq: --only after stdinq: don't fetch VPD page 0x80 */
bool do_quiet; /* sg_vpd */
+ bool examine_given; /* sg_vpd */
bool page_given; /* sg_inq + sg_vpd */
bool possible_nvme; /* sg_inq */
+ bool protect_not_sure; /* sg_vpd */
bool verbose_given; /* sg_inq + sg_vpd */
bool version_given; /* sg_inq + sg_vpd */
bool do_vpd; /* sg_inq */
@@ -189,62 +191,71 @@ typedef int (*recurse_vpd_decodep)(struct opts_t *, sgj_opaque_p jop, int off);
sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop,
const char * name, const uint8_t * vpd_hdrp);
-void decode_net_man_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_net_man_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
-void decode_x_inq_vpd(uint8_t * b, int len, bool protect, struct opts_t * op,
- sgj_opaque_p jop);
-void decode_softw_inf_id(uint8_t * buff, int len, struct opts_t * op,
+void decode_x_inq_vpd(const uint8_t * b, int len, bool protect,
+ struct opts_t * op, sgj_opaque_p jop);
+void decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
-void decode_mode_policy_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
-void decode_power_condition(uint8_t * buff, int len, struct opts_t * op,
+void decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+void decode_power_condition(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop);
int filter_json_dev_ids(uint8_t * buff, int len, int m_assoc,
struct opts_t * op, sgj_opaque_p jap);
void decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop);
-void decode_feature_sets_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
void decode_dev_constit_vpd(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jap,
recurse_vpd_decodep fp);
sgj_opaque_p std_inq_decode_js(const uint8_t * b, int len,
struct opts_t * op, sgj_opaque_p jop);
-void decode_power_consumption(uint8_t * buff, int len,
+void decode_power_consumption(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jap);
void decode_block_limits_vpd(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jop);
void decode_block_dev_ch_vpd(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jop);
-int decode_block_lb_prov_vpd(uint8_t * buff, int len,
+int decode_block_lb_prov_vpd(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jop);
-void decode_referrals_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop);
-void decode_sup_block_lens_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap);
-void decode_block_dev_char_ext_vpd(uint8_t * buff, int len,
+void decode_sup_block_lens_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap);
+void decode_block_dev_char_ext_vpd(const uint8_t * buff, int len,
struct opts_t * op, sgj_opaque_p jop);
-void decode_zbdch_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jop);
-void decode_block_limits_ext_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jop);
-void decode_format_presets_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap);
-void decode_con_pos_range_vpd(uint8_t * buff, int len, struct opts_t * op,
- sgj_opaque_p jap);
-void decode_3party_copy_vpd(uint8_t * buff, int len, struct opts_t * op,
+void decode_block_limits_ext_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jop);
+void decode_format_presets_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap);
+void decode_con_pos_range_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jap);
+void decode_3party_copy_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
void
-decode_proto_lu_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
void
-decode_proto_port_vpd(uint8_t * buff, int len, struct opts_t * op,
+decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op,
sgj_opaque_p jap);
+void
+decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op,
+ sgj_opaque_p jap);
+void
+decode_tapealert_supported_vpd(const uint8_t * buff, int len,
+ struct opts_t * op, sgj_opaque_p jop);
const char * pqual_str(int pqual);
void svpd_enumerate_vendor(int vend_prod_num);
int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num);
-int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off);
+int svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop,
+ int off);
const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap);
int svpd_find_vp_num_by_acron(const char * vp_ap);
const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num,
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index 23df1442..5cfc7ee3 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -92,10 +92,6 @@
#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 */
-#endif
-
#define DEF_ALLOC_LEN 252
#define MX_ALLOC_LEN (0xc000 + 0x80)
@@ -115,6 +111,17 @@ dup_sanity_chk(int sz_opts_t, int sz_values_name_t)
sz_values_name_t);
}
+static int
+no_ascii_4hex(const struct opts_t * op)
+{
+ if (op->do_hex < 2)
+ return 1;
+ else if (2 == op->do_hex)
+ return 0;
+ else
+ return -1;
+}
+
static bool
is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp)
{
@@ -1227,15 +1234,20 @@ decode_vpd_d2_hit(uint8_t * b, int blen)
/* Returns 0 if successful, see sg_ll_inquiry() plus SG_LIB_CAT_OTHER for
unsupported page */
int
-svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
+svpd_decode_vendor(int sg_fd, struct opts_t * op, sgj_opaque_p jop, int off)
{
- int len, res;
- char name[64];
- const struct svpd_values_name_t * vnp;
+ bool hex0 = (0 == op->do_hex);
+ int len, pdt, plen, pn;
int alloc_len = op->maxlen;
+ int res = 0;
+ const struct svpd_values_name_t * vnp;
+ sgj_state * jsp = &op->json_st;
+ sgj_opaque_p jo2p;
uint8_t * rp;
+ char name[80];
- switch (op->vpd_pn) {
+ pn = op->vpd_pn;
+ switch (pn) { /* VPD codes that we support vendor pages for */
case 0x3:
case 0xc0:
case 0xc1:
@@ -1249,6 +1261,7 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
case 0xd0:
case 0xd1:
case 0xd2:
+ case 0xde:
break;
default: /* not known so return prior to fetching page */
return SG_LIB_CAT_OTHER;
@@ -1258,135 +1271,195 @@ svpd_decode_vendor(int sg_fd, struct opts_t * op, int off)
if (0 == alloc_len)
alloc_len = DEF_ALLOC_LEN;
}
- res = vpd_fetch_page(sg_fd, rp, op->vpd_pn, alloc_len, op->do_quiet,
- op->verbose, &len);
- if (0 == res) {
- vnp = svpd_get_v_detail(op->vpd_pn, op->vend_prod_num, 0xf & rp[0]);
- if (vnp && vnp->name)
- snprintf(name, sizeof(name), "%s", vnp->name);
- else
- snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x",
- op->vpd_pn);
- if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 2))
- printf("%s VPD Page:\n", name);
- if (op->do_raw)
- dStrRaw(rp, len);
- else if (op->do_hex)
- 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);
- else if (VPD_VP_EMC == op->vend_prod_num)
- decode_upr_vpd_c0_emc(rp, len);
- else if (VPD_VP_HP3PAR == op->vend_prod_num)
- decode_vpd_c0_hp3par(rp, len);
- else if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c0(rp, len);
- else if (VPD_VP_DDS == op->vend_prod_num)
- decode_dds_vpd_c0(rp, len);
- else if (VPD_VP_IBM_LTO == op->vend_prod_num)
- decode_ibm_lto_dcrl(rp, len);
- else if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc1:
- if (VPD_VP_SEAGATE == op->vend_prod_num)
- decode_date_code_vpd_c1_sea(rp, len);
- else if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c1(rp, len);
- else if (VPD_VP_IBM_LTO == op->vend_prod_num)
- decode_ibm_lto_dsn(rp, len);
- else if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc2:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c2(rp, len);
- else if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc3:
- if (VPD_VP_SEAGATE == op->vend_prod_num)
- decode_dev_beh_vpd_c3_sea(rp, len);
- else if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c3(rp, len);
- else if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc4:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c4(rp, len);
- else if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc5:
- if (VPD_VP_HP_LTO == op->vend_prod_num)
- decode_hp_lto_vpd_cx(rp, len, op->vpd_pn);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc8:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c8(rp, len);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xc9:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_c9(rp, len);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xca:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_ca(rp, len);
- else
- hex2stdout(rp, len, 0);
- break;
- case 0xd0:
- if (VPD_VP_RDAC == op->vend_prod_num)
- decode_rdac_vpd_d0(rp, len);
- 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);
+ res = vpd_fetch_page(sg_fd, rp, pn, alloc_len, op->do_quiet, op->verbose,
+ &len);
+ if (res) {
+ pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn);
+ return res;
+ }
+ pdt = rp[0] & PDT_MASK;
+ vnp = svpd_get_v_detail(pn, op->vend_prod_num, pdt);
+ if (vnp && vnp->name)
+ snprintf(name, sizeof(name), "%s", vnp->name);
+ else
+ snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", pn);
+ if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3))
+ sgj_pr_hr(jsp, "%s VPD Page:\n", name);
+ if (op->do_raw)
+ dStrRaw(rp, len);
+ else {
+ switch(pn) {
+ case 0x3:
+ if (hex0 && (VPD_VP_WDC_HITACHI == op->vend_prod_num))
+ decode_vpd_3_hit(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc0:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_SEAGATE == op->vend_prod_num)
+ decode_firm_vpd_c0_sea(rp, len);
+ else if (VPD_VP_EMC == op->vend_prod_num)
+ decode_upr_vpd_c0_emc(rp, len);
+ else if (VPD_VP_HP3PAR == op->vend_prod_num)
+ decode_vpd_c0_hp3par(rp, len);
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c0(rp, len);
+ else if (VPD_VP_DDS == op->vend_prod_num)
+ decode_dds_vpd_c0(rp, len);
+ else if (VPD_VP_IBM_LTO == op->vend_prod_num)
+ decode_ibm_lto_dcrl(rp, len);
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc1:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_SEAGATE == op->vend_prod_num)
+ decode_date_code_vpd_c1_sea(rp, len);
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c1(rp, len);
+ else if (VPD_VP_IBM_LTO == op->vend_prod_num)
+ decode_ibm_lto_dsn(rp, len);
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc2:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c2(rp, len);
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc3:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_SEAGATE == op->vend_prod_num)
+ decode_dev_beh_vpd_c3_sea(rp, len);
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c3(rp, len);
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc4:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c4(rp, len);
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc5:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_HP_LTO == op->vend_prod_num)
+ decode_hp_lto_vpd_cx(rp, len, pn);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc8:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c8(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xc9:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_c9(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xca:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_ca(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xd0:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_RDAC == op->vend_prod_num)
+ decode_rdac_vpd_d0(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xd1:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_WDC_HITACHI == op->vend_prod_num)
+ decode_vpd_d1_hit(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case 0xd2:
+ if (! hex0)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (VPD_VP_WDC_HITACHI == op->vend_prod_num)
+ decode_vpd_d2_hit(rp, len);
+ else
+ res = SG_LIB_CAT_OTHER;
+ break;
+ case SG_NVME_VPD_NICR: /* 0xde */
+ if (VPD_VP_SG != op->vend_prod_num) {
+ res = SG_LIB_CAT_OTHER;
+ break;
+ }
+ /* NVMe: Identify Controller data structure (CNS 01h) */
+ plen = sg_get_unaligned_be16(rp + 2) + 4;
+ if (plen > len) { /* fetch the whole page */
+ res = vpd_fetch_page(sg_fd, rp, pn, plen,
+ op->do_quiet, op->verbose, &len);
+ if (res) {
+ pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn);
+ return res;
+ }
+ }
+ if (len < 16) {
+ pr2serr("%s expected to be > 15 bytes long (got: %d)\n",
+ name, len);
+ break;
+ } else {
+ int n = len - 16;
+
+ if (n > 4096) {
+ pr2serr("NVMe Identify response expected to be "
+ "<= 4096 bytes (got: %d)\n", n);
break;
- default:
- pr2serr("%s: logic error, should know can't decode "
- "pn=0x%x\n", __func__, op->vpd_pn);
- return SG_LIB_CAT_OTHER;
+ }
+ if (op->do_hex)
+ hex2stdout(rp, len, no_ascii_4hex(op));
+ else if (jsp->pr_as_json) {
+ jo2p = sg_vpd_js_hdr(jsp, jop, name, rp);
+ sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes",
+ rp + 16, n);
+ } else
+ hex2stdout(rp + 16, n, 1);
}
- return 0;
+ break;
+ default:
+ res = SG_LIB_CAT_OTHER;
}
- } else
- pr2serr("Vendor VPD page=0x%x failed to fetch\n", op->vpd_pn);
+ }
+ if (res && op->verbose)
+ pr2serr("%s: can't decode pn=0x%x, vend_prod_num=%d\n", __func__,
+ pn, op->vend_prod_num);
return res;
}
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index 60d25aa8..0d7d2e1b 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -84,7 +84,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "4.22 20220118";
+static const char * version_str = "4.23 20220815";
static const char * my_name = "sgs_dd";
#ifndef SGV4_FLAG_HIPRI
@@ -1415,7 +1415,7 @@ main(int argc, char * argv[])
return 1;
}
if (clp->iflag.mmap && clp->oflag.mmap)
- clp->both_mmap = true;;
+ clp->both_mmap = true;
if (clp->debug > 3)
pr2serr("%s: if=%s skip=%d of=%s seek=%d count=%d\n", my_name,