aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2019-01-31 14:29:54 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2019-01-31 14:29:54 +0000
commit04adb7f5027fb9f8b4368e4eaa561e14591bb1a7 (patch)
tree7f3af533e28c692c020eabd152b49762f340f106
parenta918d1a30569c4d3f09cc87836ff19215db6d8b7 (diff)
downloadsg3_utils-04adb7f5027fb9f8b4368e4eaa561e14591bb1a7.tar.gz
linux: add nanosecond durations when SG3_UTILS_LINUX_NANO environment variable given
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@809 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog4
-rw-r--r--doc/sg3_utils.89
-rw-r--r--include/sg_pt.h8
-rw-r--r--lib/sg_cmds_basic.c24
-rw-r--r--lib/sg_lib.c2
-rw-r--r--lib/sg_pt_common.c2
-rw-r--r--lib/sg_pt_freebsd.c8
-rw-r--r--lib/sg_pt_linux.c110
-rw-r--r--lib/sg_pt_osf1.c8
-rw-r--r--lib/sg_pt_solaris.c8
-rw-r--r--lib/sg_pt_win32.c8
-rw-r--r--src/sg_raw.c9
-rw-r--r--src/sg_write_same.c4
-rw-r--r--testing/sg_queue_tst.c6
-rw-r--r--testing/sg_tst_async.cpp10
-rw-r--r--testing/sg_tst_bidi.c10
-rw-r--r--testing/sg_tst_ioctl.c71
-rw-r--r--testing/sgh_dd.c193
-rw-r--r--testing/uapi_sg.h46
19 files changed, 368 insertions, 172 deletions
diff --git a/ChangeLog b/ChangeLog
index c36443da..debe236f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.45 [20190123] [svn: r808]
+Changelog for sg3_utils-1.45 [20190131] [svn: r809]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (spc5r20)
@@ -18,6 +18,8 @@ Changelog for sg3_utils-1.45 [20190123] [svn: r808]
- tweak sg_pt interface to better handle bidi
- sg_cmds_process_resp(): two arguments removed
- sg_pt_freebsd: fixes for FreeBSD 12.0 release
+ - linux: add nanosecond durations when
+ SG3_UTILS_LINUX_NANO environment variable given
- rescan-scsi-bus: widen LUN 0 only scanning
- testing/sg_tst_async: fix free_list issue
- testing/sg_tst_ioctl: for sg 4.0 driver
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index be4a53e8..e3e4b70b 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -98,6 +98,15 @@ SCSI to NVMe Translation Layer within the underlying library).
Several utilities have their own environment variable setting (e.g.
sg_persist has SG_PERSIST_IN_RDONLY). See individual utility man pages
for more information.
+.PP
+There is a Linux specific environment variable called SG3_UTILS_LINUX_NANO
+that if defined and the sg driver in the system is 4.0.0 or later, will
+show command durations in nanoseconds rather than the default milliseconds.
+Command durations are typically only shown if \-\-verbose is used 3 or more
+times. Due to an interface problem (a 32 bit integer that should be 64 bits
+with the benefit of hindsight) the maximum duration that can be represented
+in nanoseconds is about 4.2 seconds. If longer durations may occur then
+don't define this environment variable (or undefine it).
.SH LINUX DEVICE NAMING
Most disk block devices have names like /dev/sda, /dev/sdb, /dev/sdc, etc.
SCSI disks in Linux have always had names like that but in recent Linux
diff --git a/include/sg_pt.h b/include/sg_pt.h
index 00a43096..2be9cbf9 100644
--- a/include/sg_pt.h
+++ b/include/sg_pt.h
@@ -211,14 +211,18 @@ char * get_scsi_pt_transport_err_str(const struct sg_pt_base * objp,
* command. */
int get_scsi_pt_duration_ms(const struct sg_pt_base * objp);
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t get_pt_duration_ns(const struct sg_pt_base * objp);
+
/* The two functions yield requested and actual data transfer lengths in
* bytes. The second argument is a pointer to the data-in length; the third
* argument is a pointer to the data-out length. The pointers may be NULL.
* The _actual_ values are related to resid (residual count from DMA) */
void get_pt_req_lengths(const struct sg_pt_base * objp, int * req_dinp,
- int * req_doutp);
+ int * req_doutp);
void get_pt_actual_lengths(const struct sg_pt_base * objp, int * act_dinp,
- int * act_doutp);
+ int * act_doutp);
/* Return true if device associated with 'objp' uses NVMe command set. To
* be useful (in modifying the type of command sent (SCSI or NVMe) then
diff --git a/lib/sg_cmds_basic.c b/lib/sg_cmds_basic.c
index 3e26af24..927c92a5 100644
--- a/lib/sg_cmds_basic.c
+++ b/lib/sg_cmds_basic.c
@@ -23,6 +23,8 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -40,7 +42,7 @@
#endif
-static const char * const version_str = "1.91 20190113";
+static const char * const version_str = "1.93 20190128";
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -190,7 +192,7 @@ sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
int pt_res, bool noisy, int verbose, int * o_sense_cat)
{
bool transport_sense;
- int cat, duration, slen, resp_code, sstat, req_din_x, req_dout_x;
+ int cat, slen, resp_code, sstat, req_din_x, req_dout_x;
int act_din_x, act_dout_x;
const uint8_t * sbp;
char b[1024];
@@ -223,8 +225,18 @@ sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
pr2ws("%s: %s timeout\n", leadin, pass_through_s);
return -1;
}
- if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
- pr2ws(" duration=%d ms\n", duration);
+ if (verbose > 2) {
+ uint64_t duration = get_pt_duration_ns(ptvp);
+
+ if (duration > 0)
+ pr2ws(" duration=%" PRIu64 " ns\n", duration);
+ else {
+ int d = get_scsi_pt_duration_ms(ptvp);
+
+ if (d != -1)
+ pr2ws(" duration=%u ms\n", (uint32_t)d);
+ }
+ }
get_pt_req_lengths(ptvp, &req_din_x, &req_dout_x);
get_pt_actual_lengths(ptvp, &act_din_x, &act_dout_x);
slen = get_scsi_pt_sense_len(ptvp);
@@ -503,7 +515,7 @@ sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
inq_data->peripheral_qualifier = 0x3;
inq_data->peripheral_type = 0x1f;
}
- inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, verbose > 4);
+ inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
if (NULL == inq_resp) {
pr2ws("%s: out of memory\n", __func__);
return sg_convert_errno(ENOMEM);
@@ -545,7 +557,7 @@ sg_simple_inquiry_pt(struct sg_pt_base * ptvp,
inq_data->peripheral_qualifier = 0x3;
inq_data->peripheral_type = 0x1f;
}
- inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, verbose > 4);
+ inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
if (NULL == inq_resp) {
pr2ws("%s: out of memory\n", __func__);
return sg_convert_errno(ENOMEM);
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 3e40c111..79783974 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -1914,7 +1914,7 @@ sg_print_sense(const char * leadin, const uint8_t * sbp, int sb_len,
char *cp;
uint8_t *free_cp;
- cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, 0);
+ cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, false);
if (NULL == cp)
return;
sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp);
diff --git a/lib/sg_pt_common.c b/lib/sg_pt_common.c
index ffd76c1d..48bf4b2e 100644
--- a/lib/sg_pt_common.c
+++ b/lib/sg_pt_common.c
@@ -31,7 +31,7 @@
#include "sg_pt_nvme.h"
#endif
-static const char * scsi_pt_version_str = "3.10 20190113";
+static const char * scsi_pt_version_str = "3.11 20190128";
const char *
diff --git a/lib/sg_pt_freebsd.c b/lib/sg_pt_freebsd.c
index 3c38dbe6..596c77aa 100644
--- a/lib/sg_pt_freebsd.c
+++ b/lib/sg_pt_freebsd.c
@@ -890,6 +890,14 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
return -1;
}
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t
+get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
+{
+ return 0;
+}
+
int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)
{
diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c
index 0b50e439..4a570f8e 100644
--- a/lib/sg_pt_linux.c
+++ b/lib/sg_pt_linux.c
@@ -109,6 +109,10 @@ bool sg_bsg_nvme_char_major_checked = false;
int sg_bsg_major = 0;
volatile int sg_nvme_char_major = 0;
+bool sg_checked_version_num = false;
+int sg_driver_version_num = 0;
+bool sg_duration_set_nano = false;
+
long sg_lin_page_size = 4096; /* default, overridden with correct value */
@@ -470,6 +474,36 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
}
}
+#ifndef SG_SET_GET_EXTENDED
+
+/* If both sei_wr_mask and sei_rd_mask are 0, this ioctl does nothing */
+struct sg_extended_info {
+ uint32_t sei_wr_mask; /* OR-ed SG_SEIM_* user->driver values */
+ uint32_t sei_rd_mask; /* OR-ed SG_SEIM_* driver->user values */
+ uint32_t ctl_flags_wr_mask; /* OR-ed SG_CTL_FLAGM_* values */
+ uint32_t ctl_flags_rd_mask; /* OR-ed SG_CTL_FLAGM_* values */
+ uint32_t ctl_flags; /* bit values OR-ed, see SG_CTL_FLAGM_* */
+ uint32_t read_value; /* write SG_SEIRV_*, read back related */
+
+ uint32_t reserved_sz; /* data/sgl size of pre-allocated request */
+ uint32_t tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */
+ uint32_t minor_index; /* rd: kernel's sg device minor number */
+ uint32_t share_fd; /* SHARE_FD and CHG_SHARE_FD use this */
+ uint32_t sgat_elem_sz; /* sgat element size (must be power of 2) */
+ uint8_t pad_to_96[52]; /* pad so struct is 96 bytes long */
+};
+
+#define SG_IOCTL_MAGIC_NUM 0x22
+
+#define SG_SET_GET_EXTENDED _IOWR(SG_IOCTL_MAGIC_NUM, 0x51, \
+ struct sg_extended_info)
+
+#define SG_SEIM_CTL_FLAGS 0x1
+
+#define SG_CTL_FLAGM_TIME_IN_NS 0x1
+
+#endif
+
/* Forget any previous dev_fd and install the one given. May attempt to
* find file type (e.g. if pass-though) from OS so there could be an error.
* Returns 0 for success or the same value as get_scsi_pt_os_err()
@@ -489,12 +523,15 @@ set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg,
&ptp->is_nvme, &ptp->nvme_nsid,
&ptp->os_err, verbose);
- if (ptp->is_sg) {
+ if (ptp->is_sg && (! sg_checked_version_num)) {
if (ioctl(dev_fd, SG_GET_VERSION_NUM, &ptp->sg_version) < 0) {
ptp->sg_version = 0;
if (verbose > 3)
pr2ws("%s: ioctl(SG_GET_VERSION_NUM) failed: errno: %d "
"[%s]\n", __func__, errno, safe_strerror(errno));
+ } else { /* got version number */
+ sg_driver_version_num = ptp->sg_version;
+ sg_checked_version_num = true;
}
if (verbose > 4) {
int ver = ptp->sg_version;
@@ -514,6 +551,30 @@ set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
__func__, ver / 10000, (ver / 100) % 100,
ver % 100);
}
+ } else if (ptp->is_sg)
+ ptp->sg_version = sg_driver_version_num;
+
+ if (ptp->is_sg && (ptp->sg_version >= SG_LINUX_SG_VER_V4) &&
+ getenv("SG3_UTILS_LINUX_NANO")) {
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip = &sei;
+
+ memset(seip, 0, sizeof(*seip));
+ /* try to override default of milliseconds */
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
+ seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
+ if (ioctl(dev_fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ if (verbose > 2)
+ pr2ws("%s: unable to override milli --> nanoseconds: "
+ "%s\n", __func__, safe_strerror(errno));
+ } else {
+ if (! sg_duration_set_nano)
+ sg_duration_set_nano = true;
+ if (verbose > 5)
+ pr2ws("%s: dev_fd=%d, succeeding in setting durations "
+ "to nanoseconds\n", __func__, dev_fd);
+ }
}
} else {
ptp->is_sg = false;
@@ -708,16 +769,16 @@ get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
const struct sg_pt_linux_scsi * ptp = &vp->impl;
if (req_dinp) {
- if (ptp->io_hdr.din_xfer_len > 0)
- *req_dinp = ptp->io_hdr.din_xfer_len;
- else
- *req_dinp = 0;
+ if (ptp->io_hdr.din_xfer_len > 0)
+ *req_dinp = ptp->io_hdr.din_xfer_len;
+ else
+ *req_dinp = 0;
}
if (req_doutp) {
- if (ptp->io_hdr.dout_xfer_len > 0)
- *req_doutp = ptp->io_hdr.dout_xfer_len;
- else
- *req_doutp = 0;
+ if (ptp->io_hdr.dout_xfer_len > 0)
+ *req_doutp = ptp->io_hdr.dout_xfer_len;
+ else
+ *req_doutp = 0;
}
}
@@ -728,18 +789,18 @@ get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
const struct sg_pt_linux_scsi * ptp = &vp->impl;
if (act_dinp) {
- if (ptp->io_hdr.din_xfer_len > 0) {
- int res = ptp->io_hdr.din_xfer_len - ptp->io_hdr.din_resid;
+ if (ptp->io_hdr.din_xfer_len > 0) {
+ int res = ptp->io_hdr.din_xfer_len - ptp->io_hdr.din_resid;
- *act_dinp = (res > 0) ? res : 0;
- } else
- *act_dinp = 0;
+ *act_dinp = (res > 0) ? res : 0;
+ } else
+ *act_dinp = 0;
}
if (act_doutp) {
- if (ptp->io_hdr.dout_xfer_len > 0)
- *act_doutp = ptp->io_hdr.dout_xfer_len - ptp->io_hdr.dout_resid;
- else
- *act_doutp = 0;
+ if (ptp->io_hdr.dout_xfer_len > 0)
+ *act_doutp = ptp->io_hdr.dout_xfer_len - ptp->io_hdr.dout_resid;
+ else
+ *act_doutp = 0;
}
}
@@ -786,7 +847,18 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
{
const struct sg_pt_linux_scsi * ptp = &vp->impl;
- return ptp->io_hdr.duration;
+ return sg_duration_set_nano ? (ptp->io_hdr.duration / 1000) :
+ ptp->io_hdr.duration;
+}
+
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t
+get_pt_duration_ns(const struct sg_pt_base * vp)
+{
+ const struct sg_pt_linux_scsi * ptp = &vp->impl;
+
+ return sg_duration_set_nano ? (uint32_t)ptp->io_hdr.duration : 0;
}
int
diff --git a/lib/sg_pt_osf1.c b/lib/sg_pt_osf1.c
index 3114a8b1..18ba5287 100644
--- a/lib/sg_pt_osf1.c
+++ b/lib/sg_pt_osf1.c
@@ -539,6 +539,14 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
return -1;
}
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t
+get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
+{
+ return 0;
+}
+
int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)
{
diff --git a/lib/sg_pt_solaris.c b/lib/sg_pt_solaris.c
index e8d71dc6..3d0cb228 100644
--- a/lib/sg_pt_solaris.c
+++ b/lib/sg_pt_solaris.c
@@ -413,6 +413,14 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
return -1; /* not available */
}
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t
+get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
+{
+ return 0;
+}
+
int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)
{
diff --git a/lib/sg_pt_win32.c b/lib/sg_pt_win32.c
index e357ff22..65e3f2b9 100644
--- a/lib/sg_pt_win32.c
+++ b/lib/sg_pt_win32.c
@@ -1360,6 +1360,14 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
return -1;
}
+/* If not available return 0 otherwise return number of nanoseconds that the
+ * lower layers (and hardware) took to execute the command just completed. */
+uint64_t
+get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
+{
+ return 0;
+}
+
int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)
{
diff --git a/src/sg_raw.c b/src/sg_raw.c
index 33a85f7c..00a58e0f 100644
--- a/src/sg_raw.c
+++ b/src/sg_raw.c
@@ -1,7 +1,7 @@
/*
* A utility program originally written for the Linux OS SCSI subsystem.
*
- * Copyright (C) 2000-2018 Ingo van Lil <inguin@gmx.de>
+ * Copyright (C) 2000-2019 Ingo van Lil <inguin@gmx.de>
*
* 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
@@ -39,7 +39,7 @@
#include "sg_pr2serr.h"
#include "sg_unaligned.h"
-#define SG_RAW_VERSION "0.4.28 (2018-12-20)"
+#define SG_RAW_VERSION "0.4.29 (2019-01-24)"
#define DEFAULT_TIMEOUT 20
#define MIN_SCSI_CDBSZ 6
@@ -575,7 +575,7 @@ fetch_dataout(struct opts_t * op, uint8_t ** free_buf, int * errp)
}
tot_len = op->dataout_len;
- buf = sg_memalign(tot_len, 0 /* page_size */, free_buf, op->verbose > 3);
+ buf = sg_memalign(tot_len, 0 /* page_size */, free_buf, false);
if (buf == NULL) {
pr2serr("sg_memalign: failed to get %d bytes of memory\n", tot_len);
if (errp)
@@ -748,8 +748,7 @@ main(int argc, char *argv[])
if (op->do_datain) {
uint32_t din_len = op->datain_len;
- dinp = sg_memalign(din_len, 0 /* page_size */, &wrkBuf,
- op->verbose > 3);
+ dinp = sg_memalign(din_len, 0 /* page_size */, &wrkBuf, false);
if (dinp == NULL) {
pr2serr("sg_memalign: failed to get %d bytes of memory\n",
din_len);
diff --git a/src/sg_write_same.c b/src/sg_write_same.c
index a1721c41..f50647db 100644
--- a/src/sg_write_same.c
+++ b/src/sg_write_same.c
@@ -33,7 +33,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.27 20190113";
+static const char * version_str = "1.28 20190124";
#define ME "sg_write_same: "
@@ -584,7 +584,7 @@ main(int argc, char * argv[])
ret = SG_LIB_SYNTAX_ERROR;
goto err_out;
}
- wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, vb > 3);
+ wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, false);
if (NULL == wBuff) {
pr2serr("unable to allocate %d bytes of memory with "
"sg_memalign()\n", op->xfer_len);
diff --git a/testing/sg_queue_tst.c b/testing/sg_queue_tst.c
index 064d3885..f7754fae 100644
--- a/testing/sg_queue_tst.c
+++ b/testing/sg_queue_tst.c
@@ -15,7 +15,7 @@
* Invocation: sg_queue_tst [-l=Q_LEN] [-t] <sg_device>
* -t queue at tail
*
- * Version 0.95 (20190111)
+ * Version 0.96 (20190128)
*/
#include <unistd.h>
@@ -84,8 +84,8 @@ set_nanosecs(int sg_fd)
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
diff --git a/testing/sg_tst_async.cpp b/testing/sg_tst_async.cpp
index 9c34b7a3..ab133348 100644
--- a/testing/sg_tst_async.cpp
+++ b/testing/sg_tst_async.cpp
@@ -88,7 +88,7 @@
#include "sg_pt.h"
#include "sg_cmds.h"
-static const char * version_str = "1.24 20190104";
+static const char * version_str = "1.25 20190128";
static const char * util_name = "sg_tst_async";
/* This is a test program for checking the async usage of the Linux sg
@@ -935,8 +935,8 @@ work_thread(int id, struct opts_t * op)
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n",
@@ -944,8 +944,8 @@ work_thread(int id, struct opts_t * op)
}
if (! (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags)) {
memset(seip, 0, sizeof(*seip));
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0)
diff --git a/testing/sg_tst_bidi.c b/testing/sg_tst_bidi.c
index fd5d00c0..624266cc 100644
--- a/testing/sg_tst_bidi.c
+++ b/testing/sg_tst_bidi.c
@@ -53,7 +53,7 @@
is implemented by the scsi_debug driver is used. */
-static const char * version_str = "Version: 1.03 20190122";
+static const char * version_str = "Version: 1.04 20190128";
#define INQ_REPLY_LEN 96
#define INQ_CMD_OP 0x12
@@ -130,11 +130,11 @@ ext_ioctl(int sg_fd, bool nanosecs)
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_RESERVED_SIZE;
+ seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE;
seip->reserved_sz = reserve_buff_sz;
- seip->valid_rd_mask |= SG_SEIM_RESERVED_SIZE;
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
+ seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE;
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
if (nanosecs)
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index c030889e..cdca282c 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -53,7 +53,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 1.03 20190123";
+static const char * version_str = "Version: 1.03 20190128";
#define INQ_REPLY_LEN 96
#define INQ_CMD_LEN 6
@@ -221,16 +221,15 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_RESERVED_SIZE;
+ seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE;
seip->reserved_sz = reserve_buff_sz;
seip->sgat_elem_sz = 64 * 1024;
- seip->valid_rd_mask |= SG_SEIM_RESERVED_SIZE;
- seip->valid_rd_mask |= SG_SEIM_RQ_REM_THRESH;
- seip->valid_rd_mask |= SG_SEIM_TOT_FD_THRESH;
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
- seip->valid_rd_mask |= SG_SEIM_MINOR_INDEX;
- seip->valid_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
+ seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE;
+ seip->sei_rd_mask |= SG_SEIM_TOT_FD_THRESH;
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
+ seip->sei_rd_mask |= SG_SEIM_MINOR_INDEX;
+ seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_OTHER_OPENS;
@@ -251,16 +250,14 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
}
#if 1
printf("%sSG_SET_GET_EXTENDED ioctl ok\n", cp);
- if (SG_SEIM_RESERVED_SIZE & seip->valid_rd_mask)
+ if (SG_SEIM_RESERVED_SIZE & seip->sei_rd_mask)
printf(" %sreserved size: %u\n", cp, seip->reserved_sz);
- if (SG_SEIM_MINOR_INDEX & seip->valid_rd_mask)
+ if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask)
printf(" %sminor index: %u\n", cp, seip->minor_index);
- if (SG_SEIM_RQ_REM_THRESH & seip->valid_rd_mask)
- printf(" %srq_rem_sgat_thresh: %u\n", cp, seip->rq_rem_sgat_thresh);
- if (SG_SEIM_TOT_FD_THRESH & seip->valid_rd_mask)
+ if (SG_SEIM_TOT_FD_THRESH & seip->sei_rd_mask)
printf(" %stot_fd_thresh: %u\n", cp, seip->tot_fd_thresh);
- if ((SG_SEIM_CTL_FLAGS & seip->valid_rd_mask) ||
- (SG_SEIM_CTL_FLAGS & seip->valid_wr_mask)) {
+ if ((SG_SEIM_CTL_FLAGS & seip->sei_rd_mask) ||
+ (SG_SEIM_CTL_FLAGS & seip->sei_wr_mask)) {
cflags = seip->ctl_flags;
if (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags_rd_mask)
printf(" %sTIME_IN_NS: %s\n", cp,
@@ -293,14 +290,14 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sCHECK_FOR_MORE: %s\n", cp,
(SG_CTL_FLAGM_CHECK_FOR_MORE & cflags) ? "true" : "false");
}
- if (SG_SEIM_MINOR_INDEX & seip->valid_rd_mask)
+ if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask)
printf(" %sminor_index: %u\n", cp, seip->minor_index);
printf("\n");
#endif
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_READ_VAL;
- seip->valid_rd_mask |= SG_SEIM_READ_VAL;
+ seip->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
seip->read_value = SG_SEIRV_INT_MASK;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -310,8 +307,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_INT_MASK]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
seip->read_value = SG_SEIRV_BOOL_MASK;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -321,8 +318,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_BOOL_MASK]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
seip->read_value = SG_SEIRV_VERS_NUM;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -332,8 +329,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_VERS_NUM]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
seip->read_value = SG_SEIRV_FL_RQS;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -343,8 +340,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_FL_RQS]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_rd_mask |= SG_SEIM_READ_VAL;
seip->read_value = SG_SEIRV_DEV_FL_RQS;
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
@@ -354,8 +351,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_DEV_FL_RQS]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_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,
@@ -365,8 +362,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_TRC_SZ]= %u\n", cp, 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->sei_wr_mask |= SG_SEIM_READ_VAL;
+ seip->sei_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,
@@ -376,8 +373,8 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
printf(" %sread_value[SG_SEIRV_TRC_MAX_SZ]= %u\n", cp, seip->read_value);
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_SHARE_FD;
- seip->valid_rd_mask |= SG_SEIM_SHARE_FD;
+ seip->sei_wr_mask |= SG_SEIM_SHARE_FD;
+ seip->sei_rd_mask |= SG_SEIM_SHARE_FD;
#if 1
seip->share_fd = sg_fd2;
#else
@@ -389,7 +386,7 @@ tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
pr2serr("%sioctl(SG_SET_GET_EXTENDED) shared_fd=%d, failed errno=%d "
"%s\n", cp, sg_fd2, errno, strerror(errno));
}
- printf(" %sshare successful, read back shared_fd= %d\n", cp,
+ printf(" %sshare successful, read back previous shared_fd= %d\n", cp,
(int)seip->share_fd);
bypass_share:
@@ -440,6 +437,8 @@ bypass_share:
return 0;
}
+#include <linux/fs.h>
+#include <linux/blktrace_api.h>
int
main(int argc, char * argv[])
@@ -462,6 +461,10 @@ main(int argc, char * argv[])
const char * cp;
struct sg_scsi_id ssi;
+
+ if (sizeof(struct sg_extended_info) != 96)
+ pr2serr("Warning <<<< sizeof(struct sg_extended_info)=%zu not 96\n",
+ sizeof(struct sg_extended_info));
for (k = 1; k < argc; ++k) {
if (0 == memcmp("-f", argv[k], 2))
do_fork = true;
diff --git a/testing/sgh_dd.c b/testing/sgh_dd.c
index 6d0ae7a7..1c78eba8 100644
--- a/testing/sgh_dd.c
+++ b/testing/sgh_dd.c
@@ -46,9 +46,11 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <stdatomic.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
+#include <poll.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
@@ -87,7 +89,7 @@
#else
#define __user
-#endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
+#endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -96,7 +98,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.14 20190107";
+static const char * version_str = "1.17 20190130";
#ifdef __GNUC__
#ifndef __clang__
@@ -177,6 +179,7 @@ typedef struct global_collection
int out2fd;
int out2_type;
int cdbsz_out;
+ int aen; /* abort every nth command */
struct flags_t out_flags;
int64_t out_blk; /* -\ next block address to write */
int64_t out_count; /* | blocks remaining for next write */
@@ -223,6 +226,9 @@ typedef struct request_element
int resid;
int cdbsz_in;
int cdbsz_out;
+ int aen;
+ int rep_count;
+ int rq_id;
int mmap_len;
struct flags_t in_flags;
struct flags_t out_flags;
@@ -236,6 +242,8 @@ typedef struct thread_info
pthread_t a_pthr;
} Thread_info;
+static atomic_int mono_pack_id;
+
static sigset_t signal_set;
static pthread_t sig_listen_thread_id;
@@ -509,13 +517,13 @@ usage(int pg_num)
" [obs=BS] [of=OFILE] [oflag=FLAGS] "
"[seek=SEEK] [skip=SKIP]\n"
" [--help] [--version]\n\n");
- pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] "
- "[deb=VERB] [dio=0|1]\n"
- " [elemsz_kb=ESK] [fua=0|1|2|3] [of2=OFILE2] "
- "[ofreg=OFREG]\n"
- " [sync=0|1] [thr=THR] [time=0|1] [verbose=VERB] "
- "[--dry-run]\n"
- " [--verbose]\n\n"
+ pr2serr(" [ae=AEN] [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] "
+ "[deb=VERB]\n"
+ " [dio=0|1] [elemsz_kb=ESK] [fua=0|1|2|3] "
+ "[of2=OFILE2]\n"
+ " [ofreg=OFREG] [sync=0|1] [thr=THR] [time=0|1] "
+ "[verbose=VERB]\n"
+ " [--dry-run] [--verbose]\n\n"
" where the main options (shown in first group above) are:\n"
" bs must be device logical block size (default "
"512)\n"
@@ -549,10 +557,12 @@ usage(int pg_num)
page2:
pr2serr("Syntax: sgh_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"
+ "'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"
+ " ae abort every n commands (def: 0 --> don't abort "
+ "any)\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), "
@@ -734,8 +744,8 @@ sg_share_prepare(int slave_wr_fd, int master_rd_fd, int id, bool vb_b)
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_SHARE_FD;
- seip->valid_rd_mask |= SG_SEIM_SHARE_FD;
+ seip->sei_wr_mask |= SG_SEIM_SHARE_FD;
+ seip->sei_rd_mask |= SG_SEIM_SHARE_FD;
seip->share_fd = master_rd_fd;
if (ioctl(slave_wr_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed "
@@ -815,6 +825,8 @@ read_write_thread(void * v_tip)
rep->cdbsz_out = clp->cdbsz_out;
rep->in_flags = clp->in_flags;
rep->out_flags = clp->out_flags;
+ rep->aen = clp->aen;
+ rep->rep_count = 0;
if (rep->in_flags.same_fds || rep->out_flags.same_fds)
; /* we are sharing a single pair of fd_s across all threads */
@@ -905,6 +917,7 @@ read_write_thread(void * v_tip)
if (0 != status) err_exit(status, "unlock in_mutex");
}
pthread_cleanup_pop(0);
+ ++rep->rep_count;
/* Start of WRITE part of a segment */
rep->wr = true;
@@ -968,11 +981,13 @@ skip_force_out_sequence:
clp->out_rem_count -= blocks;
status = pthread_mutex_unlock(&clp->out_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
+ --rep->rep_count;
} else {
normal_out_wr(clp, rep, blocks);
status = pthread_mutex_unlock(&clp->out_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
}
+ ++rep->rep_count;
pthread_cleanup_pop(0);
/* Output to OFILE2 if sg device */
@@ -990,6 +1005,14 @@ skip_force_out_sequence:
break;
} /* end of while loop which copies segments */
+ status = pthread_mutex_lock(&clp->in_mutex);
+ if (0 != status) err_exit(status, "lock in_mutex");
+ if (! clp->in_stop)
+ clp->in_stop = true; /* flag other workers to stop */
+ status = pthread_mutex_unlock(&clp->in_mutex);
+ if (0 != status) err_exit(status, "unlock in_mutex");
+
+fini:
if (rep->mmap_len > 0) {
if (munmap(rep->buffp, rep->mmap_len) < 0) {
int err = errno;
@@ -1001,18 +1024,11 @@ skip_force_out_sequence:
} else if (rep->alloc_bp)
free(rep->alloc_bp);
- status = pthread_mutex_lock(&clp->in_mutex);
- if (0 != status) err_exit(status, "lock in_mutex");
- if (! clp->in_stop)
- clp->in_stop = true; /* flag other workers to stop */
- status = pthread_mutex_unlock(&clp->in_mutex);
- if (0 != status) err_exit(status, "unlock in_mutex");
-fini:
- if (own_infd)
+ if (own_infd && (rep->infd >= 0))
close(rep->infd);
- if (own_outfd)
+ if (own_outfd && (rep->outfd >= 0))
close(rep->outfd);
- if (own_out2fd)
+ if (own_out2fd && (rep->out2fd >= 0))
close(rep->out2fd);
pthread_cond_broadcast(&clp->out_sync_cv);
return stop_after_write ? NULL : clp;
@@ -1257,13 +1273,13 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before)
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_CHG_SHARE_FD;
- seip->valid_rd_mask |= SG_SEIM_CHG_SHARE_FD;
+ seip->sei_wr_mask |= SG_SEIM_CHG_SHARE_FD;
+ seip->sei_rd_mask |= SG_SEIM_CHG_SHARE_FD;
seip->share_fd = to_fd;
if (before) {
/* clear MASTER_FINI bit to put master in SG_RQ_SHR_SWAP state */
- seip->valid_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->valid_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MASTER_FINI;
seip->ctl_flags &= SG_CTL_FLAGM_MASTER_FINI;/* would be 0 anyway */
}
@@ -1425,10 +1441,11 @@ sg_start_io(Rq_elem * rep, bool is_wr2)
cp = (wr ? " slave active" : " master active");
} else
cp = (wr ? " slave not sharing" : " master not sharing");
+ rep->rq_id = atomic_fetch_add(&mono_pack_id, 1);
if (rep->debug > 3) {
- pr2serr_lk("%s tid=%d: SCSI %s%s%s%s, blk=%" PRId64 " num_blks=%d\n",
- __func__, rep->id, crwp, cp, c2p, c3p, rep->blk,
- rep->num_blks);
+ pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s%s%s, blk=%" PRId64
+ " num_blks=%d\n", __func__, rep->id, rep->rq_id, crwp, cp,
+ c2p, c3p, rep->blk, rep->num_blks);
lk_print_command(rep->cmd);
}
if (v4)
@@ -1445,7 +1462,7 @@ sg_start_io(Rq_elem * rep, bool is_wr2)
hp->sbp = rep->sb;
hp->timeout = DEF_TIMEOUT;
hp->usr_ptr = rep;
- hp->pack_id = (int)rep->blk;
+ hp->pack_id = rep->rq_id;
hp->flags = flags;
while (((res = write(fd, hp, sizeof(struct sg_io_hdr))) < 0) &&
@@ -1476,7 +1493,7 @@ do_v4:
h4p->response = (uint64_t)rep->sb;
h4p->timeout = DEF_TIMEOUT;
h4p->usr_ptr = (uint64_t)rep;
- h4p->request_extra = rep->blk;/* N.B. blk --> pack_id --> request_extra */
+ h4p->request_extra = rep->rq_id; /* this is the pack_id */
h4p->flags = flags;
while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) &&
((EINTR == errno) || (EAGAIN == errno)))
@@ -1489,6 +1506,28 @@ do_v4:
rep->id, cp, c2p, c3p, strerror(err));
return -1;
}
+ if ((rep->aen > 0) && (rep->rep_count > 0)) {
+ if (0 == (rep->rq_id % rep->aen)) {
+ struct pollfd a_poll;
+
+ a_poll.fd = fd;
+ a_poll.events = POLL_IN;
+ a_poll.revents = 0;
+ res = poll(&a_poll, 1 /* element */, 1 /* millisecond */);
+ if (res < 0)
+ pr2serr_lk("%s: poll() failed: %s [%d]\n",
+ __func__, safe_strerror(errno), errno);
+ else if (0 == res) { /* timeout, cmd still inflight, so abort */
+ res = ioctl(fd, SG_IOABORT, h4p);
+ if (res < 0)
+ pr2serr_lk("%s: ioctl(SG_IOABORT) failed: %s [%d]\n",
+ __func__, safe_strerror(errno), errno);
+ else if (rep->debug > 3)
+ pr2serr_lk("%s: sending ioctl(SG_IOABORT) on rq_id=%d\n",
+ __func__, rep->rq_id);
+ } /* else got response, too late for timeout, so skip */
+ }
+ }
return 0;
}
@@ -1521,7 +1560,7 @@ sg_finish_io(bool wr, Rq_elem * rep, bool is_wr2)
/* FORCE_PACK_ID active set only read packet with matching pack_id */
io_hdr.interface_id = 'S';
io_hdr.dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
- io_hdr.pack_id = (int)rep->blk;
+ io_hdr.pack_id = rep->rq_id;
while (((res = read(fd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) &&
((EINTR == errno) || (EAGAIN == errno)))
@@ -1601,8 +1640,17 @@ do_v4:
{
char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, cp, rep->blk);
+ snprintf(ebuff, EBUFF_SZ, "%s rq_id=%d, blk=%" PRId64, cp,
+ rep->rq_id, rep->blk);
lk_chk_n_print4(ebuff, h4p, false);
+ if ((rep->debug > 4) && h4p->info)
+ pr2serr_lk(" info=0x%x sg_info_check=%d another_waiting=%d "
+ "direct=%d detaching=%d aborted=%d\n", h4p->info,
+ !!(h4p->info & SG_INFO_CHECK),
+ !!(h4p->info & SG_INFO_ANOTHER_WAITING),
+ !!(h4p->info & SG_INFO_DIRECT_IO),
+ !!(h4p->info & SG_INFO_DEVICE_DETACHING),
+ !!(h4p->info & SG_INFO_ABORTED));
return res;
}
}
@@ -1616,14 +1664,16 @@ do_v4:
rep->dio_incomplete_count = 0;
rep->resid = h4p->din_resid;
if (rep->debug > 3) {
- pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, cp);
- if (rep->debug > 4)
+ pr2serr_lk("%s: tid,rq_id=%d,%d: completed %s\n", __func__, rep->id,
+ rep->rq_id, cp);
+ if ((rep->debug > 4) && h4p->info)
pr2serr_lk(" info=0x%x sg_info_check=%d another_waiting=%d "
- "direct=%d detaching=%d\n", h4p->info,
+ "direct=%d detaching=%d aborted=%d\n", h4p->info,
!!(h4p->info & SG_INFO_CHECK),
!!(h4p->info & SG_INFO_ANOTHER_WAITING),
!!(h4p->info & SG_INFO_DIRECT_IO),
- !!(h4p->info & SG_INFO_DEVICE_DETACHING));
+ !!(h4p->info & SG_INFO_DEVICE_DETACHING),
+ !!(h4p->info & SG_INFO_ABORTED));
}
return 0;
}
@@ -1647,14 +1697,14 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
seip = &sei;
memset(seip, 0, sizeof(*seip));
- seip->valid_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
+ seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd "
"error: %s\n", __func__, strerror(errno));
if (elem_sz != (int)seip->sgat_elem_sz) {
memset(seip, 0, sizeof(*seip));
- seip->valid_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
+ seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
seip->sgat_elem_sz = elem_sz;
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
@@ -1882,27 +1932,34 @@ main(int argc, char * argv[])
if (*buf)
*buf++ = '\0';
keylen = strlen(key);
- if (0 == strcmp(key,"bpt")) {
+ if (0 == strcmp(key, "ae")) {
+ clp->aen = sg_get_num(buf);
+ if (clp->aen < 0) {
+ pr2serr("%sbad argument to 'ae=', want 0 or higher\n",
+ my_name);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strcmp(key, "bpt")) {
clp->bpt = sg_get_num(buf);
if (-1 == clp->bpt) {
pr2serr("%sbad argument to 'bpt='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
bpt_given = true;
- } else if (0 == strcmp(key,"bs")) {
+ } else if (0 == strcmp(key, "bs")) {
clp->bs = sg_get_num(buf);
if (-1 == clp->bs) {
pr2serr("%sbad argument to 'bs='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"cdbsz")) {
+ } else if (0 == strcmp(key, "cdbsz")) {
clp->cdbsz_in = sg_get_num(buf);
clp->cdbsz_out = clp->cdbsz_in;
cdbsz_given = true;
- } else if (0 == strcmp(key,"coe")) {
+ } else if (0 == strcmp(key, "coe")) {
clp->in_flags.coe = !! sg_get_num(buf);
clp->out_flags.coe = clp->in_flags.coe;
- } else if (0 == strcmp(key,"count")) {
+ } else if (0 == strcmp(key, "count")) {
if (0 != strcmp("-1", buf)) {
dd_count = sg_get_llnum(buf);
if (-1LL == dd_count) {
@@ -1910,32 +1967,32 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
} /* treat 'count=-1' as calculate count (same as not given) */
- } else if ((0 == strncmp(key,"deb", 3)) ||
- (0 == strncmp(key,"verb", 4)))
+ } else if ((0 == strncmp(key, "deb", 3)) ||
+ (0 == strncmp(key, "verb", 4)))
clp->debug = sg_get_num(buf);
- else if (0 == strcmp(key,"dio")) {
+ else if (0 == strcmp(key, "dio")) {
clp->in_flags.dio = !! sg_get_num(buf);
clp->out_flags.dio = clp->in_flags.dio;
- } else if (0 == strcmp(key,"elemsz_kb")) {
+ } else if (0 == strcmp(key, "elemsz_kb")) {
clp->elem_sz = sg_get_num(buf) * 1024;
if ((clp->elem_sz > 0) && (clp->elem_sz < 4096)) {
pr2serr("elemsz_kb cannot be less than 4 (4 KB = 4096 "
"bytes)\n");
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"fua")) {
+ } else if (0 == strcmp(key, "fua")) {
n = sg_get_num(buf);
if (n & 1)
clp->out_flags.fua = true;
if (n & 2)
clp->in_flags.fua = true;
- } else if (0 == strcmp(key,"ibs")) {
+ } else if (0 == strcmp(key, "ibs")) {
ibs = sg_get_num(buf);
if (-1 == ibs) {
pr2serr("%sbad argument to 'ibs='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (strcmp(key,"if") == 0) {
+ } else if (0 == strcmp(key, "if")) {
if ('\0' != inf[0]) {
pr2serr("Second 'if=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
@@ -1946,25 +2003,25 @@ main(int argc, char * argv[])
pr2serr("%sbad argument to 'iflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"obs")) {
+ } else if (0 == strcmp(key, "obs")) {
obs = sg_get_num(buf);
if (-1 == obs) {
pr2serr("%sbad argument to 'obs='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (strcmp(key,"of2") == 0) {
+ } 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,"ofreg") == 0) {
+ } else if (strcmp(key, "ofreg") == 0) {
if ('\0' != outregf[0]) {
pr2serr("Second OFREG argument??\n");
return SG_LIB_CONTRADICT;
} else
strncpy(outregf, buf, INOUTF_SZ - 1);
- } else if (strcmp(key,"of") == 0) {
+ } else if (strcmp(key, "of") == 0) {
if ('\0' != outf[0]) {
pr2serr("Second 'of=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
@@ -1975,23 +2032,23 @@ main(int argc, char * argv[])
pr2serr("%sbad argument to 'oflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"seek")) {
+ } else if (0 == strcmp(key, "seek")) {
seek = sg_get_llnum(buf);
if (-1LL == seek) {
pr2serr("%sbad argument to 'seek='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"skip")) {
+ } else if (0 == strcmp(key, "skip")) {
skip = sg_get_llnum(buf);
if (-1LL == skip) {
pr2serr("%sbad argument to 'skip='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"sync"))
+ } else if (0 == strcmp(key, "sync"))
do_sync = !! sg_get_num(buf);
- else if (0 == strcmp(key,"thr"))
+ else if (0 == strcmp(key, "thr"))
num_threads = sg_get_num(buf);
- else if (0 == strcmp(key,"time"))
+ else if (0 == strcmp(key, "time"))
do_time = !! sg_get_num(buf);
else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
res = 0;
@@ -2342,7 +2399,8 @@ main(int argc, char * argv[])
clp->outregfd = -1;
if ((STDIN_FILENO == clp->infd) && (STDOUT_FILENO == clp->outfd)) {
- pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n");
+ pr2serr("Won't default both IFILE to stdin _and_ OFILE to "
+ "/dev/null\n");
pr2serr("For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -2560,13 +2618,16 @@ main(int argc, char * argv[])
fini:
- if (STDIN_FILENO != clp->infd)
+ if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0))
close(clp->infd);
- if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type))
+ if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type) &&
+ (clp->outfd >= 0))
close(clp->outfd);
- if ((STDOUT_FILENO != clp->out2fd) && (FT_DEV_NULL != clp->out2_type))
+ if ((clp->out2fd >= 0) && (STDOUT_FILENO != clp->out2fd) &&
+ (FT_DEV_NULL != clp->out2_type))
close(clp->out2fd);
- if ((STDOUT_FILENO != clp->outregfd) && (FT_DEV_NULL != clp->outreg_type))
+ if ((clp->outregfd >= 0) && (STDOUT_FILENO != clp->outregfd) &&
+ (FT_DEV_NULL != clp->outreg_type))
close(clp->outregfd);
res = exit_status;
if ((0 != clp->out_count) && (0 == clp->dry_run)) {
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index d6f366af..cfb0044b 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -14,8 +14,8 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version 4.0.03 (20181227)
- * This version is for Linux 2.6, 3 and 4 series kernels.
+ * Version 4.0.05 (20190126)
+ * This version is for Linux 2.6, 3, 4 and 5 series kernels.
*
* Documentation
* =============
@@ -128,6 +128,7 @@ typedef struct sg_io_hdr {
#define SG_INFO_MIXED_IO 0x4 /* not used, always 0 */
#define SG_INFO_DEVICE_DETACHING 0x8 /* completed successfully but ... */
#define SG_INFO_ANOTHER_WAITING 0x10 /* needs SG_CTL_FLAGM_CHECK_FOR_MORE */
+#define SG_INFO_ABORTED 0x20 /* this command has been aborted */
typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
@@ -164,25 +165,24 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
/*
* The following defines are for manipulating struct sg_extended_info which
* is abbreviated to "SEI". A following "M" (i.e. "_SEIM_") indicates a
- * mask. Most mask values correspond to a integer (usually a __u32) apart
+ * mask. Most mask values correspond to a integer (usually a uint32_t) apart
* from SG_SEIM_CTL_FLAGS which is for boolean values packed into an integer.
* The mask values for those booleans start with "SG_CTL_FLAGM_". The scope
* of these settings, like most other ioctls, is usually that of the file
* descriptor the ioctl is executed on. The "rd:" indication means read-only,
* attempts to write to them are ignored. "rd>" means action when reading.
*/
-#define SG_SEIM_RESERVED_SIZE 0x1 /* reserved_sz field valid */
-#define SG_SEIM_RQ_REM_THRESH 0x2 /* rq_rem_sgat_thresh field valid */
-#define SG_SEIM_TOT_FD_THRESH 0x4 /* tot_fd_thresh field valid */
-#define SG_SEIM_CTL_FLAGS 0x8 /* ctl_flags_mask bits in ctl_flags */
+#define SG_SEIM_CTL_FLAGS 0x1 /* ctl_flags_mask bits in ctl_flags */
+#define SG_SEIM_READ_VAL 0x2 /* write SG_SEIRV_*, read back value */
+#define SG_SEIM_RESERVED_SIZE 0x4 /* reserved_sz of reserve request */
+#define SG_SEIM_TOT_FD_THRESH 0x8 /* tot_fd_thresh of data buffers */
#define SG_SEIM_MINOR_INDEX 0x10 /* sg device minor index number */
-#define SG_SEIM_READ_VAL 0x20 /* write SG_SEIRV_*, read back value */
-#define SG_SEIM_SHARE_FD 0x40 /* slave gives fd of master, sharing */
+#define SG_SEIM_SHARE_FD 0x20 /* slave gives fd of master: sharing */
+#define SG_SEIM_CHG_SHARE_FD 0x40 /* master gives fd of new slave */
#define SG_SEIM_SGAT_ELEM_SZ 0x80 /* sgat element size (>= PAGE_SIZE) */
-#define SG_SEIM_CHG_SHARE_FD 0x100 /* master gives fd of new slave */
-#define SG_SEIM_ALL_BITS 0x1ff /* should be OR of previous items */
+#define SG_SEIM_ALL_BITS 0xff /* should be OR of previous items */
-/* flag and mask values for boolena fields follow */
+/* flag and mask values for boolean fields follow */
#define SG_CTL_FLAGM_TIME_IN_NS 0x1 /* time: nanosecs (def: millisecs) */
#define SG_CTL_FLAGM_TAG_FOR_PACK_ID 0x2 /* prefer tag over pack_id (def) */
#define SG_CTL_FLAGM_OTHER_OPENS 0x4 /* rd: other sg fd_s on this dev */
@@ -218,19 +218,21 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
* setting but no other operation will split the two. This structure is
* padded to 96 bytes to allow for new values to be added in the future.
*/
+
+/* If both sei_wr_mask and sei_rd_mask are 0, this ioctl does nothing */
struct sg_extended_info {
- __u32 valid_wr_mask; /* OR-ed SG_SEIM_* user->driver values */
- __u32 valid_rd_mask; /* OR-ed SG_SEIM_* driver->user values */
- __u32 reserved_sz; /* data/sgl size of pre-allocated request */
- __u32 rq_rem_sgat_thresh;/* request re-use: clear data/sgat if > */
- __u32 tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */
+ __u32 sei_wr_mask; /* OR-ed SG_SEIM_* user->driver values */
+ __u32 sei_rd_mask; /* OR-ed SG_SEIM_* driver->user values */
__u32 ctl_flags_wr_mask; /* OR-ed SG_CTL_FLAGM_* values */
__u32 ctl_flags_rd_mask; /* OR-ed SG_CTL_FLAGM_* values */
__u32 ctl_flags; /* bit values OR-ed, see SG_CTL_FLAGM_* */
+ __u32 read_value; /* write SG_SEIRV_*, read back related */
+
+ __u32 reserved_sz; /* data/sgl size of pre-allocated request */
+ __u32 tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */
__u32 minor_index; /* rd: kernel's sg device minor number */
- __u32 read_value; /* write known value, read back related */
- __u32 share_fd; /* slave provided fd of master */
- __u32 sgat_elem_sz; /* sgat element size (must be power of 2 */
+ __u32 share_fd; /* SHARE_FD and CHG_SHARE_FD use this */
+ __u32 sgat_elem_sz; /* sgat element size (must be power of 2) */
__u8 pad_to_96[52]; /* pad so struct is 96 bytes long */
};
@@ -283,10 +285,10 @@ struct sg_extended_info {
* file descriptor (default: use pack_id). If pack_id or tag is -1 then read
* oldest waiting and this is the same action as when FORCE_PACK_ID is
* clear on the parent file descriptor. In the v4 interface the pack_id is
- * placed in sg_io_v4::request_extra field .
+ * placed the in sg_io_v4::request_extra field .
*/
#define SG_SET_FORCE_PACK_ID 0x227b /* pack_id or in v4 can be tag */
-#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
+#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id/tag, or -1 */
#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */