aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2019-03-02 01:03:55 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2019-03-02 01:03:55 +0000
commit8bdc5521368ade1b8ecaecf194f03ad74f845fed (patch)
tree790ea0d014de7d3a5922794b336c848ac5d5533a
parent9ddcd0ac08f1c6a46d681bc349f3f523e8da4fcf (diff)
downloadsg3_utils-8bdc5521368ade1b8ecaecf194f03ad74f845fed.tar.gz
sg_lib: extend small SNTL to support read capacity
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@812 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog3
-rw-r--r--doc/sg3_utils.813
-rw-r--r--doc/sg_dd.86
-rw-r--r--doc/sg_xcopy.84
-rw-r--r--doc/sgm_dd.86
-rw-r--r--doc/sgp_dd.86
-rw-r--r--lib/sg_pt_linux_nvme.c119
-rw-r--r--testing/Makefile1
-rw-r--r--testing/sgh_dd.c25
-rw-r--r--testing/uapi_sg.h2
10 files changed, 151 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index fbd77fd1..f7dd0dba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.45 [20190210] [svn: r811]
+Changelog for sg3_utils-1.45 [20190301] [svn: r812]
- sg_ses: bug: --page= being overridden when --control
and --data= also given; fix
- sg_opcodes: expand MLU (spc5r20)
@@ -30,6 +30,7 @@ Changelog for sg3_utils-1.45 [20190210] [svn: r811]
SIGPOLL (SIGIO) and realtime (RT) signals
- sg_pt: add sg_get_opcode_translation() to replace
global pointer to array: sg_opcode_info_arr[]
+ - extend small SNTL to support read capacity
- utils/hxascdmp: add -o=<offset> option
- sg_io_linux (sg_lib): add sg_linux_sense_print()
- sg_pt_linux: uses sg v4 interface if sg driver
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index e3e4b70b..836e1769 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "January 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG3_UTILS "8" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
@@ -260,6 +260,12 @@ package assume they are talking to a SCSI device and decode any response
accordingly. One easy way for users to see the underlying device is a
NVMe device is the standard INQUIRY response Vendor Identification field
of "NVMe " (an 8 character long string with 4 spaces to the right).
+.PP
+The following SCSI commands are currently supported by the SNTL library:
+INQUIRY, MODE SELECT(10), MODE SENSE(10), READ CAPACITY(10 and 16),
+RECEIVE DIAGNOSTIC RESULTS, REQUEST SENSE, REPORT LUNS, REPORT SUPPORTED
+OPERATION CODES, REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS, SEND
+DIAGNOSTICS, and TEST UNIT READY.
.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
@@ -407,6 +413,11 @@ like "shouldn't/can't get here". Perhaps the author should be informed.
.B 33
the command sent to \fIDEVICE\fR has timed out.
.TP
+.B 34
+this is a Windows only exit status and indicates that the Windows error
+number (32 bits) cannot meaningfully be mapped to an equivalent Unix error
+number returned as the exit status (7 bits).
+.TP
.B 36
no error has occurred plus the utility wants to convey a boolean value
of false. The corresponding true value is conveyed by a 0 exit status.
diff --git a/doc/sg_dd.8 b/doc/sg_dd.8
index 881d11ed..872c43cf 100644
--- a/doc/sg_dd.8
+++ b/doc/sg_dd.8
@@ -1,4 +1,4 @@
-.TH SG_DD "8" "August 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SG_DD "8" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -101,7 +101,7 @@ copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
report from SCSI READ CAPACITY commands or that block devices (or their
partitions) report. Normal files are not probed for their size. If
-\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e.
+\fIskip=SKIP\fR or \fIseek=SEEK\fR are given and the count is derived (i.e.
not explicitly given) then the derived count is scaled back so that the
copy will not overrun the device. If the file name is a block device
partition and \fICOUNT\fR is not given then the size of the partition
@@ -491,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\-2018 Douglas Gilbert
+Copyright \(co 2000\-2019 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_xcopy.8 b/doc/sg_xcopy.8
index ccd470ec..197fc37b 100644
--- a/doc/sg_xcopy.8
+++ b/doc/sg_xcopy.8
@@ -1,4 +1,4 @@
-.TH SG_XCOPY "8" "January 2019" "sg3_utils\-1.45" SG3_UTILS
+.TH SG_XCOPY "8" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sg_xcopy \- copy data to and from files and devices using SCSI EXTENDED
COPY (XCOPY)
@@ -88,7 +88,7 @@ minimum (\fIIFILE\fR if \fIdc=0\fR or \fIOFILE\fR if \fIdc=1\fR)
number of blocks that SCSI devices report from SCSI READ CAPACITY
commands or that block devices (or their partitions) report. Normal
files are not probed for their size. If \fIskip=SKIP\fR or
-\fIskip=SEEK\fR are given and the count is derived (i.e. not
+\fIseek=SEEK\fR are given and the count is derived (i.e. not
explicitly given) then the derived count is scaled back so that the
copy will not overrun the device. If the file name is a block device
partition and \fICOUNT\fR is not given then the size of the partition
diff --git a/doc/sgm_dd.8 b/doc/sgm_dd.8
index 346bedb9..58782d72 100644
--- a/doc/sgm_dd.8
+++ b/doc/sgm_dd.8
@@ -1,4 +1,4 @@
-.TH SGM_DD "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SGM_DD "8" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sgm_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -66,7 +66,7 @@ copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
report from SCSI READ CAPACITY commands or that block devices (or their
partitions) report. Normal files are not probed for their size. If
-\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e.
+\fIskip=SKIP\fR or \fIseek=SEEK\fR are given and the count is derived (i.e.
not explicitly given) then the derived count is scaled back so that the
copy will not overrun the device. If the file name is a block device
partition and \fICOUNT\fR is not given then the size of the partition rather
@@ -269,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\-2018 Douglas Gilbert
+Copyright \(co 2000\-2019 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 0c997121..bd18d2a5 100644
--- a/doc/sgp_dd.8
+++ b/doc/sgp_dd.8
@@ -1,4 +1,4 @@
-.TH SGP_DD "8" "June 2018" "sg3_utils\-1.43" SG3_UTILS
+.TH SGP_DD "8" "February 2019" "sg3_utils\-1.45" SG3_UTILS
.SH NAME
sgp_dd \- copy data to and from files and devices, especially SCSI
devices
@@ -61,7 +61,7 @@ copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
report from SCSI READ CAPACITY commands or that block devices (or their
partitions) report. Normal files are not probed for their size. If
-\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is deduced (i.e.
+\fIskip=SKIP\fR or \fIseek=SEEK\fR are given and the count is deduced (i.e.
not explicitly given) then that count is scaled back so that the copy will
not overrun the device. If the file name is a block device partition and
\fICOUNT\fR is not given then the size of the partition rather than the
@@ -314,7 +314,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\-2019 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/lib/sg_pt_linux_nvme.c b/lib/sg_pt_linux_nvme.c
index 2309a794..4f8f8661 100644
--- a/lib/sg_pt_linux_nvme.c
+++ b/lib/sg_pt_linux_nvme.c
@@ -41,7 +41,7 @@
* MA 02110-1301, USA.
*/
-/* sg_pt_linux_nvme version 1.07 20190210 */
+/* sg_pt_linux_nvme version 1.08 20190218 */
/* This file contains a small "SPC-only" SNTL to support the SES pass-through
* of SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS through NVME-MI
@@ -91,6 +91,10 @@
#define SCSI_REP_SUP_TMFS_OPC 0xd
#define SCSI_MODE_SENSE10_OPC 0x5a
#define SCSI_MODE_SELECT10_OPC 0x55
+#define SCSI_READ_CAPACITY10_OPC 0x25
+#define SCSI_SERVICE_ACT_IN_OPC 0x9e
+#define SCSI_READ_CAPACITY16_SA 0x10
+#define SCSI_SA_MSK 0x1f
/* Additional Sense Code (ASC) */
#define NO_ADDITIONAL_SENSE 0x0
@@ -412,6 +416,20 @@ sntl_check_enclosure_override(struct sg_pt_linux_scsi * ptp, int vb)
}
}
+static int
+sntl_do_identify(struct sg_pt_linux_scsi * ptp, int cns, int nsid,
+ int time_secs, int u_len, uint8_t * up, int vb)
+{
+ struct sg_nvme_passthru_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = 0x6; /* Identify */
+ cmd.nsid = nsid;
+ cmd.cdw10 = cns;
+ cmd.addr = (uint64_t)(sg_uintptr_t)up;
+ cmd.data_len = u_len;
+ return do_nvme_admin_cmd(ptp, &cmd, up, true, time_secs, vb);
+}
/* Currently only caches associated identify controller response (4096 bytes).
* Returns 0 on success; otherwise a positive value is returned */
@@ -421,7 +439,6 @@ sntl_cache_identity(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
int ret;
uint32_t pg_sz = sg_get_page_size();
uint8_t * up;
- struct sg_nvme_passthru_cmd cmd;
up = sg_memalign(pg_sz, pg_sz, &ptp->free_nvme_id_ctlp, false);
ptp->nvme_id_ctlp = up;
@@ -429,12 +446,8 @@ sntl_cache_identity(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
return sg_convert_errno(ENOMEM);
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x6; /* Identify */
- cmd.cdw10 = 0x1; /* CNS=0x1 Identify controller */
- cmd.addr = (uint64_t)(sg_uintptr_t)ptp->nvme_id_ctlp;
- cmd.data_len = pg_sz;
- ret = do_nvme_admin_cmd(ptp, &cmd, up, true, time_secs, vb);
+ ret = sntl_do_identify(ptp, 0x1 /* CNS */, 0 /* nsid */, time_secs,
+ pg_sz, up, vb);
if (0 == ret)
sntl_check_enclosure_override(ptp, vb);
return (ret < 0) ? sg_convert_errno(-ret) : ret;
@@ -503,16 +516,9 @@ sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns,
false);
if (nvme_id_ns) {
- struct sg_nvme_passthru_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x6; /* Identify */
- cmd.nsid = ptp->nvme_nsid;
- cmd.cdw10 = 0x0; /* CNS=0x0 Identify namespace */
- cmd.addr = (uint64_t)(sg_uintptr_t)nvme_id_ns;
- cmd.data_len = pg_sz;
- res = do_nvme_admin_cmd(ptp, &cmd, nvme_id_ns, true,
- time_secs, vb > 3);
+ /* CNS=0x0 Identify namespace */
+ res = sntl_do_identify(ptp, 0x0, ptp->nvme_nsid,
+ time_secs, pg_sz, nvme_id_ns, vb);
if (res) {
free(free_nvme_id_ns);
free_nvme_id_ns = NULL;
@@ -1158,6 +1164,74 @@ sntl_rep_tmfs(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
return 0;
}
+static int
+sntl_readcap(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
+ int time_secs, int vb)
+{
+ bool is_rcap10 = (SCSI_READ_CAPACITY10_OPC == cdbp[0]);
+ int res, n, len, alloc_len, dps;
+ uint8_t flbas, index, lbads;
+ uint32_t lbafx; /* "x" is 0 to 15 in NVMe spec */
+ uint32_t pg_sz = sg_get_page_size();
+ uint64_t nsze;
+ uint8_t * bp;
+ uint8_t * up;
+ uint8_t * free_up = NULL;
+ uint8_t resp[32];
+
+ if (vb > 3)
+ pr2ws("%s: RCAP%d, time_secs=%d\n", __func__,
+ (is_rcap10 ? 10 : 16), time_secs);
+ up = sg_memalign(pg_sz, pg_sz, &free_up, false);
+ if (NULL == up) {
+ pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
+ return sg_convert_errno(ENOMEM);
+ }
+ res = sntl_do_identify(ptp, 0x0 /* CNS */, ptp->nvme_nsid, time_secs,
+ pg_sz, up, vb);
+ if (res < 0) {
+ res = sg_convert_errno(-res);
+ goto fini;
+ }
+ memset(resp, 0, sizeof(*resp));
+ nsze = sg_get_unaligned_le64(up + 0);
+ flbas = up[26];
+ index = 128 + (4 * (flbas & 0xf));
+ lbafx = sg_get_unaligned_le32(up + index);
+ lbads = (lbafx >> 16) & 0xff; /* bits 16 to 23 inclusive, pow2 */
+ if (is_rcap10) {
+ alloc_len = 8; /* implicit, not in cdb */
+ if (nsze > 0xfffffffe)
+ sg_put_unaligned_be32(0xffffffff, resp + 0);
+ else
+ sg_put_unaligned_be32((uint32_t)nsze, resp + 0);
+ sg_put_unaligned_be32(1 << lbads, resp + 4); /* LB size */
+ } else {
+ alloc_len = sg_get_unaligned_be32(cdbp + 10);
+ dps = up[29];
+ if (0x7 & dps) {
+ resp[12] = 0x1;
+ n = (0x7 & dps) - 1;
+ if (n > 0)
+ resp[12] |= (n + n);
+ }
+ sg_put_unaligned_be64(nsze, resp + 0);
+ sg_put_unaligned_be32(1 << lbads, resp + 8); /* LB size */
+ }
+ len = ptp->io_hdr.din_xfer_len;
+ bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
+ n = 16;
+ n = (n < alloc_len) ? n : alloc_len;
+ n = (n < len) ? n : len;
+ ptp->io_hdr.din_resid = len - n;
+ if (n > 0)
+ memcpy(bp, resp, n);
+fini:
+ if (free_up)
+ free(free_up);
+ return res;
+}
+
/* Executes NVMe Admin command (or at least forwards it to lower layers).
* Returns 0 for success, negative numbers are negated 'errno' values from
* OS system calls. Positive return values are errors from this package.
@@ -1219,14 +1293,21 @@ sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb)
case SCSI_MODE_SENSE10_OPC:
case SCSI_MODE_SELECT10_OPC:
return sntl_mode_ss(ptp, cdbp, time_secs, vb);
+ case SCSI_READ_CAPACITY10_OPC:
+ return sntl_readcap(ptp, cdbp, time_secs, vb);
+ case SCSI_SERVICE_ACT_IN_OPC:
+ if (SCSI_READ_CAPACITY16_SA == (cdbp[1] & SCSI_SA_MSK))
+ return sntl_readcap(ptp, cdbp, time_secs, vb);
+ goto fini;
case SCSI_MAINT_IN_OPC:
- sa = 0x1f & cdbp[1]; /* service action */
+ sa = SCSI_SA_MSK & cdbp[1]; /* service action */
if (SCSI_REP_SUP_OPCS_OPC == sa)
return sntl_rep_opcodes(ptp, cdbp, time_secs, vb);
else if (SCSI_REP_SUP_TMFS_OPC == sa)
return sntl_rep_tmfs(ptp, cdbp, time_secs, vb);
/* fall through */
default:
+fini:
if (vb > 2) {
char b[64];
diff --git a/testing/Makefile b/testing/Makefile
index 7ff39a44..518eb5cb 100644
--- a/testing/Makefile
+++ b/testing/Makefile
@@ -90,6 +90,7 @@ sgs_dd: sgs_dd.o $(LIBFILESOLD)
sg_tst_bidi: sg_tst_bidi.o $(LIBFILESNEW)
$(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $^; \
diff --git a/testing/sgh_dd.c b/testing/sgh_dd.c
index adcf7818..5ff9e710 100644
--- a/testing/sgh_dd.c
+++ b/testing/sgh_dd.c
@@ -98,7 +98,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.19 20190210";
+static const char * version_str = "1.20 20190212";
#ifdef __GNUC__
#ifndef __clang__
@@ -106,6 +106,9 @@ static const char * version_str = "1.19 20190210";
#endif
#endif
+/* <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> xxxxxxxxxx beware next line */
+#define SGH_DD_READ_COMPLET_AFTER 1
+
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
#define DEF_BLOCKS_PER_2048TRANSFER 32
@@ -559,6 +562,10 @@ usage(int pg_num)
"It expects one or both IFILE\nand OFILE to be sg devices. It "
"is Linux specific and uses the v4 sg driver\n'share' capability "
"if available. Use '-hh' or '-hhh' for more information.\n"
+#ifdef SGH_DD_READ_COMPLET_AFTER
+ "\nIn this version oflag=swait does read completion _after_ "
+ "write completion\n"
+#endif
);
return;
page2:
@@ -1777,6 +1784,12 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
status = pthread_mutex_unlock(&clp->in_mutex);
if (0 != status) err_exit(status, "unlock in_mutex");
+#ifdef SGH_DD_READ_COMPLET_AFTER
+#warning "SGH_DD_READ_COMPLET_AFTER is set (testing)"
+ goto write_complet;
+read_complet:
+#endif
+
/* finish READ */
rep->rq_id = pid_read;
rep->wr = false;
@@ -1832,6 +1845,12 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
break;
}
+
+#ifdef SGH_DD_READ_COMPLET_AFTER
+ return;
+
+write_complet:
+#endif
/* finish WRITE, no lock held */
rep->rq_id = pid_write;
rep->wr = true;
@@ -1871,6 +1890,10 @@ sg_in_out_interleave(Gbl_coll *clp, Rq_elem * rep)
clp->out_rem_count -= rep->num_blks;
status = pthread_mutex_unlock(&clp->in_mutex);
if (0 != status) err_exit(status, "unlock out_mutex");
+
+#ifdef SGH_DD_READ_COMPLET_AFTER
+ goto read_complet;
+#endif
return;
default:
pr2serr_lk("error finishing sg out command (%d)\n", res);
diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h
index d6cbf14d..f109690d 100644
--- a/testing/uapi_sg.h
+++ b/testing/uapi_sg.h
@@ -14,7 +14,7 @@
* Later extensions (versions 2, 3 and 4) to driver:
* Copyright (C) 1998 - 2018 Douglas Gilbert
*
- * Version 4.0.06 (20190201)
+ * Version 4.0.06 (20190210)
* This version is for Linux 2.6, 3, 4 and 5 series kernels.
*
* Documentation