sg_raw: fix --send bug when using stdin; work on sgs_dd
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@800 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/ChangeLog b/ChangeLog
index 6155902..49ca734 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,13 +2,14 @@
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 [20181217] [svn: r798]
+Changelog for sg3_utils-1.45 [20181220] [svn: r800]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (18-102r0)
- sg_write_buffer: allow comma and period separated
lists when input from stdin
- sg_format: add --dcrt used twice (FOV=1 DCRT=0)
+ - sg_raw: fix --send bug when using stdin
- sg_scan (win32): expand limits for big arrays
- rescan-scsi-bus: widen LUN 0 only scanning
- testing/sg_tst_async: fix free_list issue
diff --git a/doc/sg_raw.8 b/doc/sg_raw.8
index b6bdbcc..62fa3cc 100644
--- a/doc/sg_raw.8
+++ b/doc/sg_raw.8
@@ -1,4 +1,4 @@
-.TH SG_RAW "8" "May 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_RAW "8" "December 2018" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_raw \- send arbitrary SCSI command to a device
.SH SYNOPSIS
diff --git a/src/sg_raw.c b/src/sg_raw.c
index 9cc0ab2..33a85f7 100644
--- a/src/sg_raw.c
+++ b/src/sg_raw.c
@@ -39,7 +39,7 @@
#include "sg_pr2serr.h"
#include "sg_unaligned.h"
-#define SG_RAW_VERSION "0.4.27 (2018-06-27)"
+#define SG_RAW_VERSION "0.4.28 (2018-12-20)"
#define DEFAULT_TIMEOUT 20
#define MIN_SCSI_CDBSZ 6
@@ -540,7 +540,7 @@
fetch_dataout(struct opts_t * op, uint8_t ** free_buf, int * errp)
{
bool ok = false;
- int fd, len, err;
+ int fd, len, tot_len, boff, err;
uint8_t *buf = NULL;
*free_buf = NULL;
@@ -574,28 +574,29 @@
}
}
- buf = sg_memalign(op->dataout_len, 0 /* page_size */, free_buf,
- op->verbose > 3);
+ tot_len = op->dataout_len;
+ buf = sg_memalign(tot_len, 0 /* page_size */, free_buf, op->verbose > 3);
if (buf == NULL) {
- pr2serr("sg_memalign: failed to get %d bytes of memory\n",
- op->dataout_len);
+ pr2serr("sg_memalign: failed to get %d bytes of memory\n", tot_len);
if (errp)
*errp = sg_convert_errno(ENOMEM);
goto bail;
}
- len = read(fd, buf, op->dataout_len);
- if (len < 0) {
- err = errno;
- if (errp)
- *errp = sg_convert_errno(err);
- perror("Failed to read input data");
- goto bail;
- } else if (len < op->dataout_len) {
- if (errp)
- *errp = SG_LIB_FILE_ERROR;
- pr2serr("EOF on input file/stream\n");
- goto bail;
+ for (boff = 0; boff < tot_len; boff += len) {
+ len = read(fd, buf + boff , tot_len - boff);
+ if (len < 0) {
+ err = errno;
+ if (errp)
+ *errp = sg_convert_errno(err);
+ perror("Failed to read input data");
+ goto bail;
+ } else if (0 == len) {
+ if (errp)
+ *errp = SG_LIB_FILE_ERROR;
+ pr2serr("EOF on input file/stream at buffer offset %d\n", boff);
+ goto bail;
+ }
}
ok = true;
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index 3d1a107..15c4a4b 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -88,7 +88,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.06 20181215";
+static const char * version_str = "1.08 20181220";
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wclobbered"
@@ -141,6 +141,7 @@
bool fua;
bool mmap;
bool noshare;
+ bool noxfer;
bool v3;
bool v4;
};
@@ -152,6 +153,7 @@
int in_type;
int cdbsz_in;
int help;
+ int elem_sz;
struct flags_t in_flags;
int64_t in_blk; /* -\ next block address to read */
int64_t in_count; /* | blocks remaining for next read */
@@ -180,6 +182,7 @@
int sum_of_resids; /* -/ */
int debug; /* both -v and deb=VERB bump this field */
int dry_run;
+ bool ofile_given;
const char * infp;
const char * outfp;
} Gbl_coll;
@@ -240,7 +243,7 @@
static bool shutting_down = false;
static bool do_sync = false;
-static bool do_time = false;
+static bool do_time = true;
static Gbl_coll gcoll;
static struct timeval start_tm;
static int64_t dd_count = -1;
@@ -479,9 +482,10 @@
" [--help] [--version]\n\n");
pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] "
"[deb=VERB] [dio=0|1]\n"
- " [fua=0|1|2|3] [of2=OFILE2] [sync=0|1] [thr=THR] "
- "[time=0|1]\n"
- " [verbose=VERB] [--dry-run] [--verbose]\n\n"
+ " [elemsz_kb=ESK] [fua=0|1|2|3] [of2=OFILE2] "
+ "[sync=0|1]\n"
+ " [thr=THR] [time=0|1] [verbose=VERB] [--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"
@@ -489,13 +493,14 @@
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [2fds,coe,defres,dio,"
"direct,dpo,\n"
- " dsync,excl,fua,mmap,noshare,null,v3,v4]\n"
- " of file or device to write to (def: stdout), "
- "OFILE of '.'\n"
- " treated as /dev/null\n"
+ " dsync,excl,fua,mmap,noshare,noxfer,null,v3,v4]\n"
+ " of file or device to write to (def: /dev/null which "
+ "is different\n"
+ " from dd that defaults to stdout). If 'of=.' "
+ "assumes /dev/null\n"
" oflag comma separated list from: [2fds,append,coe,dio,"
"direct,dpo,\n"
- " dsync,excl,fua,mmap,noshare,null,v3,v4]\n"
+ " dsync,excl,fua,mmap,noshare,noxfer,null,v3,v4]\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"
@@ -503,7 +508,9 @@
"Copy from IFILE to OFILE, similar to dd command. This utility "
"is specialized\nfor SCSI devices and uses multiple POSIX "
"threads. It expects one or both\nIFILE and OFILE to be sg "
- "devices. Use '-hh' or '-hhh' for more information.\n"
+ "devices. It is Linux specific and uses the v4\nsg driver "
+ "'share' capbility if available (hence the 'sgs' part of its "
+ "name).\nUse '-hh' or '-hhh' for more information.\n"
);
return;
page2:
@@ -520,6 +527,8 @@
" deb for debug, 0->none (def), > 0->varying degrees "
"of debug\n"
" dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
+ " elemsz_kb scatter gather list element size in kilobytes "
+ "(def: 32 [KB])\n"
" fua force unit access: 0->don't(def), 1->OFILE, "
"2->IFILE,\n"
" 3->OFILE+IFILE\n"
@@ -530,8 +539,8 @@
"after copy\n"
" thr is number of threads, must be > 0, default 4, "
"max 16\n"
- " time 0->no timing(def), 1->time plus calculate "
- "throughput\n"
+ " time 0->no timing, 1->time plus calculate "
+ "throughput (def)\n"
" verbose same as 'deb=VERB': increase verbosity\n"
" --dry-run|-d prepare but bypass copy/read\n"
" --verbose|-v increase verbosity of utility\n\n"
@@ -770,7 +779,7 @@
rep->in_flags = clp->in_flags;
rep->out_flags = clp->out_flags;
if (rep->in_flags.fds2 || rep->out_flags.fds2)
- ;
+ ; /* we are sharing a single pair of fd_s across all threads */
else {
int fd;
@@ -1255,6 +1264,7 @@
bool dpo = wr ? rep->out_flags.dpo : rep->in_flags.dpo;
bool dio = wr ? rep->out_flags.dio : rep->in_flags.dio;
bool mmap = wr ? rep->out_flags.mmap : rep->in_flags.mmap;
+ bool noxfer = wr ? rep->out_flags.noxfer : rep->in_flags.noxfer;
bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4;
int cdbsz = wr ? rep->cdbsz_out : rep->cdbsz_in;
int flags = 0;
@@ -1275,6 +1285,8 @@
flags |= SG_FLAG_MMAP_IO;
c3p = " mmap";
}
+ if (noxfer)
+ flags |= SG_FLAG_NO_DXFER;
if (dio)
flags |= SG_FLAG_DIRECT_IO;
if (rep->has_share) {
@@ -1496,7 +1508,8 @@
/* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
static int
-sg_prepare(int fd, int bs, int bpt, bool def_res, uint8_t **mmpp)
+sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
+ uint8_t **mmpp)
{
int res, t, num;
uint8_t *mmp;
@@ -1506,6 +1519,27 @@
pr2serr_lk("%ssg driver prior to 3.9.02\n", my_name);
return 0;
}
+ if (elem_sz >= 4096) {
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
+
+ seip = &sei;
+ memset(seip, 0, sizeof(*seip));
+ seip->valid_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
+ res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
+ if (res < 0)
+ pr2serr_lk("sgs_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->sgat_elem_sz = elem_sz;
+ res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
+ if (res < 0)
+ pr2serr_lk("sgs_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) "
+ "wr error: %s\n", __func__, strerror(errno));
+ }
+ }
if (! def_res) {
num = bs * bpt;
res = ioctl(fd, SG_SET_RESERVED_SIZE, &num);
@@ -1570,6 +1604,8 @@
fp->mmap = true;
else if (0 == strcmp(cp, "noshare"))
fp->noshare = true;
+ else if (0 == strcmp(cp, "noxfer"))
+ fp->noxfer = true;
else if (0 == strcmp(cp, "null"))
;
else if (0 == strcmp(cp, "v3"))
@@ -1620,7 +1656,8 @@
perror(ebuff);
return -sg_convert_errno(err);;
}
- n = sg_prepare(fd, clp->bs, clp->bpt, clp->in_flags.defres, mmpp);
+ n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->in_flags.defres,
+ clp->elem_sz, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -1649,7 +1686,8 @@
perror(ebuff);
return -sg_convert_errno(err);
}
- n = sg_prepare(fd, clp->bs, clp->bpt, clp->out_flags.defres, mmpp);
+ n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->out_flags.defres,
+ clp->elem_sz, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -1698,7 +1736,8 @@
memset(thread_arr, 0, sizeof(thread_arr));
clp->bpt = DEF_BLOCKS_PER_TRANSFER;
clp->in_type = FT_OTHER;
- clp->out_type = FT_OTHER;
+ /* change dd's default: if of=OFILE not given, assume /dev/null */
+ clp->out_type = FT_DEV_NULL;
clp->cdbsz_in = DEF_SCSI_CDBSZ;
clp->cdbsz_out = DEF_SCSI_CDBSZ;
inf[0] = '\0';
@@ -1751,6 +1790,13 @@
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")) {
+ 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")) {
n = sg_get_num(buf);
if (n & 1)
@@ -1987,6 +2033,8 @@
"device\n", my_name);
}
}
+ if (outf[0])
+ clp->ofile_given = true;
if (outf[0] && ('-' != outf[0])) {
clp->out_type = dd_filetype(outf);
@@ -2203,6 +2251,10 @@
pr2serr("Due to --dry-run option, bypass copy/read\n");
goto fini;
}
+ if (! clp->ofile_given)
+ pr2serr("of=OFILE not given so only read from IFILE, to output to "
+ "stdout use 'of=-'\n");
+
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGINT);
status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);