aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-12-29 05:00:57 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-12-29 05:00:57 +0000
commit284fbfc7e0eb7b53b3ab7a9872aa1416685de785 (patch)
tree1b88d64bba80c6dd3c0d7588f1fbc69f0836a0b6
parentc11e8331a86c301d44c34445dabbec8ad6a02d85 (diff)
downloadsg3_utils-284fbfc7e0eb7b53b3ab7a9872aa1416685de785.tar.gz
sgp_dd: clean-up; more testing work for v4 driver
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@803 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog2
-rw-r--r--examples/sg_excl.c3
-rw-r--r--src/sgp_dd.c267
-rw-r--r--testing/Makefile3
-rw-r--r--testing/sgh_dd.c57
-rw-r--r--testing/uapi_sg.h123
6 files changed, 239 insertions, 216 deletions
diff --git a/ChangeLog b/ChangeLog
index 96f785c2..f85461a9 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 [20181224] [svn: r802]
+Changelog for sg3_utils-1.45 [20181228] [svn: r803]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (18-102r0)
diff --git a/examples/sg_excl.c b/examples/sg_excl.c
index 38645252..7e589b23 100644
--- a/examples/sg_excl.c
+++ b/examples/sg_excl.c
@@ -13,7 +13,7 @@
*
* Invocation: sg_excl [-x] <sg_device>
*
- * Version 3.61 (20181207)
+ * Version 3.62 (20181227)
*
* 6 byte INQUIRY command:
* [0x12][ |lu][pg cde][res ][al len][cntrl ]
@@ -195,6 +195,7 @@ int main(int argc, char * argv[])
"msg_status=%d\n", io_hdr.duration, io_hdr.resid,
(int)io_hdr.msg_status);
+ printf("Wait for 60 seconds with O_EXCL help on %s\n", file_name);
sleep(60);
close(sg_fd);
return 0;
diff --git a/src/sgp_dd.c b/src/sgp_dd.c
index e6e06355..42abe3ea 100644
--- a/src/sgp_dd.c
+++ b/src/sgp_dd.c
@@ -68,7 +68,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "5.70 20181213";
+static const char * version_str = "5.71 20181227";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -1180,6 +1180,7 @@ main(int argc, char * argv[])
pthread_t threads[MAX_NUM_THREADS];
int in_sect_sz, out_sect_sz, status, n, flags;
void * vp;
+ Rq_coll * clp = &rcoll;
char ebuff[EBUFF_SZ];
#if SG_LIB_ANDROID
struct sigaction actions;
@@ -1190,12 +1191,12 @@ main(int argc, char * argv[])
actions.sa_handler = thread_exit_handler;
sigaction(SIGUSR1, &actions, NULL);
#endif
- memset(&rcoll, 0, sizeof(Rq_coll));
- rcoll.bpt = DEF_BLOCKS_PER_TRANSFER;
- rcoll.in_type = FT_OTHER;
- rcoll.out_type = FT_OTHER;
- rcoll.cdbsz_in = DEF_SCSI_CDBSZ;
- rcoll.cdbsz_out = DEF_SCSI_CDBSZ;
+ memset(clp, 0, sizeof(*clp));
+ clp->bpt = DEF_BLOCKS_PER_TRANSFER;
+ clp->in_type = FT_OTHER;
+ clp->out_type = FT_OTHER;
+ clp->cdbsz_in = DEF_SCSI_CDBSZ;
+ clp->cdbsz_out = DEF_SCSI_CDBSZ;
inf[0] = '\0';
outf[0] = '\0';
@@ -1212,25 +1213,25 @@ main(int argc, char * argv[])
*buf++ = '\0';
keylen = strlen(key);
if (0 == strcmp(key,"bpt")) {
- rcoll.bpt = sg_get_num(buf);
- if (-1 == rcoll.bpt) {
+ clp->bpt = sg_get_num(buf);
+ if (-1 == clp->bpt) {
pr2serr("%sbad argument to 'bpt='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
bpt_given = 1;
} else if (0 == strcmp(key,"bs")) {
- rcoll.bs = sg_get_num(buf);
- if (-1 == rcoll.bs) {
+ clp->bs = sg_get_num(buf);
+ if (-1 == clp->bs) {
pr2serr("%sbad argument to 'bs='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"cdbsz")) {
- rcoll.cdbsz_in = sg_get_num(buf);
- rcoll.cdbsz_out = rcoll.cdbsz_in;
+ clp->cdbsz_in = sg_get_num(buf);
+ clp->cdbsz_out = clp->cdbsz_in;
cdbsz_given = 1;
} else if (0 == strcmp(key,"coe")) {
- rcoll.in_flags.coe = !! sg_get_num(buf);
- rcoll.out_flags.coe = rcoll.in_flags.coe;
+ clp->in_flags.coe = !! sg_get_num(buf);
+ clp->out_flags.coe = clp->in_flags.coe;
} else if (0 == strcmp(key,"count")) {
if (0 != strcmp("-1", buf)) {
dd_count = sg_get_llnum(buf);
@@ -1241,16 +1242,16 @@ main(int argc, char * argv[])
} /* treat 'count=-1' as calculate count (same as not given) */
} else if ((0 == strncmp(key,"deb", 3)) ||
(0 == strncmp(key,"verb", 4)))
- rcoll.debug = sg_get_num(buf);
+ clp->debug = sg_get_num(buf);
else if (0 == strcmp(key,"dio")) {
- rcoll.in_flags.dio = !! sg_get_num(buf);
- rcoll.out_flags.dio = rcoll.in_flags.dio;
+ clp->in_flags.dio = !! sg_get_num(buf);
+ clp->out_flags.dio = clp->in_flags.dio;
} else if (0 == strcmp(key,"fua")) {
n = sg_get_num(buf);
if (n & 1)
- rcoll.out_flags.fua = true;
+ clp->out_flags.fua = true;
if (n & 2)
- rcoll.in_flags.fua = true;
+ clp->in_flags.fua = true;
} else if (0 == strcmp(key,"ibs")) {
ibs = sg_get_num(buf);
if (-1 == ibs) {
@@ -1264,7 +1265,7 @@ main(int argc, char * argv[])
} else
snprintf(inf, INOUTF_SZ, "%s", buf);
} else if (0 == strcmp(key, "iflag")) {
- if (process_flags(buf, &rcoll.in_flags)) {
+ if (process_flags(buf, &clp->in_flags)) {
pr2serr("%sbad argument to 'iflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
@@ -1281,7 +1282,7 @@ main(int argc, char * argv[])
} else
snprintf(outf, INOUTF_SZ, "%s", buf);
} else if (0 == strcmp(key, "oflag")) {
- if (process_flags(buf, &rcoll.out_flags)) {
+ if (process_flags(buf, &clp->out_flags)) {
pr2serr("%sbad argument to 'oflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
@@ -1306,7 +1307,7 @@ main(int argc, char * argv[])
else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
res = 0;
n = num_chs_in_str(key + 1, keylen - 1, 'd');
- rcoll.dry_run += n;
+ clp->dry_run += n;
res += n;
n = num_chs_in_str(key + 1, keylen - 1, 'h');
if (n > 0) {
@@ -1316,7 +1317,7 @@ main(int argc, char * argv[])
n = num_chs_in_str(key + 1, keylen - 1, 'v');
if (n > 0)
verbose_given = true;
- rcoll.debug += n; /* -v ---> --verbose */
+ clp->debug += n; /* -v ---> --verbose */
res += n;
n = num_chs_in_str(key + 1, keylen - 1, 'V');
if (n > 0)
@@ -1330,14 +1331,14 @@ main(int argc, char * argv[])
}
} else if ((0 == strncmp(key, "--dry-run", 9)) ||
(0 == strncmp(key, "--dry_run", 9)))
- ++rcoll.dry_run;
+ ++clp->dry_run;
else if ((0 == strncmp(key, "--help", 6)) ||
(0 == strcmp(key, "-?"))) {
usage();
return 0;
} else if (0 == strncmp(key, "--verb", 6)) {
verbose_given = true;
- ++rcoll.debug; /* --verbose */
+ ++clp->debug; /* --verbose */
} else if (0 == strncmp(key, "--vers", 6))
version_given = true;
else {
@@ -1353,12 +1354,12 @@ main(int argc, char * argv[])
pr2serr("but override: '-vV' given, zero verbose and continue\n");
verbose_given = false;
version_given = false;
- rcoll.debug = 0;
+ clp->debug = 0;
} else if (! verbose_given) {
pr2serr("set '-vv'\n");
- rcoll.debug = 2;
+ clp->debug = 2;
} else
- pr2serr("keep verbose=%d\n", rcoll.debug);
+ pr2serr("keep verbose=%d\n", clp->debug);
#else
if (verbose_given && version_given)
pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
@@ -1368,12 +1369,12 @@ main(int argc, char * argv[])
return 0;
}
- if (rcoll.bs <= 0) {
- rcoll.bs = DEF_BLOCK_SIZE;
+ if (clp->bs <= 0) {
+ clp->bs = DEF_BLOCK_SIZE;
pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n",
- rcoll.bs);
+ clp->bs);
}
- if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) {
+ if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) {
pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
usage();
return SG_LIB_SYNTAX_ERROR;
@@ -1382,25 +1383,25 @@ main(int argc, char * argv[])
pr2serr("skip and seek cannot be negative\n");
return SG_LIB_SYNTAX_ERROR;
}
- if (rcoll.out_flags.append && (seek > 0)) {
+ if (clp->out_flags.append && (seek > 0)) {
pr2serr("Can't use both append and seek switches\n");
return SG_LIB_SYNTAX_ERROR;
}
- if (rcoll.bpt < 1) {
+ if (clp->bpt < 1) {
pr2serr("bpt must be greater than 0\n");
return SG_LIB_SYNTAX_ERROR;
}
/* 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. */
- if ((rcoll.bs >= 2048) && (0 == bpt_given))
- rcoll.bpt = DEF_BLOCKS_PER_2048TRANSFER;
+ if ((clp->bs >= 2048) && (0 == bpt_given))
+ clp->bpt = DEF_BLOCKS_PER_2048TRANSFER;
if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
pr2serr("too few or too many threads requested\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
- if (rcoll.debug)
+ if (clp->debug)
pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%"
PRId64 "\n", my_name, inf, skip, outf, seek, dd_count);
@@ -1409,46 +1410,46 @@ main(int argc, char * argv[])
install_handler(SIGPIPE, interrupt_handler);
install_handler(SIGUSR1, siginfo_handler);
- rcoll.infd = STDIN_FILENO;
- rcoll.outfd = STDOUT_FILENO;
+ clp->infd = STDIN_FILENO;
+ clp->outfd = STDOUT_FILENO;
if (inf[0] && ('-' != inf[0])) {
- rcoll.in_type = dd_filetype(inf);
+ clp->in_type = dd_filetype(inf);
- if (FT_ERROR == rcoll.in_type) {
+ if (FT_ERROR == clp->in_type) {
pr2serr("%sunable to access %s\n", my_name, inf);
return SG_LIB_FILE_ERROR;
- } else if (FT_ST == rcoll.in_type) {
+ } else if (FT_ST == clp->in_type) {
pr2serr("%sunable to use scsi tape device %s\n", my_name, inf);
return SG_LIB_FILE_ERROR;
- } else if (FT_SG == rcoll.in_type) {
+ } else if (FT_SG == clp->in_type) {
flags = O_RDWR;
- if (rcoll.in_flags.direct)
+ if (clp->in_flags.direct)
flags |= O_DIRECT;
- if (rcoll.in_flags.excl)
+ if (clp->in_flags.excl)
flags |= O_EXCL;
- if (rcoll.in_flags.dsync)
+ if (clp->in_flags.dsync)
flags |= O_SYNC;
- if ((rcoll.infd = open(inf, flags)) < 0) {
+ if ((clp->infd = open(inf, flags)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
"reading", my_name, inf);
perror(ebuff);
return sg_convert_errno(err);;
}
- if (sg_prepare(rcoll.infd, rcoll.bs, rcoll.bpt))
+ if (sg_prepare(clp->infd, clp->bs, clp->bpt))
return SG_LIB_FILE_ERROR;
}
else {
flags = O_RDONLY;
- if (rcoll.in_flags.direct)
+ if (clp->in_flags.direct)
flags |= O_DIRECT;
- if (rcoll.in_flags.excl)
+ if (clp->in_flags.excl)
flags |= O_EXCL;
- if (rcoll.in_flags.dsync)
+ if (clp->in_flags.dsync)
flags |= O_SYNC;
- if ((rcoll.infd = open(inf, flags)) < 0) {
+ if ((clp->infd = open(inf, flags)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading",
my_name, inf);
@@ -1458,8 +1459,8 @@ main(int argc, char * argv[])
else if (skip > 0) {
off64_t offset = skip;
- offset *= rcoll.bs; /* could exceed 32 here! */
- if (lseek64(rcoll.infd, offset, SEEK_SET) < 0) {
+ offset *= clp->bs; /* could exceed 32 here! */
+ if (lseek64(clp->infd, offset, SEEK_SET) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required "
"position on %s", my_name, inf);
@@ -1470,22 +1471,22 @@ main(int argc, char * argv[])
}
}
if (outf[0] && ('-' != outf[0])) {
- rcoll.out_type = dd_filetype(outf);
+ clp->out_type = dd_filetype(outf);
- if (FT_ST == rcoll.out_type) {
+ if (FT_ST == clp->out_type) {
pr2serr("%sunable to use scsi tape device %s\n", my_name, outf);
return SG_LIB_FILE_ERROR;
}
- else if (FT_SG == rcoll.out_type) {
+ else if (FT_SG == clp->out_type) {
flags = O_RDWR;
- if (rcoll.out_flags.direct)
+ if (clp->out_flags.direct)
flags |= O_DIRECT;
- if (rcoll.out_flags.excl)
+ if (clp->out_flags.excl)
flags |= O_EXCL;
- if (rcoll.out_flags.dsync)
+ if (clp->out_flags.dsync)
flags |= O_SYNC;
- if ((rcoll.outfd = open(outf, flags)) < 0) {
+ if ((clp->outfd = open(outf, flags)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
"writing", my_name, outf);
@@ -1493,24 +1494,24 @@ main(int argc, char * argv[])
return sg_convert_errno(err);
}
- if (sg_prepare(rcoll.outfd, rcoll.bs, rcoll.bpt))
+ if (sg_prepare(clp->outfd, clp->bs, clp->bpt))
return SG_LIB_FILE_ERROR;
}
- else if (FT_DEV_NULL == rcoll.out_type)
- rcoll.outfd = -1; /* don't bother opening */
+ else if (FT_DEV_NULL == clp->out_type)
+ clp->outfd = -1; /* don't bother opening */
else {
- if (FT_RAW != rcoll.out_type) {
+ if (FT_RAW != clp->out_type) {
flags = O_WRONLY | O_CREAT;
- if (rcoll.out_flags.direct)
+ if (clp->out_flags.direct)
flags |= O_DIRECT;
- if (rcoll.out_flags.excl)
+ if (clp->out_flags.excl)
flags |= O_EXCL;
- if (rcoll.out_flags.dsync)
+ if (clp->out_flags.dsync)
flags |= O_SYNC;
- if (rcoll.out_flags.append)
+ if (clp->out_flags.append)
flags |= O_APPEND;
- if ((rcoll.outfd = open(outf, flags, 0666)) < 0) {
+ if ((clp->outfd = open(outf, flags, 0666)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for "
"writing", my_name, outf);
@@ -1519,7 +1520,7 @@ main(int argc, char * argv[])
}
}
else { /* raw output file */
- if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) {
+ if ((clp->outfd = open(outf, O_WRONLY)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for raw "
"writing", my_name, outf);
@@ -1530,8 +1531,8 @@ main(int argc, char * argv[])
if (seek > 0) {
off64_t offset = seek;
- offset *= rcoll.bs; /* could exceed 32 bits here! */
- if (lseek64(rcoll.outfd, offset, SEEK_SET) < 0) {
+ offset *= clp->bs; /* could exceed 32 bits here! */
+ if (lseek64(clp->outfd, offset, SEEK_SET) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required "
"position on %s", my_name, outf);
@@ -1541,18 +1542,18 @@ main(int argc, char * argv[])
}
}
}
- if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
+ if ((STDIN_FILENO == clp->infd) && (STDOUT_FILENO == clp->outfd)) {
pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n");
pr2serr("For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
}
if (dd_count < 0) {
in_num_sect = -1;
- if (FT_SG == rcoll.in_type) {
- res = scsi_read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
+ if (FT_SG == clp->in_type) {
+ res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz);
if (2 == res) {
pr2serr("Unit attention, media changed(in), continuing\n");
- res = scsi_read_capacity(rcoll.infd, &in_num_sect,
+ res = scsi_read_capacity(clp->infd, &in_num_sect,
&in_sect_sz);
}
if (0 != res) {
@@ -1564,15 +1565,15 @@ main(int argc, char * argv[])
pr2serr("Unable to read capacity on %s\n", inf);
in_num_sect = -1;
}
- } else if (FT_BLOCK == rcoll.in_type) {
- if (0 != read_blkdev_capacity(rcoll.infd, &in_num_sect,
+ } else if (FT_BLOCK == clp->in_type) {
+ if (0 != read_blkdev_capacity(clp->infd, &in_num_sect,
&in_sect_sz)) {
pr2serr("Unable to read block capacity on %s\n", inf);
in_num_sect = -1;
}
- if (rcoll.bs != in_sect_sz) {
+ if (clp->bs != in_sect_sz) {
pr2serr("logical block size on %s confusion; bs=%d, from "
- "device=%d\n", inf, rcoll.bs, in_sect_sz);
+ "device=%d\n", inf, clp->bs, in_sect_sz);
in_num_sect = -1;
}
}
@@ -1580,11 +1581,11 @@ main(int argc, char * argv[])
in_num_sect -= skip;
out_num_sect = -1;
- if (FT_SG == rcoll.out_type) {
- res = scsi_read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
+ if (FT_SG == clp->out_type) {
+ res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz);
if (2 == res) {
pr2serr("Unit attention, media changed(out), continuing\n");
- res = scsi_read_capacity(rcoll.outfd, &out_num_sect,
+ res = scsi_read_capacity(clp->outfd, &out_num_sect,
&out_sect_sz);
}
if (0 != res) {
@@ -1596,15 +1597,15 @@ main(int argc, char * argv[])
pr2serr("Unable to read capacity on %s\n", outf);
out_num_sect = -1;
}
- } else if (FT_BLOCK == rcoll.out_type) {
- if (0 != read_blkdev_capacity(rcoll.outfd, &out_num_sect,
+ } else if (FT_BLOCK == clp->out_type) {
+ if (0 != read_blkdev_capacity(clp->outfd, &out_num_sect,
&out_sect_sz)) {
pr2serr("Unable to read block capacity on %s\n", outf);
out_num_sect = -1;
}
- if (rcoll.bs != out_sect_sz) {
+ if (clp->bs != out_sect_sz) {
pr2serr("logical block size on %s confusion: bs=%d, from "
- "device=%d\n", outf, rcoll.bs, out_sect_sz);
+ "device=%d\n", outf, clp->bs, out_sect_sz);
out_num_sect = -1;
}
}
@@ -1621,7 +1622,7 @@ main(int argc, char * argv[])
else
dd_count = out_num_sect;
}
- if (rcoll.debug > 1)
+ if (clp->debug > 1)
pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64
", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect,
out_num_sect);
@@ -1630,38 +1631,38 @@ main(int argc, char * argv[])
return SG_LIB_CAT_OTHER;
}
if (! cdbsz_given) {
- if ((FT_SG == rcoll.in_type) && (MAX_SCSI_CDBSZ != rcoll.cdbsz_in) &&
- (((dd_count + skip) > UINT_MAX) || (rcoll.bpt > USHRT_MAX))) {
+ if ((FT_SG == clp->in_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_in) &&
+ (((dd_count + skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) {
pr2serr("Note: SCSI command size increased to 16 bytes (for "
"'if')\n");
- rcoll.cdbsz_in = MAX_SCSI_CDBSZ;
+ clp->cdbsz_in = MAX_SCSI_CDBSZ;
}
- if ((FT_SG == rcoll.out_type) && (MAX_SCSI_CDBSZ != rcoll.cdbsz_out) &&
- (((dd_count + seek) > UINT_MAX) || (rcoll.bpt > USHRT_MAX))) {
+ if ((FT_SG == clp->out_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_out) &&
+ (((dd_count + seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) {
pr2serr("Note: SCSI command size increased to 16 bytes (for "
"'of')\n");
- rcoll.cdbsz_out = MAX_SCSI_CDBSZ;
+ clp->cdbsz_out = MAX_SCSI_CDBSZ;
}
}
- rcoll.in_count = dd_count;
- rcoll.in_rem_count = dd_count;
- rcoll.skip = skip;
- rcoll.in_blk = skip;
- rcoll.out_count = dd_count;
- rcoll.out_rem_count = dd_count;
- rcoll.seek = seek;
- rcoll.out_blk = seek;
- status = pthread_mutex_init(&rcoll.in_mutex, NULL);
+ clp->in_count = dd_count;
+ clp->in_rem_count = dd_count;
+ clp->skip = skip;
+ clp->in_blk = skip;
+ clp->out_count = dd_count;
+ clp->out_rem_count = dd_count;
+ clp->seek = seek;
+ clp->out_blk = seek;
+ status = pthread_mutex_init(&clp->in_mutex, NULL);
if (0 != status) err_exit(status, "init in_mutex");
- status = pthread_mutex_init(&rcoll.out_mutex, NULL);
+ status = pthread_mutex_init(&clp->out_mutex, NULL);
if (0 != status) err_exit(status, "init out_mutex");
- status = pthread_mutex_init(&rcoll.aux_mutex, NULL);
+ status = pthread_mutex_init(&clp->aux_mutex, NULL);
if (0 != status) err_exit(status, "init aux_mutex");
- status = pthread_cond_init(&rcoll.out_sync_cv, NULL);
+ status = pthread_cond_init(&clp->out_sync_cv, NULL);
if (0 != status) err_exit(status, "init out_sync_cv");
- if (rcoll.dry_run > 0) {
+ if (clp->dry_run > 0) {
pr2serr("Due to --dry-run option, bypass copy/read\n");
goto fini;
}
@@ -1670,7 +1671,7 @@ main(int argc, char * argv[])
status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
if (0 != status) err_exit(status, "pthread_sigmask");
status = pthread_create(&sig_listen_thread_id, NULL,
- sig_listen_thread, (void *)&rcoll);
+ sig_listen_thread, (void *)clp);
if (0 != status) err_exit(status, "pthread_create, sig...");
if (do_time) {
@@ -1680,30 +1681,30 @@ main(int argc, char * argv[])
}
/* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */
- if ((rcoll.out_rem_count > 0) && (num_threads > 0)) {
+ if ((clp->out_rem_count > 0) && (num_threads > 0)) {
/* Run 1 work thread to shake down infant retryable stuff */
- status = pthread_mutex_lock(&rcoll.out_mutex);
+ status = pthread_mutex_lock(&clp->out_mutex);
if (0 != status) err_exit(status, "lock out_mutex");
status = pthread_create(&threads[0], NULL, read_write_thread,
- (void *)&rcoll);
+ (void *)clp);
if (0 != status) err_exit(status, "pthread_create");
- if (rcoll.debug)
+ if (clp->debug)
pr2serr("Starting worker thread k=0\n");
/* wait for any broadcast */
- pthread_cleanup_push(cleanup_out, (void *)&rcoll);
- status = pthread_cond_wait(&rcoll.out_sync_cv, &rcoll.out_mutex);
+ pthread_cleanup_push(cleanup_out, (void *)clp);
+ status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex);
if (0 != status) err_exit(status, "cond out_sync_cv");
pthread_cleanup_pop(0);
- status = pthread_mutex_unlock(&rcoll.out_mutex);
+ status = pthread_mutex_unlock(&clp->out_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
/* now start the rest of the threads */
for (k = 1; k < num_threads; ++k) {
status = pthread_create(&threads[k], NULL, read_write_thread,
- (void *)&rcoll);
+ (void *)clp);
if (0 != status) err_exit(status, "pthread_create");
- if (rcoll.debug)
+ if (clp->debug)
pr2serr("Starting worker thread k=%d\n", k);
}
@@ -1711,7 +1712,7 @@ main(int argc, char * argv[])
for (k = 0; k < num_threads; ++k) {
status = pthread_join(threads[k], &vp);
if (0 != status) err_exit(status, "pthread_join");
- if (rcoll.debug)
+ if (clp->debug)
pr2serr("Worker thread k=%d terminated\n", k);
}
} /* started worker threads and here after they have all exited */
@@ -1720,12 +1721,12 @@ main(int argc, char * argv[])
calc_duration_throughput(0);
if (do_sync) {
- if (FT_SG == rcoll.out_type) {
+ if (FT_SG == clp->out_type) {
pr2serr(">> Synchronizing cache on %s\n", outf);
- res = sg_ll_sync_cache_10(rcoll.outfd, 0, 0, 0, 0, 0, false, 0);
+ res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0);
if (SG_LIB_CAT_UNIT_ATTENTION == res) {
pr2serr("Unit attention(out), continuing\n");
- res = sg_ll_sync_cache_10(rcoll.outfd, 0, 0, 0, 0, 0, false,
+ res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false,
0);
}
if (0 != res)
@@ -1752,24 +1753,24 @@ main(int argc, char * argv[])
* _join() to clear heap taken by associated _create() */
fini:
- if (STDIN_FILENO != rcoll.infd)
- close(rcoll.infd);
- if ((STDOUT_FILENO != rcoll.outfd) && (FT_DEV_NULL != rcoll.out_type))
- close(rcoll.outfd);
+ if (STDIN_FILENO != clp->infd)
+ close(clp->infd);
+ if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type))
+ close(clp->outfd);
res = exit_status;
- if ((0 != rcoll.out_count) && (0 == rcoll.dry_run)) {
+ if ((0 != clp->out_count) && (0 == clp->dry_run)) {
pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n",
- rcoll.out_count);
+ clp->out_count);
if (0 == res)
res = SG_LIB_CAT_OTHER;
}
print_stats("");
- if (rcoll.dio_incomplete_count) {
+ if (clp->dio_incomplete_count) {
int fd;
char c;
pr2serr(">> Direct IO requested but incomplete %d times\n",
- rcoll.dio_incomplete_count);
+ clp->dio_incomplete_count);
if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
if (1 == read(fd, &c, 1)) {
if ('0' == c)
@@ -1779,8 +1780,8 @@ fini:
close(fd);
}
}
- if (rcoll.sum_of_resids)
+ if (clp->sum_of_resids)
pr2serr(">> Non-zero sum of residual counts=%d\n",
- rcoll.sum_of_resids);
+ clp->sum_of_resids);
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
diff --git a/testing/Makefile b/testing/Makefile
index 9326ef36..e337e66b 100644
--- a/testing/Makefile
+++ b/testing/Makefile
@@ -27,7 +27,8 @@ LD = $(CC)
CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME
# 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
+CFLAGS = -g -O2 -W -Wall -DDEBUG
# CFLAGS = -g -O2 -Wall -DSG_KERNEL_INCLUDES
# CFLAGS = -g -O2 -Wall -pedantic
# CFLAGS = -Wall -W -pedantic -std=c11 --analyze
diff --git a/testing/sgh_dd.c b/testing/sgh_dd.c
index f84bac5e..72c37530 100644
--- a/testing/sgh_dd.c
+++ b/testing/sgh_dd.c
@@ -91,11 +91,13 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.09 20181224";
+static const char * version_str = "1.12 20181227";
#ifdef __GNUC__
+#ifndef __clang__
#pragma GCC diagnostic ignored "-Wclobbered"
#endif
+#endif
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -178,7 +180,6 @@ typedef struct global_collection
bool out_stop; /* | */
pthread_mutex_t out_mutex; /* | */
pthread_cond_t out_sync_cv; /* | hold writes until "in order" */
- pthread_cond_t hold_1st_cv; /* -/ wait for 1st thread to do 1 seg */
pthread_mutex_t out2_mutex;
int bs;
int bpt;
@@ -403,6 +404,20 @@ siginfo_handler(int sig)
}
static void
+siginfo2_handler(int sig)
+{
+ Gbl_coll * clp = &gcoll;
+
+ if (sig) { ; } /* unused, dummy to suppress warning */
+ pr2serr("Progress report, continuing ...\n");
+ if (do_time)
+ calc_duration_throughput(1);
+ print_stats(" ");
+ pr2serr("Send broadcast on out_sync_cv condition variable\n");
+ pthread_cond_broadcast(&clp->out_sync_cv);
+}
+
+static void
install_handler(int sig_num, void (*sig_handler) (int sig))
{
struct sigaction sigact;
@@ -766,7 +781,6 @@ read_write_thread(void * v_tip)
bool own_infd = false;
bool own_outfd = false;
bool own_out2fd = false;
- bool is_first = true;
bool share_and_ofreg;
tip = (Thread_info *)v_tip;
@@ -797,17 +811,6 @@ read_write_thread(void * v_tip)
rep->in_flags = clp->in_flags;
rep->out_flags = clp->out_flags;
- if (rep->id > 0) {
- /* wait for a broadcast on hold_1st_cv other than tid=0 thread so
- * tide=0 can complete one READ/WRITE cycle (segment), makes infant
- * mortality errors easier to analyze and fix. */
- pthread_cleanup_push(cleanup_out, (void *)clp);
- status = pthread_cond_wait(&clp->hold_1st_cv, &clp->out_mutex);
- if (0 != status) err_exit(status, "cond hold_1st_cv");
- pthread_cleanup_pop(0);
- status = pthread_mutex_unlock(&clp->out_mutex);
- if (0 != status) err_exit(status, "unlock out_mutex");
- }
if (rep->in_flags.same_fds || rep->out_flags.same_fds)
; /* we are sharing a single pair of fd_s across all threads */
else {
@@ -865,7 +868,7 @@ read_write_thread(void * v_tip)
} else if ((FT_SG == clp->in_type) && (FT_SG == clp->out_type))
rep->has_share = sg_share_prepare(rep->outfd, rep->infd, rep->id,
rep->debug > 9);
- if (vb > 0)
+ if (vb > 9)
pr2serr_lk("tid=%d, has_share=%s\n", rep->id,
(rep->has_share ? "true" : "false"));
share_and_ofreg = (rep->has_share && (rep->outregfd >= 0));
@@ -977,11 +980,7 @@ skip_force_out_sequence:
pthread_cleanup_pop(0);
}
// if ((! rep->has_share) && (FT_DEV_NULL != clp->out_type))
- pthread_cond_broadcast(&clp->out_sync_cv);
- if ((0 == rep->id) && is_first) {
- is_first = false; /* allow rest of threads to start */
- pthread_cond_broadcast(&clp->hold_1st_cv);
- }
+ pthread_cond_broadcast(&clp->out_sync_cv);
if (stop_after_write)
break;
} /* end of while loop which copies segments */
@@ -1011,10 +1010,6 @@ fini:
if (own_out2fd)
close(rep->out2fd);
pthread_cond_broadcast(&clp->out_sync_cv);
- if ((0 == rep->id) && is_first) {
- is_first = false; /* allow rest of threads to start */
- pthread_cond_broadcast(&clp->hold_1st_cv);
- }
return stop_after_write ? NULL : clp;
}
@@ -1527,7 +1522,7 @@ sg_finish_io(bool wr, Rq_elem * rep, bool is_wr2)
((EINTR == errno) || (EAGAIN == errno)))
sched_yield(); /* another thread may be able to progress */
if (res < 0) {
- perror("finishing io on sg device, error");
+ perror("finishing io [read(2)] on sg device, error");
return -1;
}
if (rep != (Rq_elem *)io_hdr.usr_ptr)
@@ -1576,7 +1571,7 @@ do_v4:
((EINTR == errno) || (EAGAIN == errno)))
sched_yield(); /* another thread may be able to progress */
if (res < 0) {
- perror("finishing io on sg device, error");
+ perror("finishing io [SG_IORECEIVE] on sg device, error");
return -1;
}
if (rep != (Rq_elem *)h4p->usr_ptr)
@@ -1854,6 +1849,7 @@ main(int argc, char * argv[])
actions.sa_flags = 0;
actions.sa_handler = thread_exit_handler;
sigaction(SIGUSR1, &actions, NULL);
+ sigaction(SIGUSR2, &actions, NULL);
#endif
memset(clp, 0, sizeof(*clp));
memset(thread_arr, 0, sizeof(thread_arr));
@@ -2111,6 +2107,7 @@ main(int argc, char * argv[])
install_handler(SIGQUIT, interrupt_handler);
install_handler(SIGPIPE, interrupt_handler);
install_handler(SIGUSR1, siginfo_handler);
+ install_handler(SIGUSR2, siginfo2_handler);
clp->infd = STDIN_FILENO;
clp->outfd = STDOUT_FILENO;
@@ -2489,6 +2486,14 @@ main(int argc, char * argv[])
(void *)tip);
if (0 != status) err_exit(status, "pthread_create");
+ /* wait for any broadcast */
+ pthread_cleanup_push(cleanup_out, (void *)clp);
+ status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex);
+ if (0 != status) err_exit(status, "cond out_sync_cv");
+ pthread_cleanup_pop(0);
+ status = pthread_mutex_unlock(&clp->out_mutex);
+ if (0 != status) err_exit(status, "unlock out_mutex");
+
/* now start the rest of the threads */
for (k = 1; k < num_threads; ++k) {
tip = thread_arr + k;
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 51cc31dd..d6f366af 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 - 2018 Douglas Gilbert
*
- * Version 4.0.02 (20181223)
+ * Version 4.0.03 (20181227)
* This version is for Linux 2.6, 3 and 4 series kernels.
*
* Documentation
@@ -52,7 +52,7 @@ typedef struct sg_io_hdr {
unsigned char mx_sb_len;/* [i] max length to write to sbp */
unsigned short iovec_count; /* [i] 0 implies no sgat list */
unsigned int dxfer_len; /* [i] byte count of data transfer */
- /* points to data transfer memory or scatter gather list */
+ /* dxferp points to data transfer memory or scatter gather list */
void __user *dxferp; /* [i], [*io] */
unsigned char __user *cmdp;/* [i], [*i] points to command to perform */
void __user *sbp; /* [i], [*o] points to sense_buffer memory */
@@ -79,29 +79,30 @@ typedef struct sg_io_hdr {
#define SG_DXFER_TO_DEV (-2) /* data-out buffer e.g. SCSI WRITE command */
#define SG_DXFER_FROM_DEV (-3) /* data-in buffer e.g. SCSI READ command */
/*
- * treated like SG_DXFER_FROM_DEV with the additional property than during
- * indirect IO the user buffer is copied into the kernel buffers _before_
- * the transfer from the device takes place. Useful if short DMA transfers
- * (less than requested) are not reported (e.g. resid always 0).
+ * SG_DXFER_TO_FROM_DEV is treated like SG_DXFER_FROM_DEV with the additional
+ * property than during indirect IO the user buffer is copied into the kernel
+ * buffers _before_ the transfer from the device takes place. Useful if short
+ * DMA transfers (less than requested) are not reported (e.g. resid always 0).
*/
#define SG_DXFER_TO_FROM_DEV (-4)
#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction, do not use */
-/* following flag values can be OR-ed together */
+/* following flag values can be OR-ed together in v3::flags or v4::flags */
#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
+/* SG_FLAG_UNUSED_LUN_INHIBIT is ignored in sg v4 driver */
#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */
/* command block (when <= SCSI_2) */
#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */
-/* no transfer of kernel buffers to/from user space; to debug indirect IO */
+/* no transfer of kernel buffers to/from user space; used for sharing */
#define SG_FLAG_NO_DXFER 0x10000
-/* defaults: for sg driver (v3): Q_AT_HEAD; for block layer: Q_AT_TAIL */
+/* defaults: for sg driver (v3_v4): Q_AT_HEAD; for block layer: Q_AT_TAIL */
#define SG_FLAG_Q_AT_TAIL 0x10
#define SG_FLAG_Q_AT_HEAD 0x20
/*
* Flags used by ioctl(SG_IOSUBMIT) [abbrev: SG_IOS] and ioctl(SG_IORECEIVE)
- * [abbrev: SG_IOR] OR-ed into sg_io_v4::flags, also with ioctl(SG_IO) when
- * sg_io_v4::guard is 'Q' in which case SGV4_FLAG_SYNC is implicitly set.
+ * [abbrev: SG_IOR] OR-ed into sg_io_v4::flags. The sync v4 interface uses
+ * ioctl(SG_IO) and can take these new flags, as can the v3 interface.
* These flags apply for SG_IOS unless otherwise noted. May be OR-ed together.
*/
#define SGV4_FLAG_DIRECT_IO SG_FLAG_DIRECT_IO
@@ -109,14 +110,14 @@ typedef struct sg_io_hdr {
#define SGV4_FLAG_YIELD_TAG 0x8 /* sg_io_v4::request_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_FIND_BY_TAG 0x100 /* in SG_IOR, def: find by pack_id */
-#define SGV4_FLAG_IMMED 0x400 /* for polling with SG_IOR else ignored */
+/* Flag values 0x100 and 0x200 not currently used */
+#define SGV4_FLAG_IMMED 0x400 /* for polling with SG_IOR, ignored in SG_IOS */
/* Flag value 0x800 not currently used */
#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_NO_DXFER SG_FLAG_NO_DXFER
+#define SGV4_FLAG_NO_DXFER SG_FLAG_NO_DXFER /* needed for sharing */
-/* following 'info' values are OR-ed together */
+/* Output (potentially OR-ed together) in v3::info or v4::info field */
#define SG_INFO_OK_MASK 0x1
#define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */
#define SG_INFO_CHECK 0x1 /* something abnormal happened */
@@ -137,55 +138,61 @@ typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
int scsi_type; /* TYPE_... defined in scsi/scsi.h */
short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
short d_queue_depth;/* device (or adapter) maximum queue length */
- int unused[2]; /* probably find a good use, set 0 for now */
+ int minor_num; /* new in sg v4 driver, example: 3 for /dev/sg3 */
+ int unused[1]; /* held in reserve, set 0 for now */
} sg_scsi_id_t;
+/* For backward compatibility v4 driver yields at most SG_MAX_QUEUE of these */
typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
- char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */
+ char req_state; /* See 'enum sg_rq_state' definition in v4 driver */
char orphan; /* 0 -> normal request, 1 -> from interrupted SG_IO */
+ /* sg_io_owned set imples synchronous, clear implies asynchronous */
char sg_io_owned;/* 0 -> complete with read(), 1 -> owned by SG_IO */
char problem; /* 0 -> no problem detected, 1 -> error to report */
- int pack_id; /* pack_id associated with request */
- void __user *usr_ptr; /* user provided pointer (in new interface) */
+ /* If SG_CTL_FLAGM_TAG_FOR_PACK_ID set on fd then next field is tag */
+ int pack_id; /* pack_id, in v4 driver may be tag instead */
+ void __user *usr_ptr; /* user provided pointer in v3+v4 interface */
/*
* millisecs elapsed since the command started (req_state==1) or
- * command duration (req_state==2). May be in nanoseconds after
- * the SG_SET_GET_EXTENDED ioctl.
+ * command duration (req_state==2). Will be in nanoseconds after
+ * the SG_SET_GET_EXTENDED{TIME_IN_NS} ioctl.
*/
unsigned int duration;
int unused;
} sg_req_info_t;
/*
- * The following defines may help when using struct sg_extended_info which
+ * The following defines are for manipulating struct sg_extended_info which
* is abbreviated to "SEI". A following "M" (i.e. "_SEIM_") indicates a
* mask. Most mask values correspond to a integer (usually a __u32) apart
- * from SG_SEIM_CTL_FLAGS which is for a collection of boolean values
- * packed into an integer. The mask values for those booleans start with
- * "SG_CTL_FLAGM_". The scope of these settings, like most other ioctls,
- * is usually that of the file descriptor the ioctl is executed on. Masks
- * marked with "rd" are read-only, attempts to write to them are ignored.
+ * from SG_SEIM_CTL_FLAGS which is for boolean values packed into an integer.
+ * The mask values for those booleans start with "SG_CTL_FLAGM_". The scope
+ * of these settings, like most other ioctls, is usually that of the file
+ * descriptor the ioctl is executed on. The "rd:" indication means read-only,
+ * attempts to write to them are ignored. "rd>" means action when reading.
*/
#define SG_SEIM_RESERVED_SIZE 0x1 /* reserved_sz field valid */
#define SG_SEIM_RQ_REM_THRESH 0x2 /* rq_rem_sgat_thresh field valid */
#define SG_SEIM_TOT_FD_THRESH 0x4 /* tot_fd_thresh field valid */
#define SG_SEIM_CTL_FLAGS 0x8 /* ctl_flags_mask bits in ctl_flags */
#define SG_SEIM_MINOR_INDEX 0x10 /* sg device minor index number */
-#define SG_SEIM_READ_VAL 0x20 /* write SG_SEIRV, read related */
+#define SG_SEIM_READ_VAL 0x20 /* write SG_SEIRV_*, read back value */
#define SG_SEIM_SHARE_FD 0x40 /* slave gives fd of master, sharing */
#define SG_SEIM_SGAT_ELEM_SZ 0x80 /* sgat element size (>= PAGE_SIZE) */
#define SG_SEIM_CHG_SHARE_FD 0x100 /* master gives fd of new slave */
#define SG_SEIM_ALL_BITS 0x1ff /* should be OR of previous items */
+/* flag and mask values for boolena fields follow */
#define SG_CTL_FLAGM_TIME_IN_NS 0x1 /* time: nanosecs (def: millisecs) */
-#define SG_CTL_FLAGM_TAG_FOR_PACK_ID 0x2
+#define SG_CTL_FLAGM_TAG_FOR_PACK_ID 0x2 /* prefer tag over pack_id (def) */
#define SG_CTL_FLAGM_OTHER_OPENS 0x4 /* rd: other sg fd_s on this dev */
#define SG_CTL_FLAGM_ORPHANS 0x8 /* rd: orphaned requests on this fd */
#define SG_CTL_FLAGM_Q_TAIL 0x10 /* used for future cmds on this fd */
#define SG_CTL_FLAGM_IS_SHARE 0x20 /* rd: fd is master or slave share */
#define SG_CTL_FLAGM_IS_MASTER 0x40 /* rd: this fd is share master */
#define SG_CTL_FLAGM_UNSHARE 0x80 /* undo share after inflight cmd */
-#define SG_CTL_FLAGM_MASTER_FINI 0x100 /* share: master finished; 1: finish */
+/* rd> 1: master finished 0: not; wr> 1: finish share post master */
+#define SG_CTL_FLAGM_MASTER_FINI 0x100 /* wr> 0: setup for repeat slave req */
#define SG_CTL_FLAGM_MASTER_ERR 0x200 /* rd: sharing, master got error */
#define SG_CTL_FLAGM_CHECK_FOR_MORE 0x400 /* additional ready to read? */
#define SG_CTL_FLAGM_ALL_BITS 0x7ff /* should be OR of previous items */
@@ -207,9 +214,9 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
* and modify the driver. Each bit in the *_rd_mask fields causes the
* corresponding integer or bit to be fetched from the driver and written
* back to the user space. If the same bit is set in both the *_wr_mask and
- * corresponding *_rd_mask fields, then the write action takes place before
- * the read action and no other operation will split the two. This structure
- * is padded to 96 bytes to allow for new values to be added in the future.
+ * corresponding *_rd_mask fields, then which one comes first depends on the
+ * setting but no other operation will split the two. This structure is
+ * padded to 96 bytes to allow for new values to be added in the future.
*/
struct sg_extended_info {
__u32 valid_wr_mask; /* OR-ed SG_SEIM_* user->driver values */
@@ -252,7 +259,7 @@ struct sg_extended_info {
/*
* Historically the scsi/sg driver has used 0x22 as it ioctl base number.
* Add a define for that value and use it for several new ioctls added in
- * version 3.9.01 sg driver.
+ * version 4.0.01 sg driver and later.
*/
#define SG_IOCTL_MAGIC_NUM 0x22
@@ -272,10 +279,11 @@ struct sg_extended_info {
* ioctl(SG_IO_RECEIVE). These functions wait until matching packet (request/
* command) is finished but they will return with EAGAIN quickly if the file
* descriptor was opened O_NONBLOCK or (in v4) if SGV4_FLAG_IMMED is given.
- * The tag is used when SGV4_FLAG_FIND_BY_TAG is given (default: use pack_id).
- * If pack_id or tag is -1 then read oldest waiting. When FORCE_PACK_ID is
- * cleared to 0 the oldest readable request/command is fetched. In v4 the
- * pack_id is placed in sg_io_v4::request_extra .
+ * The tag is used when SG_CTL_FLAGM_TAG_FOR_PACK_ID is set on the parent
+ * file descriptor (default: use pack_id). If pack_id or tag is -1 then read
+ * oldest waiting and this is the same action as when FORCE_PACK_ID is
+ * clear on the parent file descriptor. In the v4 interface the pack_id is
+ * placed in sg_io_v4::request_extra field .
*/
#define SG_SET_FORCE_PACK_ID 0x227b /* pack_id or in v4 can be tag */
#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
@@ -285,7 +293,11 @@ struct sg_extended_info {
/* Yields max scatter gather tablesize allowed by current host adapter */
#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */
-#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
+/*
+ * Integer form of version number: [x]xyyzz where [x] empty when x=0 .
+ * String form of version number: "[x]x.[y]y.zz"
+ */
+#define SG_GET_VERSION_NUM 0x2282 /* Example: version "2.1.34" yields 20134 */
/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
#define SG_SCSI_RESET 0x2284
@@ -301,12 +313,12 @@ struct sg_extended_info {
#define SG_SCSI_RESET_TARGET 4
#define SG_SCSI_RESET_NO_ESCALATE 0x100
-/* synchronous SCSI command ioctl, (only in version 3 interface) */
+/* synchronous SCSI command ioctl, (for version 3 and 4 interface) */
#define SG_IO 0x2285 /* similar effect as write() followed by read() */
#define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */
-/* How to treat EINTR during SG_IO ioctl(), only in SG 3.x series */
+/* How to treat EINTR during SG_IO ioctl(), only in sg v3 and v4 driver */
#define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */
#define SG_GET_KEEP_ORPHAN 0x2288
@@ -318,14 +330,14 @@ struct sg_extended_info {
/*
- * Largest size (in bytes) a single scatter-gather list element can have.
- * The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
- * This value should be a power of 2 (and may be rounded up internally).
- * If scatter-gather is not supported by adapter then this value is the
- * largest data block that can be read/written by a single scsi command.
+ * Default size (in bytes) a single scatter-gather list element can have.
+ * The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'. This
+ * value should be a power of 2 (and may be rounded up internally). In the
+ * v4 driver this can be changed by ioctl(SG_SET_GET_EXTENDED{SGAT_ELEM_SZ}).
*/
#define SG_SCATTER_SZ (8 * 4096)
+/* sg driver users' code should handle retries (e.g. from Unit Attentions) */
#define SG_DEFAULT_RETRIES 0
/* Defaults, commented if they differ from original sg driver */
@@ -354,7 +366,7 @@ typedef struct sg_req_info Sg_req_info;
/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
-/* The older SG interface based on the 'sg_header' structure follows. */
+/* The v1+v2 SG interface based on the 'sg_header' structure follows. */
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
#define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */
@@ -380,18 +392,20 @@ struct sg_header {
};
/*
- * IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t
- * interface is used. They are kept for backward compatibility with
- * the original and version 2 drivers.
+ * IOCTLs: The following are not required (or ignored) when the v3 or v4
+ * interface is used as those structures contain a timeout field. These
+ * ioctls are kept for backward compatibility with v1+v2 interfaces.
*/
-#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */
+#define SG_SET_TIMEOUT 0x2201 /* unit: (user space) jiffies */
#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */
/*
* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q.
* Each time a sg_io_hdr_t object is seen on this file descriptor, this
* command queuing flag is set on (overriding the previous setting).
+ * This setting defaults to 0 (i.e. no queuing) but gets set the first
+ * time that fd sees a v3 or v4 interface request.
*/
#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */
#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */
@@ -404,7 +418,7 @@ struct sg_header {
/*
* override SCSI command length with given number on the next write() on
- * this file descriptor
+ * this file descriptor (v1 and v2 interface only)
*/
#define SG_NEXT_CMD_LEN 0x2283
@@ -429,11 +443,12 @@ struct sg_header {
/* via pointer reads v4 object (including tag), writes nothing, so _IOW */
#define SG_IOABORT _IOW(SG_IOCTL_MAGIC_NUM, 0x43, struct sg_io_v4)
-/* command queuing is always on when the new interface is used */
+/* command queuing is always on when the v3 or v4 interface is used */
#define SG_DEF_COMMAND_Q 0
#define SG_DEF_UNDERRUN_FLAG 0
+/* If the timeout value in the v3_v4 interfaces is 0, this value is used */
#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
-#endif
+#endif /* end of _UAPI_SCSI_SG_H guard */