aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-02-03 02:38:23 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-02-03 02:38:23 +0000
commit6b32eacd43ada71e267506e510db11e8988cc7dc (patch)
tree394e5b9921dfd8bf199310581609e945f4b76e7d
parentd5890d56b6bcb6d1aa277f0bab78abb1ef66a88e (diff)
downloadsg3_utils-6b32eacd43ada71e267506e510db11e8988cc7dc.tar.gz
sg_rep_zones: add --brief option and --find ZT option; sg_modes: improve handling of zbc disks with pdt=0x14
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@935 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog9
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg3_utils.82
-rw-r--r--doc/sg_rep_zones.876
-rw-r--r--include/sg_lib.h23
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_logs.c150
-rw-r--r--src/sg_modes.c13
-rw-r--r--src/sg_rep_zones.c295
-rw-r--r--src/sg_senddiag.c25
-rw-r--r--testing/sg_tst_ioctl.c6
11 files changed, 451 insertions, 152 deletions
diff --git a/ChangeLog b/ChangeLog
index 6f04a2e0..9a369e21 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 [20220128] [svn: r934]
+Changelog for pre-release sg3_utils-1.48 [20220202] [svn: r935]
- 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
@@ -12,10 +12,17 @@ Changelog for pre-release sg3_utils-1.48 [20220128] [svn: r934]
Change script to use either
- sg_rep_zones: add Report zone starting LBA granularity
field in REPORT ZONES response [zbc2r12]
+ - add --brief option, show part of header and last
+ descriptor fetched
+ - add --find ZT option to find the first occurrence of
+ ZT; if ZT prefixed by - or ! find first not equal to ZT
- sg_decode_sense: add --nodecode option
- sg_logs: tweak the meaning of --list option to more closely
reflect the contents of log pages 0x0 and 0x0,0xff
- make '-lll' set union of log pages 0x0 and 0x0,0xff
+ - 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_opcodes: cleanup error reporting
- sg_lib: add sg_pdt_s_eq() to cope with ZBC disks which may
be either PDT_ZBC (if host managed) or PDT_DISK
diff --git a/debian/changelog b/debian/changelog
index c3e329eb..7867ee7f 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> Fri, 21 Jan 2022 14:00:00 -0500
+ -- Douglas Gilbert <dgilbert@interlog.com> Wed, 02 Feb 2022 11:00:00 -0500
sg3-utils (1.47-0.1) unstable; urgency=low
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 5460f215..f60fd841 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "January 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG3_UTILS "8" "February 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
diff --git a/doc/sg_rep_zones.8 b/doc/sg_rep_zones.8
index 839d368b..2f03ba9a 100644
--- a/doc/sg_rep_zones.8
+++ b/doc/sg_rep_zones.8
@@ -1,10 +1,10 @@
-.TH SG_REP_ZONES "8" "January 2022" "sg3_utils\-1.48" SG3_UTILS
+.TH SG_REP_ZONES "8" "February 2022" "sg3_utils\-1.48" SG3_UTILS
.SH NAME
sg_rep_zones \- send SCSI REPORT ZONES, REALMS or ZONE DOMAINS command
.SH SYNOPSIS
.B sg_rep_zones
-[\fI\-\-brief\fR] [\fI\-\-domain\fR] [\fI\-\-force\fR] [\fI\-\-help\fR]
-[\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-locator=LBA\fR]
+[\fI\-\-brief\fR] [\fI\-\-domain\fR] [\fI\-\-find=ZT\fR] [\fI\-\-force\fR]
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-locator=LBA\fR]
[\fI\-\-maxlen=LEN\fR] [\fI\-\-num=NUM\fR] [\fI\-\-partial\fR] [\fI\-\-raw\fR]
[\fI\-\-readonly\fR] [\fI\-\-realm\fR] [\fI\-\-report=OPT\fR]
[\fI\-\-start=LBA\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wp\fR]
@@ -14,13 +14,13 @@ sg_rep_zones \- send SCSI REPORT ZONES, REALMS or ZONE DOMAINS command
.PP
Sends a SCSI REPORT ZONES, REPORT REALMS or REPORT ZONE DOMAINS command to
\fIDEVICE\fR and decodes (or simply outputs) the data returned. These
-commands is found in the ZBC\-2 draft standard, revision 10 (zbc2r05.pdf).
+commands are found in the ZBC\-2 draft standard, revision 12 (zbc2r12.pdf).
Only the REPORT ZONES command is defined in the original ZBC
-standard (INCITS 536\-2017) and it is the default.
+standard (INCITS 536\-2017) and it is the default for this utility.
.PP
-The REPORT ZONE DOMAINS command will be sent (or decoded) when the
+The REPORT ZONE DOMAINS command will be sent (and decoded) when the
\fI\-\-domain\fR option is given. The REPORT REALMS command will be
-sent (or decoded) when the \fI\-\-realm\fR option is given.
+sent (and decoded) when the \fI\-\-realm\fR option is given.
.PP
Rather than send a SCSI command to \fIDEVICE\fR, if the \fI\-\-inhex=FN\fR
option is given, then the contents of the file named \fIFN\fR are decoded
@@ -32,15 +32,38 @@ option is given then the corresponding command response is assumed.
Arguments to long options are mandatory for short options as well.
.TP
\fB\-b\fR, \fB\-\-brief\fR
-even though a ZBC disk will typically limit the size of the response
-to the REPORT ZONES command (e.g. to 127 zones say), this is still
-potentially a lot of output. This option will only decode and output
-fields found in the header plus some of the fields from the last
+even though a ZBC disk will typically limit the size of the response to the
+REPORT ZONES command (e.g. due to the "allocation length" field), this may
+still be potentially a lot of output. This option will only decode and
+output fields found in the response header plus fields from the last
descriptor in the current response.
.TP
\fB\-d\fR, \fB\-\-domain\fR
send or decode the SCSI REPORT ZONE DOMAINS command.
.TP
+\fB\-F\fR, \fB\-\-find\fR=\fIZT\fR
+where \fIZT\fR is a zone type number or an abbreviation for a zone
+type. If \fIZT\fR is prefixed by either '\-' or '!' then the check for
+equality is inverted to be a check for inequality. IOWs it does a: find
+the first occurrence that is
+.B not
+the given zone type.
+.br
+The algorithm used by this option takes into account the \fI\-\-hex\fR,
+\fI\-\-maxlen=LEN\fR, \fI\-\-report=OPT\fR and \fI\-\-start=LBA\fR options,
+if given, and ignores other options. It is only implemented for the Report
+zones command. The algorithm may call the Report zones command repeatedly,
+with the PARTIAL bit set and the Zone start LBA field being increased as it
+goes. This continues until either there is a match on the \fIZT\fR condition
+or the number of zones is exhausted.
+.br
+The \fIZT\fR numbers and abbreviations are listed when the \fI\-\-help\fR
+option is given twice. Warning: using '!' for inverting the condition may
+not be so practical as the shell (e.g. bash) may interprete '!' as having
+special meaning. Placing single quotes around \fIZT\fR fixes the problem
+for the bash shell (e.g. \-\-find='!c' meaning find the first zone whose
+type is not conventional).
+.TP
\fB\-f\fR, \fB\-\-force\fR
when decoding the response to this command, certain sanity checks are
done and if they fail a message is sent to stderr and a non\-zero
@@ -48,7 +71,8 @@ exit status is set. If this option is given those sanity checks are
bypassed.
.TP
\fB\-h\fR, \fB\-\-help\fR
-output the usage message then exit.
+output the usage message then exit. When given twice, additional usage
+information is output.
.TP
\fB\-H\fR, \fB\-\-hex\fR
output the response in hexadecimal to stdout. When used once the whole
@@ -57,8 +81,13 @@ response is output in ASCII hexadecimal with a leading address (starting at
output separately in hexadecimal. When used thrice the whole response is
output in hexadecimal with no leading address (on each line).
.br
-The output format when this option is given thrice is suitable contents
-for a later invocation with the \fI\-\-inhex=FN\fR option.
+When this option is used twice, it can be useful with either the
+\fI\-\-brief\fR or \fI\-\-find=ZT\fR option to only output the header
+and zone descriptor in hex that those two options would otherwise print
+in ASCII in the absence of the \fI\-\-hex\fR option.
+.br
+The output format when this option is given thrice is suitable for a later
+invocation with the \fI\-\-inhex=FN\fR option.
.TP
\fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR
where \fIFN\fR is a file name whose contents are assumed to be ASCII
@@ -80,7 +109,7 @@ commands.
\fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR
where \fILEN\fR is the (maximum) response length in bytes. It is placed in
the cdb's "allocation length" field. If not given (or \fILEN\fR is zero)
-then 8192 is used. The maximum allowed value of \fILEN\fR is 1048576.
+then 16384 is used. The maximum allowed value of \fILEN\fR is 2097152.
.TP
\fB\-n\fR, \fB\-\-num\fR=\fINUM\fR
where \fINUM\fR is the (maximum) number of zone descriptors to print out.
@@ -88,7 +117,22 @@ The default value is zero which is taken to mean print out all zone
descriptors returned by the REPORT ZONES command.
.TP
\fB\-p\fR, \fB\-\-partial\fR
-set the PARTIAL bit in the cdb.
+set the PARTIAL bit in the cdb. Without the PARTIAL bit set a ZBC disk
+will attempt to form a response with all zones from \fILBA\fR to the end
+of the disk. If there are a large number of zones (e.g. > 10,000) this
+large response will be truncated so that it doesn't exceed the "allocation
+length" field in the cdb (see \fI\-\-maxlen=LEN\fR). The advantage of doing
+this is that the number of (remaining) zones on the disk can be calculated.
+The disadvantage is the amount of time that may take.
+.br
+With the PARTIAL bit set in the cdb, only the number of zones implied by
+the "allocation length" field are fetched. This may be considerably faster
+than the same command without the PARTIAL bit set.
+.br
+When iterating through the zones on a ZBC disk, the process will be faster
+when the PARTIAL bit is set. Typically \fI\-\-start=LBA\fR is set to zero
+or the [LBA + zone_length] of the last zone reported in the previous
+iteration.
.TP
\fB\-r\fR, \fB\-\-raw\fR
output response in binary (to stdout) unless the \fI\-\-inhex=FN\fR option
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 38aa0011..16e6fc15 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -71,7 +71,7 @@ extern "C" {
* So squeeze two PDTs into one integer. Use sg_pdt_s_eq() to compare.
* N.B. Must not use PDT_DISK as upper */
#define PDT_DISK_ZBC (PDT_DISK | (PDT_ZBC << 8))
-#define PDT_ALL (-1) /* for common to all PDTs */
+#define PDT_ALL (-1) /* for common to all PDTs */
#define PDT_LOWER_MASK 0xff
#define PDT_UPPER_MASK (~PDT_LOWER_MASK)
@@ -515,7 +515,7 @@ bool sg_exit2str(int exit_status, bool longer, int b_len, char * b);
/* for 33 see SG_LIB_CAT_TIMEOUT below */
#define SG_LIB_WINDOWS_ERR 34 /* Windows error number don't fit in 7 bits so
* map to a single value for exit statuses */
-#define SG_LIB_TRANSPORT_ERROR 35 /* driver or interconnect */
+#define SG_LIB_TRANSPORT_ERROR 35 /* driver or interconnect */
#define SG_LIB_OK_FALSE 36 /* no error, reporting false (cf. no error,
* reporting true is SG_LIB_OK_TRUE(0) ) */
#define SG_LIB_CAT_PROTECTION 40 /* subset of aborted command (for PI, DIF)
@@ -612,19 +612,22 @@ void dStrHexFp(const char* str, int len, int no_ascii, FILE * fp);
* starts with 'leadin' (NULL for no leadin) and there are 16 bytes
* per line with an extra space between the 8th and 9th bytes. 'format'
* is 0 for repeat in printable ASCII ('.' for non printable chars) to
- * right of each line; 1 don't (so just output ASCII hex). Returns
- * number of bytes written to 'b' excluding the trailing '\0'. */
+ * right of each line; 1 don't (so just output ASCII hex). Note that
+ * an address is not printed on each line preceding the hex data. Returns
+ * number of bytes written to 'b' excluding the trailing '\0'.
+ * The only difference between dStrHexStr() and hex2str() is the type of
+ * the first argument. */
int dStrHexStr(const char * str, int len, const char * leadin, int format,
int cb_len, char * cbp);
+int hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
+ int cb_len, char * cbp);
-/* The following 3 functions are equivalent to dStrHex(), dStrHexErr() and
- * dStrHexStr() respectively. The difference is the type of the first of
- * argument: uint8_t instead of char. The name of the argument is changed
- * to b_str to stress it is a pointer to the start of a binary string. */
+/* The following 2 functions are equivalent to dStrHex() and dStrHexErr()
+ * respectively. The difference is only the type of the first of argument:
+ * uint8_t instead of char. The name of the argument is changed to b_str to
+ * stress it is a pointer to the start of a binary string. */
void hex2stdout(const uint8_t * b_str, int len, int no_ascii);
void hex2stderr(const uint8_t * b_str, int len, int no_ascii);
-int hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
- int cb_len, char * cbp);
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
* stdin). If reading ASCII hex then there should be either one entry per
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 4f493684..c66d3fa2 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Fri Jan 21 2022 - dgilbert at interlog dot com
+* Wed Feb 02 2022 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.48
diff --git a/src/sg_logs.c b/src/sg_logs.c
index 26e1b477..2fce0b5a 100644
--- a/src/sg_logs.c
+++ b/src/sg_logs.c
@@ -36,7 +36,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.93 20220127"; /* spc6r06 + sbc5r01 */
+static const char * version_str = "1.94 20220201"; /* spc6r06 + sbc5r01 */
#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
@@ -3112,7 +3112,7 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
const uint8_t * bp;
const char * cp;
char str[PCB_STR_LEN];
- char b[256];
+ char b[512];
char bb[32];
bool full, decoded;
bool has_header = false;
@@ -3305,8 +3305,8 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op)
break;
} /* end of switch statement */
if ((! decoded) && full) {
- printf(" parameter code = 0x%x, contents in hex:\n", pc);
- hex2stdout(bp, param_len, 1);
+ hex2str(bp, param_len, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf(" parameter code = 0x%x, contents in hex:\n%s", pc, b);
} else
printf("\n");
if (op->do_pcb)
@@ -4132,6 +4132,7 @@ show_format_status_page(const uint8_t * resp, int len,
const uint8_t * xp;
uint64_t ull;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Format status page [0x8]\n");
@@ -4160,8 +4161,9 @@ show_format_status_page(const uint8_t * resp, int len,
if (sg_all_ffs(bp + 4, pl - 4))
printf(" Format data out: <not available>\n");
else {
- printf(" Format data out:\n");
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf(" Format data out:\n%s", b);
}
}
is_count = false;
@@ -4181,7 +4183,8 @@ show_format_status_page(const uint8_t * resp, int len,
default:
printf(" Unknown Format parameter code = 0x%x\n", pc);
is_count = false;
- hex2stdout(bp, pl, 0);
+ hex2str(bp, pl, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
}
if (is_count) {
@@ -4543,7 +4546,7 @@ show_dt_device_status_page(const uint8_t * resp, int len,
int num, pl, pc, j;
const uint8_t * bp;
char str[PCB_STR_LEN];
- char b[64];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("DT device status page (ssc-3, adc-3) [0x11]\n");
@@ -4621,7 +4624,8 @@ show_dt_device_status_page(const uint8_t * resp, int len,
pl);
break;
}
- hex2stdout(bp + 4, 8, 1);
+ hex2str(bp + 4, 8, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
case 0x3:
printf(" Key management error data (hex only now):\n");
@@ -4634,7 +4638,8 @@ show_dt_device_status_page(const uint8_t * resp, int len,
pl);
break;
}
- hex2stdout(bp + 4, 12, 1);
+ hex2str(bp + 4, 12, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
default:
if ((pc >= 0x101) && (pc <= 0x1ff)) {
@@ -4651,14 +4656,20 @@ show_dt_device_status_page(const uint8_t * resp, int len,
sg_get_unaligned_be64(bp + 8));
} else {
printf(" non-SAS transport, in hex:\n");
- hex2stdout(bp + 4, ((pl < num) ? pl : num) - 4, 0);
+ hex2str(bp + 4, ((pl < num) ? pl : num) - 4, " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
} else if (pc >= 0x8000) {
printf(" Vendor specific [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
} else {
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
}
break;
}
@@ -4681,6 +4692,7 @@ show_tapealert_response_page(const uint8_t * resp, int len,
int num, pl, pc, k, mod, div;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("TapeAlert response page (ssc-3, adc-3) [0x12]\n");
@@ -4721,10 +4733,14 @@ show_tapealert_response_page(const uint8_t * resp, int len,
default:
if (pc <= 0x8000) {
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
} else {
printf(" Vendor specific [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
break;
}
@@ -4770,6 +4786,7 @@ show_requested_recovery_page(const uint8_t * resp, int len,
int num, pl, pc, j, k;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Requested recovery page (ssc-3) [0x13]\n");
@@ -4805,10 +4822,14 @@ show_requested_recovery_page(const uint8_t * resp, int len,
default:
if (pc <= 0x8000) {
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
} else {
printf(" Vendor specific [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
break;
}
@@ -4832,6 +4853,7 @@ show_ata_pt_results_page(const uint8_t * resp, int len,
const uint8_t * bp;
const uint8_t * dp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("ATA pass-through results page (sat-2) [0x16]\n");
@@ -4869,11 +4891,15 @@ show_ata_pt_results_page(const uint8_t * resp, int len,
printf(" device=0x%x status=0x%x\n", dp[12], dp[13]);
} else if (pl > 17) {
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
} else {
printf(" short parameter length: %d [parameter_code=0x%x]:\n",
pl, pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
if (op->do_pcb)
printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
@@ -4921,6 +4947,7 @@ show_background_scan_results_page(const uint8_t * resp, int len,
int j, m, num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Background scan results page [0x15]\n");
@@ -4987,7 +5014,9 @@ show_background_scan_results_page(const uint8_t * resp, int len,
else
printf(" Medium scan parameter # %d [0x%x], "
"reserved\n", pc, pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
} else
printf(" Medium scan parameter # %d [0x%x]\n", pc, pc);
@@ -5050,6 +5079,7 @@ show_zoned_block_dev_stats(const uint8_t * resp, int len,
int num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Zoned block device statistics page [0x14,0x1]\n");
@@ -5196,7 +5226,9 @@ show_zoned_block_dev_stats(const uint8_t * resp, int len,
break;
default:
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
}
if (trunc)
@@ -5299,6 +5331,7 @@ show_background_op_page(const uint8_t * resp, int len,
int num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Background operation page [0x15,0x2]\n");
@@ -5334,7 +5367,9 @@ show_background_op_page(const uint8_t * resp, int len,
break;
default:
printf(" Reserved [parameter_code=0x%x]:\n", pc);
- hex2stdout(bp, ((pl < num) ? pl : num), 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
}
if (op->do_pcb)
@@ -5357,6 +5392,7 @@ show_lps_misalignment_page(const uint8_t * resp, int len,
int num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("LPS misalignment page [0x15,0x3]\n");
@@ -5396,7 +5432,9 @@ show_lps_misalignment_page(const uint8_t * resp, int len,
pc, bp[4]);
} else {
printf("<unexpected pc=0x%x>\n", pc);
- hex2stdout(bp, pl, 0);
+ hex2str(bp, ((pl < num) ? pl : num), " ",
+ 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
break;
}
@@ -5419,6 +5457,7 @@ show_service_buffer_info_page(const uint8_t * resp, int len,
int num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Service buffer information page (adc-3) [0x15]\n");
@@ -5449,11 +5488,13 @@ show_service_buffer_info_page(const uint8_t * resp, int len,
} else if (pc < 0x8000) {
printf(" parameter_code=0x%x, Reserved, parameter in hex:\n",
pc);
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
} else {
printf(" parameter_code=0x%x, Vendor-specific, parameter in "
"hex:\n", pc);
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
}
if (op->do_pcb)
printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
@@ -5588,6 +5629,7 @@ show_device_stats_page(const uint8_t * resp, int len,
int num, pl, pc;
const uint8_t * bp;
char str[PCB_STR_LEN];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Device statistics page (ssc-3 and adc)\n");
@@ -5719,7 +5761,9 @@ show_device_stats_page(const uint8_t * resp, int len,
default:
vl_num = false;
printf(" Reserved parameter code [0x%x] data in hex:\n", pc);
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
break;
}
if (vl_num)
@@ -5742,7 +5786,9 @@ show_device_stats_page(const uint8_t * resp, int len,
"hex:\n", pc);
else
printf(" Reserved parameter [0x%x], dump in hex:\n", pc);
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
break;
}
}
@@ -5949,11 +5995,11 @@ static bool
show_tape_diag_data_page(const uint8_t * resp, int len,
const struct opts_t * op)
{
- int k, num, pl, pc;
+ int k, n, num, pl, pc;
unsigned int v;
const uint8_t * bp;
char str[PCB_STR_LEN];
- char b[80];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Tape diagnostics data page (ssc-3) [0x16]\n");
@@ -6000,24 +6046,25 @@ show_tape_diag_data_page(const uint8_t * resp, int len,
if (sg_all_zeros(bp + 32, 32))
printf(" Medium id number is 32 bytes of zero\n");
else {
- printf(" Medium id number (in hex):\n");
- hex2stdout(bp + 32, 32, 0);
+ hex2str(bp + 32, 32, " ", 0 /* with ASCII */, sizeof(b), b);
+ printf(" Medium id number (in hex):\n%s", b);
}
printf(" Timestamp origin: 0x%x\n", bp[64] & 0xf);
// Check Timestamp for all zeros
- for (k = 66; k < 72; ++k) {
- if(bp[k])
- break;
- }
- if (72 == k)
+ if (sg_all_zeros(bp + 66, 6))
printf(" Timestamp is all zeros:\n");
else {
- printf(" Timestamp:\n");
- hex2stdout(bp + 66, 6, 1);
+ hex2str(bp + 66, 6, NULL, 1 /* no ASCII */, sizeof(b), b);
+ printf(" Timestamp: %s", b);
}
if (pl > 72) {
+ n = pl - 72;
+ k = hex2str(bp + 72, n, " ", 0 /* with ASCII */,
+ sizeof(b), b);
printf(" Vendor specific:\n");
- hex2stdout(bp + 72, pl - 72, 0);
+ printf("%s", b);
+ if (k >= (int)sizeof(b) - 1)
+ printf(" <truncated>\n");
}
if (op->do_pcb)
printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
@@ -6039,7 +6086,7 @@ show_mchanger_diag_data_page(const uint8_t * resp, int len,
unsigned int v;
const uint8_t * bp;
char str[PCB_STR_LEN];
- char b[80];
+ char b[512];
if (op->verbose || ((! op->do_raw) && (0 == op->do_hex)))
printf("Media changer diagnostics data page (smc-3) [0x16]\n");
@@ -6104,12 +6151,16 @@ show_mchanger_diag_data_page(const uint8_t * resp, int len,
printf(" Destination address: 0x%x\n", v);
if (pl > 91) {
printf(" Volume tag information:\n");
- hex2stdout((bp + 56), 36, 0);
+ hex2str(bp + 56, 36, " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
}
if (pl > 99) {
printf(" Timestamp origin: 0x%x\n", bp[92] & 0xf);
printf(" Timestamp:\n");
- hex2stdout((bp + 94), 6, 1);
+ hex2str(bp + 94, 6, " ", 1 /* no ASCII */,
+ sizeof(b), b);
+ printf("%s", b);
}
if (op->do_pcb)
printf(" <%s>\n", get_pcb_str(bp[2], str, sizeof(str)));
@@ -6202,7 +6253,7 @@ show_volume_stats_pages(const uint8_t * resp, int len,
bool spf;
const uint8_t * bp;
char str[PCB_STR_LEN];
- char b[64];
+ char b[512];
spf = !!(resp[0] & 0x40);
subpg_code = spf ? resp[1] : 0;
@@ -6414,7 +6465,8 @@ show_volume_stats_pages(const uint8_t * resp, int len,
else
printf(" Reserved parameter code (0x%x), payload in hex\n",
pc);
- hex2stdout(bp + 4, pl - 4, 0);
+ hex2str(bp + 4, pl - 4, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
break;
}
if (op->do_pcb)
@@ -6735,6 +6787,7 @@ decode_page_contents(const uint8_t * resp, int len, struct opts_t * op)
bool spf;
bool done = false;
const struct log_elem * lep;
+ char b[512];
if (len < 3) {
pr2serr("%s: response has bad length: %d\n", __func__, len);
@@ -6764,12 +6817,15 @@ decode_page_contents(const uint8_t * resp, int len, struct opts_t * op)
else
printf("Unable to decode page = 0x%x, here is hex:\n", pg_code);
if (len > 128) {
- hex2stdout(resp, 64, 1);
+ hex2str(resp, 64, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
printf(" ..... [truncated after 64 of %d bytes (use '-H' to "
"see the rest)]\n", len);
}
- else
- hex2stdout(resp, len, 1);
+ else {
+ hex2str(resp, len, " ", 1 /* no ASCII */, sizeof(b), b);
+ printf("%s", b);
+ }
}
}
diff --git a/src/sg_modes.c b/src/sg_modes.c
index c0fc87f0..2eead452 100644
--- a/src/sg_modes.c
+++ b/src/sg_modes.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2021 D. Gilbert
+ * Copyright (C) 2000-2022 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -32,7 +32,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.74 20210803";
+static const char * version_str = "1.75 20220202";
#define DEF_ALLOC_LEN (1024 * 4)
#define DEF_6_ALLOC_LEN 252
@@ -880,8 +880,7 @@ static const char *
find_page_code_desc(int page_num, int subpage_num, int scsi_ptype,
bool encserv, bool mchngr, int t_proto)
{
- int k;
- int num;
+ int k, num, decayed_pdt;
const struct page_code_desc * pcdp;
if (t_proto >= 0) {
@@ -896,6 +895,7 @@ find_page_code_desc(int page_num, int subpage_num, int scsi_ptype,
}
}
}
+try_again:
pcdp = get_mpage_tbl_size(scsi_ptype, &num);
if (pcdp) {
for (k = 0; k < num; ++k, ++pcdp) {
@@ -906,6 +906,11 @@ find_page_code_desc(int page_num, int subpage_num, int scsi_ptype,
break;
}
}
+ decayed_pdt = sg_lib_pdt_decay(scsi_ptype);
+ if (decayed_pdt != scsi_ptype) {
+ scsi_ptype = decayed_pdt;
+ goto try_again;
+ }
if ((0xd != scsi_ptype) && encserv) {
/* check for attached enclosure services processor */
pcdp = get_mpage_tbl_size(0xd, &num);
diff --git a/src/sg_rep_zones.c b/src/sg_rep_zones.c
index 02c8953c..c77bd785 100644
--- a/src/sg_rep_zones.c
+++ b/src/sg_rep_zones.c
@@ -39,11 +39,11 @@
* Based on zbc2r10.pdf
*/
-static const char * version_str = "1.30 20220128";
+static const char * version_str = "1.31 20220201";
#define WILD_RZONES_BUFF_LEN (1 << 28)
-#define MAX_RZONES_BUFF_LEN (1024 * 1024)
-#define DEF_RZONES_BUFF_LEN (1024 * 8)
+#define MAX_RZONES_BUFF_LEN (2 * 1024 * 1024)
+#define DEF_RZONES_BUFF_LEN (1024 * 16)
#define SG_ZONING_IN_CMDLEN 16
@@ -51,6 +51,7 @@ static const char * version_str = "1.30 20220128";
#define REPORT_ZONE_DOMAINS_SA 0x7
#define REPORT_REALMS_SA 0x6
+#define REPORT_ZONES_DESC_LEN 64
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
#define DEF_PT_TIMEOUT 60 /* 60 seconds */
@@ -69,6 +70,7 @@ struct opts_t {
int do_help;
int do_hex;
int do_num;
+ int find_zt; /* negative values: find first not equal to */
int maxlen;
int reporting_opt;
int vb;
@@ -76,12 +78,17 @@ struct opts_t {
const char * in_fn;
};
+struct zt_num2abbrev_t {
+ int ztn;
+ const char * abbrev;
+};
static struct option long_options[] = {
{"brief", no_argument, 0, 'b'}, /* only header and last descriptor */
{"domain", no_argument, 0, 'd'},
{"domains", no_argument, 0, 'd'},
{"force", no_argument, 0, 'f'},
+ {"find", required_argument, 0, 'F'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */
@@ -102,22 +109,58 @@ static struct option long_options[] = {
{0, 0, 0, 0},
};
+static struct zt_num2abbrev_t zt_num2abbrev[] = {
+ {0, "none"},
+ {1, "c"}, /* conventionial */
+ {2, "swr"}, /* sequential write required */
+ {3, "swp"}, /* sequential write preferred */
+ {4, "sobr"}, /* sequential or before required */
+ {5, "g"}, /* gap */
+ {-1, NULL}, /* sentinel */
+};
+
+static const char * zn_dnum_s = "zone descriptor number: ";
+
+
+static void
+prn_zone_type_abbrevs(void)
+{
+ const struct zt_num2abbrev_t * n2ap = zt_num2abbrev;
+ char b[32];
+
+ pr2serr("Zone type number\tAbbreviation\tName\n");
+ pr2serr("----------------\t------------\t----\n");
+ for ( ; n2ap->abbrev; ++n2ap) {
+ if (n2ap == zt_num2abbrev)
+ pr2serr("\t%d\t\t%s\t\t[reserved]\n",
+ n2ap->ztn, n2ap->abbrev);
+ else
+ pr2serr("\t%d\t\t%s\t\t%s\n", n2ap->ztn, n2ap->abbrev,
+ sg_get_zone_type_str(n2ap->ztn, sizeof(b), b));
+ }
+}
static void
usage(int h)
{
if (h > 1) goto h_twoormore;
pr2serr("Usage: "
- "sg_rep_zones [--domain] [--force] [--help] [--hex] "
- "[--inhex=FN]\n"
- " [--locator=LBA] [--maxlen=LEN] "
- "[--partial] [--only]\n"
- " [--raw] [--readonly] [--realm] "
- "[--report=OPT]\n"
- " [--start=LBA] [--verbose] [--version] "
- "DEVICE\n");
+ "sg_rep_zones [--domain] [--find=ZT] [--force] [--help] "
+ "[--hex]\n"
+ " [--inhex=FN] [--locator=LBA] "
+ "[--maxlen=LEN]\n"
+ " [--partial] [--only] [--raw] "
+ "[--readonly]\n"
+ " [--realm] [--report=OPT] [--start=LBA] "
+ "[--verbose]\n"
+ " [--version] DEVICE\n");
pr2serr(" where:\n"
" --domain|-d sends a REPORT ZONE DOMAINS command\n"
+ " --find=ZT|-F ZT find first zone with ZT zone type, "
+ "starting at LBA\n"
+ " if first character of ZT is - or !, "
+ "find first\n"
+ " zone that is not ZT\n"
" --force|-f bypass some sanity checks when decoding "
"response\n"
" --help|-h print out usage message, use twice for "
@@ -186,6 +229,8 @@ h_twoormore:
"Required zones\n"
" 0x3 list all realms that contain active Sequential Write "
"Preferred zones\n");
+ pr2serr("\n");
+ prn_zone_type_abbrevs();
}
/* Invokes a SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT REALMS command
@@ -317,18 +362,44 @@ static const char * same_desc_arr[16] = {
"Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
};
+static uint64_t
+prt_a_zn_desc(const uint8_t *bp, const struct opts_t * op)
+{
+ uint8_t zt, zc;
+ uint64_t lba, len, wp;
+ char b[80];
+
+ zt = bp[0] & 0xf;
+ zc = (bp[1] >> 4) & 0xf;
+ printf(" Zone type: %s\n", sg_get_zone_type_str(zt, sizeof(b), b));
+ printf(" Zone condition: %s\n", zone_condition_str(zc, b,
+ sizeof(b), op->vb));
+ printf(" PUEP: %d\n", !!(bp[1] & 0x4)); /* added in zbc2r07 */
+ printf(" Non_seq: %d\n", !!(bp[1] & 0x2));
+ printf(" Reset: %d\n", bp[1] & 0x1);
+ len = sg_get_unaligned_be64(bp + 8);
+ printf(" Zone Length: 0x%" PRIx64 "\n", len);
+ lba = sg_get_unaligned_be64(bp + 16);
+ printf(" Zone start LBA: 0x%" PRIx64 "\n", lba);
+ wp = sg_get_unaligned_be64(bp + 24);
+ if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
+ printf(" Write pointer LBA: -1\n");
+ else
+ printf(" Write pointer LBA: 0x%" PRIx64 "\n", wp);
+ return lba + len;
+}
+
static int
decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
const struct opts_t * op)
{
- uint8_t zt;
- int k, same, zc, num_zd;
- uint64_t wp, ul, ul2, mx_lba;
+ int k, same, num_zd;
+ uint64_t wp, ul, mx_lba;
const uint8_t * bp;
- char b[80];
if ((uint32_t)act_len < decod_len) {
- num_zd = (act_len >= 64) ? ((act_len - 64) / 64): 0;
+ num_zd = (act_len >= 64) ? ((act_len - 64) / REPORT_ZONES_DESC_LEN)
+ : 0;
if (act_len == op->maxlen) {
if (op->maxlen_given)
pr2serr("decode length [%u bytes] may be constrained by "
@@ -338,10 +409,15 @@ decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
} else if (op->in_fn)
pr2serr("perhaps %s has been truncated\n", op->in_fn);
} else
- num_zd = (decod_len - 64) / 64;
+ num_zd = (decod_len - 64) / REPORT_ZONES_DESC_LEN;
same = rzBuff[4] & 0xf;
mx_lba = sg_get_unaligned_be64(rzBuff + 8);
- if (! op->wp_only) {
+ if (op->wp_only) {
+ ;
+ } else if (op->do_hex) {
+ hex2stdout(rzBuff, 64, -1);
+ printf("\n");
+ } else {
printf(" Same=%d: %s\n", same, same_desc_arr[same]);
printf(" Maximum LBA: 0x%" PRIx64 "\n\n", mx_lba);
printf(" Reported zone starting LBA granularity: 0x%" PRIx64 "\n\n",
@@ -349,61 +425,54 @@ decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len,
}
if (op->do_num > 0)
num_zd = (num_zd > op->do_num) ? op->do_num : num_zd;
- if (((uint32_t)act_len < decod_len) && ((num_zd * 64) + 64 > act_len)) {
+ if (((uint32_t)act_len < decod_len) &&
+ ((num_zd * REPORT_ZONES_DESC_LEN) + 64 > act_len)) {
pr2serr("Skip due to truncated response, try using --num= to a "
"value less than %d\n", num_zd);
return SG_LIB_CAT_MALFORMED;
}
if (op->do_brief && (num_zd > 0)) {
- bp = rzBuff + 64 + ((num_zd - 1) * 64);
+ bp = rzBuff + 64 + ((num_zd - 1) * REPORT_ZONES_DESC_LEN);
+ if (op->do_hex) {
+ if (op->wp_only)
+ hex2stdout(bp + 24, 8, -1);
+ else
+ hex2stdout(bp, 64, -1);
+ return 0;
+ }
printf("From last descriptor in this response:\n");
- ul = sg_get_unaligned_be64(bp + 16);
- printf(" Zone start LBA: 0x%" PRIx64 "\n", ul);
- ul2 = sg_get_unaligned_be64(bp + 8);
- printf(" Zone Length: 0x%" PRIx64 "\n", ul2);
- ul = ul + ul2;
+ printf(" %s%d\n", zn_dnum_s, num_zd - 1);
+ ul = prt_a_zn_desc(bp, op);
if (ul > mx_lba)
- printf(" This zone seems to be the last one\n");
+ printf(" >> This zone seems to be the last one\n");
else
- printf(" Probable next Zone start LBA: 0x%" PRIx64 "\n", ul);
+ printf(" >> Probable next Zone start LBA: 0x%" PRIx64 "\n", ul);
return 0;
}
- for (k = 0, bp = rzBuff + 64; k < num_zd; ++k, bp += 64) {
+ for (k = 0, bp = rzBuff + 64; k < num_zd;
+ ++k, bp += REPORT_ZONES_DESC_LEN) {
if (! op->wp_only)
- printf(" Zone descriptor: %d\n", k);
+ printf(" %s%d\n", zn_dnum_s, k);
if (op->do_hex) {
hex2stdout(bp, 64, -1);
continue;
}
if (op->wp_only) {
- wp = sg_get_unaligned_be64(bp + 24);
- if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
- printf("-1\n");
- else
- printf("0x%" PRIx64 "\n", wp);
+ if (op->do_hex)
+ hex2stdout(bp + 24, 8, -1);
+ else {
+ wp = sg_get_unaligned_be64(bp + 24);
+ if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
+ printf("-1\n");
+ else
+ printf("0x%" PRIx64 "\n", wp);
+ }
continue;
}
- zt = bp[0] & 0xf;
- zc = (bp[1] >> 4) & 0xf;
- printf(" Zone type: %s\n", sg_get_zone_type_str(zt, sizeof(b),
- b));
- printf(" Zone condition: %s\n", zone_condition_str(zc, b,
- sizeof(b), op->vb));
- printf(" PUEP: %d\n", !!(bp[1] & 0x4)); /* added in zbc2r07 */
- printf(" Non_seq: %d\n", !!(bp[1] & 0x2));
- printf(" Reset: %d\n", bp[1] & 0x1);
- printf(" Zone Length: 0x%" PRIx64 "\n",
- sg_get_unaligned_be64(bp + 8));
- printf(" Zone start LBA: 0x%" PRIx64 "\n",
- sg_get_unaligned_be64(bp + 16));
- wp = sg_get_unaligned_be64(bp + 24);
- if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp)))
- printf(" Write pointer LBA: -1\n");
- else
- printf(" Write pointer LBA: 0x%" PRIx64 "\n", wp);
+ prt_a_zn_desc(bp, op);
}
- if ((op->do_num == 0) && (! op->wp_only)) {
- if ((64 + (64 * (uint32_t)num_zd)) < decod_len)
+ if ((op->do_num == 0) && (! op->wp_only) && (! op->do_hex)) {
+ if ((64 + (REPORT_ZONES_DESC_LEN * (uint32_t)num_zd)) < decod_len)
printf("\n>>> Beware: Zone list truncated, may need another "
"call\n");
}
@@ -532,11 +601,89 @@ decode_rep_zdomains(const uint8_t * rzBuff, int act_len,
return 0;
}
+static int
+find_report_zones(int sg_fd, uint8_t * rzBuff, const char * cmd_name,
+ struct opts_t * op)
+{
+ bool found = false;
+ uint8_t zt;
+ int k, res, resid, rlen, num_zd;
+ uint32_t zn_dnum = 0;
+ uint64_t slba = op->st_lba;
+ uint64_t mx_lba = 0;
+ const uint8_t * bp = rzBuff;
+ char b[96];
+
+ k = 0;
+ while (true) {
+ resid = 0;
+ res = sg_ll_report_zzz(sg_fd, REPORT_ZONES_SA, slba,
+ true /* set partial */, op->reporting_opt,
+ rzBuff, op->maxlen, &resid, true, op->vb);
+ if (res) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ pr2serr("%s: %s%u, %s command not supported\n", __func__,
+ zn_dnum_s, zn_dnum, cmd_name);
+ else {
+ sg_get_category_sense_str(res, sizeof(b), b, op->vb);
+ pr2serr("%s: %s%u, %s command: %s\n", __func__,
+ zn_dnum_s, zn_dnum, cmd_name, b);
+ }
+ break;
+ }
+ rlen = op->maxlen - resid;
+ if (rlen <= 64) {
+ break;
+ }
+ mx_lba = sg_get_unaligned_be64(rzBuff + 8);
+ num_zd = (rlen - 64) / REPORT_ZONES_DESC_LEN;
+ for (k = 0, bp = rzBuff + 64; k < num_zd;
+ ++k, bp += REPORT_ZONES_DESC_LEN, ++zn_dnum) {
+ zt = 0xf & bp[0];
+ if (op->find_zt > 0) {
+ if ((uint8_t)op->find_zt == zt )
+ break;
+ } else if (op->find_zt < 0) {
+ if ((uint8_t)(-op->find_zt) != zt )
+ break;
+ }
+ slba = sg_get_unaligned_be64(bp + 16) +
+ sg_get_unaligned_be64(bp + 8);
+ }
+ if (k < num_zd) {
+ found = true;
+ break;
+ } else if (slba > mx_lba)
+ break;
+ }
+ if (res == 0) {
+ if (found) {
+ if (op->do_hex) {
+ hex2stdout(rzBuff, 64, -1);
+ printf("\n");
+ hex2stdout(bp, 64, -1);
+ } else {
+ printf("Condition met at:\n");
+ printf(" %s: %d\n", zn_dnum_s, zn_dnum);
+ prt_a_zn_desc(bp, op);
+ }
+ } else {
+ if (op->do_hex) {
+ memset(b, 0xff, 64);
+ hex2stdout((const uint8_t *)b, 64, -1);
+ } else
+ printf("Condition NOT met; next %s%u\n", zn_dnum_s, zn_dnum);
+ }
+ }
+ return res;
+}
+
+
int
main(int argc, char * argv[])
{
bool no_final_msg = false;
- int res, c, act_len, rlen, in_len;
+ int res, c, act_len, rlen, in_len, off;
int sg_fd = -1;
int resid = 0;
int ret = 0;
@@ -555,8 +702,8 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "bdefhHi:l:m:n:o:prRs:vVw", long_options,
- &option_index);
+ c = getopt_long(argc, argv, "bdefF:hHi:l:m:n:o:prRs:vVw",
+ long_options, &option_index);
if (c == -1)
break;
@@ -575,6 +722,31 @@ main(int argc, char * argv[])
case 'f':
op->do_force = true;
break;
+ case 'F':
+ off = (('-' == *optarg) || ('!' == *optarg)) ? 1 : 0;
+ if (isdigit(*(optarg + off))) {
+ op->find_zt = sg_get_num_nomult(optarg + off);
+ if (op->find_zt < 0) {
+ pr2serr("bad numeric argument to '--find='\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (off)
+ op->find_zt = -op->find_zt; /* find first not equal */
+ } else { /* check for abbreviation */
+ struct zt_num2abbrev_t * zn2ap = zt_num2abbrev;
+
+ for ( ; zn2ap->abbrev; ++zn2ap) {
+ if (0 == strcmp(optarg + off, zn2ap->abbrev))
+ break;
+ }
+ if (NULL == zn2ap->abbrev) {
+ pr2serr("bad abbreviation argument to '--find='\n\n");
+ prn_zone_type_abbrevs();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ op->find_zt = off ? -zn2ap->ztn : zn2ap->ztn;
+ }
+ break;
case 'h':
case '?':
++op->do_help;
@@ -758,6 +930,10 @@ main(int argc, char * argv[])
goto the_end;
}
+ if (op->find_zt) { /* so '-F none' will drop through */
+ ret = find_report_zones(sg_fd, rzBuff, cmd_name, op);
+ goto the_end;
+ }
res = sg_ll_report_zzz(sg_fd, serv_act, op->st_lba, op->do_partial,
op->reporting_opt, rzBuff, op->maxlen, &resid,
true, op->vb);
@@ -782,7 +958,8 @@ start_response:
if ((REPORT_ZONES_SA == serv_act) && (! op->do_partial)) {
printf("%u zones starting from LBA 0x%" PRIx64 " available "
"but only %d zones returned\n",
- (decod_len - 64) / 64, op->st_lba, (rlen - 64) / 64);
+ (decod_len - 64) / REPORT_ZONES_DESC_LEN, op->st_lba,
+ (rlen - 64) / REPORT_ZONES_DESC_LEN);
decod_len = rlen;
act_len = rlen;
} else {
@@ -806,7 +983,7 @@ start_response:
hex2stdout(rzBuff, act_len, ((1 == op->do_hex) ? 1 : -1));
goto the_end;
}
- if (! op->wp_only)
+ if (! op->wp_only && (! op->do_hex))
printf("%s response:\n", cmd_name);
if (act_len < 64) {
pr2serr("Zone length [%d] too short (perhaps after truncation\n)",
diff --git a/src/sg_senddiag.c b/src/sg_senddiag.c
index 6539d79d..7e82dd47 100644
--- a/src/sg_senddiag.c
+++ b/src/sg_senddiag.c
@@ -1,6 +1,6 @@
/*
* A utility program originally written for the Linux OS SCSI subsystem
- * Copyright (C) 2003-2021 D. Gilbert
+ * Copyright (C) 2003-2022 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -34,7 +34,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "0.64 20210610";
+static const char * version_str = "0.65 20220128";
#define ME "sg_senddiag: "
@@ -836,16 +836,23 @@ main(int argc, char * argv[])
num = sg_msense_calc_length(rsp_buff, 32, false, &bd_len);
num -= (8 /* MS(10) header length */ + bd_len);
if (num >= 0xc) {
- int secs;
-
- secs = sg_get_unaligned_be16(rsp_buff + 8 + bd_len + 10);
+ int secs = sg_get_unaligned_be16(rsp_buff + 8 + bd_len + 10);
+
+ if (0xffff == secs) {
+ if (op->verbose > 1)
+ printf("Expected extended self-test duration's value "
+ "[65535] indicates the\nsimilarly named field "
+ "in the Extended Inquiry VPD page should be "
+ "used\n");
+ } else {
#ifdef SG_LIB_MINGW
- printf("Expected extended self-test duration=%d seconds "
- "(%g minutes)\n", secs, secs / 60.0);
+ printf("Expected extended self-test duration=%d seconds "
+ "(%g minutes)\n", secs, secs / 60.0);
#else
- printf("Expected extended self-test duration=%d seconds "
- "(%.2f minutes)\n", secs, secs / 60.0);
+ printf("Expected extended self-test duration=%d seconds "
+ "(%.2f minutes)\n", secs, secs / 60.0);
#endif
+ }
} else
printf("Extended self-test duration not available\n");
} else {
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index 5f361d7b..1d396eb0 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2021 D. Gilbert
+ * Copyright (C) 2018-2022 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -60,7 +60,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 1.20 20210406";
+static const char * version_str = "Version: 1.21 20220202";
#define INQ_REPLY_LEN 128
#define INQ_CMD_LEN 6
@@ -193,7 +193,7 @@ timespec_diff(const struct timespec *lhs_p, const struct timespec *rhs_p,
}
/* Returns 0 on success. */
-int timespec2str(char *buf, uint len, struct timespec *ts)
+int timespec2str(char *buf, unsigned int len, struct timespec *ts)
{
int ret;
struct tm t;