aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--CREDITS6
-rw-r--r--ChangeLog4
-rw-r--r--doc/sg_write_buffer.82
-rw-r--r--src/sg_write_buffer.c61
-rw-r--r--testing/sg_tst_ioctl.c85
-rw-r--r--testing/sgs_dd.c256
-rw-r--r--testing/uapi_sg.h22
7 files changed, 286 insertions, 150 deletions
diff --git a/CREDITS b/CREDITS
index beefb4cb..d67a9a34 100644
--- a/CREDITS
+++ b/CREDITS
@@ -11,6 +11,10 @@ Bart Van Assche <bart dot vanassche at sandisk dot com>
configure.ac and Makefile.am cleanup plus sgp_dd code
to replace pthread_cancel with pthread_kill [20180102]
+Bean Huo <beanhuo dot micron dot com>
+ sg_write_buffer: patch to allow comma or period separated bytes
+ (in decimal or hex) to be decoded when given as standard input.
+
Brian Bunker <Brian dot Bunker at netapp dot com> contributed
sg_read_block_limits and the target reset addition to sg_reset
[20090615]
@@ -141,4 +145,4 @@ Trent Piepho <xyzzy at speakeasy dot org> print out some "sense key specific"
Douglas Gilbert
-2nd January 2018
+12th November 2018
diff --git a/ChangeLog b/ChangeLog
index bc82c5b8..dd82b41a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,10 +2,12 @@ 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 [20181112] [svn: r795]
+Changelog for sg3_utils-1.45 [20181127] [svn: r796]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (18-102r0)
+ - sg_write_buffer: allow comma and period separated
+ lists when input from stdin
- sg_scan (win32): expand limits for big arrays
- rescan-scsi-bus: widen LUN 0 only scanning
- testing/sg_tst_async: fix free_list issue
diff --git a/doc/sg_write_buffer.8 b/doc/sg_write_buffer.8
index d2aab53e..09332e1e 100644
--- a/doc/sg_write_buffer.8
+++ b/doc/sg_write_buffer.8
@@ -1,4 +1,4 @@
-.TH SG_WRITE_BUFFER "8" "January 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_WRITE_BUFFER "8" "November 2018" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_write_buffer \- send SCSI WRITE BUFFER commands
.SH SYNOPSIS
diff --git a/src/sg_write_buffer.c b/src/sg_write_buffer.c
index 9c81e930..d3b02942 100644
--- a/src/sg_write_buffer.c
+++ b/src/sg_write_buffer.c
@@ -38,7 +38,7 @@
* This utility issues the SCSI WRITE BUFFER command to the given device.
*/
-static const char * version_str = "1.28 20180628"; /* spc5r19 */
+static const char * version_str = "1.29 20181112"; /* spc5r19 */
#define ME "sg_write_buffer: "
#define DEF_XFER_LEN (8 * 1024 * 1024)
@@ -212,6 +212,7 @@ main(int argc, char * argv[])
const char * device_name = NULL;
const char * file_name = NULL;
uint8_t * dop = NULL;
+ uint8_t * read_buf = NULL;
uint8_t * free_dop = NULL;
char * cp;
const struct mode_s * mp;
@@ -440,15 +441,53 @@ main(int argc, char * argv[])
}
}
}
- res = read(infd, dop, wb_len);
- if (res < 0) {
- ret = sg_convert_errno(errno);
- snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
- file_name);
- perror(ebuff);
- if (! got_stdin)
- close(infd);
- goto err_out;
+ if (infd == STDIN_FILENO) {
+ if (NULL == (read_buf = (uint8_t *)malloc(DEF_XFER_LEN))) {
+ pr2serr(ME "out of memory\n");
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
+ }
+ res = read(infd, read_buf, DEF_XFER_LEN);
+ if (res < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't read from STDIN");
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ char * pch;
+ int val = 0;
+ res = 0;
+ pch = strtok((char*)read_buf, ",. \n\t");
+ while (pch != NULL) {
+ val = sg_get_num_nomult(pch);
+ if (val >= 0 && val < 255) {
+ dop[res] = val;
+ res++;
+ } else {
+ pr2serr("Data read from STDIO is wrong.\nPlease "
+ "input the data a byte at a time, the bytes "
+ "should be separated\nby either space, or "
+ "',' ( or by '.'), and the value per byte "
+ "should\nbe between 0~255. Hexadecimal "
+ "numbers should be preceded by either '0x' "
+ "or\n'OX' (or have a trailing 'h' or "
+ "'H').\n");
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
+ }
+ pch = strtok(NULL, ",. \n\t");
+ }
+ } else {
+ res = read(infd, dop, wb_len);
+ if (res < 0) {
+ ret = sg_convert_errno(errno);
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
+ file_name);
+ perror(ebuff);
+ if (! got_stdin)
+ close(infd);
+ goto err_out;
+ }
}
if (res < wb_len) {
if (wb_len_given) {
@@ -537,6 +576,8 @@ main(int argc, char * argv[])
err_out:
if (free_dop)
free(free_dop);
+ if (read_buf)
+ free(read_buf);
if (sg_fd >= 0) {
res = sg_cmds_close_device(sg_fd);
if (res < 0) {
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