• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017-2021 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * The code to use the NVMe Management Interface (MI) SES pass-through
10  * was provided by WDC in November 2017.
11  */
12 
13 /*
14  * Copyright 2017, Western Digital Corporation
15  *
16  * Written by Berck Nash
17  *
18  * Use of this source code is governed by a BSD-style
19  * license that can be found in the BSD_LICENSE file.
20  *
21  * Based on the NVM-Express command line utility, which bore the following
22  * notice:
23  *
24  * Copyright (c) 2014-2015, Intel Corporation.
25  *
26  * Written by Keith Busch <keith.busch@intel.com>
27  *
28  * This program is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU General Public License
30  * as published by the Free Software Foundation; either version 2
31  * of the License, or (at your option) any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41  *                   MA 02110-1301, USA.
42  */
43 
44 /* sg_pt_linux_nvme version 1.18 20210601 */
45 
46 /* This file contains a small "SPC-only" SNTL to support the SES pass-through
47  * of SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS through NVME-MI
48  * SES Send and SES Receive. */
49 
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <stdbool.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <unistd.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #define __STDC_FORMAT_MACROS 1
61 #include <inttypes.h>
62 #include <sys/ioctl.h>
63 #include <sys/stat.h>
64 #include <sys/sysmacros.h>      /* to define 'major' */
65 #ifndef major
66 #include <sys/types.h>
67 #endif
68 
69 
70 #ifdef HAVE_CONFIG_H
71 #include "config.h"
72 #endif
73 
74 #include <linux/major.h>
75 
76 #include "sg_pt.h"
77 #include "sg_lib.h"
78 #include "sg_linux_inc.h"
79 #include "sg_pt_linux.h"
80 #include "sg_unaligned.h"
81 #include "sg_pr2serr.h"
82 
83 #define SCSI_INQUIRY_OPC     0x12
84 #define SCSI_REPORT_LUNS_OPC 0xa0
85 #define SCSI_TEST_UNIT_READY_OPC  0x0
86 #define SCSI_REQUEST_SENSE_OPC  0x3
87 #define SCSI_SEND_DIAGNOSTIC_OPC  0x1d
88 #define SCSI_RECEIVE_DIAGNOSTIC_OPC  0x1c
89 #define SCSI_MAINT_IN_OPC  0xa3
90 #define SCSI_READ10_OPC 0x28
91 #define SCSI_READ16_OPC 0x88
92 #define SCSI_REP_SUP_OPCS_OPC  0xc
93 #define SCSI_REP_SUP_TMFS_OPC  0xd
94 #define SCSI_MODE_SENSE10_OPC  0x5a
95 #define SCSI_MODE_SELECT10_OPC  0x55
96 #define SCSI_READ_CAPACITY10_OPC  0x25
97 #define SCSI_START_STOP_OPC 0x1b
98 #define SCSI_SYNC_CACHE10_OPC  0x35
99 #define SCSI_SYNC_CACHE16_OPC  0x91
100 #define SCSI_VERIFY10_OPC 0x2f
101 #define SCSI_VERIFY16_OPC 0x8f
102 #define SCSI_WRITE10_OPC 0x2a
103 #define SCSI_WRITE16_OPC 0x8a
104 #define SCSI_WRITE_SAME10_OPC 0x41
105 #define SCSI_WRITE_SAME16_OPC 0x93
106 #define SCSI_SERVICE_ACT_IN_OPC  0x9e
107 #define SCSI_READ_CAPACITY16_SA  0x10
108 #define SCSI_SA_MSK  0x1f
109 
110 /* Additional Sense Code (ASC) */
111 #define NO_ADDITIONAL_SENSE 0x0
112 #define LOGICAL_UNIT_NOT_READY 0x4
113 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
114 #define UNRECOVERED_READ_ERR 0x11
115 #define PARAMETER_LIST_LENGTH_ERR 0x1a
116 #define INVALID_OPCODE 0x20
117 #define LBA_OUT_OF_RANGE 0x21
118 #define INVALID_FIELD_IN_CDB 0x24
119 #define INVALID_FIELD_IN_PARAM_LIST 0x26
120 #define UA_RESET_ASC 0x29
121 #define UA_CHANGED_ASC 0x2a
122 #define TARGET_CHANGED_ASC 0x3f
123 #define LUNS_CHANGED_ASCQ 0x0e
124 #define INSUFF_RES_ASC 0x55
125 #define INSUFF_RES_ASCQ 0x3
126 #define LOW_POWER_COND_ON_ASC  0x5e     /* ASCQ=0 */
127 #define POWER_ON_RESET_ASCQ 0x0
128 #define BUS_RESET_ASCQ 0x2      /* scsi bus reset occurred */
129 #define MODE_CHANGED_ASCQ 0x1   /* mode parameters changed */
130 #define CAPACITY_CHANGED_ASCQ 0x9
131 #define SAVING_PARAMS_UNSUP 0x39
132 #define TRANSPORT_PROBLEM 0x4b
133 #define THRESHOLD_EXCEEDED 0x5d
134 #define LOW_POWER_COND_ON 0x5e
135 #define MISCOMPARE_VERIFY_ASC 0x1d
136 #define MICROCODE_CHANGED_ASCQ 0x1      /* with TARGET_CHANGED_ASC */
137 #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
138 #define PCIE_ERR_ASC 0x4b
139 #define PCIE_UNSUPP_REQ_ASCQ 0x13
140 
141 /* NVMe Admin commands */
142 #define SG_NVME_AD_GET_FEATURE 0xa
143 #define SG_NVME_AD_SET_FEATURE 0x9
144 #define SG_NVME_AD_IDENTIFY 0x6         /* similar to SCSI INQUIRY */
145 #define SG_NVME_AD_DEV_SELT_TEST 0x14
146 #define SG_NVME_AD_MI_RECEIVE 0x1e      /* MI: Management Interface */
147 #define SG_NVME_AD_MI_SEND 0x1d         /* hmmm, same opcode as SEND DIAG */
148 
149 /* NVMe NVM (Non-Volatile Memory) commands */
150 #define SG_NVME_NVM_FLUSH 0x0           /* SCSI SYNCHRONIZE CACHE */
151 #define SG_NVME_NVM_COMPARE 0x5         /* SCSI VERIFY(BYTCHK=1) */
152 #define SG_NVME_NVM_READ 0x2
153 #define SG_NVME_NVM_VERIFY 0xc          /* SCSI VERIFY(BYTCHK=0) */
154 #define SG_NVME_NVM_WRITE 0x1
155 #define SG_NVME_NVM_WRITE_ZEROES 0x8    /* SCSI WRITE SAME */
156 
157 #define SG_NVME_RW_CONTROL_FUA (1 << 14) /* Force Unit Access bit */
158 
159 
160 #if (HAVE_NVME && (! IGNORE_NVME))
161 
162 /* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5)
163  * to the name of its associated char device (e.g. /dev/nvme0). If this
164  * occurs true is returned and the char device name is placed in 'b' (as
165  * long as b_len is sufficient). Otherwise false is returned. */
166 bool
sg_get_nvme_char_devname(const char * nvme_block_devname,uint32_t b_len,char * b)167 sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len,
168                          char * b)
169 {
170     uint32_t n, tlen;
171     const char * cp;
172     char buff[8];
173 
174     if ((NULL == b) || (b_len < 5))
175         return false;   /* degenerate cases */
176     cp = strstr(nvme_block_devname, "nvme");
177     if (NULL == cp)
178         return false;   /* expected to find "nvme" in given name */
179     if (1 != sscanf(cp, "nvme%u", &n))
180         return false;   /* didn't find valid "nvme<number>" */
181     snprintf(buff, sizeof(buff), "%u", n);
182     tlen = (cp - nvme_block_devname) + 4 + strlen(buff);
183     if ((tlen + 1) > b_len)
184         return false;           /* b isn't long enough to fit output */
185     memcpy(b, nvme_block_devname, tlen);
186     b[tlen] = '\0';
187     return true;
188 }
189 
190 static void
mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp,int sk,int asc,int ascq,int vb)191 mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq,
192                   int vb)
193 {
194     bool dsense = !! ptp->dev_stat.scsi_dsense;
195     int n;
196     uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
197 
198     ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION;
199     n = ptp->io_hdr.max_response_len;
200     if ((n < 8) || ((! dsense) && (n < 14))) {
201         if (vb)
202             pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
203                   __func__, n);
204         return;
205     } else
206         ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
207     memset(sbp, 0, n);
208     sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
209     if (vb > 3)
210         pr2ws("%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk,
211               asc, ascq);
212 }
213 
214 static void
mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp,int vb)215 mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp, int vb)
216 {
217     bool ok;
218     bool dsense = !! ptp->dev_stat.scsi_dsense;
219     int n;
220     uint8_t sstatus, sk, asc, ascq;
221     uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
222 
223     ok = sg_nvme_status2scsi(ptp->nvme_status, &sstatus, &sk, &asc, &ascq);
224     if (! ok) { /* can't find a mapping to a SCSI error, so ... */
225         sstatus = SAM_STAT_CHECK_CONDITION;
226         sk = SPC_SK_ILLEGAL_REQUEST;
227         asc = 0xb;
228         ascq = 0x0;     /* asc: "WARNING" purposely vague */
229     }
230 
231     ptp->io_hdr.device_status = sstatus;
232     n = ptp->io_hdr.max_response_len;
233     if ((n < 8) || ((! dsense) && (n < 14))) {
234         pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n);
235         return;
236     } else
237         ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
238     memset(sbp, 0, n);
239     sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
240     if (dsense && (ptp->nvme_status > 0))
241         sg_nvme_desc2sense(sbp, ptp->nvme_stat_dnr, ptp->nvme_stat_more,
242                            ptp->nvme_status);
243     if (vb > 3)
244         pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n",
245               __func__, sstatus, sk, asc, ascq);
246 }
247 
248 /* Set in_bit to -1 to indicate no bit position of invalid field */
249 static void
mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp,bool in_cdb,int in_byte,int in_bit,int vb)250 mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte,
251                      int in_bit, int vb)
252 {
253     bool dsense = !! ptp->dev_stat.scsi_dsense;
254     int asc, n;
255     uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
256     uint8_t sks[4];
257 
258     ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION;
259     asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
260     n = ptp->io_hdr.max_response_len;
261     if ((n < 8) || ((! dsense) && (n < 14))) {
262         if (vb)
263             pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
264                   __func__, n);
265         return;
266     } else
267         ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18);
268 
269     memset(sbp, 0, n);
270     sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
271     memset(sks, 0, sizeof(sks));
272     sks[0] = 0x80;
273     if (in_cdb)
274         sks[0] |= 0x40;
275     if (in_bit >= 0) {
276         sks[0] |= 0x8;
277         sks[0] |= (0x7 & in_bit);
278     }
279     sg_put_unaligned_be16(in_byte, sks + 1);
280     if (dsense) {
281         int sl = sbp[7] + 8;
282 
283         sbp[7] = sl;
284         sbp[sl] = 0x2;
285         sbp[sl + 1] = 0x6;
286         memcpy(sbp + sl + 4, sks, 3);
287     } else
288         memcpy(sbp + 15, sks, 3);
289     if (vb > 3)
290         pr2ws("%s:  [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
291               __func__, asc, in_cdb ? 'C' : 'D', in_byte,
292               ((in_bit > 0) ? (0x7 & in_bit) : 0));
293 }
294 
295 /* Returns 0 for success. Returns SG_LIB_NVME_STATUS if there is non-zero
296  * NVMe status (from the completion queue) with the value placed in
297  * ptp->nvme_status. If Unix error from ioctl then return negated value
298  * (equivalent -errno from basic Unix system functions like open()).
299  * CDW0 from the completion queue is placed in ptp->nvme_result in the
300  * absence of a Unix error. If time_secs is negative it is treated as
301  * a timeout in milliseconds (of abs(time_secs) ). */
302 static int
sg_nvme_admin_cmd(struct sg_pt_linux_scsi * ptp,struct sg_nvme_passthru_cmd * cmdp,void * dp,bool is_read,int time_secs,int vb)303 sg_nvme_admin_cmd(struct sg_pt_linux_scsi * ptp,
304                   struct sg_nvme_passthru_cmd *cmdp, void * dp, bool is_read,
305                   int time_secs, int vb)
306 {
307     const uint32_t cmd_len = sizeof(struct sg_nvme_passthru_cmd);
308     int res;
309     uint32_t n;
310     uint16_t sct_sc;
311     const uint8_t * up = ((const uint8_t *)cmdp) + SG_NVME_PT_OPCODE;
312     char nam[64];
313 
314     if (vb)
315         sg_get_nvme_opcode_name(*up, true /* ADMIN */, sizeof(nam), nam);
316     else
317         nam[0] = '\0';
318     cmdp->timeout_ms = (time_secs < 0) ? (-time_secs) : (1000 * time_secs);
319     ptp->os_err = 0;
320     if (vb > 2) {
321         pr2ws("NVMe Admin command: %s\n", nam);
322         hex2stderr((const uint8_t *)cmdp, cmd_len, 1);
323         if ((vb > 4) && (! is_read) && dp) {
324             uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN);
325 
326             if (len > 0) {
327                 n = len;
328                 if ((len < 512) || (vb > 5))
329                     pr2ws("\nData-out buffer (%u bytes):\n", n);
330                 else {
331                     pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n);
332                     n = 512;
333                 }
334                 hex2stderr((const uint8_t *)dp, n, 0);
335             }
336         }
337     }
338     res = ioctl(ptp->dev_fd, NVME_IOCTL_ADMIN_CMD, cmdp);
339     if (res < 0) {  /* OS error (errno negated) */
340         ptp->os_err = -res;
341         if (vb > 1) {
342             pr2ws("%s: ioctl for %s [0x%x] failed: %s "
343                   "(errno=%d)\n", __func__, nam, *up, strerror(-res), -res);
344         }
345         return res;
346     }
347 
348     /* Now res contains NVMe completion queue CDW3 31:17 (15 bits) */
349     ptp->nvme_result = cmdp->result;
350     if ((! ptp->nvme_our_sntl) && ptp->io_hdr.response &&
351         (ptp->io_hdr.max_response_len > 3)) {
352         /* build 32 byte "sense" buffer */
353         uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
354         uint16_t st = (uint16_t)res;
355 
356         n = ptp->io_hdr.max_response_len;
357         n = (n < 32) ? n : 32;
358         memset(sbp, 0 , n);
359         ptp->io_hdr.response_len = n;
360         sg_put_unaligned_le32(cmdp->result,
361                               sbp + SG_NVME_PT_CQ_RESULT);
362         if (n > 15) /* LSBit will be 0 (Phase bit) after (st << 1) */
363             sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P);
364     }
365     /* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */
366     sct_sc = 0x7ff & res;       /* 11 bits */
367     ptp->nvme_status = sct_sc;
368     ptp->nvme_stat_dnr = !!(0x4000 & res);
369     ptp->nvme_stat_more = !!(0x2000 & res);
370     if (sct_sc) {  /* when non-zero, treat as command error */
371         if (vb > 1) {
372             char b[80];
373 
374             pr2ws("%s: ioctl for %s [0x%x] failed, status: %s [0x%x]\n",
375                    __func__, nam, *up,
376                   sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b), sct_sc);
377         }
378         return SG_LIB_NVME_STATUS;      /* == SCSI_PT_DO_NVME_STATUS */
379     }
380     if ((vb > 4) && is_read && dp) {
381         uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN);
382 
383         if (len > 0) {
384             n = len;
385             if ((len < 1024) || (vb > 5))
386                 pr2ws("\nData-in buffer (%u bytes):\n", n);
387             else {
388                 pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n);
389                 n = 1024;
390             }
391             hex2stderr((const uint8_t *)dp, n, 0);
392         }
393     }
394     return 0;
395 }
396 
397 /* see NVME MI document, NVMSR is NVM Subsystem Report */
398 static void
sntl_check_enclosure_override(struct sg_pt_linux_scsi * ptp,int vb)399 sntl_check_enclosure_override(struct sg_pt_linux_scsi * ptp, int vb)
400 {
401     uint8_t * up = ptp->nvme_id_ctlp;
402     uint8_t nvmsr;
403 
404     if (NULL == up)
405         return;
406     nvmsr = up[253];
407     if (vb > 5)
408         pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr);
409     ptp->dev_stat.id_ctl253 = nvmsr;
410     switch (ptp->dev_stat.enclosure_override) {
411     case 0x0:       /* no override */
412         if (0x3 == (0x3 & nvmsr)) {
413             ptp->dev_stat.pdt = PDT_DISK;
414             ptp->dev_stat.enc_serv = 1;
415         } else if (0x2 & nvmsr) {
416             ptp->dev_stat.pdt = PDT_SES;
417             ptp->dev_stat.enc_serv = 1;
418         } else if (0x1 & nvmsr) {
419             ptp->dev_stat.pdt = PDT_DISK;
420             ptp->dev_stat.enc_serv = 0;
421         } else {
422             uint32_t nn = sg_get_unaligned_le32(up + 516);
423 
424             ptp->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN;
425             ptp->dev_stat.enc_serv = 0;
426         }
427         break;
428     case 0x1:       /* override to SES device */
429         ptp->dev_stat.pdt = PDT_SES;
430         ptp->dev_stat.enc_serv = 1;
431         break;
432     case 0x2:       /* override to disk with attached SES device */
433         ptp->dev_stat.pdt = PDT_DISK;
434         ptp->dev_stat.enc_serv = 1;
435         break;
436     case 0x3:       /* override to SAFTE device (PDT_PROCESSOR) */
437         ptp->dev_stat.pdt = PDT_PROCESSOR;
438         ptp->dev_stat.enc_serv = 1;
439         break;
440     case 0xff:      /* override to normal disk */
441         ptp->dev_stat.pdt = PDT_DISK;
442         ptp->dev_stat.enc_serv = 0;
443         break;
444     default:
445         pr2ws("%s: unknown enclosure_override value: %d\n", __func__,
446               ptp->dev_stat.enclosure_override);
447         break;
448     }
449 }
450 
451 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)452 sntl_do_identify(struct sg_pt_linux_scsi * ptp, int cns, int nsid,
453                  int time_secs, int u_len, uint8_t * up, int vb)
454 {
455     struct sg_nvme_passthru_cmd cmd;
456 
457     memset(&cmd, 0, sizeof(cmd));
458     cmd.opcode = SG_NVME_AD_IDENTIFY;
459     cmd.nsid = nsid;
460     cmd.cdw10 = cns;
461     cmd.addr = (uint64_t)(sg_uintptr_t)up;
462     cmd.data_len = u_len;
463     return sg_nvme_admin_cmd(ptp, &cmd, up, true, time_secs, vb);
464 }
465 
466 /* Currently only caches associated identify controller response (4096 bytes).
467  * Returns 0 on success; otherwise a positive value is returned */
468 static int
sntl_cache_identify(struct sg_pt_linux_scsi * ptp,int time_secs,int vb)469 sntl_cache_identify(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
470 {
471     int ret;
472     uint32_t pg_sz = sg_get_page_size();
473     uint8_t * up;
474 
475     up = sg_memalign(pg_sz, pg_sz, &ptp->free_nvme_id_ctlp, false);
476     ptp->nvme_id_ctlp = up;
477     if (NULL == up) {
478         pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
479         return sg_convert_errno(ENOMEM);
480     }
481     ret = sntl_do_identify(ptp, 0x1 /* CNS */, 0 /* nsid */, time_secs,
482                            pg_sz, up, vb);
483     if (0 == ret)
484         sntl_check_enclosure_override(ptp, vb);
485     return (ret < 0) ? sg_convert_errno(-ret) : ret;
486 }
487 
488 /* If nsid==0 then set cmdp->nsid to SG_NVME_BROADCAST_NSID. */
489 static int
sntl_get_features(struct sg_pt_linux_scsi * ptp,int feature_id,int select,uint32_t nsid,uint64_t din_addr,int time_secs,int vb)490 sntl_get_features(struct sg_pt_linux_scsi * ptp, int feature_id, int select,
491                   uint32_t nsid, uint64_t din_addr, int time_secs, int vb)
492 {
493     int res;
494     struct sg_nvme_passthru_cmd cmd;
495     struct sg_nvme_passthru_cmd * cmdp = &cmd;
496 
497     if (vb > 4)
498         pr2ws("%s: feature_id=0x%x, select=%d\n", __func__, feature_id,
499               select);
500     memset(cmdp, 0, sizeof(*cmdp));
501     cmdp->opcode = SG_NVME_AD_GET_FEATURE;
502     cmdp->nsid = nsid ? nsid : SG_NVME_BROADCAST_NSID;
503     select &= 0x7;
504     feature_id &= 0xff;
505     cmdp->cdw10 = (select << 8) | feature_id;
506     if (din_addr)
507         cmdp->addr = din_addr;
508     cmdp->timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs);
509     res = sg_nvme_admin_cmd(ptp, cmdp, NULL, false, time_secs, vb);
510     if (res)
511         return res;
512     ptp->os_err = 0;
513     ptp->nvme_status = 0;
514     return 0;
515 }
516 
517 static const char * nvme_scsi_vendor_str = "NVMe    ";
518 static const uint16_t inq_resp_len = 36;
519 
520 static int
sntl_inq(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)521 sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
522          int vb)
523 {
524     bool evpd;
525     int res;
526     uint16_t n, alloc_len, pg_cd;
527     uint32_t pg_sz = sg_get_page_size();
528     uint8_t * nvme_id_ns = NULL;
529     uint8_t * free_nvme_id_ns = NULL;
530     uint8_t inq_dout[256];
531 
532     if (vb > 5)
533         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
534 
535     if (0x2 & cdbp[1]) {        /* Reject CmdDt=1 */
536         mk_sense_invalid_fld(ptp, true, 1, 1, vb);
537         return 0;
538     }
539     if (NULL == ptp->nvme_id_ctlp) {
540         res = sntl_cache_identify(ptp, time_secs, vb);
541         if (SG_LIB_NVME_STATUS == res) {
542             mk_sense_from_nvme_status(ptp, vb);
543             return 0;
544         } else if (res) /* should be negative errno */
545             return res;
546     }
547     memset(inq_dout, 0, sizeof(inq_dout));
548     alloc_len = sg_get_unaligned_be16(cdbp + 3);
549     evpd = !!(0x1 & cdbp[1]);
550     pg_cd = cdbp[2];
551     if (evpd) {         /* VPD page responses */
552         bool cp_id_ctl = false;
553 
554         switch (pg_cd) {
555         case 0:
556             /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
557             inq_dout[1] = pg_cd;
558             n = 11;
559             sg_put_unaligned_be16(n - 4, inq_dout + 2);
560             inq_dout[4] = 0x0;
561             inq_dout[5] = 0x80;
562             inq_dout[6] = 0x83;
563             inq_dout[7] = 0x86;
564             inq_dout[8] = 0x87;
565             inq_dout[9] = 0x92;
566             inq_dout[n - 1] = SG_NVME_VPD_NICR;     /* last VPD number */
567             break;
568         case 0x80:
569             /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
570             inq_dout[1] = pg_cd;
571             n = 24;
572             sg_put_unaligned_be16(n - 4, inq_dout + 2);
573             memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20);    /* SN */
574             break;
575         case 0x83:
576             if ((ptp->nvme_nsid > 0) &&
577                 (ptp->nvme_nsid < SG_NVME_BROADCAST_NSID)) {
578                 nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns,
579                                          false);
580                 if (nvme_id_ns) {
581                     /* CNS=0x0 Identify namespace */
582                     res = sntl_do_identify(ptp, 0x0, ptp->nvme_nsid,
583                                            time_secs, pg_sz, nvme_id_ns, vb);
584                     if (res) {
585                         free(free_nvme_id_ns);
586                         free_nvme_id_ns = NULL;
587                         nvme_id_ns = NULL;
588                     }
589                 }
590             }
591             n = sg_make_vpd_devid_for_nvme(ptp->nvme_id_ctlp, nvme_id_ns,
592                                            0 /* pdt */, -1 /*tproto */,
593                                            inq_dout, sizeof(inq_dout));
594             if (n > 3)
595                 sg_put_unaligned_be16(n - 4, inq_dout + 2);
596             if (free_nvme_id_ns) {
597                 free(free_nvme_id_ns);
598                 free_nvme_id_ns = NULL;
599                 nvme_id_ns = NULL;
600             }
601             break;
602         case 0x86:      /* Extended INQUIRY (per SFS SPC Discovery 2016) */
603             inq_dout[1] = pg_cd;
604             n = 64;
605             sg_put_unaligned_be16(n - 4, inq_dout + 2);
606             inq_dout[5] = 0x1;          /* SIMPSUP=1 */
607             inq_dout[7] = 0x1;          /* LUICLR=1 */
608             inq_dout[13] = 0x40;        /* max supported sense data length */
609             break;
610         case 0x87:      /* Mode page policy (per SFS SPC Discovery 2016) */
611             inq_dout[1] = pg_cd;
612             n = 8;
613             sg_put_unaligned_be16(n - 4, inq_dout + 2);
614             inq_dout[4] = 0x3f;         /* all mode pages */
615             inq_dout[5] = 0xff;         /*     and their sub-pages */
616             inq_dout[6] = 0x80;         /* MLUS=1, policy=shared */
617             break;
618         case 0x92:      /* SCSI Feature set: only SPC Discovery 2016 */
619             inq_dout[1] = pg_cd;
620             n = 10;
621             sg_put_unaligned_be16(n - 4, inq_dout + 2);
622             inq_dout[9] = 0x1;  /* SFS SPC Discovery 2016 */
623             break;
624         case SG_NVME_VPD_NICR:  /* 0xde (vendor (sg3_utils) specific) */
625             inq_dout[1] = pg_cd;
626             sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
627             n = 16 + 4096;
628             cp_id_ctl = true;
629             break;
630         default:        /* Point to page_code field in cdb */
631             mk_sense_invalid_fld(ptp, true, 2, 7, vb);
632             return 0;
633         }
634         if (alloc_len > 0) {
635             n = (alloc_len < n) ? alloc_len : n;
636             n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
637             ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
638             if (n > 0) {
639                 uint8_t * dp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
640 
641                 if (cp_id_ctl) {
642                     memcpy(dp, inq_dout, (n < 16 ? n : 16));
643                     if (n > 16)
644                         memcpy(dp + 16, ptp->nvme_id_ctlp, n - 16);
645                 } else
646                     memcpy(dp, inq_dout, n);
647             }
648         }
649     } else {            /* Standard INQUIRY response */
650         /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */
651         inq_dout[0] = (0x1f & ptp->dev_stat.pdt);  /* (PQ=0)<<5 */
652         /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6 | (HOT_PLUG=0)<<4; */
653         inq_dout[2] = 6;   /* version: SPC-4 */
654         inq_dout[3] = 2;   /* NORMACA=0, HISUP=0, response data format: 2 */
655         inq_dout[4] = 31;  /* so response length is (or could be) 36 bytes */
656         inq_dout[6] = ptp->dev_stat.enc_serv ? 0x40 : 0;
657         inq_dout[7] = 0x2;    /* CMDQUE=1 */
658         memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8);  /* NVMe not Intel */
659         memcpy(inq_dout + 16, ptp->nvme_id_ctlp + 24, 16); /* Prod <-- MN */
660         memcpy(inq_dout + 32, ptp->nvme_id_ctlp + 64, 4);  /* Rev <-- FR */
661         if (alloc_len > 0) {
662             n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len;
663             n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
664             ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
665             if (n > 0)
666                 memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp,
667                        inq_dout, n);
668         }
669     }
670     return 0;
671 }
672 
673 static int
sntl_rluns(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)674 sntl_rluns(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs,
675            int vb)
676 {
677     int res;
678     uint16_t sel_report;
679     uint32_t alloc_len, k, n, num, max_nsid;
680     uint8_t * rl_doutp;
681     uint8_t * up;
682 
683     if (vb > 5)
684         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
685 
686     sel_report = cdbp[2];
687     alloc_len = sg_get_unaligned_be32(cdbp + 6);
688     if (NULL == ptp->nvme_id_ctlp) {
689         res = sntl_cache_identify(ptp, time_secs, vb);
690         if (SG_LIB_NVME_STATUS == res) {
691             mk_sense_from_nvme_status(ptp, vb);
692             return 0;
693         } else if (res)
694             return res;
695     }
696     max_nsid = sg_get_unaligned_le32(ptp->nvme_id_ctlp + 516);
697     switch (sel_report) {
698     case 0:
699     case 2:
700         num = max_nsid;
701         break;
702     case 1:
703     case 0x10:
704     case 0x12:
705         num = 0;
706         break;
707     case 0x11:
708         num = (1 == ptp->nvme_nsid) ? max_nsid :  0;
709         break;
710     default:
711         if (vb > 1)
712             pr2ws("%s: bad select_report value: 0x%x\n", __func__,
713                   sel_report);
714         mk_sense_invalid_fld(ptp, true, 2, 7, vb);
715         return 0;
716     }
717     rl_doutp = (uint8_t *)calloc(num + 1, 8);
718     if (NULL == rl_doutp) {
719         pr2ws("%s: calloc() failed to get memory\n", __func__);
720         return sg_convert_errno(ENOMEM);
721     }
722     for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8)
723         sg_put_unaligned_be16(k, up);
724     n = num * 8;
725     sg_put_unaligned_be32(n, rl_doutp);
726     n+= 8;
727     if (alloc_len > 0) {
728         n = (alloc_len < n) ? alloc_len : n;
729         n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
730         ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
731         if (n > 0)
732             memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, rl_doutp,
733                    n);
734     }
735     res = 0;
736     free(rl_doutp);
737     return res;
738 }
739 
740 static int
sntl_tur(struct sg_pt_linux_scsi * ptp,int time_secs,int vb)741 sntl_tur(struct sg_pt_linux_scsi * ptp, int time_secs, int vb)
742 {
743     int res;
744     uint32_t pow_state;
745 
746     if (vb > 5)
747         pr2ws("%s: start\n", __func__);
748     if (NULL == ptp->nvme_id_ctlp) {
749         res = sntl_cache_identify(ptp, time_secs, vb);
750         if (SG_LIB_NVME_STATUS == res) {
751             mk_sense_from_nvme_status(ptp, vb);
752             return 0;
753         } else if (res)
754             return res;
755     }
756     res = sntl_get_features(ptp, 2 /* Power Management */, 0 /* current */,
757                             0, 0, time_secs, vb);
758     if (0 != res) {
759         if (SG_LIB_NVME_STATUS == res) {
760             mk_sense_from_nvme_status(ptp, vb);
761             return 0;
762         } else
763             return res;
764     }
765     pow_state = (0x1f & ptp->nvme_result);
766     if (vb > 5)
767         pr2ws("%s: pow_state=%u\n", __func__, pow_state);
768 #if 0   /* pow_state bounces around too much on laptop */
769     if (pow_state)
770         mk_sense_asc_ascq(ptp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0,
771                           vb);
772 #endif
773     return 0;
774 }
775 
776 static int
sntl_req_sense(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)777 sntl_req_sense(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
778                int time_secs, int vb)
779 {
780     bool desc;
781     int res;
782     uint32_t pow_state, alloc_len, n;
783     uint8_t rs_dout[64];
784 
785     if (vb > 5)
786         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
787     if (NULL == ptp->nvme_id_ctlp) {
788         res = sntl_cache_identify(ptp, time_secs, vb);
789         if (SG_LIB_NVME_STATUS == res) {
790             mk_sense_from_nvme_status(ptp, vb);
791             return 0;
792         } else if (res)
793             return res;
794     }
795     desc = !!(0x1 & cdbp[1]);
796     alloc_len = cdbp[4];
797     res = sntl_get_features(ptp, 0x2 /* Power Management */, 0 /* current */,
798                             0, 0, time_secs, vb);
799     if (0 != res) {
800         if (SG_LIB_NVME_STATUS == res) {
801             mk_sense_from_nvme_status(ptp, vb);
802             return 0;
803         } else
804             return res;
805     }
806     ptp->io_hdr.response_len = 0;
807     pow_state = (0x1f & ptp->nvme_result);
808     if (vb > 5)
809         pr2ws("%s: pow_state=%u\n", __func__, pow_state);
810     memset(rs_dout, 0, sizeof(rs_dout));
811     if (pow_state)
812         sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
813                               LOW_POWER_COND_ON_ASC, 0);
814     else
815         sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
816                               NO_ADDITIONAL_SENSE, 0);
817     n = desc ? 8 : 18;
818     n = (n < alloc_len) ? n : alloc_len;
819     n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len;
820     ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n;
821     if (n > 0)
822         memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, rs_dout, n);
823     return 0;
824 }
825 
826 static uint8_t pc_t10_2_select[] = {0, 3, 1, 2};
827 
828 /* For MODE SENSE(10) and MODE SELECT(10). 6 byte variants not supported */
829 static int
sntl_mode_ss(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)830 sntl_mode_ss(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
831              int time_secs, int vb)
832 {
833     bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]);
834     int res, n, len;
835     uint8_t * bp;
836     struct sg_sntl_result_t sntl_result;
837 
838     if (vb > 5)
839         pr2ws("%s: mode se%s\n", __func__, (is_msense ? "nse" : "lect"));
840     if (NULL == ptp->nvme_id_ctlp) {
841         res = sntl_cache_identify(ptp, time_secs, vb);
842         if (SG_LIB_NVME_STATUS == res) {
843             mk_sense_from_nvme_status(ptp, vb);
844             return 0;
845         } else if (res)
846             return res;
847     }
848     if (is_msense) {    /* MODE SENSE(10) */
849         uint8_t pc_t10 = (cdbp[2] >> 6) & 0x3;
850         int mp_t10 = (cdbp[2] & 0x3f);
851 
852         if ((0x3f == mp_t10) || (0x8 /* caching mpage */ == mp_t10)) {
853             /* 0x6 is "Volatile write cache" feature id */
854             res = sntl_get_features(ptp, 0x6, pc_t10_2_select[pc_t10], 0,
855                                     0, time_secs, vb);
856             if (0 != res) {
857                 if (SG_LIB_NVME_STATUS == res) {
858                     mk_sense_from_nvme_status(ptp, vb);
859                     return 0;
860                 } else
861                     return res;
862             }
863             ptp->dev_stat.wce = !!(0x1 & ptp->nvme_result);
864         }
865         len = ptp->io_hdr.din_xfer_len;
866         bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
867         n = sntl_resp_mode_sense10(&ptp->dev_stat, cdbp, bp, len,
868                                    &sntl_result);
869         ptp->io_hdr.din_resid = (n >= 0) ? len - n : len;
870     } else {            /* MODE SELECT(10) */
871         bool sp = !!(0x1 & cdbp[1]);    /* Save Page indication */
872         uint8_t pre_enc_ov = ptp->dev_stat.enclosure_override;
873 
874         len = ptp->io_hdr.dout_xfer_len;
875         bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
876         ptp->dev_stat.wce_changed = false;
877         n = sntl_resp_mode_select10(&ptp->dev_stat, cdbp, bp, len,
878                                     &sntl_result);
879         if (ptp->dev_stat.wce_changed) {
880             uint32_t nsid = ptp->nvme_nsid;
881             struct sg_nvme_passthru_cmd cmd;
882             struct sg_nvme_passthru_cmd * cmdp = &cmd;
883 
884             ptp->dev_stat.wce_changed = false;
885             memset(cmdp, 0, sizeof(*cmdp));
886             cmdp->opcode = SG_NVME_AD_SET_FEATURE;
887             cmdp->nsid = nsid ? nsid : SG_NVME_BROADCAST_NSID;
888             cmdp->cdw10 = 0x6; /* "Volatile write cache" feature id */
889             if (sp)
890                 cmdp->cdw10 |= (1U << 31);
891             cmdp->cdw11 = (uint32_t)ptp->dev_stat.wce;
892             cmdp->timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs);
893             res = sg_nvme_admin_cmd(ptp, cmdp, NULL, false, time_secs, vb);
894             if (0 != res) {
895                 if (SG_LIB_NVME_STATUS == res) {
896                     mk_sense_from_nvme_status(ptp, vb);
897                     return 0;
898                 } else
899                     return res;
900             }
901             ptp->os_err = 0;
902             ptp->nvme_status = 0;
903         }
904         if (pre_enc_ov != ptp->dev_stat.enclosure_override)
905             sntl_check_enclosure_override(ptp, vb);  /* ENC_OV has changed */
906     }
907     if (n < 0) {
908         int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit :
909                                                    -1;
910         if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) &&
911             (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) {
912             if (INVALID_FIELD_IN_CDB == sntl_result.asc)
913                 mk_sense_invalid_fld(ptp, true, sntl_result.in_byte, in_bit,
914                                      vb);
915             else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc)
916                 mk_sense_invalid_fld(ptp, false, sntl_result.in_byte, in_bit,
917                                      vb);
918             else
919                 mk_sense_asc_ascq(ptp, sntl_result.sk, sntl_result.asc,
920                                   sntl_result.ascq, vb);
921         } else
922             pr2ws("%s: error but no sense?? n=%d\n", __func__, n);
923     }
924     return 0;
925 }
926 
927 /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI
928  * has a special command (SES Send) to tunnel through pages to an
929  * enclosure. The NVMe enclosure is meant to understand the SES
930  * (SCSI Enclosure Services) use of diagnostics pages that are
931  * related to SES. */
932 static int
sntl_senddiag(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)933 sntl_senddiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
934               int time_secs, int vb)
935 {
936     bool pf, self_test;
937     int res;
938     uint8_t st_cd, dpg_cd;
939     uint32_t alloc_len, n, dout_len, dpg_len;
940     const uint32_t pg_sz = sg_get_page_size();
941     uint8_t * dop;
942     struct sg_nvme_passthru_cmd cmd;
943     uint8_t * cmd_up = (uint8_t *)&cmd;
944 
945     st_cd = 0x7 & (cdbp[1] >> 5);
946     self_test = !! (0x4 & cdbp[1]);
947     pf = !! (0x10 & cdbp[1]);
948     if (vb > 5)
949         pr2ws("%s: pf=%d, self_test=%d (st_code=%d)\n", __func__, (int)pf,
950               (int)self_test, (int)st_cd);
951     if (self_test || st_cd) {
952         uint32_t nvme_dst;
953 
954         memset(cmd_up, 0, sizeof(cmd));
955         cmd_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_DEV_SELT_TEST;
956         /* just this namespace (if there is one) and controller */
957         sg_put_unaligned_le32(ptp->nvme_nsid, cmd_up + SG_NVME_PT_NSID);
958         switch (st_cd) {
959         case 0: /* Here if self_test is set, do short self-test */
960         case 1: /* Background short */
961         case 5: /* Foreground short */
962             nvme_dst = 1;
963             break;
964         case 2: /* Background extended */
965         case 6: /* Foreground extended */
966             nvme_dst = 2;
967             break;
968         case 4: /* Abort self-test */
969             nvme_dst = 0xf;
970             break;
971         default:
972             pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd);
973             mk_sense_invalid_fld(ptp, true, 1, 7, vb);
974             return 0;
975         }
976         sg_put_unaligned_le32(nvme_dst, cmd_up + SG_NVME_PT_CDW10);
977         res = sg_nvme_admin_cmd(ptp, &cmd, NULL, false, time_secs, vb);
978         if (0 != res) {
979             if (SG_LIB_NVME_STATUS == res) {
980                 mk_sense_from_nvme_status(ptp, vb);
981                 return 0;
982             } else
983                 return res;
984         }
985     }
986     alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
987     dout_len = ptp->io_hdr.dout_xfer_len;
988     if (pf) {
989         if (0 == alloc_len) {
990             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
991             if (vb)
992                 pr2ws("%s: PF bit set bit param_list_len=0\n", __func__);
993             return 0;
994         }
995     } else {    /* PF bit clear */
996         if (alloc_len) {
997             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
998             if (vb)
999                 pr2ws("%s: param_list_len>0 but PF clear\n", __func__);
1000             return 0;
1001         } else
1002             return 0;     /* nothing to do */
1003     }
1004     if (dout_len < 4) {
1005         if (vb)
1006             pr2ws("%s: dout length (%u bytes) too short\n", __func__,
1007                   dout_len);
1008         return SCSI_PT_DO_BAD_PARAMS;
1009     }
1010     n = dout_len;
1011     n = (n < alloc_len) ? n : alloc_len;
1012     dop = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
1013     if (! sg_is_aligned(dop, pg_sz)) {  /* is dop page aligned ? */
1014         if (vb)
1015             pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__,
1016                   (uint64_t)ptp->io_hdr.dout_xferp);
1017         return SCSI_PT_DO_BAD_PARAMS;
1018     }
1019     dpg_cd = dop[0];
1020     dpg_len = sg_get_unaligned_be16(dop + 2) + 4;
1021     /* should we allow for more than one D_PG is dout ?? */
1022     n = (n < dpg_len) ? n : dpg_len;    /* not yet ... */
1023 
1024     if (vb)
1025         pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n",
1026               __func__, dpg_cd, dpg_len);
1027     memset(&cmd, 0, sizeof(cmd));
1028     cmd.opcode = SG_NVME_AD_MI_SEND;
1029     cmd.addr = (uint64_t)(sg_uintptr_t)dop;
1030     cmd.data_len = 0x1000;   /* NVMe 4k page size. Maybe determine this? */
1031                              /* dout_len > 0x1000, is this a problem?? */
1032     cmd.cdw10 = 0x0804;      /* NVMe Message Header */
1033     cmd.cdw11 = 0x9;         /* nvme_mi_ses_send; (0x8 -> mi_ses_recv) */
1034     cmd.cdw13 = n;
1035     res = sg_nvme_admin_cmd(ptp, &cmd, dop, false, time_secs, vb);
1036     if (0 != res) {
1037         if (SG_LIB_NVME_STATUS == res) {
1038             mk_sense_from_nvme_status(ptp, vb);
1039             return 0;
1040         }
1041     }
1042     return res;
1043 }
1044 
1045 /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1)
1046  * NVMe-MI has a special command (SES Receive) to read pages through a
1047  * tunnel from an enclosure. The NVMe enclosure is meant to understand the
1048  * SES (SCSI Enclosure Services) use of diagnostics pages that are
1049  * related to SES. */
1050 static int
sntl_recvdiag(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1051 sntl_recvdiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1052               int time_secs, int vb)
1053 {
1054     bool pcv;
1055     int res;
1056     uint8_t dpg_cd;
1057     uint32_t alloc_len, n, din_len;
1058     uint32_t pg_sz = sg_get_page_size();
1059     uint8_t * dip;
1060     struct sg_nvme_passthru_cmd cmd;
1061 
1062     pcv = !! (0x1 & cdbp[1]);
1063     dpg_cd = cdbp[2];
1064     alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
1065     if (vb > 5)
1066         pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__,
1067               dpg_cd, (int)pcv, alloc_len);
1068     din_len = ptp->io_hdr.din_xfer_len;
1069     n = din_len;
1070     n = (n < alloc_len) ? n : alloc_len;
1071     dip = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
1072     if (! sg_is_aligned(dip, pg_sz)) {
1073         if (vb)
1074             pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__,
1075                   (uint64_t)ptp->io_hdr.din_xferp);
1076         return SCSI_PT_DO_BAD_PARAMS;
1077     }
1078 
1079     if (vb)
1080         pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__,
1081               dpg_cd);
1082     memset(&cmd, 0, sizeof(cmd));
1083     cmd.opcode = SG_NVME_AD_MI_RECEIVE;
1084     cmd.addr = (uint64_t)(sg_uintptr_t)dip;
1085     cmd.data_len = 0x1000;   /* NVMe 4k page size. Maybe determine this? */
1086                              /* din_len > 0x1000, is this a problem?? */
1087     cmd.cdw10 = 0x0804;      /* NVMe Message Header */
1088     cmd.cdw11 = 0x8;         /* nvme_mi_ses_receive */
1089     cmd.cdw12 = dpg_cd;
1090     cmd.cdw13 = n;
1091     res = sg_nvme_admin_cmd(ptp, &cmd, dip, true, time_secs, vb);
1092     if (0 != res) {
1093         if (SG_LIB_NVME_STATUS == res) {
1094             mk_sense_from_nvme_status(ptp, vb);
1095             return 0;
1096         } else
1097             return res;
1098     }
1099     ptp->io_hdr.din_resid = din_len - n;
1100     return res;
1101 }
1102 
1103 #define F_SA_LOW                0x80    /* cdb byte 1, bits 4 to 0 */
1104 #define F_SA_HIGH               0x100   /* as used by variable length cdbs */
1105 #define FF_SA (F_SA_HIGH | F_SA_LOW)
1106 #define F_INV_OP                0x200
1107 
1108 static int
sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1109 sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1110                  int time_secs, int vb)
1111 {
1112     bool rctd;
1113     uint8_t reporting_opts, req_opcode, supp;
1114     uint16_t req_sa;
1115     uint32_t alloc_len, offset, a_len;
1116     uint32_t pg_sz = sg_get_page_size();
1117     int len, count, bump;
1118     const struct sg_opcode_info_t *oip;
1119     uint8_t *arr;
1120     uint8_t *free_arr;
1121 
1122     if (vb > 5)
1123         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
1124     rctd = !!(cdbp[2] & 0x80);      /* report command timeout desc. */
1125     reporting_opts = cdbp[2] & 0x7;
1126     req_opcode = cdbp[3];
1127     req_sa = sg_get_unaligned_be16(cdbp + 4);
1128     alloc_len = sg_get_unaligned_be32(cdbp + 6);
1129     if (alloc_len < 4 || alloc_len > 0xffff) {
1130         mk_sense_invalid_fld(ptp, true, 6, -1, vb);
1131         return 0;
1132     }
1133     a_len = pg_sz - 72;
1134     arr = sg_memalign(pg_sz, pg_sz, &free_arr, false);
1135     if (NULL == arr) {
1136         pr2ws("%s: calloc() failed to get memory\n", __func__);
1137         return sg_convert_errno(ENOMEM);
1138     }
1139     switch (reporting_opts) {
1140     case 0: /* all commands */
1141         count = 0;
1142         bump = rctd ? 20 : 8;
1143         for (offset = 4, oip = sg_get_opcode_translation();
1144              (oip->flags != 0xffff) && (offset < a_len); ++oip) {
1145             if (F_INV_OP & oip->flags)
1146                 continue;
1147             ++count;
1148             arr[offset] = oip->opcode;
1149             sg_put_unaligned_be16(oip->sa, arr + offset + 2);
1150             if (rctd)
1151                 arr[offset + 5] |= 0x2;
1152             if (FF_SA & oip->flags)
1153                 arr[offset + 5] |= 0x1;
1154             sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1155             if (rctd)
1156                 sg_put_unaligned_be16(0xa, arr + offset + 8);
1157             offset += bump;
1158         }
1159         sg_put_unaligned_be32(count * bump, arr + 0);
1160         break;
1161     case 1: /* one command: opcode only */
1162     case 2: /* one command: opcode plus service action */
1163     case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1164         for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
1165             if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
1166                 break;
1167         }
1168         if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) {
1169             supp = 1;
1170             offset = 4;
1171         } else {
1172             if (1 == reporting_opts) {
1173                 if (FF_SA & oip->flags) {
1174                     mk_sense_invalid_fld(ptp, true, 2, 2, vb);
1175                     free(free_arr);
1176                     return 0;
1177                 }
1178                 req_sa = 0;
1179             } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) {
1180                 mk_sense_invalid_fld(ptp, true, 4, -1, vb);
1181                 free(free_arr);
1182                 return 0;
1183             }
1184             if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode))
1185                 supp = 3;
1186             else if (0 == (FF_SA & oip->flags))
1187                 supp = 1;
1188             else if (req_sa != oip->sa)
1189                 supp = 1;
1190             else
1191                 supp = 3;
1192             if (3 == supp) {
1193                 uint16_t u;
1194                 int k;
1195 
1196                 u = oip->len_mask[0];
1197                 sg_put_unaligned_be16(u, arr + 2);
1198                 arr[4] = oip->opcode;
1199                 for (k = 1; k < u; ++k)
1200                     arr[4 + k] = (k < 16) ?
1201                 oip->len_mask[k] : 0xff;
1202                 offset = 4 + u;
1203             } else
1204                 offset = 4;
1205         }
1206         arr[1] = (rctd ? 0x80 : 0) | supp;
1207         if (rctd) {
1208             sg_put_unaligned_be16(0xa, arr + offset);
1209             offset += 12;
1210         }
1211         break;
1212     default:
1213         mk_sense_invalid_fld(ptp, true, 2, 2, vb);
1214         free(free_arr);
1215         return 0;
1216     }
1217     offset = (offset < a_len) ? offset : a_len;
1218     len = (offset < alloc_len) ? offset : alloc_len;
1219     ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len;
1220     if (len > 0)
1221         memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, arr, len);
1222     free(free_arr);
1223     return 0;
1224 }
1225 
1226 static int
sntl_rep_tmfs(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1227 sntl_rep_tmfs(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1228               int time_secs, int vb)
1229 {
1230     bool repd;
1231     uint32_t alloc_len, len;
1232     uint8_t arr[16];
1233 
1234     if (vb > 5)
1235         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
1236     memset(arr, 0, sizeof(arr));
1237     repd = !!(cdbp[2] & 0x80);
1238     alloc_len = sg_get_unaligned_be32(cdbp + 6);
1239     if (alloc_len < 4) {
1240         mk_sense_invalid_fld(ptp, true, 6, -1, vb);
1241         return 0;
1242     }
1243     arr[0] = 0xc8;          /* ATS | ATSS | LURS */
1244     arr[1] = 0x1;           /* ITNRS */
1245     if (repd) {
1246         arr[3] = 0xc;
1247         len = 16;
1248     } else
1249         len = 4;
1250 
1251     len = (len < alloc_len) ? len : alloc_len;
1252     ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len;
1253     if (len > 0)
1254         memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, arr, len);
1255     return 0;
1256 }
1257 
1258 /* Note that the "Returned logical block address" (RLBA) field in the SCSI
1259  * READ CAPACITY (10+16) command's response provides the address of the _last_
1260  * LBA (counting origin 0) which will be one less that the "size" in the
1261  * NVMe Identify command response's NSZE field. One problem is that in
1262  * some situations NSZE can be zero: temporarily set RLBA field to 0
1263  * (implying a 1 LB logical units size) pending further research. The LBLIB
1264  * is the "Logical Block Length In Bytes" field in the RCAP response. */
1265 static int
sntl_readcap(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1266 sntl_readcap(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1267              int time_secs, int vb)
1268 {
1269     bool is_rcap10 = (SCSI_READ_CAPACITY10_OPC == cdbp[0]);
1270     int res, n, len, alloc_len, dps;
1271     uint8_t flbas, index, lbads;  /* NVMe: 2**LBADS --> Logical Block size */
1272     uint32_t lbafx;     /* NVME: LBAF0...LBAF15, each 16 bytes */
1273     uint32_t pg_sz = sg_get_page_size();
1274     uint64_t nsze;
1275     uint8_t * bp;
1276     uint8_t * up;
1277     uint8_t * free_up = NULL;
1278     uint8_t resp[32];
1279 
1280     if (vb > 5)
1281         pr2ws("%s: RCAP%d, time_secs=%d\n", __func__,
1282               (is_rcap10 ? 10 : 16), time_secs);
1283     up = sg_memalign(pg_sz, pg_sz, &free_up, false);
1284     if (NULL == up) {
1285         pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
1286         return sg_convert_errno(ENOMEM);
1287     }
1288     res = sntl_do_identify(ptp, 0x0 /* CNS */, ptp->nvme_nsid, time_secs,
1289                            pg_sz, up, vb);
1290     if (res < 0) {
1291         res = sg_convert_errno(-res);
1292         goto fini;
1293     }
1294     memset(resp, 0, sizeof(resp));
1295     nsze = sg_get_unaligned_le64(up + 0);
1296     flbas = up[26];     /* NVME FLBAS field from Identify, want LBAF[flbas] */
1297     index = 128 + (4 * (flbas & 0xf));
1298     lbafx = sg_get_unaligned_le32(up + index);
1299     lbads = (lbafx >> 16) & 0xff;       /* bits 16 to 23 inclusive, pow2 */
1300     if (is_rcap10) {
1301         alloc_len = 8;  /* implicit, not in cdb */
1302         if (nsze > 0xffffffff)
1303             sg_put_unaligned_be32(0xffffffff, resp + 0);
1304         else if (0 == nsze)     /* no good answer here */
1305             sg_put_unaligned_be32(0, resp + 0);         /* SCSI RLBA field */
1306         else
1307             sg_put_unaligned_be32((uint32_t)(nsze - 1), resp + 0);
1308         sg_put_unaligned_be32(1 << lbads, resp + 4);    /* SCSI LBLIB field */
1309     } else {
1310         alloc_len = sg_get_unaligned_be32(cdbp + 10);
1311         dps = up[29];
1312         if (0x7 & dps) {
1313             resp[12] = 0x1;
1314             n = (0x7 & dps) - 1;
1315             if (n > 0)
1316                 resp[12] |= (n + n);
1317         }
1318         if (0 == nsze)  /* no good answer here */
1319             sg_put_unaligned_be64(0, resp + 0);
1320         else
1321             sg_put_unaligned_be64(nsze - 1, resp + 0);
1322         sg_put_unaligned_be32(1 << lbads, resp + 8);    /* SCSI LBLIB field */
1323     }
1324     len = ptp->io_hdr.din_xfer_len;
1325     bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
1326     n = 32;
1327     n = (n < alloc_len) ? n : alloc_len;
1328     n = (n < len) ? n : len;
1329     ptp->io_hdr.din_resid = len - n;
1330     if (n > 0)
1331         memcpy(bp, resp, n);
1332 fini:
1333     if (free_up)
1334         free(free_up);
1335     return res;
1336 }
1337 
1338 static int
do_nvm_pt_low(struct sg_pt_linux_scsi * ptp,struct sg_nvme_passthru_cmd * cmdp,void * dp,int dlen,bool is_read,int time_secs,int vb)1339 do_nvm_pt_low(struct sg_pt_linux_scsi * ptp,
1340               struct sg_nvme_passthru_cmd *cmdp, void * dp, int dlen,
1341               bool is_read, int time_secs, int vb)
1342 {
1343     const uint32_t cmd_len = sizeof(struct sg_nvme_passthru_cmd);
1344     int res;
1345     uint32_t n;
1346     uint16_t sct_sc;
1347     const uint8_t * up = ((const uint8_t *)cmdp) + SG_NVME_PT_OPCODE;
1348     char nam[64];
1349 
1350     if (vb)
1351         sg_get_nvme_opcode_name(*up, false /* NVM */ , sizeof(nam), nam);
1352     else
1353         nam[0] = '\0';
1354     cmdp->timeout_ms = (time_secs < 0) ? (-time_secs) : (1000 * time_secs);
1355     ptp->os_err = 0;
1356     if (vb > 2) {
1357         pr2ws("NVMe NVM command: %s\n", nam);
1358         hex2stderr((const uint8_t *)cmdp, cmd_len, 1);
1359         if ((vb > 4) && (! is_read) && dp) {
1360             if (dlen > 0) {
1361                 n = dlen;
1362                 if ((dlen < 512) || (vb > 5))
1363                     pr2ws("\nData-out buffer (%u bytes):\n", n);
1364                 else {
1365                     pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n);
1366                     n = 512;
1367                 }
1368                 hex2stderr((const uint8_t *)dp, n, 0);
1369             }
1370         }
1371     }
1372     res = ioctl(ptp->dev_fd, NVME_IOCTL_IO_CMD, cmdp);
1373     if (res < 0) {  /* OS error (errno negated) */
1374         ptp->os_err = -res;
1375         if (vb > 1) {
1376             pr2ws("%s: ioctl for %s [0x%x] failed: %s "
1377                   "(errno=%d)\n", __func__, nam, *up, strerror(-res), -res);
1378         }
1379         return res;
1380     }
1381 
1382     /* Now res contains NVMe completion queue CDW3 31:17 (15 bits) */
1383     ptp->nvme_result = cmdp->result;
1384     if ((! ptp->nvme_our_sntl) && ptp->io_hdr.response &&
1385         (ptp->io_hdr.max_response_len > 3)) {
1386         /* build 32 byte "sense" buffer */
1387         uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
1388         uint16_t st = (uint16_t)res;
1389 
1390         n = ptp->io_hdr.max_response_len;
1391         n = (n < 32) ? n : 32;
1392         memset(sbp, 0 , n);
1393         ptp->io_hdr.response_len = n;
1394         sg_put_unaligned_le32(cmdp->result,
1395                               sbp + SG_NVME_PT_CQ_RESULT);
1396         if (n > 15) /* LSBit will be 0 (Phase bit) after (st << 1) */
1397             sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P);
1398     }
1399     /* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */
1400     sct_sc = 0x7ff & res;       /* 11 bits */
1401     ptp->nvme_status = sct_sc;
1402     ptp->nvme_stat_dnr = !!(0x4000 & res);
1403     ptp->nvme_stat_more = !!(0x2000 & res);
1404     if (sct_sc) {  /* when non-zero, treat as command error */
1405         if (vb > 1) {
1406             char b[80];
1407 
1408             pr2ws("%s: ioctl for %s [0x%x] failed, status: %s [0x%x]\n",
1409                    __func__, nam, *up,
1410                   sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b), sct_sc);
1411         }
1412         return SG_LIB_NVME_STATUS;      /* == SCSI_PT_DO_NVME_STATUS */
1413     }
1414     if ((vb > 4) && is_read && dp) {
1415         if (dlen > 0) {
1416             n = dlen;
1417             if ((dlen < 1024) || (vb > 5))
1418                 pr2ws("\nData-in buffer (%u bytes):\n", n);
1419             else {
1420                 pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n);
1421                 n = 1024;
1422             }
1423             hex2stderr((const uint8_t *)dp, n, 0);
1424         }
1425     }
1426     return 0;
1427 }
1428 
1429 /* Since ptp can be a char device (e.g. /dev/nvme0) or a blocks device
1430  * (e.g. /dev/nvme0n1 or /dev/nvme0n1p3) use NVME_IOCTL_IO_CMD which is
1431  * common to both (and takes a timeout). The difficult is that
1432  * NVME_IOCTL_IO_CMD takes a nvme_passthru_cmd object point. */
1433 static int
sntl_do_nvm_cmd(struct sg_pt_linux_scsi * ptp,struct sg_nvme_user_io * iop,uint32_t dlen,bool is_read,int time_secs,int vb)1434 sntl_do_nvm_cmd(struct sg_pt_linux_scsi * ptp, struct sg_nvme_user_io * iop,
1435                 uint32_t dlen, bool is_read, int time_secs, int vb)
1436 {
1437 
1438     struct sg_nvme_passthru_cmd nvme_pt_cmd;
1439     struct sg_nvme_passthru_cmd *cmdp = &nvme_pt_cmd;
1440     void * dp = (void *)(sg_uintptr_t)iop->addr;
1441 
1442     memset(cmdp, 0, sizeof(*cmdp));
1443     cmdp->opcode = iop->opcode;
1444     cmdp->flags = iop->flags;
1445     cmdp->nsid = ptp->nvme_nsid;
1446     cmdp->addr = iop->addr;
1447     cmdp->data_len = dlen;
1448     cmdp->cdw10 = iop->slba & 0xffffffff;
1449     cmdp->cdw11 = (iop->slba >> 32) & 0xffffffff;
1450     cmdp->cdw12 = iop->nblocks; /* lower 16 bits already "0's based" count */
1451 
1452     return do_nvm_pt_low(ptp, cmdp, dp, dlen, is_read, time_secs, vb);
1453 }
1454 
1455 static int
sntl_rread(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1456 sntl_rread(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1457            int time_secs, int vb)
1458 {
1459     bool is_read10 = (SCSI_READ10_OPC == cdbp[0]);
1460     bool have_fua = !!(cdbp[1] & 0x8);
1461     int res;
1462     uint32_t nblks_t10 = 0;
1463     struct sg_nvme_user_io io;
1464     struct sg_nvme_user_io * iop = &io;
1465 
1466     if (vb > 5)
1467         pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua,
1468               time_secs);
1469     memset(iop, 0, sizeof(*iop));
1470     iop->opcode = SG_NVME_NVM_READ;
1471     if (is_read10) {
1472         iop->slba = sg_get_unaligned_be32(cdbp + 2);
1473         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
1474     } else {
1475         iop->slba = sg_get_unaligned_be64(cdbp + 2);
1476         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
1477         if (nblks_t10 > (UINT16_MAX + 1)) {
1478             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
1479             return 0;
1480         }
1481     }
1482     if (0 == nblks_t10) {         /* NOP in SCSI */
1483         if (vb > 4)
1484             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
1485                   __func__);
1486         return 0;
1487     }
1488     iop->nblocks = nblks_t10 - 1;       /* crazy "0's based" */
1489     if (have_fua)
1490         iop->control |= SG_NVME_RW_CONTROL_FUA;
1491     iop->addr = (uint64_t)ptp->io_hdr.din_xferp;
1492     res = sntl_do_nvm_cmd(ptp, iop, ptp->io_hdr.din_xfer_len,
1493                           true /* is_read */, time_secs, vb);
1494     if (SG_LIB_NVME_STATUS == res) {
1495         mk_sense_from_nvme_status(ptp, vb);
1496         return 0;
1497     }
1498     return res;
1499 }
1500 
1501 static int
sntl_write(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1502 sntl_write(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1503            int time_secs, int vb)
1504 {
1505     bool is_write10 = (SCSI_WRITE10_OPC == cdbp[0]);
1506     bool have_fua = !!(cdbp[1] & 0x8);
1507     int res;
1508     uint32_t nblks_t10 = 0;
1509     struct sg_nvme_user_io io;
1510     struct sg_nvme_user_io * iop = &io;
1511 
1512     if (vb > 5)
1513         pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua,
1514               time_secs);
1515     memset(iop, 0, sizeof(*iop));
1516     iop->opcode = SG_NVME_NVM_WRITE;
1517     if (is_write10) {
1518         iop->slba = sg_get_unaligned_be32(cdbp + 2);
1519         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
1520     } else {
1521         iop->slba = sg_get_unaligned_be64(cdbp + 2);
1522         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
1523         if (nblks_t10 > (UINT16_MAX + 1)) {
1524             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
1525             return 0;
1526         }
1527     }
1528     if (0 == nblks_t10) { /* NOP in SCSI */
1529         if (vb > 4)
1530             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
1531                   __func__);
1532         return 0;
1533     }
1534     iop->nblocks = nblks_t10 - 1;
1535     if (have_fua)
1536         iop->control |= SG_NVME_RW_CONTROL_FUA;
1537     iop->addr = (uint64_t)ptp->io_hdr.dout_xferp;
1538     res = sntl_do_nvm_cmd(ptp, iop, ptp->io_hdr.dout_xfer_len, false,
1539                           time_secs, vb);
1540     if (SG_LIB_NVME_STATUS == res) {
1541         mk_sense_from_nvme_status(ptp, vb);
1542         return 0;
1543     }
1544     return res;
1545 }
1546 
1547 static int
sntl_verify(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1548 sntl_verify(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1549            int time_secs, int vb)
1550 {
1551     bool is_verify10 = (SCSI_VERIFY10_OPC == cdbp[0]);
1552     uint8_t bytchk = (cdbp[1] >> 1) & 0x3;
1553     uint32_t dlen = 0;
1554     int res;
1555     uint32_t nblks_t10 = 0;
1556     struct sg_nvme_user_io io;
1557     struct sg_nvme_user_io * iop = &io;
1558 
1559     if (vb > 5)
1560         pr2ws("%s: bytchk=%d, time_secs=%d\n", __func__, bytchk, time_secs);
1561     if (bytchk > 1) {
1562         mk_sense_invalid_fld(ptp, true, 1, 2, vb);
1563         return 0;
1564     }
1565     memset(iop, 0, sizeof(*iop));
1566     iop->opcode = bytchk ? SG_NVME_NVM_COMPARE : SG_NVME_NVM_VERIFY;
1567     if (is_verify10) {
1568         iop->slba = sg_get_unaligned_be32(cdbp + 2);
1569         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
1570     } else {
1571         iop->slba = sg_get_unaligned_be64(cdbp + 2);
1572         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
1573         if (nblks_t10 > (UINT16_MAX + 1)) {
1574             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
1575             return 0;
1576         }
1577     }
1578     if (0 == nblks_t10) { /* NOP in SCSI */
1579         if (vb > 4)
1580             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
1581                   __func__);
1582         return 0;
1583     }
1584     iop->nblocks = nblks_t10 - 1;
1585     if (bytchk) {
1586         iop->addr = (uint64_t)ptp->io_hdr.dout_xferp;
1587         dlen = ptp->io_hdr.dout_xfer_len;
1588     }
1589     res = sntl_do_nvm_cmd(ptp, iop, dlen, false, time_secs, vb);
1590     if (SG_LIB_NVME_STATUS == res) {
1591         mk_sense_from_nvme_status(ptp, vb);
1592         return 0;
1593     }
1594     return res;
1595 }
1596 
1597 static int
sntl_write_same(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1598 sntl_write_same(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1599                 int time_secs, int vb)
1600 {
1601     bool is_ws10 = (SCSI_WRITE_SAME10_OPC == cdbp[0]);
1602     bool ndob = is_ws10 ? false : !!(0x1 & cdbp[1]);
1603     int res;
1604     int nblks_t10 = 0;
1605     struct sg_nvme_user_io io;
1606     struct sg_nvme_user_io * iop = &io;
1607 
1608     if (vb > 5)
1609         pr2ws("%s: ndob=%d, time_secs=%d\n", __func__, (int)ndob, time_secs);
1610     if (! ndob) {
1611         int flbas, index, lbafx, lbads, lbsize;
1612         uint8_t * up;
1613         uint8_t * dp;
1614 
1615         dp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
1616         if (dp == NULL)
1617             return sg_convert_errno(ENOMEM);
1618         if (NULL == ptp->nvme_id_ctlp) {
1619             res = sntl_cache_identify(ptp, time_secs, vb);
1620             if (SG_LIB_NVME_STATUS == res) {
1621                 mk_sense_from_nvme_status(ptp, vb);
1622                 return 0;
1623             } else if (res)
1624                 return res;
1625         }
1626         up = ptp->nvme_id_ctlp;
1627         flbas = up[26];     /* NVME FLBAS field from Identify */
1628         index = 128 + (4 * (flbas & 0xf));
1629         lbafx = sg_get_unaligned_le32(up + index);
1630         lbads = (lbafx >> 16) & 0xff;  /* bits 16 to 23 inclusive, pow2 */
1631         lbsize = 1 << lbads;
1632         if (! sg_all_zeros(dp, lbsize)) {
1633             mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, PCIE_ERR_ASC,
1634                               PCIE_UNSUPP_REQ_ASCQ, vb);
1635             return 0;
1636         }
1637         /* so given single LB full of zeros, can translate .... */
1638     }
1639     memset(iop, 0, sizeof(*iop));
1640     iop->opcode =  SG_NVME_NVM_WRITE_ZEROES;
1641     if (is_ws10) {
1642         iop->slba = sg_get_unaligned_be32(cdbp + 2);
1643         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
1644     } else {
1645         uint32_t num = sg_get_unaligned_be32(cdbp + 10);
1646 
1647         iop->slba = sg_get_unaligned_be64(cdbp + 2);
1648         if (num > (UINT16_MAX + 1)) {
1649             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
1650             return 0;
1651         } else
1652             nblks_t10 = num;
1653     }
1654     if (0 == nblks_t10) { /* NOP in SCSI */
1655         if (vb > 4)
1656             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
1657                   __func__);
1658         return 0;
1659     }
1660     iop->nblocks = nblks_t10 - 1;
1661     res = sntl_do_nvm_cmd(ptp, iop, 0, false, time_secs, vb);
1662     if (SG_LIB_NVME_STATUS == res) {
1663         mk_sense_from_nvme_status(ptp, vb);
1664         return 0;
1665     }
1666     return res;
1667 }
1668 
1669 static int
sntl_sync_cache(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1670 sntl_sync_cache(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1671                 int time_secs, int vb)
1672 {
1673     bool immed = !!(0x2 & cdbp[1]);
1674     struct sg_nvme_user_io io;
1675     struct sg_nvme_user_io * iop = &io;
1676     int res;
1677 
1678     if (vb > 5)
1679         pr2ws("%s: immed=%d, time_secs=%d\n", __func__, (int)immed,
1680               time_secs);
1681     memset(iop, 0, sizeof(*iop));
1682     iop->opcode =  SG_NVME_NVM_FLUSH;
1683     if (vb > 4)
1684         pr2ws("%s: immed bit, lba and num_lbs fields ignored\n", __func__);
1685     res = sntl_do_nvm_cmd(ptp, iop, 0, false, time_secs, vb);
1686     if (SG_LIB_NVME_STATUS == res) {
1687         mk_sense_from_nvme_status(ptp, vb);
1688         return 0;
1689     }
1690     return res;
1691 }
1692 
1693 static int
sntl_start_stop(struct sg_pt_linux_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1694 sntl_start_stop(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp,
1695                 int time_secs, int vb)
1696 {
1697     bool immed = !!(0x1 & cdbp[1]);
1698 
1699     if (vb > 5)
1700         pr2ws("%s: immed=%d, time_secs=%d, ignore\n", __func__, (int)immed,
1701               time_secs);
1702     if (ptp) { }        /* suppress warning */
1703     return 0;
1704 }
1705 
1706 /* Executes NVMe Admin command (or at least forwards it to lower layers).
1707  * Returns 0 for success, negative numbers are negated 'errno' values from
1708  * OS system calls. Positive return values are errors from this package.
1709  * When time_secs is 0 the Linux NVMe Admin command default of 60 seconds
1710  * is used. */
1711 int
sg_do_nvme_pt(struct sg_pt_base * vp,int fd,int time_secs,int vb)1712 sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb)
1713 {
1714     bool scsi_cdb;
1715     bool is_read = false;
1716     int n, len, hold_dev_fd;
1717     uint16_t sa;
1718     struct sg_pt_linux_scsi * ptp = &vp->impl;
1719     struct sg_nvme_passthru_cmd cmd;
1720     const uint8_t * cdbp;
1721     void * dp = NULL;
1722 
1723     if (! ptp->io_hdr.request) {
1724         if (vb)
1725             pr2ws("No NVMe command given (set_scsi_pt_cdb())\n");
1726         return SCSI_PT_DO_BAD_PARAMS;
1727     }
1728     hold_dev_fd = ptp->dev_fd;
1729     if (fd >= 0) {
1730         if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
1731             if (vb)
1732                 pr2ws("%s: file descriptor given to create() and here "
1733                       "differ\n", __func__);
1734             return SCSI_PT_DO_BAD_PARAMS;
1735         }
1736         ptp->dev_fd = fd;
1737     } else if (ptp->dev_fd < 0) {
1738         if (vb)
1739             pr2ws("%s: invalid file descriptors\n", __func__);
1740         return SCSI_PT_DO_BAD_PARAMS;
1741     }
1742     n = ptp->io_hdr.request_len;
1743     cdbp = (const uint8_t *)(sg_uintptr_t)ptp->io_hdr.request;
1744     if (vb > 4)
1745         pr2ws("%s: opcode=0x%x, fd=%d (dev_fd=%d), time_secs=%d\n", __func__,
1746               cdbp[0], fd, hold_dev_fd, time_secs);
1747     scsi_cdb = sg_is_scsi_cdb(cdbp, n);
1748     /* direct NVMe command (i.e. 64 bytes long) or SNTL */
1749     ptp->nvme_our_sntl = scsi_cdb;
1750     if (scsi_cdb) {
1751         switch (cdbp[0]) {
1752         case SCSI_INQUIRY_OPC:
1753             return sntl_inq(ptp, cdbp, time_secs, vb);
1754         case SCSI_REPORT_LUNS_OPC:
1755             return sntl_rluns(ptp, cdbp, time_secs, vb);
1756         case SCSI_TEST_UNIT_READY_OPC:
1757             return sntl_tur(ptp, time_secs, vb);
1758         case SCSI_REQUEST_SENSE_OPC:
1759             return sntl_req_sense(ptp, cdbp, time_secs, vb);
1760         case SCSI_READ10_OPC:
1761         case SCSI_READ16_OPC:
1762             return sntl_rread(ptp, cdbp, time_secs, vb);
1763         case SCSI_WRITE10_OPC:
1764         case SCSI_WRITE16_OPC:
1765             return sntl_write(ptp, cdbp, time_secs, vb);
1766         case SCSI_START_STOP_OPC:
1767             return sntl_start_stop(ptp, cdbp, time_secs, vb);
1768         case SCSI_SEND_DIAGNOSTIC_OPC:
1769             return sntl_senddiag(ptp, cdbp, time_secs, vb);
1770         case SCSI_RECEIVE_DIAGNOSTIC_OPC:
1771             return sntl_recvdiag(ptp, cdbp, time_secs, vb);
1772         case SCSI_MODE_SENSE10_OPC:
1773         case SCSI_MODE_SELECT10_OPC:
1774             return sntl_mode_ss(ptp, cdbp, time_secs, vb);
1775         case SCSI_READ_CAPACITY10_OPC:
1776             return sntl_readcap(ptp, cdbp, time_secs, vb);
1777         case SCSI_VERIFY10_OPC:
1778         case SCSI_VERIFY16_OPC:
1779             return sntl_verify(ptp, cdbp, time_secs, vb);
1780         case SCSI_WRITE_SAME10_OPC:
1781         case SCSI_WRITE_SAME16_OPC:
1782             return sntl_write_same(ptp, cdbp, time_secs, vb);
1783         case SCSI_SYNC_CACHE10_OPC:
1784         case SCSI_SYNC_CACHE16_OPC:
1785             return sntl_sync_cache(ptp, cdbp, time_secs, vb);
1786         case SCSI_SERVICE_ACT_IN_OPC:
1787             if (SCSI_READ_CAPACITY16_SA == (cdbp[1] & SCSI_SA_MSK))
1788                 return sntl_readcap(ptp, cdbp, time_secs, vb);
1789             goto fini;
1790         case SCSI_MAINT_IN_OPC:
1791             sa = SCSI_SA_MSK & cdbp[1];        /* service action */
1792             if (SCSI_REP_SUP_OPCS_OPC == sa)
1793                 return sntl_rep_opcodes(ptp, cdbp, time_secs, vb);
1794             else if (SCSI_REP_SUP_TMFS_OPC == sa)
1795                 return sntl_rep_tmfs(ptp, cdbp, time_secs, vb);
1796             /* fall through */
1797         default:
1798 fini:
1799             if (vb > 2) {
1800                 char b[64];
1801 
1802                 sg_get_command_name(cdbp, -1, sizeof(b), b);
1803                 pr2ws("%s: no translation to NVMe for SCSI %s command\n",
1804                       __func__, b);
1805             }
1806             mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE,
1807                               0, vb);
1808             return 0;
1809         }
1810     }
1811     len = (int)sizeof(cmd);
1812     n = (n < len) ? n : len;
1813     if (n < 64) {
1814         if (vb)
1815             pr2ws("%s: command length of %d bytes is too short\n", __func__,
1816                   n);
1817         return SCSI_PT_DO_BAD_PARAMS;
1818     }
1819     memcpy(&cmd, (const uint8_t *)(sg_uintptr_t)ptp->io_hdr.request, n);
1820     if (n < len)        /* zero out rest of 'cmd' */
1821         memset((uint8_t *)&cmd + n, 0, len - n);
1822     if (ptp->io_hdr.din_xfer_len > 0) {
1823         cmd.data_len = ptp->io_hdr.din_xfer_len;
1824         dp = (void *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
1825         cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.din_xferp;
1826         is_read = true;
1827     } else if (ptp->io_hdr.dout_xfer_len > 0) {
1828         cmd.data_len = ptp->io_hdr.dout_xfer_len;
1829         dp = (void *)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
1830         cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
1831         is_read = false;
1832     }
1833     return sg_nvme_admin_cmd(ptp, &cmd, dp, is_read, time_secs, vb);
1834 }
1835 
1836 #else           /* (HAVE_NVME && (! IGNORE_NVME)) [around line 140] */
1837 
1838 int
sg_do_nvme_pt(struct sg_pt_base * vp,int fd,int time_secs,int vb)1839 sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb)
1840 {
1841     if (vb) {
1842         pr2ws("%s: not supported, ", __func__);
1843 #ifdef HAVE_NVME
1844         pr2ws("HAVE_NVME, ");
1845 #else
1846         pr2ws("don't HAVE_NVME, ");
1847 #endif
1848 
1849 #ifdef IGNORE_NVME
1850         pr2ws("IGNORE_NVME");
1851 #else
1852         pr2ws("don't IGNORE_NVME");
1853 #endif
1854         pr2ws("\n");
1855      }
1856     if (vp) { ; }               /* suppress warning */
1857     if (fd) { ; }               /* suppress warning */
1858     if (time_secs) { ; }        /* suppress warning */
1859     return -ENOTTY;             /* inappropriate ioctl error */
1860 }
1861 
1862 #endif          /* (HAVE_NVME && (! IGNORE_NVME)) */
1863 
1864 #if (HAVE_NVME && (! IGNORE_NVME))
1865 
1866 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int vb)1867 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb)
1868 {
1869     bool is_read = false;
1870     int dlen;
1871     struct sg_pt_linux_scsi * ptp = &vp->impl;
1872     struct sg_nvme_passthru_cmd cmd;
1873     uint8_t * cmdp = (uint8_t *)&cmd;
1874     void * dp = NULL;
1875 
1876     if (vb && (submq != 0))
1877         pr2ws("%s: warning, uses submit queue 0\n", __func__);
1878     if (ptp->dev_fd < 0) {
1879         if (vb > 1)
1880             pr2ws("%s: no NVMe file descriptor given\n", __func__);
1881         return SCSI_PT_DO_BAD_PARAMS;
1882     }
1883     if (! ptp->is_nvme) {
1884         if (vb > 1)
1885             pr2ws("%s: file descriptor is not NVMe device\n", __func__);
1886         return SCSI_PT_DO_BAD_PARAMS;
1887     }
1888     if ((! ptp->io_hdr.request) || (64 != ptp->io_hdr.request_len)) {
1889         if (vb > 1)
1890             pr2ws("%s: no NVMe 64 byte command present\n", __func__);
1891         return SCSI_PT_DO_BAD_PARAMS;
1892     }
1893     if (sizeof(cmd) > 64)
1894         memset(cmdp + 64, 0, sizeof(cmd) - 64);
1895     memcpy(cmdp, (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request, 64);
1896     ptp->nvme_our_sntl = false;
1897 
1898     dlen = ptp->io_hdr.din_xfer_len;
1899     if (dlen > 0) {
1900         is_read = true;
1901         dp = (void *)(sg_uintptr_t)ptp->io_hdr.din_xferp;
1902     } else {
1903         dlen = ptp->io_hdr.dout_xfer_len;
1904         if (dlen > 0)
1905             dp = (void *)(sg_uintptr_t)ptp->io_hdr.dout_xferp;
1906     }
1907     return do_nvm_pt_low(ptp, &cmd, dp, dlen, is_read, timeout_secs, vb);
1908 }
1909 
1910 #else           /* (HAVE_NVME && (! IGNORE_NVME)) */
1911 
1912 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int vb)1913 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb)
1914 {
1915     if (vb) {
1916         pr2ws("%s: not supported, ", __func__);
1917 #ifdef HAVE_NVME
1918         pr2ws("HAVE_NVME, ");
1919 #else
1920         pr2ws("don't HAVE_NVME, ");
1921 #endif
1922 
1923 #ifdef IGNORE_NVME
1924         pr2ws("IGNORE_NVME");
1925 #else
1926         pr2ws("don't IGNORE_NVME");
1927 #endif
1928     }
1929     if (vp) { }
1930     if (submq) { }
1931     if (timeout_secs) { }
1932     return SCSI_PT_DO_NOT_SUPPORTED;
1933 }
1934 
1935 #endif          /* (HAVE_NVME && (! IGNORE_NVME)) */
1936