aboutsummaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-11-27 18:38:56 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-11-27 18:38:56 +0000
commit8101850bc7cd2a05d35b4df3ecfd3f934cff584e (patch)
tree09532aaaf968dbffe9599c90cb2af79996552a00 /testing
parentd6e191ba93e7188a95b6b4fd73dbfa9157dda3ac (diff)
downloadsg3_utils-8101850bc7cd2a05d35b4df3ecfd3f934cff584e.tar.gz
sg_write_buffer: allow comma and period separated lists when input from stdin; sg driver share testing
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@796 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-rw-r--r--testing/sg_tst_ioctl.c85
-rw-r--r--testing/sgs_dd.c256
-rw-r--r--testing/uapi_sg.h22
3 files changed, 226 insertions, 137 deletions
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index bb747754..b37be2e6 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -38,12 +38,11 @@
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
- * Invocation: sg_tst_ioctl [-l=Q_LEN] [-t] <sg_device>
- * -t queue at tail
+ * Invocation: See usage() function below.
*
*/
-static const char * version_str = "Version: 0.96 20181106";
+static const char * version_str = "Version: 0.97 20181121";
#define INQ_REPLY_LEN 96
#define INQ_CMD_LEN 6
@@ -66,9 +65,33 @@ static const char * version_str = "Version: 0.96 20181106";
#define DEF_RESERVE_BUFF_SZ (256 * 1024)
-int main(int argc, char * argv[])
+static void
+usage(void)
+{
+ printf("Usage: 'sg_tst_ioctl [-h] [-l=Q_LEN] [-o] [-r=SZ] [-s=SEC] "
+ "[-t]\n"
+ " [-v] [-V] [-w] <sg_device>'\n"
+ " where:\n"
+ " -h help: print usage message then exit\n"
+ " -l=Q_LEN queue length, between 1 and 511 (def: 16)\n"
+ " -o ioctls only, then exit\n"
+ " -r=SZ reserve buffer size in KB (def: 256 --> 256 "
+ "KB)\n"
+ " -s=SEC sleep between writes and reads (def: 0)\n"
+ " -t queue_at_tail (def: q_at_head)\n"
+ " -v increase verbosity of output\n"
+ " -V print version string then exit\n"
+ " -w write (submit) only then exit\n");
+}
+
+
+int
+main(int argc, char * argv[])
{
bool done;
+ bool q_at_tail = false;
+ bool ioctl_only = false;
+ bool write_only = false;
int sg_fd, k, ok, ver_num, pack_id, num_waiting, access_count;
int sg_fd2 = -1;
uint8_t inq_cdb[INQ_CMD_LEN] =
@@ -81,7 +104,6 @@ int main(int argc, char * argv[])
char * file_name = 0;
char ebuff[EBUFF_SZ];
uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
- int q_at_tail = 0;
int q_len = DEF_Q_LEN;
int sleep_secs = 0;
int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
@@ -94,7 +116,7 @@ int main(int argc, char * argv[])
for (k = 1; k < argc; ++k) {
if (0 == memcmp("-t", argv[k], 2))
- ++q_at_tail;
+ q_at_tail = true;
else if (0 == memcmp("-h", argv[k], 2)) {
file_name = 0;
break;
@@ -106,7 +128,9 @@ int main(int argc, char * argv[])
file_name = 0;
break;
}
- } else if (0 == memcmp("-r=", argv[k], 3)) {
+ } else if (0 == memcmp("-o", argv[k], 2))
+ ioctl_only = true;
+ else if (0 == memcmp("-r=", argv[k], 3)) {
reserve_buff_sz = atoi(argv[k] + 3);
if (reserve_buff_sz < 0) {
printf("Expect -r= to take a number 0 or higher\n");
@@ -132,7 +156,9 @@ int main(int argc, char * argv[])
printf("%s\n", version_str);
file_name = 0;
break;
- } else if (*argv[k] == '-') {
+ } else if (0 == memcmp("-w", argv[k], 2))
+ write_only = true;
+ else if (*argv[k] == '-') {
printf("Unrecognized switch: %s\n", argv[k]);
file_name = 0;
break;
@@ -146,18 +172,7 @@ int main(int argc, char * argv[])
}
}
if (0 == file_name) {
- printf("Usage: 'sg_tst_ioctl [-h] [-l=Q_LEN] [-t] [-v] [-V] "
- "<sg_device>'\n"
- " where:\n"
- " -h help: print usage message then exit\n"
- " -l=Q_LEN queue length, between 1 and 511 "
- "(def: 16)\n"
- " -r=SZ reserve buffer size in KB (def: 256 --> 256 "
- "KB)\n"
- " -s=SEC sleep between writes and reads (def: 0)\n"
- " -t queue_at_tail (def: q_at_head)\n"
- " -v increase verbosity of output\n"
- " -V print version string then exit\n");
+ usage();
return 1;
}
@@ -294,7 +309,6 @@ int main(int argc, char * argv[])
}
printf(" read_value[SG_SEIRV_FL_RQS]= %u\n", seip->read_value);
-#if 1
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_READ_VAL;
seip->valid_rd_mask |= SG_SEIM_READ_VAL;
@@ -305,7 +319,28 @@ int main(int argc, char * argv[])
goto out;
}
printf(" read_value[SG_SEIRV_DEV_FL_RQS]= %u\n", seip->read_value);
-#endif
+
+ memset(seip, 0, sizeof(*seip));
+ seip->valid_wr_mask |= SG_SEIM_READ_VAL;
+ seip->valid_rd_mask |= SG_SEIM_READ_VAL;
+ seip->read_value = SG_SEIRV_TRC_SZ;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
+ strerror(errno));
+ goto out;
+ }
+ printf(" read_value[SG_SEIRV_TRC_SZ]= %u\n", seip->read_value);
+
+ memset(seip, 0, sizeof(*seip));
+ seip->valid_wr_mask |= SG_SEIM_READ_VAL;
+ seip->valid_rd_mask |= SG_SEIM_READ_VAL;
+ seip->read_value = SG_SEIRV_TRC_MAX_SZ;
+ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
+ strerror(errno));
+ goto out;
+ }
+ printf(" read_value[SG_SEIRV_TRC_MAX_SZ]= %u\n", seip->read_value);
memset(seip, 0, sizeof(*seip));
seip->valid_wr_mask |= SG_SEIM_SHARE_FD;
@@ -334,6 +369,9 @@ int main(int argc, char * argv[])
printf("SG_SET_TRANSFORM okay (does nothing)\n");
printf("\n");
+ if (ioctl_only)
+ goto out;
+
printf("start write() calls\n");
for (k = 0; k < q_len; ++k) {
/* Prepare INQUIRY command */
@@ -396,6 +434,9 @@ int main(int argc, char * argv[])
sleep(sleep_secs);
+ if (write_only)
+ goto out;
+
if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
errno, strerror(errno));
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index dd2b41d2..a82ca80a 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -1,7 +1,7 @@
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
- * Copyright (C) 1999 - 2018 D. Gilbert and P. Allworth
+ * Copyright (C) 2018 D. Gilbert
* 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
* the Free Software Foundation; either version 2, or (at your option)
@@ -85,7 +85,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.02 20180912";
+static const char * version_str = "1.03 20181126";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -139,6 +139,7 @@ typedef struct global_collection
int64_t skip;
int in_type;
int cdbsz_in;
+ int help;
struct flags_t in_flags;
int64_t in_blk; /* -\ next block address to read */
int64_t in_count; /* | blocks remaining for next read */
@@ -149,6 +150,8 @@ typedef struct global_collection
int outfd;
int64_t seek;
int out_type;
+ int out2fd;
+ int out2_type;
int cdbsz_out;
struct flags_t out_flags;
int64_t out_blk; /* -\ next block address to write */
@@ -174,6 +177,7 @@ typedef struct request_element
int id;
int infd;
int outfd;
+ int out2fd;
int64_t blk;
int num_blks;
uint8_t * buffp;
@@ -413,8 +417,10 @@ dd_filetype(const char * filename)
}
static void
-usage()
+usage(int pg_num)
{
+ if (pg_num > 0)
+ goto page2;
pr2serr("Usage: sgs_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
" [iflag=FLAGS]\n"
" [obs=BS] [of=OFILE] [oflag=FLAGS] "
@@ -422,22 +428,12 @@ usage()
" [--help] [--version]\n\n");
pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] "
"[deb=VERB] [dio=0|1]\n"
- " [fua=0|1|2|3] [sync=0|1] [thr=THR] "
- "[time=0|1] [verbose=VERB]\n"
- " [--dry-run] [--verbose]\n"
- " where:\n"
- " bpt is blocks_per_transfer (default is 128)\n"
+ " [fua=0|1|2|3] [of2=OFILE2] [sync=0|1] [thr=THR] "
+ "[time=0|1]\n"
+ " [verbose=VERB] [--dry-run] [--verbose]\n"
+ " where the main options (shown in first group above) are:\n"
" bs must be device block size (default 512)\n"
- " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n"
- " coe continue on error, 0->exit (def), "
- "1->zero + continue\n"
" count number of blocks to copy (def: device size)\n"
- " deb for debug, 0->none (def), > 0->varying degrees "
- "of debug\n");
- pr2serr(" dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
- " fua force unit access: 0->don't(def), 1->OFILE, "
- "2->IFILE,\n"
- " 3->OFILE+IFILE\n"
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,dio,direct,dpo,"
"dsync,excl,\n"
@@ -450,6 +446,38 @@ usage()
" excl,fua,noshare,null]\n"
" 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"
+ " --version|-V output version string then exit\n\n"
+ "Copy from IFILE to OFILE, similar to dd command. This utility "
+ "is specialized\nfor SCSI devices and uses multiple POSIX "
+ "threads. It expects one or both\nIFILE and OFILE to be SCSI "
+ "generic devices. If both are sg devices 'shared'\nmode is "
+ "selected unless 'noshare' is given to 'iflag=' or 'oflag='. "
+ "If\n'of2=OFLAG2' is given, the read-side is output to OFLAG2. "
+ "Without 'of2=' and\nwith IFILE and OFILE sg devices the copy "
+ "is via a single in-kernel buffer.\n"
+ );
+ return;
+page2:
+ pr2serr("Syntax: sgs_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\n"
+ " where the less used options (not shown on first help page) "
+ "are:\n"
+ " bpt is blocks_per_transfer (default is 128)\n"
+ " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n"
+ " coe continue on error, 0->exit (def), "
+ "1->zero + continue\n"
+ " deb for debug, 0->none (def), > 0->varying degrees "
+ "of debug\n"
+ " dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
+ " fua force unit access: 0->don't(def), 1->OFILE, "
+ "2->IFILE,\n"
+ " 3->OFILE+IFILE\n"
+ " of2 OFILE2 is regular file or pipe to output what is "
+ "read from the\n"
+ " disk in the first half of each shared element\n"
" sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
"after copy\n"
" thr is number of threads, must be > 0, default 4, "
@@ -458,12 +486,8 @@ usage()
"throughput\n"
" verbose same as 'deb=VERB': increase verbosity\n"
" --dry-run|-d prepare but bypass copy/read\n"
- " --help|-h output this usage message then exit\n"
" --verbose|-v increase verbosity of utility\n"
- " --version|-V output version string then exit\n\n"
- "Copy from IFILE to OFILE, similar to dd command. This utility "
- "is\nspecialized for SCSI devices, uses multiple POSIX threads. "
- "It expects\n");
+ );
}
static void
@@ -565,7 +589,7 @@ sig_listen_thread(void * v_clp)
if (shutting_down)
break;
if (SIGINT == sig_number) {
- pr2serr("%sinterrupted by SIGINT\n", my_name);
+ pr2serr_lk("%sinterrupted by SIGINT\n", my_name);
guarded_stop_both(clp);
pthread_cond_broadcast(&clp->out_sync_cv);
}
@@ -573,7 +597,7 @@ sig_listen_thread(void * v_clp)
return NULL;
}
-static int
+static bool
sg_share_prepare(int slave_writer_fd, int master_reader_fd, int id, bool vb_b)
{
struct sg_extended_info sei;
@@ -587,11 +611,11 @@ sg_share_prepare(int slave_writer_fd, int master_reader_fd, int id, bool vb_b)
if (ioctl(slave_writer_fd, SG_SET_GET_EXTENDED, seip) < 0) {
if (vb_b)
pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed "
- "errno=%d %s\n", id, master_reader_fd, errno,
- strerror(errno));
- return 1;
+ "errno=%d %s\n", id, master_reader_fd, errno,
+ strerror(errno));
+ return false;
}
- return 0;
+ return true;
}
static void
@@ -645,6 +669,7 @@ read_write_thread(void * v_tip)
rep->bs = clp->bs;
rep->infd = clp->infd;
rep->outfd = clp->outfd;
+ rep->out2fd = clp->out2fd;
rep->debug = clp->debug;
rep->cdbsz_in = clp->cdbsz_in;
rep->cdbsz_out = clp->cdbsz_out;
@@ -654,8 +679,8 @@ read_write_thread(void * v_tip)
if (vb)
pr2serr_lk("Skipping share on both IFILE and OFILE\n");
} else
- rep->has_share = !(sg_share_prepare(clp->outfd, clp->infd, rep->id,
- clp->debug));
+ rep->has_share = sg_share_prepare(clp->outfd, clp->infd, rep->id,
+ clp->debug);
if (vb > 0)
pr2serr_lk("starting thread %d, has_share=%s\n", rep->id,
(rep->has_share ? "true" : "false"));
@@ -915,7 +940,6 @@ sg_in_operation(Gbl_coll * clp, Rq_elem * rep)
/* enters holding in_mutex */
while (1) {
-// sleep(20); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
res = sg_start_io(rep);
if (1 == res)
err_exit(ENOMEM, "sg starting in command");
@@ -929,11 +953,9 @@ sg_in_operation(Gbl_coll * clp, Rq_elem * rep)
}
/* Now release in mutex to let other reads run in parallel */
status = pthread_mutex_unlock(&clp->in_mutex);
-// sleep(20); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
if (0 != status) err_exit(status, "unlock in_mutex");
res = sg_finish_io(rep->wr, rep, &clp->aux_mutex);
-// sleep(6); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
switch (res) {
case SG_LIB_CAT_ABORTED_COMMAND:
case SG_LIB_CAT_UNIT_ATTENTION:
@@ -994,9 +1016,9 @@ sg_out_operation(Gbl_coll * clp, Rq_elem * rep)
int res;
int status;
+
/* enters holding out_mutex */
while (1) {
-// sleep(10); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
res = sg_start_io(rep);
if (1 == res)
err_exit(ENOMEM, "sg starting out command");
@@ -1012,9 +1034,7 @@ sg_out_operation(Gbl_coll * clp, Rq_elem * rep)
status = pthread_mutex_unlock(&clp->out_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
-// sleep(10); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
res = sg_finish_io(rep->wr, rep, &clp->aux_mutex);
-// sleep(6); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx
switch (res) {
case SG_LIB_CAT_ABORTED_COMMAND:
case SG_LIB_CAT_UNIT_ATTENTION:
@@ -1076,6 +1096,7 @@ sg_start_io(Rq_elem * rep)
int res;
struct sg_io_hdr * hp = &rep->io_hdr;
const char * cp = "";
+ const char * c2p = "";
if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, rep->blk,
rep->wr, fua, dpo)) {
@@ -1097,21 +1118,22 @@ sg_start_io(Rq_elem * rep)
hp->pack_id = (int)rep->blk;
if (dio)
hp->flags |= SG_FLAG_DIRECT_IO;
-#if 1
if (rep->has_share) {
-#else
- if (rep->has_share && !wr) { /* && !wr is temporary xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
-#endif
hp->flags |= SGV4_FLAG_SHARE;
if (wr)
- hp->flags |= SGV4_FLAG_NO_DXFER;
+ hp->flags |= SGV4_FLAG_NO_DXFER;
+ else if (rep->out2fd < 0)
+ hp->flags |= SGV4_FLAG_NO_DXFER;
+ if (hp->flags & SGV4_FLAG_NO_DXFER)
+ c2p = " and FLAG_NO_DXFER";
+
cp = (wr ? " slave active" : " master active");
- }
+ } else
cp = (wr ? " slave not sharing" : " master not sharing");
- if (rep->debug > 8) {
- pr2serr_lk("%s tid=%d: SCSI %s%s, blk=%" PRId64 " num_blks=%d\n",
+ if (rep->debug > 3) {
+ pr2serr_lk("%s tid=%d: SCSI %s%s%s, blk=%" PRId64 " num_blks=%d\n",
__func__, rep->id, (rep->wr ? "WRITE" : "READ"), cp,
- rep->blk, rep->num_blks);
+ c2p, rep->blk, rep->num_blks);
sg_print_command(hp->cmdp);
}
@@ -1134,7 +1156,7 @@ sg_start_io(Rq_elem * rep)
static int
sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
{
- int res, status;
+ int res, err, status;
struct sg_io_hdr io_hdr;
struct sg_io_hdr * hp;
#if 0
@@ -1162,31 +1184,31 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
res = sg_err_category3(hp);
switch (res) {
- case SG_LIB_CAT_CLEAN:
- break;
- case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3((wr ? "writing continuing":
- "reading continuing"), hp, false);
- break;
- case SG_LIB_CAT_ABORTED_COMMAND:
- case SG_LIB_CAT_UNIT_ATTENTION:
- if (rep->debug > 8)
- sg_chk_n_print3((wr ? "writing": "reading"), hp, false);
+ case SG_LIB_CAT_CLEAN:
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ sg_chk_n_print3((wr ? "writing continuing":
+ "reading continuing"), hp, false);
+ break;
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ if (rep->debug > 3)
+ sg_chk_n_print3((wr ? "writing": "reading"), hp, false);
+ return res;
+ case SG_LIB_CAT_NOT_READY:
+ default:
+ {
+ char ebuff[EBUFF_SZ];
+
+ snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64,
+ wr ? "writing": "reading", rep->blk);
+ status = pthread_mutex_lock(a_mutp);
+ if (0 != status) err_exit(status, "lock aux_mutex");
+ sg_chk_n_print3(ebuff, hp, false);
+ status = pthread_mutex_unlock(a_mutp);
+ if (0 != status) err_exit(status, "unlock aux_mutex");
return res;
- case SG_LIB_CAT_NOT_READY:
- default:
- {
- char ebuff[EBUFF_SZ];
-
- snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64,
- wr ? "writing": "reading", rep->blk);
- status = pthread_mutex_lock(a_mutp);
- if (0 != status) err_exit(status, "lock aux_mutex");
- sg_chk_n_print3(ebuff, hp, false);
- status = pthread_mutex_unlock(a_mutp);
- if (0 != status) err_exit(status, "unlock aux_mutex");
- return res;
- }
+ }
}
#if 0
if (0 == (++testing % 100)) return -1;
@@ -1197,7 +1219,18 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
else
rep->dio_incomplete_count = 0;
rep->resid = hp->resid;
- if (rep->debug > 8)
+ if ((! wr) && (rep->out2fd >= 0)) {
+ status = pthread_mutex_lock(a_mutp);
+ if (0 != status) err_exit(status, "lock aux_mutex");
+ res = write(rep->out2fd, rep->buffp, rep->bs * rep->num_blks);
+ err = errno;
+ status = pthread_mutex_unlock(a_mutp);
+ if (0 != status) err_exit(status, "unlock aux_mutex");
+ if (res < 0)
+ pr2serr_lk("%s: tid=%d: write(out2fd) failed: %s\n", __func__,
+ rep->id, strerror(err));
+ }
+ if (rep->debug > 3)
pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id,
wr ? "WRITE" : "READ");
return 0;
@@ -1334,7 +1367,7 @@ sg_out_open(Gbl_coll *clp, const char *outf)
}
if (sg_prepare(fd, clp->bs, clp->bpt))
return -SG_LIB_FILE_ERROR;
- else if (gcoll.debug > 0)
+ else if (gcoll.debug > 1)
pr2serr("Sharing writer's fd (%d) with reader (fd=%d) "
"successful\n", clp->infd, fd);
return fd;
@@ -1359,6 +1392,7 @@ main(int argc, char * argv[])
char * buf;
char inf[INOUTF_SZ];
char outf[INOUTF_SZ];
+ char out2f[INOUTF_SZ];
int res, k, err, keylen;
int64_t in_num_sect = 0;
int64_t out_num_sect = 0;
@@ -1383,6 +1417,7 @@ main(int argc, char * argv[])
gcoll.cdbsz_out = DEF_SCSI_CDBSZ;
inf[0] = '\0';
outf[0] = '\0';
+ out2f[0] = '\0';
for (k = 1; k < argc; k++) {
if (argv[k]) {
@@ -1459,6 +1494,12 @@ main(int argc, char * argv[])
pr2serr("%sbad argument to 'obs='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
+ } else if (strcmp(key,"of2") == 0) {
+ if ('\0' != out2f[0]) {
+ pr2serr("Second OFILE2 argument??\n");
+ return SG_LIB_CONTRADICT;
+ } else
+ strncpy(out2f, buf, INOUTF_SZ - 1);
} else if (strcmp(key,"of") == 0) {
if ('\0' != outf[0]) {
pr2serr("Second 'of=' argument??\n");
@@ -1494,10 +1535,8 @@ main(int argc, char * argv[])
gcoll.dry_run += n;
res += n;
n = num_chs_in_str(key + 1, keylen - 1, 'h');
- if (n > 0) {
- usage();
- return 0;
- }
+ gcoll.help += n;
+ res += n;
n = num_chs_in_str(key + 1, keylen - 1, 'v');
if (n > 0)
verbose_given = true;
@@ -1517,10 +1556,9 @@ main(int argc, char * argv[])
(0 == strncmp(key, "--dry_run", 9)))
++gcoll.dry_run;
else if ((0 == strncmp(key, "--help", 6)) ||
- (0 == strcmp(key, "-?"))) {
- usage();
- return 0;
- } else if (0 == strncmp(key, "--verb", 6)) {
+ (0 == strcmp(key, "-?")))
+ ++gcoll.help;
+ else if (0 == strncmp(key, "--verb", 6)) {
verbose_given = true;
++gcoll.debug; /* --verbose */
} else if (0 == strncmp(key, "--vers", 6))
@@ -1552,14 +1590,20 @@ main(int argc, char * argv[])
pr2serr("%s%s\n", my_name, version_str);
return 0;
}
-
+ if (gcoll.help > 0) {
+ if (1 == gcoll.help)
+ usage(0);
+ else
+ usage(1);
+ return 0;
+ }
if (gcoll.bs <= 0) {
gcoll.bs = DEF_BLOCK_SIZE;
pr2serr("Assume default 'bs' (block size) of %d bytes\n", gcoll.bs);
}
if ((ibs && (ibs != gcoll.bs)) || (obs && (obs != gcoll.bs))) {
pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
- usage();
+ usage(0);
return SG_LIB_SYNTAX_ERROR;
}
if ((skip < 0) || (seek < 0)) {
@@ -1581,7 +1625,7 @@ main(int argc, char * argv[])
gcoll.bpt = DEF_BLOCKS_PER_2048TRANSFER;
if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
pr2serr("too few or too many threads requested\n");
- usage();
+ usage(1);
return SG_LIB_SYNTAX_ERROR;
}
if (gcoll.debug)
@@ -1695,6 +1739,17 @@ main(int argc, char * argv[])
}
}
}
+ if (out2f[0]) {
+ gcoll.out2_type = dd_filetype(out2f);
+ if ((gcoll.out2fd = open(out2f, O_WRONLY | O_CREAT, 0666)) < 0) {
+ err = errno;
+ snprintf(ebuff, EBUFF_SZ, "could not open %s for writing", out2f);
+ perror(ebuff);
+ return sg_convert_errno(err);
+ }
+ } else
+ gcoll.out2fd = -1;
+
if ((STDIN_FILENO == gcoll.infd) && (STDOUT_FILENO == gcoll.outfd)) {
pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n");
pr2serr("For more information use '--help'\n");
@@ -1775,7 +1830,7 @@ main(int argc, char * argv[])
else
dd_count = out_num_sect;
}
- if (gcoll.debug > 1)
+ if (gcoll.debug > 2)
pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64
", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect,
out_num_sect);
@@ -1845,8 +1900,8 @@ main(int argc, char * argv[])
status = pthread_create(&threads[0], NULL, read_write_thread,
(void *)&ti);
if (0 != status) err_exit(status, "pthread_create");
- if (gcoll.debug)
- pr2serr("Starting worker thread k=0\n");
+ if (gcoll.debug > 1)
+ pr2serr_lk("Starting worker thread k=0\n");
/* wait for any broadcast */
pthread_cleanup_push(cleanup_out, (void *)&gcoll);
@@ -1865,16 +1920,16 @@ main(int argc, char * argv[])
status = pthread_create(&threads[k], NULL, read_write_thread,
(void *)&tinfo);
if (0 != status) err_exit(status, "pthread_create");
- if (gcoll.debug)
- pr2serr("Starting worker thread k=%d\n", k);
+ if (gcoll.debug > 1)
+ pr2serr_lk("Starting worker thread k=%d\n", k);
}
/* now wait for worker threads to finish */
for (k = 0; k < num_threads; ++k) {
status = pthread_join(threads[k], &vp);
if (0 != status) err_exit(status, "pthread_join");
- if (gcoll.debug)
- pr2serr("Worker thread k=%d terminated\n", k);
+ if (gcoll.debug > 0)
+ pr2serr_lk("Worker thread k=%d terminated\n", k);
}
} /* started worker threads and here after they have all exited */
@@ -1883,30 +1938,18 @@ main(int argc, char * argv[])
if (do_sync) {
if (FT_SG == gcoll.out_type) {
- pr2serr(">> Synchronizing cache on %s\n", outf);
+ pr2serr_lk(">> Synchronizing cache on %s\n", outf);
res = sg_ll_sync_cache_10(gcoll.outfd, 0, 0, 0, 0, 0, false, 0);
if (SG_LIB_CAT_UNIT_ATTENTION == res) {
- pr2serr("Unit attention(out), continuing\n");
+ pr2serr_lk("Unit attention(out), continuing\n");
res = sg_ll_sync_cache_10(gcoll.outfd, 0, 0, 0, 0, 0, false,
0);
}
if (0 != res)
- pr2serr("Unable to synchronize cache\n");
+ pr2serr_lk("Unable to synchronize cache\n");
}
}
-#if 0
-#if SG_LIB_ANDROID
- /* Android doesn't have pthread_cancel() so use pthread_kill() instead.
- * Also there is no need to link with -lpthread in Android */
- status = pthread_kill(sig_listen_thread_id, SIGUSR1);
- if (0 != status) err_exit(status, "pthread_kill");
-#else
- status = pthread_cancel(sig_listen_thread_id);
- if (0 != status) err_exit(status, "pthread_cancel");
-#endif
-#endif /* #if 0, because always do pthread_kill(), see next */
-
shutting_down = true;
status = pthread_kill(sig_listen_thread_id, SIGINT);
if (0 != status) err_exit(status, "pthread_kill");
@@ -1915,11 +1958,12 @@ main(int argc, char * argv[])
fini:
-// sleep(20); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxxx
if (STDIN_FILENO != gcoll.infd)
close(gcoll.infd);
if ((STDOUT_FILENO != gcoll.outfd) && (FT_DEV_NULL != gcoll.out_type))
close(gcoll.outfd);
+ if ((STDOUT_FILENO != gcoll.out2fd) && (FT_DEV_NULL != gcoll.out2_type))
+ close(gcoll.out2fd);
res = exit_status;
if ((0 != gcoll.out_count) && (0 == gcoll.dry_run)) {
pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n",
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index f9d8298e..1485c2e8 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -13,7 +13,7 @@
* Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version: 3.9.02 (20181104)
+ * Version: 3.9.02 (20181118)
* This version is for Linux 2.6, 3 and 4 series kernels.
*
* Documentation
@@ -30,12 +30,12 @@
#include <linux/types.h>
#include <linux/major.h>
-/* bsg.h contains the sg v4 use space interface structure. */
+/* bsg.h contains the sg v4 user space interface structure. */
#include <linux/bsg.h>
/*
* Same structure as used by readv() call. It defines one scatter-gather
- * element. "Scatter-gather" is abbreviated to "sgat" in thsi driver to
+ * element. "Scatter-gather" is abbreviated to "sgat" in this driver to
* avoid confusion with this driver's name.
*/
typedef struct sg_iovec {
@@ -143,7 +143,7 @@ typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
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 orphan; /* 0 -> normal request, 1 -> from interruped SG_IO */
+ char orphan; /* 0 -> normal request, 1 -> from interrupted SG_IO */
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 */
@@ -182,11 +182,13 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#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_UNSHARE 0x20 /* undo share after inflight cmd */
-#define SG_CTL_FLAGM_MASTER_FINI 0x40 /* share: master finished; 1: finish */
-#define SG_CTL_FLAGM_MASTER_ERR 0x80 /* rd: sharing, master got error */
-#define SG_CTL_FLAGM_CHECK_FOR_MORE 0x100 /* additional ready to read? */
-#define SG_CTL_FLAGM_ALL_BITS 0x1ff /* should be OR of previous items */
+#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 */
+#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 */
/* Write one of the following values to sg_extended_info::read_value, get... */
#define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */
@@ -194,6 +196,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_SEIRV_VERS_NUM 0x2 /* get driver version number as int */
#define SG_SEIRV_FL_RQS 0x3 /* number of requests in free list */
#define SG_SEIRV_DEV_FL_RQS 0x4 /* sum of rqs on all fds on this dev */
+#define SG_SEIRV_TRC_SZ 0x5 /* current size of trace buffer */
+#define SG_SEIRV_TRC_MAX_SZ 0x6 /* maximum size of trace buffer */
/*
* A pointer to the following structure is passed as the third argument to