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