aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-06-03 23:59:56 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-06-03 23:59:56 +0000
commite05f7acda57fbbbad555df38fef89aa70447b590 (patch)
treeeeb77582446b28c0b89f2415f8a0a34eef3e1fc4
parent14a6fbe3500a5ead474126ded5e0f1df8dd88ade (diff)
downloadsg3_utils-e05f7acda57fbbbad555df38fef89aa70447b590.tar.gz
sg_decode sense: add --err=ES; sg_dd, sgp_dd, sgm_dd: add --dry-run and --verbose options; introduce SG3_UTILS_DSENSE environment variable; sg_lib: add sg_nvme_desc2sense(), sg_build_sense_buffer(), and pr2ws()
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@777 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog15
-rw-r--r--debian/changelog2
-rw-r--r--doc/rescan-scsi-bus.sh.88
-rw-r--r--doc/sg3_utils.836
-rw-r--r--doc/sg_compare_and_write.82
-rw-r--r--doc/sg_dd.824
-rw-r--r--doc/sg_decode_sense.838
-rw-r--r--doc/sg_format.88
-rw-r--r--doc/sg_get_lba_status.82
-rw-r--r--doc/sg_inq.88
-rw-r--r--doc/sg_logs.82
-rw-r--r--doc/sg_luns.812
-rw-r--r--doc/sg_raw.82
-rw-r--r--doc/sg_reset.82
-rw-r--r--doc/sg_sat_read_gplog.84
-rw-r--r--doc/sg_seek.85
-rw-r--r--doc/sg_ses.82
-rw-r--r--doc/sg_ses_microcode.86
-rw-r--r--doc/sg_vpd.89
-rw-r--r--doc/sg_write_buffer.82
-rw-r--r--doc/sg_write_verify.88
-rw-r--r--doc/sg_write_x.84
-rw-r--r--doc/sgm_dd.823
-rw-r--r--doc/sgp_dd.819
-rw-r--r--include/sg_lib.h14
-rw-r--r--include/sg_pr2serr.h11
-rw-r--r--include/sg_pt_linux.h3
-rw-r--r--include/sg_pt_nvme.h2
-rw-r--r--lib/sg_cmds_basic.c23
-rw-r--r--lib/sg_cmds_basic2.c21
-rw-r--r--lib/sg_cmds_extra.c20
-rw-r--r--lib/sg_cmds_mmc.c20
-rw-r--r--lib/sg_io_linux.c22
-rw-r--r--lib/sg_lib.c116
-rw-r--r--lib/sg_lib_data.c48
-rw-r--r--lib/sg_pt_common.c12
-rw-r--r--lib/sg_pt_freebsd.c88
-rw-r--r--lib/sg_pt_linux.c36
-rw-r--r--lib/sg_pt_linux_nvme.c79
-rw-r--r--lib/sg_pt_osf1.c20
-rw-r--r--lib/sg_pt_win32.c106
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_decode_sense.c59
-rw-r--r--src/sgm_dd.c74
-rw-r--r--src/sgp_dd.c74
45 files changed, 621 insertions, 472 deletions
diff --git a/ChangeLog b/ChangeLog
index 7c2ba040..68595734 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.43 [20180531] [svn: r776]
+Changelog for sg3_utils-1.43 [20180603] [svn: r777]
- sg_write_x: where x can be normal, atomic, or(write),
same, scattered, or stream writes with 16 or 32 byte
cdbs (sbc4r04 for atomic, sbc4r11 for scattered)
@@ -17,7 +17,7 @@ Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- add --quick option to skip reconsideration time
- extend --wait timeout to 40 hours for disk sizes
> 4 TB and 80 hours if > 8 TB
- - sg_decode sense: add --cdb option
+ - sg_decode sense: add --cdb and --err=ES options
- sg_ses: handle 2 bit EIIOE field in aes dpage
- add --quiet option to suppress messages
- expand join handling of SAS connectors and others
@@ -83,8 +83,6 @@ Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- sg_vpd: 3 party copy VPD page improvements
- fully implement Device constituents VPD page
- improve handling of unknown pages
- - sg_dd: add --dry-run and --verbose options
- - allow multiple short options (e.g. -dvv )
- sg_reassign+sg_write_same: fix ULONG_MAX problem
- sg_rdac: add sanity checks for -f=lun value
- sg_turs+sg_requests: make both accept '--num=NUM'
@@ -95,9 +93,13 @@ Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- sg_reset_wp add --count=ZC option, zbc2r01b
- sg_persist: add --maxlen-LEN option, LEN defaults to
decimal, similar to --alloc-length= which takes hex
+ - sg_dd: add --dry-run and --verbose options
+ - allow multiple short options (e.g. -dvv )
- sgp_dd: pthread_cancel() has issues in C++ (and
the Android multi-threaded library doesn't supply it)
so use pthread_kill() in its place [Linux only]
+ - add --dry-run and --verbose options
+ - sgm_dd: add --dry-run and --verbose options
- sg_opcode: add '--enumerate' and '--pdt=' options
- support CDLP (command duration limit page)
- check resid and trim response if necessary
@@ -122,6 +124,7 @@ Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- sg_wr_mode: add --rtd option for RTD bit
- sg_timestamp: add '--no-timestamp' option
- add --elapsed and --hex options
+ - introduce SG3_UTILS_DSENSE environment variable
- manpages and usage messages: corrections from
Gris Ge via github
- group_number: is 6 bit field allowing 0 to 63,
@@ -152,9 +155,11 @@ Changelog for sg3_utils-1.43 [20180531] [svn: r776]
- add sg_is_scsi_cdb()
- add sg_get_nvme_cmd_status_str()
- add sg_nvme_status2scsi()
+ - add sg_nvme_desc2sense()
+ - add sg_build_sense_buffer()
- add sg_get_nvme_opcode_name()
- add sg_memalign() and sg_get_page_size()
- - add sg_is_aligned()
+ - add sg_is_aligned() and pr2ws()
- add sg_get_big_endian(), sg_set_big_endian()
- add hex2stdout(), hex2stderr() and hex2str()
- add sg_convert_errno()
diff --git a/debian/changelog b/debian/changelog
index 7ee9b06e..627a12aa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.43-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Wed, 23 May 2018 21:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Sat, 02 Jun 2018 13:00:00 -0400
sg3-utils (1.42-0.1) unstable; urgency=low
diff --git a/doc/rescan-scsi-bus.sh.8 b/doc/rescan-scsi-bus.sh.8
index 16c9a95a..3020dd23 100644
--- a/doc/rescan-scsi-bus.sh.8
+++ b/doc/rescan-scsi-bus.sh.8
@@ -1,8 +1,8 @@
-.TH RESCAN-SCSI-BUS.SH "1" "January 2016" "rescan-scsi-bus.sh" "User Commands"
+.TH RESCAN\-SCSI\-BUS.SH "1" "January 2016" "rescan\-scsi\-bus.sh" "User Commands"
.SH NAME
rescan-scsi-bus.sh \- script to add and remove SCSI devices without rebooting
.SH SYNOPSIS
-.B rescan-scsi-bus.sh
+.B rescan\-scsi\-bus.sh
[\fI\-\-alltargets\fR] [\fI\-\-attachpq3\fR] [\fI\-c\fR] [\fI\-\-color\fR]
[\fI\-\--channels=CLIST\fR] [\fI\-d\fR] [\fI\-\-flush\fR]
[\fI\-\-forceremove\fR] [\fI\-\-forcerescan\fR] [\fI\-\-help\fR]
@@ -106,7 +106,7 @@ form:
which is a comma separated list of single values and/or ranges (no spaces
allowed).
.SH SEE ALSO
-\fBrescan-scsi-bus.sh\fR Homepage:
-\fBhttp://www.garloff.de/kurt/linux/#rescan-scsi\fR
+\fBrescan\-scsi\-bus.sh\fR Homepage:
+\fBhttp://www.garloff.de/kurt/linux/#rescan\-scsi\fR
.PP
\fBsg3_utils\fR Homepage: \fBhttp://sg.danny.cz/sg\fR
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 66cd8fa7..ea6c9a34 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "May 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG3_UTILS "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
@@ -84,6 +84,18 @@ and permit copying data at the level of SCSI READ and WRITE commands. sg_dd
is tightly bound to Linux and hence is not ported to other OSes. A more
generic utility (than sg_dd) called ddpt in a package of the same name has
been ported to other OSes.
+.SH ENVIRONMENT VARIABLES
+The SG3_UTILS_OLD_OPTS environment variable is explained in the previous
+section. It is only for backward compatibility of the command line options
+for older utilities.
+.PP
+The SG3_UTILS_DSENSE environment variable may be set to a number. If that
+number is non\-zero then descriptor sense is set in the SNTL (the small
+SCSI to NVMe Translation Layer within the underlying library).
+.PP
+Several utilities have their own environment variable setting (e.g.
+sg_persist has SG_PERSIST_IN_RDONLY). See individual utility man pages
+for more information.
.SH LINUX DEVICE NAMING
Most disk block devices have names like /dev/sda, /dev/sdb, /dev/sdc, etc.
SCSI disks in Linux have always had names like that but in recent Linux
@@ -240,7 +252,16 @@ of "NVMe " (an 8 character long string with 4 spaces to the right).
.SH EXIT STATUS
To aid scripts that call these utilities, the exit status is set to indicate
success (0) or failure (1 or more). Note that some of the lower values
-correspond to the SCSI sense key values. The exit status values are:
+correspond to the SCSI sense key values.
+.PP
+The exit status values listed below can be given to the sg_decode_sense
+utility (which is found in this package) as follows:
+.br
+ sg_decode_sense \-\-err=<exit_status>
+.br
+and a short explanatory string will be output to stdout.
+.PP
+The exit status values are:
.TP
.B 0
success
@@ -329,7 +350,7 @@ often when trying to access the last block on a storage device; either a
classic "off by one" logic error or a misreading of the response from READ
CAPACITY(10 or 16) in which the address of the last block rather than the
number of blocks on the \fIDEVICE\fR is returned. Since LBAs are origin zero
-they range from 0 to n-1 where n is the number of blocks on the \fIDEVICE\fR,
+they range from 0 to n\-1 where n is the number of blocks on the \fIDEVICE\fR,
so the LBA of the last block is one less than the total number of blocks.
.TP
.B 24
@@ -396,7 +417,7 @@ actually received by HBA is 'requested_bytes \- residual_count') that is
.TP
.B 50
OS system calls that fail often return a small integer number to help. In
-Unix these are valled "errno" values where 0 implies no error. These error
+Unix these are called "errno" values where 0 implies no error. These error
codes set aside 51 to 96 for mapping these errno values but that may not be
sufficient. Higher errno values that cannot be mapped are all mapped to
this value (i.e. 50).
@@ -455,10 +476,9 @@ associated signal number of 11; so the exit status will be 139 .
the utility tried to yield an exit status of 255 or larger. That should
not happen; given here for completeness.
.PP
-Most of the error conditions reported above will be repeatable (an
-example of one that is not is "unit attention") so the utility can
-be run again with the '\-v' option (or several) to obtain more
-information.
+Most of the error conditions reported above will be repeatable (an example
+of one that is not is "unit attention") so the utility can be run again with
+the '\-v' option (or several) to obtain more information.
.SH COMMON OPTIONS
Arguments to long options are mandatory for short options as well. In the
short form an argument to an option uses zero or more spaces as a
diff --git a/doc/sg_compare_and_write.8 b/doc/sg_compare_and_write.8
index 9329f6e1..46c4c7cd 100644
--- a/doc/sg_compare_and_write.8
+++ b/doc/sg_compare_and_write.8
@@ -124,7 +124,7 @@ utility.
\fB\-x\fR, \fB\-\-xferlen\fR=\fILEN\fR
where \fILEN\fR is the data out buffer length in byte. It defaults to (2 *
\fINUM\fR * 512) bytes. If the \fIDEVICE\fR block size is other than 512
-bytes or \fIWP\fR is non-zero (implying additional protection information)
+bytes or \fIWP\fR is non\-zero (implying additional protection information)
then this default will be incorrect; the use must supply the correct value
for \fILEN\fR
.SH NOTES
diff --git a/doc/sg_dd.8 b/doc/sg_dd.8
index 0aa7a386..2773ee67 100644
--- a/doc/sg_dd.8
+++ b/doc/sg_dd.8
@@ -1,4 +1,4 @@
-.TH SG_DD "8" "November 2017" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_DD "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -6,8 +6,8 @@ devices
.B sg_dd
[\fIbs=BS\fR] [\fIconv=CONV\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR]
[\fIif=IFILE\fR] [\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR]
-[\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR]
-[\fI\-\-version\fR]
+[\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-dry\-run\fR]
+[\fI\-\-help\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
.PP
[\fIblk_sgio=\fR{0|1}] [\fIbpt=BPT\fR] [\fIcdbsz=\fR{6|10|12|16}]
[\fIcoe=\fR{0|1|2|3}] [\fIcoe_limit=CL\fR] [\fIdio=\fR{0|1}]
@@ -194,13 +194,21 @@ Unix read() and write() calls) so there can be a lot of output.
This only occurs for scsi generic (sg) devices and block devices when
the 'blk_sgio=1' option is set.
.TP
-\fB\-\-help\fR
+\fB\-d\fR, \fB\-\-dry\-run\fR
+does all the command line parsing and preparation but bypasses the actual
+copy or read. That preparation may include opening \fIIFILE\fR or
+\fIOFILE\fR to determine their lengths. This option may be useful for
+testing the syntax of complex command line invocations in advance of
+executing them.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
outputs usage message and exits.
.TP
-\fB\-\-version\fR
-outputs version number information and exits.
+\fB\-v\fR, \fB\-\-verbose\fR
+when used once, this is equivalent to \fIverbose=1\fR. When used
+twice (e.g. "\-vv") this is equivalent to \fIverbose=2\fR, etc.
.TP
-\fB\-V\fR
+\fB\-V\fR, \fB\-\-version\fR
outputs version number information and exits.
.SH CONVERSIONS
One or more conversions can be given to the "conv=" option. If more than
@@ -483,7 +491,7 @@ Written by Douglas Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000\-2017 Douglas Gilbert
+Copyright \(co 2000\-2018 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sg_decode_sense.8 b/doc/sg_decode_sense.8
index ecf04f66..18e6e9fb 100644
--- a/doc/sg_decode_sense.8
+++ b/doc/sg_decode_sense.8
@@ -1,17 +1,17 @@
-.TH SG_DECODE_SENSE "8" "May 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_DECODE_SENSE "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_decode_sense \- decode SCSI sense data
.SH SYNOPSIS
.B sg_decode_sense
-[\fI\-\-binary=FN\fR] [\fI\-\-cdb\fR] [\fI\-\-file=FN\fR] [\fI\-\-help\fR]
-[\fI\-\-hex\fR] [\fI\-\-nospace\fR] [\fI\-\-status=SS\fR]
+[\fI\-\-binary=FN\fR] [\fI\-\-cdb\fR] [\fI\-\-err=ES\fR] [\fI\-\-file=FN\fR]
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-nospace\fR] [\fI\-\-status=SS\fR]
[\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-write=WFN\fR]
[H1 H2 H3 ...]
.SH DESCRIPTION
.\" Add any additional description here
This utility takes SCSI sense data in binary or as a sequence of
ASCII hexadecimal bytes and decodes it. The primary reference for the
-decoding is SPC\-4 ANSI INCITS 513-2015 and the most recent draft
+decoding is SPC\-4 ANSI INCITS 513\-2015 and the most recent draft
SPC\-5 revision 8 which can be found at http://www.t10.org and other
locations on the internet.
.PP
@@ -35,6 +35,10 @@ arguments as sense data, it is viewed as a SCSI command descriptor
block (CDB). In this case the command name is printed out. That name is
based on the first hex byte given (know as the opcode) and optionally on
another field called the "service action".
+.PP
+Another alternate action is when the \fI\-\-err=ES\fR is given. \fIES\fR
+is assumed to be an "exit status" value between 0 and 255. A descriptive
+string is printed. Other options are ignored apart from \fI\-\-verbose\fR.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
.TP
@@ -45,14 +49,15 @@ the sense data is read in binary from a file called \fIFN\fR.
treat the given string of hex arguments as bytes in a SCSI CDB and
decode the command name.
.TP
-\fB\-h\fR, \fB\-\-help\fR
-output the usage message then exit.
-.TP
-\fB\-H\fR, \fB\-\-hex\fR
-this option is used in conjunction with \fI\-\-write=WFN\fR in order to
-change the output written to \fIWFN\fR to lines of ASCII hex bytes suitable
-for a C language compiler. Each line contains up to 16 bytes (e.g. a line
-starting with "0x3b,0x07,0x00,0xff").
+\fB\-e\fR, \fB\-\-err\fR=\fIES\fR
+\fIES\fR should be an "exit status" value between 0 and 255 that is
+available from the shell (i.e. the utility's execution context) after the
+utility is finished. By default an indicative error message is printed to
+stdout; and if the \fI\-\-verbose\fR option is given once (or an odd number
+of times) then the message is instead printed to stderr. If \fI\-\-verbose\fR
+is given two or more times a longer form of the message is output. In all
+cases the message is less than 128 characters long with one trailing line
+feed. All other command line options and arguments are ignored.
.TP
\fB\-f\fR, \fB\-\-file\fR=\fIFN\fR
the sense data is read in ASCII hexadecimal from a file called \fIFN\fR.
@@ -62,6 +67,15 @@ end of that line is ignored. If \fI\-\-nospace\fR is set then no separator
is required between the ASCII hexadecimal digits in \fIFN\fR with bytes
decoded from pairs of ASCII hexadecimal digits.
.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit.
+.TP
+\fB\-H\fR, \fB\-\-hex\fR
+this option is used in conjunction with \fI\-\-write=WFN\fR in order to
+change the output written to \fIWFN\fR to lines of ASCII hex bytes suitable
+for a C language compiler. Each line contains up to 16 bytes (e.g. a line
+starting with "0x3b,0x07,0x00,0xff").
+.TP
\fB\-n\fR, \fB\-\-nospace\fR
expect ASCII hexadecimal to be a string of hexadecimal digits with no
spaces between them. Bytes are decoded by taking two hexadecimal digits
diff --git a/doc/sg_format.8 b/doc/sg_format.8
index 7d36f5fe..cb029510 100644
--- a/doc/sg_format.8
+++ b/doc/sg_format.8
@@ -211,10 +211,10 @@ below for more information.
\fB\-q\fR, \fB\-\-pie\fR=\fIPIE\fR
sets the "Protection Interval Exponent" field in the parameter block
associated with a FORMAT UNIT command to \fIPIE\fR. The default value is 0.
-\fIPIE\fR can only be non-zero with protection types 2 and 3.
+\fIPIE\fR can only be non\-zero with protection types 2 and 3.
The value of 0 is typical for 512 byte blocks; with 4096 byte blocks a value
of 3 may be appropriate (i.e. 8 protection intervals interleaved with 4096
-bytes of user data). A device may not support any non-zero values. This
+bytes of user data). A device may not support any non\-zero values. This
field first appeared in SBC\-3 revision 18.
.TP
\fB\-p\fR, \fB\-\-pinfo\fR
@@ -504,7 +504,7 @@ sdparm utility.
.PP
Prior to invoking this utility the tape may need to be positioned to the
beginning of partition 0. In Linux that can typically be done with the mt
-utility (e.g. 'mt -f /dev/st0 rewind').
+utility (e.g. 'mt \-f /dev/st0 rewind').
.SH EXAMPLES
These examples use Linux device names. For suitable device names in
other supported Operating Systems see the sg3_utils(8) man page.
@@ -598,4 +598,4 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.B sg_turs(8), sg_requests(8), sg_inq(8), sg_modes(8), sg_vpd(8),
.B sg_reassign(8), sg_readcap(8), sg3_utils(8),
.B sg_sanitize(8) [all in sg3_utils],
-.B mt(mt-st), sdparm(8), scsiformat (old), hdparm(8)
+.B mt(mt\-st), sdparm(8), scsiformat (old), hdparm(8)
diff --git a/doc/sg_get_lba_status.8 b/doc/sg_get_lba_status.8
index cada6b49..13889b37 100644
--- a/doc/sg_get_lba_status.8
+++ b/doc/sg_get_lba_status.8
@@ -83,7 +83,7 @@ The default is to open it read\-write.
\fB\-t\fR, \fB\-\-report\-type\fR=\fIRT\fR
where \fIRT\fR is 0 for report all LBAs; 1 for report LBAs using non\-zero
provisioning status; 2 for report LBAs that are mapped; 3 for report LBAs
-that are de-allocated; 4 for report LBAs that are anchored; 5 for report
+that are de\-allocated; 4 for report LBAs that are anchored; 5 for report
LBAs that may return an unrecovered error. The REPORT TYPE field was added
to the GET LBA STATUS cdb in sbc4r12.
.TP
diff --git a/doc/sg_inq.8 b/doc/sg_inq.8
index a5edbf65..f94a8916 100644
--- a/doc/sg_inq.8
+++ b/doc/sg_inq.8
@@ -65,7 +65,7 @@ option name.
\fB\-a\fR, \fB\-\-ata\fR
Assume given \fIDEVICE\fR is an ATA or ATAPI device which can receive ATA
commands from the host operating system. Skip the SCSI INQUIRY command and
-use either the ATA IDENTIFY DEVICE command (for non-packet devices) or the
+use either the ATA IDENTIFY DEVICE command (for non\-packet devices) or the
ATA IDENTIFY PACKET DEVICE command. To show the response in hex, add
a '\-\-verbose' option. This option is only available in Linux.
.TP
@@ -186,7 +186,7 @@ Do not attempt to additionally retrieve the serial number VPD page (0x80) to
enhance the output of a standard INQUIRY. So with this option given and no
others, this utility will send a standard INQUIRY SCSI command and decode
its response. No other SCSI commands will be sent to the \fIDEVICE\fR.
-Without this option an additional SCSI command is sent: a (non-standard)
+Without this option an additional SCSI command is sent: a (non\-standard)
SCSI INQUIRY to fetch the Serial Number VPD page. However the Serial
Number VPD page is not mandatory (while the Device Identification page is
mandatory but a billion USB keys ignore that) and may cause nuisance error
@@ -330,8 +330,8 @@ get the controller's Identify decoded use the \fI\-\-only\fR option.
.PP
It is possible that even though the \fIDEVICE\fR presents as a NVMe device,
it has a SNTL and accepts SCSI commands. In this case to send a SCSI INQUIRY
-command (and fetch its VPD pages) use 'sg_vpd -p sinq <dev>' (or to get VPD
-pages: 'sg_vpd -p <vpd_page> <dev>').
+command (and fetch its VPD pages) use 'sg_vpd \-p sinq <dev>' (or to get VPD
+pages: 'sg_vpd \-p <vpd_page> <dev>').
.SH EXIT STATUS
The exit status of sg_inq is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
diff --git a/doc/sg_logs.8 b/doc/sg_logs.8
index 8a2447b6..f5d2e774 100644
--- a/doc/sg_logs.8
+++ b/doc/sg_logs.8
@@ -297,7 +297,7 @@ are followed by "[hex only]".
print out version string then exit.
.SH LOG SELECT
The LOG SELECT command can be used to reset certain parameters to vendor
-specific defaults, save them to non-volatile storage (i.e. the media), or
+specific defaults, save them to non\-volatile storage (i.e. the media), or
supply new page contents. This command has changed between SPC\-3 and SPC\-4
with the addition of the Page and Subpage Code fields which can only be
non zero when the Parameter list length is zero.
diff --git a/doc/sg_luns.8 b/doc/sg_luns.8
index eb79ddf3..f27ed6f6 100644
--- a/doc/sg_luns.8
+++ b/doc/sg_luns.8
@@ -1,4 +1,4 @@
-.TH SG_LUNS "8" "November" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_LUNS "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_luns \- send SCSI REPORT LUNS command or decode given LUN
.SH SYNOPSIS
@@ -41,7 +41,7 @@ given or not. If this option is given once then the given \fIALUN\fR is
output in T10 preferred format (which is 8 pairs of hex digits, each
separated by a space). If given twice then the given \fIALUN\fR is output
in an alternate T10 format made up of four quads of hex digits with each
-quad separated by a "-" (e.g. C101-0000-0000-0000).
+quad separated by a "-" (e.g. C101\-0000\-0000\-0000).
.TP
\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
@@ -128,9 +128,9 @@ the right if less than 16 hexadecimal digits are given (e.g.
\fI\-\-test=0122003a\fR represents T10 LUN: 01 22 00 3a 00 00 00 00).
\fIALUN\fR may be prefixed by '0x' or '0X' (e.g. the previous example could
have been \fI\-\-test=0x0122003a\fR). \fIALUN\fR may also be given with
-spaces, tabs, or a '-' between each byte (or other grouping (e.g.
-c101-0000-0000-0000)). However in the case of space or tab separators the
-\fIALUN\fR would need to be surrounded by single or double quotes.
+spaces, tabs, or a '\-' between each byte (or other grouping (e.g.
+c101\-0000\-0000\-0000)). However in the case of space or tab separators
+the \fIALUN\fR would need to be surrounded by single or double quotes.
.br
In the leading 'L' case the, following decimal number (hex if preceded
by '0x') is assumed to be a Linux "word flipped" LUN which is converted
@@ -311,7 +311,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004\-2017 Douglas Gilbert
+Copyright \(co 2004\-2018 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sg_raw.8 b/doc/sg_raw.8
index 4bdea7ad..b6bdbccd 100644
--- a/doc/sg_raw.8
+++ b/doc/sg_raw.8
@@ -136,7 +136,7 @@ makes a clear distinction between an initiator (often called a HBA) and
a target (device) while (at least on the PCIe transport) the NVMe
controller plays both roles. At this time this utility only
supports "Admin" commands (i.e. it does not support the I/O (or "NVM")
-command set). Admin commands are sent to submission queue 0 while non-admin
+command set). Admin commands are sent to submission queue 0 while non\-admin
commands are sent to submissions greater than 0.
.PP
One significant difference is that SCSI uses a big endian representation
diff --git a/doc/sg_reset.8 b/doc/sg_reset.8
index 0444a7f5..5d4f8f37 100644
--- a/doc/sg_reset.8
+++ b/doc/sg_reset.8
@@ -117,7 +117,7 @@ output will be verbose as it was previously (equivalent to using the
\fI\-\-verbose\fR option now).
For example:
.PP
- SG_RESET_OLD_OPTS=1 sg_reset -h /dev/sg1
+ SG_RESET_OLD_OPTS=1 sg_reset \-h /dev/sg1
.br
sg_reset: starting host reset
.br
diff --git a/doc/sg_sat_read_gplog.8 b/doc/sg_sat_read_gplog.8
index 1f0c750a..cb8f646f 100644
--- a/doc/sg_sat_read_gplog.8
+++ b/doc/sg_sat_read_gplog.8
@@ -42,7 +42,7 @@ a sense buffer containing a ATA Result descriptor if the ATA command failed.
.TP
\fB\-c\fR, \fB\-\-count\fR=\fICO\fR
the number \fICO\fR is placed in the "count" field in the ATA READ
-LOG EXT command. This specified the number of 512-byte blocks of
+LOG EXT command. This specified the number of 512\-byte blocks of
data to be read from the specified log.
.TP
\fB\-d\fR, \fB\-\-dma\fR
@@ -65,7 +65,7 @@ to process.
\fB\-L\fR, \fB\-\-log\fR=\fILA\fR
the number \fILA\fR is known as the "log address" in the ATA standards and
is placed in bits 7:0 of the "lba" field of the ATA READ LOG (DMA) EXT
-command. This specifies the log to be returned (See ATA-ACS for a detailed
+command. This specifies the log to be returned (See ATA\-ACS for a detailed
list of available log addresses). The default value placed in the "lba
field is 0, returning the directory of available logs. The maximum value
allowed for \fILOG\fR is 0xff.
diff --git a/doc/sg_seek.8 b/doc/sg_seek.8
index c550788b..99685003 100644
--- a/doc/sg_seek.8
+++ b/doc/sg_seek.8
@@ -28,7 +28,7 @@ IMMED=1) then a CONDITION MET status is returned. If the requested number of
blocks did not fit (IMMED=0) or would not fit (IMMED=1) then status GOOD
is returned. So if a disk has a large cache and PRE\-FETCH is used sparingly
then the command is more likely to return CONDITION MET than GOOD. This
-presents some SCSI sub-systems with problems as due to its rareness they
+presents some SCSI sub\-systems with problems as due to its rareness they
mishandle CONDITION MET and treat it as an error.
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
@@ -116,7 +116,8 @@ print the version string and then exit.
\fB\-w\fR, \fB\-\-wrap\-offset\fR=\fIWO\fR
\fIWO\fR is the number of blocks, relative to \fILBA\fR, that when exceeded,
set the next command's logical block address back to \fILBA\fR. Whether
-this "reset-to-LBA" action occurs depends on the values \fINC\fR and \fISB\fR.
+this "reset\-to\-LBA" action occurs depends on the values \fINC\fR and
+\fISB\fR.
.SH NOTES
As of Linux kernel 4.15 the CONDITION MET status is logged as an error.
.SH EXIT STATUS
diff --git a/doc/sg_ses.8 b/doc/sg_ses.8
index b838267b..51cf77c1 100644
--- a/doc/sg_ses.8
+++ b/doc/sg_ses.8
@@ -207,7 +207,7 @@ option is used). Also see the \fI\-\-raw\fR option which may be used
with this option.
.br
To dump one of more dpage responses to stdout in ASCII parsable hexadecimal
-use \fI-HHH\fR or \fI-HHHH\fR. The triple H form only outputs hexadecimals
+use \fI\-HHH\fR or \fI\-HHHH\fR. The triple H form only outputs hexadecimals
which is fine for a single dpage response. When all dpages are dumped (e.g.
with \fI\-\-page=all\fR) then the quad H form adds the name of each dpage
following a hash mark ('#'). The \fI\-\-data=\fR option parser ignores
diff --git a/doc/sg_ses_microcode.8 b/doc/sg_ses_microcode.8
index 0f486b03..43e73ac2 100644
--- a/doc/sg_ses_microcode.8
+++ b/doc/sg_ses_microcode.8
@@ -166,9 +166,9 @@ dmc_offs_defer [14, 0xe]
Download microcode with offsets, save, and defer activate.
.TP
activate_mc [15, 0xf]
-Activate deferred microcode. There is no follow-up RECEIVE DIAGNOSTIC RESULTS
-to fetch the Download microcode status dpage since the \fIDEVICE\fR might be
-resetting.
+Activate deferred microcode. There is no follow\-up RECEIVE DIAGNOSTIC
+RESULTS to fetch the Download microcode status dpage since the \fIDEVICE\fR
+might be resetting.
.PP
Apart from dmc_status, these are placed in the Download microcode mode
field in the Download microcode control dpage. In the case of dmc_status
diff --git a/doc/sg_vpd.8 b/doc/sg_vpd.8
index 3ee10fc7..1bbdc7c2 100644
--- a/doc/sg_vpd.8
+++ b/doc/sg_vpd.8
@@ -147,10 +147,11 @@ binary.
.TP
\fB\-M\fR, \fB\-\-vendor\fR=\fIVP\fR
where \fIVP\fR is a vendor (e.g. "sea" for Seagate) or vendor/product
-acronym (e.g. "hp3par" for the 3PAR array from HP). Many vendors have re-used
-the numbers at the beginning of the vendor specific VPD page range (e.g.
-page 0xc0) and this option is a way of selecting only those which are of
-interest. Using a \fIVP\fR of "xxx" will list the available acronyms.
+acronym (e.g. "hp3par" for the 3PAR array from HP). Many vendors have
+re\-used the numbers at the beginning of the vendor specific VPD page
+range (e.g. page 0xc0) and this option is a way of selecting only those
+which are of interest. Using a \fIVP\fR of "xxx" will list the available
+acronyms.
.br
If this option is used with \fI\-\-page=PG\fR and \fIPG\fR is an acronym
then this option is ignored. If \fIPG\fR is a number (e.g. 0xc0) then
diff --git a/doc/sg_write_buffer.8 b/doc/sg_write_buffer.8
index cde60deb..d2aab53e 100644
--- a/doc/sg_write_buffer.8
+++ b/doc/sg_write_buffer.8
@@ -181,7 +181,7 @@ can be quite small, for example 4096 bytes, resulting in many WRITE
BUFFER commands being sent.
.PP
Attempting to download a microcode/firmware file that is too large may
-cause an error to occur in the pass-through layer (i.e. before the
+cause an error to occur in the pass\-through layer (i.e. before the
SCSI command is issued). In Linux such error reports can be obscure as
in "pass through os error invalid argument". FreeBSD reports such
errors well to the machine's console but returns a cryptic error message
diff --git a/doc/sg_write_verify.8 b/doc/sg_write_verify.8
index 195fa1ae..1ae27cb0 100644
--- a/doc/sg_write_verify.8
+++ b/doc/sg_write_verify.8
@@ -1,4 +1,4 @@
-.TH "WRITE AND VERIFY" "8" "July 2014" "sg3_utils\-1.40" SG3_UTILS
+.TH "WRITE AND VERIFY" "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sg_write_and_verify \- send the SCSI WRITE AND VERIFY command
.SH SYNOPSIS
@@ -161,13 +161,13 @@ Since '\-\-num=' is not given then it defaults to 1. Further the \fIILEN\fR
value is obtained from the file size of t.bin . To additionally do a
data\-out comparison to the read back data:
.PP
- # sg_write_verify -l 0x1234 -i t.bin --bytchk=1 /dev/sg4
+ # sg_write_verify \-l 0x1234 \-i t.bin --bytchk=1 /dev/sg4
.PP
The ddpt command can do copies between SCSI devices using READ and WRITE
commands. However, currently it has no facility to promote those WRITES
to WRITE AND VERIFY commands. Using a pipe, that could be done like this:
.PP
- # ddpt if=/dev/sg2 bs=512 bpt=8 count=11 of=- |
+ # ddpt if=/dev/sg2 bs=512 bpt=8 count=11 of=\- |
.br
sg_write_verify \-\-in=\- \-l 0x567 \-n 8 \-\-ilen=4096 \-\-repeat /dev/sg4
.PP
@@ -182,7 +182,7 @@ Bruno Goncalves and Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2014 Douglas Gilbert
+Copyright \(co 2014\-2018 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sg_write_x.8 b/doc/sg_write_x.8
index 5d776709..122d950a 100644
--- a/doc/sg_write_x.8
+++ b/doc/sg_write_x.8
@@ -292,7 +292,7 @@ OSes, any number of zeros can be produced by using the /dev/zero device file.
.br
\fIIF\fR may be "\-" which is taken as stdin. In this case the
\fI\-\-offset=OFF,DLEN\fR can be given with \fIOFF\fR set to 0 and
-\fILEN\fR set to a non-zero value, preferably a multiple of the actual block
+\fILEN\fR set to a non\-zero value, preferably a multiple of the actual block
size. The utility can also deduce how long the \fIIF\fR should be from
\fINUM\fR (or the sum of them in the case of a scatter list).
.TP
@@ -435,7 +435,7 @@ where \fITO\fR is the command timeout value in seconds. The default value is
may require considerably more time than 120 seconds to complete.
.TP
\fB\-u\fR, \fB\-\-unmap\fR=\fIU_A\fR
-where \fIU_A\fR is OR-ed bit values used to set the UNMAP and ANCHOR bit
+where \fIU_A\fR is OR\-ed bit values used to set the UNMAP and ANCHOR bit
fields in the WRITE SAME (16 or 32) cdb. If \fIU_A\fR is 1 then the UNMAP
bit field is set; if \fIU_A\fR is 2 then the ANCHOR bit field is set; if
\fIU_A\fR is 3 then both the UNMAP and ANCHOR bit fields are set. The
diff --git a/doc/sgm_dd.8 b/doc/sgm_dd.8
index d4e0378c..346bedb9 100644
--- a/doc/sgm_dd.8
+++ b/doc/sgm_dd.8
@@ -1,4 +1,4 @@
-.TH SGM_DD "8" "February 2015" "sg3_utils\-1.41" SG3_UTILS
+.TH SGM_DD "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sgm_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -9,7 +9,8 @@ devices
[\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR]
.PP
[\fIbpt=BPT\fR] [\fIcdbsz=\fR6|10|12|16] [\fIdio=\fR0|1] [\fIsync=\fR0|1]
-[\fItime=\fR0|1] [\fIverbose=VERB\fR]
+[\fItime=\fR0|1] [\fIverbose=VERB\fR] [\fI\-\-dry\-run\fR]
+[\fI\-\-verbose\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -134,10 +135,21 @@ A value of 1 reports extra information that is not repetitive. A value
repetitive. Values of 3 and 4 yield output for all SCSI commands (and
Unix read() and write() calls) so there can be a lot of output.
.TP
-\fB\-\-help\fR
+\fB\-d\fR, \fB\-\-dry\-run\fR
+does all the command line parsing and preparation but bypasses the actual
+copy or read. That preparation may include opening \fIIFILE\fR or
+\fIOFILE\fR to determine their lengths. This option may be useful for
+testing the syntax of complex command line invocations in advance of
+executing them.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
outputs usage message and exits.
.TP
-\fB\-\-version\fR
+\fB\-v\fR, \fB\-\-verbose\fR
+when used once, this is equivalent to \fIverbose=1\fR. When used
+twice (e.g. "\-vv") this is equivalent to \fIverbose=2\fR, etc.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
outputs version number information and exits.
.SH FLAGS
Here is a list of flags and their meanings:
@@ -238,7 +250,6 @@ advanced "copy on error" logic see the
.B sg_dd
utility (and its 'coe' flag).
.SH EXAMPLES
-.PP
See the examples given in the man page for
.B sg_dd(8).
.SH SIGNALS
@@ -258,7 +269,7 @@ Written by Douglas Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000\-2015 Douglas Gilbert
+Copyright \(co 2000\-2018 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/sgp_dd.8 b/doc/sgp_dd.8
index 9a0ead5c..0c997121 100644
--- a/doc/sgp_dd.8
+++ b/doc/sgp_dd.8
@@ -1,4 +1,4 @@
-.TH SGP_DD "8" "December 2017" "sg3_utils\-1.43" SG3_UTILS
+.TH SGP_DD "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
.SH NAME
sgp_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -10,7 +10,7 @@ devices
.PP
[\fIbpt=BPT\fR] [\fIcoe=\fR0|1] [\fIcdbsz=\fR6|10|12|16] [\fIdeb=VERB\fR]
[\fIdio=\fR0|1] [\fIsync=\fR0|1] [\fIthr=THR\fR] [\fItime=\fR0|1]
-[\fIverbose=VERB\fR]
+[\fIverbose=VERB\fR] [\fI\-\-dry\-run\fR] [\fI\-\-verbose\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -134,10 +134,21 @@ performed, outputting the results (to stderr) at completion. When
increase verbosity. Same as \fIdeb=VERB\fR. Added for compatibility with
sg_dd and sgm_dd.
.TP
-\fB\-\-help\fR
+\fB\-d\fR, \fB\-\-dry\-run\fR
+does all the command line parsing and preparation but bypasses the actual
+copy or read. That preparation may include opening \fIIFILE\fR or
+\fIOFILE\fR to determine their lengths. This option may be useful for
+testing the syntax of complex command line invocations in advance of
+executing them.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
outputs usage message and exits.
.TP
-\fB\-\-version\fR
+\fB\-v\fR, \fB\-\-verbose\fR
+when used once, this is equivalent to \fIverbose=1\fR. When used
+twice (e.g. "\-vv") this is equivalent to \fIverbose=2\fR, etc.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
outputs version number information and exits.
.SH FLAGS
Here is a list of flags and their meanings:
diff --git a/include/sg_lib.h b/include/sg_lib.h
index 547ab029..18f7e192 100644
--- a/include/sg_lib.h
+++ b/include/sg_lib.h
@@ -350,6 +350,16 @@ char * sg_get_nvme_cmd_status_str(uint16_t sct_sc, int buff_len, char * buff);
bool sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
uint8_t * asc_p, uint8_t * ascq_p);
+/* Add vendor (sg3_utils) specific sense descriptor for the NVMe Status
+ * field. Assumes descriptor (i.e. not fixed) sense. Assume sbp has room. */
+void sg_nvme_desc2sense(uint8_t * sbp, bool dnr, bool more, uint16_t sct_sc);
+
+/* Build minimum sense buffer, either descriptor type (desc=true) or fixed
+ * type (desc=false). Assume sbp has enough room (8 or 14 bytes
+ * respectively). sbp should have room for 32 or 18 bytes respectively */
+void sg_build_sense_buffer(bool desc, uint8_t *sbp, uint8_t skey,
+ uint8_t asc, uint8_t ascq);
+
extern FILE * sg_warnings_strm;
void sg_set_warnings_strm(FILE * warnings_strm);
@@ -360,6 +370,10 @@ void sg_set_warnings_strm(FILE * warnings_strm);
void sg_print_command(const uint8_t * command);
void sg_print_scsi_status(int scsi_status);
+/* DSENSE is 'descriptor sense' as opposed to the older 'fixed sense'. Reads
+ * environment variable SG3_UTILS_DSENSE. Only (currently) used in SNTL. */
+bool sg_get_initial_dsense(void);
+
/* 'leadin' is string prepended to each line printed out, NULL treated as
* "". N.B. prior to sg3_utils v 1.42 'leadin' was only prepended to the
* first line printed. */
diff --git a/include/sg_pr2serr.h b/include/sg_pr2serr.h
index 4419087e..6f0b766a 100644
--- a/include/sg_pr2serr.h
+++ b/include/sg_pr2serr.h
@@ -8,6 +8,12 @@
* license that can be found in the BSD_LICENSE file.
*/
+/* These are convenience functions that replace the somewhat long-winded
+ * fprintf(stderr, ....). The second form (i.e. pr2ws() ) is for internal
+ * library use and may place its output somewhere other than stderr; it
+ * depends on the external variable sg_warnings_strm which can be set
+ * with sg_set_warnings_strm(). By default it uses stderr. */
+
#include <stdio.h>
#ifdef __cplusplus
@@ -18,8 +24,13 @@ extern "C" {
#if defined(__GNUC__) || defined(__clang__)
int pr2serr(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
+
+int pr2ws(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
#else
int pr2serr(const char * fmt, ...);
+
+int pr2ws(const char * fmt, ...);
#endif
diff --git a/include/sg_pt_linux.h b/include/sg_pt_linux.h
index b6dea224..00010ba8 100644
--- a/include/sg_pt_linux.h
+++ b/include/sg_pt_linux.h
@@ -98,8 +98,9 @@ struct sg_pt_linux_scsi {
bool is_bsg;
bool is_nvme; /* OS device type, if false ignore nvme_direct */
bool nvme_direct; /* false: our SNTL; true: received NVMe command */
+ bool nvme_stat_dnr; /* Do No Retry, part of completion status field */
+ bool nvme_stat_more; /* More, part of completion status field */
bool mdxfer_out; /* direction of metadata xfer, true->data-out */
- bool scsi_dsense; /* SCSI descriptor sense active when true */
int dev_fd; /* -1 if not given (yet) */
int in_err;
int os_err;
diff --git a/include/sg_pt_nvme.h b/include/sg_pt_nvme.h
index 14525120..a910b052 100644
--- a/include/sg_pt_nvme.h
+++ b/include/sg_pt_nvme.h
@@ -114,7 +114,7 @@ __packed;
#endif
struct sg_sntl_dev_state_t {
- uint8_t descriptor_sense;
+ uint8_t scsi_dsense;
uint8_t enclosure_override; /* ENC_OV in sdparm */
uint8_t pdt; /* 6 bit value in INQUIRY response */
uint8_t enc_serv; /* single bit in INQUIRY response */
diff --git a/lib/sg_cmds_basic.c b/lib/sg_cmds_basic.c
index 4b91ec57..ad298896 100644
--- a/lib/sg_cmds_basic.c
+++ b/lib/sg_cmds_basic.c
@@ -30,6 +30,7 @@
#include "sg_cmds_basic.h"
#include "sg_pt.h"
#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
/* Needs to be after config.h */
#ifdef SG_LIB_LINUX
@@ -37,7 +38,7 @@
#endif
-static const char * const version_str = "1.87 20180522";
+static const char * const version_str = "1.88 20180603";
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -65,26 +66,6 @@ sg_cmds_version()
return version_str;
}
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
/* Returns file descriptor >= 0 if successful. If error in Unix returns
negated errno. */
int
diff --git a/lib/sg_cmds_basic2.c b/lib/sg_cmds_basic2.c
index eb7e2fef..227b8601 100644
--- a/lib/sg_cmds_basic2.c
+++ b/lib/sg_cmds_basic2.c
@@ -28,6 +28,7 @@
#include "sg_cmds_basic.h"
#include "sg_pt.h"
#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
@@ -69,26 +70,6 @@
#define INQUIRY_RESP_INITIAL_LEN 36
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
static struct sg_pt_base *
create_pt_obj(const char * cname)
{
diff --git a/lib/sg_cmds_extra.c b/lib/sg_cmds_extra.c
index 232d55d6..90168969 100644
--- a/lib/sg_cmds_extra.c
+++ b/lib/sg_cmds_extra.c
@@ -24,6 +24,7 @@
#include "sg_cmds_extra.h"
#include "sg_pt.h"
#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -101,25 +102,6 @@
#define REPORT_REFERRALS_SA 0x13
#define EXTENDED_COPY_LID1_SA 0x0
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
static struct sg_pt_base *
create_pt_obj(const char * cname)
diff --git a/lib/sg_cmds_mmc.c b/lib/sg_cmds_mmc.c
index 759e7ce6..e1358591 100644
--- a/lib/sg_cmds_mmc.c
+++ b/lib/sg_cmds_mmc.c
@@ -22,6 +22,7 @@
#include "sg_cmds_mmc.h"
#include "sg_pt.h"
#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -37,25 +38,6 @@
#define SET_STREAMING_CMD 0xb6
#define SET_STREAMING_CMDLEN 12
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
static struct sg_pt_base *
create_pt_obj(const char * cname)
diff --git a/lib/sg_io_linux.c b/lib/sg_io_linux.c
index 1619b40e..1be42f68 100644
--- a/lib/sg_io_linux.c
+++ b/lib/sg_io_linux.c
@@ -21,27 +21,7 @@
#include "sg_io_linux.h"
-/* Version 1.08 20180218 */
-
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
+/* Version 1.09 20180603 */
void
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index d127f3ba..fd1b12c3 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -53,15 +53,8 @@
FILE * sg_warnings_strm = NULL; /* would like to default to stderr */
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-static int
+int
pr2ws(const char * fmt, ...)
{
va_list args;
@@ -103,11 +96,28 @@ scnpr(char * cp, int cp_max_len, const char * fmt, ...)
/* Simple ASCII printable (does not use locale), includes space and excludes
* DEL (0x7f). */
-static inline int my_isprint(int ch)
+static inline int
+my_isprint(int ch)
{
return ((ch >= ' ') && (ch < 0x7f));
}
+/* DSENSE is 'descriptor sense' as opposed to the older 'fixed sense'.
+ * Only (currently) used in SNTL. */
+bool
+sg_get_initial_dsense(void)
+{
+ int k;
+ const char * cp;
+
+ cp = getenv("SG3_UTILS_DSENSE");
+ if (cp) {
+ if (1 == sscanf(cp, "%d", &k))
+ return k ? true : false;
+ }
+ return false;
+}
+
/* Searches 'arr' for match on 'value' then 'peri_type'. If matches
'value' but not 'peri_type' then yields first 'value' match entry.
Last element of 'arr' has NULL 'name'. If no match returns NULL. */
@@ -1290,6 +1300,7 @@ sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
{
int add_sb_len, add_d_len, desc_len, k, j, sense_key;
int n, progress, pr, rem;
+ uint16_t sct_sc;
bool processed;
const uint8_t * descp;
const char * dtsp = " >> descriptor too short";
@@ -1549,6 +1560,24 @@ sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
else
n += scnpr(b + n, blen - n, "%d seconds\n", progress);
break;
+ case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */
+ n += scnpr(b + n, blen - n, "NVMe Status: ");
+ if (add_d_len < 6) {
+ n += scnpr(b + n, blen - n, "%s\n", dtsp);
+ processed = false;
+ break;
+ }
+ n += scnpr(b + n, blen - n, "DNR=%d, M=%d, ",
+ (int)!!(0x80 & descp[5]), (int)!!(0x40 & descp[5]));
+ sct_sc = sg_get_unaligned_be16(descp + 6);
+ n += scnpr(b + n, blen - n, "SCT_SC=0x%x\n", sct_sc);
+ if (sct_sc > 0) {
+ char d[80];
+
+ n += scnpr(b + n, blen - n, " %s\n",
+ sg_get_nvme_cmd_status_str(sct_sc, sizeof(d), d));
+ }
+ break;
default:
if (descp[0] >= 0x80)
n += scnpr(b + n, blen - n, "Vendor specific [0x%x]\n",
@@ -1678,8 +1707,8 @@ sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len,
n += scnpr(cbp + n, cblen - n, "%s%s; Sense key: %s\n", lip, ebp,
sg_lib_sense_key_desc[ssh.sense_key]);
if (sdat_ovfl)
- n += scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow>>>\n",
- lip);
+ n += scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow "
+ "(SDAT_OVFL)>>>\n", lip);
if (descriptor_format) {
n += scnpr(cbp + n, cblen - n, "%s%s\n", lip,
sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
@@ -1814,14 +1843,25 @@ sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len,
}
check_raw:
if (raw_sinfo) {
+ int embed_len;
char z[64];
- n += scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex):\n",
- lip);
+ n += scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex), "
+ "sb_len=%d", lip, sb_len);
if (n >= (cblen - 1))
return n;
+ if ((sb_len > 7) && (sbp[0] >= 0x70) && (sbp[0] < 0x74)) {
+ embed_len = sbp[7] + 8;
+ n += scnpr(cbp + n, cblen - n, ", embedded_len=%d\n", embed_len);
+ } else {
+ embed_len = sb_len;
+ n += scnpr(cbp + n, cblen - n, "\n");
+ }
+ if (n >= (cblen - 1))
+ return n;
+
scnpr(z, sizeof(z), "%.50s ", lip);
- n += hex2str(sbp, len, z, -1, cblen - n, cbp + n);
+ n += hex2str(sbp, embed_len, z, -1, cblen - n, cbp + n);
}
return n;
}
@@ -1852,7 +1892,9 @@ sg_print_sense(const char * leadin, const uint8_t * sbp, int sb_len,
* output; in both cases true is returned. If exit_status is negative then
* a null character is output and false is returned. All messages are a
* single line (less than 80 characters) with no trailing LF. The output
- * string including the trailing null character is no longer than b_len. */
+ * string including the trailing null character is no longer than b_len.
+ * exit_status represents the Unix exit status available after a utility
+ * finishes executing (for whatever reason). */
bool sg_exit2str(int exit_status, bool longer, int b_len, char *b)
{
const struct sg_value_2names_t * ess = sg_exit_str_arr;
@@ -1874,6 +1916,10 @@ bool sg_exit2str(int exit_status, bool longer, int b_len, char *b)
snprintf(b, b_len, "%s%s", (longer ? "OS error: " : ""),
safe_strerror(exit_status - SG_LIB_OS_BASE_ERR));
return true;
+ } else if ((exit_status > 128) && (exit_status < 255)) {
+ snprintf(b, b_len, "Utility stopped/aborted by signal number: %d",
+ exit_status - 128);
+ return true;
}
for ( ; ess->name; ++ess) {
if (exit_status == ess->value)
@@ -2539,6 +2585,46 @@ sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
return true;
}
+/* Add vendor (sg3_utils) specific sense descriptor for the NVMe Status
+ * field. Assumes descriptor (i.e. not fixed) sense. Assumes sbp has room. */
+void
+sg_nvme_desc2sense(uint8_t * sbp, bool dnr, bool more, uint16_t sct_sc)
+{
+ int len = sbp[7] + 8;
+
+ sbp[len] = 0xde; /* vendor specific descriptor type */
+ sbp[len + 1] = 6; /* descriptor is 8 bytes long */
+ memset(sbp + len + 2, 0, 6);
+ if (dnr)
+ sbp[len + 5] = 0x80;
+ if (more)
+ sbp[len + 5] |= 0x40;
+ sg_put_unaligned_be16(sct_sc, sbp + len + 6);
+ sbp[7] += 8;
+}
+
+/* Build minimum sense buffer, either descriptor type (desc=true) or fixed
+ * type (desc=false). Assume sbp has enough room (8 or 14 bytes
+ * respectively). sbp should have room for 32 or 18 bytes respectively */
+void
+sg_build_sense_buffer(bool desc, uint8_t *sbp, uint8_t skey, uint8_t asc,
+ uint8_t ascq)
+{
+ if (desc) {
+ sbp[0] = 0x72; /* descriptor, current */
+ sbp[1] = skey;
+ sbp[2] = asc;
+ sbp[3] = ascq;
+ sbp[7] = 0;
+ } else {
+ sbp[0] = 0x70; /* fixed, current */
+ sbp[2] = skey;
+ sbp[7] = 0xa; /* Assumes length is 18 bytes */
+ sbp[12] = asc;
+ sbp[13] = ascq;
+ }
+}
+
/* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
* Allows for situation in which strerror() is given a wild value (or the
* C library is incomplete) and returns NULL. Still not thread safe.
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 4256315c..80e91f9f 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -17,7 +17,7 @@
#include "sg_lib_data.h"
-const char * sg_lib_version_str = "2.48 20180530";/* spc5r19, sbc4r15 */
+const char * sg_lib_version_str = "2.50 20180603";/* spc5r19, sbc4r15 */
/* indexed by pdt; those that map to own index do not decay */
@@ -1743,28 +1743,30 @@ struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] =
struct sg_value_2names_t sg_exit_str_arr[] = {
{0, "No errors", NULL},
{1, "Syntax error", "command line options (usually)"},
- {2, "Device not ready", "sense key"},
- {3, "Medium or hardware error", "sense key (plus blank check for tape)"},
- {5, "Illegal request", "sense key, apart from Invalid opcode"},
- {6, "Unit attention", "sense key"},
- {7, "Data protect", "sense key, write protected media?"},
- {9, "Illegal request, Invalid opcode", "sense key + asc,ascq"},
- {10, "Copy aborted", "sense key"},
+ {2, "Device not ready", "type: sense key"},
+ {3, "Medium or hardware error", "type: sense key (plus blank check for "
+ "tape)"},
+ {5, "Illegal request", "type: sense key, apart from Invalid opcode"},
+ {6, "Unit attention", "type: sense key"},
+ {7, "Data protect", "type: sense key; write protected media?"},
+ {9, "Illegal request, Invalid opcode", "type: sense key + asc,ascq"},
+ {10, "Copy aborted", "type: sense key"},
{11, "Aborted command",
- "sense key, other than protection related (asc=0x10)"},
- {14, "Miscompare", "sense key"},
+ "type: sense key, other than protection related (asc=0x10)"},
+ {14, "Miscompare", "type: sense key"},
{15, "File error", NULL},
{17, "Illegal request with Info field", NULL},
{18, "Medium or hardware error with Info", NULL},
- {20, "No sense key", "probably additional sense code"},
- {21, "Recovered error (warning)", "sense key"}, /* Warning not error */
+ {20, "No sense key", "type: probably additional sense code"},
+ {21, "Recovered error (warning)", "tye: sense key"},
+ /* N.B. this is a warning not error */
{22, "LBA out of range", NULL},
- {24, "Reservation conflict", "SCSI status"},
- {25, "Condition met", "SCSI status"}, /* from PRE-FETCH command */
- {26, "Busy", "SCSI status"}, /* more likely if SAS expander present */
- {27, "Task set full", "SCSI status"},
- {28, "ACA aactive", "SCSI status"},
- {29, "Task aborted", "SCSI status"},
+ {24, "Reservation conflict", "type: SCSI status"},
+ {25, "Condition met", "type: SCSI status"}, /* from PRE-FETCH command */
+ {26, "Busy", "type: SCSI status"}, /* could be transport issue */
+ {27, "Task set full", "type: SCSI status"},
+ {28, "ACA aactive", "type: SCSI status"},
+ {29, "Task aborted", "type: SCSI status"},
{31, "Contradict", "command line options contradict or select bad mode"},
{32, "Logic error", "unexpected situation, contact author"},
{33, "SCSI command timeout", NULL}, /* OS timed out command */
@@ -1772,7 +1774,7 @@ struct sg_value_2names_t sg_exit_str_arr[] = {
{41, "Aborted command, protection error with Info field", NULL},
{47, "flock (Unix system call) error", NULL}, /* ddpt */
{48, "NVMe command with non-zero status", NULL},
- {50, "An OS error occurred", "(errno > 46)"},
+ {50, "An OS error occurred", "(errno > 46 or negative)"},
/* OS errors (errno in Unix) from 1 to 46 mapped into this range */
{97, "Malformed SCSI command", "trouble building command"},
{98, "Some other sense error", "try '-v' option for more information"},
@@ -1802,11 +1804,13 @@ struct sg_value_2names_t sg_exit_str_arr[] = {
{120, "Invalid token operation, invalid token length", NULL},
/* The following error codes are generated by a Unix OS */
- /* 126: utility did not have executable permissions */
- /* 127: utility to be executed not found */
+ {126, "Utility found but did not have execute permissions", NULL},
+ {127, "Utility to be executed was not found", NULL},
+ {128, "Utility stopped/aborted by signal number: 0", "signal # 0 ??"},
/* 128 + <signal_number>: signal number that aborted the utility.
real time signals start at offset SIGRTMIN */
- /* 255: utility returned an exit status > 255 (and probably < 0) */
+ /* OS signals from 1 to 126 mapped into this range (129 to 254) */
+ {255, "Utility returned 255 or higher", "Windows error number?"},
{0xffff, NULL, NULL}, /* end marking sentinel */
};
diff --git a/lib/sg_pt_common.c b/lib/sg_pt_common.c
index 8049f53d..060923b6 100644
--- a/lib/sg_pt_common.c
+++ b/lib/sg_pt_common.c
@@ -23,13 +23,14 @@
#include "sg_pt.h"
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
+#include "sg_pr2serr.h"
#if (HAVE_NVME && (! IGNORE_NVME))
#include "sg_pt_nvme.h"
#endif
-static const char * scsi_pt_version_str = "3.06 20180531";
+static const char * scsi_pt_version_str = "3.07 20180603";
@@ -45,6 +46,7 @@ sg_pt_version()
return scsi_pt_version_str;
}
+
#if (HAVE_NVME && (! IGNORE_NVME))
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
@@ -297,8 +299,10 @@ resp_vs_ua_m_pg(uint8_t *p, int pcontrol)
void
sntl_init_dev_stat(struct sg_sntl_dev_state_t * dsp)
{
- dsp->descriptor_sense = !! (0x4 & ctrl_m_pg[2]);
- dsp->enclosure_override = vs_ua_m_pg[2];
+ if (dsp) {
+ dsp->scsi_dsense = !! (0x4 & ctrl_m_pg[2]);
+ dsp->enclosure_override = vs_ua_m_pg[2];
+ }
}
@@ -499,7 +503,7 @@ sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp,
if (ctrl_m_pg[1] == arr[off + 1]) {
memcpy(ctrl_m_pg + 2, arr + off + 2,
sizeof(ctrl_m_pg) - 2);
- dsp->descriptor_sense = !!(ctrl_m_pg[2] & 0x4);
+ dsp->scsi_dsense = !!(ctrl_m_pg[2] & 0x4);
break;
}
}
diff --git a/lib/sg_pt_freebsd.c b/lib/sg_pt_freebsd.c
index 491d1305..b168bcd0 100644
--- a/lib/sg_pt_freebsd.c
+++ b/lib/sg_pt_freebsd.c
@@ -5,7 +5,7 @@
* license that can be found in the BSD_LICENSE file.
*/
-/* sg_pt_freebsd version 1.29 20180531 */
+/* sg_pt_freebsd version 1.30 20180603 */
#include <stdio.h>
#include <stdlib.h>
@@ -39,6 +39,7 @@
#include "sg_lib.h"
#include "sg_unaligned.h"
#include "sg_pt_nvme.h"
+#include "sg_pr2serr.h"
#if (HAVE_NVME && (! IGNORE_NVME))
#include "freebsd_nvme_ioctl.h"
@@ -67,7 +68,7 @@ struct freebsd_dev_channel {
uint8_t * nvme_id_ctlp;
uint8_t * free_nvme_id_ctlp;
uint8_t cq_dw0_3[16];
- struct sg_sntl_dev_state_t dev_stat;
+ struct sg_sntl_dev_state_t dev_stat; // owner
};
// Private table of open devices: guaranteed zero on startup since
@@ -93,7 +94,6 @@ struct sg_pt_freebsd_scsi {
uint32_t dxfer_olen;
uint32_t mdxfer_len;
bool mdxfer_out;
- bool scsi_dsense;
int timeout_ms;
int scsi_status;
int resid;
@@ -106,6 +106,7 @@ struct sg_pt_freebsd_scsi {
// index into devicetable[]
bool is_nvme; // copy of same field in fdc object
bool nvme_direct; // copy of same field in fdc object
+ struct sg_sntl_dev_state_t * dev_statp; // points to associated fdc
};
struct sg_pt_base {
@@ -114,27 +115,9 @@ struct sg_pt_base {
static const uint32_t broadcast_nsid = SG_NVME_BROADCAST_NSID;
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
static int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int vb);
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
static struct freebsd_dev_channel *
get_fdc_p(struct sg_pt_freebsd_scsi * ptp)
@@ -376,6 +359,11 @@ check_pt_file_handle(int device_han, const char * device_name, int vb)
}
}
+#if (HAVE_NVME && (! IGNORE_NVME))
+static bool checked_ev_dsense = false;
+static bool ev_dsense = false;
+#endif
+
struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int dev_han, int vb)
{
@@ -393,6 +381,15 @@ construct_scsi_pt_obj_with_fd(int dev_han, int vb)
if (fdc_p) {
ptp->is_nvme = fdc_p->is_nvme;
ptp->cam_dev = fdc_p->cam_dev;
+ ptp->dev_statp = &fdc_p->dev_stat;
+#if (HAVE_NVME && (! IGNORE_NVME))
+ sntl_init_dev_stat(ptp->dev_statp);
+ if (! checked_ev_dsense) {
+ ev_dsense = sg_get_initial_dsense();
+ checked_ev_dsense = true;
+ }
+ fdc_p->dev_stat.scsi_dsense = ev_dsense;
+#endif
} else if (vb)
pr2ws("%s: bad dev_han=%d\n", __func__, dev_han);
}
@@ -431,6 +428,7 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
int dev_han;
struct sg_pt_freebsd_scsi * ptp;
struct cam_device* cam_dev;
+ struct sg_sntl_dev_state_t * dsp;
if (NULL == vp) {
pr2ws(">>>>> %s: NULL pointer given\n", __func__);
@@ -442,11 +440,13 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
is_nvme = ptp->is_nvme;
dev_han = ptp->dev_han;
cam_dev = ptp->cam_dev;
+ dsp = ptp->dev_statp;
memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi));
ptp->dxfer_dir = CAM_DIR_NONE;
ptp->dev_han = dev_han;
ptp->is_nvme = is_nvme;
ptp->cam_dev = cam_dev;
+ ptp->dev_statp = dsp;
}
}
@@ -984,29 +984,10 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
#if (HAVE_NVME && (! IGNORE_NVME))
static void
-build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
- uint8_t ascq)
-{
- if (desc) {
- buf[0] = 0x72; /* descriptor, current */
- buf[1] = skey;
- buf[2] = asc;
- buf[3] = ascq;
- buf[7] = 0;
- } else {
- buf[0] = 0x70; /* fixed, current */
- buf[2] = skey;
- buf[7] = 0xa; /* Assumes length is 18 bytes */
- buf[12] = asc;
- buf[13] = ascq;
- }
-}
-
-static void
mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp, int sk, int asc, int ascq,
int vb)
{
- bool dsense = ptp->scsi_dsense;
+ bool dsense = ptp->dev_statp->scsi_dsense;
int n;
uint8_t * sbp = ptp->sense;
@@ -1019,7 +1000,7 @@ mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp, int sk, int asc, int ascq,
ptp->sense_resid = ptp->sense_len -
(dsense ? 8 : ((n < 18) ? n : 18));
memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__,
sk, asc, ascq);
@@ -1030,7 +1011,7 @@ mk_sense_from_nvme_status(struct sg_pt_freebsd_scsi * ptp, uint16_t sct_sc,
int vb)
{
bool ok;
- bool dsense = ptp->scsi_dsense;
+ bool dsense = ptp->dev_statp->scsi_dsense;
int n;
uint8_t sstatus, sk, asc, ascq;
uint8_t * sbp = ptp->sense;
@@ -1052,10 +1033,15 @@ mk_sense_from_nvme_status(struct sg_pt_freebsd_scsi * ptp, uint16_t sct_sc,
ptp->sense_resid = ptp->sense_len -
(dsense ? 8 : ((n < 18) ? n : 18));
memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__,
sk, asc, ascq);
+ if (dsense && (sct_sc > 0) && (ptp->sense_resid > 7)) {
+ sg_nvme_desc2sense(sbp, 0x4000 & sct_sc /* dnr */,
+ 0x2000 & sct_sc /* more */, 0x7ff & sct_sc);
+ ptp->sense_resid -= 8;
+ }
}
/* Set in_bit to -1 to indicate no bit position of invalid field */
@@ -1063,7 +1049,7 @@ static void
mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp, bool in_cdb,
int in_byte, int in_bit, int vb)
{
- bool ds = ptp->scsi_dsense;
+ bool ds = ptp->dev_statp->scsi_dsense;
int sl, asc, n;
uint8_t * sbp = (uint8_t *)ptp->sense;
uint8_t sks[4];
@@ -1078,7 +1064,7 @@ mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp, bool in_cdb,
} else
ptp->sense_resid = ptp->sense_len - (ds ? 8 : ((n < 18) ? n : 18));
memset(sbp, 0, n);
- build_sense_buffer(ds, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
+ sg_build_sense_buffer(ds, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
memset(sks, 0, sizeof(sks));
sks[0] = 0x80;
if (in_cdb)
@@ -1295,7 +1281,7 @@ sntl_inq(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int vb)
inq_dout[1] = pg_cd;
n = 24;
sg_put_unaligned_be16(n - 4, inq_dout + 2);
- memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
+ memcpy(inq_dout + 4, fdc_p->nvme_id_ctlp + 4, 20); /* SN */
break;
case 0x83: /* Device identification VPD page */
if ((fdc_p->nsid > 0) && (fdc_p->nsid < SG_NVME_BROADCAST_NSID)) {
@@ -1577,11 +1563,11 @@ sntl_req_sense(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int vb)
pr2ws("%s: pow_state=%u\n", __func__, pow_state);
memset(rs_dout, 0, sizeof(rs_dout));
if (pow_state)
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- LOW_POWER_COND_ON_ASC, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ LOW_POWER_COND_ON_ASC, 0);
else
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- NO_ADDITIONAL_SENSE, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ NO_ADDITIONAL_SENSE, 0);
n = desc ? 8 : 18;
n = (n < alloc_len) ? n : alloc_len;
n = (n < (uint32_t)ptp->dxfer_len) ? n : (uint32_t)ptp->dxfer_len;
diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c
index af0036d7..64956b3e 100644
--- a/lib/sg_pt_linux.c
+++ b/lib/sg_pt_linux.c
@@ -5,7 +5,7 @@
* license that can be found in the BSD_LICENSE file.
*/
-/* sg_pt_linux version 1.42 20180526 */
+/* sg_pt_linux version 1.43 20180603 */
#include <stdio.h>
@@ -35,6 +35,7 @@
#include "sg_lib.h"
#include "sg_linux_inc.h"
#include "sg_pt_linux.h"
+#include "sg_pr2serr.h"
#ifdef major
@@ -106,26 +107,6 @@ volatile int sg_nvme_char_major = 0;
long sg_lin_page_size = 4096; /* default, overridden with correct value */
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
/* This function only needs to be called once (unless a NVMe controller
* can be hot-plugged into system in which case it should be called
* (again) after that event). */
@@ -382,6 +363,11 @@ scsi_pt_close_device(int device_fd)
return res;
}
+#if (HAVE_NVME && (! IGNORE_NVME))
+static bool checked_ev_dsense = false;
+static bool ev_dsense = false;
+#endif
+
/* Caller should additionally call get_scsi_pt_os_err() after this call */
struct sg_pt_base *
@@ -395,6 +381,11 @@ construct_scsi_pt_obj_with_fd(int dev_fd, int verbose)
if (ptp) {
#if (HAVE_NVME && (! IGNORE_NVME))
sntl_init_dev_stat(&ptp->dev_stat);
+ if (! checked_ev_dsense) {
+ ev_dsense = sg_get_initial_dsense();
+ checked_ev_dsense = true;
+ }
+ ptp->dev_stat.scsi_dsense = ev_dsense;
#endif
err = set_pt_file_handle((struct sg_pt_base *)ptp, dev_fd, verbose);
if ((0 == err) && (! ptp->is_nvme)) {
@@ -444,6 +435,7 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
bool is_sg, is_bsg, is_nvme;
int fd;
uint32_t nvme_nsid;
+ struct sg_sntl_dev_state_t dev_stat;
struct sg_pt_linux_scsi * ptp = &vp->impl;
if (ptp) {
@@ -452,6 +444,7 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
is_bsg = ptp->is_bsg;
is_nvme = ptp->is_nvme;
nvme_nsid = ptp->nvme_nsid;
+ dev_stat = ptp->dev_stat;
if (ptp->free_nvme_id_ctlp)
free(ptp->free_nvme_id_ctlp);
memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
@@ -468,6 +461,7 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
ptp->is_nvme = is_nvme;
ptp->nvme_direct = false;
ptp->nvme_nsid = nvme_nsid;
+ ptp->dev_stat = dev_stat;
}
}
diff --git a/lib/sg_pt_linux_nvme.c b/lib/sg_pt_linux_nvme.c
index f78600af..98ddc501 100644
--- a/lib/sg_pt_linux_nvme.c
+++ b/lib/sg_pt_linux_nvme.c
@@ -39,7 +39,7 @@
* MA 02110-1301, USA.
*/
-/* sg_pt_linux_nvme version 1.04 20180115 */
+/* sg_pt_linux_nvme version 1.05 20180602 */
/* This file contains a small "SPC-only" SNTL to support the SES pass-through
* of SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS through NVME-MI
@@ -76,6 +76,7 @@
#include "sg_linux_inc.h"
#include "sg_pt_linux.h"
#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
#define SCSI_INQUIRY_OPC 0x12
#define SCSI_REPORT_LUNS_OPC 0xa0
@@ -119,25 +120,6 @@
#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
#if (HAVE_NVME && (! IGNORE_NVME))
@@ -170,29 +152,10 @@ sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len,
}
static void
-build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
- uint8_t ascq)
-{
- if (desc) {
- buf[0] = 0x72; /* descriptor, current */
- buf[1] = skey;
- buf[2] = asc;
- buf[3] = ascq;
- buf[7] = 0;
- } else {
- buf[0] = 0x70; /* fixed, current */
- buf[2] = skey;
- buf[7] = 0xa; /* Assumes length is 18 bytes */
- buf[12] = asc;
- buf[13] = ascq;
- }
-}
-
-static void
mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq,
int vb)
{
- bool dsense = !! ptp->dev_stat.descriptor_sense;
+ bool dsense = !! ptp->dev_stat.scsi_dsense;
int n;
uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
@@ -204,9 +167,9 @@ mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq,
__func__, n);
return;
} else
- ptp->io_hdr.response_len = dsense ? 8 : ((n < 18) ? n : 18);
+ ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk,
asc, ascq);
@@ -216,7 +179,7 @@ static void
mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp, int vb)
{
bool ok;
- bool dsense = !! ptp->dev_stat.descriptor_sense;
+ bool dsense = !! ptp->dev_stat.scsi_dsense;
int n;
uint8_t sstatus, sk, asc, ascq;
uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
@@ -235,9 +198,12 @@ mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp, int vb)
pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n);
return;
} else
- ptp->io_hdr.response_len = (dsense ? 8 : ((n < 18) ? n : 18));
+ ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ if (dsense && (ptp->nvme_status > 0))
+ sg_nvme_desc2sense(sbp, ptp->nvme_stat_dnr, ptp->nvme_stat_more,
+ ptp->nvme_status);
if (vb > 3)
pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n",
__func__, sstatus, sk, asc, ascq);
@@ -248,7 +214,7 @@ static void
mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte,
int in_bit, int vb)
{
- bool dsense = !! ptp->dev_stat.descriptor_sense;
+ bool dsense = !! ptp->dev_stat.scsi_dsense;
int sl, asc, n;
uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
uint8_t sks[4];
@@ -262,9 +228,10 @@ mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte,
__func__, n);
return;
} else
- ptp->io_hdr.response_len = dsense ? 8 : ((n < 18) ? n : 18);
+ ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
+
memset(sbp, 0, n);
- build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
+ sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
memset(sks, 0, sizeof(sks));
sks[0] = 0x80;
if (in_cdb)
@@ -340,12 +307,12 @@ do_nvme_admin_cmd(struct sg_pt_linux_scsi * ptp,
ptp->nvme_result = cmdp->result;
if (ptp->nvme_direct && ptp->io_hdr.response &&
(ptp->io_hdr.max_response_len > 3)) {
- /* build 16 byte "sense" buffer */
+ /* build 32 byte "sense" buffer */
uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
uint16_t st = (uint16_t)res;
n = ptp->io_hdr.max_response_len;
- n = (n < 16) ? n : 16;
+ n = (n < 32) ? n : 32;
memset(sbp, 0 , n);
ptp->io_hdr.response_len = n;
sg_put_unaligned_le32(cmdp->result,
@@ -354,8 +321,10 @@ do_nvme_admin_cmd(struct sg_pt_linux_scsi * ptp,
sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P);
}
/* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */
- sct_sc = 0x3ff & res;
+ sct_sc = 0x7ff & res; /* 11 bits */
ptp->nvme_status = sct_sc;
+ ptp->nvme_stat_dnr = !!(0x4000 & res);
+ ptp->nvme_stat_more = !!(0x2000 & res);
if (sct_sc) { /* when non-zero, treat as command error */
if (vb > 1) {
char b[80];
@@ -781,11 +750,11 @@ sntl_req_sense(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
pr2ws("%s: pow_state=%u\n", __func__, pow_state);
memset(rs_dout, 0, sizeof(rs_dout));
if (pow_state)
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- LOW_POWER_COND_ON_ASC, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ LOW_POWER_COND_ON_ASC, 0);
else
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- NO_ADDITIONAL_SENSE, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ NO_ADDITIONAL_SENSE, 0);
n = desc ? 8 : 18;
n = (n < alloc_len) ? n : alloc_len;
n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
diff --git a/lib/sg_pt_osf1.c b/lib/sg_pt_osf1.c
index a140a407..35ca067c 100644
--- a/lib/sg_pt_osf1.c
+++ b/lib/sg_pt_osf1.c
@@ -26,6 +26,7 @@
#include "sg_pt.h"
#include "sg_lib.h"
+#include "sg_pr2serr.h"
#define OSF1_MAXDEV 64
@@ -65,25 +66,6 @@ struct sg_pt_base {
struct sg_pt_osf1_scsi impl;
};
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
-
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
/* Returns >= 0 if successful. If error in Unix returns negated errno. */
diff --git a/lib/sg_pt_win32.c b/lib/sg_pt_win32.c
index 1d218b2e..79c2f346 100644
--- a/lib/sg_pt_win32.c
+++ b/lib/sg_pt_win32.c
@@ -5,7 +5,7 @@
* license that can be found in the BSD_LICENSE file.
*/
-/* sg_pt_win32 version 1.27 20180531 */
+/* sg_pt_win32 version 1.27 20180603 */
#include <stdio.h>
#include <stdlib.h>
@@ -27,6 +27,7 @@
#include "sg_pt.h"
#include "sg_pt_win32.h"
#include "sg_pt_nvme.h"
+#include "sg_pr2serr.h"
/* Comment the following line out to use the pre-W10 NVMe pass-through */
@@ -134,7 +135,7 @@ struct sg_pt_handle {
// uint32_t nvme_nsid; /* how do we find this given file handle ?? */
int verbose; /* tunnel verbose through to scsi_pt_close_device */
char dname[20];
- struct sg_sntl_dev_state_t dev_stat;
+ struct sg_sntl_dev_state_t dev_stat; // owner
};
/* Start zeroed but need to zeroed before use because could be re-use */
@@ -144,7 +145,6 @@ struct sg_pt_win32_scsi {
bool is_nvme;
bool nvme_direct; /* false: our SNTL; true: received NVMe command */
bool mdxfer_out; /* direction of metadata xfer, true->data-out */
- bool scsi_dsense; /* SCSI "descriptor" sense format, active when true */
bool have_nvme_cmd;
bool is_read;
int sense_len;
@@ -171,6 +171,7 @@ struct sg_pt_win32_scsi {
uint8_t * sensep;
uint8_t * nvme_id_ctlp;
uint8_t * free_nvme_id_ctlp;
+ struct sg_sntl_dev_state_t * dev_statp; /* points to handle's dev_stat */
uint8_t nvme_cmd[64];
union {
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb_d;
@@ -191,29 +192,10 @@ static int spt_direct = 1;
static int spt_direct = 0;
#endif
-#if defined(__GNUC__) || defined(__clang__)
-static int pr2ws(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
-#else
-static int pr2ws(const char * fmt, ...);
-#endif
-
static int nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
int time_secs, int vb);
-static int
-pr2ws(const char * fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
- va_end(args);
- return n;
-}
-
/* Request SPT direct interface when state_direct is 1, state_direct set
* to 0 for the SPT indirect interface. */
void
@@ -679,6 +661,11 @@ check_pt_file_handle(int device_fd, const char * device_name, int vb)
/* SCSI generic pass-though device: 1 */
}
+#if (HAVE_NVME && (! IGNORE_NVME))
+static bool checked_ev_dsense = false;
+static bool ev_dsense = false;
+#endif
+
struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int dev_fd, int vb)
{
@@ -709,8 +696,18 @@ construct_scsi_pt_obj_with_fd(int dev_fd, int vb)
1);
if (psp) {
psp->dev_fd = (dev_fd < 0) ? -1 : dev_fd;
- if (shp)
+ if (shp) {
psp->is_nvme = shp->is_nvme;
+ psp->dev_statp = &shp->dev_stat;
+#if (HAVE_NVME && (! IGNORE_NVME))
+ sntl_init_dev_stat(psp->dev_statp);
+ if (! checked_ev_dsense) {
+ ev_dsense = sg_get_initial_dsense();
+ checked_ev_dsense = true;
+ }
+ shp->dev_stat.scsi_dsense = ev_dsense;
+#endif
+ }
if (psp->is_nvme) {
; /* should be 'psp->nvme_nsid = shp->nvme_nsid' */
} else if (spt_direct) {
@@ -835,11 +832,13 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
int dev_fd;
uint32_t nvme_nsid;
struct sg_pt_win32_scsi * psp = vp->implp;
+ struct sg_sntl_dev_state_t * dsp;
if (psp) {
dev_fd = psp->dev_fd;
is_nvme = psp->is_nvme;
nvme_nsid = psp->nvme_nsid;
+ dsp = psp->dev_statp;
memset(psp, 0, sizeof(struct sg_pt_win32_scsi));
if (spt_direct) {
psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
@@ -857,6 +856,7 @@ clear_scsi_pt_obj(struct sg_pt_base * vp)
psp->dev_fd = dev_fd;
psp->is_nvme = is_nvme;
psp->nvme_nsid = nvme_nsid;
+ psp->dev_statp = dsp;
}
}
@@ -1379,31 +1379,11 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
#if (HAVE_NVME && (! IGNORE_NVME))
-
-static void
-build_sense_buffer(bool desc, uint8_t *buf, uint8_t skey, uint8_t asc,
- uint8_t ascq)
-{
- if (desc) {
- buf[0] = 0x72; /* descriptor, current */
- buf[1] = skey;
- buf[2] = asc;
- buf[3] = ascq;
- buf[7] = 0;
- } else {
- buf[0] = 0x70; /* fixed, current */
- buf[2] = skey;
- buf[7] = 0xa; /* Assumes length is 18 bytes */
- buf[12] = asc;
- buf[13] = ascq;
- }
-}
-
static void
mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp, int sk, int asc, int ascq,
int vb)
{
- bool dsense = psp->scsi_dsense;
+ bool dsense = psp->dev_statp->scsi_dsense;
int slen = psp->sense_len;
int n;
uint8_t * sbp = (uint8_t *)psp->sensep;
@@ -1415,10 +1395,13 @@ mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp, int sk, int asc, int ascq,
__func__, slen);
return;
}
- n = dsense ? 8 : ((slen < 18) ? slen : 18);
+ if (dsense)
+ n = (slen > 32) ? 32 : slen;
+ else
+ n = (slen < 18) ? slen : 18;
psp->sense_resid = (slen > n) ? (slen - n) : 0;
memset(sbp, 0, slen);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
if (vb > 3)
pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk,
asc, ascq);
@@ -1428,7 +1411,7 @@ static void
mk_sense_from_nvme_status(struct sg_pt_win32_scsi * psp, int vb)
{
bool ok;
- bool dsense = psp->scsi_dsense;
+ bool dsense = psp->dev_statp->scsi_dsense;
int n;
int slen = psp->sense_len;
uint8_t sstatus, sk, asc, ascq;
@@ -1449,10 +1432,16 @@ mk_sense_from_nvme_status(struct sg_pt_win32_scsi * psp, int vb)
slen);
return;
}
- n = (dsense ? 8 : ((slen < 18) ? slen : 18));
+ if (dsense)
+ n = (slen > 32) ? 32 : slen;
+ else
+ n = (slen < 18) ? slen : 18;
psp->sense_resid = (slen > n) ? slen - n : 0;
memset(sbp, 0, slen);
- build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
+ if (dsense && (psp->nvme_status > 0))
+ sg_nvme_desc2sense(sbp, false /* dnr */, false /* more */,
+ psp->nvme_status);
if (vb > 3)
pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n",
__func__, sstatus, sk, asc, ascq);
@@ -1463,7 +1452,7 @@ static void
mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp, bool in_cdb, int in_byte,
int in_bit, int vb)
{
- bool dsense = psp->scsi_dsense;
+ bool dsense = psp->dev_statp->scsi_dsense;
int sl, asc, n;
int slen = psp->sense_len;
uint8_t * sbp = (uint8_t *)psp->sensep;
@@ -1477,10 +1466,13 @@ mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp, bool in_cdb, int in_byte,
__func__, slen);
return;
}
- n = dsense ? 8 : ((slen < 18) ? slen : 18);
+ if (dsense)
+ n = (slen > 32) ? 32 : slen;
+ else
+ n = (slen < 18) ? slen : 18;
psp->sense_resid = (slen > n) ? (slen - n) : 0;
memset(sbp, 0, slen);
- build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
+ sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
memset(sks, 0, sizeof(sks));
sks[0] = 0x80;
if (in_cdb)
@@ -2259,7 +2251,7 @@ sntl_inq(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
inq_dout[1] = pg_cd;
n = 24;
sg_put_unaligned_be16(n - 4, inq_dout + 2);
- memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */
+ memcpy(inq_dout + 4, psp->nvme_id_ctlp + 4, 20); /* SN */
break;
case 0x83:
if ((psp->nvme_nsid > 0) &&
@@ -2523,11 +2515,11 @@ sntl_req_sense(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
pr2ws("%s: pow_state=%u\n", __func__, pow_state);
memset(rs_dout, 0, sizeof(rs_dout));
if (pow_state)
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- LOW_POWER_COND_ON_ASC, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ LOW_POWER_COND_ON_ASC, 0);
else
- build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
- NO_ADDITIONAL_SENSE, 0);
+ sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
+ NO_ADDITIONAL_SENSE, 0);
n = desc ? 8 : 18;
n = (n < alloc_len) ? n : alloc_len;
n = (n < psp->dxfer_len) ? n : psp->dxfer_len;
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 21742304..0905c741 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@ fi
%{_libdir}/*.la
%changelog
-* Wed May 23 2018 - dgilbert at interlog dot com
+* Sat Jun 02 2018 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.43
diff --git a/src/sg_decode_sense.c b/src/sg_decode_sense.c
index ef3dcfad..0e3e77c5 100644
--- a/src/sg_decode_sense.c
+++ b/src/sg_decode_sense.c
@@ -28,13 +28,16 @@
#include "sg_unaligned.h"
-static const char * version_str = "1.16 20180522";
+static const char * version_str = "1.17 20180602";
#define MAX_SENSE_LEN 1024 /* max descriptor format actually: 256+8 */
static struct option long_options[] = {
{"binary", required_argument, 0, 'b'},
{"cdb", no_argument, 0, 'c'},
+ {"err", required_argument, 0, 'e'},
+ {"exit-status", required_argument, 0, 'e'},
+ {"exit_status", required_argument, 0, 'e'},
{"file", required_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
@@ -54,11 +57,13 @@ struct opts_t {
bool no_space;
bool do_status;
bool do_version;
+ bool err_given;
bool file_given;
const char * fname;
+ int es_val;
int sense_len;
int sstatus;
- int do_verbose;
+ int verbose;
const char * wfname;
const char * no_space_str;
uint8_t sense[MAX_SENSE_LEN + 4];
@@ -70,11 +75,11 @@ static char concat_buff[1024];
static void
usage()
{
- pr2serr("Usage: sg_decode_sense [--binary=FN] [--cdb] [--file=FN] "
- "[--help] [--hex]\n"
- " [--nospace] [--status=SS] [--verbose] "
- "[--version]\n"
- " [--write=WFN] H1 H2 H3 ...\n"
+ pr2serr("Usage: sg_decode_sense [--binary=FN] [--cdb] [--err=ES] "
+ "[--file=FN]\n"
+ " [--help] [--hex] [--nospace] [--status=SS] "
+ "[--verbose]\n"
+ " [--version] [--write=WFN] H1 H2 H3 ...\n"
" where:\n"
" --binary=FN|-b FN FN is a file name to read sense "
"data in\n"
@@ -82,6 +87,8 @@ usage()
"from stdin\n"
" --cdb|-c decode given hex as cdb rather than "
"sense data\n"
+ " --err=ES|-e ES ES is Exit Status from utility in this "
+ "package\n"
" --file=FN|-f FN FN is a file name from which to read "
"sense data\n"
" in ASCII hexadecimal. Interpret '-' "
@@ -112,14 +119,14 @@ usage()
static int
parse_cmd_line(struct opts_t *op, int argc, char *argv[])
{
- int c;
+ int c, n;
unsigned int ui;
long val;
char * avp;
char *endptr;
while (1) {
- c = getopt_long(argc, argv, "b:cf:hHns:vVw:", long_options, NULL);
+ c = getopt_long(argc, argv, "b:ce:f:hHns:vVw:", long_options, NULL);
if (c == -1)
break;
@@ -136,6 +143,15 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
case 'c':
op->do_cdb = true;
break;
+ case 'e':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 255)) {
+ pr2serr("--err= expected number from 0 to 255 inclusive\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ op->err_given = true;
+ op->es_val = n;
+ break;
case 'f':
if (op->fname) {
pr2serr("expect only one '--binary=FN' or '--file=FN' "
@@ -168,7 +184,7 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
op->sstatus = ui;
break;
case 'v':
- ++op->do_verbose;
+ ++op->verbose;
break;
case 'V':
op->do_version = true;
@@ -180,6 +196,8 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
return SG_LIB_SYNTAX_ERROR;
}
}
+ if (op->err_given)
+ goto the_end;
while (optind < argc) {
avp = argv[optind++];
@@ -218,6 +236,7 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
}
op->sense[op->sense_len++] = (uint8_t)val;
}
+the_end:
return 0;
}
@@ -407,6 +426,7 @@ write2wfn(FILE * fp, struct opts_t * op)
int
main(int argc, char *argv[])
{
+ bool ok;
int k, err;
int ret = 0;
unsigned int ui;
@@ -432,6 +452,19 @@ main(int argc, char *argv[])
return 0;
}
+ if (op->err_given) {
+ char d[128];
+ const int dlen = sizeof(d);
+
+ ok = sg_exit2str(op->es_val, op->verbose > 1, dlen, d);
+ if (! ok)
+ snprintf(d, dlen, "Unable to decode exit status %d", op->es_val);
+ if (1 & op->verbose) /* odd values of verbose print to stderr */
+ pr2serr("%s\n", d);
+ else /* even values of verbose (including not given) to stdout */
+ printf("%s\n", d);
+ goto fini;
+ }
if (op->do_status) {
sg_get_scsi_status_str(op->sstatus, sizeof(b) - 1, b);
@@ -439,7 +472,7 @@ main(int argc, char *argv[])
}
if ((0 == op->sense_len) && op->no_space_str) {
- if (op->do_verbose > 2)
+ if (op->verbose > 2)
pr2serr("no_space str: %s\n", op->no_space_str);
cp = op->no_space_str;
for (k = 0; isxdigit(cp[k]) && isxdigit(cp[k + 1]); k += 2) {
@@ -518,9 +551,9 @@ main(int argc, char *argv[])
sg_get_opcode_sa_name(opcode, sa, 0, sizeof(b), b);
} else
sg_get_sense_str(NULL, op->sense, op->sense_len,
- op->do_verbose, sizeof(b) - 1, b);
+ op->verbose, sizeof(b) - 1, b);
printf("%s\n", b);
}
-
+fini:
return ret;
}
diff --git a/src/sgm_dd.c b/src/sgm_dd.c
index e95ab4da..dc47ca77 100644
--- a/src/sgm_dd.c
+++ b/src/sgm_dd.c
@@ -66,7 +66,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.54 20180532";
+static const char * version_str = "1.55 20180601";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -113,6 +113,7 @@ static int in_partial = 0;
static int64_t out_full = 0;
static int out_partial = 0;
static int verbose = 0;
+static int dry_run = 0;
static bool do_time = false;
static bool start_tm_valid = false;
@@ -266,7 +267,8 @@ usage()
" [--help] [--version]\n\n");
pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] "
"[fua=0|1|2|3]\n"
- " [sync=0|1] [time=0|1] [verbose=VERB]\n\n"
+ " [sync=0|1] [time=0|1] [verbose=VERB] "
+ "[--dry-run] [--verbose]\n\n"
" where:\n"
" bpt is blocks_per_transfer (default is 128)\n"
" bs must be device block size (default 512)\n"
@@ -295,8 +297,10 @@ usage()
"throughput\n"
" verbose 0->quiet(def), 1->some noise, 2->more noise, "
"etc\n"
- " --help print usage message then exit\n"
- " --version print version information then exit\n\n"
+ " --dry-run|-d prepare but bypass copy/read\n"
+ " --help|-h print usage message then exit\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version information then exit\n\n"
"Copy from IFILE to OFILE, similar to dd command\n"
"specialized for SCSI devices for which mmap-ed IO attempted\n");
}
@@ -677,12 +681,25 @@ process_flags(const char * arg, struct flags_t * fp)
return 0;
}
+/* Returns the number of times 'ch' is found in string 's' given the
+ * string's length. */
+static int
+num_chs_in_str(const char * s, int slen, int ch)
+{
+ int res = 0;
+
+ while (--slen >= 0) {
+ if (ch == s[slen])
+ ++res;
+ }
+ return res;
+}
+
#define STR_SZ 1024
#define INOUTF_SZ 512
#define EBUFF_SZ 768
-
int
main(int argc, char * argv[])
{
@@ -690,7 +707,7 @@ main(int argc, char * argv[])
bool cdbsz_given = false;
bool do_coe = false; /* dummy, just accept + ignore */
bool do_sync = false;
- int res, k, t, infd, outfd, blocks, n, flags, blocks_per, err;
+ int res, k, t, infd, outfd, blocks, n, flags, blocks_per, err, keylen;
int bpt = DEF_BLOCKS_PER_TRANSFER;
int ibs = 0;
int in_res_sz = 0;
@@ -741,6 +758,7 @@ main(int argc, char * argv[])
buf++;
if (*buf)
*buf++ = '\0';
+ keylen = strlen(key);
if (0 == strcmp(key,"bpt")) {
bpt = sg_get_num(buf);
if (-1 == bpt) {
@@ -829,16 +847,42 @@ main(int argc, char * argv[])
do_time = sg_get_num(buf);
else if (0 == strncmp(key, "verb", 4))
verbose = sg_get_num(buf);
- else if ((0 == strncmp(key, "--help", 7)) ||
- (0 == strcmp(key, "-h")) || (0 == strcmp(key, "-?"))) {
+ else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
+ res = 0;
+ n = num_chs_in_str(key + 1, keylen - 1, 'd');
+ dry_run += n;
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'h');
+ if (n > 0) {
+ usage();
+ return 0;
+ }
+ n = num_chs_in_str(key + 1, keylen - 1, 'v');
+ verbose += n;
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'V');
+ if (n > 0) {
+ pr2serr(ME ": %s\n", version_str);
+ return 0;
+ }
+ if (res < (keylen - 1)) {
+ pr2serr("Unrecognised short option in '%s', try '--help'\n",
+ key);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if ((0 == strncmp(key, "--dry-run", 9)) ||
+ (0 == strncmp(key, "--dry_run", 9)))
+ ++dry_run;
+ else if ((0 == strncmp(key, "--help", 6)) ||
+ (0 == strcmp(key, "-?"))) {
usage();
return 0;
- } else if ((0 == strncmp(key, "--vers", 6)) ||
- (0 == strcmp(key, "-V"))) {
+ } else if (0 == strncmp(key, "--verb", 6))
+ ++verbose;
+ else if (0 == strncmp(key, "--vers", 6)) {
pr2serr(ME ": %s\n", version_str);
return 0;
- }
- else {
+ } else {
pr2serr("Unrecognized option '%s'\n", key);
pr2serr("For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
@@ -1218,6 +1262,9 @@ main(int argc, char * argv[])
pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count,
blocks_per);
#endif
+ if (dry_run > 0)
+ goto fini;
+
if (do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
@@ -1352,13 +1399,14 @@ main(int argc, char * argv[])
}
}
+fini:
if (wrkBuff)
free(wrkBuff);
if (STDIN_FILENO != infd)
close(infd);
if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type))
close(outfd);
- if (0 != dd_count) {
+ if ((0 != dd_count) && (0 == dry_run)) {
pr2serr("Some error occurred,");
if (0 == ret)
ret = SG_LIB_CAT_OTHER;
diff --git a/src/sgp_dd.c b/src/sgp_dd.c
index 68eeeda0..55df3df7 100644
--- a/src/sgp_dd.c
+++ b/src/sgp_dd.c
@@ -60,7 +60,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "5.64 20180523";
+static const char * version_str = "5.65 20180601";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -140,6 +140,7 @@ typedef struct request_collection
int sum_of_resids; /* | */
pthread_mutex_t aux_mutex; /* -/ (also serializes some printf()s */
int debug;
+ int dry_run;
} Rq_coll;
typedef struct request_element
@@ -346,6 +347,7 @@ usage()
"[deb=VERB] [dio=0|1]\n"
" [fua=0|1|2|3] [sync=0|1] [thr=THR] "
"[time=0|1] [verbose=VERB]\n"
+ " [--dry-run] [--verbose]\n"
" where:\n"
" bpt is blocks_per_transfer (default is 128)\n"
" bs must be device block size (default 512)\n"
@@ -378,8 +380,10 @@ usage()
" time 0->no timing(def), 1->time plus calculate "
"throughput\n"
" verbose same as 'deb=VERB': increase verbosity\n"
- " --help output this usage message then exit\n"
- " --version output version string then exit\n"
+ " --dry-run|-d prepare but bypass copy/read\n"
+ " --help|-h output this usage message then exit\n"
+ " --verbose|-v increase verbosity of utility\n"
+ " --version|-V output version string then exit\n"
"Copy from IFILE to OFILE, similar to dd command\n"
"specialized for SCSI devices, uses multiple POSIX threads\n");
}
@@ -1129,11 +1133,24 @@ process_flags(const char * arg, struct flags_t * fp)
return 0;
}
+/* Returns the number of times 'ch' is found in string 's' given the
+ * string's length. */
+static int
+num_chs_in_str(const char * s, int slen, int ch)
+{
+ int res = 0;
+
+ while (--slen >= 0) {
+ if (ch == s[slen])
+ ++res;
+ }
+ return res;
+}
+
#define STR_SZ 1024
#define INOUTF_SZ 512
-
int
main(int argc, char * argv[])
{
@@ -1148,7 +1165,7 @@ main(int argc, char * argv[])
char * buf;
char inf[INOUTF_SZ];
char outf[INOUTF_SZ];
- int res, k, err;
+ int res, k, err, keylen;
int64_t in_num_sect = 0;
int64_t out_num_sect = 0;
pthread_t threads[MAX_NUM_THREADS];
@@ -1184,6 +1201,7 @@ main(int argc, char * argv[])
buf++;
if (*buf)
*buf++ = '\0';
+ keylen = strlen(key);
if (0 == strcmp(key,"bpt")) {
rcoll.bpt = sg_get_num(buf);
if (-1 == rcoll.bpt) {
@@ -1276,17 +1294,42 @@ main(int argc, char * argv[])
num_threads = sg_get_num(buf);
else if (0 == strcmp(key,"time"))
do_time = !! sg_get_num(buf);
- else if ((0 == strncmp(key, "--help", 7)) ||
- (0 == strncmp(key, "-h", 2)) ||
- (0 == strcmp(key, "-?"))) {
+ else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
+ res = 0;
+ n = num_chs_in_str(key + 1, keylen - 1, 'd');
+ rcoll.dry_run += n;
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'h');
+ if (n > 0) {
+ usage();
+ return 0;
+ }
+ n = num_chs_in_str(key + 1, keylen - 1, 'v');
+ rcoll.debug += n; /* -v ---> --verbose */
+ res += n;
+ n = num_chs_in_str(key + 1, keylen - 1, 'V');
+ if (n > 0) {
+ pr2serr("%s%s\n", my_name, version_str);
+ return 0;
+ }
+ if (res < (keylen - 1)) {
+ pr2serr("Unrecognised short option in '%s', try '--help'\n",
+ key);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if ((0 == strncmp(key, "--dry-run", 9)) ||
+ (0 == strncmp(key, "--dry_run", 9)))
+ ++rcoll.dry_run;
+ else if ((0 == strncmp(key, "--help", 6)) ||
+ (0 == strcmp(key, "-?"))) {
usage();
return 0;
- } else if ((0 == strncmp(key, "--vers", 6)) ||
- (0 == strcmp(key, "-V"))) {
+ } else if (0 == strncmp(key, "--verb", 6))
+ ++rcoll.debug; /* --verbose */
+ else if (0 == strncmp(key, "--vers", 6)) {
pr2serr("%s%s\n", my_name, version_str);
return 0;
- }
- else {
+ } else {
pr2serr("Unrecognized option '%s'\n", key);
pr2serr("For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
@@ -1584,6 +1627,10 @@ main(int argc, char * argv[])
status = pthread_cond_init(&rcoll.out_sync_cv, NULL);
if (0 != status) err_exit(status, "init out_sync_cv");
+ if (rcoll.dry_run > 0) {
+ pr2serr("Due to --dry-run option, bypass copy/read\n");
+ goto fini;
+ }
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGINT);
status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
@@ -1666,12 +1713,13 @@ main(int argc, char * argv[])
shutting_down = true;
status = pthread_kill(sig_listen_thread_id, SIGINT);
if (0 != status) err_exit(status, "pthread_kill");
+fini:
if (STDIN_FILENO != rcoll.infd)
close(rcoll.infd);
if ((STDOUT_FILENO != rcoll.outfd) && (FT_DEV_NULL != rcoll.out_type))
close(rcoll.outfd);
res = exit_status;
- if (0 != rcoll.out_count) {
+ if ((0 != rcoll.out_count) && (0 == rcoll.dry_run)) {
pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n",
rcoll.out_count);
if (0 == res)