aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--src/sg_dd.c12
-rw-r--r--testing/sg_mrq_dd.cpp138
-rw-r--r--testing/sg_scat_gath.cpp15
-rw-r--r--testing/sgh_dd.cpp111
-rw-r--r--testing/sgs_dd.c98
-rw-r--r--testing/uapi_sg.h13
7 files changed, 256 insertions, 133 deletions
diff --git a/ChangeLog b/ChangeLog
index 9826472e..9f398e22 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.46 [20200903] [svn: r862]
+Changelog for sg3_utils-1.46 [20200927] [svn: r863]
- sg_rep_pip: report new provisioning initialization pattern cmd
- sg_turs: estimated time-to-ready [20-061r2]
- add --delay=MS option
diff --git a/src/sg_dd.c b/src/sg_dd.c
index 328ff3d7..a224ef31 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -66,7 +66,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "6.16 20200825";
+static const char * version_str = "6.17 20200923";
#define ME "sg_dd: "
@@ -222,12 +222,12 @@ print_stats(const char * str)
pr2serr("%s%d recovered errors\n", str, recovered_errs);
if (num_retries > 0)
pr2serr("%s%d retries attempted\n", str, num_retries);
- if (iflag.coe || oflag.coe) {
- pr2serr("%s%d unrecovered errors\n", str, unrecovered_errs);
- pr2serr("%s%d read_longs fetched part of unrecovered read errors\n",
- str, read_longs);
- } else if (unrecovered_errs > 0)
+ if (unrecovered_errs > 0) {
pr2serr("%s%d unrecovered error(s)\n", str, unrecovered_errs);
+ if (iflag.coe || oflag.coe)
+ pr2serr("%s%d read_longs fetched part of unrecovered read "
+ "errors\n", str, read_longs);
+ }
if (miscompare_errs > 0)
pr2serr("%s%d miscompare error(s)\n", str, miscompare_errs);
}
diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp
index 5049b0b2..2d4515a4 100644
--- a/testing/sg_mrq_dd.cpp
+++ b/testing/sg_mrq_dd.cpp
@@ -30,7 +30,7 @@
*
*/
-static const char * version_str = "1.10 20200830";
+static const char * version_str = "1.13 20200927";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -127,7 +127,7 @@ using namespace std;
#define DEF_BLOCKS_PER_TRANSFER 128
#define DEF_BLOCKS_PER_2048TRANSFER 32
#define DEF_SCSI_CDB_SZ 10
-#define MAX_SCSI_CDB_SZ 16
+#define MAX_SCSI_CDB_SZ 16 /* could be 32 */
#define PACK_ID_TID_MULTIPLIER (0x1000000) /* 16,777,216 */
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -310,7 +310,6 @@ struct sg_io_extra {
#define MONO_MRQ_ID_INIT 0x10000
-typedef array<uint8_t, 32> big_cdb; /* allow up to a 32 byte cdb */
/* Use this class to wrap C++11 <random> features to produce uniform random
@@ -331,6 +330,7 @@ private:
static atomic<int> num_ebusy(0);
static atomic<int> num_start_eagain(0);
static atomic<int> num_fin_eagain(0);
+static atomic<int> num_miscompare(0);
static atomic<bool> vb_first_time(true);
static sigset_t signal_set;
@@ -360,7 +360,7 @@ static mutex strerr_mut;
static bool have_sg_version = false;
static int sg_version = 0;
-static bool sg_version_ge_40030 = false;
+static bool sg_version_ge_40045 = false;
static atomic<bool> shutting_down{false};
static bool do_sync = false;
static int do_time = 1;
@@ -421,6 +421,13 @@ lk_chk_n_print4(const char * leadin, const struct sg_io_v4 * h4p,
{
lock_guard<mutex> lk(strerr_mut);
+ if (h4p->usr_ptr) {
+ const cdb_arr_t * cdbp = (const cdb_arr_t *)h4p->usr_ptr;
+
+ pr2serr("Failed cdb: ");
+ sg_print_command(cdbp->data());
+ } else
+ pr2serr("cdb: <null>\n");
sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status,
h4p->driver_status, (const uint8_t *)h4p->response,
h4p->response_len, raw_sinfo);
@@ -813,16 +820,22 @@ usage(int pg_num)
" [iflag=FLAGS]\n"
" [obs=BS] [of=OFILE] [oflag=FLAGS] "
"[seek=SEEK]\n"
- " [skip=SKIP] [--help] [--version]\n\n");
+ " [skip=SKIP] [--help] [--verify] "
+ "[--version]\n\n");
pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] "
"[elemsz_kb=EKB]\n"
" [fua=0|1|2|3] [mrq=MRQ] [no_waitq=0|1] "
"[ofreg=OFREG]\n"
" [sync=0|1] [thr=THR] [time=0|1|2] "
"[verbose=VERB]\n"
- " [--dry-run] [--verbose] [--verify] "
+ " [--dry-run] [--pre-fetch] [--verbose] "
"[--version]\n\n"
- " where the main options (shown in first group above) are:\n"
+ " where: operands have the form name=value and are pecular to "
+ "'dd'\n"
+ " style commands, and options start with one or "
+ "two hyphens;\n"
+ " the main operands and options (shown in first group "
+ "above) are:\n"
" bs must be device logical block size (default "
"512)\n"
" count number of blocks to copy (def: device size)\n"
@@ -831,10 +844,6 @@ usage(int pg_num)
"direct,dpo,\n"
" dsync,excl,fua,masync,mmap,nodur,\n"
" null,order,qtail,serial,wq_excl]\n"
- " mrq number of cmds placed in each sg call "
- "(def: 16)\n"
- " if mrq=0 does single, blocking ioctl(SG_IO)s "
- "for all IO\n"
" of file or device to write to (def: /dev/null "
"N.B. different\n"
" from dd it defaults to stdout). If 'of=.' "
@@ -844,7 +853,6 @@ usage(int pg_num)
" seek block position to start writing to OFILE\n"
" skip block position to start reading from IFILE\n"
" --help|-h output this usage message then exit\n"
- " --prefetch|-p with verify: do pre-fetch first\n"
" --verify|-x do a verify (compare) operation [def: do a "
"copy]\n"
" --version|-V output version string then exit\n\n"
@@ -860,10 +868,6 @@ usage(int pg_num)
return;
page2:
pr2serr("Syntax: sg_mrq_dd [operands] [options]\n\n"
- " where: operands have the form name=value and are pecular to "
- "'dd'\n"
- " style commands, and options start with one or "
- "two hyphens;\n"
" the lesser used operands and option are:\n\n"
" bpt is blocks_per_transfer (default is 128)\n"
" cdbsz size of SCSI READ, WRITE or VERIFY cdb_s "
@@ -876,8 +880,16 @@ page2:
" fua force unit access: 0->don't(def), 1->OFILE, "
"2->IFILE,\n"
" 3->OFILE+IFILE\n"
+ " ibs IFILE logical block size, cannot differ from "
+ "obs or bs\n"
+ " mrq number of cmds placed in each sg call "
+ "(def: 16)\n"
+ " if mrq=0 does one-by-one, blocking "
+ "ioctl(SG_IO)s\n"
" no_waitq=0|1 poll for completion when 1; def: 0 (use "
"wait queue)\n"
+ " obs OFILE logical block size, cannot differ from "
+ "ibs or bs\n"
" ofreg OFREG is regular file or pipe to send what is "
"read from\n"
" IFILE in the first half of each shared element\n"
@@ -888,8 +900,9 @@ page2:
" time 0->no timing; 1/2->millisec/nanosec precision "
"(def: 1)\n"
" verbose increase verbosity (def: VERB=0)\n"
- " --dry-run|-d prepare but bypass copy/read\n"
- " --verbose|-v increase verbosity of utility\n\n"
+ " --dry-run|-d prepare but bypass copy/read\n"
+ " --prefetch|-p with verify: do pre-fetch first\n"
+ " --verbose|-v increase verbosity of utility\n\n"
"Use '-hhh' or '-hhhh' for more information about flags.\n"
);
return;
@@ -915,8 +928,6 @@ page3:
" masync set 'more async' flag on this sg device\n"
" mmap setup mmap IO on IFILE or OFILE\n"
" mmap,mmap when used twice, doesn't call munmap()\n"
- " mrq_svb if mrq and sg->sg copy, do shared_variable_"
- "blocking\n"
" nodur turns off command duration calculations\n"
" order require write ordering on sg->sg copy; only "
"for oflag\n"
@@ -970,7 +981,8 @@ page4:
"For comparing IFILE with OFILE. Does repeated sequences of: "
"READ(ifile)\nand uses data returned to send to VERIFY(ofile, "
"BYTCHK=1). So the OFILE\ndevice/disk is doing the actual "
- "comparison. Stops on first miscompare.\n\n");
+ "comparison. Stops on first miscompare\nunless oflag=coe is "
+ "given\n\n");
pr2serr("--prefetch :\n"
"Used with --verify option. Prepends a PRE-FETCH(ofile, IMMED) "
"to verify\nsequence. This should speed the trailing VERIFY by "
@@ -1247,7 +1259,7 @@ read_write_thread(struct global_collection * clp, int id, bool singleton)
// share_and_ofreg = (rep->has_share && (rep->outregfd >= 0));
/* vvvvvvvvvvvvvv Main segment copy loop vvvvvvvvvvvvvvvvvvvvvvv */
- while (1) {
+ while (! shutting_down) {
get_next_res gnr = clp->get_next(clp->mrq_num * clp->bpt);
seg_blks = gnr.second;
@@ -1309,9 +1321,14 @@ read_write_thread(struct global_collection * clp, int id, bool singleton)
clp->infant_cv.notify_one();
singleton = false;
}
- if (rep->stop_after_write)
+ if (rep->stop_after_write) {
+ shutting_down = true;
break;
+ }
} /* ^^^^^^^^^^ end of main while loop which copies segments ^^^^^^ */
+
+ if (shutting_down)
+ goto fini;
if (singleton) {
{
lock_guard<mutex> lk(clp->infant_mut);
@@ -1644,10 +1661,9 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
int n_good = 0;
int hole_count = 0;
int vb = clp->verbose;
- int k, j, f1, slen, sstatus, blen;
+ int k, j, f1, slen, sstatus;
char b[160];
- blen = sizeof(b);
good_inblks = 0;
good_outblks = 0;
if (vb > 2)
@@ -1707,34 +1723,30 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
if (sg_scsi_normalize_sense(sbp, slen, &ssh) &&
(ssh.response_code >= 0x70)) {
- char b[256];
-
if (ssh.response_code & 0x1) {
ok = true;
last_err_on_in = false;
}
- if (vb) {
- sg_get_sense_str(" ", sbp, slen, false, blen, b);
- pr2serr_lk("[%d] a_v4[%d]:\n%s\n", id, k, b);
- }
+ if (SPC_SK_MISCOMPARE == ssh.sense_key)
+ ++num_miscompare;
+
+ pr2serr_lk("[%d] a_v4[%d]:\n", id, k);
+ if (vb)
+ lk_chk_n_print4(" >>", a_v4p, vb > 4);
}
}
if (ok && f1) {
++n_good;
- if (a_v4p->dout_xfer_len >= (uint32_t)clp->bs) {
- if (a_v4p->dout_resid)
- good_outblks +=
- (a_v4p->dout_xfer_len - a_v4p->dout_resid) / clp->bs;
- else /* avoid division in common case of resid==0 */
- good_outblks += (uint32_t)a_v4p->usr_ptr;
- }
- if (a_v4p->din_xfer_len >= (uint32_t)clp->bs) {
- if (a_v4p->din_resid)
- good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) /
- clp->bs;
- else
- good_inblks += (uint32_t)a_v4p->usr_ptr;
- }
+ if (a_v4p->dout_xfer_len >= (uint32_t)clp->bs)
+ good_outblks += (a_v4p->dout_xfer_len - a_v4p->dout_resid) /
+ clp->bs;
+ if (a_v4p->din_xfer_len >= (uint32_t)clp->bs)
+ good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) /
+ clp->bs;
+ }
+ if (! ok) {
+ if ((a_v4p->dout_xfer_len > 0) || (! clp->in_flags.coe))
+ rep->stop_after_write = true;
}
} /* end of request array scan loop */
if ((n_subm == num_mrq) || (vb < 3))
@@ -1815,6 +1827,7 @@ sg_half_segment_mrq0(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr,
memset(t_v4p, 0, sizeof(*t_v4p));
t_v4p->guard = 'Q';
t_v4p->request = (uint64_t)t_cdb.data();
+ t_v4p->usr_ptr = t_v4p->request;
t_v4p->response = (uint64_t)rep->sb;
t_v4p->flags = rflags;
t_v4p->request_len = cdbsz;
@@ -1826,7 +1839,6 @@ sg_half_segment_mrq0(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr,
t_v4p->din_xferp = (uint64_t)(dp + (q_blks * clp->bs));
}
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off;
mrq0_again:
res = ioctl(fd, SG_IO, t_v4p);
@@ -1932,6 +1944,7 @@ sg_half_segment(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr,
t_v4p->guard = 'Q';
t_v4p->flags = rflags;
t_v4p->request_len = cdbsz;
+ t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1];
if (is_wr) {
t_v4p->dout_xfer_len = num * clp->bs;
t_v4p->dout_xferp = (uint64_t)(dp + (mrq_q_blks * clp->bs));
@@ -1940,7 +1953,6 @@ sg_half_segment(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr,
t_v4p->din_xferp = (uint64_t)(dp + (mrq_q_blks * clp->bs));
}
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
mrq_q_blks += num;
t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off;
a_v4.push_back(t_v4);
@@ -2338,12 +2350,12 @@ do_both_sg_segment_mrq0(Rq_elem * rep, scat_gath_iter & i_sg_it,
memset(t_v4p, 0, sizeof(*t_v4p));
t_v4p->guard = 'Q';
t_v4p->request = (uint64_t)t_cdb.data();
+ t_v4p->usr_ptr = t_v4p->request;
t_v4p->response = (uint64_t)rep->sb;
t_v4p->flags = iflags;
t_v4p->request_len = cdbsz;
t_v4p->din_xfer_len = num * clp->bs;
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off;
mrq0_again:
res = ioctl(rep->infd, SG_IO, t_v4p);
@@ -2387,12 +2399,12 @@ mrq0_again:
memset(t_v4p, 0, sizeof(*t_v4p));
t_v4p->guard = 'Q';
t_v4p->request = (uint64_t)t_cdb.data();
+ t_v4p->usr_ptr = t_v4p->request;
t_v4p->response = (uint64_t)rep->sb;
t_v4p->flags = oflags;
t_v4p->request_len = cdbsz;
t_v4p->dout_xfer_len = num * clp->bs;
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off;
mrq0_again2:
res = ioctl(rep->outfd, SG_IO, t_v4p);
@@ -2517,9 +2529,9 @@ do_both_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it,
t_v4p->guard = 'Q';
t_v4p->flags = iflags;
t_v4p->request_len = cdbsz;
+ t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1];
t_v4p->din_xfer_len = num * clp->bs;
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
in_mrq_q_blks += num;
t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off;
a_v4.push_back(t_v4);
@@ -2540,9 +2552,9 @@ do_both_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it,
t_v4p->guard = 'Q';
t_v4p->flags = oflags;
t_v4p->request_len = cdbsz;
+ t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1];
t_v4p->dout_xfer_len = num * clp->bs;
t_v4p->timeout = DEF_TIMEOUT;
- t_v4p->usr_ptr = num; /* pass number blocks requested */
out_mrq_q_blks += num;
t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off;
a_v4.push_back(t_v4);
@@ -2779,6 +2791,17 @@ bypass:
errno, strerror(errno));
}
}
+ if (clp->no_waitq) {
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ res = -1;
+ pr2serr_lk("ioctl(EXTENDED(NO_WAIT_POLL)) failed, errno=%d %s\n",
+ errno, strerror(errno));
+ }
+ }
if (clp->verbose) {
t = 1;
/* more info in /proc/scsi/sg/debug */
@@ -3058,6 +3081,10 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp,
clp->cdbsz_in = sg_get_num(buf);
clp->cdbsz_out = clp->cdbsz_in;
clp->cdbsz_given = true;
+ } else if (0 == strcmp(key, "coe")) {
+ /* not documented, for compat with sgh_dd */
+ clp->in_flags.coe = !! sg_get_num(buf);
+ clp->out_flags.coe = clp->in_flags.coe;
} else if (0 == strcmp(key, "count")) {
if (clp->count_given) {
pr2serr("second 'count=' argument detected, only one "
@@ -3607,10 +3634,10 @@ main(int argc, char * argv[])
outf[0] = '\0';
outregf[0] = '\0';
fetch_sg_version();
- if (sg_version >= 40030)
- sg_version_ge_40030 = true;
+ if (sg_version >= 40045)
+ sg_version_ge_40045 = true;
else {
- pr2serr(">>> %srequires an sg driver version of 4.0.30 or later\n\n",
+ pr2serr(">>> %srequires an sg driver version of 4.0.45 or later\n\n",
my_name);
fail_after_cli = true;
}
@@ -3930,6 +3957,9 @@ fini:
pr2serr("Number of finish EAGAINs: %d\n", num_fin_eagain.load());
if (clp->verbose && (num_ebusy > 0))
pr2serr("Number of EBUSYs: %d\n", num_ebusy.load());
+ if (clp->verbose && (num_miscompare > 0))
+ pr2serr("Number of miscompare%s: %d\n",
+ (num_miscompare > 1) ? "s" : "", num_miscompare.load());
if (clp->verify && (SG_LIB_CAT_MISCOMPARE == res))
pr2serr("Verify/compare failed due to miscompare\n");
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
diff --git a/testing/sg_scat_gath.cpp b/testing/sg_scat_gath.cpp
index 832cbed1..91e9d37a 100644
--- a/testing/sg_scat_gath.cpp
+++ b/testing/sg_scat_gath.cpp
@@ -560,7 +560,7 @@ scat_gath_list::append_1or(int64_t extra_blks, int64_t start_lba)
int64_t cnt = 0;
class scat_gath_elem sge;
- if ((extra_blks <= 0) || (start_lba < 0))
+ if ((extra_blks <= 0) && (start_lba < 0))
return o_num; /* nothing to do */
if ((o_num > 0) && (! sum_hard)) {
sge = sgl[o_num - 1]; /* assume sge.num==0 */
@@ -578,9 +578,16 @@ scat_gath_list::append_1or(int64_t extra_blks, int64_t start_lba)
return o_num;
}
}
- } else if (0 == o_num)
+ } else if (0 == o_num) {
lowest_lba = start_lba;
-
+ if (0 == extra_blks) {
+ sge.lba = start_lba;
+ sge.num = 0;
+ sgl.push_back(sge);
+ high_lba_p1 = sge.lba;
+ return sgl.size();
+ }
+ }
for ( ; cnt < extra_blks; cnt += max_nbs) {
sge.lba = start_lba + cnt;
if ((extra_blks - cnt) <= max_nbs)
@@ -599,10 +606,12 @@ int
scat_gath_list::append_1or(int64_t extra_blks)
{
int o_num = sgl.size();
+
if (o_num < 1)
return append_1or(extra_blks, 0);
class scat_gath_elem sge = sgl[o_num - 1];
+
return append_1or(extra_blks, sge.lba + sge.num);
}
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 8221eb25..82d9869d 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -36,7 +36,7 @@
* renamed [20181221]
*/
-static const char * version_str = "1.91 20200829";
+static const char * version_str = "1.94 20200927";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -357,6 +357,7 @@ static atomic<int> num_abort_req(0);
static atomic<int> num_abort_req_success(0);
static atomic<int> num_mrq_abort_req(0);
static atomic<int> num_mrq_abort_req_success(0);
+static atomic<int> num_miscompare(0);
static atomic<long> num_waiting_calls(0);
static atomic<bool> vb_first_time(true);
@@ -388,7 +389,7 @@ static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER;
static bool have_sg_version = false;
static int sg_version = 0;
static bool sg_version_lt_4 = false;
-static bool sg_version_ge_40030 = false;
+static bool sg_version_ge_40045 = false;
static bool shutting_down = false;
static bool do_sync = false;
static int do_time = 1;
@@ -1296,7 +1297,7 @@ sg_unshare(int sg_fd, int id, bool vb_b)
static void
sg_noshare_enlarge(int sg_fd, bool vb_b)
{
- if (sg_version_ge_40030) {
+ if (sg_version_ge_40045) {
struct sg_extended_info sei;
struct sg_extended_info * seip;
@@ -1507,7 +1508,7 @@ read_write_thread(void * v_tip)
pr2serr_lk("thread=%d: using global sg OFILE2, fd=%d\n", rep->id,
rep->out2fd);
}
- if (!sg_version_ge_40030) {
+ if (!sg_version_ge_40045) {
if (vb > 4)
pr2serr_lk("thread=%d: Skipping share because driver too old\n",
rep->id);
@@ -1515,7 +1516,7 @@ read_write_thread(void * v_tip)
if (vb > 4)
pr2serr_lk("thread=%d: Skipping IFILE share with OFILE due to "
"noshare=1\n", rep->id);
- } else if (sg_version_ge_40030 && in_is_sg && out_is_sg)
+ } else if (sg_version_ge_40045 && in_is_sg && out_is_sg)
rep->has_share = sg_share_prepare(rep->outfd, rep->infd, rep->id,
vb > 9);
if (vb > 9)
@@ -1689,7 +1690,7 @@ fini:
rep->mmap_active = 0;
}
- if (sg_version_ge_40030) {
+ if (sg_version_ge_40045) {
if (clp->noshare) {
if ((clp->nmrqs > 0) && clp->unshare)
sg_unshare(rep->infd, rep->id, vb > 9);
@@ -2079,6 +2080,7 @@ sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2, bool prefetch)
pthread_mutex_t * mutexp = is_wr2 ? &clp->out2_mutex : &clp->out_mutex;
struct sg_io_extra xtr;
struct sg_io_extra * xtrp = &xtr;
+ const char * wr_or_ver = clp->verify ? "verify" : "out";
memset(xtrp, 0, sizeof(*xtrp));
xtrp->is_wr2 = is_wr2;
@@ -2093,8 +2095,8 @@ again:
if (1 == res)
err_exit(ENOMEM, "sg starting out command");
else if (res < 0) {
- pr2serr_lk("%soutputting from sg failed, blk=%" PRId64 "\n",
- my_name, rep->oblk);
+ pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n",
+ my_name, wr_or_ver, rep->oblk);
status = pthread_mutex_unlock(mutexp);
if (0 != status) err_exit(status, "unlock out_mutex");
stop_both(clp);
@@ -2143,8 +2145,8 @@ split_upper:
if (1 == res)
err_exit(ENOMEM, "sg starting out command");
else if (res < 0) {
- pr2serr_lk("%soutputting from sg failed, blk=%" PRId64 "\n",
- my_name, rep->oblk);
+ pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n", my_name,
+ wr_or_ver, rep->oblk);
status = pthread_mutex_unlock(mutexp);
if (0 != status) err_exit(status, "unlock out_mutex");
stop_both(clp);
@@ -2167,14 +2169,14 @@ split_upper:
case SG_LIB_CAT_MEDIUM_HARD:
if (0 == clp->out_flags.coe) {
pr2serr_lk("error finishing sg %s command (medium)\n",
- (clp->verify ? "verify" : "out"));
+ wr_or_ver);
if (exit_status <= 0)
exit_status = res;
stop_both(clp);
goto fini;
} else
- pr2serr_lk(">> ignored error for out blk=%" PRId64 " for %d "
- "bytes\n", rep->oblk, nblks * clp->bs);
+ pr2serr_lk(">> ignored error for %s blk=%" PRId64 " for %d "
+ "bytes\n", wr_or_ver, rep->oblk, nblks * clp->bs);
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
__attribute__((fallthrough));
@@ -2195,9 +2197,12 @@ split_upper:
if (0 != status) err_exit(status, "unlock out_mutex");
}
goto fini;
+ case SG_LIB_CAT_MISCOMPARE:
+ ++num_miscompare;
+ // fall through
default:
- pr2serr_lk("error finishing sg %s command (%d)\n",
- (clp->verify ? "verify" : "out"), res);
+ pr2serr_lk("error finishing sg %s command (%d)\n", wr_or_ver,
+ res);
if (exit_status <= 0)
exit_status = res;
stop_both(clp);
@@ -2311,20 +2316,12 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
}
if (ok && f1) {
++n_good;
- if (a_v4p->dout_xfer_len >= (uint32_t)clp->bs) {
- if (a_v4p->dout_resid)
- good_outblks +=
- (a_v4p->dout_xfer_len - a_v4p->dout_resid) / clp->bs;
- else /* avoid division in common case of resid==0 */
- good_outblks += (uint32_t)a_v4p->usr_ptr;
- }
- if (a_v4p->din_xfer_len >= (uint32_t)clp->bs) {
- if (a_v4p->din_resid)
- good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) /
- clp->bs;
- else
- good_inblks += (uint32_t)a_v4p->usr_ptr;
- }
+ if (a_v4p->dout_xfer_len >= (uint32_t)clp->bs)
+ good_outblks += (a_v4p->dout_xfer_len - a_v4p->dout_resid) /
+ clp->bs;
+ if (a_v4p->din_xfer_len >= (uint32_t)clp->bs)
+ good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) /
+ clp->bs;
}
} /* end of request array scan loop */
if ((n_subm == num_mrq) || (vb < 3))
@@ -3362,6 +3359,9 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, struct sg_io_extra *xtrp)
if (clp->verbose > 3)
lk_chk_n_print3(cp, hp, false);
return res;
+ case SG_LIB_CAT_MISCOMPARE:
+ ++num_miscompare;
+ // fall through
case SG_LIB_CAT_NOT_READY:
default:
{
@@ -3428,6 +3428,9 @@ do_v4:
if (clp->verbose > 3)
lk_chk_n_print4(cp, h4p, false);
return res;
+ case SG_LIB_CAT_MISCOMPARE:
+ ++num_miscompare;
+ // fall through
case SG_LIB_CAT_NOT_READY:
default:
{
@@ -3468,11 +3471,15 @@ do_v4:
/* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
static int
-sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
- bool unit_nano, bool no_dur, bool masync, bool wq_excl,
+sg_prepare_resbuf(int fd, bool is_in, struct global_collection *clp,
uint8_t **mmpp)
{
static bool done = false;
+ bool def_res = is_in ? clp->in_flags.defres : clp->out_flags.defres;
+ bool no_dur = is_in ? clp->in_flags.no_dur : clp->out_flags.no_dur;
+ bool masync = is_in ? clp->in_flags.masync : clp->out_flags.masync;
+ bool wq_excl = is_in ? clp->in_flags.wq_excl : clp->out_flags.wq_excl;
+ bool no_waitq = is_in ? clp->in_flags.no_waitq : clp->out_flags.no_waitq;
int res, t, num;
uint8_t *mmp;
struct sg_extended_info sei;
@@ -3493,19 +3500,19 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
}
goto bypass;
}
- if (! sg_version_ge_40030)
+ if (! sg_version_ge_40045)
goto bypass;
- if (elem_sz >= 4096) {
+ if (clp->elem_sz >= 4096) {
memset(seip, 0, sizeof(*seip));
seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd "
"error: %s\n", __func__, strerror(errno));
- if (elem_sz != (int)seip->sgat_elem_sz) {
+ if (clp->elem_sz != (int)seip->sgat_elem_sz) {
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
- seip->sgat_elem_sz = elem_sz;
+ seip->sgat_elem_sz = clp->elem_sz;
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) "
@@ -3534,7 +3541,7 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
}
bypass:
if (! def_res) {
- num = bs * bpt;
+ num = clp->bs * clp->bpt;
res = ioctl(fd, SG_SET_RESERVED_SIZE, &num);
if (res < 0) {
perror("sgh_dd: SG_SET_RESERVED_SIZE error");
@@ -3570,7 +3577,7 @@ bypass:
res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
if (res < 0)
perror("sgh_dd: SG_SET_FORCE_PACK_ID error");
- if (unit_nano && sg_version_ge_40030) {
+ if (clp->unit_nanosec && sg_version_ge_40045) {
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
@@ -3581,6 +3588,17 @@ bypass:
errno, strerror(errno));
}
}
+ if (no_waitq && sg_version_ge_40045) {
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ res = -1;
+ pr2serr_lk("ioctl(EXTENDED(NO_WAIT_POLL)) failed, errno=%d %s\n",
+ errno, strerror(errno));
+ }
+ }
t = 1;
res = ioctl(fd, SG_SET_DEBUG, &t); /* more info in /proc/scsi/sg/debug */
if (res < 0)
@@ -3652,6 +3670,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->no_unshare = true;
else if (0 == strcmp(cp, "no_waitq"))
fp->no_waitq = 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"))
@@ -3722,10 +3742,7 @@ sg_in_open(struct global_collection *clp, const char *inf, uint8_t **mmpp,
perror(ebuff);
return -sg_convert_errno(err);
}
- n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->in_flags.defres,
- clp->elem_sz, clp->unit_nanosec,
- clp->in_flags.no_dur, clp->in_flags.masync,
- clp->in_flags.wq_excl, mmpp);
+ n = sg_prepare_resbuf(fd, true, clp, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (clp->noshare)
@@ -3757,10 +3774,7 @@ sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp,
perror(ebuff);
return -sg_convert_errno(err);
}
- n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->out_flags.defres,
- clp->elem_sz, clp->unit_nanosec,
- clp->out_flags.no_dur, clp->out_flags.masync,
- clp->out_flags.wq_excl, mmpp);
+ n = sg_prepare_resbuf(fd, false, clp, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (clp->noshare)
@@ -4205,8 +4219,8 @@ main(int argc, char * argv[])
if (sg_version > 40000) {
clp->in_flags.v4 = true;
clp->out_flags.v4 = true;
- if (sg_version >= 40030)
- sg_version_ge_40030 = true;
+ if (sg_version >= 40045)
+ sg_version_ge_40045 = true;
}
res = parse_cmdline_sanity(argc, argv, clp, inf, outf, out2f, outregf);
@@ -4775,6 +4789,9 @@ fini:
pr2serr("Number of successful MRQ Aborts: %d\n",
num_mrq_abort_req_success.load());
}
+ if (clp->verbose && (num_miscompare > 0))
+ pr2serr("Number of miscompare%s: %d\n",
+ (num_miscompare > 1) ? "s" : "", num_miscompare.load());
if (clp->verbose > 1) {
if (clp->verbose > 3)
pr2serr("Final pack_id=%d, mrq_id=%d\n", mono_pack_id.load(),
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index cca5330c..ccae39e0 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -1,7 +1,7 @@
/*
* Test code for the extensions to the Linux OS SCSI generic ("sg")
* device driver.
- * Copyright (C) 1999-2019 D. Gilbert and P. Allworth
+ * Copyright (C) 1999-2020 D. Gilbert and P. Allworth
*
* 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
@@ -83,7 +83,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "4.14 20200330";
+static const char * version_str = "4.15 20200916";
static const char * my_name = "sgs_dd";
#define DEF_BLOCK_SIZE 512
@@ -121,6 +121,7 @@ struct flags_t {
bool immed;
bool mmap;
bool noxfer;
+ bool no_waitq;
bool pack;
bool tag;
bool v3;
@@ -169,6 +170,8 @@ typedef struct request_collection
int bpt;
int dio_incomplete;
int sum_of_resids;
+ int poll_ms;
+ int pollerr_count;
int debug;
sigset_t blocked_sigs;
int sigs_waiting;
@@ -187,31 +190,54 @@ static bool sgs_nanosec_unit = false;
static void
-usage(void)
+usage(int pg_num)
{
+ if (pg_num > 1)
+ goto second_page;
printf("Usage: "
"sgs_dd [bpt=BPT] [bs=BS] [count=NUM] [deb=DEB] [if=IFILE]\n"
" [iflag=FLAGS] [no_sig=0|1] [of=OFILE] "
"[oflag=FLAGS]\n"
- " [rt_sig=0|1] [seek=SEEK] [skip=SKIP] "
- "[--version]\n"
+ " [poll_ms=MS] [rt_sig=0|1] [seek=SEEK] "
+ "[skip=SKIP]\n"
+ " [--help] [--version]\n"
"where:\n"
" bpt blocks_per_transfer (default: 65536/bs (or 128 for "
"bs=512))\n"
" bs must be the logical block size of device (def: 512)\n"
" deb debug: 0->no debug (def); > 0 -> more debug\n"
" iflag comma separated list from: dio,evfd,excl,immed,mmap,"
- "noxfer,\n"
- " null,pack,tag,v3,v4 bound to IFILE\n"
+ "no_waitq,\n"
+ " noxfer,null,pack,tag,v3,v4 bound to IFILE\n"
" no_sig 0-> use signals (def); 1-> no signals, hard polling "
"instead\n"
" oflag same flags as iflag but bound to OFILE\n"
+ " poll_ms number of milliseconds to wait on poll (def: 0)\n"
" rt_sig 0->use SIGIO (def); 1->use RT sig (SIGRTMIN + 1)\n"
" <other operands> as per dd command\n\n");
printf("dd clone for testing Linux sg driver SIGPOLL and/or polling. "
"Either\nIFILE or OFILE must be a scsi generic device. If OFILE "
"not given then\n/dev/null assumed (rather than stdout like "
- "dd).\n");
+ "dd). Use '-hh' or '-hhh'\nfor more information.\n");
+ return;
+second_page:
+ printf("flag description:\n"
+ " dio this driver's version of O_DIRECT\n"
+ " evfd when poll() gives POLLIN, use eventfd to find "
+ "out how many\n"
+ " excl open IFILE or OFILE with O_EXCL\n"
+ " immed use SGV4_FLAG_IMMED flag on each request\n"
+ " mmap use mmap()-ed IO on IFILE or OFILE\n"
+ " no_waitq use SGV4_FLAG_NO_WAIQ flag on each request\n"
+ " noxfer no transfer between user space and kernel IO "
+ "buffers\n"
+ " null does nothing, placeholder\n"
+ " pack submit with rising pack_id, complete matching "
+ "each pack_id\n"
+ " tag use tag (from block layer) rather than "
+ "pack_id\n"
+ " v3 use sg v3 interface (default)\n"
+ " v4 use sg vr interface (i.e. struct sg_io_v4)\n");
}
/* Return of 0 -> success, -1 -> failure, 2 -> try again */
@@ -296,6 +322,8 @@ sg_start_io(Rq_coll * clp, Rq_elem * rep)
hp->flags |= SG_FLAG_MMAP_IO;
if (flagp->evfd)
hp->flags |= SGV4_FLAG_EVENTFD;
+ if (flagp->no_waitq)
+ hp->flags |= SGV4_FLAG_NO_WAITQ;
#ifdef SG_DEBUG
pr2serr("%s: SCSI %s, blk=%d num_blks=%d\n", __func__,
rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
@@ -559,7 +587,7 @@ sz_reserve(Rq_coll * clp, bool is_in)
if (vb)
pr2serr("sgs_dd: warning: sg driver prior to 4.0.00\n");
sgs_old_sg_driver = true;
- } else if (t < 40030) {
+ } else if (t < 40045) {
sgs_old_sg_driver = false;
sgs_full_v4_sg_driver = false;
} else
@@ -625,6 +653,20 @@ sz_reserve(Rq_coll * clp, bool is_in)
return 1;
}
}
+ if (flagsp->no_waitq) {
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_WAIT_POLL;
+ if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("ioctl(EXTENDED(NO_WAIT_POLL)) failed, errno=%d %s\n",
+ errno, strerror(errno));
+ return 1;
+ }
+ }
+ } else if (flagsp->no_waitq) {
+ pr2serr("need sg version >= 4.0.45 for no_waitq flag\n");
+ return 1;
}
if (!clp->no_sig) {
if (-1 == fcntl(fd, F_SETOWN, getpid())) {
@@ -868,7 +910,7 @@ do_num_poll_in(Rq_coll * clp, int fd, bool is_evfd)
}
}
a_pollfd.fd = fd;
- if (poll(&a_pollfd, 1, 0) < 0) {
+ if (poll(&a_pollfd, 1, clp->poll_ms) < 0) {
err = errno;
pr2serr("%s: poll(): %s [%d]\n", __func__, strerror(err), err);
return -err;
@@ -887,8 +929,10 @@ do_num_poll_in(Rq_coll * clp, int fd, bool is_evfd)
return (int)count;
} else
return 1; /* could be more but don't know without evfd */
- } else
- return 0;
+ } else if (a_pollfd.revents & POLLERR)
+ ++clp->pollerr_count;
+
+ return 0;
}
static int
@@ -1055,6 +1099,9 @@ process_flags(const char * arg, struct flags_t * fp)
fp->immed = true;
else if (0 == strcmp(cp, "mmap"))
fp->mmap = true;
+ else if ((0 == strcmp(cp, "no_waitq")) ||
+ (0 == strcmp(cp, "no-waitq")))
+ fp->no_waitq = true;
else if (0 == strcmp(cp, "noxfer"))
fp->noxfer = true;
else if (0 == strcmp(cp, "null"))
@@ -1088,6 +1135,7 @@ main(int argc, char * argv[])
int count = -1;
int in_num_sect = 0;
int out_num_sect = 0;
+ int help_pg = 0;
int res, k, in_sect_sz, out_sect_sz, crw, open_fl;
char str[STR_SZ];
char * key;
@@ -1105,7 +1153,7 @@ main(int argc, char * argv[])
inf[0] = '\0';
outf[0] = '\0';
if (argc < 2) {
- usage();
+ usage(1);
return 1;
}
sgs_nanosec_unit = !!getenv("SG3_UTILS_LINUX_NANO");
@@ -1151,7 +1199,9 @@ main(int argc, char * argv[])
pr2serr("%sbad argument to 'oflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"rt_sig"))
+ } else if (0 == strcmp(key,"poll_ms"))
+ clp->poll_ms = sg_get_num(buf);
+ else if (0 == strcmp(key,"rt_sig"))
clp->use_rt_sig = !!sg_get_num(buf);
else if (0 == strcmp(key,"seek"))
seek = sg_get_num(buf);
@@ -1168,9 +1218,17 @@ main(int argc, char * argv[])
clp->debug +=2;
else if ((0 == strcmp(key,"-v")) || (0 == strcmp(key,"--verbose")))
++clp->debug;
+ else if (0 == strcmp(key,"-hhhh"))
+ help_pg +=4;
+ else if (0 == strcmp(key,"-hhh"))
+ help_pg +=3;
+ else if (0 == strcmp(key,"-hh"))
+ help_pg +=2;
+ else if ((0 == strcmp(key,"-h")) || (0 == strcmp(key,"--help")))
+ ++help_pg;
else {
pr2serr("Unrecognized argument '%s'\n", key);
- usage();
+ usage(help_pg);
return 1;
}
}
@@ -1179,9 +1237,14 @@ main(int argc, char * argv[])
} else
bs_given = true;
+ if (help_pg > 0) {
+ usage(help_pg);
+ return 0;
+ }
+
if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) {
pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
- usage();
+ usage(1);
return 1;
}
if (clp->bpt <= 0) {
@@ -1420,6 +1483,9 @@ main(int argc, char * argv[])
if ((! clp->no_sig) && clp->debug > 0)
pr2serr("SIGIO/SIGPOLL signals received: %d, RT sigs: %d\n",
clp->sigs_io_received, clp->sigs_rt_received);
+ if (clp->pollerr_count > 0)
+ pr2serr(">> poll() system call gave POLLERR %d times\n",
+ clp->pollerr_count);
remove_elems(clp);
return res < 0 ? 99 : res;
}
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 2a7e6d9f..fc793dca 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -14,7 +14,7 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2020 Douglas Gilbert
*
- * Version 4.0.44 (20200818)
+ * Version 4.0.45 (20200913)
* This version is for Linux 4 and 5 series kernels.
*
* Documentation
@@ -114,18 +114,18 @@ typedef struct sg_io_hdr {
#define SGV4_FLAG_YIELD_TAG 0x8 /* sg_io_v4::generated_tag set after SG_IOS */
#define SGV4_FLAG_Q_AT_TAIL SG_FLAG_Q_AT_TAIL
#define SGV4_FLAG_Q_AT_HEAD SG_FLAG_Q_AT_HEAD
-#define SGV4_FLAG_NO_WAITQ 0x40 /* implies SGV4_FLAG_IMMED */
+#define SGV4_FLAG_NO_WAITQ 0x40 /* need to poll for completion */
#define SGV4_FLAG_DOUT_OFFSET 0x80 /* dout byte offset in v4::spare_in */
-#define SGV4_FLAG_COMPLETE_B4 0x100
+#define SGV4_FLAG_COMPLETE_B4 0x100 /* mrq: complete this rq before next */
#define SGV4_FLAG_SIGNAL 0x200 /* v3: ignored; v4 signal on completion */
-#define SGV4_FLAG_IMMED 0x400 /* for polling with SG_IOR, ignored in SG_IOS */
+#define SGV4_FLAG_IMMED 0x400 /* issue request and return immediately ... */
#define SGV4_FLAG_STOP_IF 0x800 /* Stops sync mrq if error or warning */
#define SGV4_FLAG_DEV_SCOPE 0x1000 /* permit SG_IOABORT to have wider scope */
#define SGV4_FLAG_SHARE 0x2000 /* share IO buffer; needs SG_SEIM_SHARE_FD */
#define SGV4_FLAG_DO_ON_OTHER 0x4000 /* available on either of shared pair */
#define SGV4_FLAG_KEEP_SHARE 0x8000 /* ... buffer for another dout command */
#define SGV4_FLAG_NO_DXFER SG_FLAG_NO_DXFER /* needed for sharing */
-#define SGV4_FLAG_MULTIPLE_REQS 0x20000 /* n sg_io_v4s in data-in */
+#define SGV4_FLAG_MULTIPLE_REQS 0x20000 /* 1 or more sg_io_v4-s in data-in */
#define SGV4_FLAG_EVENTFD 0x40000 /* signal completion on ... */
#define SGV4_FLAG_ORDERED_WR 0x80000 /* svb: issue in-order writes */
#define SGV4_FLAG_REC_ORDER 0x100000 /* receive order in v4:request_priority */
@@ -218,7 +218,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_CTL_FLAGM_EXCL_WAITQ 0x1000 /* only 1 wake up per response */
#define SG_CTL_FLAGM_SNAP_DEV 0x2000 /* output to debugfs::snapped */
#define SG_CTL_FLAGM_RM_EVENTFD 0x4000 /* only if new eventfd wanted */
-#define SG_CTL_FLAGM_ALL_BITS 0x7fff /* should be OR of previous items */
+#define SG_CTL_FLAGM_NO_WAIT_POLL 0x8000 /* POLLERR on poll(2)s that wait */
+#define SG_CTL_FLAGM_ALL_BITS 0xffff /* 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 */