diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2019-03-02 01:03:55 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2019-03-02 01:03:55 +0000 |
commit | 8bdc5521368ade1b8ecaecf194f03ad74f845fed (patch) | |
tree | 790ea0d014de7d3a5922794b336c848ac5d5533a | |
parent | 9ddcd0ac08f1c6a46d681bc349f3f523e8da4fcf (diff) | |
download | sg3_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-- | ChangeLog | 3 | ||||
-rw-r--r-- | doc/sg3_utils.8 | 13 | ||||
-rw-r--r-- | doc/sg_dd.8 | 6 | ||||
-rw-r--r-- | doc/sg_xcopy.8 | 4 | ||||
-rw-r--r-- | doc/sgm_dd.8 | 6 | ||||
-rw-r--r-- | doc/sgp_dd.8 | 6 | ||||
-rw-r--r-- | lib/sg_pt_linux_nvme.c | 119 | ||||
-rw-r--r-- | testing/Makefile | 1 | ||||
-rw-r--r-- | testing/sgh_dd.c | 25 | ||||
-rw-r--r-- | testing/uapi_sg.h | 2 |
10 files changed, 151 insertions, 34 deletions
@@ -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 |