aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg_read_buffer.894
-rw-r--r--lib/sg_lib.c28
-rw-r--r--lib/sg_lib_data.c52
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_inq.c39
-rw-r--r--src/sg_read_buffer.c449
-rw-r--r--src/sg_vpd.c10
-rw-r--r--src/sg_vpd_vendor.c17
-rw-r--r--src/sg_write_x.c5
-rw-r--r--src/sg_z_act_query.c5
12 files changed, 449 insertions, 259 deletions
diff --git a/ChangeLog b/ChangeLog
index 0483870a..eb4dad38 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 [20220211] [svn: r937]
+Changelog for pre-release sg3_utils-1.48 [20220217] [svn: r938]
- sg_z_act_query: new utility for sending either a
Zone activate or Zone query command
- sg_rep_density: new utility for decoding the response of
@@ -25,8 +25,11 @@ Changelog for pre-release sg3_utils-1.48 [20220211] [svn: r937]
- for short binary fields, remove address (index) from
the left hand side of each line of hex
- sg_modes: improve handling of zbc disks with pdt=0x14
+ - sg_inq, sg_vpd: Device Identication VPD page, change
+ "IEEE Company_id" to "AOI" as per spc6r06.pdf
- sg_opcodes: cleanup error reporting
- sg_format: allow disk formats on ZBC (zoned) disks
+ - sg_read_buffer: add --eh_code= and --no_output options
- sg_lib: add sg_pdt_s_eq() to cope with ZBC disks which may
be either PDT_ZBC (if host managed) or PDT_DISK
- cleanup masks for PDT [0x1f] and group_number [0x3f]
diff --git a/debian/changelog b/debian/changelog
index 7867ee7f..f427b240 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.48-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Wed, 02 Feb 2022 11:00:00 -0500
+ -- Douglas Gilbert <dgilbert@interlog.com> Thu, 17 Feb 2022 23:00:00 -0500
sg3-utils (1.47-0.1) unstable; urgency=low
diff --git a/doc/sg_read_buffer.8 b/doc/sg_read_buffer.8
index d1aed04b..09e39414 100644
--- a/doc/sg_read_buffer.8
+++ b/doc/sg_read_buffer.8
@@ -1,30 +1,48 @@
-.TH SG_READ_BUFFER "8" "May 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG_READ_BUFFER "8" "February 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_read_buffer \- send SCSI READ BUFFER command
.SH SYNOPSIS
.B sg_read_buffer
-[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-inhex=FN\fR]
-[\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR]
-[\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-specific=MS\fR]
-[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+[\fI\-\-eh_code=EHC\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR]
+[\fI\-\-inhex=FN\fR] [\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR]
+[\fI\-\-no_output\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR]
+[\fI\-\-readonly\fR] [\fI\-\-specific=MS\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Sends a SCSI READ BUFFER command to the \fIDEVICE\fR, and if there
-is a response either decodes it, prints it in hexadecimal or sends
-it in binary to stdout. If a response is received for a "descriptor"
-mode then, in the absence of \fI\-\-hex\fR and \fI\-\-raw\fR, it is
-decoded. Response for non\-descriptor modes are output in hexadecimal
-unless the \fI\-\-raw\fR option is given.
+Sends a SCSI READ BUFFER command to the \fIDEVICE\fR, and if there is a
+response either decodes it, prints it in hexadecimal or sends it in binary to
+stdout. If a response is received for a "descriptor" mode then, in the absence
+of \fI\-\-hex\fR and \fI\-\-raw\fR, it is decoded. Response for
+non\-descriptor modes are output in hexadecimal unless the \fI\-\-raw\fR
+option is given.
+.PP
+The responses to the Read microcode status ('rd_microc_st' [0xf]) and Error
+history ('err_hist' [0x1c]) modes are decoded as described in spc6r06.pdf and
+earlier T10 documents.
.PP
This utility may be called without a \fIDEVICE\fR but with a
-\fI\-\-inhex=FN\fR option instead. \fIFN\fR is expected to be a file
-name (or '\-' for stdin). The contents of the file (or stdin stream)
-is assumed to be hexadecimal (or binary) data that represents a SCSI
-READ BUFFER command response and is decoded as such.
+\fI\-\-inhex=FN\fR option instead. \fIFN\fR is expected to be a file name (or
+ '\-' for stdin). The contents of the file (or stdin stream) is assumed to be
+hexadecimal (or binary) data that represents a SCSI READ BUFFER command
+response and is decoded as such.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
.TP
+\fB\-e\fR, \fB\-\-eh_code\fR=\fIEHC\fR
+\fIEHC\fR is the error history code placed in the Buffer ID field of the cdb.
+The Mode field is set to err_hist [0x1c]. The option is equivalent to using
+the '\fI\-\-mode=eh\fR \fI\-\-id=EHC\fR' options. If this option and one of
+the other options is given, then an error will be generated if they
+contradict. The default (maximum) response length is increased to 64 bytes
+when may need to be increased (if so that is noted if the output is
+truncated).
+.br
+An example is setting \fIEHC\fR to 0 in which case the error history
+directory will be decoded (unless \fI\-\-hex\fR or \fI\-\-raw\fR options
+is given).
+.TP
\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit. If used multiple times also prints
the mode names and their acronyms.
@@ -32,26 +50,34 @@ the mode names and their acronyms.
\fB\-H\fR, \fB\-\-hex\fR
output the response in hexadecimal. When given twice the response is
output in hex with the corresponding representation in ASCII to the
-right of each line.
+right of each line. When given three time the hex is printed without
+addresses (indexes) at the start of each line; this type of format is
+suitable for the \fI\-\-inhex=FN\fR option on a subsequent invocation.
.TP
\fB\-i\fR, \fB\-\-id\fR=\fIID\fR
-this option sets the buffer id field in the cdb. \fIID\fR is a value between
-0 (default) and 255 inclusive.
+this option sets the Buffer ID field in the cdb. \fIID\fR is a value between
+0 (default) and 255 inclusive. The meaning of the Buffer ID field varies
+with the value in the Mode field of the cdb.
.TP
\fB\-I\fR, \fB\-\-inhex\fR=\fIFN\fR
\fIFN\fR is expected to be a file name (or '\-' for stdin) which contains
ASCII hexadecimal or binary representing a READ BUFFER response. If known
-this utility will then decode that response. It is preferable to also
-supply the \fI\-\-mode=MO\fR and \fI\-\-specific=MS\fR options, since these
-are not present in the response. The hexadecimal should be arranged as 1 or
-2 digits representing a byte each of which is whitespace or comma separated.
-Anything from and including a hash mark to the end of line is ignored. If the
-\fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary.
+this utility will then decode that response. It is preferable to also supply
+the \fI\-\-mode=MO\fR, \fI\-\-id=ID\fR and possible \fI\-\-specific=MS\fR
+options, since these are not present in the response. See the "FORMAT OF
+FILES CONTAINING ASCII HEX" section in the sg3_utils manpage for more
+information. If the \fI\-\-raw\fR option is also given then the contents
+of \fIFN\fR is treated as binary.
.TP
\fB\-l\fR, \fB\-\-length\fR=\fILEN\fR
where \fILEN\fR is the length, in bytes, that is placed in the "allocation
-length" field in the cdb. The default value is 4 (bytes). The device may
+length" field in the cdb. The default value is 4 (bytes) which is increased
+to 64 if the 'err_hist' mode [0x1c] is given or implied. The device may
respond with less bytes.
+.br
+If the \fI\-\-inhex=FN\fR option is given, then the default value of the
+length is increased to 8192 bytes. This length may then be reduced to match
+the number of bytes decoded from the contents of \fIFN\fR.
.TP
\fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR
this option sets the mode field in the cdb. \fIMO\fR is a value between
@@ -60,12 +86,23 @@ See the MODES section below. To list the available mode abbreviations use
an invalid one (e.g. '\-\-mode=xxx'). As an example, to fetch the read
buffer descriptor give '\-\-mode=desc' .
.TP
+\fB\-N\fR, \fB\-\-no_output\fR
+when this option is given after sending the SCSI command to the \fIDEVICE\fR
+the response is processed, looking for any errors, and then this utility
+exits. Any data read by the READ BUFFER command is ignored.
+.br
+May be useful for timing larger reads from the \fIDEVICE\fR buffer in 'data'
+mode [0x2].
+.TP
\fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR
this option sets the buffer offset field in the cdb. \fIOFF\fR is a value
between 0 (default) and 2**24\-1 . It is a byte offset.
.TP
\fB\-r\fR, \fB\-\-raw\fR
-if a response is received then it is sent in binary to stdout.
+if a response is received then it is sent in binary to stdout. When this
+option is given together with \fI\-\-inhex=FN\fR then the contents of
+\fIFN\fR is assumed to be binary and the output of this utility is
+normal ASCII (i.e. _not_ in binary).
.TP
\fB\-R\fR, \fB\-\-readonly\fR
open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag).
@@ -115,8 +152,9 @@ en_ex [26, 0x1a]
Enable expander communications protocol and Echo buffer. Made obsolete in
SPC\-4.
.TP
-err_hist [28, 0x1c]
-Error history. Introduced in SPC\-4.
+err_hist|eh [28, 0x1c]
+Error history. Either 'err_hist' or the short 'eh' abbreviation can be used
+for this mode. Introduced in SPC\-4.
.SH NOTES
All numbers given with options are assumed to be decimal.
Alternatively numerical values can be given in hexadecimal preceded by
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index f7029cad..e504e6b8 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -954,8 +954,8 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
{
int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa;
int vsi, k, n, dlen;
+ uint64_t ccc_id, vsei;
const uint8_t * ip;
- uint64_t vsei;
char e[64];
const char * cp;
@@ -1061,17 +1061,9 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
break;
}
- c_id = sg_get_unaligned_be24(ip + ci_off);
- n += sg_scnpr(b + n, blen - n, "%s IEEE Company_id: 0x%x\n", lip,
- c_id);
- vsei = 0;
- for (m = 0; m < 5; ++m) {
- if (m > 0)
- vsei <<= 8;
- vsei |= ip[ci_off + 3 + m];
- }
- n += sg_scnpr(b + n, blen - n, "%s Vendor Specific Extension "
- "Identifier: 0x%" PRIx64 "\n", lip, vsei);
+ ccc_id = sg_get_unaligned_be64(ip + ci_off);
+ n += sg_scnpr(b + n, blen - n, "%s IEEE identifier: 0x%"
+ PRIx64 "x\n", lip, ccc_id);
if (12 == dlen) {
d_id = sg_get_unaligned_be32(ip + 8);
n += sg_scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n",
@@ -1100,8 +1092,8 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
if (do_long) {
n += sg_scnpr(b + n, blen - n, "%s NAA 2, vendor "
"specific identifier A: 0x%x\n", lip, d_id);
- n += sg_scnpr(b + n, blen - n, "%s IEEE Company_id: "
- "0x%x\n", lip, c_id);
+ n += sg_scnpr(b + n, blen - n, "%s AOI: 0x%x\n", lip,
+ c_id);
n += sg_scnpr(b + n, blen - n, "%s vendor specific "
"identifier B: 0x%x\n", lip, vsi);
n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
@@ -1144,8 +1136,8 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
vsei |= ip[3 + m];
}
if (do_long) {
- n += sg_scnpr(b + n, blen - n, "%s NAA 5, IEEE "
- "Company_id: 0x%x\n", lip, c_id);
+ n += sg_scnpr(b + n, blen - n, "%s NAA 5, AOI: 0x%x\n",
+ lip, c_id);
n += sg_scnpr(b + n, blen - n, "%s Vendor Specific "
"Identifier: 0x%" PRIx64 "\n", lip, vsei);
n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
@@ -1174,8 +1166,8 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
vsei |= ip[3 + m];
}
if (do_long) {
- n += sg_scnpr(b + n, blen - n, "%s NAA 6, IEEE "
- "Company_id: 0x%x\n", lip, c_id);
+ n += sg_scnpr(b + n, blen - n, "%s NAA 6, AOI: 0x%x\n",
+ lip, c_id);
n += sg_scnpr(b + n, blen - n, "%s Vendor Specific "
"Identifier: 0x%" PRIx64 "\n", lip, vsei);
vsei = sg_get_unaligned_be64(ip + 8);
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 15798fe3..a7970f2a 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.85 20220127";
+const char * sg_lib_version_str = "2.87 20220217";
/* spc6r06, sbc5r01, zbc2r12 */
@@ -257,6 +257,7 @@ struct sg_lib_value_name_t sg_lib_read_buff_arr[] = {
{0x3, PDT_ALL, "descriptor"},
{0xa, PDT_ALL, "read data from echo buffer"},
{0xb, PDT_ALL, "echo buffer descriptor"},
+ {0xf, PDT_ALL, "read microcode status"}, /* added in spc5r20 */
{0x1a, PDT_ALL, "enable expander comms protocol and echo buffer"},
{0x1c, PDT_ALL, "error history"},
{0xffff, 0, NULL},
@@ -1625,7 +1626,7 @@ struct sg_lib_simple_value_name_t sg_lib_nvme_nvm_cmd_arr[] =
/* .value is completion queue's DW3 as follows: ((DW3 >> 17) & 0x3ff)
* .peri_dev_type is an index for the sg_lib_scsi_status_sense_arr[]
* .name is taken from NVMe 1.3a document, section 4.6.1.2.1 with less
- * capitalization.
+ * capitalization.
* NVMe term bits 31:17 of DW3 in the completion field as the "Status
* Field" (SF). Bit 31 is "Do not retry" (DNR) and bit 30 is "More" (M).
* Bits 29:28 are reserved, bit 27:25 are the "Status Code Type" (SCT)
@@ -1674,14 +1675,31 @@ struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] =
{0x20, 18, "Namespace is write protected"}, /* NVMe 1.4 */
{0x21, 6, "Command interrupted"}, /* NVMe 1.4 */
{0x22, 5, "Transient transport error"}, /* NVMe 1.4 */
+ {0x23, 5, "Prohibited by lockdown"}, /* NVMe 2.0 */
+ {0x24, 5, "Admin command: media not ready"}, /* NVMe 2.0 */
/* 0x80 - 0xbf: I/O command set specific */
- /* Generic command status values, NVM (I/O) Command Set */
+ /* Command specific status values, NVM (I/O) Command Set */
{0x80, 12, "LBA out of range"},
{0x81, 3, "Capacity exceeded"},
{0x82, 13, "Namespace not ready"},
{0x83, 14, "Reservation conflict"},
{0x84, 15, "Format in progress"},
+ {0x85, 2, "Invalid value size"},
+ {0x86, 2, "Invalid key size"},
+ {0x87, 2, "KV key does not exist"},
+ {0x88, 15, "Unrecovered error"},
+ {0x89, 2, "Key exists"},
+
+ /* Command specific status values, ZNS (NVM) Command Set */
+ {0xb8, 0x1f, "Zone boundary error"},
+ {0xb9, 0x2, "Zone is full"},
+ {0xba, 0x1b, "Zone is read only"},
+ {0xbb, 0x1c, "Zone is offline"},
+ {0xbc, 2, "Zone invalid write"},
+ {0xbd, 0x20, "Too many active zones"},
+ {0xbe, 0x20, "Too many open zones"},
+ {0xbf, 2, "Invalid zone state transition"},
/* 0xc0 - 0xff: vendor specific */
/* Command specific status values, Status Code Type (SCT): 1h */
@@ -1753,14 +1771,18 @@ struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] =
* as 0x2. */
struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] =
{
- {SAM_STAT_GOOD, SPC_SK_NO_SENSE, 0, 0}, /* it's all good */ /* 0 */
+ /* SCSI Status, SCSI sense key, ASC, ASCQ */
+/* index: 0 */
+ {SAM_STAT_GOOD, SPC_SK_NO_SENSE, 0, 0}, /* it's all good */
{SAM_STAT_CHECK_CONDITION, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x0},/* opcode */
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x24, 0x0}, /* field in cdb */
{0x2, SPC_SK_MEDIUM_ERROR, 0x0, 0x0},
{SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0xb, 0x8},
- {0x2, SPC_SK_HARDWARE_ERROR, 0x44, 0x0}, /* internal error */ /* 5 */
+ {0x2, SPC_SK_HARDWARE_ERROR, 0x44, 0x0}, /* internal error */
{SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0x0, 0x0},
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x9}, /* invalid LU */
+
+/* index: 8 */
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x2}, /* access denied */
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x2c, 0x0}, /* cmd sequence error */
{0x2, SPC_SK_MEDIUM_ERROR, 0x31, 0x3}, /* sanitize failed */ /* 10 */
@@ -1768,18 +1790,30 @@ struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] =
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x21, 0x0}, /* LBA out of range */
{0x2, SPC_SK_NOT_READY, 0x4, 0x0}, /* not reportable; 0x1: becoming */
{SAM_STAT_RESERVATION_CONFLICT, 0x0, 0x0, 0x0},
- {0x2, SPC_SK_NOT_READY, 0x4, 0x4}, /* format in progress */ /* 15 */
+ {0x2, SPC_SK_NOT_READY, 0x4, 0x4}, /* format in progress */
+
+/* index: 0x10 */
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x31, 0x1}, /* format failed */
{0x2, SPC_SK_NOT_READY, 0x4, 0x9}, /* self-test in progress */
{0x2, SPC_SK_DATA_PROTECT, 0x27, 0x0}, /* write prohibited */
{0x2, SPC_SK_ILLEGAL_REQUEST, 0x10, 0x5}, /* protection info */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x3, 0x0}, /* periph dev w fault */ /* 20 */
+ {0x2, SPC_SK_MEDIUM_ERROR, 0x3, 0x0}, /* periph dev w fault */
{0x2, SPC_SK_MEDIUM_ERROR, 0x11, 0x0}, /* unrecoc rd */
{0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x1}, /* PI guard */
{0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x2}, /* PI app tag */
- {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x2}, /* PI app tag */
- {0x2, SPC_SK_MISCOMPARE, 0x1d, 0x0}, /* during verify */ /* 25 */
+
+/* index: 0x18 */
+ {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x3}, /* PI reference tag */
+ {0x2, SPC_SK_MISCOMPARE, 0x1d, 0x0}, /* during verify */
{0x2, SPC_SK_MEDIUM_ERROR, 0x21, 0x6}, /* read invalid data */
+ {0x2, SPC_SK_DATA_PROTECT, 0x27, 0x8}, /* zone is read only */
+ {0x2, SPC_SK_DATA_PROTECT, 0x2c, 0xe}, /* zone is offline */
+ {0x2, SPC_SK_DATA_PROTECT, 0x2c, 0x12}, /* zone is inactive */
+ {0x2, SPC_SK_DATA_PROTECT, 0x3f, 0x17}, /* zone is full */
+ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x21, 0x5}, /* Write boundary violation */
+
+/* index: 0x20 */
+ {0x2, SPC_SK_DATA_PROTECT, 0x55, 0xe}, /* Insufficient zone resources */
/* Leave this Sentinel value at end of this array */
{0xff, 0xff, 0xff, 0xff},
diff --git a/sg3_utils.spec b/sg3_utils.spec
index c66d3fa2..e8b5d330 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Wed Feb 02 2022 - dgilbert at interlog dot com
+* Thu Feb 17 2022 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.48
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 38b033b6..92333975 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -51,7 +51,7 @@
#include "sg_pt_nvme.h"
#endif
-static const char * version_str = "2.14 20220109"; /* spc6r06 */
+static const char * version_str = "2.16 20220217"; /* spc6r06 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -1337,12 +1337,11 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
{
int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len;
int off, ci_off, c_id, d_id, naa, vsi, k;
- uint64_t vsei;
- uint64_t id_ext;
+ uint64_t vsei, id_ext, ccc_id;
const uint8_t * bp;
const uint8_t * ip;
- char b[64];
const char * cp;
+ char b[64];
if (buff[2] != 0) {
/*
@@ -1452,11 +1451,8 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
hex2stderr(ip, i_len, -1);
break;
}
- c_id = sg_get_unaligned_be24(ip + ci_off);
- printf(" IEEE Company_id: 0x%x\n", c_id);
- vsei = sg_get_unaligned_be48(ip + ci_off + 3);
- printf(" Vendor Specific Extension Identifier: 0x%" PRIx64
- "\n", vsei);
+ ccc_id = sg_get_unaligned_be64(ip + ci_off);
+ printf(" IEEE identifier: 0x%" PRIx64 "\n", ccc_id);
if (12 == i_len) {
d_id = sg_get_unaligned_be32(ip + 8);
printf(" Directory ID: 0x%x\n", d_id);
@@ -1487,7 +1483,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
vsi = sg_get_unaligned_be24(ip + 5);
printf(" NAA 2, vendor specific identifier A: 0x%x\n",
d_id);
- printf(" IEEE Company_id: 0x%x\n", c_id);
+ printf(" AOI: 0x%x\n", c_id);
printf(" vendor specific identifier B: 0x%x\n", vsi);
printf(" [0x");
for (m = 0; m < 8; ++m)
@@ -1521,7 +1517,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
vsei <<= 8;
vsei |= ip[3 + m];
}
- printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id);
+ printf(" NAA 5, AOI: 0x%x\n", c_id);
printf(" Vendor Specific Identifier: 0x%" PRIx64
"\n", vsei);
printf(" [0x");
@@ -1543,7 +1539,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex,
vsei <<= 8;
vsei |= ip[3 + m];
}
- printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id);
+ printf(" NAA 6, AOI: 0x%x\n", c_id);
printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n",
vsei);
vsei = sg_get_unaligned_be64(ip + 8);
@@ -2032,9 +2028,8 @@ decode_softw_inf_id(uint8_t * buff, int len, int do_hex)
len -= 4;
buff += 4;
for ( ; len > 5; len -= 6, buff += 6)
- printf(" IEEE Company_id: 0x%06x, vendor specific extension "
- "id: 0x%06x\n", sg_get_unaligned_be24(buff + 0),
- sg_get_unaligned_be24(buff + 3));
+ printf(" IEEE identifier: 0x%" PRIx64 "\n",
+ sg_get_unaligned_be48(buff + 0));
}
/* VPD_ATA_INFO [0x89] */
@@ -2189,7 +2184,7 @@ decode_b0_vpd(uint8_t * buff, int len, int do_hex)
}
pdt = PDT_MASK & buff[0];
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
if (len < 16) {
pr2serr("Block limits VPD page length too short=%d\n", len);
return;
@@ -2335,7 +2330,7 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex)
}
pdt = PDT_MASK & buff[0];
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
if (len < 64) {
pr2serr("Block device characteristics VPD page length too "
"short=%d\n", len);
@@ -2410,7 +2405,7 @@ decode_b3_vpd(uint8_t * buff, int len, int do_hex)
}
pdt = PDT_MASK & buff[0];
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
if (len < 0x10) {
pr2serr("Referrals VPD page length too short=%d\n", len);
return;
@@ -3541,7 +3536,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
printf("VPD INQUIRY: Block limits page (SBC)\n");
break;
case PDT_TAPE: case PDT_MCHANGER:
@@ -3569,7 +3564,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
printf("VPD INQUIRY: Block device characteristics page "
"(SBC)\n");
break;
@@ -3607,7 +3602,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len)
pdt = rp[0] & PDT_MASK;
if (! op->do_raw && (op->do_hex < 2)) {
switch (pdt) {
- case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
+ case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC:
printf("VPD INQUIRY: Referrals VPD page (SBC)\n");
break;
default:
@@ -3902,7 +3897,7 @@ show_nvme_id_ctrl(const uint8_t *dinp, const char *dev_name, int do_long)
printf(" PCI vendor ID VID/SSVID: 0x%x/0x%x\n",
sg_get_unaligned_le16(dinp + 0),
sg_get_unaligned_le16(dinp + 2));
- printf(" IEEE OUI Identifier: 0x%x\n",
+ printf(" IEEE OUI Identifier: 0x%x\n", /* this has been renamed AOI */
sg_get_unaligned_le24(dinp + 73));
got_fguid = ! sg_all_zeros(dinp + 112, 16);
if (got_fguid) {
diff --git a/src/sg_read_buffer.c b/src/sg_read_buffer.c
index 01a79c33..cbc5023b 100644
--- a/src/sg_read_buffer.c
+++ b/src/sg_read_buffer.c
@@ -39,8 +39,7 @@
* device.
*/
-static const char * version_str = "1.34 20220118"; /* spc6r05 */
-
+static const char * version_str = "1.35 20220217"; /* spc6r06 */
#ifndef SG_READ_BUFFER_10_CMD
#define SG_READ_BUFFER_10_CMD 0x3c
@@ -51,13 +50,26 @@ static const char * version_str = "1.34 20220118"; /* spc6r05 */
#define SG_READ_BUFFER_16_CMDLEN 16
#endif
+#define MODE_HEADER_DATA 0
+#define MODE_VENDOR 1
+#define MODE_DATA 2
+#define MODE_DESCRIPTOR 3
+#define MODE_ECHO_BUFFER 0x0A
+#define MODE_ECHO_BDESC 0x0B
+#define MODE_READ_MICROCODE_ST 0x0F
+#define MODE_EN_EX_ECHO 0x1A
+#define MODE_ERR_HISTORY 0x1C
+
#define MAX_DEF_INHEX_LEN 8192
-#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
-#define DEF_PT_TIMEOUT 60 /* 60 seconds */
+#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
+#define DEF_PT_TIMEOUT 60 /* 60 seconds */
+#define DEF_RESPONSE_LEN 4 /* increased to 64 fo MODE_ERR_HISTORY */
static struct option long_options[] = {
{"16", no_argument, 0, 'L'},
+ {"eh_code", required_argument, 0, 'e'},
+ {"eh-code", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"id", required_argument, 0, 'i'},
@@ -65,6 +77,8 @@ static struct option long_options[] = {
{"length", required_argument, 0, 'l'},
{"long", no_argument, 0, 'L'},
{"mode", required_argument, 0, 'm'},
+ {"no_output", no_argument, 0, 'N'},
+ {"no-output", no_argument, 0, 'N'},
{"offset", required_argument, 0, 'o'},
{"raw", no_argument, 0, 'r'},
{"readonly", no_argument, 0, 'R'},
@@ -74,19 +88,48 @@ static struct option long_options[] = {
{0, 0, 0, 0}, /* sentinel */
};
+struct opts_t {
+ bool do_long;
+ bool o_readonly;
+ bool do_raw;
+ bool eh_code_given;
+ bool no_output;
+ bool rb_id_given;
+ bool rb_len_given;
+ bool rb_mode_given;
+ bool verbose_given;
+ bool version_given;
+ int sg_fd;
+ int do_help;
+ int do_hex;
+ int eh_code;
+ int rb_id;
+ int rb_len;
+ int rb_mode;
+ int rb_mode_sp;
+ int verbose;
+ uint64_t rb_offset;
+ const char * device_name;
+ const char * inhex_name;
+};
+
static void
usage()
{
- pr2serr("Usage: sg_read_buffer [--16] [--help] [--hex] [--id=ID] "
- "[--inhex=FN]\n"
- " [--length=LEN] [--long] [--mode=MO] "
- "[--offset=OFF]\n"
- " [--raw] [--readonly] [--specific=MS] "
- "[--verbose]\n"
- " [--version] DEVICE\n"
+ pr2serr("Usage: sg_read_buffer [--16] [--eh_code=EHC] [--help] [--hex] "
+ "[--id=ID]\n"
+ " [--inhex=FN] [--length=LEN] [--long] "
+ "[--mode=MO]\n"
+ " [--no_output] [--offset=OFF] [--raw] "
+ "[--readonly]\n"
+ " [--specific=MS] [--verbose] [--version] "
+ "DEVICE\n"
" where:\n"
" --16|-L issue READ BUFFER(16) (def: 10)\n"
+ " --eh_code=EHC|-e EHC same as '-m eh -i EHC' where "
+ "EHC is the\n"
+ " error history code\n"
" --help|-h print out usage message\n"
" --hex|-H print output in hex\n"
" --id=ID|-i ID buffer identifier (0 (default) to 255)\n"
@@ -94,10 +137,12 @@ usage()
"decode\n"
" rather than DEVICE. If --raw given "
"then binary\n"
- " --length=LEN|-l LEN length in bytes to read (def: 4)\n"
+ " --length=LEN|-l LEN length in bytes to read (def: 4, "
+ "64 for eh)\n"
" --long|-L issue READ BUFFER(16) (def: 10)\n"
" --mode=MO|-m MO read buffer mode, MO is number or "
"acronym (def: 0)\n"
+ " --no_output|-N perform the command then exit\n"
" --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
" --raw|-r output response in binary to stdout\n"
" --readonly|-R open DEVICE read-only (def: read-write)\n"
@@ -106,22 +151,12 @@ usage()
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
"Performs a SCSI READ BUFFER (10 or 16) command. Use '-m xxx' to "
- "list\navailable modes. Numbers given in options are decimal "
- "unless they have\na hex indicator (e.g. a leading '0x').\n"
+ "list\navailable modes. Some responses are decoded, others are "
+ "output in hex.\n"
);
}
-#define MODE_HEADER_DATA 0
-#define MODE_VENDOR 1
-#define MODE_DATA 2
-#define MODE_DESCRIPTOR 3
-#define MODE_ECHO_BUFFER 0x0A
-#define MODE_ECHO_BDESC 0x0B
-#define MODE_READ_MICROCODE_ST 0x0F
-#define MODE_EN_EX_ECHO 0x1A
-#define MODE_ERR_HISTORY 0x1C
-
static struct mode_s {
const char *mode_string;
int mode;
@@ -138,7 +173,7 @@ static struct mode_s {
"(spc-5)"},
{ "en_ex", MODE_EN_EX_ECHO,
"enable expander communications protocol and echo buffer (spc-3)"},
- { "err_hist", MODE_ERR_HISTORY, "error history (spc-4)"},
+ { "err_hist|eh", MODE_ERR_HISTORY, "error history (spc-4)"},
{ NULL, 999, NULL}, /* end sentinel */
};
@@ -159,9 +194,8 @@ print_modes(void)
/* Invokes a SCSI READ BUFFER(10) command (spc5r02). Return of 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
-sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
- uint32_t rb_offset, void * resp, int mx_resp_len,
- int * residp, bool noisy, int verbose)
+sg_ll_read_buffer_10(void * resp, int * residp, bool noisy,
+ const struct opts_t * op)
{
int ret, res, sense_cat;
uint8_t rb10_cb[SG_READ_BUFFER_10_CMDLEN] =
@@ -169,13 +203,13 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
struct sg_pt_base * ptvp;
- rb10_cb[1] = (uint8_t)(rb_mode & 0x1f);
- if (rb_mode_sp)
- rb10_cb[1] |= (uint8_t)((rb_mode_sp & 0x7) << 5);
- rb10_cb[2] = (uint8_t)rb_id;
- sg_put_unaligned_be24(rb_offset, rb10_cb + 3);
- sg_put_unaligned_be24(mx_resp_len, rb10_cb + 6);
- if (verbose) {
+ rb10_cb[1] = (uint8_t)(op->rb_mode & 0x1f);
+ if (op->rb_mode_sp)
+ rb10_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5);
+ rb10_cb[2] = (uint8_t)op->rb_id;
+ sg_put_unaligned_be24(op->rb_offset, rb10_cb + 3);
+ sg_put_unaligned_be24(op->rb_len, rb10_cb + 6);
+ if (op->verbose) {
char b[128];
pr2serr(" Read buffer(10) cdb: %s\n",
@@ -190,10 +224,10 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
}
set_scsi_pt_cdb(ptvp, rb10_cb, sizeof(rb10_cb));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, "Read buffer(10)", res, noisy, verbose,
- &sense_cat);
+ set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len);
+ res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose);
+ ret = sg_cmds_process_resp(ptvp, "Read buffer(10)", res, noisy,
+ op->verbose, &sense_cat);
if (-1 == ret) {
if (get_scsi_pt_transport_err(ptvp))
ret = SG_LIB_TRANSPORT_ERROR;
@@ -210,7 +244,7 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
break;
}
} else {
- if ((verbose > 2) && (ret > 0)) {
+ if ((op->verbose > 2) && (ret > 0)) {
pr2serr(" Read buffer(10): response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1);
@@ -226,9 +260,8 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
/* Invokes a SCSI READ BUFFER(16) command (spc5r02). Return of 0 -> success,
* various SG_LIB_CAT_* positive values or -1 -> other errors */
static int
-sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
- uint64_t rb_offset, void * resp, int mx_resp_len,
- int * residp, bool noisy, int verbose)
+sg_ll_read_buffer_16(void * resp, int * residp, bool noisy,
+ const struct opts_t * op)
{
int ret, res, sense_cat;
uint8_t rb16_cb[SG_READ_BUFFER_16_CMDLEN] =
@@ -237,13 +270,13 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
uint8_t sense_b[SENSE_BUFF_LEN] = {0};
struct sg_pt_base * ptvp;
- rb16_cb[1] = (uint8_t)(rb_mode & 0x1f);
- if (rb_mode_sp)
- rb16_cb[1] |= (uint8_t)((rb_mode_sp & 0x7) << 5);
- sg_put_unaligned_be64(rb_offset, rb16_cb + 2);
- sg_put_unaligned_be24(mx_resp_len, rb16_cb + 11);
- rb16_cb[14] = (uint8_t)rb_id;
- if (verbose) {
+ rb16_cb[1] = (uint8_t)(op->rb_mode & 0x1f);
+ if (op->rb_mode_sp)
+ rb16_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5);
+ sg_put_unaligned_be64(op->rb_offset, rb16_cb + 2);
+ sg_put_unaligned_be32(op->rb_len, rb16_cb + 10);
+ rb16_cb[14] = (uint8_t)op->rb_id;
+ if (op->verbose) {
char b[128];
pr2serr(" Read buffer(16) cdb: %s\n",
@@ -253,15 +286,15 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
ptvp = construct_scsi_pt_obj();
if (NULL == ptvp) {
- pr2serr("Read buffer(16): out of memory\n");
+ pr2serr("%s: out of memory\n", __func__);
return -1;
}
set_scsi_pt_cdb(ptvp, rb16_cb, sizeof(rb16_cb));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
- res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
- ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, noisy, verbose,
- &sense_cat);
+ set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len);
+ res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose);
+ ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, noisy,
+ op->verbose, &sense_cat);
if (-1 == ret) {
if (get_scsi_pt_transport_err(ptvp))
ret = SG_LIB_TRANSPORT_ERROR;
@@ -278,7 +311,7 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
break;
}
} else {
- if ((verbose > 2) && (ret > 0)) {
+ if ((op->verbose > 2) && (ret > 0)) {
pr2serr(" Read buffer(16): response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1);
@@ -343,7 +376,7 @@ struct sg_lib_simple_value_name_t down_micro_st_arr[] = {
};
static void
-decode_microcode_status(uint8_t * resp, int rb_len)
+decode_microcode_status(const uint8_t * resp, const struct opts_t * op)
{
int n;
uint32_t u;
@@ -351,7 +384,7 @@ decode_microcode_status(uint8_t * resp, int rb_len)
const struct sg_lib_simple_value_name_t * vnp;
char b[32];
- if ((NULL == resp) || (rb_len < 1))
+ if ((NULL == resp) || (op->rb_len < 1))
return;
n = resp[0];
if (n < (int)SG_ARRAY_SIZE(act_micro_st_arr))
@@ -362,7 +395,7 @@ decode_microcode_status(uint8_t * resp, int rb_len)
}
printf("Activated microcode status: %s\n", cp);
- if (rb_len < 2)
+ if (op->rb_len < 2)
return;
n = resp[1];
if (n < (int)SG_ARRAY_SIZE(red_micro_st_arr))
@@ -373,7 +406,7 @@ decode_microcode_status(uint8_t * resp, int rb_len)
}
printf("Redundant microcode status: %s\n", cp);
- if (rb_len < 3)
+ if (op->rb_len < 3)
return;
n = resp[2];
for (vnp = down_micro_st_arr, cp = NULL; vnp->name; ++vnp) {
@@ -388,11 +421,11 @@ decode_microcode_status(uint8_t * resp, int rb_len)
}
printf("Download microcode status: %s\n", cp);
- if (rb_len > 7) {
+ if (op->rb_len > 7) {
u = sg_get_unaligned_be32(resp + 4);
printf("Download microcode maximum size (bytes): %u [0x%x]\n", u, u);
}
- if (rb_len > 15) {
+ if (op->rb_len > 15) {
u = sg_get_unaligned_be32(resp + 12);
printf("Download microcode expected buffer offset (bytes): %u "
"[0x%x]\n", u, u);
@@ -400,6 +433,59 @@ decode_microcode_status(uint8_t * resp, int rb_len)
}
static void
+decode_error_history(const uint8_t * resp, const struct opts_t * op)
+{
+ static const char * eh_s = "Error history";
+ int k, num;
+ uint32_t dir_len;
+ const uint8_t * up;
+
+ if (op->rb_id < 0x4) { /* eh directory variants */
+ if (op->rb_len < 8) {
+ pr2serr("%s response buffer too short [%d] to show directory "
+ "header\n", eh_s, op->rb_len);
+ return;
+ }
+ printf("%s directory header:\n", eh_s);
+ printf(" T10 Vendor: %.8s\n", resp + 0);
+ printf(" Version: %u\n", resp[8]);
+ printf(" EHS_retrieved: %u\n", 0x3 & (resp[9] >> 3));
+ printf(" EHS_source: %u\n", 0x3 & (resp[9] >> 1));
+ printf(" CLR_SUP: %u\n", 0x1 & resp[9]);
+ if (op->rb_len < 32) {
+ pr2serr("%s response buffer too short [%d] to show directory "
+ "length\n", eh_s, op->rb_len);
+ return;
+ }
+ dir_len = sg_get_unaligned_be16(resp + 30);
+ printf(" Directory length: %u\n", dir_len);
+ if ((unsigned)op->rb_len < (32 + dir_len)) {
+ pr2serr("%s directory entries truncated, try adding '-l %u' "
+ "option\n", eh_s, 32 + dir_len);
+ }
+ num = (op->rb_len - 32) / 8;
+ for (k = 0, up = resp + 32; k < num; ++k, up += 8) {
+ if (k > 0)
+ printf("\n");
+ printf(" Supported buffer ID: 0x%x\n", up[0]);
+ printf(" Buffer format: 0x%x\n", up[1]);
+ printf(" Buffer source: 0x%x\n", 0xf & up[2]);
+ printf(" Maximum available length: 0x%x\n",
+ sg_get_unaligned_be32(up + 4));
+ }
+ } else if ((op->rb_id >= 0x10) && (op->rb_id <= 0xef))
+ hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1));
+ else if (0xfe == op->rb_id)
+ pr2serr("clear %s I_T nexus [0x%x]\n", eh_s, op->rb_id);
+ else if (0xff == op->rb_id)
+ pr2serr("clear %s I_T nexus and release any snapshots [0x%x]\n",
+ eh_s, op->rb_id);
+ else
+ pr2serr("Reserved Buffer ID value [0x%x] for %s\n", op->rb_id, eh_s);
+
+}
+
+static void
dStrRaw(const uint8_t * str, int len)
{
int k;
@@ -411,84 +497,90 @@ dStrRaw(const uint8_t * str, int len)
int
main(int argc, char * argv[])
{
- bool do_long = false;
- bool o_readonly = false;
- bool do_raw = false;
- bool verbose_given = false;
- bool version_given = false;
int res, c, len, k;
int inhex_len = 0;
- int sg_fd = -1;
- int do_help = 0;
- int do_hex = 0;
- int rb_id = 0;
- int rb_len = 4;
- int rb_mode = 0;
- int rb_mode_sp = 0;
int resid = 0;
- int verbose = 0;
int ret = 0;
int64_t ll;
- uint64_t rb_offset = 0;
- const char * device_name = NULL;
- const char * fname = NULL;
+ const char * cp = NULL;
uint8_t * resp = NULL;
uint8_t * free_resp = NULL;
const struct mode_s * mp;
+ struct opts_t opts = {0};
+ struct opts_t * op = &opts;
+
+ op->sg_fd = -1;
+ op->rb_len = DEF_RESPONSE_LEN;
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "hHi:I:l:Lm:o:rRS:vV", long_options,
+ c = getopt_long(argc, argv, "e:hHi:I:l:Lm:No:rRS:vV", long_options,
&option_index);
if (c == -1)
break;
switch (c) {
+ case 'e':
+ if (op->rb_mode_given && (MODE_ERR_HISTORY != op->rb_mode)) {
+ pr2serr("mode incompatible with --eh_code= option\n");
+ return SG_LIB_CONTRADICT;
+ }
+ op->eh_code = sg_get_num(optarg);
+ if ((op->eh_code < 0) || (op->eh_code > 255)) {
+ pr2serr("argument to '--eh_code=' should be in the range 0 "
+ "to 255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ op->rb_mode = MODE_ERR_HISTORY;
+ op->eh_code_given = true;
+ break;
case 'h':
case '?':
- ++do_help;
+ ++op->do_help;
break;
case 'H':
- ++do_hex;
+ ++op->do_hex;
break;
case 'i':
- rb_id = sg_get_num(optarg);
- if ((rb_id < 0) || (rb_id > 255)) {
- pr2serr("argument to '--id' should be in the range 0 to "
+ op->rb_id = sg_get_num(optarg);
+ if ((op->rb_id < 0) || (op->rb_id > 255)) {
+ pr2serr("argument to '--id=' should be in the range 0 to "
"255\n");
return SG_LIB_SYNTAX_ERROR;
}
+ op->rb_id_given = true;
break;
case 'I':
- if (fname) {
+ if (op->inhex_name) {
pr2serr("--inhex= option given more than once. Once only "
"please\n");
return SG_LIB_SYNTAX_ERROR;
} else
- fname = optarg;
+ op->inhex_name = optarg;
break;
case 'l':
- rb_len = sg_get_num(optarg);
- if (rb_len < 0) {
+ op->rb_len = sg_get_num(optarg);
+ if (op->rb_len < 0) {
pr2serr("bad argument to '--length'\n");
return SG_LIB_SYNTAX_ERROR;
}
- if (rb_len > 0xffffff) {
+ if (op->rb_len > 0xffffff) {
pr2serr("argument to '--length' must be <= 0xffffff\n");
return SG_LIB_SYNTAX_ERROR;
}
+ op->rb_len_given = true;
break;
case 'L':
- do_long = true;
+ op->do_long = true;
break;
case 'm':
if (NULL == optarg) {
pr2serr("bad argument to '--mode'\n");
return SG_LIB_SYNTAX_ERROR;
} else if (isdigit((uint8_t)*optarg)) {
- rb_mode = sg_get_num(optarg);
- if ((rb_mode < 0) || (rb_mode > 31)) {
+ op->rb_mode = sg_get_num(optarg);
+ if ((op->rb_mode < 0) || (op->rb_mode > 31)) {
pr2serr("argument to '--mode' should be in the range 0 "
"to 31\n");
return SG_LIB_SYNTAX_ERROR;
@@ -496,9 +588,24 @@ main(int argc, char * argv[])
} else {
len = strlen(optarg);
for (mp = modes; mp->mode_string; ++mp) {
- if (0 == strncmp(mp->mode_string, optarg, len)) {
- rb_mode = mp->mode;
- break;
+ cp = strchr(mp->mode_string, '|');
+ if (NULL == cp) {
+ if (0 == strncmp(mp->mode_string, optarg, len)) {
+ op->rb_mode = mp->mode;
+ break;
+ }
+ } else {
+ int f_len = cp - mp->mode_string;
+
+ if ((f_len == len) &&
+ (0 == memcmp(mp->mode_string, optarg, len))) {
+ op->rb_mode = mp->mode;
+ break;
+ }
+ if (0 == strncmp(cp + 1, optarg, len)) {
+ op->rb_mode = mp->mode;
+ break;
+ }
}
}
if (NULL == mp->mode_string) {
@@ -506,6 +613,14 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
}
+ if (op->eh_code_given && (MODE_ERR_HISTORY != op->rb_mode)) {
+ pr2serr("mode incompatible with --eh_code= option\n");
+ return SG_LIB_CONTRADICT;
+ }
+ op->rb_mode_given = true;
+ break;
+ case 'N':
+ op->no_output = true;
break;
case 'o':
ll = sg_get_llnum(optarg);
@@ -513,27 +628,27 @@ main(int argc, char * argv[])
pr2serr("bad argument to '--offset'\n");
return SG_LIB_SYNTAX_ERROR;
}
- rb_offset = ll;
+ op->rb_offset = ll;
break;
case 'r':
- do_raw = true;
+ op->do_raw = true;
break;
case 'R':
- o_readonly = true;
+ op->o_readonly = true;
break;
case 'S':
- rb_mode_sp = sg_get_num(optarg);
- if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) {
+ op->rb_mode_sp = sg_get_num(optarg);
+ if ((op->rb_mode_sp < 0) || (op->rb_mode_sp > 7)) {
pr2serr("expected argument to '--specific' to be 0 to 7\n");
return SG_LIB_SYNTAX_ERROR;
}
break;
case 'v':
- verbose_given = true;
- ++verbose;
+ op->verbose_given = true;
+ ++op->verbose;
break;
case 'V':
- version_given = true;
+ op->version_given = true;
break;
default:
pr2serr("unrecognised option code 0x%x ??\n", c);
@@ -541,8 +656,8 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
}
- if (do_help) {
- if (do_help > 1) {
+ if (op->do_help) {
+ if (op->do_help > 1) {
usage();
pr2serr("\n");
print_modes();
@@ -551,8 +666,8 @@ main(int argc, char * argv[])
return 0;
}
if (optind < argc) {
- if (NULL == device_name) {
- device_name = argv[optind];
+ if (NULL == op->device_name) {
+ op->device_name = argv[optind];
++optind;
}
if (optind < argc) {
@@ -565,54 +680,67 @@ main(int argc, char * argv[])
#ifdef DEBUG
pr2serr("In DEBUG mode, ");
- if (verbose_given && version_given) {
+ if (op->verbose_given && op->version_given) {
pr2serr("but override: '-vV' given, zero verbose and continue\n");
- verbose_given = false;
- version_given = false;
- verbose = 0;
- } else if (! verbose_given) {
+ op->verbose_given = false;
+ op->version_given = false;
+ op->verbose = 0;
+ } else if (! op->verbose_given) {
pr2serr("set '-vv'\n");
- verbose = 2;
+ op->verbose = 2;
} else
- pr2serr("keep verbose=%d\n", verbose);
+ pr2serr("keep verbose=%d\n", op->verbose);
#else
- if (verbose_given && version_given)
+ if (op->verbose_given && op->version_given)
pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
#endif
- if (version_given) {
+ if (op->version_given) {
pr2serr("version: %s\n", version_str);
return 0;
}
+ if ((MODE_ERR_HISTORY == op->rb_mode) && (NULL == op->inhex_name)) {
+ if (! op->rb_len_given)
+ op->rb_len = 64;
+ }
+ if (op->eh_code_given) {
+ if (op->rb_id_given && (op->eh_code != op->rb_id)) {
+ pr2serr("Buffer ID incompatible with --eh_code= option\n");
+ return SG_LIB_CONTRADICT;
+ }
+ op->rb_id = op->eh_code;
+ }
- if (device_name && fname) {
+ if (op->device_name && op->inhex_name) {
pr2serr("Confused: both DEVICE (%s) and --inhex= option given. One "
- "only please\n", device_name);
+ "only please\n", op->device_name);
return SG_LIB_SYNTAX_ERROR;
- } else if (fname) {
- rb_len = (rb_len > MAX_DEF_INHEX_LEN) ? rb_len : MAX_DEF_INHEX_LEN;
- resp = (uint8_t *)sg_memalign(rb_len, 0, &free_resp, false);
- ret = sg_f2hex_arr(fname, do_raw, false, resp, &inhex_len, rb_len);
+ } else if (op->inhex_name) {
+ op->rb_len = (op->rb_len > MAX_DEF_INHEX_LEN) ? op->rb_len :
+ MAX_DEF_INHEX_LEN;
+ resp = (uint8_t *)sg_memalign(op->rb_len, 0, &free_resp, false);
+ ret = sg_f2hex_arr(op->inhex_name, op->do_raw, false, resp,
+ &inhex_len, op->rb_len);
if (ret)
goto fini;
- if (do_raw)
- do_raw = false; /* only used for input in this case */
- rb_len = inhex_len;
+ if (op->do_raw)
+ op->do_raw = false; /* only used for input in this case */
+ op->rb_len = inhex_len;
resid = 0;
goto decode_result;
- } else if (NULL == device_name) {
+ } else if (NULL == op->device_name) {
pr2serr("Missing device name!\n\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
- len = rb_len ? rb_len : 8;
+ len = op->rb_len ? op->rb_len : 8;
resp = (uint8_t *)sg_memalign(len, 0, &free_resp, false);
if (NULL == resp) {
pr2serr("unable to allocate %d bytes on the heap\n", len);
return SG_LIB_CAT_OTHER;
}
- if (do_raw) {
+ if (op->do_raw) {
if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
perror("sg_set_binary_mode");
ret = SG_LIB_FILE_ERROR;
@@ -622,55 +750,56 @@ main(int argc, char * argv[])
#ifdef SG_LIB_WIN32
#ifdef SG_LIB_WIN32_DIRECT
- if (verbose > 4)
+ if (op->verbose > 4)
pr2serr("Initial win32 SPT interface state: %s\n",
scsi_pt_win32_spt_state() ? "direct" : "indirect");
scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
#endif
#endif
- sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose);
- if (sg_fd < 0) {
- if (verbose)
- pr2serr("open error: %s: %s\n", device_name,
- safe_strerror(-sg_fd));
- ret = sg_convert_errno(-sg_fd);
+ op->sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly,
+ op->verbose);
+ if (op->sg_fd < 0) {
+ if (op->verbose)
+ pr2serr("open error: %s: %s\n", op->device_name,
+ safe_strerror(-op->sg_fd));
+ ret = sg_convert_errno(-op->sg_fd);
goto fini;
}
- if (do_long)
- res = sg_ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id,
- rb_offset, resp, rb_len, &resid, true,
- verbose);
- else if (rb_offset > 0xffffff) {
+ if (op->do_long)
+ res = sg_ll_read_buffer_16(resp, &resid, true, op);
+ else if (op->rb_offset > 0xffffff) {
pr2serr("--offset value is too large for READ BUFFER(10), try "
"--16\n");
ret = SG_LIB_SYNTAX_ERROR;
goto fini;
} else
- res = sg_ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id,
- (uint32_t)rb_offset, resp, rb_len, &resid,
- true, verbose);
+ res = sg_ll_read_buffer_10(resp, &resid, true, op);
if (0 != res) {
char b[80];
ret = res;
if (res > 0) {
- sg_get_category_sense_str(res, sizeof(b), b, verbose);
- pr2serr("Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b);
+ sg_get_category_sense_str(res, sizeof(b), b, op->verbose);
+ pr2serr("Read buffer(%d) failed: %s\n",
+ (op->do_long ? 16 : 10), b);
}
goto fini;
}
if (resid > 0)
- rb_len -= resid; /* got back less than requested */
+ op->rb_len -= resid; /* got back less than requested */
+ if (op->no_output)
+ goto fini;
decode_result:
- if (rb_len > 0) {
- if (do_raw)
- dStrRaw(resp, rb_len);
- else if (do_hex || (rb_len < 4))
- hex2stdout((const uint8_t *)resp, rb_len, ((do_hex > 1) ? 0 : 1));
- else {
- switch (rb_mode) {
+ if (op->rb_len > 0) {
+ if (op->do_raw)
+ dStrRaw(resp, op->rb_len);
+ else if (op->do_hex || (op->rb_len < 4)) {
+ k = (op->do_hex > 2) ? -1 : (2 - op->do_hex);
+ hex2stdout(resp, op->rb_len, k);
+ } else {
+ switch (op->rb_mode) {
case MODE_DESCRIPTOR:
k = sg_get_unaligned_be24(resp + 1);
printf("OFFSET BOUNDARY: %d, Buffer offset alignment: "
@@ -683,11 +812,13 @@ decode_result:
printf("Echo buffer capacity: %d (0x%x)\n", k, k);
break;
case MODE_READ_MICROCODE_ST:
- decode_microcode_status(resp, rb_len);
+ decode_microcode_status(resp, op);
+ break;
+ case MODE_ERR_HISTORY:
+ decode_error_history(resp, op);
break;
default:
- hex2stdout((const uint8_t *)resp, rb_len,
- (verbose > 1 ? 0 : 1));
+ hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1));
break;
}
}
@@ -696,15 +827,15 @@ decode_result:
fini:
if (free_resp)
free(free_resp);
- if (sg_fd >= 0) {
- res = sg_cmds_close_device(sg_fd);
+ if (op->sg_fd >= 0) {
+ res = sg_cmds_close_device(op->sg_fd);
if (res < 0) {
pr2serr("close error: %s\n", safe_strerror(-res));
if (0 == ret)
ret = sg_convert_errno(-res);
}
}
- if (0 == verbose) {
+ if (0 == op->verbose) {
if (! sg_if_can2stderr("sg_read_buffer failed: ", ret))
pr2serr("Some error occurred, try again with '-v' "
"or '-vv' for more information\n");
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 46b7e603..31954183 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.68 20220118"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.69 20220217"; /* spc6r06 + sbc5r01 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -1150,11 +1150,9 @@ decode_softw_inf_id(uint8_t * buff, int len, int do_hex)
}
len -= 4;
buff += 4;
- for ( ; len > 5; len -= 6, buff += 6) {
- printf(" IEEE Company_id: 0x%06x, vendor specific extension "
- "id: 0x%06x\n", sg_get_unaligned_be24(buff),
- sg_get_unaligned_be24(buff + 3));
- }
+ for ( ; len > 5; len -= 6, buff += 6)
+ printf(" IEEE identifier: 0x%" PRIx64 "\n",
+ sg_get_unaligned_be48(buff + 0));
}
/* VPD_ATA_INFO */
diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c
index 4f3b25e5..d79ccc7d 100644
--- a/src/sg_vpd_vendor.c
+++ b/src/sg_vpd_vendor.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2019 Douglas Gilbert.
+ * Copyright (c) 2006-2022 Douglas Gilbert.
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
@@ -232,11 +233,11 @@ dup_sanity_chk(int sz_opts_t, int sz_values_name_t)
sz_values_name_t);
}
-static int
+static bool
is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp)
{
if (actual_pdt == vnp->pdt)
- return 1;
+ return true;
if (PDT_DISK == vnp->pdt) {
switch (actual_pdt) {
case PDT_DISK:
@@ -244,21 +245,21 @@ is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp)
case PDT_PROCESSOR:
case PDT_SAC:
case PDT_ZBC:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
} else if (PDT_TAPE == vnp->pdt) {
switch (actual_pdt) {
case PDT_TAPE:
case PDT_MCHANGER:
case PDT_ADC:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
} else
- return 0;
+ return false;
}
static const struct svpd_values_name_t *
diff --git a/src/sg_write_x.c b/src/sg_write_x.c
index 81ee1a67..b7c34f75 100644
--- a/src/sg_write_x.c
+++ b/src/sg_write_x.c
@@ -38,7 +38,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.30 20220127";
+static const char * version_str = "1.31 20220217";
/* Protection Information refers to 8 bytes of extra information usually
* associated with each logical block and is often abbreviated to PI while
@@ -2197,10 +2197,9 @@ main(int argc, char * argv[])
uint64_t addr_arr[MAX_NUM_ADDR];
uint32_t num_arr[MAX_NUM_ADDR];
struct stat if_stat, sf_stat;
- struct opts_t opts;
+ struct opts_t opts = {0};
op = &opts;
- memset(op, 0, sizeof(opts));
memset(&if_stat, 0, sizeof(if_stat));
memset(&sf_stat, 0, sizeof(sf_stat));
op->numblocks = DEF_WR_NUMBLOCKS;
diff --git a/src/sg_z_act_query.c b/src/sg_z_act_query.c
index a345b2e8..cd347820 100644
--- a/src/sg_z_act_query.c
+++ b/src/sg_z_act_query.c
@@ -38,7 +38,7 @@
* command to the given SCSI device. Based on zbc2r12.pdf .
*/
-static const char * version_str = "1.02 20211203";
+static const char * version_str = "1.03 20211217";
#define SG_ZBC_IN_CMDLEN 16
#define Z_ACTIVATE_SA 0x8
@@ -365,10 +365,9 @@ main(int argc, char * argv[])
uint8_t * free_zibp = NULL;
const char * sa_name;
char b[80];
- struct opts_t opts;
+ struct opts_t opts = {0};
struct opts_t * op = &opts;
- memset(&opts, 0, sizeof(opts));
while (1) {
int option_index = 0;