aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-12-13 18:50:10 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-12-13 18:50:10 +0000
commitd906e8cb000e95d9260d1833d3692c1c763e489a (patch)
tree8c1c3a3fc6aebf2751670d64f8389ca0ca8aa4b3
parent4445eeca7f024eb55a9d5eb5ee6a7183816f0c2e (diff)
downloadsg3_utils-d906e8cb000e95d9260d1833d3692c1c763e489a.tar.gz
sg_format: add --dcrt used twice (FOV=1 DCRT=0); sg_pt_linux: uses sg v4 interface if sg driver >= 4.0.0
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@798 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog11
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure13
-rw-r--r--configure.ac4
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg3_utils.82
-rw-r--r--doc/sg_format.816
-rw-r--r--include/sg_io_linux.h10
-rw-r--r--include/sg_pt_linux.h26
-rw-r--r--lib/sg_io_linux.c5
-rw-r--r--lib/sg_pt_linux.c109
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_format.c53
-rw-r--r--testing/sgs_dd.c208
-rw-r--r--testing/uapi_sg.h25
15 files changed, 388 insertions, 101 deletions
diff --git a/ChangeLog b/ChangeLog
index 42d67de5..3cbdca10 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,18 +2,25 @@ 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 [20181207] [svn: r797]
+Changelog for sg3_utils-1.45 [20181213] [svn: r797]
- 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_scan (win32): expand limits for big arrays
- rescan-scsi-bus: widen LUN 0 only scanning
- testing/sg_tst_async: fix free_list issue
- testing/sg_tst_ioctl: for sg 3.9 driver
- testing/sgs_dd: for share in sg 3.9.02 driver
- - add: SPDX-License-Identifier: BSD-2-Clause
+ - sg_io_linux (sg_lib): add sg_linux_sense_print()
+ - sg_pt_linux: uses sg v4 interface if sg driver
+ >= 4.0.0 . Force sg v3 always by building with
+ './configure --disable-linux-sgv4'
+ - add sg_linux_get_sg_version() function
+ - add: 'SPDX-License-Identifier: BSD-2-Clause'
+ or a small number of 'GPL-2.0-or-later'
Changelog for sg3_utils-1.44 [20180912] [svn: r791]
- same code as release 1.43 20180911 svn rev 789;
diff --git a/config.h.in b/config.h.in
index ab0eb007..1aa1e952 100644
--- a/config.h.in
+++ b/config.h.in
@@ -81,6 +81,9 @@
/* option ignored */
#undef IGNORE_LINUX_BSG
+/* even if Linux sg v4 available, use v3 instead */
+#undef IGNORE_LINUX_SGV4
+
/* compile out NVMe support */
#undef IGNORE_NVME
diff --git a/configure b/configure
index 62f87c57..b73d8102 100755
--- a/configure
+++ b/configure
@@ -791,6 +791,7 @@ enable_win32_spt_direct
enable_scsistrings
enable_nvme_supp
enable_fast_lebe
+enable_linux_sgv4
'
ac_precious_vars='build_alias
host_alias
@@ -1453,6 +1454,8 @@ Optional Features:
strings
--disable-nvme-supp remove all or most NVMe code
--disable-fast-lebe use generic little-endian/big-endian code instead
+ --disable-linux-sgv4 for Linux sg driver avoid v4 interface even if
+ available
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -12793,6 +12796,16 @@ _ACEOF
fi
+# Check whether --enable-linux-sgv4 was given.
+if test "${enable_linux_sgv4+set}" = set; then :
+ enableval=$enable_linux_sgv4;
+cat >>confdefs.h <<_ACEOF
+#define IGNORE_LINUX_SGV4 1
+_ACEOF
+
+fi
+
+
ac_config_files="$ac_config_files Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile"
diff --git a/configure.ac b/configure.ac
index eb3e22e9..c9dbd4f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,6 +128,10 @@ AC_ARG_ENABLE([fast-lebe],
AC_HELP_STRING([--disable-fast-lebe], [use generic little-endian/big-endian code instead]),
[AC_DEFINE_UNQUOTED(IGNORE_FAST_LEBE, 1, [use generic little-endian/big-endian instead], )], [])
+AC_ARG_ENABLE([linux-sgv4],
+ AC_HELP_STRING([--disable-linux-sgv4], [for Linux sg driver avoid v4 interface even if available]),
+ [AC_DEFINE_UNQUOTED(IGNORE_LINUX_SGV4, 1, [even if Linux sg v4 available, use v3 instead], )], [])
+
AC_OUTPUT(Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile)
diff --git a/debian/changelog b/debian/changelog
index 7a816700..242f6403 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.45-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Fri, 14 Sep 2018 11:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Wed, 12 Dec 2018 22:00:00 -0500
sg3-utils (1.44-0.1) unstable; urgency=low
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 4ac930f0..9bf46d4a 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "November 2018" "sg3_utils\-1.45" SG3_UTILS
+.TH SG3_UTILS "8" "December 2018" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
diff --git a/doc/sg_format.8 b/doc/sg_format.8
index d1d3fdef..82a62c2b 100644
--- a/doc/sg_format.8
+++ b/doc/sg_format.8
@@ -1,4 +1,4 @@
-.TH SG_FORMAT "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_FORMAT "8" "December 2018" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_format \- format, resize a SCSI disk or format a tape
.SH SYNOPSIS
@@ -113,10 +113,16 @@ See NOTES section below.
\fB\-D\fR, \fB\-\-dcrt\fR
this option sets the DCRT bit in the FORMAT UNIT command's parameter list
header. It will "disable certification". Certification verifies that blocks
-are usable during the format process. Using this option may speed the format.
-The default action of this utility (i.e. when this option is not given) is
-to clear the DCRT bit thereby requesting "media certification". When the DCRT
-bit is set, the FOV bit must also be set hence sg_format does that.
+are usable during the format process. Using this option may speed the format
+but \fI\-\-ffmt=FFMT\fR, if available, would probably be better. The default
+action of this utility (i.e. when this option is not given) is to clear the
+DCRT bit thereby requesting "media certification" (also unless another
+option needs it, the FOV bit will be cleared). When the DCRT bit is set, the
+FOV bit must also be set hence sg_format does that.
+.br
+If this option is given twice then certification is enabled by clearing the
+DCRT bit and setting the FOV bit. Both these bits are found in the parameter
+list associated with the FORMAT UNIT cdb.
.TP
\fB\-d\fR, \fB\-\-dry\-run\fR
this option will parse the command line, do all the preparation but bypass
diff --git a/include/sg_io_linux.h b/include/sg_io_linux.h
index afbd3657..4766e2ae 100644
--- a/include/sg_io_linux.h
+++ b/include/sg_io_linux.h
@@ -11,7 +11,7 @@
*/
/*
- * Version 1.06 [20180119]
+ * Version 1.07 [20181211]
*/
/*
@@ -160,6 +160,14 @@ struct sg_io_hdr;
int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp,
bool raw_sinfo);
+/* Returns 1 if no errors found and thus nothing printed; otherwise
+ * prints error/warning (prefix by 'leadin') to stderr (pr2ws) and
+ * returns 0. */
+int sg_linux_sense_print(const char * leadin, int scsi_status,
+ int host_status, int driver_status,
+ const uint8_t * sense_buffer, int sb_len,
+ bool raw_sinfo);
+
/* Calls sg_scsi_normalize_sense() after obtaining the sense buffer and
its length from the struct sg_io_hdr pointer. If these cannot be
obtained, false is returned. */
diff --git a/include/sg_pt_linux.h b/include/sg_pt_linux.h
index bf1a1691..eb451e8d 100644
--- a/include/sg_pt_linux.h
+++ b/include/sg_pt_linux.h
@@ -42,6 +42,25 @@ extern "C" {
#define BSG_FLAG_Q_AT_TAIL 0x10 /* default is Q_AT_HEAD */
#define BSG_FLAG_Q_AT_HEAD 0x20
+#ifndef SGV4_FLAG_YIELD_TAG
+#define SGV4_FLAG_YIELD_TAG 0x8
+#endif
+#ifndef SGV4_FLAG_FIND_BY_TAG
+#define SGV4_FLAG_FIND_BY_TAG 0x100
+#endif
+#ifndef SGV4_FLAG_IMMED
+#define SGV4_FLAG_IMMED 0x400
+#endif
+#ifndef SGV4_FLAG_IMMED
+#define SGV4_FLAG_IMMED 0x400
+#endif
+#ifndef SGV4_FLAG_DEV_SCOPE
+#define SGV4_FLAG_DEV_SCOPE 0x1000
+#endif
+#ifndef SGV4_FLAG_SHARE
+#define SGV4_FLAG_SHARE 0x2000
+#endif
+
struct sg_io_v4 {
__s32 guard; /* [i] 'Q' to differentiate from v3 */
__u32 protocol; /* [i] 0 -> SCSI , .... */
@@ -50,10 +69,10 @@ struct sg_io_v4 {
__u32 request_len; /* [i] in bytes */
__u64 request; /* [i], [*i] {SCSI: cdb} */
- __u64 request_tag; /* [i] {SCSI: task tag (only if flagged)} */
+ __u64 request_tag; /* [i] {in sg 4.0+ this is out parameter} */
__u32 request_attr; /* [i] {SCSI: task attribute} */
__u32 request_priority; /* [i] {SCSI: task priority} */
- __u32 request_extra; /* [i] {spare, for padding} */
+ __u32 request_extra; /* [i] {used for pack_id} */
__u32 max_response_len; /* [i] in bytes */
__u64 response; /* [i], [*o] {SCSI: (auto)sense data} */
@@ -106,6 +125,7 @@ struct sg_pt_linux_scsi {
int dev_fd; /* -1 if not given (yet) */
int in_err;
int os_err;
+ int sg_version; /* for deciding whether to use v3 or v4 interface */
uint32_t nvme_nsid; /* 1 to 0xfffffffe are possibly valid, 0
* implies dev_fd is not a NVMe device
* (is_nvme=false) or it is a NVMe char
@@ -159,6 +179,7 @@ extern long sg_lin_page_size;
void sg_find_bsg_nvme_char_major(int verbose);
int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb);
+int sg_linux_get_sg_version(const struct sg_pt_base * vp);
/* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5)
* to the name of its associated char device (e.g. /dev/nvme0). If this
@@ -167,7 +188,6 @@ int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb);
bool sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len,
char * b);
-
#ifdef __cplusplus
}
#endif
diff --git a/lib/sg_io_linux.c b/lib/sg_io_linux.c
index 127a49e7..15e684e2 100644
--- a/lib/sg_io_linux.c
+++ b/lib/sg_io_linux.c
@@ -96,8 +96,9 @@ sg_print_driver_status(int driver_status)
}
/* Returns 1 if no errors found and thus nothing printed; otherwise
- prints error/warning (prefix by 'leadin') and returns 0. */
-static int
+ * prints error/warning (prefix by 'leadin') to stderr (pr2ws) and
+ * returns 0. */
+int
sg_linux_sense_print(const char * leadin, int scsi_status, int host_status,
int driver_status, const uint8_t * sense_buffer,
int sb_len, bool raw_sinfo)
diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c
index f3cb6ea0..1f43e227 100644
--- a/lib/sg_pt_linux.c
+++ b/lib/sg_pt_linux.c
@@ -7,7 +7,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
-/* sg_pt_linux version 1.43 20180603 */
+/* sg_pt_linux version 1.44 20181212 */
#include <stdio.h>
@@ -55,6 +55,9 @@
#define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */
+/* sg driver displayed format: [x]xyyzz --> [x]x.[y]y.zz */
+#define SG_LINUX_SG_VER_V4 40000 /* lowest version in which v4 available */
+
static const char * linux_host_bytes[] = {
"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
"DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
@@ -482,11 +485,37 @@ set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
sg_find_bsg_nvme_char_major(verbose);
}
ptp->dev_fd = dev_fd;
- if (dev_fd >= 0)
+ if (dev_fd >= 0) {
ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg,
&ptp->is_nvme, &ptp->nvme_nsid,
&ptp->os_err, verbose);
- else {
+ if (ptp->is_sg) {
+ 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));
+ }
+ if (verbose > 4) {
+ int ver = ptp->sg_version;
+
+ if (ptp->sg_version >= SG_LINUX_SG_VER_V4) {
+#ifdef IGNORE_LINUX_SGV4
+ pr2ws("%s: sg driver version %d.%02d.%02d but config "
+ "override back to v3\n", __func__, ver / 10000,
+ (ver / 100) % 100, ver % 100);
+#else
+ pr2ws("%s: sg driver version %d.%02d.%02d so choose v4\n",
+ __func__, ver / 10000, (ver / 100) % 100,
+ ver % 100);
+#endif
+ } else if (verbose > 5)
+ pr2ws("%s: sg driver version %d.%02d.%02d so choose v3\n",
+ __func__, ver / 10000, (ver / 100) % 100,
+ ver % 100);
+ }
+ }
+ } else {
ptp->is_sg = false;
ptp->is_bsg = false;
ptp->is_nvme = false;
@@ -497,6 +526,14 @@ set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
return ptp->os_err;
}
+int
+sg_linux_get_sg_version(const struct sg_pt_base * vp)
+{
+ const struct sg_pt_linux_scsi * ptp = &vp->impl;
+
+ return ptp->sg_version;
+}
+
/* Valid file handles (which is the return value) are >= 0 . Returns -1
* if there is no valid file handle. */
int
@@ -580,7 +617,7 @@ set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
{
struct sg_pt_linux_scsi * ptp = &vp->impl;
- ptp->io_hdr.spare_in = pack_id;
+ ptp->io_hdr.request_extra = pack_id; /* was place in spare_in */
}
void
@@ -849,7 +886,7 @@ do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
v3_hdr.sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
v3_hdr.mx_sb_len = (uint8_t)ptp->io_hdr.max_response_len;
}
- v3_hdr.pack_id = (int)ptp->io_hdr.spare_in;
+ v3_hdr.pack_id = (int)ptp->io_hdr.request_extra;
if (BSG_FLAG_Q_AT_HEAD & ptp->io_hdr.flags)
v3_hdr.flags |= SG_FLAG_Q_AT_HEAD; /* favour AT_HEAD */
else if (BSG_FLAG_Q_AT_TAIL & ptp->io_hdr.flags)
@@ -857,7 +894,7 @@ do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
if (NULL == v3_hdr.cmdp) {
if (verbose)
- pr2ws("No SCSI command (cdb) given\n");
+ pr2ws("No SCSI command (cdb) given [v3]\n");
return SCSI_PT_DO_BAD_PARAMS;
}
/* io_hdr.timeout is in milliseconds, if greater than zero */
@@ -880,6 +917,28 @@ do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
return 0;
}
+/* Executes SCSI command using sg v4 interface */
+static int
+do_scsi_pt_v4(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
+ int verbose)
+{
+ if (0 == ptp->io_hdr.request) {
+ if (verbose)
+ pr2ws("No SCSI command (cdb) given [v4]\n");
+ return SCSI_PT_DO_BAD_PARAMS;
+ }
+ /* io_hdr.timeout is in milliseconds, if greater than zero */
+ ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
+ if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
+ ptp->os_err = errno;
+ if (verbose > 1)
+ pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n",
+ safe_strerror(ptp->os_err), ptp->os_err);
+ return -ptp->os_err;
+ }
+ return 0;
+}
+
/* Executes SCSI command (or at least forwards it to lower layers).
* Returns 0 for success, negative numbers are negated 'errno' values from
* OS system calls. Positive return values are errors from this package. */
@@ -922,36 +981,22 @@ do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
return -ptp->os_err;
if (ptp->is_nvme)
return sg_do_nvme_pt(vp, -1, time_secs, verbose);
- else if (sg_bsg_major <= 0)
+ else if (ptp->is_sg) {
+#ifdef IGNORE_LINUX_SGV4
+ return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
+#else
+ if (ptp->sg_version >= SG_LINUX_SG_VER_V4)
+ return do_scsi_pt_v4(ptp, fd, time_secs, verbose);
+ else
+ return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
+#endif
+ } else if (sg_bsg_major <= 0)
return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
else if (ptp->is_bsg)
- ; /* drop through to sg v4 implementation */
+ return do_scsi_pt_v4(ptp, fd, time_secs, verbose);
else
return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
- if (! ptp->io_hdr.request) {
- if (verbose)
- pr2ws("No SCSI command (cdb) given (v4)\n");
- return SCSI_PT_DO_BAD_PARAMS;
- }
- /* io_hdr.timeout is in milliseconds */
- ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) :
- DEF_TIMEOUT);
-#if 0
- /* sense buffer already zeroed */
- if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
- void * p;
-
- p = (void *)(sg_uintptr_t)ptp->io_hdr.response;
- memset(p, 0, ptp->io_hdr.max_response_len);
- }
-#endif
- if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
- ptp->os_err = errno;
- if (verbose > 1)
- pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n",
- safe_strerror(ptp->os_err), ptp->os_err);
- return -ptp->os_err;
- }
+ pr2ws("%s: Should never reach this point\n", __func__);
return 0;
}
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 4f80b101..7f11f8ce 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -84,7 +84,7 @@ fi
%{_libdir}/*.la
%changelog
-* Fri Sep 14 2018 - dgilbert at interlog dot com
+* Wed Dec 12 2018 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.45
diff --git a/src/sg_format.c b/src/sg_format.c
index 8113b097..092b55d7 100644
--- a/src/sg_format.c
+++ b/src/sg_format.c
@@ -40,7 +40,7 @@
#include "sg_pr2serr.h"
#include "sg_pt.h"
-static const char * version_str = "1.55 20180830";
+static const char * version_str = "1.56 20181212";
#define RW_ERROR_RECOVERY_PAGE 1 /* can give alternate with --mode=MP */
@@ -77,7 +77,6 @@ static const char * version_str = "1.55 20180830";
struct opts_t {
bool cmplst; /* -C value */
bool cmplst_given;
- bool dcrt; /* -D */
bool dry_run; /* -d */
bool early; /* -e */
bool fwait; /* -w (negate for immed) */
@@ -94,6 +93,7 @@ struct opts_t {
bool verbose_given;
bool verify; /* -y */
bool version_given;
+ int dcrt; /* -D (can be given once or twice) */
int lblk_sz; /* -s value */
int ffmt; /* -t value; fast_format if > 0 */
int fmtpinfo;
@@ -172,6 +172,8 @@ usage()
"same as current\n"
" --dcrt|-D disable certification (doesn't "
"verify media)\n"
+ " use twice to enable certification and "
+ "set FOV bit\n"
" --dry-run|-d bypass device modifying commands (i.e. "
"don't format)\n"
" --early|-e exit once format started (user can "
@@ -303,7 +305,7 @@ sg_ll_format_medium(int sg_fd, bool verify, bool immed, int format,
static int
scsi_format_unit(int fd, const struct opts_t * op)
{
- bool need_hdr, longlist, ip_desc;
+ bool need_param_lst, longlist, ip_desc;
bool immed = ! op->fwait;
int res, progress, pr, rem, param_sz, off, resp_len, tmout;
int poll_wait_secs;
@@ -339,8 +341,10 @@ scsi_format_unit(int fd, const struct opts_t * op)
off = longlist ? LONG_FORMAT_HEADER_SZ : SH_FORMAT_HEADER_SZ;
param[0] = op->pfu & 0x7; /* PROTECTION_FIELD_USAGE (bits 2-0) */
param[1] = (immed ? 0x2 : 0); /* FOV=0, [DPRY,DCRT,STPF,IP=0] */
- if (op->dcrt)
+ if (1 == op->dcrt)
param[1] |= 0xa0; /* FOV=1, DCRT=1 */
+ else if (op->dcrt > 1)
+ param[1] |= 0x80; /* FOV=1, DCRT=0 */
if (ip_desc) {
param[1] |= 0x88; /* FOV=1, IP=1 */
if (op->sec_init)
@@ -350,9 +354,9 @@ scsi_format_unit(int fd, const struct opts_t * op)
param[3] = (op->pie & 0xf);/* PROTECTION_INTERVAL_EXPONENT */
/* with the long parameter list header, P_I_INFORMATION is always 0 */
- need_hdr = (immed || op->cmplst || op->dcrt || ip_desc ||
- (op->pfu > 0) || (op->pie > 0));
- param_sz = need_hdr ?
+ need_param_lst = (immed || op->cmplst || (op->dcrt > 0) || ip_desc ||
+ (op->pfu > 0) || (op->pie > 0));
+ param_sz = need_param_lst ?
(off + (ip_desc ? INIT_PATTERN_DESC_SZ : 0)) : 0;
if (op->dry_run) {
@@ -360,7 +364,7 @@ scsi_format_unit(int fd, const struct opts_t * op)
pr2serr("Due to --dry-run option bypassing FORMAT UNIT "
"command\n");
if (vb) {
- if (need_hdr) {
+ if (need_param_lst) {
pr2serr(" FU would have received parameter "
"list: ");
hex2stderr(param, max_param_sz, -1);
@@ -370,13 +374,14 @@ scsi_format_unit(int fd, const struct opts_t * op)
pr2serr(" FU cdb fields: fmtpinfo=0x%x, "
"longlist=%d, fmtdata=%d, cmplst=%d, "
"ffmt=%d [timeout=%d secs]\n",
- op->fmtpinfo, longlist, need_hdr, op->cmplst,
- op->ffmt, tmout);
+ op->fmtpinfo, longlist, need_param_lst,
+ op->cmplst, op->ffmt, tmout);
}
} else
res = sg_ll_format_unit_v2(fd, op->fmtpinfo, longlist,
- need_hdr, op->cmplst, 0, op->ffmt,
- tmout, param, param_sz, true, vb);
+ need_param_lst, op->cmplst, 0,
+ op->ffmt, tmout, param, param_sz,
+ true, vb);
if (free_param)
free(free_param);
@@ -1074,7 +1079,7 @@ parse_cmd_line(struct opts_t * op, int argc, char **argv)
op->dry_run = true;
break;
case 'D':
- op->dcrt = true;
+ ++op->dcrt;
break;
case 'e':
op->early = true;
@@ -1328,9 +1333,14 @@ main(int argc, char **argv)
goto format_only;
ret = print_dev_id(fd, inq_resp, inq_resp_sz, op);
- if (ret)
- goto out;
- pdt = 0x1f & inq_resp[0];
+ if (ret) {
+ if (op->dry_run) {
+ pr2serr("INQUIRY failed, assume device is a disk\n");
+ pdt = 0;
+ } else
+ goto out;
+ } else
+ pdt = 0x1f & inq_resp[0];
if (op->format) {
if ((PDT_DISK != pdt) && (PDT_OPTICAL != pdt) &&
(PDT_RBC != pdt)) {
@@ -1350,9 +1360,14 @@ main(int argc, char **argv)
}
ret = fetch_block_desc(fd, dbuff, &calc_len, &bd_lb_sz, op);
- if (ret)
- goto out;
-
+ if (ret) {
+ if (op->dry_run) {
+ /* pick some numbers ... */
+ calc_len = 1024 * 1024 * 1024;
+ bd_lb_sz = 512;
+ } else
+ goto out;
+ }
rq_lb_sz = op->lblk_sz;
if (op->resize || (op->format && ((op->blk_count != 0) ||
((rq_lb_sz > 0) && (rq_lb_sz != bd_lb_sz))))) {
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index 95d36fc2..16aab4fa 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.04 20181207";
+static const char * version_str = "1.05 20181213";
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wclobbered"
@@ -141,6 +141,8 @@ struct flags_t {
bool fua;
bool mmap;
bool noshare;
+ bool v3;
+ bool v4;
};
typedef struct global_collection
@@ -195,6 +197,7 @@ typedef struct request_element
uint8_t * buffp;
uint8_t * alloc_bp;
struct sg_io_hdr io_hdr;
+ struct sg_io_v4 io_hdr4;
uint8_t cmd[MAX_SCSI_CDBSZ];
uint8_t sb[SENSE_BUFF_LEN];
int bs;
@@ -308,6 +311,17 @@ lk_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo)
pthread_mutex_unlock(&strerr_mut);
}
+
+static void
+lk_chk_n_print4(const char * leadin, struct sg_io_v4 * h4p, bool raw_sinfo)
+{
+ pthread_mutex_lock(&strerr_mut);
+ sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status,
+ h4p->driver_status, (const uint8_t *)h4p->response,
+ h4p->response_len, raw_sinfo);
+ pthread_mutex_unlock(&strerr_mut);
+}
+
static void
calc_duration_throughput(int contin)
{
@@ -474,13 +488,13 @@ usage(int pg_num)
" 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]\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"
" oflag comma separated list from: [2fds,append,coe,dio,"
"direct,dpo,\n"
- " dsync,excl,fua,mmap,noshare,null]\n"
+ " dsync,excl,fua,mmap,noshare,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"
@@ -545,8 +559,12 @@ page3:
" mmap setup mmap IO on IFILE or OFILE; OFILE only "
"with noshare\n"
" noshare if IFILE and OFILE are sg devices, don't set "
- "up share\n"
+ "up sharing\n"
" (def: do)\n"
+ " v3 use v3 sg interface which is the default (aslo "
+ "see v4)\n"
+ " v4 use v4 sg interface (def: v3 unless other side "
+ "us v4)\n"
"\n"
"If both are sg devices 'shared' mode is selected unless "
"'noshare' is given\nto 'iflag=' or 'oflag='. If 'of2=OFLAG2' "
@@ -916,6 +934,10 @@ fini:
if (own_outfd)
close(rep->outfd);
pthread_cond_broadcast(&clp->out_sync_cv);
+ if ((0 == rep->id) && is_first) {
+ is_first = false; /* allow rest of threads to start */
+ pthread_cond_broadcast(&clp->hold_1st_cv);
+ }
return stop_after_write ? NULL : clp;
}
@@ -1217,6 +1239,7 @@ sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep)
} /* end of while (1) loop */
}
+/* Returns 0 on success, 1 if ENOMEM error else -1 for other errors. */
static int
sg_start_io(Rq_elem * rep)
{
@@ -1225,9 +1248,12 @@ sg_start_io(Rq_elem * rep)
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 v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4;
int cdbsz = wr ? rep->cdbsz_out : rep->cdbsz_in;
+ int flags = 0;
int res, err;
struct sg_io_hdr * hp = &rep->io_hdr;
+ struct sg_io_v4 * h4p = &rep->io_hdr4;
const char * cp = "";
const char * c2p = "";
const char * c3p = "";
@@ -1238,31 +1264,19 @@ sg_start_io(Rq_elem * rep)
my_name, rep->blk, rep->num_blks);
return -1;
}
- memset(hp, 0, sizeof(struct sg_io_hdr));
- hp->interface_id = 'S';
- hp->cmd_len = cdbsz;
- hp->cmdp = rep->cmd;
- hp->dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
- hp->dxfer_len = rep->bs * rep->num_blks;
- hp->dxferp = rep->buffp;
- hp->mx_sb_len = sizeof(rep->sb);
- hp->sbp = rep->sb;
- hp->timeout = DEF_TIMEOUT;
- hp->usr_ptr = rep;
- hp->pack_id = (int)rep->blk;
if (mmap && (rep->out2fd >= 0)) {
- hp->flags |= SG_FLAG_MMAP_IO;
+ flags |= SG_FLAG_MMAP_IO;
c3p = " mmap";
}
if (dio)
- hp->flags |= SG_FLAG_DIRECT_IO;
+ flags |= SG_FLAG_DIRECT_IO;
if (rep->has_share) {
- hp->flags |= SGV4_FLAG_SHARE;
+ flags |= SGV4_FLAG_SHARE;
if (wr)
- hp->flags |= SGV4_FLAG_NO_DXFER;
+ flags |= SGV4_FLAG_NO_DXFER;
else if (rep->out2fd < 0)
- hp->flags |= SGV4_FLAG_NO_DXFER;
- if (hp->flags & SGV4_FLAG_NO_DXFER)
+ flags |= SGV4_FLAG_NO_DXFER;
+ if (flags & SGV4_FLAG_NO_DXFER)
c2p = " and FLAG_NO_DXFER";
cp = (wr ? " slave active" : " master active");
@@ -1272,8 +1286,24 @@ sg_start_io(Rq_elem * rep)
pr2serr_lk("%s tid=%d: SCSI %s%s%s%s, blk=%" PRId64 " num_blks=%d\n",
__func__, rep->id, (rep->wr ? "WRITE" : "READ"), cp,
c2p, c3p, rep->blk, rep->num_blks);
- lk_print_command(hp->cmdp);
+ lk_print_command(rep->cmd);
}
+ if (v4)
+ goto do_v4;
+
+ memset(hp, 0, sizeof(struct sg_io_hdr));
+ hp->interface_id = 'S';
+ hp->cmd_len = cdbsz;
+ hp->cmdp = rep->cmd;
+ hp->dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
+ hp->dxfer_len = rep->bs * rep->num_blks;
+ hp->dxferp = rep->buffp;
+ hp->mx_sb_len = sizeof(rep->sb);
+ hp->sbp = rep->sb;
+ hp->timeout = DEF_TIMEOUT;
+ hp->usr_ptr = rep;
+ hp->pack_id = (int)rep->blk;
+ hp->flags = flags;
while (((res = write(rep->wr ? rep->outfd : rep->infd, hp,
sizeof(struct sg_io_hdr))) < 0) &&
@@ -1288,6 +1318,37 @@ sg_start_io(Rq_elem * rep)
return -1;
}
return 0;
+do_v4:
+ memset(h4p, 0, sizeof(struct sg_io_v4));
+ h4p->guard = 'Q';
+ h4p->request_len = cdbsz;
+ h4p->request = (uint64_t)rep->cmd;
+ if (wr) {
+ h4p->dout_xfer_len = rep->bs * rep->num_blks;
+ h4p->dout_xferp = (uint64_t)rep->buffp;
+ } else if (rep->num_blks > 0) {
+ h4p->din_xfer_len = rep->bs * rep->num_blks;
+ h4p->din_xferp = (uint64_t)rep->buffp;
+ }
+ h4p->max_response_len = sizeof(rep->sb);
+ 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->flags = flags;
+ while (((res = ioctl(rep->wr ? rep->outfd : rep->infd, SG_IOSUBMIT,
+ h4p)) < 0) && ((EINTR == errno) ||
+ (EAGAIN == errno)))
+ ;
+ err = errno;
+ if (res < 0) {
+ if (ENOMEM == err)
+ return 1;
+ pr2serr_lk("%s tid=%d: %s%s%s ioctl(2) failed: %s\n", __func__,
+ rep->id, cp, c2p, c3p, strerror(err));
+ return -1;
+ }
+ return 0;
}
/* 0 -> successful, SG_LIB_CAT_UNIT_ATTENTION or SG_LIB_CAT_ABORTED_COMMAND
@@ -1296,13 +1357,17 @@ sg_start_io(Rq_elem * rep)
static int
sg_finish_io(bool wr, Rq_elem * rep)
{
+ bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4;
int res;
struct sg_io_hdr io_hdr;
struct sg_io_hdr * hp;
+ struct sg_io_v4 * h4p;
#if 0
static int testing = 0; /* thread dubious! */
#endif
+ if (v4)
+ goto do_v4;
memset(&io_hdr, 0 , sizeof(struct sg_io_hdr));
/* FORCE_PACK_ID active set only read packet with matching pack_id */
io_hdr.interface_id = 'S';
@@ -1359,6 +1424,67 @@ sg_finish_io(bool wr, Rq_elem * rep)
pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id,
wr ? "WRITE" : "READ");
return 0;
+
+do_v4:
+ h4p = &rep->io_hdr4;
+ while (((res = ioctl(wr ? rep->outfd : rep->infd, SG_IORECEIVE,
+ h4p)) < 0) && ((EINTR == errno) ||
+ (EAGAIN == errno)))
+ ;
+ if (res < 0) {
+ perror("finishing io on sg device, error");
+ return -1;
+ }
+ if (rep != (Rq_elem *)h4p->usr_ptr)
+ err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n");
+ res = sg_err_category_new(h4p->device_status, h4p->transport_status,
+ h4p->driver_status,
+ (const uint8_t *)h4p->response,
+ h4p->response_len);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ lk_chk_n_print4((wr ? "writing continuing":
+ "reading continuing"), h4p, false);
+ break;
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ if (rep->debug > 3)
+ lk_chk_n_print4((wr ? "writing": "reading"), h4p, false);
+ return res;
+ case SG_LIB_CAT_NOT_READY:
+ default:
+ {
+ char ebuff[EBUFF_SZ];
+
+ snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64,
+ wr ? "writing": "reading", rep->blk);
+ lk_chk_n_print4(ebuff, h4p, false);
+ return res;
+ }
+ }
+#if 0
+ if (0 == (++testing % 100)) return -1;
+#endif
+ if ((wr ? rep->out_flags.dio : rep->in_flags.dio) &&
+ (h4p->info & SG_INFO_DIRECT_IO))
+ rep->dio_incomplete_count = 1; /* count dios done as indirect IO */
+ else
+ 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,
+ wr ? "WRITE" : "READ");
+ if (rep->debug > 4)
+ pr2serr_lk(" info=0x%x sg_info_check=%d another_waiting=%d "
+ "direct=%d detaching=%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));
+ }
+ return 0;
}
/* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
@@ -1439,6 +1565,10 @@ process_flags(const char * arg, struct flags_t * fp)
fp->noshare = true;
else if (0 == strcmp(cp, "null"))
;
+ else if (0 == strcmp(cp, "v3"))
+ fp->v3 = true;
+ else if (0 == strcmp(cp, "v4"))
+ fp->v4 = true;
else {
pr2serr("unrecognised flag: %s\n", cp);
return false;
@@ -1841,6 +1971,13 @@ main(int argc, char * argv[])
}
}
clp->infp = inf;
+ if ((clp->in_flags.v3 || clp->in_flags.v4) &&
+ (FT_SG != clp->in_type)) {
+ clp->in_flags.v3 = false;
+ clp->in_flags.v4 = false;
+ pr2serr("%siflag= v3 and v4 both ignored when IFILE is not sg "
+ "device\n", my_name);
+ }
}
if (outf[0] && ('-' != outf[0])) {
clp->out_type = dd_filetype(outf);
@@ -1899,6 +2036,31 @@ main(int argc, char * argv[])
}
}
clp->outfp = outf;
+ if ((clp->out_flags.v3 || clp->out_flags.v4) &&
+ (FT_SG != clp->out_type)) {
+ clp->out_flags.v3 = false;
+ clp->out_flags.v4 = false;
+ pr2serr("%soflag= v3 and v4 both ignored when OFILE is not sg "
+ "device\n", my_name);
+ }
+ }
+ if ((FT_SG == clp->in_type ) && (FT_SG == clp->out_type)) {
+ if (clp->in_flags.v4 && (! clp->out_flags.v3)) {
+ if (! clp->out_flags.v4) {
+ clp->out_flags.v4 = true;
+ if (clp->debug)
+ pr2serr("Changing OFILE from v3 to v4, use oflag=v3 to "
+ "force v3\n");
+ }
+ }
+ if (clp->out_flags.v4 && (! clp->in_flags.v3)) {
+ if (! clp->in_flags.v4) {
+ clp->in_flags.v4 = true;
+ if (clp->debug)
+ pr2serr("Changing IFILE from v3 to v4, use iflag=v3 to "
+ "force v3\n");
+ }
+ }
}
if (out2f[0]) {
clp->out2_type = dd_filetype(out2f);
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 38087a71..4985fd9f 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -105,16 +105,15 @@ typedef struct sg_io_hdr {
*/
#define SGV4_FLAG_DIRECT_IO SG_FLAG_DIRECT_IO
#define SGV4_FLAG_MMAP_IO SG_FLAG_MMAP_IO
-#define SGV4_FLAG_V3_MAP 0x8 /* used internally */
+#define SGV4_FLAG_YIELD_TAG 0x8 /* sg_io_v4::request_attr set after SG_IOS */
#define SGV4_FLAG_Q_AT_TAIL SG_FLAG_Q_AT_TAIL
#define SGV4_FLAG_Q_AT_HEAD SG_FLAG_Q_AT_HEAD
-/* Following 2 flags for request::tag (type: int) manipulations */
-#define SGV4_NO_TAG_REQUIRED 0x100 /* default: SG_IOS yields tag */
-#define SGV4_USE_GIVEN_TAG 0x200 /* SG_IOR selector else ignored */
+#define SGV4_FLAG_FIND_BY_TAG 0x100 /* in SG_IOR, def: find by pack_id */
+/* Flag value 0x200 not currently used */
#define SGV4_FLAG_IMMED 0x400 /* for polling with SG_IOR else ignored */
-#define SGV4_FLAG_ASYNC 0x800 /* make sync ioctl (e.g. SG_IO) async */
+/* Flag value 0x800 not currently used */
#define SGV4_FLAG_DEV_SCOPE 0x1000 /* permit SG_IOABORT to have wider scope */
-#define SGV4_FLAG_SHARE 0x2000 /* share IO buffer, already setup or err */
+#define SGV4_FLAG_SHARE 0x2000 /* share IO buffer; needs SG_SEIM_SHARE_FD */
#define SGV4_FLAG_NO_DXFER SG_FLAG_NO_DXFER
/* following 'info' values are OR-ed together */
@@ -268,12 +267,16 @@ struct sg_extended_info {
#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */
/*
- * When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
- * tries to fetch a packet with a matching pack_id, waits, or returns EAGAIN.
- * If pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
- * then pack_id ignored by read() and oldest readable fetched.
+ * When SG_SET_FORCE_PACK_ID set to 1, pack_id (or tag) is input to read() or
+ * ioctl(SG_IO_RECEIVE). These functions wait until matching packet (request/
+ * command) is finished but they will return with EAGAIN quickly if the file
+ * descriptor was opened O_NONBLOCK or (in v4) if SGV4_FLAG_IMMED is given.
+ * The tag is used when SGV4_FLAG_FIND_BY_TAG is given (default: use pack_id).
+ * If pack_id or tag is -1 then read oldest waiting. When FORCE_PACK_ID is
+ * cleared to 0 the oldest readable request/command is fetched. In v4 the
+ * pack_id is placed in sg_io_v4::request_extra .
*/
-#define SG_SET_FORCE_PACK_ID 0x227b
+#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_NUM_WAITING 0x227d /* Number of commands awaiting read() */