aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2019-05-15 14:30:29 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2019-05-15 14:30:29 +0000
commit28903a1cc840874d25f0a6f2b9360bf800e3d46a (patch)
tree1ec51363339eef1cbbdac5a17e9d2add84b96d22
parent3a5deb427c87030be41c99aa0b3fa26d9d79ec67 (diff)
downloadsg3_utils-28903a1cc840874d25f0a6f2b9360bf800e3d46a.tar.gz
sg_read_buffer: decode read microcode status page, add --inhex=FN option
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@822 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog4
-rw-r--r--doc/sg3_utils.88
-rw-r--r--doc/sg_read_buffer.823
-rw-r--r--src/sg_logs.c4
-rw-r--r--src/sg_read_buffer.c381
-rw-r--r--src/sg_ses_microcode.c22
-rw-r--r--testing/sg_tst_async.cpp161
-rw-r--r--testing/sg_tst_bidi.c30
-rw-r--r--testing/sg_tst_ioctl.c122
-rw-r--r--testing/sgh_dd.cpp78
-rw-r--r--testing/sgs_dd.c27
-rw-r--r--testing/uapi_sg.h5
12 files changed, 712 insertions, 153 deletions
diff --git a/ChangeLog b/ChangeLog
index 308990ef..6cf72649 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.45 [20190501] [svn: r821]
+Changelog for sg3_utils-1.45 [20190515] [svn: r822]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (spc5r20)
@@ -13,6 +13,8 @@ Changelog for sg3_utils-1.45 [20190501] [svn: r821]
- sg_raw: fix --send bug when using stdin
- sg_vpd: 3pc VPD page add copy group descriptor
- add --examine option
+ - sg_read_buffer: decode read microcode status page
+ - add --inhex=FN option
- sg_xcopy: add --fco (fast copy only) (spc5r20)
- implement --app=1 (append) on regular OFILE type
- sg_scan (win32): expand limits for big arrays
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index e2d3f9d7..d3f661e0 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "April 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG3_UTILS "8" "May 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
@@ -573,8 +573,10 @@ act on the input, typically it acts on the output data.
Since the structure of the data returned by SCSI commands varies
considerably then the usage information or the manpage of the utility being
used should be checked. In some cases \fI\-\-hex\fR may need to be used
-multiple times (and is more conveniently given as '\-HH' or '\-HHH). In
-other cases the name of this option is \fI\-\-inhex=FN\fR.
+multiple times (and is more conveniently given as '\-HH' or '\-HHH).
+.br
+In some cases the name of the option with this functionality is
+\fI\-\-inhex=FN\fR.
.TP
\fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR
several important SCSI commands (e.g. INQUIRY and MODE SENSE) have response
diff --git a/doc/sg_read_buffer.8 b/doc/sg_read_buffer.8
index d133cce0..422f0fa1 100644
--- a/doc/sg_read_buffer.8
+++ b/doc/sg_read_buffer.8
@@ -1,11 +1,12 @@
-.TH SG_READ_BUFFER "8" "January 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG_READ_BUFFER "8" "May 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_read_buffer \- send SCSI READ BUFFER command
.SH SYNOPSIS
.B sg_read_buffer
-[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-length=LEN\fR]
-[\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR]
-[\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-inhex=FN\fR]
+[\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR]
+[\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-specific=MS\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -31,6 +32,16 @@ right of each line.
this option sets the buffer id field in the cdb. \fIID\fR is a value between
0 (default) and 255 inclusive.
.TP
+\fB\-I\fR, \fB\-\-inhex\fR=\fIFN\fR
+\fIFN\fR is expected to be a file name (or '\-' for stdin) which contains
+ASCII hexadecimal or binary representing a READ BUFFER response. If known
+this utility will then decode that response. It is preferable to also
+supply the \fI\-\-mode=MO\fR and \fI\-\-specific=MS\fR options, since these
+are not present in the response. The hexadecimal should be arranged as 1 or
+2 digits representing a byte each of which is whitespace or comma separated.
+Anything from and including a hash mark to the end of line is ignored. If the
+\fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary.
+.TP
\fB\-l\fR, \fB\-\-length\fR=\fILEN\fR
where \fILEN\fR is the length, in bytes, that is placed in the "allocation
length" field in the cdb. The default value is 4 (bytes). The device may
@@ -54,6 +65,10 @@ if a response is received then it is sent in binary to stdout.
open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag).
The default is to open it read\-write.
.TP
+\fB\-S\fR, \fB\-\-specific\fR=\fIMS\fR
+this option sets the mode specific field in the cdb. \fIMS\fR is a value
+between 0 and 7 as this is a 3 bit field.
+.TP
\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
diff --git a/src/sg_logs.c b/src/sg_logs.c
index ed246674..a869f0c9 100644
--- a/src/sg_logs.c
+++ b/src/sg_logs.c
@@ -36,7 +36,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.73 20190405"; /* spc5r21 + sbc4r17 */
+static const char * version_str = "1.74 20190502"; /* spc5r21 + sbc4r17 */
#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
@@ -1928,7 +1928,7 @@ show_error_counter_page(const uint8_t * resp, int len,
}
val = sg_get_unaligned_be(pl - 4, bp + 4);
printf(" = %" PRIu64 "", val);
- if (val > (1UL << 40))
+ if (val > ((uint64_t)1 << 40))
printf(" [%" PRIu64 " TB]\n",
(val / (1000UL * 1000 * 1000 * 1000)));
else
diff --git a/src/sg_read_buffer.c b/src/sg_read_buffer.c
index 9f92f255..82682f30 100644
--- a/src/sg_read_buffer.c
+++ b/src/sg_read_buffer.c
@@ -15,15 +15,19 @@
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
+#include <errno.h>
#include <getopt.h>
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sg_lib.h"
+#include "sg_lib_data.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
#include "sg_pt.h"
@@ -35,7 +39,7 @@
* device.
*/
-static const char * version_str = "1.27 20190113"; /* spc5r20 */
+static const char * version_str = "1.29 20190515"; /* spc5r22 */
#ifndef SG_READ_BUFFER_10_CMD
@@ -47,6 +51,7 @@ static const char * version_str = "1.27 20190113"; /* spc5r20 */
#define SG_READ_BUFFER_16_CMDLEN 16
#endif
+#define MAX_DEF_INHEX_LEN 8192
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
#define DEF_PT_TIMEOUT 60 /* 60 seconds */
@@ -56,6 +61,7 @@ static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"id", required_argument, 0, 'i'},
+ {"inhex", required_argument, 0, 'I'},
{"length", required_argument, 0, 'l'},
{"long", no_argument, 0, 'L'},
{"mode", required_argument, 0, 'm'},
@@ -73,23 +79,27 @@ static void
usage()
{
pr2serr("Usage: sg_read_buffer [--16] [--help] [--hex] [--id=ID] "
- "[--length=LEN]\n"
- " [--long] [--mode=MO] [--offset=OFF] "
- "[--raw]\n"
- " [--readonly] [--specific=MS] [--verbose] "
- "[--version]\n"
- " DEVICE\n"
+ "[--inhex=FN]\n"
+ " [--length=LEN] [--long] [--mode=MO] "
+ "[--offset=OFF]\n"
+ " [--raw] [--readonly] [--specific=MS] "
+ "[--verbose]\n"
+ " [--version] DEVICE\n"
" where:\n"
" --16|-L issue READ BUFFER(16) (def: 10)\n"
" --help|-h print out usage message\n"
" --hex|-H print output in hex\n"
" --id=ID|-i ID buffer identifier (0 (default) to 255)\n"
+ " --inhex=FN|-I FN filename FN contains hex data to "
+ "decode\n"
+ " rather than DEVICE. If --raw given "
+ "then binary\n"
" --length=LEN|-l LEN length in bytes to read (def: 4)\n"
" --long|-L issue READ BUFFER(16) (def: 10)\n"
" --mode=MO|-m MO read buffer mode, MO is number or "
"acronym (def: 0)\n"
" --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
- " --raw|-r output response to stdout\n"
+ " --raw|-r output response in binary to stdout\n"
" --readonly|-R open DEVICE read-only (def: read-write)\n"
" --specific=MS|-S MS mode specific value; 3 bit field (0 "
"to 7)\n"
@@ -273,6 +283,315 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id,
return ret;
}
+/* Microcode status: active, redundant and download */
+static const char * act_micro_st_arr[] = {
+ "Microcode status not reported",
+ "Activated microcode is valid",
+ "Activated microcode is not valid",
+ "Activated microcode is not a full microcode image",
+};
+
+static const char * red_micro_st_arr[] = {
+ "Redundant microcode status is not reported",
+ "At least one redundant microcode copy is valid",
+ "No redundant microcode copy is valid",
+ "Redundant microcode is not a full microcode image",
+};
+
+/* Major overlap between this SPC-4 table and SES-4r2 table 63 */
+struct sg_lib_simple_value_name_t down_micro_st_arr[] = {
+ {0x0, "No download microcode operation in progress"},
+ {0x1, "Download in progress, awaiting more"}, /* SES */
+ {0x2, "Download complete, updating storage"}, /* SES */
+ {0x3, "Updating storage with deferred microcode"}, /* SES */
+ {0x10, "Complete, no error, starting now"}, /* SES */
+ {0x11, "Complete, no error, start after hard reset or power "
+ "cycle"}, /* SES */
+ {0x12, "Complete, no error, start after power cycle"}, /* SES */
+ {0x13, "Complete, no error, start after activate_mc, hard reset or "
+ "power cycle"}, /* SES */
+ {0x21, "Download in progress, awaiting more"}, /* SPC-6 */
+ {0x22, "Download complete, updating storage"}, /* SPC-6 */
+ {0x23, "Updating storage with deferred microcode"}, /* SPC-6 */
+ {0x30, "Deferred microcode download complete, no reports"}, /* SPC-6 */
+ {0x31, "Deferred download ok, await hard reset or power cycle"},
+ {0x32, "Deferred download ok, await power cycle"}, /* SPC-6 */
+ {0x33, "Deferred download ok, await any event"}, /* SPC-6 */
+ {0x34, "Deferred download ok, await Write buffer command"}, /* SPC-6 */
+ {0x35, "Deferred download ok, await any event, WB only this LU"},
+ {0x80, "Error, discarded, see additional status"}, /* SES */
+ {0x81, "Error, discarded, image error"}, /* SES */
+ {0x82, "Timeout, discarded"}, /* SES */
+ {0x83, "Internal error, need new microcode before reset"}, /* SES */
+ {0x84, "Internal error, need new microcode, reset safe"}, /* SES */
+ {0x85, "Unexpected activate_mc received"}, /* SES */
+ {0x90, "Error, discarded, see additional status"}, /* SPC-6 */
+ {0x91, "Error, discarded, image error"}, /* SPC-6 */
+ {0x92, "Timeout, discarded"}, /* SPC-6 */
+ {0x93, "Internal error, need new microcode before reset"}, /* SPC-6 */
+ {0x94, "Internal error, need new microcode, reset safe"}, /* SPC-6 */
+ {0x95, "Unexpected activate_mc received, mcrocode discard"}, /* SPC-6 */
+ {0x1000, NULL}, /* End sentinel */
+};
+
+static void
+decode_microcode_status(uint8_t * resp, int rb_len)
+{
+ int n;
+ uint32_t u;
+ const char * cp;
+ const struct sg_lib_simple_value_name_t * vnp;
+ char b[32];
+
+ if ((NULL == resp) || (rb_len < 1))
+ return;
+ n = resp[0];
+ if (n < (int)SG_ARRAY_SIZE(act_micro_st_arr))
+ cp = act_micro_st_arr[n];
+ else {
+ snprintf(b, sizeof(b), "unknown [0x%x]", n);
+ cp = b;
+ }
+ printf("Activated microcode status: %s\n", cp);
+
+ if (rb_len < 2)
+ return;
+ n = resp[1];
+ if (n < (int)SG_ARRAY_SIZE(red_micro_st_arr))
+ cp = red_micro_st_arr[n];
+ else {
+ snprintf(b, sizeof(b), "unknown [0x%x]", n);
+ cp = b;
+ }
+ printf("Redundant microcode status: %s\n", cp);
+
+ if (rb_len < 3)
+ return;
+ n = resp[2];
+ for (vnp = down_micro_st_arr, cp = NULL; vnp->name; ++vnp) {
+ if (vnp->value == n) {
+ cp = vnp->name;
+ break;
+ }
+ }
+ if (NULL == cp) {
+ snprintf(b, sizeof(b), "unknown [0x%x]", n);
+ cp = b;
+ }
+ printf("Download microcode status: %s\n", cp);
+
+ if (rb_len > 7) {
+ u = sg_get_unaligned_be32(resp + 4);
+ printf("Download microcode maximum size (bytes): %u [0x%x]\n", u, u);
+ }
+ if (rb_len > 15) {
+ u = sg_get_unaligned_be32(resp + 12);
+ printf("Download microcode expected buffer offset (bytes): %u "
+ "[0x%x]\n", u, u);
+ }
+}
+
+/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
+ * stdin). If reading ASCII hex then there should be either one entry per
+ * line or a comma, space or tab separated list of bytes. If no_space is
+ * set then a string of ACSII hex digits is expected, 2 per byte. Everything
+ * from and including a '#' on a line is ignored. Returns 0 if ok, or an
+ * error code. */
+static int
+f2hex_arr(const char * fname, int as_binary, int no_space,
+ uint8_t * mp_arr, int * mp_arr_len, int max_arr_len)
+{
+ int fn_len, in_len, k, j, m, fd, err;
+ bool has_stdin, split_line;
+ unsigned int h;
+ const char * lcp;
+ FILE * fp;
+ char line[512];
+ char carry_over[4];
+ int off = 0;
+ struct stat a_stat;
+
+ if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len))
+ return SG_LIB_LOGIC_ERROR;
+ fn_len = strlen(fname);
+ if (0 == fn_len)
+ return SG_LIB_SYNTAX_ERROR;
+ has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */
+ if (as_binary) {
+ if (has_stdin)
+ fd = STDIN_FILENO;
+ else {
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ err = errno;
+ pr2serr("unable to open binary file %s: %s\n", fname,
+ safe_strerror(err));
+ return sg_convert_errno(err);
+ }
+ }
+ k = read(fd, mp_arr, max_arr_len);
+ if (k <= 0) {
+ int ret = SG_LIB_SYNTAX_ERROR;
+
+ if (0 == k)
+ pr2serr("read 0 bytes from binary file %s\n", fname);
+ else {
+ ret = sg_convert_errno(errno);
+ pr2serr("read from binary file %s: %s\n", fname,
+ safe_strerror(errno));
+ }
+ if (! has_stdin)
+ close(fd);
+ return ret;
+ }
+ if ((0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) {
+ /* pipe; keep reading till error or 0 read */
+ while (k < max_arr_len) {
+ m = read(fd, mp_arr + k, max_arr_len - k);
+ if (0 == m)
+ break;
+ if (m < 0) {
+ err = errno;
+ pr2serr("read from binary pipe %s: %s\n", fname,
+ safe_strerror(err));
+ if (! has_stdin)
+ close(fd);
+ return sg_convert_errno(err);
+ }
+ k += m;
+ }
+ }
+ *mp_arr_len = k;
+ if (! has_stdin)
+ close(fd);
+ return 0;
+ } else { /* So read the file as ASCII hex */
+ if (has_stdin)
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (NULL == fp) {
+ err = errno;
+ pr2serr("Unable to open %s for reading: %s\n", fname,
+ safe_strerror(err));
+ return sg_convert_errno(err);
+ }
+ }
+ }
+
+ carry_over[0] = 0;
+ for (j = 0; j < 512; ++j) {
+ if (NULL == fgets(line, sizeof(line), fp))
+ break;
+ in_len = strlen(line);
+ if (in_len > 0) {
+ if ('\n' == line[in_len - 1]) {
+ --in_len;
+ line[in_len] = '\0';
+ split_line = false;
+ } else
+ split_line = true;
+ }
+ if (in_len < 1) {
+ carry_over[0] = 0;
+ continue;
+ }
+ if (carry_over[0]) {
+ if (isxdigit(line[0])) {
+ carry_over[1] = line[0];
+ carry_over[2] = '\0';
+ if (1 == sscanf(carry_over, "%4x", &h))
+ mp_arr[off - 1] = h; /* back up and overwrite */
+ else {
+ pr2serr("%s: carry_over error ['%s'] around line %d\n",
+ __func__, carry_over, j + 1);
+ goto bad;
+ }
+ lcp = line + 1;
+ --in_len;
+ } else
+ lcp = line;
+ carry_over[0] = 0;
+ } else
+ lcp = line;
+
+ m = strspn(lcp, " \t");
+ if (m == in_len)
+ continue;
+ lcp += m;
+ in_len -= m;
+ if ('#' == *lcp)
+ continue;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ if ((k < in_len) && ('#' != lcp[k]) && ('\r' != lcp[k])) {
+ pr2serr("%s: syntax error at line %d, pos %d\n", __func__,
+ j + 1, m + k + 1);
+ goto bad;
+ }
+ if (no_space) {
+ for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1));
+ ++k, lcp += 2) {
+ if (1 != sscanf(lcp, "%2x", &h)) {
+ pr2serr("%s: bad hex number in line %d, pos %d\n",
+ __func__, j + 1, (int)(lcp - line + 1));
+ goto bad;
+ }
+ if ((off + k) >= max_arr_len) {
+ pr2serr("%s: array length exceeded\n", __func__);
+ goto bad;
+ }
+ mp_arr[off + k] = h;
+ }
+ if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1))))
+ carry_over[0] = *lcp;
+ off += k;
+ } else {
+ for (k = 0; k < 1024; ++k) {
+ if (1 == sscanf(lcp, "%10x", &h)) {
+ if (h > 0xff) {
+ pr2serr("%s: hex number larger than 0xff in line "
+ "%d, pos %d\n", __func__, j + 1,
+ (int)(lcp - line + 1));
+ goto bad;
+ }
+ if (split_line && (1 == strlen(lcp))) {
+ /* single trailing hex digit might be a split pair */
+ carry_over[0] = *lcp;
+ }
+ if ((off + k) >= max_arr_len) {
+ pr2serr("%s: array length exceeded\n", __func__);
+ goto bad;
+ }
+ mp_arr[off + k] = h;
+ lcp = strpbrk(lcp, " ,\t");
+ if (NULL == lcp)
+ break;
+ lcp += strspn(lcp, " ,\t");
+ if ('\0' == *lcp)
+ break;
+ } else {
+ if (('#' == *lcp) || ('\r' == *lcp)) {
+ --k;
+ break;
+ }
+ pr2serr("%s: error in line %d, at pos %d\n", __func__,
+ j + 1, (int)(lcp - line + 1));
+ goto bad;
+ }
+ }
+ off += (k + 1);
+ }
+ }
+ *mp_arr_len = off;
+ if (stdin != fp)
+ fclose(fp);
+ return 0;
+bad:
+ if (stdin != fp)
+ fclose(fp);
+ return 1;
+}
+
static void
dStrRaw(const uint8_t * str, int len)
{
@@ -290,7 +609,7 @@ main(int argc, char * argv[])
bool do_raw = false;
bool verbose_given = false;
bool version_given = false;
- int res, c, len, k;
+ int res, c, len, k, inhex_len;
int sg_fd = -1;
int do_help = 0;
int do_hex = 0;
@@ -304,13 +623,15 @@ main(int argc, char * argv[])
int64_t ll;
uint64_t rb_offset = 0;
const char * device_name = NULL;
- uint8_t * resp;
+ const char * fname = NULL;
+ uint8_t * resp = NULL;
+ uint8_t * free_resp = NULL;
const struct mode_s * mp;
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "hHi:l:Lm:o:rRS:vV", long_options,
+ c = getopt_long(argc, argv, "hHi:I:l:Lm:o:rRS:vV", long_options,
&option_index);
if (c == -1)
break;
@@ -331,6 +652,14 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
break;
+ case 'I':
+ if (fname) {
+ pr2serr("--inhex= option given more than once. Once only "
+ "please\n");
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ fname = optarg;
+ break;
case 'l':
rb_len = sg_get_num(optarg);
if (rb_len < 0) {
@@ -444,19 +773,35 @@ main(int argc, char * argv[])
return 0;
}
- if (NULL == device_name) {
+ rb_len = 0;
+ inhex_len = 0;
+ if (device_name && fname) {
+ pr2serr("Confused: both DEVICE (%s) and --inhex= option given. One "
+ "only please\n", device_name);
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (fname) {
+ rb_len = (rb_len > MAX_DEF_INHEX_LEN) ? rb_len : MAX_DEF_INHEX_LEN;
+ resp = (uint8_t *)sg_memalign(rb_len, 0, &free_resp, false);
+ ret = f2hex_arr(fname, do_raw, 0, resp, &inhex_len, rb_len);
+ if (ret)
+ goto fini;
+ if (do_raw)
+ do_raw = false; /* only used for input in this case */
+ rb_len = inhex_len;
+ resid = 0;
+ goto decode_result;
+ } else if (NULL == device_name) {
pr2serr("Missing device name!\n\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
len = rb_len ? rb_len : 8;
- resp = (uint8_t *)malloc(len);
+ resp = (uint8_t *)sg_memalign(len, 0, &free_resp, false);
if (NULL == resp) {
pr2serr("unable to allocate %d bytes on the heap\n", len);
return SG_LIB_CAT_OTHER;
}
- memset(resp, 0, len);
if (do_raw) {
if (sg_set_binary_mode(STDOUT_FILENO) < 0) {
@@ -509,6 +854,7 @@ main(int argc, char * argv[])
}
if (resid > 0)
rb_len -= resid; /* got back less than requested */
+decode_result:
if (rb_len > 0) {
if (do_raw)
dStrRaw(resp, rb_len);
@@ -527,6 +873,9 @@ main(int argc, char * argv[])
printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0);
printf("Echo buffer capacity: %d (0x%x)\n", k, k);
break;
+ case MODE_READ_MICROCODE_ST:
+ decode_microcode_status(resp, rb_len);
+ break;
default:
hex2stdout((const uint8_t *)resp, rb_len,
(verbose > 1 ? 0 : 1));
@@ -536,8 +885,8 @@ main(int argc, char * argv[])
}
fini:
- if (resp)
- free(resp);
+ if (free_resp)
+ free(free_resp);
if (sg_fd >= 0) {
res = sg_cmds_close_device(sg_fd);
if (res < 0) {
diff --git a/src/sg_ses_microcode.c b/src/sg_ses_microcode.c
index 44e79b70..36f3659e 100644
--- a/src/sg_ses_microcode.c
+++ b/src/sg_ses_microcode.c
@@ -28,6 +28,7 @@
#endif
#include "sg_lib.h"
+#include "sg_lib_data.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
#include "sg_unaligned.h"
@@ -44,7 +45,7 @@
* RESULTS commands in order to send microcode to the given SES device.
*/
-static const char * version_str = "1.17 20190416"; /* ses4r02 */
+static const char * version_str = "1.18 20190513"; /* ses4r02 */
#define ME "sg_ses_microcode: "
#define MAX_XFER_LEN (128 * 1024 * 1024)
@@ -120,13 +121,10 @@ static struct mode_s mode_arr[] = {
{NULL, 0, NULL},
};
-struct diag_page_code {
- int page_code;
- const char * desc;
-};
-
-/* An array of Download microcode status field values and descriptions */
-static struct diag_page_code mc_status_arr[] = {
+/* An array of Download microcode status field values and descriptions.
+ * This table is a subset of one in sg_read_buffer for the read microcode
+ * status page. */
+static struct sg_lib_simple_value_name_t mc_status_arr[] = {
{0x0, "No download microcode operation in progress"},
{0x1, "Download in progress, awaiting more"},
{0x2, "Download complete, updating storage"},
@@ -241,11 +239,11 @@ print_modes(void)
static const char *
get_mc_status_str(uint8_t status_val)
{
- const struct diag_page_code * mcsp;
+ const struct sg_lib_simple_value_name_t * mcsp;
- for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) {
- if (status_val == mcsp->page_code)
- return mcsp->desc;
+ for (mcsp = mc_status_arr; mcsp->name; ++mcsp) {
+ if (status_val == mcsp->value)
+ return mcsp->name;
}
return "";
}
diff --git a/testing/sg_tst_async.cpp b/testing/sg_tst_async.cpp
index c1067d0b..d6b1c5d0 100644
--- a/testing/sg_tst_async.cpp
+++ b/testing/sg_tst_async.cpp
@@ -89,7 +89,7 @@
#include "sg_pt.h"
#include "sg_cmds.h"
-static const char * version_str = "1.32 20190427";
+static const char * version_str = "1.34 20190506";
static const char * util_name = "sg_tst_async";
/* This is a test program for checking the async usage of the Linux sg
@@ -168,7 +168,9 @@ static atomic<int> start_ebusy_count(0);
static atomic<int> start_e2big_count(0);
static atomic<int> start_eagain_count(0);
static atomic<int> fin_eagain_count(0);
+static atomic<int> fin_ebusy_count(0);
static atomic<int> start_edom_count(0);
+static atomic<int> enomem_count(0);
static atomic<int> uniq_pack_id(1);
// static atomic<int> generic_errs(0);
@@ -190,6 +192,7 @@ struct opts_t {
bool cmd_time;
bool direct;
bool generic_sync;
+ bool masync;
bool mmap_io;
bool no_xfer;
bool pack_id_force;
@@ -217,7 +220,9 @@ struct opts_t {
myQDiscipline myqd; /* --qfav= value (def: 2 --> MYQD_HIGH) */
};
-static struct opts_t a_opts; /* Expect zero fill on simple types */
+static struct opts_t a_opts; /* Expect zero fill on simple types */
+
+static int pr_rusage(int id);
#if 0
class Rand_uint {
@@ -262,6 +267,9 @@ private:
static struct option long_options[] = {
{"v3", no_argument, 0, '3'},
{"v4", no_argument, 0, '4'},
+ {"more-async", no_argument, 0, 'a'},
+ {"more_async", no_argument, 0, 'a'},
+ {"masync", no_argument, 0, 'a'},
{"cmd-time", no_argument, 0, 'c'},
{"cmd_time", no_argument, 0, 'c'},
{"direct", no_argument, 0, 'd'},
@@ -302,16 +310,17 @@ usage(void)
{
printf("Usage: %s [--cmd-time] [--direct] [--force] [--generic-sync]\n"
" [--help] [--lba=LBA+] [--lbsz=LBSZ] "
- "[--maxqpt=QPT]\n"
- " [--mmap-io] [--numpt=NPT] [--noxfer] "
- "[--override=OVN]\n"
- " [--pack-id] [--qat=AT] [-qfav=FAV] [--read] "
- "[--stats]\n"
- " [--submit] [--szlb=LB[,NLBS]] [--tnum=NT] "
- "[--tur]\n"
- " [--v3] [--v4] [--verbose] [--version] "
- "[--wait=MS]\n"
- " [--write] <sg_disk_device>*\n",
+ "[--masync]\n"
+ " [--maxqpt=QPT] [--mmap-io] [--numpt=NPT] "
+ "[--noxfer]\n"
+ " [--override=OVN] [--pack-id] [--qat=AT] "
+ "[-qfav=FAV]\n"
+ " [--read] [--stats] [--submit] "
+ "[--szlb=LB[,NLBS]]\n"
+ " [--tnum=NT] [--tur] [--v3] [--v4] "
+ "[--verbose]\n"
+ " [--version] [--wait=MS] [--write] "
+ "<sg_disk_device>*\n",
util_name);
printf(" where\n");
printf(" --cmd-time|-c calculate per command average time (ns)\n");
@@ -333,10 +342,10 @@ usage(void)
printf(" --lbsz=LBSZ|-L LBSZ logical block size in bytes (def: "
"512)\n"
" should be power of 2 (0 --> 512)\n");
+ printf(" --masync|-a set 'more async' flag on devices\n");
printf(" --maxqpt=QPT|-M QPT maximum commands queued per thread "
"(def:%d)\n", MAX_Q_PER_FD);
- printf(" --mmap-io|-m mmap-ed IO (1 cmd outstanding per "
- "thread)\n");
+ printf(" --mmap-io|-m mmap-ed IO (1 cmd outstanding per thread)\n");
printf(" --numpt=NPT|-n NPT number of commands per thread "
"(def: %d)\n", DEF_NUM_PER_THREAD);
printf(" --noxfer|-N no data xfer (def: xfer on READ and "
@@ -344,7 +353,7 @@ usage(void)
printf(" --override OVN|-O OVN override FAV=2 when OVN queue "
"depth\n"
" reached (def: 0 -> no override)\n");
- printf(" --pack-id|-p set FORCE_PACK_ID, pack-id input to "
+ printf(" --pack-id|-p set FORCE_PACK_ID, pack-id input to "
"read/finish\n");
printf(" --qat=AT|-q AT AT=0: q_at_head; AT=1: q_at_tail (def: "
"(drv): head)\n");
@@ -447,8 +456,8 @@ get_urandom_uint(void)
static int
start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
uint8_t * lbp, int xfer_bytes, int flags, bool submit,
- unsigned int & eagains, unsigned int & ebusy,
- unsigned int & e2big, unsigned int & edom)
+ unsigned int & enomem, unsigned int & eagains,
+ unsigned int & ebusy, unsigned int & e2big, unsigned int & edom)
{
struct sg_io_hdr pt;
struct sg_io_v4 p4t;
@@ -510,6 +519,7 @@ start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
write(sg_fd, ptp, sizeof(*ptp)) < 0);
++k) {
if ((ENOMEM == errno) && (k < MAX_CONSEC_NOMEMS)) {
+ ++enomem;
this_thread::yield();
continue;
} else if (EAGAIN == errno) {
@@ -525,6 +535,8 @@ start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
return 2;
} else if (EDOM == errno)
++edom;
+ else if (ENOMEM == errno)
+ pr_rusage(-1);
pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id);
return -1;
}
@@ -533,8 +545,9 @@ start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
static int
finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
- bool receive, int wait_ms, unsigned int & eagains,
- unsigned int & nanosecs)
+ bool receive, int wait_ms, unsigned int & enomem,
+ unsigned int & eagains, unsigned int & ebusys,
+ unsigned int & nanosecs)
{
bool ok;
int res, k;
@@ -575,8 +588,13 @@ finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
k = 0;
while ((((res = receive ? ioctl(sg_fd, SG_IORECEIVE_V3, ptp) :
read(sg_fd, ptp, sizeof(*ptp)))) < 0) &&
- (EAGAIN == errno)) {
- ++eagains;
+ ((EAGAIN == errno) || (EBUSY == errno) || (ENOMEM == errno))) {
+ if (ENOMEM == errno)
+ ++enomem;
+ else if (EAGAIN == errno)
+ ++eagains;
+ else
+ ++ebusys;
++k;
if (k > 10000) {
pr2serr_lk("%s: sg_fd=%d: after %d EAGAINs, unable to find "
@@ -591,6 +609,8 @@ finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
sleep(0); // process yield ??
}
if (res < 0) {
+ if (ENOMEM == errno)
+ pr_rusage(-1);
pr_errno_lk(errno, "%s: %s", __func__, np);
return -1;
}
@@ -622,8 +642,8 @@ finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
static int
start_sg4_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
uint8_t * lbp, int xfer_bytes, int flags, bool submit,
- unsigned int & eagains, unsigned int & ebusy,
- unsigned int & e2big, unsigned int & edom)
+ unsigned int & enomem, unsigned int & eagains,
+ unsigned int & ebusy, unsigned int & e2big, unsigned int & edom)
{
struct sg_io_v4 p4t;
uint8_t turCmdBlk[TUR_CMD_LEN] = {0, 0, 0, 0, 0, 0};
@@ -677,6 +697,7 @@ start_sg4_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
for (int k = 0; ioctl(sg_fd, SG_IOSUBMIT, ptp) < 0; ++k) {
if ((ENOMEM == errno) && (k < MAX_CONSEC_NOMEMS)) {
+ ++enomem;
this_thread::yield();
continue;
} else if (EAGAIN == errno) {
@@ -692,6 +713,8 @@ start_sg4_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
return 2;
} else if (EDOM == errno)
++edom;
+ else if (ENOMEM == errno)
+ pr_rusage(-1);
pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id);
return -1;
}
@@ -700,8 +723,9 @@ start_sg4_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba,
static int
finish_sg4_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
- bool receive, int wait_ms, unsigned int & eagains,
- unsigned int & nanosecs)
+ bool receive, int wait_ms, unsigned int & enomem,
+ unsigned int & eagains, unsigned int & ebusys,
+ unsigned int & nanosecs)
{
bool ok;
int res, k;
@@ -737,8 +761,11 @@ finish_sg4_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
k = 0;
while ((((res = ioctl(sg_fd, SG_IORECEIVE, ptp))) < 0) &&
- (EAGAIN == errno)) {
- ++eagains;
+ ((EAGAIN == errno) || (EBUSY == errno))) {
+ if (EAGAIN == errno)
+ ++eagains;
+ else
+ ++ebusys;
++k;
if (k > 10000) {
pr2serr_lk("%s: sg_fd=%d: after %d EAGAINs, unable to find "
@@ -753,6 +780,10 @@ finish_sg4_cmd(int sg_fd, command2execute cmd2exe, int & pack_id,
sleep(0); // process yield ??
}
if (res < 0) {
+ if (ENOMEM == errno) {
+ ++enomem;
+ pr_rusage(-1);
+ }
pr_errno_lk(errno, "%s: %s", __func__, np);
return -1;
}
@@ -847,6 +878,8 @@ work_sync_thread(int id, const char * dev_name, unsigned int /* hi_lba */,
if ((sg_fd = sg_cmds_open_device(dev_name, false /* ro */, vb)) < 0) {
pr2serr_lk("id=%d: error opening file: %s: %s\n", id, dev_name,
safe_strerror(-sg_fd));
+ if (ENOMEM == -sg_fd)
+ pr_rusage(id);
goto err_out;
}
@@ -930,10 +963,12 @@ work_thread(int id, struct opts_t * op)
int k, n, res, sg_fd, num_outstanding, do_inc, npt, pack_id, sg_flags;
int num_waiting_read, num_to_read, sz, ern, encore_pack_id, ask, j, m, o;
int prev_pack_id, blk_sz;
+ unsigned int thr_enomem_count = 0;
unsigned int thr_start_eagain_count = 0;
unsigned int thr_start_ebusy_count = 0;
unsigned int thr_start_e2big_count = 0;
unsigned int thr_fin_eagain_count = 0;
+ unsigned int thr_fin_ebusy_count = 0;
unsigned int thr_start_edom_count = 0;
unsigned int seed = 0;
int needed_sz = op->lb_sz * op->num_lbs;
@@ -960,7 +995,7 @@ work_thread(int id, struct opts_t * op)
if (op->blk_szs.size() >= (unsigned)n)
blk_sz = op->blk_szs[id % n];
else
- blk_sz = DEF_LB_SZ;
+ blk_sz = DEF_LB_SZ;
if ((UINT_MAX == op->hi_lba) && (n == (int)op->hi_lbas.size()))
hi_lba = op->hi_lbas[id % n];
else
@@ -985,6 +1020,8 @@ work_thread(int id, struct opts_t * op)
if (sg_fd < 0) {
pr_errno_lk(errno, "%s: id=%d, error opening file: %s", __func__, id,
dev_name);
+ if (ENOMEM == -sg_fd)
+ pr_rusage(id);
return;
}
if (op->pack_id_force) {
@@ -998,7 +1035,7 @@ work_thread(int id, struct opts_t * op)
if (needed_sz > k)
ioctl(sg_fd, SG_SET_RESERVED_SIZE, &needed_sz);
}
- if (op->cmd_time) {
+ if (op->cmd_time || op->masync) {
struct sg_extended_info sei;
struct sg_extended_info * seip;
@@ -1006,14 +1043,21 @@ work_thread(int id, struct opts_t * op)
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
- seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
- seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
- seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
+ if (op->cmd_time) {
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
+ seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
+ seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
+ }
+ if (op->masync) {
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC;
+ seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC;
+ }
if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n",
errno, strerror(errno));
}
- if (! (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags)) {
+ if (op->cmd_time &&
+ (! (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags))) {
memset(seip, 0, sizeof(*seip));
seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
@@ -1231,11 +1275,13 @@ work_thread(int id, struct opts_t * op)
res = (op->v4) ?
start_sg4_cmd(sg_fd, op->c2e, pack_id, lba, lbp,
blk_sz * op->num_lbs, sg_flags, op->submit,
- thr_start_eagain_count, thr_start_ebusy_count,
- thr_start_e2big_count, thr_start_edom_count) :
+ thr_enomem_count, thr_start_eagain_count,
+ thr_start_ebusy_count, thr_start_e2big_count,
+ thr_start_edom_count) :
start_sg3_cmd(sg_fd, op->c2e, pack_id, lba, lbp,
blk_sz * op->num_lbs, sg_flags, op->submit,
- thr_start_eagain_count, thr_start_ebusy_count,
+ thr_enomem_count, thr_start_eagain_count,
+ thr_start_ebusy_count,
thr_start_e2big_count, thr_start_edom_count);
if (res) {
if (res > 1) { /* here if E2BIG, start not done, try finish */
@@ -1423,11 +1469,13 @@ work_thread(int id, struct opts_t * op)
ask = pack_id;
res = (op->v4) ?
finish_sg4_cmd(sg_fd, op->c2e, pack_id, op->submit,
- op->wait_ms, thr_fin_eagain_count,
- nanosecs) :
+ op->wait_ms, thr_enomem_count,
+ thr_fin_eagain_count, thr_fin_ebusy_count,
+ nanosecs) :
finish_sg3_cmd(sg_fd, op->c2e, pack_id, op->submit,
- op->wait_ms, thr_fin_eagain_count,
- nanosecs);
+ op->wait_ms, thr_enomem_count,
+ thr_fin_eagain_count, thr_fin_ebusy_count,
+ nanosecs);
if (res) {
err = "finish_sg3_cmd()";
if (ruip && (pack_id > 0)) {
@@ -1522,6 +1570,7 @@ work_thread(int id, struct opts_t * op)
start_ebusy_count += thr_start_ebusy_count;
start_e2big_count += thr_start_e2big_count;
fin_eagain_count += thr_fin_eagain_count;
+ fin_ebusy_count += thr_fin_ebusy_count;
start_edom_count += thr_start_edom_count;
if (op->cmd_time && op->sg_vn_ge_30901 && (npt > 0)) {
pr2serr_lk("t_id=%d average nanosecs per cmd: %" PRId64
@@ -1686,7 +1735,7 @@ main(int argc, char * argv[])
op = &a_opts;
#if 0
- memset(op, 0, sizeof(*op)); // C++ doesn't like this
+ memset(op, 0, sizeof(*op)); // C++ doesn't like this
#endif
op->direct = DEF_DIRECT;
op->lba = DEF_LBA;
@@ -1708,7 +1757,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "34cdfghl:L:mM:n:NO:pq:Q:Rs:St:TuvVw:W",
+ c = getopt_long(argc, argv, "34acdfghl:L:mM:n:NO:pq:Q:Rs:St:TuvVw:W",
long_options, &option_index);
if (c == -1)
break;
@@ -1726,6 +1775,9 @@ main(int argc, char * argv[])
op->v3 = false;
op->v3_given = false;
break;
+ case 'a':
+ op->masync = true;
+ break;
case 'c':
op->cmd_time = true;
break;
@@ -2106,14 +2158,25 @@ main(int argc, char * argv[])
cout << "Number of async_finishes: " << async_finishes.load() <<
endl;
cout << "Last pack_id: " << n << endl;
- cout << "Number of EBUSYs: " << start_ebusy_count.load() << endl;
- cout << "Number of start EAGAINs: " << start_eagain_count.load()
- << endl;
- cout << "Number of finish EAGAINs: " << fin_eagain_count.load()
- << endl;
- cout << "Number of E2BIGs: " << start_e2big_count.load() << endl;
- cout << "Number of EDOMs: " << start_edom_count.load() << endl;
}
+ n = start_ebusy_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of start EBUSYs: " << n << endl;
+ n = fin_ebusy_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of finish EBUSYs: " << n << endl;
+ n = start_eagain_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of start EAGAINs: " << n << endl;
+ n = fin_eagain_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of finish EAGAINs: " << n << endl;
+ n = start_e2big_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of E2BIGs: " << n << endl;
+ n = start_edom_count.load();
+ if (op->verbose || op->stats || (n > 0))
+ cout << "Number of EDOMs: " << n << endl;
}
catch(system_error& e) {
cerr << "got a system_error exception: " << e.what() << '\n';
diff --git a/testing/sg_tst_bidi.c b/testing/sg_tst_bidi.c
index 624266cc..d2a4ccfb 100644
--- a/testing/sg_tst_bidi.c
+++ b/testing/sg_tst_bidi.c
@@ -53,7 +53,7 @@
is implemented by the scsi_debug driver is used. */
-static const char * version_str = "Version: 1.04 20190128";
+static const char * version_str = "Version: 1.05 20190501";
#define INQ_REPLY_LEN 96
#define INQ_CMD_OP 0x12
@@ -350,12 +350,12 @@ rep_sg_io:
pr2serr("\n");
}
io_v4p->request_len = XDWRITEREAD_10_LEN;
- io_v4p->request = (uint64_t)xdwrrd10_cdb;
+ io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb;
io_v4p->din_xfer_len = din_len;
- io_v4p->din_xferp = (uint64_t)(dinp + (k * din_len));
+ io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len));
io_v4p->dout_xfer_len = dout_len;
- io_v4p->dout_xferp = (uint64_t)(doutp + (k * dout_len));
- io_v4p->response = (uint64_t)sense_buffer[k];
+ io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len));
+ io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k];
io_v4p->max_response_len = SENSE_BUFFER_LEN;
io_v4p->timeout = 20000; /* 20000 millisecs == 20 seconds */
io_v4p->request_extra = 99; /* so pack_id doesn't start at 0 */
@@ -378,7 +378,7 @@ rep_sg_io:
cat = sg_err_category_new(rio_v4.device_status,
rio_v4.transport_status,
rio_v4.driver_status,
- (const uint8_t *)rio_v4.response,
+ (const uint8_t *)(unsigned long)rio_v4.response,
rio_v4.response_len);
switch (cat) {
case SG_LIB_CAT_CLEAN:
@@ -392,7 +392,7 @@ rep_sg_io:
sg_linux_sense_print(NULL, rio_v4.device_status,
rio_v4.transport_status,
rio_v4.driver_status,
- (const uint8_t *)rio_v4.response,
+ (const uint8_t *)(unsigned long)rio_v4.response,
rio_v4.response_len, true);
break;
}
@@ -436,11 +436,11 @@ rep_async:
pr2serr("\n");
}
io_v4p->request_len = XDWRITEREAD_10_LEN;
- io_v4p->request = (uint64_t)xdwrrd10_cdb;
+ io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb;
io_v4p->din_xfer_len = din_len;
- io_v4p->din_xferp = (uint64_t)(dinp + (k * din_len));
+ io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len));
io_v4p->dout_xfer_len = dout_len;
- io_v4p->dout_xferp = (uint64_t)(doutp + (k * dout_len));
+ io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len));
} else {
if (verbose > 2) {
pr2serr(" %s cdb: ", "INQUIRY");
@@ -449,11 +449,11 @@ rep_async:
pr2serr("\n");
}
io_v4p->request_len = sizeof(inq_cdb);
- io_v4p->request = (uint64_t)inq_cdb;
+ io_v4p->request = (uint64_t)(uintptr_t)inq_cdb;
io_v4p->din_xfer_len = INQ_REPLY_LEN;
- io_v4p->din_xferp = (uint64_t)inqBuff[k];
+ io_v4p->din_xferp = (uint64_t)(uintptr_t)inqBuff[k];
}
- io_v4p->response = (uint64_t)sense_buffer[k];
+ io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k];
io_v4p->max_response_len = SENSE_BUFFER_LEN;
io_v4p->timeout = 20000; /* 20000 millisecs == 20 seconds */
io_v4p->request_extra = k + 3; /* so pack_id doesn't start at 0 */
@@ -546,7 +546,7 @@ rep_async:
cat = sg_err_category_new(rio_v4.device_status,
rio_v4.transport_status,
rio_v4.driver_status,
- (const uint8_t *)rio_v4.response,
+ (const uint8_t *)(unsigned long)rio_v4.response,
rio_v4.response_len);
switch (cat) {
case SG_LIB_CAT_CLEAN:
@@ -560,7 +560,7 @@ rep_async:
sg_linux_sense_print(NULL, rio_v4.device_status,
rio_v4.transport_status,
rio_v4.driver_status,
- (const uint8_t *)rio_v4.response,
+ (const uint8_t *)(unsigned long)rio_v4.response,
rio_v4.response_len, true);
break;
}
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c
index 2dd23c2d..a059643f 100644
--- a/testing/sg_tst_ioctl.c
+++ b/testing/sg_tst_ioctl.c
@@ -23,6 +23,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/utsname.h>
#include <sys/socket.h> /* For passing fd_s via Unix sockets */
@@ -56,7 +57,7 @@
* later of the Linux sg driver. */
-static const char * version_str = "Version: 1.09 20190430";
+static const char * version_str = "Version: 1.10 20190506";
#define INQ_REPLY_LEN 128
#define INQ_CMD_LEN 6
@@ -81,13 +82,16 @@ static const char * version_str = "Version: 1.09 20190430";
static bool is_parent = false;
static bool do_fork = false;
static bool ioctl_only = false;
+static bool more_async = false;
static bool q_at_tail = false;
static bool write_only = false;
static bool mrq_immed = false; /* if set, also sets mrq_iosubmit */
static bool mrq_half_immed = false;
static bool mrq_iosubmit = false;
+static bool show_size_value = false;
static int childs_pid = 0;
+static int sg_drv_ver_num = 0;
static int q_len = DEF_Q_LEN;
static int sleep_secs = 0;
static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
@@ -100,10 +104,10 @@ static const char * relative_cp = NULL;
static void
usage(void)
{
- printf("Usage: sg_tst_ioctl [-f] [-h] [-l=Q_LEN] [-m=MRQS[,I|S]] [-r=SZ] "
- "[-s=SEC]\n"
- " [-t] [-v] [-V] [-w] <sg_device> "
- "[<sg_device2>]\n"
+ printf("Usage: sg_tst_ioctl [-f] [-h] [-l=Q_LEN] [-m=MRQS[,I|S]] [-M] "
+ "[-o]\n"
+ " [-r=SZ] [-s=SEC] [-S] [-t] [-v] [-V] [-w]\n"
+ " <sg_device> [<sg_device2>]\n"
" where:\n"
" -f fork and test share between processes\n"
" -h help: print usage message then exit\n"
@@ -116,10 +120,13 @@ usage(void)
"receive;\n"
" 'S' is appended, then use "
"ioctl(SG_IOSUBMIT)\n"
+ " -M set 'more async' flag\n"
" -o ioctls only, then exit\n"
" -r=SZ reserve buffer size in KB (def: 256 --> 256 "
"KB)\n"
" -s=SEC sleep between writes and reads (def: 0)\n"
+ " -S size of interface structures plus ioctl "
+ "values\n"
" -t queue_at_tail (def: q_at_head)\n"
" -v increase verbosity of output\n"
" -V print version string then exit\n"
@@ -227,6 +234,28 @@ sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
return size;
}
+static void
+set_more_async(int fd)
+{
+ if (sg_drv_ver_num > 40000) {
+ struct sg_extended_info sei;
+ struct sg_extended_info * seip;
+
+ seip = &sei;
+ memset(seip, 0, sizeof(*seip));
+ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
+ seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC;
+ seip->ctl_flags = SG_CTL_FLAGM_MORE_ASYNC;
+ if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
+ pr2serr("ioctl(SG_SET_GET_EXTENDED, MORE_ASYNC) failed, "
+ "errno=%d %s\n", errno, strerror(errno));
+ return;
+ }
+ } else
+ pr2serr("sg driver too old for ioctl(SG_SET_GET_EXTENDED)\n");
+}
+
static int
tst_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
int sock, const char * cp)
@@ -509,17 +538,17 @@ do_mrqs(int sg_fd, int sg_fd2, int mrqs)
/* io_hdr[k].iovec_count = 0; */ /* memset takes care of this */
if (0 == (k % 2)) {
h4p->request_len = sizeof(sdiag_cdb);
- h4p->request = (uint64_t)sdiag_cdb;
+ h4p->request = (uint64_t)(uintptr_t)sdiag_cdb;
/* all din and dout fields are zero */
} else {
h4p->request_len = sizeof(inq_cdb);
- h4p->request = (uint64_t)inq_cdb;
+ h4p->request = (uint64_t)(uintptr_t)inq_cdb;
h4p->din_xfer_len = INQ_REPLY_LEN;
- h4p->din_xferp = (uint64_t)inqBuff;
+ h4p->din_xferp = (uint64_t)(uintptr_t)inqBuff;
if (both)
h4p->flags |= SGV4_FLAG_DO_ON_OTHER;
}
- h4p->response = (uint64_t)sense_buffer;
+ h4p->response = (uint64_t)(uintptr_t)sense_buffer;
h4p->max_response_len = sizeof(sense_buffer);
h4p->timeout = 20000; /* 20000 millisecs == 20 seconds */
h4p->request_extra = k + 3; /* so pack_id doesn't start at 0 */
@@ -529,7 +558,7 @@ do_mrqs(int sg_fd, int sg_fd2, int mrqs)
else
h4p->flags |= SG_FLAG_Q_AT_HEAD;
}
- mrq_h4p->dout_xferp = (uint64_t)arr_v4;
+ mrq_h4p->dout_xferp = (uint64_t)(uintptr_t)arr_v4;
mrq_h4p->dout_xfer_len = arr_v4_sz;
mrq_h4p->din_xferp = mrq_h4p->dout_xferp;
mrq_h4p->din_xfer_len = mrq_h4p->dout_xfer_len;
@@ -598,7 +627,7 @@ int
main(int argc, char * argv[])
{
bool done;
- int sg_fd, k, ok, ver_num, pack_id, num_waiting;
+ int sg_fd, k, ok, pack_id, num_waiting;
int res = 0;
int sg_fd2 = -1;
int sock = -1;
@@ -657,7 +686,9 @@ main(int argc, char * argv[])
break;
}
}
- } else if (0 == memcmp("-o", argv[k], 2))
+ } else if (0 == memcmp("-M", argv[k], 2))
+ more_async = true;
+ else if (0 == memcmp("-o", argv[k], 2))
ioctl_only = true;
else if (0 == memcmp("-r=", argv[k], 3)) {
reserve_buff_sz = atoi(argv[k] + 3);
@@ -673,12 +704,16 @@ main(int argc, char * argv[])
file_name = 0;
break;
}
- } else if (0 == memcmp("-t", argv[k], 2))
+ } else if (0 == memcmp("-S", argv[k], 2))
+ show_size_value = true;
+ else if (0 == memcmp("-t", argv[k], 2))
q_at_tail = true;
+ else if (0 == memcmp("-vvvvvvv", argv[k], 8))
+ verbose += 7;
else if (0 == memcmp("-vvvvvv", argv[k], 7))
- verbose += 4;
+ verbose += 6;
else if (0 == memcmp("-vvvvv", argv[k], 6))
- verbose += 4;
+ verbose += 5;
else if (0 == memcmp("-vvvv", argv[k], 5))
verbose += 4;
else if (0 == memcmp("-vvv", argv[k], 4))
@@ -708,6 +743,51 @@ main(int argc, char * argv[])
break;
}
}
+ if (show_size_value) {
+ struct utsname unam;
+
+ printf("Size in bytes:\n");
+ printf("\t%zu\tsizeof(struct sg_header) Version 2 interface "
+ "structure\n", sizeof(struct sg_header));
+ printf("\t%zu\tsizeof(struct sg_io_hdr) Version 3 interface "
+ "structure\n", sizeof(struct sg_io_hdr));
+ printf("\t%zu\tsizeof(struct sg_io_v4) Version 4 interface "
+ "structure\n", sizeof(struct sg_io_v4));
+ printf("\t%zu\tsizeof(struct sg_iovec) scatter gather element\n",
+ sizeof(struct sg_iovec));
+ printf("\t%zu\tsizeof(struct sg_scsi_id) topological device id\n",
+ sizeof(struct sg_scsi_id));
+ printf("\t%zu\tsizeof(struct sg_req_info) request information\n",
+ sizeof(struct sg_req_info));
+ printf("\t%zu\tsizeof(struct sg_extended_info) for "
+ "SG_SET_GET_EXTENDED\n",
+ sizeof(struct sg_extended_info));
+ printf("\nioctl values (i.e. second argument to ioctl()):\n");
+ printf("\t0x%lx\t\tvalue of SG_GET_NUM_WAITING ioctl\n",
+ (unsigned long)SG_GET_NUM_WAITING);
+ printf("\t0x%lx\t\tvalue of SG_IO ioctl\n",
+ (unsigned long)SG_IO);
+ printf("\t0x%lx\tvalue of SG_IOABORT ioctl\n",
+ (unsigned long)SG_IOABORT);
+ printf("\t0x%lx\tvalue of SG_IORECEIVE ioctl\n",
+ (unsigned long)SG_IORECEIVE);
+ printf("\t0x%lx\tvalue of SG_IORECEIVE_V3 ioctl\n",
+ (unsigned long)SG_IORECEIVE_V3);
+ printf("\t0x%lx\tvalue of SG_IOSUBMIT ioctl\n",
+ (unsigned long)SG_IOSUBMIT);
+ printf("\t0x%lx\tvalue of SG_IOSUBMIT_V3 ioctl\n",
+ (unsigned long)SG_IOSUBMIT_V3);
+ printf("\t0x%lx\tvalue of SG_SET_GET_EXTENDED ioctl\n",
+ (unsigned long)SG_SET_GET_EXTENDED);
+ printf("\n\t0x%x\t\tbase value of most SG_* ioctls\n",
+ SG_IOCTL_MAGIC_NUM);
+ printf("\nsizeof(void *) [a pointer] on this machine: %u bytes\n",
+ (unsigned)sizeof(void *));
+ if (0 == uname(&unam))
+ printf("Machine name: %s\n", unam.machine);
+
+ return 0;
+ }
if (0 == file_name) {
printf("No filename (sg device) given\n\n");
usage();
@@ -725,12 +805,14 @@ main(int argc, char * argv[])
fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
file_name, sg_fd);
- if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) {
+ if (ioctl(sg_fd, SG_GET_VERSION_NUM, &sg_drv_ver_num) < 0) {
pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
strerror(errno));
goto out;
}
- printf("Linux sg driver version: %d\n", ver_num);
+ printf("Linux sg driver version: %d\n", sg_drv_ver_num);
+ if (more_async)
+ set_more_async(sg_fd);
if (second_fname) {
if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
@@ -742,6 +824,8 @@ main(int argc, char * argv[])
if (verbose)
fprintf(stderr, "opened second file: %s successfully, fd=%d\n",
second_fname, sg_fd2);
+ if (more_async)
+ set_more_async(sg_fd2);
}
if (num_mrqs > 0) {
@@ -786,7 +870,7 @@ main(int argc, char * argv[])
if (do_fork && !is_parent)
return 0;
- printf("start write() calls\n");
+ printf("start iosubmit calls\n");
for (k = 0; k < q_len; ++k) {
/* Prepare INQUIRY command */
memset(&io_hdr[k], 0, sizeof(sg_io_hdr_t));
@@ -866,7 +950,7 @@ main(int argc, char * argv[])
else
printf("num_waiting: %d\n", num_waiting);
- printf("\nstart read() calls\n");
+ printf("\nstart ioreceive() calls\n");
for (k = 0, done = false; k < q_len; ++k) {
if ((! done) && (k == q_len / 2)) {
done = true;
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp
index 2fefc2c2..bde865dc 100644
--- a/testing/sgh_dd.cpp
+++ b/testing/sgh_dd.cpp
@@ -103,7 +103,7 @@
using namespace std;
-static const char * version_str = "1.29 20190430";
+static const char * version_str = "1.30 20190505";
#ifdef __GNUC__
#ifndef __clang__
@@ -161,6 +161,7 @@ struct flags_t {
bool dsync;
bool excl;
bool fua;
+ bool masync; /* more async sg v4 driver flag */
bool mmap;
bool no_dur;
bool noshare;
@@ -273,6 +274,10 @@ typedef pair< vector<struct sg_io_v4>, vector<cmd_at> > mrq_arr_t;
static atomic<int> mono_pack_id(0);
static atomic<long int> pos_index(0);
+static atomic<int> num_ebusy(0);
+static atomic<int> num_start_eagain(0);
+static atomic<int> num_fin_eagain(0);
+
static sigset_t signal_set;
static pthread_t sig_listen_thread_id;
@@ -620,18 +625,20 @@ usage(int pg_num)
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,defres,dio,"
"direct,dpo,\n"
- " dsync,excl,fua,mmap,noshare,noxfer,null,"
- "same_fds,v3,v4]\n"
+ " dsync,excl,fua,masync,mmap,noshare,noxfer,null,"
+ "same_fds,\n"
+ " v3,v4]\n"
" of file or device to write to (def: /dev/null "
"N.B. different\n"
" from dd it defaults to stdout). If 'of=.' "
"uses /dev/null\n"
" of2 second file or device to write to (def: "
"/dev/null)\n"
- " oflag comma separated list from: [append,coe,dio,"
- "direct,dpo,\n"
- " dsync,excl,fua,mmap,noshare,noxfer,null,"
- "same_fds,swait,v3,v4]\n"
+ " oflag comma separated list from: [append,coe,defres,"
+ "dio,direct,\n"
+ " dpo,dsync,excl,fua,masync,mmap,noshare,noxfer,"
+ "null,\n"
+ " same_fds,swait,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"
@@ -704,6 +711,7 @@ page3:
" excl sets the O_EXCL flag on open()\n"
" fua sets the FUA (force unit access) in SCSI READs "
"and WRITEs\n"
+ " masync set 'more async' flag on this sg device\n"
" mmap setup mmap IO on IFILE or OFILE; OFILE only "
"with noshare\n"
" nodur turns off command duration calculations\n"
@@ -1765,8 +1773,13 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
hp->flags = flags;
while (((res = write(fd, hp, sizeof(struct sg_io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
+ if (EAGAIN == errno)
+ ++num_start_eagain;
+ else if (EBUSY == errno)
+ ++num_ebusy;
sched_yield(); /* another thread may be able to progress */
+ }
err = errno;
if (res < 0) {
if (ENOMEM == err)
@@ -1808,8 +1821,13 @@ do_v4:
return res;
}
while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
+ if (EAGAIN == errno)
+ ++num_start_eagain;
+ else if (EBUSY == errno)
+ ++num_ebusy;
sched_yield(); /* another thread may be able to progress */
+ }
err = errno;
if (res < 0) {
if (ENOMEM == err)
@@ -1876,8 +1894,13 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2)
io_hdr.pack_id = pack_id;
while (((res = read(fd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
+ if (EAGAIN == errno)
+ ++num_fin_eagain;
+ else if (EBUSY == errno)
+ ++num_ebusy;
sched_yield(); /* another thread may be able to progress */
+ }
if (res < 0) {
perror("finishing io [read(2)] on sg device, error");
return -1;
@@ -1930,8 +1953,13 @@ do_v4:
h4p = &rep->io_hdr4;
h4p->request_extra = pack_id;
while (((res = ioctl(fd, SG_IORECEIVE, h4p)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
+ if (EAGAIN == errno)
+ ++num_fin_eagain;
+ else if (EBUSY == errno)
+ ++num_ebusy;
sched_yield(); /* another thread may be able to progress */
+ }
if (res < 0) {
perror("finishing io [SG_IORECEIVE] on sg device, error");
return -1;
@@ -2154,7 +2182,7 @@ write_complet:
/* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
static int
sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
- bool unit_nano, bool no_dur, uint8_t **mmpp)
+ bool unit_nano, bool no_dur, bool masync, uint8_t **mmpp)
{
int res, t, num;
uint8_t *mmp;
@@ -2189,11 +2217,17 @@ sg_prepare_resbuf(int fd, int bs, int bpt, bool def_res, int elem_sz,
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) "
"wr error: %s\n", __func__, strerror(errno));
}
- } else if (no_dur) {
+ } else if (no_dur || masync) {
memset(seip, 0, sizeof(*seip));
seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
- seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
- seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
+ if (no_dur) {
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
+ seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
+ }
+ if (masync) {
+ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC;
+ seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC;
+ }
res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
if (res < 0)
pr2serr_lk("sgh_dd: %s: SG_SET_GET_EXTENDED(NO_DURATION) "
@@ -2268,6 +2302,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->excl = true;
else if (0 == strcmp(cp, "fua"))
fp->fua = true;
+ else if (0 == strcmp(cp, "masync"))
+ fp->masync = true;
else if (0 == strcmp(cp, "mmap"))
fp->mmap = true;
else if (0 == strcmp(cp, "nodur"))
@@ -2333,7 +2369,7 @@ sg_in_open(Gbl_coll *clp, const char *inf, uint8_t **mmpp, int * mmap_lenp)
}
n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->in_flags.defres,
clp->elem_sz, clp->unit_nanosec,
- clp->in_flags.no_dur, mmpp);
+ clp->in_flags.no_dur, clp->in_flags.masync, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -2364,7 +2400,7 @@ sg_out_open(Gbl_coll *clp, const char *outf, uint8_t **mmpp, int * mmap_lenp)
}
n = sg_prepare_resbuf(fd, clp->bs, clp->bpt, clp->out_flags.defres,
clp->elem_sz, clp->unit_nanosec,
- clp->out_flags.no_dur, mmpp);
+ clp->out_flags.no_dur, clp->out_flags.masync, mmpp);
if (n <= 0)
return -SG_LIB_FILE_ERROR;
if (mmap_lenp)
@@ -3196,5 +3232,13 @@ fini:
if (clp->sum_of_resids)
pr2serr(">> Non-zero sum of residual counts=%d\n",
clp->sum_of_resids);
+ if (clp->debug && (num_start_eagain > 0))
+ pr2serr("Number of start EAGAINs: %d\n", num_start_eagain.load());
+ if (clp->debug && (num_fin_eagain > 0))
+ pr2serr("Number of finish EAGAINs: %d\n", num_fin_eagain.load());
+ if (clp->debug && (num_ebusy > 0)) {
+ pr2serr("Number of EBUSYs: %d\n", num_ebusy.load());
+
+ }
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c
index f806e610..991f8011 100644
--- a/testing/sgs_dd.c
+++ b/testing/sgs_dd.c
@@ -78,7 +78,7 @@
#include "sg_unaligned.h"
-static const char * version_str = "4.06 20190501";
+static const char * version_str = "4.07 20190503";
static const char * my_name = "sgs_dd";
#define DEF_BLOCK_SIZE 512
@@ -291,7 +291,7 @@ sg_start_io(Rq_coll * clp, Rq_elem * rep)
if (res < 0) {
if (ENOMEM == errno)
return 1;
- if ((EDOM == errno) || (EAGAIN == errno)) {
+ if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) {
rep->state = SGQ_IO_WAIT; /* busy so wait */
return 0;
}
@@ -307,18 +307,18 @@ do_v4:
memset(h4p, 0, sizeof(struct sg_io_v4));
h4p->guard = 'Q';
h4p->request_len = sizeof(rep->cmd);
- h4p->request = (uint64_t)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)rep->buffp;
+ 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)rep->buffp;
+ h4p->din_xferp = (uint64_t)(uintptr_t)rep->buffp;
}
h4p->max_response_len = sizeof(rep->sb);
- h4p->response = (uint64_t)rep->sb;
+ h4p->response = (uint64_t)(uintptr_t)rep->sb;
h4p->timeout = DEF_TIMEOUT;
- h4p->usr_ptr = (uint64_t)rep;
+ h4p->usr_ptr = (uint64_t)(uintptr_t)rep;
h4p->request_extra = rep->blk;/* N.B. blk --> pack_id --> request_extra */
if (flagp->dio)
h4p->flags |= SG_FLAG_DIRECT_IO;
@@ -333,7 +333,7 @@ do_v4:
if (res < 0) {
if (ENOMEM == errno)
return 1;
- if ((EDOM == errno) || (EAGAIN == errno)) {
+ if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) {
rep->state = SGQ_IO_WAIT; /* busy so wait */
return 0;
}
@@ -365,7 +365,7 @@ sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
goto do_v4;
memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
while (((res = read(fd, &io_hdr, sizeof(sg_io_hdr_t))) < 0) &&
- (EINTR == errno))
+ ((EINTR == errno) || (EAGAIN == errno)))
;
rep = (Rq_elem *)io_hdr.usr_ptr;
if (rep)
@@ -414,9 +414,10 @@ sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
do_v4:
memset(&io_v4, 0 , sizeof(io_v4));
io_v4.guard = 'Q';
- while (((res = ioctl(fd, SG_IORECEIVE, &io_v4)) < 0) && (EINTR == errno))
+ while (((res = ioctl(fd, SG_IORECEIVE, &io_v4)) < 0) &&
+ ((EINTR == errno) || (EAGAIN == errno)))
;
- rep = (Rq_elem *)io_v4.usr_ptr;
+ rep = (Rq_elem *)(unsigned long)io_v4.usr_ptr;
if (res < 0) {
fprintf(stderr, "%s: ioctl(SG_IORECEIVE): %s [%d]\n", __func__,
strerror(errno),
@@ -438,7 +439,7 @@ do_v4:
res = sg_err_category_new(h4p->device_status, h4p->transport_status,
h4p->driver_status,
- (const uint8_t *)h4p->response,
+ (const uint8_t *)(unsigned long)h4p->response,
h4p->response_len);
switch (res) {
case SG_LIB_CAT_CLEAN:
@@ -453,7 +454,7 @@ do_v4:
sg_linux_sense_print(rep->wr ? "writing": "reading",
h4p->device_status, h4p->transport_status,
h4p->driver_status,
- (const uint8_t *)h4p->response,
+ (const uint8_t *)(unsigned long)h4p->response,
h4p->response_len, true);
rep->state = SGQ_IO_ERR;
return -1;
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index 87700c3c..fa7f2ea3 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -14,7 +14,7 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version 4.0.11 (20190427)
+ * Version 4.0.11 (20190502)
* This version is for Linux 4 and 5 series kernels.
*
* Documentation
@@ -202,7 +202,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_CTL_FLAGM_MASTER_FINI 0x100 /* wr> 0: setup for repeat slave req */
#define SG_CTL_FLAGM_MASTER_ERR 0x200 /* rd: sharing, master got error */
#define SG_CTL_FLAGM_NO_DURATION 0x400 /* don't calc command duration */
-#define SG_CTL_FLAGM_ALL_BITS 0x7ff /* should be OR of previous items */
+#define SG_CTL_FLAGM_MORE_ASYNC 0x800 /* yield EAGAIN in more cases */
+#define SG_CTL_FLAGM_ALL_BITS 0xfff /* should be OR of previous items */
/* Write one of the following values to sg_extended_info::read_value, get... */
#define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */