aboutsummaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2020-11-10 01:46:05 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2020-11-10 01:46:05 +0000
commit6276daf9b89e1d27b91438ff1e92482a1d2e7179 (patch)
tree4803611223ef48163d2a0fb6cbf717639d992271 /testing
parent4ca8449c2826be469bc9558f2a037236c6703d64 (diff)
downloadsg3_utils-6276daf9b89e1d27b91438ff1e92482a1d2e7179.tar.gz
tweak transport error handling in Linux; sg_compare_and_write: add examples section to its manpage; testing
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@866 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-rw-r--r--testing/Makefile12
-rw-r--r--testing/sg_iovec_tst.c271
-rw-r--r--testing/sg_iovec_tst.cpp594
-rw-r--r--testing/sg_mrq_dd.cpp20
-rw-r--r--testing/sgh_dd.cpp4
5 files changed, 616 insertions, 285 deletions
diff --git a/testing/Makefile b/testing/Makefile
index 0a34ddec..8383cc5b 100644
--- a/testing/Makefile
+++ b/testing/Makefile
@@ -4,10 +4,10 @@ PREFIX=/usr/local
INSTDIR=$(DESTDIR)/$(PREFIX)/bin
MANDIR=$(DESTDIR)/$(PREFIX)/man
-EXECS = sg_iovec_tst sg_sense_test sg_queue_tst bsg_queue_tst sg_chk_asc \
- sg_tst_nvme sg_tst_ioctl sg_tst_bidi tst_sg_lib sgs_dd sg_tst_excl \
+EXECS = sg_sense_test sg_queue_tst bsg_queue_tst sg_chk_asc sg_tst_nvme \
+ sg_tst_ioctl sg_tst_bidi tst_sg_lib sgs_dd sg_tst_excl \
sg_tst_excl2 sg_tst_excl3 sg_tst_context sg_tst_async sgh_dd \
- sg_mrq_dd
+ sg_mrq_dd sg_iovec_tst
EXTRAS =
@@ -62,9 +62,6 @@ depend dep:
clean:
/bin/rm -f *.o $(EXECS) $(EXTRAS) $(BSG_EXTRAS) core .depend
-sg_iovec_tst: sg_iovec_tst.o $(LIBFILESOLD)
- $(LD) -o $@ $(LDFLAGS) $^
-
sg_sense_test: sg_sense_test.o $(LIBFILESOLD)
$(LD) -o $@ $(LDFLAGS) $^
@@ -114,6 +111,9 @@ sgh_dd: sgh_dd.o $(LIBFILESNEW)
sg_mrq_dd: sg_mrq_dd.o sg_scat_gath.o $(LIBFILESNEW)
$(CXXLD) -o $@ $(LDFLAGS) -pthread -latomic $^
+sg_iovec_tst: sg_iovec_tst.o sg_scat_gath.o $(LIBFILESNEW)
+ $(CXXLD) -o $@ $(LDFLAGS) -pthread -latomic $^
+
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/testing/sg_iovec_tst.c b/testing/sg_iovec_tst.c
deleted file mode 100644
index f95dc67f..00000000
--- a/testing/sg_iovec_tst.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2003-2019 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)
- * any later version.
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- *
- * Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
- * device driver.
- * This program will read a certain number of blocks of a given block size
- * from a given sg device node and write what is retrieved out to a
- * normal file. The purpose is to test the sg_iovec mechanism within the
- * sg_io_hdr structure.
- *
- * Version 0.17 (20181207)
- */
-
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "sg_lib.h"
-#include "sg_io_linux.h"
-#include "sg_unaligned.h"
-
-
-
-#define ME "sg_iovec_tst: "
-
-#define A_PRIME 509
-#define IOVEC_ELEMS 2048
-
-#define SENSE_BUFF_LEN 32
-#define DEF_TIMEOUT 40000 /* 40,000 milliseconds */
-
-struct sg_iovec iovec[IOVEC_ELEMS];
-
-
-static void
-usage(void)
-{
- printf("Usage: sg_iovec_tst [-a] [-b=bs] -c=num [-e=es] [-h]\n"
- " <generic_device> <output_filename>\n");
- printf(" where: -a async sg use (def: use ioctl(SGIO) )\n");
- printf(" -b=bs block size (default 512 Bytes)\n");
- printf(" -c=num count of blocks to transfer\n");
- printf(" -e=es iovec element size (def: 509)\n");
- printf(" -h this usage message\n");
- printf(" reads from <generic_device> and sends to "
- "<output_filename>\nUses iovec (a scatter list) in linear "
- "mode\n");
-}
-
-/* Returns 0 if everything ok */
-static int sg_read(int sg_fd, uint8_t * buff, int num_blocks,
- int from_block, int bs, int elem_size, int async)
-{
- uint8_t rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- uint8_t senseBuff[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
- struct pollfd a_poll;
- int dxfer_len = bs * num_blocks;
- int k, pos, rem, res;
-
- sg_put_unaligned_be32((uint32_t)from_block, rdCmd + 2);
- sg_put_unaligned_be16((uint16_t)from_block, rdCmd + 7);
-
- for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) {
- iovec[k].iov_base = buff + pos;
- iovec[k].iov_len = (rem > elem_size) ? elem_size : rem;
- if (rem <= elem_size)
- break;
- pos += elem_size;
- rem -= elem_size;
- }
- if (k >= IOVEC_ELEMS) {
- fprintf(stderr, "Can't fit dxfer_len=%d bytes in iovec\n", dxfer_len);
- return -1;
- }
- memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rdCmd);
- io_hdr.cmdp = rdCmd;
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = dxfer_len;
- io_hdr.iovec_count = k + 1;
- io_hdr.dxferp = iovec;
- io_hdr.mx_sb_len = SENSE_BUFF_LEN;
- io_hdr.sbp = senseBuff;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = from_block;
-
- if (async) {
- res = write(sg_fd, &io_hdr, sizeof(io_hdr));
- if (res < 0) {
- perror("write(<sg_device>), error");
- return -1;
- } else if (res < (int)sizeof(io_hdr)) {
- fprintf(stderr, "write(<sg_device>) returned %d, expected %d\n",
- res, (int)sizeof(io_hdr));
- return -1;
- }
- a_poll.fd = sg_fd;
- a_poll.events = POLLIN;
- a_poll.revents = 0;
- res = poll(&a_poll, 1, 2000 /* millisecs */ );
- if (res < 0) {
- perror("poll error on <sg_device>");
- return -1;
- }
- if (0 == (POLLIN & a_poll.revents)) {
- fprintf(stderr, "strange, poll() completed without data to "
- "read\n");
- return -1;
- }
- res = read(sg_fd, &io_hdr, sizeof(io_hdr));
- if (res < 0) {
- perror("read(<sg_device>), error");
- return -1;
- } else if (res < (int)sizeof(io_hdr)) {
- fprintf(stderr, "read(<sg_device>) returned %d, expected %d\n",
- res, (int)sizeof(io_hdr));
- return -1;
- }
- } else if (ioctl(sg_fd, SG_IO, &io_hdr)) {
- perror("reading (SG_IO) on sg device, error");
- return -1;
- }
- switch (sg_err_category3(&io_hdr)) {
- case SG_LIB_CAT_CLEAN:
- break;
- case SG_LIB_CAT_RECOVERED:
- fprintf(stderr, "Recovered error while reading block=%d, num=%d\n",
- from_block, num_blocks);
- break;
- case SG_LIB_CAT_UNIT_ATTENTION:
- fprintf(stderr, "Unit attention\n");
- return -1;
- default:
- sg_chk_n_print3("reading", &io_hdr, 1);
- return -1;
- }
- return 0;
-}
-
-
-int main(int argc, char * argv[])
-{
- int sg_fd, fd, res, j, m, dxfer_len;
- unsigned int k, num;
- int do_async = 0;
- int do_help = 0;
- int blk_size = 512;
- int elem_size = A_PRIME;
- int count = 0;
- char * sg_file_name = 0;
- char * out_file_name = 0;
- uint8_t * buffp;
-
- for (j = 1; j < argc; ++j) {
- if (0 == strcmp("-a", argv[j]))
- do_async = 1;
- else if (0 == strncmp("-b=", argv[j], 3)) {
- m = 3;
- num = sscanf(argv[j] + m, "%d", &blk_size);
- if ((1 != num) || (blk_size <= 0)) {
- printf("Couldn't decode number after '-b' switch\n");
- sg_file_name = 0;
- break;
- }
- } else if (0 == strncmp("-c=", argv[j], 3)) {
- m = 3;
- num = sscanf(argv[j] + m, "%d", &count);
- if (1 != num) {
- printf("Couldn't decode number after '-c' switch\n");
- sg_file_name = 0;
- break;
- }
- } else if (0 == strncmp("-e=", argv[j], 3)) {
- m = 3;
- num = sscanf(argv[j] + m, "%d", &elem_size);
- if (1 != num) {
- printf("Couldn't decode number after '-e' switch\n");
- sg_file_name = 0;
- break;
- }
- } else if (0 == strcmp("-h", argv[j]))
- do_help = 1;
- else if (*argv[j] == '-') {
- printf("Unrecognized switch: %s\n", argv[j]);
- sg_file_name = 0;
- break;
- } else if (NULL == sg_file_name)
- sg_file_name = argv[j];
- else
- out_file_name = argv[j];
- }
- if (do_help) {
- usage();
- return 0;
- }
- if (NULL == sg_file_name) {
- printf(">>> need sg node name (e.g. /dev/sg3)\n\n");
- usage();
- return 1;
- }
- if (NULL == out_file_name) {
- printf(">>> need out filename (to place what is fetched by READ\n\n");
- usage();
- return 1;
- }
- if (0 == count) {
- printf(">>> need count of blocks to READ\n\n");
- usage();
- return 1;
- }
-
- if (do_async)
- sg_fd = open(sg_file_name, O_RDWR);
- else
- sg_fd = open(sg_file_name, O_RDONLY);
- if (sg_fd < 0) {
- perror(ME "sg device node open error");
- return 1;
- }
- /* Don't worry, being very careful not to write to a none-sg file ... */
- res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k);
- if ((res < 0) || (k < 30000)) {
- printf(ME "not a sg device, or driver prior to 3.x\n");
- return 1;
- }
- fd = open(out_file_name, O_WRONLY | O_CREAT, 0666);
- if (fd < 0) {
- perror(ME "output file open error");
- return 1;
- }
- dxfer_len = count * blk_size;
- buffp = (uint8_t *)calloc(count, blk_size);
- if (buffp) {
- if (0 == sg_read(sg_fd, buffp, count, 0, blk_size, elem_size,
- do_async)) {
- if (write(fd, buffp, dxfer_len) < 0)
- perror(ME "output write failed");
- }
- free(buffp);
- } else
- fprintf(stderr, "user space calloc for %d bytes failed\n",
- dxfer_len);
- res = close(fd);
- if (res < 0) {
- perror(ME "output file close error");
- close(sg_fd);
- return 1;
- }
- res = close(sg_fd);
- if (res < 0) {
- perror(ME "sg device close error");
- return 1;
- }
- return 0;
-}
diff --git a/testing/sg_iovec_tst.cpp b/testing/sg_iovec_tst.cpp
new file mode 100644
index 00000000..3199dc8d
--- /dev/null
+++ b/testing/sg_iovec_tst.cpp
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2003-2020 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)
+ * any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
+ * device driver.
+ * This C++ program will read a certain number of blocks of a given block
+ * size from a given sg device node using struct sg_iovec and write what is
+ * retrieved out to a normal file. The purpose is to test the sg_iovec
+ * mechanism within the sg_io_hdr and sg_io_v4 structures.
+ *
+ * struct sg_iovec and struct iovec [in include/uapi/uio.h] are basically
+ * the same thing: a pointer followed by a length (of type size_t). If
+ * applied to a disk then the pointer will hold a LBA and 'length' will
+ * be a number of logical blocks (which usually cannot exceed 2**32-1 .
+ *
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <poll.h>
+#include <limits.h>
+#include <time.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/bsg.h>
+
+#ifndef HAVE_LINUX_SG_V4_HDR
+
+/* Kernel uapi header contain __user decorations on user space pointers
+ * to indicate they are unsafe in the kernel space. However glibc takes
+ * all those __user decorations out from headers in /usr/include/linux .
+ * So to stop compile errors when directly importing include/uapi/scsi/sg.h
+ * undef __user before doing that include. */
+#define __user
+
+/* Want to block the original sg.h header from also being included. That
+ * causes lots of multiple definition errors. This will only work if this
+ * header is included _before_ the original sg.h header. */
+#define _SCSI_GENERIC_H /* original kernel header guard */
+#define _SCSI_SG_H /* glibc header guard */
+
+#include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */
+
+#else
+#define __user
+#endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
+
+#include "sg_lib.h"
+#include "sg_io_linux.h"
+#include "sg_unaligned.h"
+
+// C++ local header
+#include "sg_scat_gath.h"
+
+static const char * version_str = "1.07 20201108";
+
+#define ME "sg_iovec_tst: "
+
+#define IOVEC_ELEMS 1024 /* match current UIO_MAXIOV in <linux/uio.h> */
+
+#define DEF_BLK_SZ 512
+#define SENSE_BUFF_LEN 32
+#define DEF_TIMEOUT 40000 /* 40,000 milliseconds */
+
+static struct sg_iovec iovec[IOVEC_ELEMS];
+
+static int verbose;
+
+static struct option long_options[] = {
+ {"async", no_argument, 0, 'a'},
+ {"bs", required_argument, 0, 'b'},
+ {"elem_size", required_argument, 0, 'e'},
+ {"elem-size", required_argument, 0, 'e'},
+ {"elemsz", required_argument, 0, 'e'},
+ {"fill", required_argument, 0, 'f'},
+ {"from_skip", no_argument, 0, 'F'},
+ {"from-skip", no_argument, 0, 'F'},
+ {"help", no_argument, 0, 'h'},
+ {"num", required_argument, 0, 'n'},
+ {"num_blks", required_argument, 0, 'n'},
+ {"num-blks", required_argument, 0, 'n'},
+ {"sgl", required_argument, 0, 'S'},
+ {"sgv4", no_argument, 0, '4'},
+ {"skip", required_argument, 0, 's'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+
+static void
+usage(void)
+{
+ printf("Usage: sg_iovec_tst [--async] [--bs=BS] [--elem_sz=ES] "
+ "[--fill=F_ELEMS]\n"
+ " [from_skip] [--help] --num=NUM [--sgl=SFN] "
+ "[--sgv4]\n"
+ " [--skip=SKIP] [--verbose] [--version] "
+ "SG_DEV OUT_F\n");
+ printf("where:\n"
+ " --async|-a async sg use (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");
+ printf(" --fill=F_ELEMS|-f F_ELEMS append F_ELEMS*ES zero bytes "
+ "onto OUT_F\n"
+ " after each iovec element (def: "
+ "0)\n");
+ 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(" --sgv4|-4 use the sg v4 interface (def: v3 "
+ "interface)\n");
+ printf(" --skip=SKIP|-s SKIP SKIP blocks before reading S_DEV "
+ "(def: 0)\n");
+ printf(" --verbose|-v increase verbosity\n");
+ printf(" --version|-V print version and exit\n\n");
+ printf("Reads from SG_DEV and writes that data to OUT_F in binary. Uses "
+ "iovec\n(a scatter gather list) in linear mode (i.e. it cuts up "
+ "a contiguous\nbuffer). Example:\n"
+ " sg_iovec_tst -n 8k -e 4k /dev/sg3 out.bin\n");
+}
+
+/* Returns 0 if everything ok */
+static int
+sg_read(int sg_fd, uint8_t * buff, int num_blocks, int from_block, int bs,
+ int elem_size, int async)
+{
+ uint8_t rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint8_t senseBuff[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+ struct pollfd a_poll;
+ int dxfer_len = bs * num_blocks;
+ int k, pos, rem, res;
+ char b[128];
+
+ sg_put_unaligned_be32((uint32_t)from_block, rdCmd + 2);
+ sg_put_unaligned_be16((uint16_t)num_blocks, rdCmd + 7);
+
+ for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) {
+ iovec[k].iov_base = buff + pos;
+ iovec[k].iov_len = (rem > elem_size) ? elem_size : rem;
+ if (rem <= elem_size)
+ break;
+ pos += elem_size;
+ rem -= elem_size;
+ }
+ if (k >= IOVEC_ELEMS) {
+ fprintf(stderr, "Can't fit dxfer_len=%d bytes in %d iovec elements "
+ "(would need %d)\n", dxfer_len, IOVEC_ELEMS,
+ dxfer_len / elem_size);
+ fprintf(stderr, "Try expanding elem_size which is currently %d "
+ "bytes\n", elem_size);
+ return -1;
+ }
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rdCmd);
+ io_hdr.cmdp = rdCmd;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = dxfer_len;
+ io_hdr.iovec_count = k + 1;
+ io_hdr.dxferp = iovec;
+ io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+ io_hdr.sbp = senseBuff;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = from_block;
+ if (verbose)
+ fprintf(stderr, "cdb: %s\n", sg_get_command_str(rdCmd, 10, true,
+ sizeof(b), b));
+
+ if (async) {
+ res = write(sg_fd, &io_hdr, sizeof(io_hdr));
+ if (res < 0) {
+ perror("write(<sg_device>), error");
+ return -1;
+ } else if (res < (int)sizeof(io_hdr)) {
+ fprintf(stderr, "write(<sg_device>) returned %d, expected %d\n",
+ res, (int)sizeof(io_hdr));
+ return -1;
+ }
+ a_poll.fd = sg_fd;
+ a_poll.events = POLLIN;
+ a_poll.revents = 0;
+ res = poll(&a_poll, 1, 2000 /* millisecs */ );
+ if (res < 0) {
+ perror("poll error on <sg_device>");
+ return -1;
+ }
+ if (0 == (POLLIN & a_poll.revents)) {
+ fprintf(stderr, "strange, poll() completed without data to "
+ "read\n");
+ return -1;
+ }
+ res = read(sg_fd, &io_hdr, sizeof(io_hdr));
+ if (res < 0) {
+ perror("read(<sg_device>), error");
+ return -1;
+ } else if (res < (int)sizeof(io_hdr)) {
+ fprintf(stderr, "read(<sg_device>) returned %d, expected %d\n",
+ res, (int)sizeof(io_hdr));
+ return -1;
+ }
+ } else if (ioctl(sg_fd, SG_IO, &io_hdr)) {
+ perror("reading (SG_IO) on sg device, error");
+ return -1;
+ }
+ switch (sg_err_category3(&io_hdr)) {
+ case SG_LIB_CAT_CLEAN:
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ fprintf(stderr, "Recovered error while reading block=%d, num=%d\n",
+ from_block, num_blocks);
+ break;
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ fprintf(stderr, "Unit attention\n");
+ return -1;
+ default:
+ sg_chk_n_print3("reading", &io_hdr, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Returns 0 if everything ok */
+static int
+sg_read_v4(int sg_fd, uint8_t * buff, int num_blocks, int from_block, int bs,
+ int elem_size, int async)
+{
+ uint8_t rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint8_t senseBuff[SENSE_BUFF_LEN];
+ struct sg_io_v4 io_hdr;
+ struct pollfd a_poll;
+ int dxfer_len = bs * num_blocks;
+ int k, pos, rem, res;
+ char b[128];
+
+ sg_put_unaligned_be32((uint32_t)from_block, rdCmd + 2);
+ sg_put_unaligned_be16((uint16_t)num_blocks, rdCmd + 7);
+
+ for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) {
+ iovec[k].iov_base = buff + pos;
+ iovec[k].iov_len = (rem > elem_size) ? elem_size : rem;
+ if (rem <= elem_size)
+ break;
+ pos += elem_size;
+ rem -= elem_size;
+ }
+ if (k >= IOVEC_ELEMS) {
+ fprintf(stderr, "Can't fit dxfer_len=%d bytes in %d iovec elements "
+ "(would need %d)\n", dxfer_len, IOVEC_ELEMS,
+ dxfer_len / elem_size);
+ fprintf(stderr, "Try expanding elem_size which is currently %d "
+ "bytes\n", elem_size);
+ return -1;
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_v4));
+ io_hdr.guard = 'Q';
+ io_hdr.request_len = sizeof(rdCmd);
+ io_hdr.request = (uint64_t)(uintptr_t)rdCmd;
+ io_hdr.din_xfer_len = dxfer_len;
+ io_hdr.din_xferp = (uint64_t)(uintptr_t)iovec;
+ io_hdr.din_iovec_count = k + 1;
+ io_hdr.max_response_len = SG_DXFER_FROM_DEV;
+ io_hdr.response = (uint64_t)(uintptr_t)senseBuff;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.request_extra = from_block; /* pack_id */
+ if (verbose)
+ fprintf(stderr, "cdb: %s\n", sg_get_command_str(rdCmd, 10, true,
+ sizeof(b), b));
+
+ if (async) {
+ res = ioctl(sg_fd, SG_IOSUBMIT, &io_hdr);
+ if (res < 0) {
+ perror("ioctl(SG_IOSUBMIT <sg_device>), error");
+ return -1;
+ }
+ a_poll.fd = sg_fd;
+ a_poll.events = POLLIN;
+ a_poll.revents = 0;
+ res = poll(&a_poll, 1, 2000 /* millisecs */ );
+ if (res < 0) {
+ perror("poll error on <sg_device>");
+ return -1;
+ }
+ if (0 == (POLLIN & a_poll.revents)) {
+ fprintf(stderr, "strange, poll() completed without data to "
+ "read\n");
+ return -1;
+ }
+ res = ioctl(sg_fd, SG_IORECEIVE, &io_hdr);
+ if (res < 0) {
+ perror("ioctl(SG_IORECEIVE <sg_device>), error");
+ return -1;
+ }
+ } else if (ioctl(sg_fd, SG_IO, &io_hdr)) {
+ perror("ioctl(SG_IO) on sg device, error");
+ return -1;
+ }
+
+ res = sg_err_category_new(io_hdr.device_status, io_hdr.transport_status,
+ io_hdr.driver_status,
+ (const uint8_t *)(unsigned long)io_hdr.response,
+ io_hdr.response_len);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ fprintf(stderr, "Recovered error while reading block=%d, num=%d\n",
+ from_block, num_blocks);
+ break;
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ fprintf(stderr, "Unit attention\n");
+ return -1;
+ default:
+ sg_linux_sense_print("reading", io_hdr.device_status,
+ io_hdr.transport_status, io_hdr.driver_status,
+ senseBuff, io_hdr.response_len, true);
+ return -1;
+ }
+ return 0;
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ bool do_sgv4 = false;
+ bool do_async = false;
+ bool do_help = false;
+ bool from_skip = false;
+ bool blk_size_given = false;
+ bool elem_size_given = false;
+ int sg_fd, fd, c, res, res2, err, dxfer_len;
+ unsigned int k;
+ int blk_size = DEF_BLK_SZ;
+ int elem_size = blk_size;
+ int num_blks = 0;
+ int f_elems = 0;
+ int64_t start_blk = 0;
+ char * sg_dev_name = 0;
+ char * out_file_name = 0;
+ char * sgl_fn = 0;
+ uint8_t * buffp;
+ uint8_t * fillp = NULL;
+ FILE * fp = NULL;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "4ab:e:f:Fhn:s:S:vV",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case '4':
+ do_sgv4 = true;
+ break;
+ case 'a':
+ do_async = true;
+ break;
+ case 'b':
+ blk_size = sg_get_num(optarg);
+ if (blk_size < 1) {
+ printf("Couldn't decode positive number after '--bs=' "
+ "option\n");
+ sg_dev_name = 0;
+ } else
+ blk_size_given = true;
+ break;
+ case 'e':
+ elem_size = sg_get_num(optarg);
+ if (elem_size < 1) {
+ printf("Couldn't decode positive number after '--elem_size=' "
+ "option\n");
+ sg_dev_name = 0;
+ } else
+ elem_size_given = true;
+ break;
+ case 'f':
+ f_elems = sg_get_num(optarg);
+ if (f_elems < 0) {
+ printf("Couldn't decode number after '--fill=' option\n");
+ sg_dev_name = 0;
+ }
+ break;
+ case 'F':
+ from_skip = true;
+ break;
+ case 'h':
+ do_help = true;
+ break;
+ case 'n':
+ num_blks = sg_get_num(optarg);
+ if (num_blks < 1) {
+ printf("Couldn't decode positive number after '--num=' "
+ "option\n");
+ sg_dev_name = 0;
+ }
+ break;
+ case 's':
+ start_blk = sg_get_llnum(optarg);
+ if ((start_blk < 0) || (start_blk > INT_MAX)) {
+ printf("Couldn't decode number after '--skip=' option\n");
+ sg_dev_name = 0;
+ }
+ break;
+ case 'S':
+ if (sgl_fn) {
+ printf("Looks like --sgl=SFN has been given twice\n");
+ sg_dev_name = 0;
+ } else
+ sgl_fn = optarg;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ printf("Version: %s\n", version_str);
+ return 0;
+ default:
+ fprintf(stderr, "unrecognised option code 0x%x ??\n", c);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == sg_dev_name) {
+ sg_dev_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ if (sg_dev_name) {
+ out_file_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ }
+ if (do_help) {
+ usage();
+ return 0;
+ }
+ if (NULL == sg_dev_name) {
+ printf(">>> need sg node name (e.g. /dev/sg3)\n\n");
+ usage();
+ return 1;
+ }
+ if (NULL == out_file_name) {
+ printf(">>> need out filename (to place what is fetched by READ\n\n");
+ usage();
+ return 1;
+ }
+ if (0 == num_blks) {
+ printf(">>> need number of blocks to READ\n\n");
+ usage();
+ return 1;
+ }
+
+ if ((! elem_size_given) && blk_size_given)
+ elem_size = blk_size;
+
+ if (do_async)
+ sg_fd = open(sg_dev_name, O_RDWR);
+ else
+ sg_fd = open(sg_dev_name, O_RDONLY);
+ if (sg_fd < 0) {
+ perror(ME "sg device node open error");
+ return 1;
+ }
+ /* Don't worry, being very careful not to write to a none-sg file ... */
+ res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k);
+ if ((res < 0) || (k < 30000)) {
+ printf(ME "not a sg device, or driver prior to 3.x\n");
+ return 1;
+ }
+ fd = open(out_file_name, O_WRONLY | O_CREAT, 0666);
+ if (fd < 0) {
+ perror(ME "output file open error");
+ return 1;
+ }
+ if (f_elems > 0) {
+ fillp = (uint8_t *)calloc(f_elems, elem_size);
+ if (NULL == fillp) {
+ fprintf(stderr, "fill calloc for %d bytes failed\n",
+ f_elems * elem_size);
+ goto fini;
+ }
+ }
+ if (sgl_fn) {
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+ char s[128];
+
+ fp = fopen(sgl_fn, "w");
+ if (NULL == fp) {
+ err = errno;
+ fprintf(stderr, "Unable to open %s, error: %s\n", sgl_fn,
+ strerror(err));
+ res = sg_convert_errno(err);
+ goto fini;
+ }
+ strftime(s, sizeof(s), "%c", tm);
+ fprintf(fp, "# Scatter gather list generated by sg_iovec_tst "
+ "%s\n#\n", s);
+ }
+
+ dxfer_len = num_blks * blk_size;
+ buffp = (uint8_t *)calloc(num_blks, blk_size);
+ if (buffp) {
+ int dx_len;
+ int64_t curr_blk = from_skip ? start_blk : 0;
+
+ if (do_sgv4) {
+ if (sg_read(sg_fd, buffp, num_blks, (int)start_blk, blk_size,
+ elem_size, do_async))
+ goto free_buff;
+ } else {
+ if (sg_read_v4(sg_fd, buffp, num_blks, (int)start_blk, blk_size,
+ elem_size, do_async))
+ goto free_buff;
+ }
+ if (f_elems > 0) {
+ int fill_len = f_elems * elem_size;
+
+ for (dx_len = 0; dx_len < dxfer_len; dx_len += elem_size) {
+ if (write(fd, buffp + dx_len, elem_size) < 0) {
+ perror(ME "partial dxfer output write failed");
+ break;
+ }
+ if (sgl_fn) {
+ fprintf(fp, "%" PRId64 ",1\n", curr_blk);
+ curr_blk += f_elems + 1;
+ }
+ if (write(fd, fillp, fill_len) < 0) {
+ perror(ME "partial fill output write failed");
+ break;
+ }
+ }
+ } else if (write(fd, buffp, dxfer_len) < 0)
+ perror(ME "full output write failed");
+ else if (sgl_fn) {
+ for (dx_len = 0; dx_len < dxfer_len; dx_len += elem_size)
+ fprintf(fp, "%" PRId64 ",1\n", curr_blk++);
+ }
+free_buff:
+ free(buffp);
+ } else
+ fprintf(stderr, "user space calloc for %d bytes failed\n",
+ dxfer_len);
+ res = close(fd);
+ if (res < 0) {
+ perror(ME "output file close error");
+ close(sg_fd);
+ return 1;
+ }
+fini:
+ res2 = close(sg_fd);
+ if (res2 < 0) {
+ err = errno;
+ perror(ME "sg device close error");
+ if (0 == res)
+ res = sg_convert_errno(err);
+ }
+ if (fp)
+ fclose(fp);
+ return res;
+}
diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp
index f304eb51..27424a02 100644
--- a/testing/sg_mrq_dd.cpp
+++ b/testing/sg_mrq_dd.cpp
@@ -30,7 +30,7 @@
*
*/
-static const char * version_str = "1.15 20201012";
+static const char * version_str = "1.16 20201105";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -241,6 +241,7 @@ struct global_collection /* one instance visible to all threads */
off_t outreg_st_size;
atomic<int> dio_incomplete_count;
atomic<int> sum_of_resids;
+ atomic<int> reason_res;
int verbose;
int dry_run;
bool mrq_eq_0; /* true when user gives mrq=0 */
@@ -279,7 +280,6 @@ typedef struct request_element
uint8_t sb[SENSE_BUFF_LEN];
int dio_incomplete_count;
int mmap_active;
- int resid;
int rd_p_id;
int rep_count;
int rq_id;
@@ -853,7 +853,7 @@ usage(int pg_num)
" from dd it defaults to stdout). If 'of=.' "
"uses /dev/null\n"
" oflag comma separated list from: [append,nocreat,\n"
- " <<list from iflag>>]\n"
+ " <<list from iflag>>]\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"
@@ -1212,7 +1212,7 @@ read_write_thread(struct global_collection * clp, int id, bool singleton)
if (clp->in_flags.random) {
ssize_t ssz;
- ssz = getrandom(&rep->seed, sizeof(rep->seed), 0);
+ ssz = getrandom(&rep->seed, sizeof(rep->seed), GRND_NONBLOCK);
if (ssz < (ssize_t)sizeof(rep->seed))
pr2serr_lk("[%d] %s: getrandom() failed, ret=%d\n", id, __func__,
(int)ssz);
@@ -1398,6 +1398,7 @@ fini:
clp->out_rem_count -= rep->out_local_count;
clp->in_partial += rep->in_local_partial;
clp->out_partial += rep->out_local_partial;
+ clp->sum_of_resids += rep->in_resid_bytes;
if (rep->alloc_bp)
free(rep->alloc_bp);
}
@@ -1665,6 +1666,7 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
int n_cmpl = ctl_v4p->info;
int n_good = 0;
int hole_count = 0;
+ int cat = 0;
int vb = clp->verbose;
int k, j, f1, slen, sstatus;
char b[160];
@@ -1731,7 +1733,8 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
if (ssh.response_code & 0x1) {
ok = true;
last_err_on_in = false;
- }
+ } else
+ cat = sg_err_category_sense(sbp, slen);
if (SPC_SK_MISCOMPARE == ssh.sense_key)
++num_miscompare;
@@ -1739,7 +1742,8 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
if (vb)
lk_chk_n_print4(" >>", a_v4p, vb > 4);
}
- }
+ } else if (! ok)
+ cat = SG_LIB_CAT_OTHER;
if (ok && f1) {
++n_good;
if (a_v4p->dout_xfer_len >= (uint32_t)clp->bs)
@@ -1775,6 +1779,8 @@ process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
if (all_good)
pr2serr_lk(" ... all good\n");
fini:
+ if (cat > 0)
+ clp->reason_res.store(cat);
return n_good;
}
@@ -4016,5 +4022,7 @@ fini:
(num_miscompare > 1) ? "s" : "", num_miscompare.load());
if (clp->verify && (SG_LIB_CAT_MISCOMPARE == res))
pr2serr("Verify/compare failed due to miscompare\n");
+ if (0 == res)
+ res = clp->reason_res.load();
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index b7381f44..9a53b98a 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -36,7 +36,7 @@
* renamed [20181221]
*/
-static const char * version_str = "1.95 20201012";
+static const char * version_str = "1.96 20201019";
#define _XOPEN_SOURCE 600
#ifndef _GNU_SOURCE
@@ -1200,7 +1200,7 @@ mrq_abort_thread(void * v_maip)
Mrq_abort_info l_mai = *(Mrq_abort_info *)v_maip;
struct sg_io_v4 ctl_v4;
- ssz = getrandom(&rn, sizeof(rn), 0);
+ ssz = getrandom(&rn, sizeof(rn), GRND_NONBLOCK);
if (ssz < (ssize_t)sizeof(rn))
pr2serr_lk("%s: getrandom() failed, returned %d\n", __func__,
(int)ssz);