aboutsummaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2020-09-28 03:47:37 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2020-09-28 03:47:37 +0000
commit20eb07694951b0760f741e7b74c0a363f8ed2b3b (patch)
tree59c16f7951bd6901001c8a460c67958a2151f8dc /testing
parenta37cbfd6b346caf0af438f405a8e72fe69454005 (diff)
downloadsg3_utils-20eb07694951b0760f741e7b74c0a363f8ed2b3b.tar.gz
sg_dd: tweak unrecovered error reporting; testing sg*_dd work, new uapi_sg.h
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@863 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-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
5 files changed, 249 insertions, 126 deletions
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 */