aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--doc/sg_write_same.852
-rw-r--r--doc/sgm_dd.825
-rw-r--r--examples/sg_tst_async.cpp310
-rw-r--r--src/sg_dd.c4
-rw-r--r--src/sg_vpd.c3
-rw-r--r--src/sg_write_same.c33
-rw-r--r--src/sgm_dd.c92
8 files changed, 268 insertions, 255 deletions
diff --git a/ChangeLog b/ChangeLog
index d3c7d59a..d55194dc 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.41 [20150203] [svn: r633]
+Changelog for sg3_utils-1.41 [20150216] [svn: r634]
- sg_zone: new utility for open, close and finish
zone commands introduced in zbc-r02
- sg_rep_zones and sg_reset_wp: change opcodes as
@@ -30,7 +30,9 @@ Changelog for sg3_utils-1.41 [20150203] [svn: r633]
improve error handling
- sg_modes: make '-HHH' output suitable as input to
'sdparm --inhex='
+ - sg_write_same: cleanup, mainly man page
- scsi_logging_level: replace use of tr command
+ - examples/sg_tst_async: cleanup
- examples/sg-simple_aio.c: remove
- sg_lib_data: sync asc/ascq codes with T10 20150103
diff --git a/doc/sg_write_same.8 b/doc/sg_write_same.8
index 09ccd8ac..5f30b9ae 100644
--- a/doc/sg_write_same.8
+++ b/doc/sg_write_same.8
@@ -1,11 +1,11 @@
-.TH SG_WRITE_SAME "8" "January 2015" "sg3_utils\-1.41" SG3_UTILS
+.TH SG_WRITE_SAME "8" "February 2015" "sg3_utils\-1.41" SG3_UTILS
.SH NAME
sg_write_same \- send SCSI WRITE SAME command
.SH SYNOPSIS
.B sg_write_same
[\fI\-\-10\fR] [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-anchor\fR]
[\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR]
-[\fI\-\-lbdata\fR] [\fI\-\-pbdata\fR] [\fI\-\-num=NUM\fR] [\fI\-\-ndob\fR]
+[\fI\-\-lbdata\fR] [\fI\-\-num=NUM\fR] [\fI\-\-ndob\fR] [\fI\-\-pbdata\fR]
[\fI\-\-timeout=TO\fR] [\fI\-\-unmap\fR] [\fI\-\-verbose\fR]
[\fI\-\-version\fR] [\fI\-\-wrprotect=WPR\fR] [\fI\-\-xferlen=LEN\fR]
\fIDEVICE\fR
@@ -15,11 +15,6 @@ Send the SCSI WRITE SAME (10, 16 or 32 byte) command to \fIDEVICE\fR. This
command writes the given block \fINUM\fR times to consecutive blocks on
the \fIDEVICE\fR starting at logical block address \fILBA\fR.
.PP
-SBC\-3 revision 35d introduced a "no data-out buffer" (NDOB) bit which, if
-set, bypasses the requirement to send a single block of data to the
-\fIDEVICE\fR together with the command. Only WRITE SAME (16 and 32 byte)
-support the NDOB bit.
-.PP
The length of the block to be written multiple times is obtained from either
the \fILEN\fR argument, or the length of the given input file \fIIF\fR,
or by calling READ CAPACITY(16) on \fIDEVICE\fR. The contents of the
@@ -36,6 +31,12 @@ or the \fI\-\-unmap\fR option is given then WRITE SAME(16) is sent.
The \fI\-\-10\fR, \fI\-\-16\fR and \fI\-\-32\fR options are mutually
exclusive.
.PP
+SBC\-3 revision 35d introduced a "no data-out buffer" (NDOB) bit which, if
+set, bypasses the requirement to send a single block of data to the
+\fIDEVICE\fR together with the command. Only WRITE SAME (16 and 32 byte)
+support the NDOB bit. If given, a user block of zeros is assumed; if
+required, protection information of 0xffs is assumed.
+.PP
In SBC\-3 revision 26 the UNMAP and ANCHOR bits were added to the
WRITE SAME (10) command. Since the UNMAP bit has been in WRITE SAME (16)
and WRITE SAME (32) since SBC\-3 revision 18, the lower of the two (i.e.
@@ -43,17 +44,16 @@ WRITE SAME (16)) is the default when the \fI\-\-unmap\fR option is given.
To send WRITE SAME (10) use the \fI\-\-10\fR option.
.PP
.B Take care:
-The WRITE SAME(10, 16 and 32) commands interpret a \fINUM\fR of zero
-as write to the end of \fIDEVICE\fR. This utility defaults \fINUM\fR to
-1 . The WRITE SAME commands have no IMMED bit so if \fINUM\fR is
-large (or zero) then an invocation of this utility could take a long
-time, potentially as long as a FORMAT UNIT command. In such situations
-the command timeout value \fITO\fR may need to be increased from its
-default value of 60 seconds. In SBC\-3 revision 26 the WSNZ (write same
-no zero) bit was added to the Block Limits VPD page [0xB0]. If set the
-WRITE SAME commands will not accept a \fINUM\fR of zero. The same
-SBC\-3 revision added the "Maximum Write Same Length" field to the Block
-Limits VPD page.
+The WRITE SAME(10, 16 and 32) commands may interpret a \fINUM\fR of zero as
+write to the end of \fIDEVICE\fR. This utility defaults \fINUM\fR to 1 .
+The WRITE SAME commands have no IMMED bit so if \fINUM\fR is large (or
+zero) then an invocation of this utility could take a long time, potentially
+as long as a FORMAT UNIT command. In such situations the command timeout
+value \fITO\fR may need to be increased from its default value of 60
+seconds. In SBC\-3 revision 26 the WSNZ (write same no zero) bit was added
+to the Block Limits VPD page [0xB0]. If set the WRITE SAME commands will not
+accept a \fINUM\fR of zero. The same SBC\-3 revision added the "Maximum
+Write Same Length" field to the Block Limits VPD page.
.PP
The Logical Block Provisioning VPD page [0xB2] contains the LBWS and
LBW10 bits. If LBWS is set then WRITE SAME (16) supports the UNMAP bit.
@@ -108,7 +108,8 @@ in use. Assumed to be in decimal unless prefixed with '0x' or has a
trailing 'h'.
.TP
\fB\-L\fR, \fB\-\-lbdata\fR
-sets the LBDATA bit in the WRITE SAME cdb.
+sets the LBDATA bit in the WRITE SAME cdb. This bit was made obsolete in
+sbc3r32 in September 2012.
.TP
\fB\-N\fR, \fB\-\-ndob\fR
sets the NDOB bit in the WRITE SAME (16 and 32 byte) commands. Default is to
@@ -118,12 +119,17 @@ and \fI\-\-xferlen=LEN\fR can only be given if \fILEN\fR is 0 .
\fB\-n\fR, \fB\-\-num\fR=\fINUM\fR
where \fINUM\fR is the number of blocks, starting at \fILBA\fR, to write the
data out buffer to. The default value for \fINUM\fR is 1. The value corresponds
-to the 'Number of logical blocks' field in the WRITE SAME cdb. Note that a
-value of 0 in \fINUM\fR is interpreted as write the data out buffer on every
-block starting at \fILBA\fR to the end of the \fIDEVICE\fR.
+to the 'Number of logical blocks' field in the WRITE SAME cdb.
+.br
+Note that a value of 0 in \fINUM\fR may be interpreted as write the data out
+buffer on every block starting at \fILBA\fR to the end of the \fIDEVICE\fR.
+If the WSNZ bit (introduced in sbc3r26, January 2011) in the Block Limits VPD
+page is set then the value of 0 is disallowed, yielding an Invalid request
+sense key.
.TP
\fB\-P\fR, \fB\-\-pbdata\fR
-sets the PBDATA bit in the WRITE SAME cdb.
+sets the PBDATA bit in the WRITE SAME cdb. This bit was made obsolete in
+sbc3r32 in September 2012.
.TP
\fB\-t\fR, \fB\-\-timeout\fR=\fITO\fR
where \fITO\fR is the command timeout value in seconds. The default value is
diff --git a/doc/sgm_dd.8 b/doc/sgm_dd.8
index d02392f7..d4e0378c 100644
--- a/doc/sgm_dd.8
+++ b/doc/sgm_dd.8
@@ -1,4 +1,4 @@
-.TH SGM_DD "8" "November 2019" "sg3_utils\-1.35" SG3_UTILS
+.TH SGM_DD "8" "February 2015" "sg3_utils\-1.41" SG3_UTILS
.SH NAME
sgm_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -25,11 +25,9 @@ are SCSI generic (sg) devices.
If both \fIIFILE\fR and \fIOFILE\fR are sg devices then memory mapped
transfers are performed on \fIIFILE\fR. If no other flags are specified
then indirect IO is performed on \fIOFILE\fR. If 'oflag=dio' is given then
-direct IO is attempted on \fIOFILE\fR. If 'oflag=smmap' is given then
-shared mmap\-ed IO (sharing the mmap\-ed reserve buffer associated with
-\fIIFILE\fR) is attempted. In both latter cases if the faster IO option
-is not available, they fall back to indirect IO and report this at
-the end of the copy.
+direct IO is attempted on \fIOFILE\fR. If direct IO is not available, then
+this utility falls back to indirect IO and reports this at the end of the
+copy.
.PP
The first group in the synopsis above are "standard" Unix
.B dd(1)
@@ -188,11 +186,6 @@ Only active for sg device file names.
.TP
null
has no affect, just a placeholder.
-.TP
-smmap
-is only active for oflag. It sets shared mmap IO usage on \fIOFILE\fR if
-it is a sg device node. The \fIIFILE\fR also needs to be a sg device
-node (or there is no mmap\-ed reserve buffer to share).
.SH RETIRED OPTIONS
Here are some retired options that are still present:
.TP
@@ -205,15 +198,15 @@ A raw device must be bound to a block device prior to using sgm_dd.
See
.B raw(8)
for more information about binding raw devices. To be safe, the sg device
-mapping to SCSI block devices should be checked with 'cat /proc/scsi/scsi'
+mapping to SCSI block devices should be checked with the lsscsi utility
before use.
.PP
Raw device partition information can often be found with
.B fdisk(8)
[the "\-ul" argument is useful in this respect].
.PP
-Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative
-suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section
+Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative
+suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section
in the sg3_utils(8) man page.
.PP
The count, skip and seek parameters can take 64 bit values (i.e. very
@@ -265,7 +258,7 @@ Written by Douglas Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000\-2012 Douglas Gilbert
+Copyright \(co 2000\-2015 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -277,4 +270,4 @@ A POSIX threads version of this utility called
is in the sg3_utils package. The lmbench package contains
.B lmdd
which is also interesting.
-.B raw(8), dd(1)
+.B dd(1), ddpt(ddpt), raw(8)
diff --git a/examples/sg_tst_async.cpp b/examples/sg_tst_async.cpp
index a070a819..c4e28c56 100644
--- a/examples/sg_tst_async.cpp
+++ b/examples/sg_tst_async.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Douglas Gilbert.
+ * Copyright (c) 2014-2015 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
#include <ctype.h>
#include <time.h>
#include <limits.h>
+#include <getopt.h>
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
#include <sys/ioctl.h>
@@ -57,7 +58,7 @@
#include "sg_io_linux.h"
#include "sg_unaligned.h"
-static const char * version_str = "1.08 20141028";
+static const char * version_str = "1.10 20150214";
static const char * util_name = "sg_tst_async";
/* This is a test program for checking the async usage of the Linux sg
@@ -105,7 +106,7 @@ using namespace std::chrono;
#define DEF_TIMEOUT_MS 20000 /* 20 seconds */
#define DEF_LB_SZ 512
#define DEF_BLOCKING 0
-#define DEF_DIRECT 0
+#define DEF_DIRECT 0 /* 1: direct_io, 2: mmap IO */
#define DEF_NO_XFER 0
#define DEF_LBA 1000
@@ -129,7 +130,8 @@ static mutex rand_lba_mutex;
static atomic<int> async_starts(0);
static atomic<int> async_finishes(0);
static atomic<int> ebusy_count(0);
-static atomic<int> eagain_count(0);
+static atomic<int> start_eagain_count(0);
+static atomic<int> fin_eagain_count(0);
static atomic<int> uniq_pack_id(1);
static int page_size = 4096; /* rough guess, will ask sysconf() */
@@ -145,7 +147,7 @@ enum myQDiscipline {MYQD_LOW, /* favour completions over new cmds */
struct opts_t {
vector<const char *> dev_names;
- bool direct;
+ int direct;
int maxq_per_thread;
int num_per_thread;
bool block;
@@ -154,6 +156,7 @@ struct opts_t {
vector<unsigned int> hi_lbas; /* only used when hi_lba=-1 */
int lb_sz;
bool no_xfer;
+ int stats;
int verbose;
int wait_ms;
command2execute c2e;
@@ -201,49 +204,76 @@ private:
default_random_engine dre;
};
+static struct option long_options[] = {
+ {"direct", no_argument, 0, 'd'},
+ {"force", no_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {"lba", required_argument, 0, 'l'},
+ {"maxqpt", required_argument, 0, 'M'},
+ {"numpt", required_argument, 0, 'n'},
+ {"noxfer", no_argument, 0, 'N'},
+ {"qat", required_argument, 0, 'q'},
+ {"qfav", required_argument, 0, 'Q'},
+ {"read", no_argument, 0, 'R'},
+ {"szlb", required_argument, 0, 's'},
+ {"stats", no_argument, 0, 'S'},
+ {"tnum", required_argument, 0, 't'},
+ {"tur", no_argument, 0, 'T'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wait", required_argument, 0, 'w'},
+ {"write", no_argument, 0, 'W'},
+ {0, 0, 0, 0},
+};
+
static void
usage(void)
{
- printf("Usage: %s [-d] [-f] [-h] [-l <lba+>] [-M <maxq_per_thr>]\n"
- " [-n <n_per_thr>] [-N] [-q 0|1] [-Q 0|1|2] "
- "[-R]\n"
- " [-s <lb_sz>] [-t <num_thrs>] [-T] [-v] "
- "[-V]\n"
- " [-w <wait_ms>] [-W] <sg_disk_device>*\n",
+ printf("Usage: %s [--direct] [--force] [--help] [--lba=LBA+] "
+ "[--maxqpt=QPT]\n"
+ " [--numpt=NPT] [--noxfer] [--qat=AT] "
+ "[-qfav=FAV]\n"
+ " [--read] [--szlb=LB] [--stats] [--tnum=NT] "
+ "[--tur]\n"
+ " [--verbose] [--version] [--wait=MS] "
+ "[--write]\n"
+ " <sg_disk_device>*\n",
util_name);
printf(" where\n");
- printf(" -d do direct_io (def: indirect)\n");
- printf(" -f force: any sg device (def: only scsi_debug "
+ printf(" --direct|-d do direct_io (def: indirect)\n");
+ printf(" --force|-f force: any sg device (def: only scsi_debug "
"owned)\n");
- printf(" WARNING: <lba> written to if '-W' given\n");
- printf(" -h print this usage message then exit\n");
- printf(" -l <lba> logical block to access (def: %u)\n",
+ printf(" WARNING: <lba> written to if '-W' given\n");
+ printf(" --help|-h print this usage message then exit\n");
+ printf(" --lba=LBA|-l LBA logical block to access (def: %u)\n",
DEF_LBA);
- printf(" -l <lba,hi_lba> logical block range (inclusive), if "
- "hi_lba=-1\n"
- " assume last block on device\n");
- printf(" -M <maxq_per_thr> maximum commands queued per thread "
+ printf(" --lba=LBA,HI_LBA|-l LBA,HI_LBA logical block range "
+ "(inclusive)\n"
+ " if hi_lba=-1 assume last block on "
+ "device\n");
+ printf(" --maxqpt=QPT|-M QPT maximum commands queued per thread "
"(def:%d)\n", MAX_Q_PER_FD);
- printf(" -n <n_per_thr> number of commands per thread "
+ printf(" --numpt=NPT|-n NPT number of commands per thread "
"(def: %d)\n", DEF_NUM_PER_THREAD);
- printf(" -N no data xfer (def: xfer on READ and "
+ printf(" --noxfer|-N no data xfer (def: xfer on READ and "
"WRITE)\n");
- printf(" -q 0|1 0: blk q_at_head; 1: q_at_tail\n");
- printf(" -Q 0|1|2 0: favour completions (smaller q), 1: "
- "medium,\n"
- " 2: favour submissions (larger q, "
+ printf(" --qat=AT|-q AT AT=0: q_at_head; AT=1: q_at_tail\n");
+ printf(" --qfav=FAV|-Q FAV FAV=0: favour completions (smaller q),\n"
+ " FAV=1: medium,\n"
+ " FAV=2: favour submissions (larger q, "
"default)\n");
- printf(" -s <lb_sz> logical block size (def: 512)\n");
- printf(" -R do READs (def: TUR)\n");
- printf(" -t <num_thrs> number of threads (def: %d)\n",
+ printf(" --read|-R do READs (def: TUR)\n");
+ printf(" --szlb=LB|-s LB logical block size (def: 512)\n");
+ printf(" --stats|-S show more statistics on completion\n");
+ printf(" --tnum=NT|-t NT number of threads (def: %d)\n",
DEF_NUM_THREADS);
- printf(" -T do TEST UNIT READYs (default is TURs)\n");
- printf(" -v increase verbosity\n");
- printf(" -V print version number then exit\n");
- printf(" -w <wait_ms> >0: poll(<wait_ms>); =0: poll(0); (def: "
+ printf(" --tur|-T do TEST UNIT READYs (default is TURs)\n");
+ printf(" --verbose|-v increase verbosity\n");
+ printf(" --version|-V print version number then exit\n");
+ printf(" --wait=MS|-w MS >0: poll(<wait_ms>); =0: poll(0); (def: "
"%d)\n", DEF_WAIT_MS);
- printf(" -W do WRITEs (def: TUR)\n\n");
+ printf(" --write|-W do WRITEs (def: TUR)\n\n");
printf("Multiple threads send READ(16), WRITE(16) or TEST UNIT READY "
"(TUR) SCSI\ncommands. There can be 1 or more <sg_disk_device>s "
"and each thread takes\nthe next in a round robin fashion. "
@@ -317,7 +347,8 @@ get_urandom_uint(void)
/* Returns 0 if command injected okay, else -1 */
static int
start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
- unsigned char * lbp, int xfer_bytes, int flags)
+ unsigned char * lbp, int xfer_bytes, int flags,
+ unsigned int & eagains)
{
struct sg_io_hdr pt;
unsigned char turCmdBlk[TUR_CMD_LEN] = {0, 0, 0, 0, 0, 0};
@@ -371,6 +402,11 @@ start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
this_thread::yield();
continue;
}
+ if (EAGAIN == errno) {
+ ++eagains;
+ this_thread::yield();
+ continue;
+ }
pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id);
return -1;
}
@@ -477,7 +513,8 @@ work_thread(int id, struct opts_t * op)
{
int thr_async_starts = 0;
int thr_async_finishes = 0;
- unsigned int thr_eagain_count = 0;
+ unsigned int thr_start_eagain_count = 0;
+ unsigned int thr_fin_eagain_count = 0;
unsigned int seed = 0;
unsigned int hi_lba;
int k, n, res, sg_fd, num_outstanding, do_inc, npt, pack_id, sg_flags;
@@ -576,7 +613,7 @@ work_thread(int id, struct opts_t * op)
} else
lba = 0;
if (start_sg3_cmd(sg_fd, op->c2e, pack_id, lba, lbp, op->lb_sz,
- sg_flags)) {
+ sg_flags, thr_start_eagain_count)) {
err = "start_sg3_cmd()";
break;
}
@@ -643,7 +680,7 @@ work_thread(int id, struct opts_t * op)
while (num_to_read-- > 0) {
if (finish_sg3_cmd(sg_fd, op->c2e, pack_id, op->wait_ms,
- thr_eagain_count)) {
+ thr_fin_eagain_count)) {
err = "finish_sg3_cmd()";
if (ruip && (pack_id > 0)) {
auto q = pi_2_lba.find(pack_id);
@@ -714,7 +751,8 @@ work_thread(int id, struct opts_t * op)
id, k);
async_starts += thr_async_starts;
async_finishes += thr_async_finishes;
- eagain_count += thr_eagain_count;
+ start_eagain_count += thr_start_eagain_count;
+ fin_eagain_count += thr_fin_eagain_count;
}
#define INQ_REPLY_LEN 96
@@ -857,7 +895,7 @@ do_read_capacity(const char * dev_name, int block, unsigned int * last_lba,
int
main(int argc, char * argv[])
{
- int k, n, res;
+ int k, n, c, res;
int force = 0;
int64_t ll;
int num_threads = DEF_NUM_THREADS;
@@ -869,7 +907,8 @@ main(int argc, char * argv[])
const char * dev_name;
op = &opts;
- op->direct = !! DEF_DIRECT;
+ memset(op, 0, sizeof(opts));
+ op->direct = DEF_DIRECT;
op->lba = DEF_LBA;
op->hi_lba = 0;
op->lb_sz = DEF_LB_SZ;
@@ -884,24 +923,34 @@ main(int argc, char * argv[])
op->myqd = MYQD_HIGH;
page_size = sysconf(_SC_PAGESIZE);
- for (k = 1; k < argc; ++k) {
- if (0 == memcmp("-d", argv[k], 2))
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "dfhl:M:n:Nq:Q:Rs:St:TvVw:W",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'd':
op->direct = true;
- else if (0 == memcmp("-f", argv[k], 2))
- ++force;
- else if (0 == memcmp("-h", argv[k], 2)) {
+ break;
+ case 'f':
+ force = true;
+ break;
+ case 'h':
+ case '?':
usage();
return 0;
- } else if (0 == memcmp("-l", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k])) {
- ll = sg_get_llnum(argv[k]);
+ case 'l':
+ if (isdigit(*optarg)) {
+ ll = sg_get_llnum(optarg);
if (-1 == ll) {
pr2serr_lk("could not decode lba\n");
return 1;
} else
op->lba = (uint64_t)ll;
- cp = strchr(argv[k], ',');
+ cp = strchr(optarg, ',');
if (cp) {
if (0 == strcmp("-1", cp + 1))
op->hi_lba = UINT_MAX;
@@ -915,98 +964,124 @@ main(int argc, char * argv[])
op->hi_lba = (unsigned int)ll;
}
}
- } else
- break;
- } else if (0 == memcmp("-M", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k])) {
- n = atoi(argv[k]);
+ } else {
+ pr2serr_lk("--lba= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'M':
+ if (isdigit(*optarg)) {
+ n = atoi(optarg);
if ((n < 1) || (n > MAX_Q_PER_FD)) {
pr2serr_lk("-M expects a value from 1 to %d\n",
MAX_Q_PER_FD);
return 1;
}
op->maxq_per_thread = n;
- } else
- break;
- } else if (0 == memcmp("-n", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k]))
- op->num_per_thread = sg_get_num(argv[k]);
- else
- break;
- } else if (0 == memcmp("-N", argv[k], 2))
+ } else {
+ pr2serr_lk("--maxqpt= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'n':
+ if (isdigit(*optarg))
+ op->num_per_thread = sg_get_num(optarg);
+ else {
+ pr2serr_lk("--numpt= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'N':
op->no_xfer = true;
- else if (0 == memcmp("-q", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k])) {
- n = atoi(argv[k]);
+ break;
+ case 'q':
+ if (isdigit(*optarg)) {
+ n = atoi(optarg);
if (0 == n)
op->blqd = BLQ_AT_HEAD;
else if (1 == n)
op->blqd = BLQ_AT_TAIL;
- } else
- break;
- } else if (0 == memcmp("-Q", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k])) {
- n = atoi(argv[k]);
+ } else {
+ pr2serr_lk("--qat= expects a number: 0 or 1\n");
+ return 1;
+ }
+ break;
+ case 'Q':
+ if (isdigit(*optarg)) {
+ n = atoi(optarg);
if (0 == n)
op->myqd = MYQD_LOW;
else if (1 == n)
op->myqd = MYQD_MEDIUM;
else if (2 == n)
op->myqd = MYQD_HIGH;
- } else
- break;
- } else if (0 == memcmp("-R", argv[k], 2))
+ } else {
+ pr2serr_lk("--qfav= expects a number: 0, 1 or 2\n");
+ return 1;
+ }
+ break;
+ case 'R':
op->c2e = SCSI_READ16;
- else if (0 == memcmp("-s", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k])) {
- op->lb_sz = atoi(argv[k]);
+ break;
+ case 's':
+ if (isdigit(*optarg)) {
+ op->lb_sz = atoi(optarg);
if (op->lb_sz < 256) {
cerr << "Strange lb_sz, using 256" << endl;
op->lb_sz = 256;
}
- } else
- break;
- } else if (0 == memcmp("-t", argv[k], 2)) {
- ++k;
- if ((k < argc) && isdigit(*argv[k]))
- num_threads = atoi(argv[k]);
- else
- break;
- } else if (0 == memcmp("-T", argv[k], 2))
+ } else {
+ pr2serr_lk("--szlb= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'S':
+ ++op->stats;
+ break;
+ case 't':
+ if (isdigit(*optarg))
+ num_threads = atoi(optarg);
+ else {
+ pr2serr_lk("--tnum= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'T':
op->c2e = SCSI_TUR;
- else if (0 == memcmp("-vvvv", argv[k], 5))
- op->verbose += 4;
- else if (0 == memcmp("-vvv", argv[k], 4))
- op->verbose += 3;
- else if (0 == memcmp("-vv", argv[k], 3))
- op->verbose += 2;
- else if (0 == memcmp("-v", argv[k], 2))
+ break;
+ case 'v':
++op->verbose;
- else if (0 == memcmp("-V", argv[k], 2)) {
- printf("%s version: %s\n", util_name, version_str);
+ break;
+ case 'V':
+ pr2serr_lk("version: %s\n", version_str);
return 0;
- } else if (0 == memcmp("-w", argv[k], 2)) {
- ++k;
- if ((k < argc) && (isdigit(*argv[k]) || ('-' == *argv[k]))) {
- if ('-' == *argv[k])
- op->wait_ms = - atoi(argv[k] + 1);
+ case 'w':
+ if ((isdigit(*optarg) || ('-' == *optarg))) {
+ if ('-' == *optarg)
+ op->wait_ms = - atoi(optarg + 1);
else
- op->wait_ms = atoi(argv[k]);
- } else
- break;
- } else if (0 == memcmp("-W", argv[k], 2))
+ op->wait_ms = atoi(optarg);
+ } else {
+ pr2serr_lk("--wait= expects a number\n");
+ return 1;
+ }
+ break;
+ case 'W':
op->c2e = SCSI_WRITE16;
- else if (*argv[k] == '-') {
- pr2serr_lk("Unrecognized switch: %s\n", argv[k]);
+ break;
+ default:
+ pr2serr_lk("unrecognised option code 0x%x ??\n", c);
+ usage();
return 1;
- } else
- op->dev_names.push_back(argv[k]);
+ }
+ }
+ if (optind < argc) {
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ op->dev_names.push_back(argv[optind]);
+ }
}
+
if (0 == op->dev_names.size()) {
usage();
return 1;
@@ -1112,13 +1187,16 @@ main(int argc, char * argv[])
}
}
- if (op->verbose) {
+ if (op->verbose || op->stats) {
cout << "Number of async_starts: " << async_starts.load() << endl;
cout << "Number of async_finishes: " << async_finishes.load() <<
endl;
cout << "Last pack_id: " << n << endl;
cout << "Number of EBUSYs: " << ebusy_count.load() << endl;
- cout << "Number of EAGAINs: " << eagain_count.load() << endl;
+ cout << "Number of start EAGAINs: " << start_eagain_count.load()
+ << endl;
+ cout << "Number of finish EAGAINs: " << fin_eagain_count.load()
+ << endl;
}
}
catch(system_error& e) {
diff --git a/src/sg_dd.c b/src/sg_dd.c
index 30b063b2..641e8e38 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -59,7 +59,7 @@
#include "sg_io_linux.h"
#include "sg_unaligned.h"
-static const char * version_str = "5.83 20150129";
+static const char * version_str = "5.83 20150215";
#define ME "sg_dd: "
@@ -1868,7 +1868,7 @@ main(int argc, char * argv[])
#else
wrkBuff = (unsigned char*)malloc(blk_sz * bpt + psz);
if (0 == wrkBuff) {
- fprintf(stderr, "Not enough user memory for raw\n");
+ fprintf(stderr, "Not enough user memory for work buffer\n");
return SG_LIB_CAT_OTHER;
}
wrkPos = (unsigned char *)(((uintptr_t)wrkBuff + psz - 1) &
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 2bd80823..e19fbf90 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -36,7 +36,7 @@
*/
-static const char * version_str = "1.02 20150123"; /* spc5r02 + sbc4r03 */
+static const char * version_str = "1.03 20150212"; /* spc5r02 + sbc4r05 */
/* These structures are duplicates of those of the same name in
@@ -2612,6 +2612,7 @@ decode_sup_block_lens_vpd(unsigned char * buff, int len)
u = sg_get_unaligned_be32(ucp);
printf(" Logical block length: %u\n", u);
printf(" P_I_I_SUP: %d\n", !!(ucp[4] & 0x40));
+ printf(" NO_PI_CHK: %d\n", !!(ucp[4] & 0x8)); /* sbc4r05 */
printf(" GRD_CHK: %d\n", !!(ucp[4] & 0x4));
printf(" APP_CHK: %d\n", !!(ucp[4] & 0x2));
printf(" REF_CHK: %d\n", !!(ucp[4] & 0x1));
diff --git a/src/sg_write_same.c b/src/sg_write_same.c
index 5cbb0b2a..0ac601b8 100644
--- a/src/sg_write_same.c
+++ b/src/sg_write_same.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2014 Douglas Gilbert.
+ * Copyright (c) 2009-2015 Douglas Gilbert.
* All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the BSD_LICENSE file.
@@ -26,7 +26,7 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-static const char * version_str = "1.07 20141021";
+static const char * version_str = "1.08 20150216";
#define ME "sg_write_same: "
@@ -107,8 +107,9 @@ usage()
" --10|-R do WRITE SAME(10) (even if '--unmap' "
"is given)\n"
" --16|-S do WRITE SAME(16) (def: 10 unless "
- "'--unmap' given\n"
- " or LBA+NUM needs more than 32 bits)\n"
+ "'--unmap' given,\n"
+ " LBA+NUM > 32 bits, or NUM > 65535; "
+ "then def 16)\n"
" --32|-T do WRITE SAME(32) (def: 10 or 16)\n"
" --anchor|-a set anchor field in cdb\n"
" --grpnum=GN|-g GN GN is group number field (def: 0)\n"
@@ -119,12 +120,13 @@ usage()
"DEVICE\n"
" --lba=LBA|-l LBA LBA is the logical block address to "
"start (def: 0)\n"
- " --lbdata|-L set LBDATA bit\n"
+ " --lbdata|-L set LBDATA bit (obsolete)\n"
" --ndob|-N set 'no data-out buffer' bit\n"
" --num=NUM|-n NUM NUM is number of logical blocks to "
"write (def: 1)\n"
- " [Beware NUM==0 means rest of device]\n"
- " --pbdata|-P set PBDATA bit\n"
+ " [Beware NUM==0 may mean rest of "
+ "device]\n"
+ " --pbdata|-P set PBDATA bit (obsolete)\n"
" --timeout=TO|-t TO command timeout (unit: seconds) (def: "
"60)\n"
" --unmap|-U set UNMAP bit\n"
@@ -156,9 +158,18 @@ do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp,
if ((op->numblocks > 0xffff) || (llba > ULONG_MAX) ||
op->ndob || (op->unmap && (0 == op->want_ws10))) {
cdb_len = WRITE_SAME16_LEN;
- if (op->verbose)
- fprintf(stderr, "do_write_same: use WRITE SAME(16) instead "
- "of 10 byte cdb\n");
+ if (op->verbose) {
+ const char * cp = "use WRITE SAME(16) instead of 10 byte "
+ "cdb";
+
+ if (op->numblocks > 0xffff)
+ fprintf(stderr, "%s since blocks exceed 65535\n", cp);
+ else if (llba > ULONG_MAX)
+ fprintf(stderr, "%s since LBA may exceed 32 bits\n", cp);
+ else
+ fprintf(stderr, "%s due to ndob or unmap settings\n",
+ cp);
+ }
}
}
if (act_cdb_lenp)
@@ -462,7 +473,7 @@ main(int argc, char * argv[])
if ((! if_given) && (! lba_given) && (! num_given)) {
fprintf(stderr, "As a precaution, one of '--in=', '--lba=' or "
- "'--num=' is required\n");
+ "'--num=' is required\n");
return SG_LIB_SYNTAX_ERROR;
}
diff --git a/src/sgm_dd.c b/src/sgm_dd.c
index 5ca36b8e..788a1fbb 100644
--- a/src/sgm_dd.c
+++ b/src/sgm_dd.c
@@ -62,13 +62,7 @@
#include "sg_io_linux.h"
-/* #define SG_WANT_SHARED_MMAP_IO 1 */
-
-#ifdef SG_WANT_SHARED_MMAP_IO
-static const char * version_str = "1.41 20150129 shared_mmap";
-#else
-static const char * version_str = "1.41 20150129";
-#endif
+static const char * version_str = "1.41 20150215";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -95,14 +89,6 @@ static const char * version_str = "1.41 20150129";
#define SAI_READ_CAPACITY_16 0x10
#endif
-#ifdef SG_WANT_SHARED_MMAP_IO
-#ifndef SG_FLAG_SHARED_MMAP_IO
-#define SG_FLAG_SHARED_MMAP_IO 8
-#endif
-#ifndef SG_INFO_SHARED_MMAP_IO
-#define SG_INFO_SHARED_MMAP_IO 8
-#endif
-#endif
#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
@@ -137,11 +123,6 @@ static int start_tm_valid = 0;
static struct timeval start_tm;
static int blk_sz = 0;
-#ifdef SG_WANT_SHARED_MMAP_IO
-static int shared_mm_req = 0;
-static int shared_mm_done = 0;
-#endif
-
static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio";
struct flags_t {
@@ -152,9 +133,6 @@ struct flags_t {
int dsync;
int excl;
int fua;
-#ifdef SG_WANT_SHARED_MMAP_IO
- int smmap;
-#endif
};
@@ -316,11 +294,7 @@ usage()
" treated as /dev/null\n"
" oflag comma separated list from: [append,dio,direct,"
"dpo,dsync,\n"
-#ifdef SG_WANT_SHARED_MMAP_IO
- " excl,fua,null,smmap]\n"
-#else
" excl,fua,null]\n"
-#endif
" seek block position to start writing to OFILE\n"
" skip block position to start reading from IFILE\n"
" sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
@@ -612,11 +586,7 @@ sg_read(int sg_fd, unsigned char * buff, int blocks, int64_t from_block,
* -2 -> recoverable (ENOMEM), -1 -> unrecoverable error */
static int
sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block,
- int bs, int cdbsz, int fua, int dpo, int do_mmap,
-#ifdef SG_WANT_SHARED_MMAP_IO
- int mmap_shareable,
-#endif
- int * diop)
+ int bs, int cdbsz, int fua, int dpo, int do_mmap, int * diop)
{
unsigned char wrCmd[MAX_SCSI_CDBSZ];
unsigned char senseBuff[SENSE_BUFF_LEN];
@@ -635,23 +605,13 @@ sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block,
io_hdr.cmdp = wrCmd;
io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
io_hdr.dxfer_len = bs * blocks;
-#ifdef SG_WANT_SHARED_MMAP_IO
- if (mmap_shareable || (! do_mmap))
-#else
if (! do_mmap)
-#endif
io_hdr.dxferp = buff;
io_hdr.mx_sb_len = SENSE_BUFF_LEN;
io_hdr.sbp = senseBuff;
io_hdr.timeout = DEF_TIMEOUT;
io_hdr.pack_id = (int)to_block;
-#ifdef SG_WANT_SHARED_MMAP_IO
- if (mmap_shareable) {
- io_hdr.flags |= SG_FLAG_SHARED_MMAP_IO;
- ++shared_mm_req;
- } else
-#endif
- /* nasty conditional split */ if (do_mmap)
+ if (do_mmap)
io_hdr.flags |= SG_FLAG_MMAP_IO;
else if (diop && *diop)
io_hdr.flags |= SG_FLAG_DIRECT_IO;
@@ -708,10 +668,6 @@ sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block,
sg_chk_n_print3("writing", &io_hdr, verbose > 1);
return res;
}
-#ifdef SG_WANT_SHARED_MMAP_IO
- if ((mmap_shareable) && (SG_INFO_SHARED_MMAP_IO & io_hdr.info))
- ++shared_mm_done;
-#endif
if (diop && *diop &&
((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
*diop = 0; /* flag that dio not done (completely) */
@@ -752,10 +708,6 @@ process_flags(const char * arg, struct flags_t * fp)
fp->fua = 1;
else if (0 == strcmp(cp, "null"))
;
-#ifdef SG_WANT_SHARED_MMAP_IO
- else if (0 == strcmp(cp, "smmap"))
- fp->smmap = 1;
-#endif
else {
fprintf(stderr, "unrecognised flag: %s\n", cp);
return 1;
@@ -810,9 +762,6 @@ main(int argc, char * argv[])
size_t psz;
struct flags_t in_flags;
struct flags_t out_flags;
-#ifdef SG_WANT_SHARED_MMAP_IO
- int mmap_shareable = 0;
-#endif
int ret = 0;
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
@@ -923,7 +872,7 @@ main(int argc, char * argv[])
else if (0 == strncmp(key, "verb", 4))
verbose = sg_get_num(buf);
else if ((0 == strncmp(key, "--help", 7)) ||
- (0 == strcmp(key, "-?"))) {
+ (0 == strcmp(key, "-h")) || (0 == strcmp(key, "-?"))) {
usage();
return 0;
} else if ((0 == strncmp(key, "--vers", 6)) ||
@@ -1030,11 +979,7 @@ main(int argc, char * argv[])
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
-#ifdef SG_WANT_SHARED_MMAP_IO
- mmap_shareable = 1;
-#endif
- }
- else {
+ } else {
flags = O_RDONLY;
if (in_flags.direct)
flags |= O_DIRECT;
@@ -1286,10 +1231,6 @@ main(int argc, char * argv[])
if (wrkMmap) {
wrkPos = wrkMmap;
-#ifdef SG_WANT_SHARED_MMAP_IO
- if (! (mmap_shareable && out_flags.smmap && (FT_SG == out_type)))
- mmap_shareable = 0;
-#endif
} else {
if ((FT_RAW == in_type) || (FT_RAW == out_type)) {
wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz);
@@ -1324,13 +1265,8 @@ main(int argc, char * argv[])
}
req_count = dd_count;
-#ifdef SG_WANT_SHARED_MMAP_IO
- if (verbose && (dd_count > 0) && (0 == out_flags.dio) &&
- (FT_SG == in_type) && (FT_SG == out_type) && (! mmap_shareable))
-#else
if (verbose && (dd_count > 0) && (0 == out_flags.dio) &&
(FT_SG == in_type) && (FT_SG == out_type))
-#endif
fprintf(stderr, "Since both 'if' and 'of' are sg devices, only do "
"mmap-ed transfers on 'if'\n");
@@ -1386,11 +1322,7 @@ main(int argc, char * argv[])
int dio_res = out_flags.dio;
ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out,
- out_flags.fua, out_flags.dpo, do_mmap,
-#ifdef SG_WANT_SHARED_MMAP_IO
- mmap_shareable,
-#endif
- &dio_res);
+ out_flags.fua, out_flags.dpo, do_mmap, &dio_res);
if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||
(SG_LIB_CAT_ABORTED_COMMAND == ret)) {
fprintf(stderr, "Unit attention or aborted command, "
@@ -1398,11 +1330,7 @@ main(int argc, char * argv[])
dio_res = out_flags.dio;
ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
scsi_cdbsz_out, out_flags.fua, out_flags.dpo,
- do_mmap,
-#ifdef SG_WANT_SHARED_MMAP_IO
- mmap_shareable,
-#endif
- &dio_res);
+ do_mmap, &dio_res);
}
if (0 != ret) {
fprintf(stderr, "sg_write failed, seek=%" PRId64 "\n", seek);
@@ -1481,11 +1409,5 @@ main(int argc, char * argv[])
if (num_dio_not_done)
fprintf(stderr, ">> dio requested but _not_ done %d times\n",
num_dio_not_done);
-#ifdef SG_WANT_SHARED_MMAP_IO
- if ((verbose > 0) && out_flags.smmap && (shared_mm_req > 0)) {
- fprintf(stderr, ">> shared_mm_req=%d, shared_mm_done=%d\n",
- shared_mm_req, shared_mm_done);
- }
-#endif
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}