aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COVERAGE2
-rw-r--r--ChangeLog5
-rw-r--r--README17
-rw-r--r--README.freebsd3
-rw-r--r--README.solaris3
-rw-r--r--README.win323
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg3_utils.818
-rw-r--r--include/sg_lib.h29
-rw-r--r--lib/sg_lib.c126
-rw-r--r--lib/sg_lib_data.c2
-rw-r--r--sg3_utils.spec2
-rw-r--r--testing/Makefile30
-rw-r--r--testing/README35
-rw-r--r--testing/sg_tst_async.cpp46
-rw-r--r--testing/sgh_dd.cpp133
-rw-r--r--testing/uapi_sg.h7
17 files changed, 337 insertions, 126 deletions
diff --git a/COVERAGE b/COVERAGE
index e78c20b0..00ce453f 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -159,4 +159,4 @@ THIRD PARTY COPY IN (0x83).
Douglas Gilbert
-28th May 2019
+28th August 2019
diff --git a/ChangeLog b/ChangeLog
index a738c36c..3546ab8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.45 [20190828] [svn: r830]
+Changelog for sg3_utils-1.45 [20190905] [svn: r831]
- sg_get_elem_status: new utility [sbc4r16]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
@@ -44,6 +44,8 @@ Changelog for sg3_utils-1.45 [20190828] [svn: r830]
- add ${PACKAGE_VERSION} to '.so' name
- add sg_f2hex_arr()
- update some tables for NVMe 1.4
+ - sg_get_num()+sg_get_llnum(): add 'e' decoding,
+ exabytes; allow addition (e.g. --count=3+1k)
- sg_pt_freebsd: fixes for FreeBSD 12.0 release
- scripts: update 54-before-scsi-sg3_id.rules,
scsi-enable-target-scan.sh and
@@ -58,6 +60,7 @@ Changelog for sg3_utils-1.45 [20190828] [svn: r830]
- testing/sg_tst_bidi: for sg 4.0 driver
- testing/sgh_dd: test request sharing, mreqs...
- testing/sgs_dd: back from archive, for testing
+ - 'make' now builds both C and C++ programs
SIGPOLL (SIGIO) and realtime (RT) signals
- sg_pt: add sg_get_opcode_translation() to replace
global pointer to array: sg_opcode_info_arr[]
diff --git a/README b/README
index fcf86847..1a68d8b3 100644
--- a/README
+++ b/README
@@ -259,13 +259,14 @@ Here is list in alphabetical order of utilities found in the 'src'
subdirectory of the sg3_utils package:
sginfo, sg_bt_ctl, sg_compare_and_write, sg_copy_results, sgm_dd, sgp_dd,
sg_dd, sg_decode_sense, sg_emc_trespass, sg_format, sg_get_config,
- sg_get_lba_status, sg_ident, sg_inq, sg_logs, sg_luns, sg_map, sg_map26,
- sg_modes, sg_opcodes, sg_persist, sg_prevent, sg_raw, sg_rbuf, sg_rdac,
- sg_read, sg_read_attr, sg_readcap, sg_read_block_limits, sg_read_buffer,
- sg_read_long, sg_reassign, sg_referrals, sg_request, sg_reset, sg_rmsn,
- sg_rtpg, sg_safte, sg_sanitize, sg_sat_identify, sg_sat_phy_event,
- sg_sat_read_gplog, sg_sat_set_features, sg_scan, sg_seek, sg_senddiag,
- sg_ses, sg_ses_microcode, sg_start, sg_stpg, sg_stream_ctl, sg_sync,
+ sg_get_elem_status, sg_get_lba_status, sg_ident, sg_inq, sg_logs,
+ sg_luns, sg_map, sg_map26, sg_modes, sg_opcodes, sg_persist, sg_prevent,
+ sg_raw, sg_rbuf, sg_rdac, sg_read, sg_read_attr, sg_readcap,
+ sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign,
+ sg_referrals, sg_request, sg_reset, sg_rmsn, sg_rtpg, sg_safte,
+ sg_sanitize, sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog,
+ sg_sat_set_features, sg_scan, sg_seek, sg_senddiag, sg_ses,
+ sg_ses_microcode, sg_start, sg_stpg, sg_stream_ctl, sg_sync,
sg_test_rwbuff, sg_timestamp, sg_turs, sg_unmap, sg_verify, sg_vpd,
sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify,
sg_write_x, sg_wr_mode, sg_xcopy, sg_zone
@@ -541,4 +542,4 @@ See http://sg.danny.cz/sg/tools.html
Douglas Gilbert
-29th April 2019
+9th September 2019
diff --git a/README.freebsd b/README.freebsd
index 7ca25e9a..4a720a79 100644
--- a/README.freebsd
+++ b/README.freebsd
@@ -18,6 +18,7 @@ Here is a list of utilities that have been ported:
sg_decode_sense
sg_format
sg_get_config
+ sg_get_elem_status
sg_get_lba_status
sg_ident
sg_inq [dropped ATA IDENTIFY DEVICE capability]
@@ -142,4 +143,4 @@ utilities.
Douglas Gilbert
-27th January 2018
+9th September 2019
diff --git a/README.solaris b/README.solaris
index 15e6fec5..dac22dc4 100644
--- a/README.solaris
+++ b/README.solaris
@@ -35,6 +35,7 @@ Here is a list of utilities that have been ported:
sg_decode_sense
sg_format
sg_get_config
+ sg_get_elem_status
sg_get_lba_status
sg_ident
sg_inq [dropped ATA IDENTIFY DEVICE capability]
@@ -163,4 +164,4 @@ disks to accept SCSI commands including the SCSI ATA PASS THROUGH commands.
Douglas Gilbert
-27th January 2018
+9th September 2019
diff --git a/README.win32 b/README.win32
index 41173b69..47115253 100644
--- a/README.win32
+++ b/README.win32
@@ -38,6 +38,7 @@ Here is a list of utilities that have been ported:
sg_decode_sense
sg_format
sg_get_config
+ sg_get_elem_status
sg_get_lba_status
sg_ident
sg_inq [dropped ATA IDENTIFY DEVICE capability]
@@ -242,4 +243,4 @@ mode" with the setmode() Windows command.
Douglas Gilbert
-27th January 2018
+9th September 2019
diff --git a/debian/changelog b/debian/changelog
index ea6f8985..fe0326f4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.45-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Wed, 28 Aug 2019 13:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Mon, 09 Sep 2019 15:00:00 -0400
sg3-utils (1.44-0.1) unstable; urgency=low
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index d62e0dba..54eeaa74 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "August 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG3_UTILS "8" "September 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
@@ -676,13 +676,21 @@ An example is "2k" for 2048. The large tera and peta suffixes are only
available for numeric arguments that might require 64 bits to represent
internally.
.PP
-A suffix of the form "x<n>" multiplies the leading number by <n>. An
-example is "2x33" for "66". The leading number cannot be "0" (zero) as
-that would be interpreted as a hexadecimal number (see below).
-.PP
These multiplicative suffixes are compatible with GNU's dd command (since
2002) which claims compliance with SI and with IEC 60027\-2.
.PP
+A suffix of the form "x<n>" multiplies the preceding number by <n>. An
+example is "2x33" for "66". The left argument cannot be '0' as '0x' will
+be interpreted as hexadecimal number prefix (see below). The left
+argument to the multiplication must end in a hexadecimal digit (i.e.
+0 to f) and the whole expression cannot have any embedded whitespace (e.g.
+spaces). An ugly example: "0xfx0x2" for 30.
+.PP
+A suffix of the form "+<n>" adds the preceding number to <n>. An example
+is "3+1k" for "1027". The left argument to the addition must end in a
+hexadecimal digit (i.e. 0 to f) and the whole expression cannot have any
+embedded whitespace (e.g. spaces). Another example: "0xf+0x2" for 17.
+.PP
Alternatively numerical arguments can be given in hexadecimal. There are
two syntaxes. The number can be preceded by either "0x" or "0X" as found
in the C programming language. The second hexadecimal representation is a
diff --git a/include/sg_lib.h b/include/sg_lib.h
index f1256794..c762d3a2 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -613,13 +613,14 @@ int sg_ata_get_chars(const uint16_t * word_arr, int start_word,
void dWordHex(const uint16_t * words, int num, int no_ascii, bool swapb);
/* If the number in 'buf' can not be decoded or the multiplier is unknown
- * then -1 is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
- * suffix. Otherwise a decimal multiplier suffix may be given. Recognised
- * multipliers: c C *1; w W *2; b B *512; k K KiB *1,024;
- * KB *1,000; m M MiB *1,048,576; MB *1,000,000; g G GiB *1,073,741,824;
- * GB *1,000,000,000 and <n>x<m> which multiplies <n> by <m> . Ignore leading
- * spaces and tabs; accept comma, hyphen, space, tab and hash as terminator.
- */
+ * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
+ * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
+ * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and
+ * tabs; accept comma, hyphen, space, tab and hash as terminator.
+ * Handles zero and positive values up to 2**31-1 .
+ * Experimental: left argument (must in with hexadecimal digit) added
+ * to, or multiplied, by right argument. No embedded spaces.
+ * Examples: '3+1k' (evaluates to 1027) and '0xf+0x3'. */
int sg_get_num(const char * buf);
/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
@@ -630,12 +631,14 @@ int sg_get_num(const char * buf);
int sg_get_num_nomult(const char * buf);
/* If the number in 'buf' can not be decoded or the multiplier is unknown
- * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
- * suffix. Otherwise a decimal multiplier suffix may be given. In addition
- * to supporting the multipliers of sg_get_num(), this function supports:
- * t T TiB *(2**40); TB *(10**12); p P PiB *(2**50); PB *(10**15) .
- * Ignore leading spaces and tabs; accept comma, hyphen, space, tab and hash
- * as terminator. */
+ * then -1LL is returned. Accepts a hex prefix (0x or 0X), hex suffix
+ * (h or H), or a decimal multiplier suffix (as per GNU's dd (since 2002:
+ * SI and IEC 60027-2)). Main (SI) multipliers supported: K, M, G, T, P
+ * and E. Ignore leading spaces and tabs; accept comma, hyphen, space, tab
+ * and hash as terminator. Handles zero and positive values up to 2**63-1 .
+ * Experimental: left argument (must in with hexadecimal digit) added
+ * to, or multipled by right argument. No embedded spaces.
+ * Examples: '3+1k' (evaluates to 1027) and '0xf+0x3'. */
int64_t sg_get_llnum(const char * buf);
/* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index d187d8d3..f6095f80 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -3065,18 +3065,24 @@ dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb)
printf("%.76s\n", buff);
}
-/* If the number in 'buf' can be decoded or the multiplier is unknown
+/* If the number in 'buf' can not be decoded or the multiplier is unknown
* then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
* multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
* Main (SI) multipliers supported: K, M, G. Ignore leading spaces and
- * tabs; accept comma, hyphen, space, tab and hash as terminator. */
+ * tabs; accept comma, hyphen, space, tab and hash as terminator.
+ * Handles zero and positive values up to 2**31-1 .
+ * Experimental: left argument (must in with hexadecimal digit) added
+ * to, or multiplied, by right argument. No embedded spaces.
+ * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */
int
sg_get_num(const char * buf)
{
+ bool is_hex = false;
int res, num, n, len;
unsigned int unum;
char * cp;
const char * b;
+ const char * b2p;
char c = 'c';
char c2 = '\0'; /* keep static checker happy */
char c3 = '\0'; /* keep static checker happy */
@@ -3103,24 +3109,35 @@ sg_get_num(const char * buf)
b = lb;
} else
b = buf;
+
+ b2p = b;
if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
- res = sscanf(b + 2, "%x", &unum);
+ res = sscanf(b + 2, "%x%c", &unum, &c);
num = unum;
+ is_hex = true;
+ b2p = b + 2;
} else if ('H' == toupper((int)b[len - 1])) {
res = sscanf(b, "%x", &unum);
num = unum;
} else
res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3);
+
if (res < 1)
- return -1LL;
+ return -1;
else if (1 == res)
return num;
else {
+ c = toupper((int)c);
+ if (is_hex) {
+ if (! ((c == '+') || (c == 'X')))
+ return -1;
+ }
if (res > 2)
c2 = toupper((int)c2);
if (res > 3)
c3 = toupper((int)c3);
- switch (toupper((int)c)) {
+
+ switch (c) {
case 'C':
return num;
case 'W':
@@ -3151,16 +3168,26 @@ sg_get_num(const char * buf)
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1073741824;
return -1;
- case 'X':
- cp = (char *)strchr(b, 'x');
+ case 'X': /* experimental: multiplication */
+ /* left argument must end with hexadecimal digit */
+ cp = (char *)strchr(b2p, 'x');
if (NULL == cp)
- cp = (char *)strchr(b, 'X');
+ cp = (char *)strchr(b2p, 'X');
if (cp) {
n = sg_get_num(cp + 1);
if (-1 != n)
return num * n;
}
return -1;
+ case '+': /* experimental: addition */
+ /* left argument must end with hexadecimal digit */
+ cp = (char *)strchr(b2p, '+');
+ if (cp) {
+ n = sg_get_num(cp + 1);
+ if (-1 != n)
+ return num + n;
+ }
+ return -1;
default:
pr2ws("unrecognized multiplier\n");
return -1;
@@ -3200,19 +3227,25 @@ sg_get_num_nomult(const char * buf)
return -1;
}
-/* If the number in 'buf' can be decoded or the multiplier is unknown
- * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal
- * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
- * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces
- * and tabs; accept comma, hyphen, space, tab and hash as terminator. */
+/* If the number in 'buf' can not be decoded or the multiplier is unknown
+ * then -1LL is returned. Accepts a hex prefix (0x or 0X), hex suffix
+ * (h or H), or a decimal multiplier suffix (as per GNU's dd (since 2002:
+ * SI and IEC 60027-2)). Main (SI) multipliers supported: K, M, G, T, P
+ * and E. Ignore leading spaces and tabs; accept comma, hyphen, space, tab
+ * and hash as terminator. Handles zero and positive values up to 2**63-1 .
+ * Experimental: left argument (must in with hexadecimal digit) added
+ * to, or multiplied by right argument. No embedded spaces.
+ * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */
int64_t
sg_get_llnum(const char * buf)
{
+ bool is_hex = false;
int res, len, n;
int64_t num, ll;
uint64_t unum;
char * cp;
const char * b;
+ const char * b2p;
char c = 'c';
char c2 = '\0'; /* keep static checker happy */
char c3 = '\0'; /* keep static checker happy */
@@ -3239,63 +3272,74 @@ sg_get_llnum(const char * buf)
b = lb;
} else
b = buf;
+
+ b2p = b;
if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
- res = sscanf(b + 2, "%" SCNx64 , &unum);
+ res = sscanf(b + 2, "%" SCNx64 "%c", &unum, &c);
num = unum;
+ is_hex = true;
+ b2p = b + 2;
} else if ('H' == toupper((int)b[len - 1])) {
res = sscanf(b, "%" SCNx64 , &unum);
num = unum;
} else
res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
+
if (res < 1)
return -1LL;
else if (1 == res)
return num;
else {
+ c = toupper((int)c);
+ if (is_hex) {
+ if (! ((c == '+') || (c == 'X')))
+ return -1;
+ }
if (res > 2)
c2 = toupper((int)c2);
if (res > 3)
c3 = toupper((int)c3);
- switch (toupper((int)c)) {
+
+ switch (c) {
case 'C':
return num;
case 'W':
return num * 2;
case 'B':
return num * 512;
- case 'K':
+ case 'K': /* kilo or kibi */
if (2 == res)
return num * 1024;
if (('B' == c2) || ('D' == c2))
return num * 1000;
if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1024;
+ return num * 1024; /* KiB */
return -1LL;
- case 'M':
+ case 'M': /* mega or mebi */
if (2 == res)
- return num * 1048576;
+ return num * 1048576; /* M */
if (('B' == c2) || ('D' == c2))
- return num * 1000000;
+ return num * 1000000; /* MB */
if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1048576;
+ return num * 1048576; /* MiB */
return -1LL;
- case 'G':
+ case 'G': /* giga or gibi */
if (2 == res)
- return num * 1073741824;
+ return num * 1073741824; /* G */
if (('B' == c2) || ('D' == c2))
- return num * 1000000000;
+ return num * 1000000000; /* GB */
if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1073741824;
+ return num * 1073741824; /* GiB */
return -1LL;
- case 'T':
+ case 'T': /* tera or tebi */
if (2 == res)
- return num * 1099511627776LL;
+ return num * 1099511627776LL; /* T */
if (('B' == c2) || ('D' == c2))
- return num * 1000000000000LL;
+ return num * 1000000000000LL; /* TB */
if (('I' == c2) && (4 == res) && ('B' == c3))
- return num * 1099511627776LL;
+ return num * 1099511627776LL; /* TiB */
return -1LL;
- case 'P':
+ case 'P': /* peta or pebi */
if (2 == res)
return num * 1099511627776LL * 1024;
if (('B' == c2) || ('D' == c2))
@@ -3303,16 +3347,32 @@ sg_get_llnum(const char * buf)
if (('I' == c2) && (4 == res) && ('B' == c3))
return num * 1099511627776LL * 1024;
return -1LL;
- case 'X':
- cp = (char *)strchr(b, 'x');
+ case 'E': /* exa or exbi */
+ if (2 == res)
+ return num * 1099511627776LL * 1024 * 1024;
+ if (('B' == c2) || ('D' == c2))
+ return num * 1000000000000LL * 1000 * 1000;
+ if (('I' == c2) && (4 == res) && ('B' == c3))
+ return num * 1099511627776LL * 1024 * 1024;
+ return -1LL;
+ case 'X': /* experimental: decimal (left arg) multiplication */
+ cp = (char *)strchr(b2p, 'x');
if (NULL == cp)
- cp = (char *)strchr(b, 'X');
+ cp = (char *)strchr(b2p, 'X');
if (cp) {
ll = sg_get_llnum(cp + 1);
if (-1LL != ll)
return num * ll;
}
return -1LL;
+ case '+': /* experimental: decimal (left arg) addition */
+ cp = (char *)strchr(b2p, '+');
+ if (cp) {
+ ll = sg_get_llnum(cp + 1);
+ if (-1LL != ll)
+ return num + ll;
+ }
+ return -1LL;
default:
pr2ws("unrecognized multiplier\n");
return -1LL;
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 2ab80e6b..d75168f0 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.67 20190822";/* spc5r22, sbc4r17 */
+const char * sg_lib_version_str = "2.68 20190904";/* spc5r22, sbc4r17 */
/* indexed by pdt; those that map to own index do not decay */
diff --git a/sg3_utils.spec b/sg3_utils.spec
index dfc58d24..379370ca 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Wed Aug 28 2019 - dgilbert at interlog dot com
+* Mon Sep 09 2019 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.45
diff --git a/testing/Makefile b/testing/Makefile
index 26868e92..266a960f 100644
--- a/testing/Makefile
+++ b/testing/Makefile
@@ -5,7 +5,8 @@ INSTDIR=$(DESTDIR)/$(PREFIX)/bin
MANDIR=$(DESTDIR)/$(PREFIX)/man
EXECS = sg_iovec_tst sg_sense_test sg_queue_tst bsg_queue_tst sg_chk_asc \
- sg_tst_nvme sg_tst_ioctl sg_tst_bidi tst_sg_lib sgs_dd
+ sg_tst_nvme sg_tst_ioctl sg_tst_bidi tst_sg_lib sgs_dd sg_tst_excl \
+ sg_tst_excl2 sg_tst_excl3 sg_tst_context sg_tst_async sgh_dd
EXTRAS =
@@ -19,13 +20,15 @@ LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
# For C++/clang testing
## CC = gcc
-## CC = g++
+## CXX = g++
## CC = clang
-## CC = clang++
+## CXX = clang++
+CXXLD = $(CXX)
LD = $(CC)
CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME
+CXXFLAGS = -std=c++17 -pthread -g -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS)
# CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME -DDEBUG
# CFLAGS = -g -O2 -W -Wall
CFLAGS = -g -O2 -W -Wall -DDEBUG
@@ -81,15 +84,30 @@ sg_tst_nvme: sg_tst_nvme.o $(LIBFILESNEW)
tst_sg_lib: tst_sg_lib.o ../lib/sg_lib.o ../lib/sg_lib_data.o
$(LD) -o $@ $(LDFLAGS) $^
-sgh_dd: sgh_dd.o $(LIBFILESNEW)
- $(LD) -o $@ $(LDFLAGS) -pthread $^
-
sgs_dd: sgs_dd.o $(LIBFILESOLD)
$(LD) -o $@ $(LDFLAGS) $^
sg_tst_bidi: sg_tst_bidi.o $(LIBFILESNEW)
$(LD) -o $@ $(LDFLAGS) $^
+sg_tst_excl: sg_tst_excl.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread $^
+
+sg_tst_excl2: sg_tst_excl2.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread $^
+
+sg_tst_excl3: sg_tst_excl3.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread $^
+
+sg_tst_context: sg_tst_context.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread $^
+
+sg_tst_async: sg_tst_async.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread $^
+
+sgh_dd: sgh_dd.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread -latomic $^
+
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/testing/README b/testing/README
index be304dec..5a485576 100644
--- a/testing/README
+++ b/testing/README
@@ -1,3 +1,11 @@
+
+
+The utilities in this directory are _not_ built automatically. So:
+ cd <root_of_sg3_utils_src>
+ ./configure ; make ; make install
+will _not_ build and install them. The make command (or some variant
+of it) needs to be run in this directory as outlined before.
+
Building files in this directory depends on several files being already
built in the ../lib directory. So to build files here, the ./configure
needs to be executed in the parent directory followed by changing
@@ -6,9 +14,14 @@ Another way is to do a top level 'make' after the ./configure which
will make the libraries followed by all the utilities in the src/
directory. To make them in FreeBSD use 'make -f Makefile.freebsd' .
-There is an brief explanation of each example in the README file in
-the main (i.e. this directory's parent) directory. There are also
-some notes at the top of each source file.
+The utilities in this directory do not have manpages. They have
+relatively complete but terse help messages, typically seen by using
+the '--help' option one or more times. If called several times, the
+shorter form of the help option is more convenient, for example: '-hhh'.
+And of course there is the source code. Unfortunately where the code
+implements many different options, it can become a bit dense. There
+is also a large amount of error checking, as many of these utilities
+were used to test new features placed in the sg v4 driver in Linux.
The sg_chk_asc utility decodes the SCSI additional sense code table
found at http://www.t10.org/lists/asc-num.txt and checks it against
@@ -20,10 +33,16 @@ The tst_sg_lib utility exercises several functions found in sg_lib.c
and related files in the 'lib' sibling directory. Use 'tst_sg_lib -h'
to get more information.
-Those files with the extension "cpp" are C++ examples that use facilities
-in C++11. They can be built by calling 'make -f Makefile.cplus'. A
-gcc/g++ compiler of 4.7.3 vintage or later (or a recent clang compiler)
-will be required. To make them in FreeBSD use 'make -f Makefile.cplus_fb'.
+There are both C and C++ files in this directory, they have extensions
+'.c' and '.cpp' respectively. Now both are built with rules in Makefile
+(at least in Linux). Formerly the C++ in Linux required:
+'make -f Makefile.cplus'. A gcc/g++ compiler of 4.7.3 vintage or later
+(or a recent clang compiler) will be required. To make them in FreeBSD
+use 'make -f Makefile.cplus_fb'.
+
+The sgh_dd utility (C++) uses 'libatomic' which may not be installed
+on some systems. On Debian based systems 'apt install libatomic1' fixes
+this.
Douglas Gilbert
-11th October 2018
+2nd September 2019
diff --git a/testing/sg_tst_async.cpp b/testing/sg_tst_async.cpp
index aa05ca95..af7eed87 100644
--- a/testing/sg_tst_async.cpp
+++ b/testing/sg_tst_async.cpp
@@ -89,7 +89,7 @@
#include "sg_pt.h"
#include "sg_cmds.h"
-static const char * version_str = "1.38 20190728";
+static const char * version_str = "1.39 20190902";
static const char * util_name = "sg_tst_async";
/* This is a test program for checking the async usage of the Linux sg
@@ -195,6 +195,7 @@ struct opts_t {
bool generic_sync;
bool masync;
bool mmap_io;
+ bool no_waitq;
bool no_xfer;
bool pack_id_force;
bool sg_vn_ge_40000;
@@ -288,6 +289,9 @@ static struct option long_options[] = {
{"numpt", required_argument, 0, 'n'},
{"num-pt", required_argument, 0, 'n'},
{"num_pt", required_argument, 0, 'n'},
+ {"nowaitq", no_argument, 0, 'z'},
+ {"no_waitq", no_argument, 0, 'z'},
+ {"no-waitq", no_argument, 0, 'z'},
{"noxfer", no_argument, 0, 'N'},
{"override", required_argument, 0, 'O'},
{"pack-id", no_argument, 0, 'p'},
@@ -315,10 +319,11 @@ usage(void)
" [--generic-sync] [--help] [--lba=LBA+] "
"[--lbsz=LBSZ]\n"
" [--masync] [--maxqpt=QPT] [--mmap-io] "
- "[--numpt=NPT]\n"
- " [--noxfer] [--override=OVN] [--pack-id] "
- "[--qat=AT]\n"
- " [-qfav=FAV] [--read] [--stats] [--submit]\n"
+ "[--no-waitq]\n"
+ " [--noxfer] [--numpt=NPT] [--override=OVN] "
+ "[--pack-id]\n"
+ " [--qat=AT] [-qfav=FAV] [--read] [--stats] "
+ "[--submit]\n"
" [--szlb=LB[,NLBS]] [--tnum=NT] [--tur] "
"[--v3] [--v4]\n"
" [--verbose] [--version] [--wait=MS] "
@@ -350,10 +355,12 @@ usage(void)
printf(" --maxqpt=QPT|-M QPT maximum commands queued per thread "
"(def:%d)\n", MAX_Q_PER_FD);
printf(" --mmap-io|-m mmap-ed IO (1 cmd outstanding per thread)\n");
- printf(" --numpt=NPT|-n NPT number of commands per thread "
- "(def: %d)\n", DEF_NUM_PER_THREAD);
+ printf(" --no-waitq|-z set SGV4_FLAG_NO_WAITQ, bypass poll() if "
+ "requested\n");
printf(" --noxfer|-N no data xfer (def: xfer on READ and "
"WRITE)\n");
+ printf(" --numpt=NPT|-n NPT number of commands per thread "
+ "(def: %d)\n", DEF_NUM_PER_THREAD);
printf(" --override OVN|-O OVN override FAV=2 when OVN queue "
"depth\n"
" reached (def: 0 -> no override)\n");
@@ -879,6 +886,11 @@ work_sync_thread(int id, const char * dev_name, unsigned int /* hi_lba */,
pr2serr_lk("id=%d: only support TUR here for now\n", id);
goto err_out;
}
+ if (op->no_waitq)
+ pr2serr_lk("id=%d: ignoring --no-waitq option\n", id);
+ if (op->verbose)
+ pr2serr_lk("id=%d: using libsgutils generic sync passthrough\n", id);
+
if ((sg_fd = sg_cmds_open_device(dev_name, false /* ro */, vb)) < 0) {
pr2serr_lk("id=%d: error opening file: %s: %s\n", id, dev_name,
safe_strerror(-sg_fd));
@@ -1137,6 +1149,8 @@ work_thread(int id, struct opts_t * op)
sg_flags |= SG_FLAG_MMAP_IO;
if (op->no_xfer)
sg_flags |= SG_FLAG_NO_DXFER;
+ if (op->no_waitq)
+ sg_flags |= SGV4_FLAG_NO_WAITQ;
if (vb > 1)
pr2serr_lk(" id=%d, sg_flags=0x%x, %s cmds\n", id, sg_flags,
((SCSI_TUR == op->c2e) ? "TUR":
@@ -1163,7 +1177,7 @@ work_thread(int id, struct opts_t * op)
m = 0;
}
}
- if (vb && ! once1000 && num_outstanding >= 1000) {
+ if (vb && (! once1000) && (num_outstanding >= 1000)) {
int num_waiting;
int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) :
pi2buff.size();
@@ -1299,8 +1313,8 @@ work_thread(int id, struct opts_t * op)
start_sg3_cmd(sg_fd, op->c2e, pack_id, lba, lbp,
blk_sz * op->num_lbs, sg_flags, op->submit,
thr_enomem_count, thr_start_eagain_count,
- thr_start_ebusy_count,
- thr_start_e2big_count, thr_start_edom_count);
+ thr_start_ebusy_count, thr_start_e2big_count,
+ thr_start_edom_count);
if (res) {
if (res > 1) { /* here if E2BIG, start not done, try finish */
do_inc = 0;
@@ -1411,7 +1425,7 @@ work_thread(int id, struct opts_t * op)
}
}
n = (op->wait_ms > 0) ? op->wait_ms : 0;
- if (n > 0) {
+ if ((n > 0) && (! op->no_waitq)) {
for (j = 0; (j < 1000000) &&
(0 == (res = poll(pfd, 1, n)));
++j)
@@ -1589,6 +1603,7 @@ work_thread(int id, struct opts_t * op)
start_e2big_count += thr_start_e2big_count;
fin_eagain_count += thr_fin_eagain_count;
fin_ebusy_count += thr_fin_ebusy_count;
+ enomem_count += thr_enomem_count;
start_edom_count += thr_start_edom_count;
if (op->cmd_time && op->sg_vn_ge_40030 && (npt > 0)) {
pr2serr_lk("t_id=%d average nanosecs per cmd: %" PRId64
@@ -1775,7 +1790,8 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "34acdefghl:L:mM:n:NO:pq:Q:Rs:St:TuvVw:W",
+ c = getopt_long(argc, argv,
+ "34acdefghl:L:mM:n:NO:pq:Q:Rs:St:TuvVw:Wz",
long_options, &option_index);
if (c == -1)
break;
@@ -1983,6 +1999,9 @@ main(int argc, char * argv[])
case 'W':
op->c2e = SCSI_WRITE16;
break;
+ case 'z':
+ op->no_waitq = true;
+ break;
default:
pr2serr_lk("unrecognised option code 0x%x ??\n", c);
usage();
@@ -2207,6 +2226,9 @@ main(int argc, char * argv[])
n = start_edom_count.load();
if (op->verbose || op->stats || (n > 0))
cout << "Number of EDOMs: " << n << endl;
+ n = enomem_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of ENOMEMs: " << n << endl;
}
catch(system_error& e) {
cerr << "got a system_error exception: " << e.what() << '\n';
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index c5bb731a..5a44f426 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -108,7 +108,7 @@
using namespace std;
-static const char * version_str = "1.41 20190817";
+static const char * version_str = "1.44 20190906";
#ifdef __GNUC__
#ifndef __clang__
@@ -119,6 +119,10 @@ static const char * version_str = "1.41 20190817";
/* <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> xxxxxxxxxx beware next line */
// #define SGH_DD_READ_COMPLET_AFTER 1
+
+/* comment out following line to stop ioctl(SG_CTL_FLAGM_SNAP_DEV) */
+#define SGH_DD_SNAP_DEV 1
+
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
#define DEF_BLOCKS_PER_2048TRANSFER 32
@@ -170,9 +174,9 @@ struct flags_t {
bool masync; /* more async sg v4 driver flag */
bool mmap;
bool mrq_immed; /* mrq submit non-blocking */
- bool mrq_wless; /* mrq waitless (or _NO_WAITQ) */
bool no_dur;
bool noshare;
+ bool no_waitq;
bool noxfer;
bool qtail;
bool same_fds;
@@ -230,7 +234,7 @@ typedef struct global_collection
bool ofile2_given;
bool unit_nanosec; /* default duration unit is millisecond */
bool mrq_cmds; /* mrq=<NRQS>,C given */
- bool mrq_async; /* any mrq_immed or mrq_wless flags given */
+ bool mrq_async; /* any mrq_immed or no_waitq flags given */
const char * infp;
const char * outfp;
const char * out2fp;
@@ -255,7 +259,7 @@ typedef struct request_element
bool swait; /* interleave READ WRITE async copy segment: READ submit,
* WRITE submit, READ receive, WRITE receive */
bool mrq_cmds; /* mrq=<NRQS>,C given */
- bool mrq_async; /* any mrq_immed or mrq_wless flags given */
+ bool mrq_async; /* any mrq_immed or no_waitq flags given */
// bool mrq_abort_thread_active;
int id;
int infd;
@@ -706,9 +710,9 @@ usage(int pg_num)
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,defres,dio,"
"direct,dpo,\n"
- " dsync,excl,fua,masync,mmap,mrq_immed,mrq_wless,"
- "nodur,\n"
- " noshare,noxfer,null,qtail,same_fds,v3,v4,"
+ " dsync,excl,fua,masync,mmap,mrq_immed,nodur, "
+ "noshare\n"
+ " no_waitq,noxfer,null,qtail,same_fds,v3,v4,"
"wq_excl]\n"
" of file or device to write to (def: /dev/null "
"N.B. different\n"
@@ -798,13 +802,12 @@ page3:
" mrq_immed if mrq active, do submit non-blocking (def: "
"ordered\n"
" blocking)\n"
- " mrq_wless if mrq active, do waitless non-blocking (def: "
- "ordered\n"
- " blocking)\n"
" nodur turns off command duration calculations\n"
" noshare if IFILE and OFILE are sg devices, don't set "
"up sharing\n"
" (def: do)\n"
+ " no_waitq when non-blocking (async) don't use wait "
+ "queue\n"
" qtail queue new request at tail of block queue (def: "
"q at head)\n"
" same_fds each thread use the same IFILE and OFILE(2) "
@@ -1032,6 +1035,29 @@ sg_share_prepare(int slave_wr_fd, int master_rd_fd, int id, bool vb_b)
return true;
}
+#ifdef SGH_DD_SNAP_DEV
+static void
+sg_take_snap(int sg_fd, int id, bool vb_b)
+{
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
+
+ seip = &sei;
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV;
+ seip->ctl_flags &= SG_CTL_FLAGM_SNAP_DEV; /* don't append */
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr_lk("tid=%d: ioctl(EXTENDED(SNAP_DEV), failed errno=%d %s\n",
+ id, errno, strerror(errno));
+ return;
+ }
+ if (vb_b)
+ pr2serr_lk("tid=%d: ioctl(SNAP_DEV) ok\n", id);
+}
+#endif
+
static void
cleanup_in(void * v_clp)
{
@@ -1829,6 +1855,7 @@ fini:
*good_outblksp = good_outblks;
return n_good;
}
+
static int
sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd,
struct sg_io_v4 * ctlop, int nrq)
@@ -1846,12 +1873,11 @@ sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd,
hold_ctlo = *ctlop;
a_v4p = def_arr.first.data();
ctlop->flags = SGV4_FLAG_MULTIPLE_REQS;
- if (rep->in_flags.mrq_immed || rep->out_flags.mrq_immed)
- ctlop->flags |= SGV4_FLAG_IMMED; /* submit non-blocking */
- else {
+ if (rep->in_flags.no_waitq || rep->out_flags.no_waitq) {
wless = true;
ctlop->flags |= SGV4_FLAG_NO_WAITQ; /* waitless non-blocking */
- }
+ } else
+ ctlop->flags |= SGV4_FLAG_IMMED; /* submit non-blocking */
if (rep->debug > 4) {
pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IOSUBMIT):\n",
__func__);
@@ -2272,6 +2298,7 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
bool dpo = wr ? rep->out_flags.dpo : rep->in_flags.dpo;
bool dio = wr ? rep->out_flags.dio : rep->in_flags.dio;
bool mmap = wr ? rep->out_flags.mmap : rep->in_flags.mmap;
+ bool no_waitq = wr ? rep->out_flags.no_waitq : rep->in_flags.no_waitq;
bool noxfer = wr ? rep->out_flags.noxfer : rep->in_flags.noxfer;
bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4;
bool qtail = wr ? rep->out_flags.qtail : rep->in_flags.qtail;
@@ -2356,10 +2383,19 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
while (((res = write(fd, hp, sizeof(struct sg_io_hdr))) < 0) &&
((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
- if (EAGAIN == errno)
+ if (EAGAIN == errno) {
++num_start_eagain;
- else if (EBUSY == errno)
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ } else if (EBUSY == errno) {
++num_ebusy;
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ }
std::this_thread::yield();/* another thread may be able to progress */
}
err = errno;
@@ -2388,7 +2424,7 @@ do_v4:
h4p->timeout = DEF_TIMEOUT;
h4p->usr_ptr = (uint64_t)rep;
h4p->request_extra = pack_id; /* this is the pack_id */
- h4p->flags = flags | SGV4_FLAG_IMMED;
+ h4p->flags = flags | (no_waitq ? SGV4_FLAG_NO_WAITQ : SGV4_FLAG_IMMED);
if (rep->nmrqs > 0) {
big_cdb cdb_arr;
uint8_t * cmdp = &(cdb_arr[0]);
@@ -2409,10 +2445,19 @@ do_v4:
}
while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) &&
((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
- if (EAGAIN == errno)
+ if (EAGAIN == errno) {
++num_start_eagain;
- else if (EBUSY == errno)
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ } else if (EBUSY == errno) {
++num_ebusy;
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ }
std::this_thread::yield();/* another thread may be able to progress */
}
err = errno;
@@ -2496,10 +2541,19 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2)
while (((res = read(fd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) &&
((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
- if (EAGAIN == errno)
+ if (EAGAIN == errno) {
++num_fin_eagain;
- else if (EBUSY == errno)
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ } else if (EBUSY == errno) {
++num_ebusy;
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ }
std::this_thread::yield();/* another thread may be able to progress */
}
if (res < 0) {
@@ -2555,10 +2609,19 @@ do_v4:
h4p->request_extra = pack_id;
while (((res = ioctl(fd, SG_IORECEIVE, h4p)) < 0) &&
((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
- if (EAGAIN == errno)
+ if (EAGAIN == errno) {
++num_fin_eagain;
- else if (EBUSY == errno)
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ } else if (EBUSY == errno) {
++num_ebusy;
+#ifdef SGH_DD_SNAP_DEV
+ if (0 == (num_ebusy % 1000))
+ sg_take_snap(fd, rep->id, (rep->debug > 2));
+#endif
+ }
std::this_thread::yield();/* another thread may be able to progress */
}
if (res < 0) {
@@ -2929,14 +2992,22 @@ process_flags(const char * arg, struct flags_t * fp)
fp->mmap = true;
else if (0 == strcmp(cp, "mrq_immed"))
fp->mrq_immed = true;
- else if (0 == strcmp(cp, "mrq_wless"))
- fp->mrq_wless = true;
else if (0 == strcmp(cp, "nodur"))
fp->no_dur = true;
+ else if (0 == strcmp(cp, "no_dur"))
+ fp->no_dur = true;
else if (0 == strcmp(cp, "noshare"))
fp->noshare = true;
+ else if (0 == strcmp(cp, "no_share"))
+ fp->noshare = true;
+ else if (0 == strcmp(cp, "no_waitq"))
+ fp->no_waitq = true;
+ else if (0 == strcmp(cp, "nowaitq"))
+ fp->no_waitq = true;
else if (0 == strcmp(cp, "noxfer"))
fp->noxfer = true;
+ else if (0 == strcmp(cp, "no_xfer"))
+ fp->noxfer = true;
else if (0 == strcmp(cp, "null"))
;
else if (0 == strcmp(cp, "qtail"))
@@ -3366,9 +3437,12 @@ main(int argc, char * argv[])
pr2serr("dio flag can only be used with noshare flag\n");
return SG_LIB_SYNTAX_ERROR;
}
- if (clp->in_flags.mrq_immed || clp->out_flags.mrq_immed ||
- clp->in_flags.mrq_wless || clp->out_flags.mrq_wless)
- clp->mrq_async = true;
+ if (clp->nmrqs > 0) {
+ if (clp->in_flags.mrq_immed || clp->out_flags.mrq_immed)
+ clp->mrq_async = true;
+ if (clp->in_flags.no_waitq || clp->out_flags.no_waitq)
+ clp->mrq_async = true;
+ }
/* defaulting transfer size to 128*2048 for CD/DVDs is too large
for the block layer in lk 2.6 and results in an EIO on the
SG_IO ioctl. So reduce it in that case. */
@@ -3598,8 +3672,7 @@ main(int argc, char * argv[])
}
if (clp->mrq_async && !(clp->in_flags.noshare ||
clp->out_flags.noshare)) {
- pr2serr("With mrq_immed or mrq_wless also need noshare on sg "
- "to sg copy\n");
+ pr2serr("With mrq_immed also need noshare on sg-->sg copy\n");
return SG_LIB_SYNTAX_ERROR;
}
}
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 849cd688..8bf5b7aa 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_SCSI_SG_H
#define _UAPI_SCSI_SG_H
@@ -14,7 +14,7 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version 4.0.33 (20190720)
+ * Version 4.0.34 (20190904)
* This version is for Linux 4 and 5 series kernels.
*
* Documentation
@@ -209,7 +209,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_CTL_FLAGM_NO_DURATION 0x400 /* don't calc command duration */
#define SG_CTL_FLAGM_MORE_ASYNC 0x800 /* yield EAGAIN in more cases */
#define SG_CTL_FLAGM_EXCL_WAITQ 0x1000 /* only 1 wake up per response */
-#define SG_CTL_FLAGM_ALL_BITS 0x1fff /* should be OR of previous items */
+#define SG_CTL_FLAGM_SNAP_DEV 0x2000 /* output to debugfs::snapped */
+#define SG_CTL_FLAGM_ALL_BITS 0x3fff /* should be OR of previous items */
/* Write one of the following values to sg_extended_info::read_value, get... */
#define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */