aboutsummaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2021-02-20 01:43:36 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2021-02-20 01:43:36 +0000
commit7d78ae6198005fcaf58a66c2db11cbfe605df439 (patch)
tree8323596b871e4dca7d35c0ad9cba07cea61d094a /testing
parent28d27daf0d8ff9ab8ee957a3f9917e2c2a23d232 (diff)
downloadsg3_utils-7d78ae6198005fcaf58a66c2db11cbfe605df439.tar.gz
testing updates, mainly sgs_dd
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@876 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-rw-r--r--testing/sg_iovec_tst.cpp13
-rw-r--r--testing/sg_mrq_dd.cpp6
-rw-r--r--testing/sgh_dd.cpp28
-rw-r--r--testing/sgs_dd.c427
4 files changed, 316 insertions, 158 deletions
diff --git a/testing/sg_iovec_tst.cpp b/testing/sg_iovec_tst.cpp
index 3199dc8d..3ee728ac 100644
--- a/testing/sg_iovec_tst.cpp
+++ b/testing/sg_iovec_tst.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2020 D. Gilbert
+ * Copyright (C) 2003-2021 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)
@@ -68,7 +68,7 @@
// C++ local header
#include "sg_scat_gath.h"
-static const char * version_str = "1.07 20201108";
+static const char * version_str = "1.08 20210214";
#define ME "sg_iovec_tst: "
@@ -114,7 +114,7 @@ usage(void)
" [--skip=SKIP] [--verbose] [--version] "
"SG_DEV OUT_F\n");
printf("where:\n"
- " --async|-a async sg use (def: use ioctl(SGIO) )\n");
+ " --async|-a async sg usage (def: use ioctl(SGIO) )\n");
printf(" --bs=BS|-b BS logical block size of SG_DEV (def: 512 "
"bytes)\n");
printf(" --elem_sz=ES|-e ES iovec element size (def: BS bytes)\n");
@@ -125,9 +125,10 @@ usage(void)
printf(" --from_skip|-F sgl output starts from SKIP (def: 0)\n");
printf(" --help|-h this usage message\n");
printf(" --num=NUM|-n NUM number of blocks to read from SG_DEV\n");
- printf(" --sgl=SFN|-S SFN Sgl FileName (SFN) that written to, with "
- "addresses\n"
- " and lengths having ES as their unit\n");
+ printf(" --sgl=SFN|-S SFN Sgl FileName (SFN) that is written to, "
+ "with\n"
+ " addresses and lengths having ES as "
+ "their unit\n");
printf(" --sgv4|-4 use the sg v4 interface (def: v3 "
"interface)\n");
printf(" --skip=SKIP|-s SKIP SKIP blocks before reading S_DEV "
diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp
index 5beb9b31..21232057 100644
--- a/testing/sg_mrq_dd.cpp
+++ b/testing/sg_mrq_dd.cpp
@@ -30,7 +30,7 @@
*
*/
-static const char * version_str = "1.19 20210208";
+static const char * version_str = "1.20 20210210";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -117,6 +117,10 @@ using namespace std;
// #endif
+#ifndef SGV4_FLAG_HIPRI
+#define SGV4_FLAG_HIPRI 0x800
+#endif
+
#define MAX_SGL_NUM_VAL (INT32_MAX - 1) /* should reduce for testing */
// #define MAX_SGL_NUM_VAL 7 /* should reduce for testing */
#if MAX_SGL_NUM_VAL > INT32_MAX
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 35358352..7c0c9ed6 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -36,7 +36,7 @@
* renamed [20181221]
*/
-static const char * version_str = "1.98 20210108";
+static const char * version_str = "1.99 20210216";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -120,6 +120,10 @@ using namespace std;
/* comment out following line to stop ioctl(SG_CTL_FLAGM_SNAP_DEV) */
#define SGH_DD_SNAP_DEV 1
+#ifndef SGV4_FLAG_HIPRI
+#define SGV4_FLAG_HIPRI 0x800
+#endif
+
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
#define DEF_BLOCKS_PER_2048TRANSFER 32
@@ -917,7 +921,7 @@ usage(int pg_num)
"[thr=THR]\n"
" [time=0|1|2[,TO]] [unshare=1|0] [verbose=VERB] "
"[--dry-run]\n"
- " [--prefetch] [--verbose] [--verify] "
+ " [--prefetch] [-v|-vv|-vvv] [--verbose] [--verify] "
"[--version]\n\n"
" where the main options (shown in first group above) are:\n"
" bs must be device logical block size (default "
@@ -1895,7 +1899,7 @@ sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks,
memset(cdbp, 0, cdb_sz);
if (ver_true) { /* only support VERIFY(10) */
if (cdb_sz < 10) {
- pr2serr_lk("%s only support VERIFY(10)\n", my_name);
+ pr2serr_lk("%sonly support VERIFY(10)\n", my_name);
return 1;
}
cdb_sz = 10;
@@ -3532,16 +3536,16 @@ sg_prepare_resbuf(int fd, bool is_in, struct global_collection *clp,
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));
+ pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd "
+ "error: %s\n", my_name, __func__, strerror(errno));
if (clp->elem_sz != (int)seip->sgat_elem_sz) {
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
seip->sgat_elem_sz = clp->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) "
- "wr error: %s\n", __func__, strerror(errno));
+ pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) wr "
+ "error: %s\n", my_name, __func__, strerror(errno));
}
}
if (no_dur || masync) {
@@ -3561,8 +3565,8 @@ sg_prepare_resbuf(int fd, bool is_in, struct global_collection *clp,
}
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
- pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(NO_DURATION) "
- "error: %s\n", __func__, strerror(errno));
+ pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(NO_DURATION) error: %s\n",
+ my_name, __func__, strerror(errno));
}
bypass:
if (! def_res) {
@@ -3591,8 +3595,8 @@ bypass:
if (MAP_FAILED == mmp) {
int err = errno;
- pr2serr_lk("sgh_dd: %s: sz=%d, fd=%d, mmap() failed: %s\n",
- __func__, num, fd, strerror(err));
+ pr2serr_lk("%s%s: sz=%d, fd=%d, mmap() failed: %s\n",
+ my_name, __func__, num, fd, strerror(err));
return 0;
}
*mmpp = mmp;
@@ -3627,7 +3631,7 @@ bypass:
t = 1;
res = ioctl(fd, SG_SET_DEBUG, &t); /* more info in /proc/scsi/sg/debug */
if (res < 0)
- perror("sgh_dd: SG_SET_DEBUG error");
+ perror("sgs_dd: SG_SET_DEBUG error");
return (res < 0) ? 0 : num;
}
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index ccae39e0..0943340a 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -1,7 +1,7 @@
/*
* Test code for the extensions to the Linux OS SCSI generic ("sg")
* device driver.
- * Copyright (C) 1999-2020 D. Gilbert and P. Allworth
+ * Copyright (C) 1999-2021 D. Gilbert and P. Allworth
*
* 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
@@ -51,6 +51,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h> /* for mmap() system call */
#include <sys/eventfd.h>
#include <sys/epoll.h>
#define __STDC_FORMAT_MACROS 1
@@ -83,14 +84,16 @@
#include "sg_unaligned.h"
-static const char * version_str = "4.15 20200916";
+static const char * version_str = "4.17 20210218";
static const char * my_name = "sgs_dd";
+#ifndef SGV4_FLAG_HIPRI
+#define SGV4_FLAG_HIPRI 0x800
+#endif
+
#define DEF_BLOCK_SIZE 512
#define DEF_BPT_TIMES_BS_SZ (64 * 1024) /* 64 KB */
-/* #define SG_DEBUG 1 comment out if not needed */
-
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define DEF_TIMEOUT 40000 /* 40,000 millisecs == 40 seconds */
#define S_RW_LEN 10 /* Use SCSI READ(10) and WRITE(10) */
@@ -109,6 +112,8 @@ static const char * my_name = "sgs_dd";
#define SGQ_CAN_WRITE 2
#define SGQ_TIMEOUT 4
+#define DEF_SIGTIMEDWAIT_USEC 100
+
#define STR_SZ 1024
#define INOUTF_SZ 900
@@ -118,6 +123,7 @@ struct flags_t {
bool dio;
bool evfd;
bool excl;
+ bool hipri;
bool immed;
bool mmap;
bool noxfer;
@@ -126,6 +132,7 @@ struct flags_t {
bool tag;
bool v3;
bool v4;
+ bool given_v3v4;
};
typedef struct request_element
@@ -153,6 +160,7 @@ typedef struct request_collection
bool out_is_sg;
bool no_sig;
bool use_rt_sig;
+ bool both_mmap;
int infd;
int in_evfd;
int in_blk; /* most recent read */
@@ -172,13 +180,16 @@ typedef struct request_collection
int sum_of_resids;
int poll_ms;
int pollerr_count;
- int debug;
+ int debug; /* also set with -v up to -vvvvv */
sigset_t blocked_sigs;
int sigs_waiting;
int sigs_rt_received;
int sigs_io_received;
+ int blk_poll_count;
Rq_elem * rd_posp;
Rq_elem * wr_posp;
+ uint8_t * in_mmapp;
+ uint8_t * out_mmapp;
struct flags_t iflag;
struct flags_t oflag;
Rq_elem elem[SGQ_NUM_ELEMS];
@@ -188,6 +199,10 @@ static bool sgs_old_sg_driver = false; /* true if VERSION_NUM < 4.00.00 */
static bool sgs_full_v4_sg_driver = false; /* set if VERSION_NUM >= 4.00.30 */
static bool sgs_nanosec_unit = false;
+static int sgq_rd_ahead_lim = SGQ_MAX_RD_AHEAD;
+static int sgq_wr_ahead_lim = SGQ_MAX_WR_AHEAD;
+static int sgq_num_elems = (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1);
+
static void
usage(int pg_num)
@@ -206,11 +221,13 @@ usage(int pg_num)
"bs=512))\n"
" bs must be the logical block size of device (def: 512)\n"
" deb debug: 0->no debug (def); > 0 -> more debug\n"
- " iflag comma separated list from: dio,evfd,excl,immed,mmap,"
- "no_waitq,\n"
- " noxfer,null,pack,tag,v3,v4 bound to IFILE\n"
- " no_sig 0-> use signals (def); 1-> no signals, hard polling "
- "instead\n"
+ " -v (up to -vvvvv) sets deb value to number of 'v's\n"
+ " iflag comma separated list from: dio,evfd,excl,hipri,immed,"
+ "mmap\n"
+ " no_waitq,noxfer,null,pack,tag,v3,v4 bound to IFILE\n"
+ " no_sig 0-> use signals; 1-> no signals, hard polling "
+ "instead;\n"
+ " default 0, unless hipri flag(s) given then it's 1\n"
" oflag same flags as iflag but bound to OFILE\n"
" poll_ms number of milliseconds to wait on poll (def: 0)\n"
" rt_sig 0->use SIGIO (def); 1->use RT sig (SIGRTMIN + 1)\n"
@@ -218,7 +235,7 @@ usage(int pg_num)
printf("dd clone for testing Linux sg driver SIGPOLL and/or polling. "
"Either\nIFILE or OFILE must be a scsi generic device. If OFILE "
"not given then\n/dev/null assumed (rather than stdout like "
- "dd). Use '-hh' or '-hhh'\nfor more information.\n");
+ "dd). Use '-hh' for flag\ninformation.\n");
return;
second_page:
printf("flag description:\n"
@@ -226,6 +243,7 @@ second_page:
" evfd when poll() gives POLLIN, use eventfd to find "
"out how many\n"
" excl open IFILE or OFILE with O_EXCL\n"
+ " hipri set HIPRI flag and use blk_poll() for completion\n"
" immed use SGV4_FLAG_IMMED flag on each request\n"
" mmap use mmap()-ed IO on IFILE or OFILE\n"
" no_waitq use SGV4_FLAG_NO_WAIQ flag on each request\n"
@@ -240,6 +258,26 @@ second_page:
" v4 use sg vr interface (i.e. struct sg_io_v4)\n");
}
+static int
+get_mmap_addr(int fd, int num, uint8_t ** mmpp)
+{
+ uint8_t * mmp;
+
+ if (! mmpp)
+ return -EINVAL;
+ mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (MAP_FAILED == mmp) {
+ int err = errno;
+
+ pr2serr("%s%s: sz=%d, fd=%d, mmap() failed: %s\n",
+ my_name, __func__, num, fd, strerror(err));
+ return -err;
+ }
+ *mmpp = mmp;
+ return 0;
+}
+
/* Return of 0 -> success, -1 -> failure, 2 -> try again */
static int
read_capacity(int sg_fd, int * num_sect, int * sect_sz)
@@ -273,13 +311,8 @@ read_capacity(int sg_fd, int * num_sect, int * sect_sz)
sg_chk_n_print3("read capacity", &io_hdr, true);
return -1;
}
- *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) |
- (rcBuff[2] << 8) | rcBuff[3]);
- *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
- (rcBuff[6] << 8) | rcBuff[7];
-#ifdef SG_DEBUG
- pr2serr("number of sectors=%d, sector size=%d\n", *num_sect, *sect_sz);
-#endif
+ *num_sect = sg_get_unaligned_be32(rcBuff + 0) + 1;
+ *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
return 0;
}
@@ -287,14 +320,18 @@ read_capacity(int sg_fd, int * num_sect, int * sect_sz)
static int
sg_start_io(Rq_coll * clp, Rq_elem * rep)
{
+ bool is_wr = rep->wr;
int res;
- int fd = rep->wr ? clp->outfd : clp->infd;
- struct flags_t * flagp = rep->wr ? rep->oflagp : rep->iflagp;
+ int fd = is_wr ? clp->outfd : clp->infd;
+ int num_bytes = clp->bs * rep->num_blks;
+ struct flags_t * flagp = is_wr ? rep->oflagp : rep->iflagp;
sg_io_hdr_t * hp = &rep->io_hdr;
struct sg_io_v4 * h4p = &rep->io_v4;
+ if (clp->both_mmap && is_wr)
+ memcpy(clp->out_mmapp, clp->in_mmapp, num_bytes);
memset(rep->cmd, 0, sizeof(rep->cmd));
- rep->cmd[0] = rep->wr ? 0x2a : 0x28;
+ rep->cmd[0] = is_wr ? 0x2a : 0x28;
sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2);
sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7);
if (flagp->v4)
@@ -304,9 +341,8 @@ sg_start_io(Rq_coll * clp, Rq_elem * rep)
hp->interface_id = 'S';
hp->cmd_len = sizeof(rep->cmd);
hp->cmdp = rep->cmd;
- hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
- hp->dxfer_len = clp->bs * rep->num_blks;
- hp->dxferp = rep->buffp;
+ hp->dxfer_direction = is_wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
+ hp->dxfer_len = num_bytes;
hp->mx_sb_len = sizeof(rep->sb);
hp->sbp = rep->sb;
hp->timeout = DEF_TIMEOUT;
@@ -314,23 +350,28 @@ sg_start_io(Rq_coll * clp, Rq_elem * rep)
hp->pack_id = rep->blk;
if (flagp->dio)
hp->flags |= SG_FLAG_DIRECT_IO;
+ if (flagp->hipri)
+ hp->flags |= SGV4_FLAG_HIPRI;
if (flagp->noxfer)
hp->flags |= SG_FLAG_NO_DXFER;
if (flagp->immed)
hp->flags |= SGV4_FLAG_IMMED;
- if (flagp->mmap)
+ if (flagp->mmap) {
hp->flags |= SG_FLAG_MMAP_IO;
+ hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp;
+ } else
+ hp->dxferp = rep->buffp;
if (flagp->evfd)
hp->flags |= SGV4_FLAG_EVENTFD;
if (flagp->no_waitq)
hp->flags |= SGV4_FLAG_NO_WAITQ;
-#ifdef SG_DEBUG
- pr2serr("%s: SCSI %s, blk=%d num_blks=%d\n", __func__,
- rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
- sg_print_command(hp->cmdp);
- pr2serr("dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_direction,
- hp->dxfer_len, hp->dxferp, hp->cmd_len);
-#endif
+ if (clp->debug > 5) {
+ pr2serr("%s: SCSI %s, blk=%d num_blks=%d\n", __func__,
+ is_wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
+ sg_print_command(hp->cmdp);
+ pr2serr("dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_direction,
+ hp->dxfer_len, hp->dxferp, hp->cmd_len);
+ }
while (((res = write(fd, hp, sizeof(sg_io_hdr_t))) < 0) &&
(EINTR == errno))
@@ -355,13 +396,10 @@ do_v4:
h4p->guard = 'Q';
h4p->request_len = sizeof(rep->cmd);
h4p->request = (uint64_t)(uintptr_t)rep->cmd;
- if (rep->wr) {
- h4p->dout_xfer_len = clp->bs * rep->num_blks;
- h4p->dout_xferp = (uint64_t)(uintptr_t)rep->buffp;
- } else if (rep->num_blks > 0) {
- h4p->din_xfer_len = clp->bs * rep->num_blks;
- h4p->din_xferp = (uint64_t)(uintptr_t)rep->buffp;
- }
+ if (is_wr)
+ h4p->dout_xfer_len = num_bytes;
+ else if (rep->num_blks > 0)
+ h4p->din_xfer_len = num_bytes;
h4p->max_response_len = sizeof(rep->sb);
h4p->response = (uint64_t)(uintptr_t)rep->sb;
h4p->timeout = DEF_TIMEOUT;
@@ -371,10 +409,19 @@ do_v4:
h4p->flags |= SG_FLAG_DIRECT_IO;
if (flagp->noxfer)
h4p->flags |= SG_FLAG_NO_DXFER;
+ if (flagp->hipri)
+ h4p->flags |= SGV4_FLAG_HIPRI;
if (flagp->immed)
h4p->flags |= SGV4_FLAG_IMMED;
- if (flagp->mmap)
+ if (flagp->mmap) {
h4p->flags |= SG_FLAG_MMAP_IO;
+ hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp;
+ } else {
+ if (is_wr)
+ h4p->dout_xferp = (uint64_t)(uintptr_t)rep->buffp;
+ else if (rep->num_blks > 0)
+ h4p->din_xferp = (uint64_t)(uintptr_t)rep->buffp;
+ }
if (flagp->tag)
h4p->flags |= SGV4_FLAG_YIELD_TAG;
if (flagp->evfd)
@@ -399,11 +446,11 @@ do_v4:
rep->state = SGQ_IO_STARTED;
if (! clp->no_sig)
clp->sigs_waiting++;
-#ifdef SG_DEBUG
- if (rep->wr ? clp->oflag.tag : clp->iflag.tag)
- pr2serr("%s: generated_tag=0x%" PRIx64 "\n", __func__,
- (uint64_t)h4p->generated_tag);
-#endif
+ if (clp->debug > 5) {
+ if (is_wr ? clp->oflag.tag : clp->iflag.tag)
+ pr2serr("%s: generated_tag=0x%" PRIx64 "\n", __func__,
+ (uint64_t)h4p->generated_tag);
+ }
return 0;
}
@@ -426,13 +473,38 @@ sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
if (is_v4)
goto do_v4;
+ if (use_pack) {
+ while (true) {
+ if ( ((res = ioctl(fd, SG_GET_NUM_WAITING, &n))) < 0) {
+ res = -errno;
+ pr2serr("%s: ioctl(SG_GET_NUM_WAITING): %s [%d]\n",
+ __func__, strerror(errno), errno);
+ return res;
+ }
+ if (n > 0) {
+ if ( ((res = ioctl(fd, SG_GET_PACK_ID, &id))) < 0) {
+ res = -errno;
+ pr2serr("%s: ioctl(SG_GET_PACK_ID): %s [%d]\n",
+ __func__, strerror(errno), errno);
+ return res;
+ }
+ /* got pack_id or tag of first waiting */
+ break;
+ }
+ }
+ }
memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
+ if (use_pack)
+ io_hdr.pack_id = id;
while (((res = read(fd, &io_hdr, sizeof(sg_io_hdr_t))) < 0) &&
((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
rep = (Rq_elem *)io_hdr.usr_ptr;
- if (rep)
+ if (rep) {
dio = flagsp->dio;
+ if (rep->io_hdr.flags & SGV4_FLAG_HIPRI)
+ ++clp->blk_poll_count;
+ }
if (res < 0) {
res = -errno;
pr2serr("%s: read(): %s [%d]\n", __func__, strerror(errno), errno);
@@ -461,7 +533,7 @@ sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
case SG_LIB_CAT_UNIT_ATTENTION:
return 1;
default:
- sg_chk_n_print3(rep->wr ? "writing": "reading", hp, true);
+ sg_chk_n_print3(wr ? "writing": "reading", hp, true);
rep->state = SGQ_IO_ERR;
return -1;
}
@@ -469,10 +541,10 @@ sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
++clp->dio_incomplete; /* count dios done as indirect IO */
clp->sum_of_resids += hp->resid;
rep->state = SGQ_IO_FINISHED;
-#ifdef SG_DEBUG
- pr2serr("%s: %s ", __func__, wr ? "writing" : "reading");
- pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
-#endif
+ if (clp->debug > 5) {
+ pr2serr("%s: %s ", __func__, wr ? "writing" : "reading");
+ pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
+ }
return 0;
do_v4:
id = -1;
@@ -517,6 +589,10 @@ do_v4:
rep->state = SGQ_IO_ERR;
return res;
}
+ if (rep) {
+ if (rep->io_v4.flags & SGV4_FLAG_HIPRI)
+ ++clp->blk_poll_count;
+ }
if (! (rep && (SGQ_IO_STARTED == rep->state))) {
pr2serr("%s: bad usr_ptr=0x%p\n", __func__, (void *)rep);
if (rep)
@@ -542,7 +618,7 @@ do_v4:
case SG_LIB_CAT_UNIT_ATTENTION:
return 1;
default:
- sg_linux_sense_print(rep->wr ? "writing": "reading",
+ sg_linux_sense_print(wr ? "writing": "reading",
h4p->device_status, h4p->transport_status,
h4p->driver_status,
(const uint8_t *)(unsigned long)h4p->response,
@@ -554,15 +630,15 @@ do_v4:
++clp->dio_incomplete; /* count dios done as indirect IO */
clp->sum_of_resids += h4p->din_resid;
rep->state = SGQ_IO_FINISHED;
-#ifdef SG_DEBUG
- pr2serr("%s: %s ", __func__, wr ? "writing" : "reading");
- pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
- if (use_pack)
- pr2serr("%s: pack_id=%d\n", __func__, h4p->request_extra);
- else if (use_tag)
- pr2serr("%s: request_tag=0x%" PRIx64 "\n", __func__,
- (uint64_t)h4p->request_tag);
-#endif
+ if (clp->debug > 5) {
+ pr2serr("%s: %s ", __func__, wr ? "writing" : "reading");
+ pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
+ if (use_pack)
+ pr2serr("%s: pack_id=%d\n", __func__, h4p->request_extra);
+ else if (use_tag)
+ pr2serr("%s: request_tag=0x%" PRIx64 "\n", __func__,
+ (uint64_t)h4p->request_tag);
+ }
return 0;
}
@@ -581,11 +657,11 @@ sz_reserve(Rq_coll * clp, bool is_in)
seip = &sei;
res = ioctl(fd, SG_GET_VERSION_NUM, &t);
if ((res < 0) || (t < 30000)) {
- pr2serr("sgs_dd: sg driver prior to 3.0.00\n");
+ pr2serr("%s: sg driver prior to 3.0.00\n", my_name);
return 1;
} else if (t < 40000) {
if (vb)
- pr2serr("sgs_dd: warning: sg driver prior to 4.0.00\n");
+ pr2serr("%s: warning: sg driver prior to 4.0.00\n", my_name);
sgs_old_sg_driver = true;
} else if (t < 40045) {
sgs_old_sg_driver = false;
@@ -689,22 +765,50 @@ sz_reserve(Rq_coll * clp, bool is_in)
static int
init_elems(Rq_coll * clp)
{
- Rq_elem * rep;
+ bool either_mmap = false;
int res = 0;
+ int num_bytes = clp->bpt * clp->bs;
int k;
+ Rq_elem * rep;
clp->wr_posp = &clp->elem[0]; /* making ring buffer */
clp->rd_posp = clp->wr_posp;
- for (k = 0; k < SGQ_NUM_ELEMS - 1; ++k)
+ if (clp->iflag.mmap || clp->oflag.mmap) {
+ int res;
+
+ either_mmap = true;
+ sgq_num_elems = 2;
+ sgq_rd_ahead_lim = 1;
+ sgq_wr_ahead_lim = 1;
+ if (clp->iflag.mmap) {
+ res = get_mmap_addr(clp->infd, num_bytes, &clp->in_mmapp);
+ if (res < 0)
+ return res;
+ }
+ if (clp->oflag.mmap) {
+ res = get_mmap_addr(clp->outfd, num_bytes, &clp->out_mmapp);
+ if (res < 0)
+ return res;
+ }
+ }
+ for (k = 0; k < sgq_num_elems - 1; ++k)
clp->elem[k].nextp = &clp->elem[k + 1];
- clp->elem[SGQ_NUM_ELEMS - 1].nextp = &clp->elem[0];
- for (k = 0; k < SGQ_NUM_ELEMS; ++k) {
+ clp->elem[sgq_num_elems - 1].nextp = &clp->elem[0];
+ for (k = 0; k < sgq_num_elems; ++k) {
rep = &clp->elem[k];
rep->state = SGQ_FREE;
rep->iflagp = &clp->iflag;
rep->oflagp = &clp->oflag;
- rep->buffp = sg_memalign(clp->bpt * clp->bs, 0, &rep->free_buffp,
- false);
+ if (either_mmap) {
+ if (clp->both_mmap)
+ continue;
+ if (clp->iflag.mmap)
+ rep->buffp = clp->in_mmapp;
+ else
+ rep->buffp = clp->out_mmapp;
+ continue;
+ }
+ rep->buffp = sg_memalign(num_bytes, 0, &rep->free_buffp, false);
if (NULL == rep->buffp) {
pr2serr("out of memory creating user buffers\n");
res = -ENOMEM;
@@ -719,7 +823,7 @@ remove_elems(Rq_coll * clp)
Rq_elem * rep;
int k;
- for (k = 0; k < SGQ_NUM_ELEMS; ++k) {
+ for (k = 0; k < sgq_num_elems; ++k) {
rep = &clp->elem[k];
if (rep->free_buffp)
free(rep->free_buffp);
@@ -734,9 +838,8 @@ start_read(Rq_coll * clp)
int buf_sz, res;
char ebuff[EBUFF_SZ];
-#ifdef SG_DEBUG
- pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
-#endif
+ if (clp->debug > 5)
+ pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
rep->wr = false;
rep->blk = clp->in_blk;
rep->num_blks = blocks;
@@ -759,7 +862,8 @@ start_read(Rq_coll * clp)
res = -ENOMEM;
}
else if (res < 0) {
- pr2serr("sgs_dd inputting from sg failed, blk=%d\n", rep->blk);
+ pr2serr("%s: inputting from sg failed, blk=%d\n", my_name,
+ rep->blk);
rep->state = SGQ_IO_ERR;
return res;
}
@@ -771,7 +875,8 @@ start_read(Rq_coll * clp)
;
if (res < 0) {
res = -errno;
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: reading, in_blk=%d ", rep->blk);
+ snprintf(ebuff, EBUFF_SZ, "%s: reading, in_blk=%d ", my_name,
+ rep->blk);
perror(ebuff);
rep->state = SGQ_IO_ERR;
return res;
@@ -810,9 +915,8 @@ start_write(Rq_coll * clp)
if (rep == clp->rd_posp)
return -1;
}
-#ifdef SG_DEBUG
- pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
-#endif
+ if (clp->debug > 5)
+ pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
rep->wr = true;
blocks = rep->num_blks;
rep->blk = clp->out_blk;
@@ -823,7 +927,7 @@ start_write(Rq_coll * clp)
if (1 == res) /* ENOMEM, give up */
return -ENOMEM;
else if (res < 0) {
- pr2serr("sgs_dd output to sg failed, blk=%d\n", rep->blk);
+ pr2serr("%s: output to sg failed, blk=%d\n", my_name, rep->blk);
rep->state = SGQ_IO_ERR;
return res;
}
@@ -835,7 +939,8 @@ start_write(Rq_coll * clp)
;
if (res < 0) {
res = -errno;
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: output, out_blk=%d ", rep->blk);
+ snprintf(ebuff, EBUFF_SZ, "%s: output, out_blk=%d ", my_name,
+ rep->blk);
perror(ebuff);
rep->state = SGQ_IO_ERR;
return res;
@@ -863,14 +968,16 @@ do_sigwait(Rq_coll * clp, bool inc1_clear0)
if (clp->debug > 9)
pr2serr("%s: inc1_clear0=%d\n", __func__, (int)inc1_clear0);
- ts.tv_sec = 60; /* 60 second timeout */
- ts.tv_nsec = 0;
+ ts.tv_sec = 0;
+ ts.tv_nsec = DEF_SIGTIMEDWAIT_USEC * 1000;
while (sigtimedwait(&clp->blocked_sigs, &info, &ts) < 0) {
- if (EINTR != errno) {
- int err = errno;
+ int err = errno;
+
+ if (EINTR != err) {
- pr2serr("%s: sigtimedwait(): %s [%d]\n", __func__,
- strerror(err), err); /* EAGAIN is timeout */
+ if (EAGAIN != err)
+ pr2serr("%s: sigtimedwait(): %s [%d]\n", __func__,
+ strerror(err), err);
return -err; /* EAGAIN is timeout error */
}
}
@@ -905,7 +1012,7 @@ do_num_poll_in(Rq_coll * clp, int fd, bool is_evfd)
if (clp->sigs_waiting) {
int res = do_sigwait(clp, true);
- if (res < 0)
+ if ((res < 0) && (-EAGAIN != res))
return res;
}
}
@@ -1034,17 +1141,18 @@ can_read_write(Rq_coll * clp)
else
res = 0;
}
- if (clp->debug) {
- if ((clp->debug >= 9) || wr_waiting || rd_waiting)
+ if (clp->debug > 6) {
+ if ((clp->debug > 7) || wr_waiting || rd_waiting) {
pr2serr("%d/%d (nwb/nrb): read=%d/%d (do/wt) "
"write=%d/%d (do/wt) writeable=%d sg_fin=%d\n",
clp->out_blk, clp->in_blk, reading, rd_waiting,
writing, wr_waiting, (int)writeable, sg_finished);
- fflush(stdout);
+ }
+ // fflush(stdout);
}
- if (writeable && (writing < SGQ_MAX_WR_AHEAD) && (clp->out_count > 0))
+ if (writeable && (writing < sgq_wr_ahead_lim) && (clp->out_count > 0))
return SGQ_CAN_WRITE;
- if ((reading < SGQ_MAX_RD_AHEAD) && (clp->in_count > 0) &&
+ if ((reading < sgq_rd_ahead_lim) && (clp->in_count > 0) &&
(0 == rd_waiting) && (clp->rd_posp->nextp != clp->wr_posp))
return SGQ_CAN_READ;
@@ -1054,8 +1162,8 @@ can_read_write(Rq_coll * clp)
/* usleep(10000); */ /* hang about for 10 milliseconds */
if ((! clp->no_sig) && clp->sigs_waiting) {
res = do_sigwait(clp, false);
- if (res < 0)
- return res;
+ if ((res < 0) && (-EAGAIN != res))
+ return res; /* wasn't timeout */
}
/* Now check the _whole_ buffer for pending requests */
for (rep = clp->rd_posp->nextp; rep != clp->rd_posp; rep = rep->nextp) {
@@ -1081,7 +1189,7 @@ process_flags(const char * arg, struct flags_t * fp)
strncpy(buff, arg, sizeof(buff));
buff[sizeof(buff) - 1] = '\0';
if ('\0' == buff[0]) {
- pr2serr("no flag found\n");
+ pr2serr("no flag found, 'null' can be used as a placeholder\n");
return false;
}
cp = buff;
@@ -1095,6 +1203,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->evfd = true;
else if (0 == strcmp(cp, "excl"))
fp->excl = true;
+ else if (0 == strcmp(cp, "hipri"))
+ fp->hipri = true;
else if (0 == strcmp(cp, "immed"))
fp->immed = true;
else if (0 == strcmp(cp, "mmap"))
@@ -1110,16 +1220,26 @@ process_flags(const char * arg, struct flags_t * fp)
fp->pack = true;
else if (0 == strcmp(cp, "tag"))
fp->tag = true;
- else if (0 == strcmp(cp, "v3"))
+ else if (0 == strcmp(cp, "v3")) {
fp->v3 = true;
- else if (0 == strcmp(cp, "v4"))
+ fp->given_v3v4 = true;
+ } else if (0 == strcmp(cp, "v4")) {
fp->v4 = true;
- else {
+ fp->given_v3v4 = true;
+ } else {
pr2serr("unrecognised flag: %s\n", cp);
return false;
}
cp = np;
} while (cp);
+ if (fp->dio && fp->mmap) {
+ pr2serr(" Can't set both mmap and dio\n");
+ return false;
+ }
+ if ((fp->dio || fp->mmap) && fp->noxfer) {
+ pr2serr(" Can't have mmap or dio with noxfer\n");
+ return false;
+ }
return true;
}
@@ -1128,6 +1248,8 @@ int
main(int argc, char * argv[])
{
bool bs_given = false;
+ bool no_sig_given = false;
+ bool hipri_present;
int skip = 0;
int seek = 0;
int ibs = 0;
@@ -1184,19 +1306,20 @@ main(int argc, char * argv[])
inf[INOUTF_SZ - 1] = '\0';
} else if (0 == strcmp(key, "iflag")) {
if (! process_flags(buf, &clp->iflag)) {
- pr2serr("%sbad argument to 'iflag='\n", my_name);
+ pr2serr("%s: bad argument to 'iflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == strcmp(key,"no_sig"))
+ } else if (0 == strcmp(key,"no_sig")) { /* default changes */
clp->no_sig = !!sg_get_num(buf);
- else if (0 == strcmp(key,"obs"))
+ no_sig_given = true;
+ } else if (0 == strcmp(key,"obs"))
obs = sg_get_num(buf);
else if (strcmp(key,"of") == 0) {
memcpy(outf, buf, INOUTF_SZ);
outf[INOUTF_SZ - 1] = '\0';
} else if (0 == strcmp(key, "oflag")) {
if (! process_flags(buf, &clp->oflag)) {
- pr2serr("%sbad argument to 'oflag='\n", my_name);
+ pr2serr("%s: bad argument to 'oflag='\n", my_name);
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"poll_ms"))
@@ -1210,20 +1333,26 @@ main(int argc, char * argv[])
else if ((0 == strcmp(key,"-V")) || (0 == strcmp(key,"--version"))) {
pr2serr("%s: version: %s\n", my_name, version_str);
return 0;
- } else if (0 == strcmp(key,"-vvvv"))
- clp->debug +=4;
- else if (0 == strcmp(key,"-vvv"))
- clp->debug +=3;
- else if (0 == strcmp(key,"-vv"))
- clp->debug +=2;
- else if ((0 == strcmp(key,"-v")) || (0 == strcmp(key,"--verbose")))
+ } else if (0 == strncmp(key,"-vvvvvvv", 8))
+ clp->debug += 7;
+ else if (0 == strncmp(key,"-vvvvvv", 7))
+ clp->debug += 6;
+ else if (0 == strncmp(key,"-vvvvv", 6))
+ clp->debug += 5;
+ else if (0 == strncmp(key,"-vvvv", 5))
+ clp->debug += 4;
+ else if (0 == strncmp(key,"-vvv", 4))
+ clp->debug += 3;
+ else if (0 == strncmp(key,"-vv", 3))
+ clp->debug += 2;
+ else if ((0 == strcmp(key,"--verbose")) || (0 == strncmp(key,"-v", 2)))
++clp->debug;
else if (0 == strcmp(key,"-hhhh"))
- help_pg +=4;
+ help_pg += 4;
else if (0 == strcmp(key,"-hhh"))
- help_pg +=3;
+ help_pg += 3;
else if (0 == strcmp(key,"-hh"))
- help_pg +=2;
+ help_pg += 2;
else if ((0 == strcmp(key,"-h")) || (0 == strcmp(key,"--help")))
++help_pg;
else {
@@ -1242,6 +1371,13 @@ main(int argc, char * argv[])
return 0;
}
+ hipri_present = (clp->iflag.hipri || clp->oflag.hipri);
+ if (no_sig_given) {
+ if ((0 == clp->no_sig) && hipri_present)
+ pr2serr("Warning: signalling doesn't work with hipri\n");
+ } else /* no_sig default varies: 0 normally and 1 if hipri present */
+ clp->no_sig = hipri_present ? 1 : 0;
+
if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) {
pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
usage(1);
@@ -1258,13 +1394,15 @@ main(int argc, char * argv[])
pr2serr("Assume 'bs' (block size) of %d bytes\n", clp->bs);
if ((skip < 0) || (seek < 0)) {
- pr2serr("skip and seek cannot be negative\n");
+ pr2serr("%s: skip and seek cannot be negative\n", my_name);
return 1;
}
-#ifdef SG_DEBUG
- pr2serr("sgs_dd: if=%s skip=%d of=%s seek=%d count=%d\n",
- inf, skip, outf, seek, count);
-#endif
+ if (clp->iflag.mmap && clp->oflag.mmap)
+ clp->both_mmap = true;;
+
+ if (clp->debug > 3)
+ pr2serr("%s: if=%s skip=%d of=%s seek=%d count=%d\n", my_name,
+ inf, skip, outf, seek, count);
if (! clp->no_sig) {
/* Need to block signals before SIGPOLL is enabled in sz_reserve() */
sigemptyset(&clp->blocked_sigs);
@@ -1280,8 +1418,8 @@ main(int argc, char * argv[])
if (inf[0] && ('-' != inf[0])) {
open_fl = clp->iflag.excl ? O_EXCL : 0;
if ((clp->infd = open(inf, open_fl | O_RDONLY)) < 0) {
- snprintf(ebuff, EBUFF_SZ, "sgs_dd: could not open %s for reading",
- inf);
+ snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for reading",
+ my_name, inf);
perror(ebuff);
return 1;
}
@@ -1292,8 +1430,8 @@ main(int argc, char * argv[])
offset *= clp->bs; /* could overflow here! */
if (lseek(clp->infd, offset, SEEK_SET) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: couldn't skip to required position on %s", inf);
+ snprintf(ebuff, EBUFF_SZ, "%s: couldn't skip to required "
+ "position on %s", my_name, inf);
perror(ebuff);
return 1;
}
@@ -1343,7 +1481,7 @@ main(int argc, char * argv[])
open_fl |= (O_WRONLY | O_CREAT);
if ((clp->outfd = open(outf, open_fl, 0666)) < 0) {
snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: could not open %s for writing", outf);
+ "%s: could not open %s for writing", my_name, outf);
perror(ebuff);
return 1;
}
@@ -1352,8 +1490,8 @@ main(int argc, char * argv[])
offset *= clp->bs; /* could overflow here! */
if (lseek(clp->outfd, offset, SEEK_SET) < 0) {
- snprintf(ebuff, EBUFF_SZ,
- "sgs_dd: couldn't seek to required position on %s", outf);
+ snprintf(ebuff, EBUFF_SZ, "%s: couldn't seek to required "
+ "position on %s", my_name, outf);
perror(ebuff);
return 1;
}
@@ -1378,6 +1516,11 @@ main(int argc, char * argv[])
return 1;
}
}
+ if ((clp->in_is_sg || clp->out_is_sg) && !clp->iflag.given_v3v4 &&
+ !clp->oflag.given_v3v4 && (clp->debug > 0))
+ pr2serr("using sg driver version 3 interface on %s\n",
+ clp->in_is_sg ? inf : outf);
+
if (0 == count)
return 0;
else if (count < 0) {
@@ -1390,8 +1533,10 @@ main(int argc, char * argv[])
if (0 != res) {
pr2serr("Unable to read capacity on %s\n", inf);
in_num_sect = -1;
- }
- else {
+ } else {
+ if (clp->debug > 4)
+ pr2serr("ifile: number of sectors=%d, sector size=%d\n",
+ in_num_sect, in_sect_sz);
if (in_num_sect > skip)
in_num_sect -= skip;
}
@@ -1405,16 +1550,17 @@ main(int argc, char * argv[])
if (0 != res) {
pr2serr("Unable to read capacity on %s\n", outf);
out_num_sect = -1;
- }
- else {
+ } else {
+ if (clp->debug > 4)
+ pr2serr("ofile: number of sectors=%d, sector size=%d\n",
+ out_num_sect, out_sect_sz);
if (out_num_sect > seek)
out_num_sect -= seek;
}
}
-#ifdef SG_DEBUG
- pr2serr("Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n",
- count, in_num_sect, out_num_sect);
-#endif
+ if (clp->debug > 3)
+ pr2serr("Start of loop, count=%d, in_num_sect=%d, "
+ "out_num_sect=%d\n", count, in_num_sect, out_num_sect);
if (in_num_sect > 0) {
if (out_num_sect > 0)
count = (in_num_sect > out_num_sect) ? out_num_sect :
@@ -1425,10 +1571,8 @@ main(int argc, char * argv[])
else
count = out_num_sect;
}
-
-#ifdef SG_DEBUG
- pr2serr("Start of loop, count=%d, bpt=%d\n", count, clp->bpt);
-#endif
+ if (clp->debug > 4)
+ pr2serr("Start of loop, count=%d, bpt=%d\n", count, clp->bpt);
clp->in_count = count;
clp->in_done_count = count;
@@ -1480,9 +1624,14 @@ main(int argc, char * argv[])
if (clp->sum_of_resids)
pr2serr(">> Non-zero sum of residual counts=%d\n",
clp->sum_of_resids);
- if ((! clp->no_sig) && clp->debug > 0)
- pr2serr("SIGIO/SIGPOLL signals received: %d, RT sigs: %d\n",
- clp->sigs_io_received, clp->sigs_rt_received);
+ if (clp->debug > 0) {
+ if (! clp->no_sig)
+ pr2serr("SIGIO/SIGPOLL signals received: %d, RT sigs: %d\n",
+ clp->sigs_io_received, clp->sigs_rt_received);
+ if (hipri_present)
+ pr2serr("HIPRI (blk_poll) used to complete %d commands\n",
+ clp->blk_poll_count);
+ }
if (clp->pollerr_count > 0)
pr2serr(">> poll() system call gave POLLERR %d times\n",
clp->pollerr_count);