xref: /aosp_15_r20/external/sg3_utils/lib/sg_pt_freebsd.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /*
2  * Copyright (c) 2005-2022 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 
10 /* sg_pt_freebsd version 1.48 20220811 */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <dirent.h>
19 #include <limits.h>
20 #include <libgen.h>     /* for basename */
21 #include <fcntl.h>
22 #include <errno.h>
23 #define __STDC_FORMAT_MACROS 1
24 #include <inttypes.h>   /* from PRIx macros */
25 #include <err.h>
26 #include <camlib.h>
27 #include <cam/scsi/scsi_message.h>
28 // #include <sys/ata.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <glob.h>
33 #include <fcntl.h>
34 #include <stddef.h>
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include "sg_pt.h"
41 #include "sg_lib.h"
42 #include "sg_unaligned.h"
43 #include "sg_pt_nvme.h"
44 #include "sg_pr2serr.h"
45 
46 #if (HAVE_NVME && (! IGNORE_NVME))
47 #include "freebsd_nvme_ioctl.h"
48 #else
49 #define NVME_CTRLR_PREFIX   "/dev/nvme"
50 #define NVME_NS_PREFIX      "ns"
51 #endif
52 
53 #define SG_NVME_NVD_PREFIX  "/dev/nvd"  /* >= FreeBSD 9.2 */
54 #define SG_NVME_NDA_PREFIX  "/dev/nda"  /* >= FreeBSD 12.0, CAM compatible */
55 
56 #define FREEBSD_MAXDEV 64
57 #define FREEBSD_FDOFFSET 16;
58 
59 #if __FreeBSD_version > 500000
60 #define CAM_ERROR_PRINT(a, b, c, d, e) cam_error_print(a, b, c, d, e);
61 #else
62 #define CAM_ERROR_PRINT(a, b, c, d, e)
63 #endif
64 
65 
66 struct freebsd_dev_channel {    /* one instance per open file descriptor */
67     bool is_nvme_dev;   /* true if NVMe device attached, else SCSI */
68     bool is_cam_nvme;   /* NVMe via /dev/nda<n> or /dev/pass<n> devices */
69     bool is_pass;       /* CAM passthrough device (i.e. 'pass<n>') */
70     int unitnum;        /* the SCSI unit number, NVMe controller id? */
71     uint32_t nsid;
72     // uint32_t nv_ctrlid;      /* unitnum seems to have this role */
73     int nvme_fd_ns;     // for non-CAM NVMe, use -1 to indicate not provided
74     int nvme_fd_ctrl;   // open("/dev/nvme<n>") if needed */
75     char* devname;      // from cam_get_device() or ioctl(NVME_GET_NSID)
76     struct cam_device* cam_dev;
77     uint8_t * nvme_id_ctlp;
78     uint8_t * free_nvme_id_ctlp;
79     struct sg_sntl_dev_state_t dev_stat;    // owner
80 };
81 
82 // Private table of open devices: guaranteed zero on startup since
83 // part of static data.
84 static struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV];
85 
86 #define DEF_TIMEOUT 60000       /* 60,000 milliseconds (60 seconds) */
87 
88 struct sg_pt_freebsd_scsi { /* context of one SCSI/NVME command (pt object) */
89     union ccb *ccb;
90     uint8_t * cdb;
91     int cdb_len;
92     uint8_t * sense;
93     int sense_len;
94     uint8_t * dxferp;
95     int dxfer_len;
96     int dxfer_dir;      /* CAM_DIR_NONE, _IN, _OUT and _BOTH */
97     uint8_t * dxferip;
98     uint8_t * dxferop;
99     uint8_t * mdxferp;
100     uint32_t dxfer_ilen;
101     uint32_t dxfer_olen;
102     uint32_t mdxfer_len;
103     uint32_t nvme_result;         // cdw0 from completion
104     uint16_t nvme_status;         // from completion: ((sct << 8) | sc)
105     uint8_t cq_dw0_3[16];
106     int timeout_ms;
107     int scsi_status;
108     int resid;
109     int sense_resid;
110     int in_err;
111     int os_err;
112     int transport_err;
113     int dev_han;                // should be >= FREEBSD_FDOFFSET then
114                                 // (dev_han - FREEBSD_FDOFFSET) is the
115                                 // index into devicetable[]
116     bool mdxfer_out;
117     bool is_nvme_dev;   /* copied from owning mchanp */
118     bool nvme_our_sntl; /* true: our SNTL; false: received NVMe command */
119     struct freebsd_dev_channel * mchanp;    /* associated device info */
120 };
121 
122 struct sg_pt_base {
123     struct sg_pt_freebsd_scsi impl;
124 };
125 
126 // static const uint32_t broadcast_nsid = SG_NVME_BROADCAST_NSID;
127 
128 #if (HAVE_NVME && (! IGNORE_NVME))
129 static int sg_do_nvme_pt(struct sg_pt_freebsd_scsi * ptp, int fd,
130                          bool is_admin, int timeout_secs, int vb);
131 #endif
132 
133 
134 
135 static struct freebsd_dev_channel *
get_fdc_p(struct sg_pt_freebsd_scsi * ptp)136 get_fdc_p(struct sg_pt_freebsd_scsi * ptp)
137 {
138     int han = ptp->dev_han - FREEBSD_FDOFFSET;
139 
140     if ((han < 0) || (han >= FREEBSD_MAXDEV))
141         return NULL;
142     return devicetable[han];
143 }
144 
145 static const struct freebsd_dev_channel *
get_fdc_cp(const struct sg_pt_freebsd_scsi * ptp)146 get_fdc_cp(const struct sg_pt_freebsd_scsi * ptp)
147 {
148     int han = ptp->dev_han - FREEBSD_FDOFFSET;
149 
150     if ((han < 0) || (han >= FREEBSD_MAXDEV))
151         return NULL;
152     return devicetable[han];
153 }
154 
155 #if __FreeBSD_version >= 1100000
156 /* This works with /dev/nvme*, /dev/nvd* and /dev/nda* but not /dev/pass* */
157 static int
nvme_get_nsid(int fd,uint32_t * nsid,char * b,int blen,int vb)158 nvme_get_nsid(int fd, uint32_t *nsid, char *b, int blen, int vb)
159 {
160     struct nvme_get_nsid gnsid;
161     int n_cdev = sizeof(gnsid.cdev);
162 
163     if (ioctl(fd, NVME_GET_NSID, &gnsid) < 0) {
164         int err = errno;
165 
166         if (vb > 2)
167             pr2ws("%s: ioctl(NVME_GET_NSID) failed, errno=%d\n", __func__,
168                   err);
169         return -err;
170     }
171     if (n_cdev < blen) {
172         strncpy(b, gnsid.cdev, n_cdev);
173         b[n_cdev] = '\0';
174     } else {
175         strncpy(b, gnsid.cdev, blen);
176         b[blen - 1] = '\0';
177     }
178     if (nsid != NULL)
179         *nsid = gnsid.nsid;
180     return 0;
181 }
182 #endif
183 
184 /* Returns >= 0 if successful. If error in Unix returns negated errno. */
185 int
scsi_pt_open_device(const char * device_name,bool read_only,int vb)186 scsi_pt_open_device(const char * device_name, bool read_only, int vb)
187 {
188     int oflags = 0 /* O_NONBLOCK*/ ;
189 
190     oflags |= (read_only ? O_RDONLY : O_RDWR);
191     return scsi_pt_open_flags(device_name, oflags, vb);
192 }
193 
194 #if __FreeBSD_version >= 1100000
195 /* Get a get device CCB for the specified device, borrowed from camdd.c */
196 int
sg_cam_get_cgd(struct cam_device * device,struct ccb_getdev * cgd,int vb)197 sg_cam_get_cgd(struct cam_device *device, struct ccb_getdev *cgd, int vb)
198 {
199     union ccb *ccb;
200     FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr;
201     int retval = 0;
202 
203     ccb = cam_getccb(device);
204     if (ccb == NULL) {
205         if (vb)
206             pr2ws("%s: couldn't allocate CCB\n", __func__);
207         return -ENOMEM;
208     }
209     CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cgd);
210     ccb->ccb_h.func_code = XPT_GDEV_TYPE;
211 
212     if (cam_send_ccb(device, ccb) < 0) {
213         if (vb > 1) {
214             pr2ws("%s: error sending Get Device Information CCB\n", __func__);
215             CAM_ERROR_PRINT(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp);
216         }
217         retval = -ENODEV;
218         goto bailout;
219     }
220     if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
221         if (vb > 1)
222             CAM_ERROR_PRINT(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp);
223         retval = -ENODEV;
224         goto bailout;
225     }
226     bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
227 bailout:
228     cam_freeccb(ccb);
229     return retval;
230 }
231 #endif
232 
233 /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed
234  * together. The 'oflags' is only used on NVMe devices. It is ignored on
235  * SCSI and ATA devices in FreeBSD.
236  * Returns >= 0 if successful, otherwise returns negated errno. */
237 int
scsi_pt_open_flags(const char * device_name,int oflags,int vb)238 scsi_pt_open_flags(const char * device_name, int oflags, int vb)
239 {
240     bool maybe_non_cam_nvme = false;
241     bool basnam0_n = false;
242     char first_ch;
243     int k, err, dev_fd, ret, handle_idx;
244     ssize_t s;
245     struct freebsd_dev_channel *fdc_p = NULL;
246     struct cam_device* cam_dev;
247     struct stat a_stat;
248     char dev_nm[PATH_MAX];
249 
250     if (vb > 6)
251         pr2ws("%s: device_name=%s, oflags=0x%x\n", __func__, device_name,
252               oflags);
253     // Search table for a free entry
254     for (k = 0; k < FREEBSD_MAXDEV; k++)
255         if (! devicetable[k])
256             break;
257 
258     // If no free entry found, return error.  We have max allowed number
259     // of "file descriptors" already allocated.
260     if (k == FREEBSD_MAXDEV) {
261         if (vb)
262             pr2ws("too many open file descriptors (%d)\n", FREEBSD_MAXDEV);
263         ret = -EMFILE;
264         goto err_out;
265     }
266     handle_idx = k;
267     fdc_p = (struct freebsd_dev_channel *)
268                 calloc(1,sizeof(struct freebsd_dev_channel));
269     if (fdc_p == NULL) {
270         // errno already set by call to calloc()
271         ret = -ENOMEM;
272         goto err_out;
273     }
274     fdc_p->nvme_fd_ns = -1;
275     fdc_p->nvme_fd_ctrl = -1;
276     if (! (fdc_p->devname = (char *)calloc(1, DEV_IDLEN+1))) {
277          ret = -ENOMEM;
278          goto err_out;
279     }
280     /* Don't know yet whether device_name is a SCSI, NVME(non-CAM) or
281      * NVME(CAM) device. Start by assuming it is CAM. */
282     if (cam_get_device(device_name, fdc_p->devname, DEV_IDLEN,
283                        &(fdc_p->unitnum)) == -1) {
284         if (vb > 3)
285             pr2ws("%s: cam_get_device(%s) fails, should work for SCSI and "
286                   "NVMe devices\n", __func__, device_name, errno);
287         ret = -EINVAL;
288         goto err_out;
289     } else if (vb > 6)
290         pr2ws("%s: cam_get_device() works, devname=%s unit=%u\n", __func__,
291              fdc_p->devname, fdc_p->unitnum);
292 
293     if (! (cam_dev = cam_open_spec_device(fdc_p->devname,
294                                           fdc_p->unitnum, O_RDWR, NULL))) {
295         if (vb > 6) {
296             pr2ws("cam_open_spec_device: %s\n", cam_errbuf);
297             pr2ws("%s: so not CAM, but still maybe NVME\n", __func__);
298         }
299         maybe_non_cam_nvme = true;
300     } else {    /* found CAM, could be SCSI or NVME(CAM) [nda driver] */
301 #if __FreeBSD_version >= 1100000
302         struct ccb_getdev cgd;
303 
304         fdc_p->cam_dev = cam_dev;
305         ret = sg_cam_get_cgd(cam_dev, &cgd, vb);
306         if (ret)
307             goto err_out;
308         switch (cgd.protocol) {
309         case PROTO_SCSI:
310             fdc_p->is_nvme_dev = false;
311             break;
312         case PROTO_NVME:
313             fdc_p->is_nvme_dev = true;
314             fdc_p->is_cam_nvme = true;
315             fdc_p->nsid = cam_dev->target_lun & UINT32_MAX;
316             break;
317         case PROTO_ATA:
318         case PROTO_ATAPI:
319         case PROTO_SATAPM:
320         case PROTO_SEMB:  /* SATA Enclosure Management bridge */
321             if (vb) {
322                 pr2ws("%s: ATA and derivative devices not supported\n",
323                       __func__);
324                 if (vb > 2)
325                     pr2ws("  ... FreeBSD doesn't have a SAT in its kernel\n");
326             }
327             ret = -EINVAL;
328             break;
329 #if __FreeBSD_version > 1200058
330         case PROTO_MMCSD:
331             if (vb)
332                 pr2ws("%s: MMC and SD devices not supported\n",
333                       __func__);
334             ret = -EINVAL;
335             break;
336 #endif
337         default:
338             if (vb)
339                 pr2ws("%s: unexpected device protocol\n", __func__);
340             ret = -EINVAL;
341             break;
342         }
343         if (ret)
344             goto err_out;
345         if (0 == memcpy(fdc_p->devname, "pass", 4))
346             fdc_p->is_pass = true;
347 #else
348         ret = 0;
349         fdc_p->is_nvme_dev = false;
350 #endif
351     }
352     if (maybe_non_cam_nvme) {
353         first_ch = device_name[0];
354         if (('/' != first_ch) && ('.' != first_ch)) {
355             char b[PATH_MAX];
356 
357             /* Step 1: if device_name is symlink, follow it */
358             s = readlink(device_name,  b, sizeof(b));
359             if (s <= 0) {
360                 strncpy(b, device_name, PATH_MAX - 1);
361                 b[PATH_MAX - 1] = '\0';
362             }
363             /* Step 2: if no leading '/' nor '.' given, prepend '/dev/' */
364             first_ch = b[0];
365             basnam0_n = ('n' == first_ch);
366             if (('/' != first_ch) && ('.' != first_ch))
367                 snprintf(dev_nm, PATH_MAX, "%s%s", "/dev/", b);
368             else
369                 strcpy(dev_nm, b);
370         } else {
371             const char * cp;
372 
373             strcpy(dev_nm, device_name);
374             cp = basename(dev_nm);
375             basnam0_n = ('n' == *cp);
376             strcpy(dev_nm, device_name);
377         }
378         if (stat(dev_nm, &a_stat) < 0) {
379             err = errno;
380             if (vb)
381                 pr2ws("%s: unable to stat(%s): %s; basnam0_n=%d\n",
382                       __func__, dev_nm, strerror(err), basnam0_n);
383             ret = -err;
384             goto err_out;
385         }
386         if (! (S_ISCHR(a_stat.st_mode))) {
387             if (vb > 1)
388                 pr2ws("%s: %s is not a char device ??\n", __func__, dev_nm);
389             ret = -ENODEV;
390             goto err_out;
391         }
392         dev_fd = open(dev_nm, oflags);
393         if (dev_fd < 0) {
394             err = errno;
395             if (vb > 1)
396                 pr2ws("%s: open(%s) failed: %s (errno=%d), try SCSI/ATA\n",
397                       __func__, dev_nm, strerror(err), err);
398             ret = -err;
399             goto err_out;
400         }
401 #if __FreeBSD_version >= 1100000
402         ret = nvme_get_nsid(dev_fd, &fdc_p->nsid, fdc_p->devname, DEV_IDLEN,
403                             vb);
404         if (ret)
405             goto err_out;
406 #else
407         {
408             unsigned int u;
409 
410             /* only support /dev/nvme<n> and /dev/nvme<n>ns<m> */
411             k = sscanf(dev_nm, "nvme%uns%u", &u, &fdc_p->nsid);
412             if (2 == k) {
413                 char * cp = strchr(dev_nm, 's');
414 
415                 *(cp - 2) = '\0';
416                 strcpy(fdc_p->devname, dev_nm);
417             } else if (1 == k) {
418                 strncpy(fdc_p->devname, dev_nm, DEV_IDLEN);
419                 fdc_p->nsid = 0;
420             } else if (vb > 1) {
421                 pr2ws("%s: only support '[/dev/]nvme<n>[ns<m>]'\n", __func__);
422                 goto err_out;
423             }
424         }
425 #endif
426         if (vb > 6)
427             pr2ws("%s: nvme_dev_nm: %s, nsid=%u\n", __func__, fdc_p->devname,
428                   fdc_p->nsid);
429         fdc_p->is_nvme_dev = true;
430         fdc_p->is_cam_nvme = false;
431         if (fdc_p->nsid > 0)
432             fdc_p->nvme_fd_ns = dev_fd;
433         else
434             fdc_p->nvme_fd_ctrl = dev_fd;
435     }
436     // return pointer to "file descriptor" table entry, properly offset.
437     devicetable[handle_idx] = fdc_p;
438     return handle_idx + FREEBSD_FDOFFSET;
439 
440 err_out:                /* ret should be negative value (negated errno) */
441     if (fdc_p) {
442         if (fdc_p->devname)
443             free(fdc_p->devname);
444         if (fdc_p->nvme_fd_ns >= 0)
445             close(fdc_p->nvme_fd_ns);
446         if (fdc_p->nvme_fd_ctrl >= 0)
447             close(fdc_p->nvme_fd_ctrl);
448         free(fdc_p);
449         fdc_p = NULL;
450     }
451     return ret;
452 }
453 
454 /* Returns 0 if successful. If error in Unix returns negated errno. */
455 int
scsi_pt_close_device(int device_han)456 scsi_pt_close_device(int device_han)
457 {
458     struct freebsd_dev_channel *fdc_p;
459     int han = device_han - FREEBSD_FDOFFSET;
460 
461     if ((han < 0) || (han >= FREEBSD_MAXDEV)) {
462         errno = ENODEV;
463         return -errno;
464     }
465     fdc_p = devicetable[han];
466     if (NULL == fdc_p) {
467         errno = ENODEV;
468         return -errno;
469     }
470     if (fdc_p->devname)
471         free(fdc_p->devname);
472     if (fdc_p->cam_dev)         /* N.B. can be cam_nvme devices */
473         cam_close_device(fdc_p->cam_dev);
474     else if (fdc_p->is_nvme_dev) {
475         if (fdc_p->nvme_fd_ns >= 0)
476             close(fdc_p->nvme_fd_ns);
477         if (fdc_p->nvme_fd_ctrl >= 0)
478             close(fdc_p->nvme_fd_ctrl);
479         if (fdc_p->free_nvme_id_ctlp) {
480             free(fdc_p->free_nvme_id_ctlp);
481             fdc_p->nvme_id_ctlp = NULL;
482             fdc_p->free_nvme_id_ctlp = NULL;
483         }
484     }
485     free(fdc_p);
486     devicetable[han] = NULL;
487     errno = 0;
488     return 0;
489 }
490 
491 /* Assumes device_han is an "open" file handle associated with some device.
492  * Returns 1 if SCSI generic pass-though device [SCSI CAM primary: nda0],
493  * returns 2 if secondary * SCSI pass-through device [SCSI CAM: pass<n>];
494  * returns 3 if non-CAM NVMe with no nsid [nvme0]; returns 4 if non-CAM
495  * NVMe device with nsid (> 0) [nvme0ns1, nvd0]; returns 5 if CAM NVMe
496  * (with or without nsid) [nda0]; or returns 0 if something else (e.g. ATA
497  * block device) or device_han < 0.
498  * If error, returns negated errno (operating system) value. */
499 int
check_pt_file_handle(int device_han,const char * device_name,int vb)500 check_pt_file_handle(int device_han, const char * device_name, int vb)
501 {
502     struct freebsd_dev_channel *fdc_p;
503     int han = device_han - FREEBSD_FDOFFSET;
504 
505     if (vb > 6)
506         pr2ws("%s: device_handle=%d, device_name: %s\n", __func__,
507               device_han, device_name);
508     if ((han < 0) || (han >= FREEBSD_MAXDEV))
509         return -ENODEV;
510     fdc_p = devicetable[han];
511     if (NULL == fdc_p)
512         return -ENODEV;
513     if (fdc_p->is_nvme_dev) {
514         if (fdc_p->is_cam_nvme)
515             return 5;
516         else if (fdc_p->nsid == 0)
517             return 3;
518         else
519             return 4;       /* Something like nvme0ns1 or nvd0 */
520     } else if (fdc_p->cam_dev)
521         return fdc_p->is_pass ? 2 : 1;
522     else {
523         if (vb > 1)
524             pr2ws("%s: neither SCSI nor NVMe ... hmm, device name: %s\n",
525                   __func__, device_name);
526         return 0;
527     }
528 }
529 
530 #if (HAVE_NVME && (! IGNORE_NVME))
531 static bool checked_ev_dsense = false;
532 static bool ev_dsense = false;
533 #endif
534 
535 struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int dev_han,int vb)536 construct_scsi_pt_obj_with_fd(int dev_han, int vb)
537 {
538     struct sg_pt_freebsd_scsi * ptp;
539 
540     ptp = (struct sg_pt_freebsd_scsi *)
541                 calloc(1, sizeof(struct sg_pt_freebsd_scsi));
542     if (ptp) {
543         ptp->dxfer_dir = CAM_DIR_NONE;
544         ptp->dev_han = (dev_han < 0) ? -1 : dev_han;
545         if (ptp->dev_han >= 0) {
546             struct freebsd_dev_channel *fdc_p;
547 
548             fdc_p = get_fdc_p(ptp);
549             if (fdc_p) {
550                 ptp->mchanp = fdc_p;
551 #if (HAVE_NVME && (! IGNORE_NVME))
552                 sntl_init_dev_stat(&fdc_p->dev_stat);
553                 if (! checked_ev_dsense) {
554                     ev_dsense = sg_get_initial_dsense();
555                     checked_ev_dsense = true;
556                 }
557                 fdc_p->dev_stat.scsi_dsense = ev_dsense;
558 #endif
559             } else if (vb)
560                 pr2ws("%s: bad dev_han=%d\n", __func__, dev_han);
561         }
562     } else if (vb)
563         pr2ws("%s: calloc() out of memory\n", __func__);
564     return (struct sg_pt_base *)ptp;
565 }
566 
567 
568 struct sg_pt_base *
construct_scsi_pt_obj()569 construct_scsi_pt_obj()
570 {
571     return construct_scsi_pt_obj_with_fd(-1, 0);
572 }
573 
574 void
destruct_scsi_pt_obj(struct sg_pt_base * vp)575 destruct_scsi_pt_obj(struct sg_pt_base * vp)
576 {
577     struct sg_pt_freebsd_scsi * ptp;
578 
579     if (NULL == vp) {
580         pr2ws(">>>> %s: given NULL pointer\n", __func__);
581         return;
582     }
583     if ((ptp = &vp->impl)) {
584         if (ptp->ccb)
585             cam_freeccb(ptp->ccb);
586         free(vp);
587     }
588 }
589 
590 void
clear_scsi_pt_obj(struct sg_pt_base * vp)591 clear_scsi_pt_obj(struct sg_pt_base * vp)
592 {
593     struct sg_pt_freebsd_scsi * ptp;
594 
595     if (NULL == vp) {
596         pr2ws(">>>>> %s: NULL pointer given\n", __func__);
597         return;
598     }
599     if ((ptp = &vp->impl)) {
600         int dev_han = ptp->dev_han;
601         struct freebsd_dev_channel *fdc_p = ptp->mchanp;
602 
603         if (ptp->ccb)
604             cam_freeccb(ptp->ccb);
605         memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi));
606         ptp->dxfer_dir = CAM_DIR_NONE;
607         ptp->dev_han = dev_han;
608         ptp->mchanp = fdc_p;
609     }
610 }
611 
612 void
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)613 partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
614 {
615     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
616 
617     if (NULL == ptp)
618         return;
619     ptp->in_err = 0;
620     ptp->os_err = 0;
621     ptp->transport_err = 0;
622     ptp->scsi_status = 0;
623     ptp->dxfer_dir = CAM_DIR_NONE;
624     ptp->dxferip = NULL;
625     ptp->dxfer_ilen = 0;
626     ptp->dxferop = NULL;
627     ptp->dxfer_olen = 0;
628     ptp->nvme_result = 0;
629 }
630 
631 /* Forget any previous dev_han and install the one given. May attempt to
632  * find file type (e.g. if pass-though) from OS so there could be an error.
633  * Returns 0 for success or the same value as get_scsi_pt_os_err()
634  * will return. dev_han should be >= 0 for a valid file handle or -1 . */
635 int
set_pt_file_handle(struct sg_pt_base * vp,int dev_han,int vb)636 set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb)
637 {
638     struct sg_pt_freebsd_scsi * ptp;
639 
640     if (NULL == vp) {
641         if (vb)
642             pr2ws(">>>> %s: pointer to object is NULL\n", __func__);
643         return EINVAL;
644     }
645     if ((ptp = &vp->impl)) {
646         struct freebsd_dev_channel *fdc_p;
647 
648         if (dev_han < 0) {
649             ptp->dev_han = -1;
650             ptp->dxfer_dir = CAM_DIR_NONE;
651             return 0;
652         }
653         fdc_p = get_fdc_p(ptp);
654         if (NULL == fdc_p) {
655             if (vb)
656                 pr2ws("%s: dev_han (%d) is invalid\n", __func__, dev_han);
657             ptp->os_err = EINVAL;
658             return ptp->os_err;
659         }
660         ptp->os_err = 0;
661         ptp->transport_err = 0;
662         ptp->in_err = 0;
663         ptp->scsi_status = 0;
664         ptp->dev_han = dev_han;
665         ptp->dxfer_dir = CAM_DIR_NONE;
666         ptp->mchanp = fdc_p;
667     }
668     return 0;
669 }
670 
671 /* Valid file handles (which is the return value) are >= 0 . Returns -1
672  * if there is no valid file handle. */
673 int
get_pt_file_handle(const struct sg_pt_base * vp)674 get_pt_file_handle(const struct sg_pt_base * vp)
675 {
676     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
677 
678     return ptp ? ptp->dev_han : -1;
679 }
680 
681 void
set_scsi_pt_cdb(struct sg_pt_base * vp,const uint8_t * cdb,int cdb_len)682 set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len)
683 {
684     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
685 
686     ptp->cdb = (uint8_t *)cdb;
687     ptp->cdb_len = cdb_len;
688 }
689 
690 int
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)691 get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
692 {
693     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
694 
695     return ptp->cdb_len;
696 }
697 
698 uint8_t *
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)699 get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
700 {
701     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
702 
703     return ptp->cdb;
704 }
705 
706 void
set_scsi_pt_sense(struct sg_pt_base * vp,uint8_t * sense,int max_sense_len)707 set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense,
708                   int max_sense_len)
709 {
710     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
711 
712     if (sense) {
713         if (max_sense_len > 0)
714             memset(sense, 0, max_sense_len);
715     }
716     ptp->sense = sense;
717     ptp->sense_len = max_sense_len;
718 }
719 
720 /* Setup for data transfer from device */
721 void
set_scsi_pt_data_in(struct sg_pt_base * vp,uint8_t * dxferp,int dxfer_len)722 set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp,
723                     int dxfer_len)
724 {
725     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
726 
727     if (ptp->dxferip)
728         ++ptp->in_err;
729     ptp->dxferip = dxferp;
730     ptp->dxfer_ilen = dxfer_len;
731     if (dxfer_len > 0) {
732         ptp->dxferp = dxferp;
733         ptp->dxfer_len = dxfer_len;
734         if (ptp->dxfer_dir == CAM_DIR_OUT)
735             ptp->dxfer_dir = CAM_DIR_BOTH;
736         else
737             ptp->dxfer_dir = CAM_DIR_IN;
738     }
739 }
740 
741 /* Setup for data transfer toward device */
742 void
set_scsi_pt_data_out(struct sg_pt_base * vp,const uint8_t * dxferp,int dxfer_len)743 set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp,
744                      int dxfer_len)
745 {
746     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
747 
748     if (ptp->dxferop)
749         ++ptp->in_err;
750     ptp->dxferop = (uint8_t *)dxferp;
751     ptp->dxfer_olen = dxfer_len;
752     if (dxfer_len > 0) {
753         ptp->dxferp = (uint8_t *)dxferp;
754         ptp->dxfer_len = dxfer_len;
755         if (ptp->dxfer_dir == CAM_DIR_IN)
756             ptp->dxfer_dir = CAM_DIR_BOTH;
757         else
758             ptp->dxfer_dir = CAM_DIR_OUT;
759     }
760 }
761 
762 void
set_pt_metadata_xfer(struct sg_pt_base * vp,uint8_t * mdxferp,uint32_t mdxfer_len,bool out_true)763 set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp,
764                      uint32_t mdxfer_len, bool out_true)
765 {
766     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
767 
768     if (ptp->mdxferp)
769         ++ptp->in_err;
770     ptp->mdxferp = mdxferp;
771     ptp->mdxfer_len = mdxfer_len;
772     if (mdxfer_len > 0)
773         ptp->mdxfer_out = out_true;
774 }
775 
776 void
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)777 set_scsi_pt_packet_id(struct sg_pt_base * vp __attribute__ ((unused)),
778                       int pack_id __attribute__ ((unused)))
779 {
780 }
781 
782 void
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)783 set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag __attribute__ ((unused)))
784 {
785     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
786 
787     ++ptp->in_err;
788 }
789 
790 void
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)791 set_scsi_pt_task_management(struct sg_pt_base * vp,
792                             int tmf_code __attribute__ ((unused)))
793 {
794     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
795 
796     ++ptp->in_err;
797 }
798 
799 void
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attrib,int priority)800 set_scsi_pt_task_attr(struct sg_pt_base * vp,
801                       int attrib __attribute__ ((unused)),
802                       int priority __attribute__ ((unused)))
803 {
804     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
805 
806     ++ptp->in_err;
807 }
808 
809 void
set_scsi_pt_flags(struct sg_pt_base * objp,int flags)810 set_scsi_pt_flags(struct sg_pt_base * objp, int flags)
811 {
812     if (objp) { ; }      /* unused, suppress warning */
813     if (flags) { ; }     /* unused, suppress warning */
814 }
815 
816 /* Executes SCSI command (or at least forwards it to lower layers).
817  * Clears os_err field prior to active call (whose result may set it
818  * again). */
819 int
do_scsi_pt(struct sg_pt_base * vp,int dev_han,int time_secs,int vb)820 do_scsi_pt(struct sg_pt_base * vp, int dev_han, int time_secs, int vb)
821 {
822     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
823     struct freebsd_dev_channel *fdc_p;
824     FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr;
825     union ccb *ccb;
826 
827     if (vb > 6)
828         pr2ws("%s: dev_han=%d, time_secs=%d\n", __func__, dev_han, time_secs);
829     ptp->os_err = 0;
830     if (ptp->in_err) {
831         if (vb)
832             pr2ws("Replicated or unused set_scsi_pt...\n");
833         return SCSI_PT_DO_BAD_PARAMS;
834     }
835     if (dev_han < 0) {
836         if (ptp->dev_han < 0) {
837             if (vb)
838                 pr2ws("%s: No device file handle given\n", __func__);
839             return SCSI_PT_DO_BAD_PARAMS;
840         }
841         dev_han = ptp->dev_han;
842     } else {
843         if (ptp->dev_han >= 0) {
844             if (dev_han != ptp->dev_han) {
845                 if (vb)
846                     pr2ws("%s: file handle given to create and this "
847                           "differ\n", __func__);
848                 return SCSI_PT_DO_BAD_PARAMS;
849             }
850         } else
851             ptp->dev_han = dev_han;
852     }
853 
854     if (NULL == ptp->cdb) {
855         if (vb)
856             pr2ws("No command (cdb) given\n");
857         return SCSI_PT_DO_BAD_PARAMS;
858     }
859 
860     fdc_p = ptp->mchanp;
861     if (NULL == fdc_p) {
862         fdc_p = get_fdc_p(ptp);
863         if (NULL == fdc_p) {
864             if (vb)
865                 pr2ws("File descriptor bad or closed??\n");
866             ptp->os_err = ENODEV;
867             return -ptp->os_err;
868         }
869         ptp->mchanp = fdc_p;
870     }
871 #if (HAVE_NVME && (! IGNORE_NVME))
872     if (fdc_p->is_nvme_dev)
873         return sg_do_nvme_pt(ptp, -1, true /* assume Admin */, time_secs, vb);
874 #endif
875 
876     /* SCSI CAM pass-through follows */
877     ptp->is_nvme_dev = fdc_p->is_nvme_dev;
878     if (NULL == fdc_p->cam_dev) {
879         if (vb)
880             pr2ws("No open CAM device\n");
881         return SCSI_PT_DO_BAD_PARAMS;
882     }
883 
884     if (NULL == ptp->ccb) {     /* re-use if we have one already */
885         if (! (ccb = cam_getccb(fdc_p->cam_dev))) {
886             if (vb)
887                 pr2ws("cam_getccb: failed\n");
888             ptp->os_err = ENOMEM;
889             return -ptp->os_err;
890         }
891         ptp->ccb = ccb;
892     } else
893         ccb = ptp->ccb;
894 
895     // clear out structure, except for header that was filled in for us
896     bzero(&(&ccb->ccb_h)[1],
897             sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
898 
899     ptp->timeout_ms = (time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT;
900     cam_fill_csio(&ccb->csio,
901                   /* retries */ 1,
902                   /* cbfcnp */ NULL,
903                   /* flags */ ptp->dxfer_dir,
904                   /* tagaction */ MSG_SIMPLE_Q_TAG,
905                   /* dataptr */ ptp->dxferp,
906                   /* datalen */ ptp->dxfer_len,
907                   /* senselen */ ptp->sense_len,
908                   /* cdblen */ ptp->cdb_len,
909                   /* timeout (millisecs) */ ptp->timeout_ms);
910     memcpy(ccb->csio.cdb_io.cdb_bytes, ptp->cdb, ptp->cdb_len);
911 
912     if (cam_send_ccb(fdc_p->cam_dev, ccb) < 0) {
913         if (vb) {
914             pr2serr("%s: cam_send_ccb() error\n", __func__);
915             CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL,
916                             CAM_EPF_ALL, ferrp);
917         }
918         cam_freeccb(ptp->ccb);
919         ptp->ccb = NULL;
920         ptp->os_err = EIO;
921         return -ptp->os_err;
922     }
923 
924     if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) ||
925         ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)) {
926         ptp->scsi_status = ccb->csio.scsi_status;
927         ptp->resid = ccb->csio.resid;
928         ptp->sense_resid = ccb->csio.sense_resid;
929 
930         if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) ||
931             (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status)) {
932             int len;
933 
934             if (ptp->sense_resid > ptp->sense_len)
935                 len = ptp->sense_len;   /* crazy; ignore sense_resid */
936             else
937                 len = ptp->sense_len - ptp->sense_resid;
938             if (len > 0)
939                 memcpy(ptp->sense, &(ccb->csio.sense_data), len);
940         }
941     } else
942         ptp->transport_err = 1;
943 
944     return 0;
945 }
946 
947 int
get_scsi_pt_result_category(const struct sg_pt_base * vp)948 get_scsi_pt_result_category(const struct sg_pt_base * vp)
949 {
950     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
951 
952     if (ptp->os_err)
953         return SCSI_PT_RESULT_OS_ERR;
954     else if (ptp->transport_err)
955         return SCSI_PT_RESULT_TRANSPORT_ERR;
956     else if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) ||
957              (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status))
958         return SCSI_PT_RESULT_SENSE;
959     else if (ptp->scsi_status)
960         return SCSI_PT_RESULT_STATUS;
961     else
962         return SCSI_PT_RESULT_GOOD;
963 }
964 
965 int
get_scsi_pt_resid(const struct sg_pt_base * vp)966 get_scsi_pt_resid(const struct sg_pt_base * vp)
967 {
968     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
969 
970     if ((NULL == ptp) || (NULL == ptp->mchanp))
971         return 0;
972     return ((ptp->is_nvme_dev && ! ptp->nvme_our_sntl)) ?  0 : ptp->resid;
973 }
974 
975 void
get_pt_req_lengths(const struct sg_pt_base * vp,int * req_dinp,int * req_doutp)976 get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
977                    int * req_doutp)
978 {
979     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
980     bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH);
981 
982     if (req_dinp) {
983         if (ptp->dxfer_ilen > 0)
984             *req_dinp = ptp->dxfer_ilen;
985         else
986             *req_dinp = 0;
987     }
988     if (req_doutp) {
989         if ((!bidi) && (ptp->dxfer_olen > 0))
990             *req_doutp = ptp->dxfer_olen;
991         else
992             *req_doutp = 0;
993     }
994 }
995 
996 void
get_pt_actual_lengths(const struct sg_pt_base * vp,int * act_dinp,int * act_doutp)997 get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
998                       int * act_doutp)
999 {
1000     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1001     bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH);
1002 
1003     if (act_dinp) {
1004         if (ptp->dxfer_ilen > 0)
1005             *act_dinp = ptp->dxfer_ilen - ptp->resid;
1006         else
1007             *act_dinp = 0;
1008     }
1009     if (act_doutp) {
1010         if ((!bidi) && (ptp->dxfer_olen > 0))
1011             *act_doutp = ptp->dxfer_olen - ptp->resid;
1012         else
1013             *act_doutp = 0;
1014     }
1015 }
1016 
1017 /* Returns SCSI status value (from device that received the command). If an
1018  * NVMe command was issued directly (i.e. through do_scsi_pt() then return
1019  * NVMe status (i.e. ((SCT << 8) | SC)). If problem returns -1. */
1020 int
get_scsi_pt_status_response(const struct sg_pt_base * vp)1021 get_scsi_pt_status_response(const struct sg_pt_base * vp)
1022 {
1023     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1024 
1025     if (ptp) {
1026         const struct freebsd_dev_channel * fdc_p = ptp->mchanp;
1027 
1028         if (NULL == fdc_p)
1029             return -1;
1030         if (ptp->is_nvme_dev && ! ptp->nvme_our_sntl)
1031             return (int)ptp->nvme_status;
1032         else
1033             return ptp->scsi_status;
1034     }
1035     return -1;
1036 }
1037 
1038 /* For NVMe command: CDW0 from completion (32 bits); for SCSI: the status */
1039 uint32_t
get_pt_result(const struct sg_pt_base * vp)1040 get_pt_result(const struct sg_pt_base * vp)
1041 {
1042     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1043 
1044     if (ptp) {
1045         const struct freebsd_dev_channel * fdc_p = ptp->mchanp;
1046 
1047         if (NULL == fdc_p)
1048             return -1;
1049         if (ptp->is_nvme_dev && ! ptp->nvme_our_sntl)
1050             return ptp->nvme_result;
1051         else
1052             return (uint32_t)ptp->scsi_status;
1053     }
1054     return 0xffffffff;
1055 }
1056 
1057 int
get_scsi_pt_sense_len(const struct sg_pt_base * vp)1058 get_scsi_pt_sense_len(const struct sg_pt_base * vp)
1059 {
1060     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1061 
1062     if (ptp->sense_resid > ptp->sense_len)
1063         return ptp->sense_len;  /* strange; ignore ptp->sense_resid */
1064     else
1065         return ptp->sense_len - ptp->sense_resid;
1066 }
1067 
1068 uint8_t *
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)1069 get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
1070 {
1071     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1072 
1073     return ptp->sense;
1074 }
1075 
1076 /* Not implemented so return -1 . */
1077 int
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)1078 get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
1079 {
1080     // const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1081 
1082     return -1;
1083 }
1084 
1085 /* If not available return 0 otherwise return number of nanoseconds that the
1086  * lower layers (and hardware) took to execute the command just completed. */
1087 uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp)1088 get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
1089 {
1090     return 0;
1091 }
1092 
1093 int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)1094 get_scsi_pt_transport_err(const struct sg_pt_base * vp)
1095 {
1096     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1097 
1098     return ptp->transport_err;
1099 }
1100 
1101 void
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)1102 set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
1103 {
1104     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1105 
1106     ptp->transport_err = err;
1107 }
1108 
1109 int
get_scsi_pt_os_err(const struct sg_pt_base * vp)1110 get_scsi_pt_os_err(const struct sg_pt_base * vp)
1111 {
1112     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1113 
1114     return ptp->os_err;
1115 }
1116 
1117 char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)1118 get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
1119                               char * b)
1120 {
1121     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1122 
1123     if (0 == ptp->transport_err) {
1124         strncpy(b, "no transport error available", max_b_len);
1125         b[max_b_len - 1] = '\0';
1126         return b;
1127     }
1128     if (ptp->mchanp && ptp->mchanp->is_nvme_dev) {
1129         snprintf(b, max_b_len, "NVMe has no transport errors at present "
1130                  "but tranport_err=%d ??\n", ptp->transport_err);
1131         return b;
1132     }
1133 #if __FreeBSD_version > 500000
1134     if (ptp->mchanp && ptp->mchanp->cam_dev)
1135         cam_error_string(ptp->mchanp->cam_dev, ptp->ccb, b, max_b_len,
1136                          CAM_ESF_ALL, CAM_EPF_ALL);
1137     else {
1138         strncpy(b, "no transport error available", max_b_len);
1139         b[max_b_len - 1] = '\0';
1140    }
1141 #else
1142     strncpy(b, "no transport error available", max_b_len);
1143     b[max_b_len - 1] = '\0';
1144 #endif
1145     return b;
1146 }
1147 
1148 bool
pt_device_is_nvme(const struct sg_pt_base * vp)1149 pt_device_is_nvme(const struct sg_pt_base * vp)
1150 {
1151     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1152 
1153     if (ptp && (ptp->dev_han >= 0)) {
1154         const struct freebsd_dev_channel *fdc_p;
1155 
1156         fdc_p = get_fdc_cp(ptp);
1157         if (NULL == fdc_p) {
1158             pr2ws("%s: unable to find fdc_p\n", __func__);
1159             errno = ENODEV;
1160             return false;
1161         }
1162         return fdc_p->is_nvme_dev;
1163     }
1164     return false;
1165 }
1166 
1167 /* If a NVMe block device (which includes the NSID) handle is associated
1168  * with 'objp', then its NSID is returned (values range from 0x1 to
1169  * 0xffffffe). Otherwise 0 is returned. */
1170 uint32_t
get_pt_nvme_nsid(const struct sg_pt_base * vp)1171 get_pt_nvme_nsid(const struct sg_pt_base * vp)
1172 {
1173     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1174 
1175     if (ptp && (ptp->dev_han >= 0)) {
1176         const struct freebsd_dev_channel *fdc_p;
1177 
1178         fdc_p = get_fdc_cp(ptp);
1179         if (NULL == fdc_p)
1180             return 0;
1181         return fdc_p->nsid;
1182     }
1183     return 0;
1184 }
1185 
1186 char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)1187 get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
1188 {
1189     const struct sg_pt_freebsd_scsi * ptp = &vp->impl;
1190     const char * cp;
1191 
1192     cp = safe_strerror(ptp->os_err);
1193     strncpy(b, cp, max_b_len);
1194     if ((int)strlen(cp) >= max_b_len)
1195         b[max_b_len - 1] = '\0';
1196     return b;
1197 }
1198 
1199 
1200 #define SCSI_INQUIRY_OPC     0x12
1201 #define SCSI_MAINT_IN_OPC  0xa3
1202 #define SCSI_MODE_SENSE10_OPC  0x5a
1203 #define SCSI_MODE_SELECT10_OPC  0x55
1204 #define SCSI_READ10_OPC 0x28
1205 #define SCSI_READ16_OPC 0x88
1206 #define SCSI_READ_CAPACITY10_OPC  0x25
1207 #define SCSI_START_STOP_OPC 0x1b
1208 #define SCSI_SYNC_CACHE10_OPC  0x35
1209 #define SCSI_SYNC_CACHE16_OPC  0x91
1210 #define SCSI_VERIFY10_OPC 0x2f
1211 #define SCSI_VERIFY16_OPC 0x8f
1212 #define SCSI_WRITE10_OPC 0x2a
1213 #define SCSI_WRITE16_OPC 0x8a
1214 #define SCSI_WRITE_SAME10_OPC 0x41
1215 #define SCSI_WRITE_SAME16_OPC 0x93
1216 #define SCSI_RECEIVE_DIAGNOSTIC_OPC  0x1c
1217 #define SCSI_REP_SUP_OPCS_OPC  0xc
1218 #define SCSI_REP_SUP_TMFS_OPC  0xd
1219 #define SCSI_REPORT_LUNS_OPC 0xa0
1220 #define SCSI_REQUEST_SENSE_OPC  0x3
1221 #define SCSI_SEND_DIAGNOSTIC_OPC  0x1d
1222 #define SCSI_TEST_UNIT_READY_OPC  0x0
1223 #define SCSI_SERVICE_ACT_IN_OPC  0x9e
1224 #define SCSI_READ_CAPACITY16_SA  0x10
1225 #define SCSI_SA_MSK  0x1f
1226 
1227 /* Additional Sense Code (ASC) */
1228 #define NO_ADDITIONAL_SENSE 0x0
1229 #define LOGICAL_UNIT_NOT_READY 0x4
1230 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
1231 #define UNRECOVERED_READ_ERR 0x11
1232 #define PARAMETER_LIST_LENGTH_ERR 0x1a
1233 #define INVALID_OPCODE 0x20
1234 #define LBA_OUT_OF_RANGE 0x21
1235 #define INVALID_FIELD_IN_CDB 0x24
1236 #define INVALID_FIELD_IN_PARAM_LIST 0x26
1237 #define UA_RESET_ASC 0x29
1238 #define UA_CHANGED_ASC 0x2a
1239 #define TARGET_CHANGED_ASC 0x3f
1240 #define LUNS_CHANGED_ASCQ 0x0e
1241 #define INSUFF_RES_ASC 0x55
1242 #define INSUFF_RES_ASCQ 0x3
1243 #define LOW_POWER_COND_ON_ASC  0x5e     /* ASCQ=0 */
1244 #define POWER_ON_RESET_ASCQ 0x0
1245 #define BUS_RESET_ASCQ 0x2      /* scsi bus reset occurred */
1246 #define MODE_CHANGED_ASCQ 0x1   /* mode parameters changed */
1247 #define CAPACITY_CHANGED_ASCQ 0x9
1248 #define SAVING_PARAMS_UNSUP 0x39
1249 #define TRANSPORT_PROBLEM 0x4b
1250 #define THRESHOLD_EXCEEDED 0x5d
1251 #define LOW_POWER_COND_ON 0x5e
1252 #define MISCOMPARE_VERIFY_ASC 0x1d
1253 #define MICROCODE_CHANGED_ASCQ 0x1      /* with TARGET_CHANGED_ASC */
1254 #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
1255 #define PCIE_ERR_ASC 0x4b
1256 #define PCIE_UNSUPP_REQ_ASCQ 0x13
1257 
1258 /* NVMe Admin commands */
1259 #define SG_NVME_AD_GET_FEATURE 0xa
1260 #define SG_NVME_AD_SET_FEATURE 0x9
1261 #define SG_NVME_AD_IDENTIFY 0x6         /* similar to SCSI INQUIRY */
1262 #define SG_NVME_AD_DEV_SELT_TEST 0x14
1263 #define SG_NVME_AD_MI_RECEIVE 0x1e      /* MI: Management Interface */
1264 #define SG_NVME_AD_MI_SEND 0x1d         /* hmmm, same opcode as SEND DIAG */
1265 
1266 /* NVMe NVM (Non-Volatile Memory) commands */
1267 #define SG_NVME_NVM_FLUSH 0x0           /* SCSI SYNCHRONIZE CACHE */
1268 #define SG_NVME_NVM_COMPARE 0x5         /* SCSI VERIFY(BYTCHK=1) */
1269 #define SG_NVME_NVM_READ 0x2
1270 #define SG_NVME_NVM_VERIFY 0xc          /* SCSI VERIFY(BYTCHK=0) */
1271 #define SG_NVME_NVM_WRITE 0x1
1272 #define SG_NVME_NVM_WRITE_ZEROES 0x8    /* SCSI WRITE SAME */
1273 
1274 #define SG_NVME_RW_CDW12_FUA (1 << 30) /* Force Unit Access bit */
1275 
1276 #if (HAVE_NVME && (! IGNORE_NVME))
1277 
1278 static void
mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp,int sk,int asc,int ascq,int vb)1279 mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp, int sk, int asc, int ascq,
1280                   int vb)
1281 {
1282     bool dsense = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false;
1283     int n;
1284     uint8_t * sbp = ptp->sense;
1285 
1286     ptp->scsi_status = SAM_STAT_CHECK_CONDITION;
1287     n = ptp->sense_len;
1288     if ((n < 8) || ((! dsense) && (n < 14))) {
1289         if (vb)
1290             pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__,
1291                   n);
1292         return;
1293     } else
1294         ptp->sense_resid = ptp->sense_len -
1295                            (dsense ? 8 : ((n < 18) ? n : 18));
1296     memset(sbp, 0, n);
1297     sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
1298     if (vb > 3)
1299         pr2ws("%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__,
1300               sk, asc, ascq);
1301 }
1302 
1303 static void
mk_sense_from_nvme_status(struct sg_pt_freebsd_scsi * ptp,uint16_t sct_sc,int vb)1304 mk_sense_from_nvme_status(struct sg_pt_freebsd_scsi * ptp, uint16_t sct_sc,
1305                           int vb)
1306 {
1307     bool ok;
1308     bool dsense = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false;
1309     int n;
1310     uint8_t sstatus, sk, asc, ascq;
1311     uint8_t * sbp = ptp->sense;
1312 
1313     ok = sg_nvme_status2scsi(sct_sc, &sstatus, &sk, &asc, &ascq);
1314     if (! ok) { /* can't find a mapping to a SCSI error, so ... */
1315         sstatus = SAM_STAT_CHECK_CONDITION;
1316         sk = SPC_SK_ILLEGAL_REQUEST;
1317         asc = 0xb;
1318         ascq = 0x0;     /* asc: "WARNING" purposely vague */
1319     }
1320 
1321     ptp->scsi_status = sstatus;
1322     n = ptp->sense_len;
1323     if ((n < 8) || ((! dsense) && (n < 14))) {
1324         if (vb)
1325             pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__,
1326                   n);
1327         return;
1328     } else
1329         ptp->sense_resid = ptp->sense_len -
1330                            (dsense ? 8 : ((n < 18) ? n : 18));
1331     memset(sbp, 0, n);
1332     sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
1333     if (vb > 3)
1334         pr2ws("%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__,
1335               sk, asc, ascq);
1336     if (dsense && (sct_sc > 0) && (ptp->sense_resid > 7)) {
1337         sg_nvme_desc2sense(sbp, 0x4000 & sct_sc /* dnr */,
1338                            0x2000 & sct_sc /* more */, 0x7ff & sct_sc);
1339         ptp->sense_resid -= 8;
1340     }
1341 }
1342 
1343 /* Set in_bit to -1 to indicate no bit position of invalid field */
1344 static void
mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp,bool in_cdb,int in_byte,int in_bit,int vb)1345 mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp, bool in_cdb,
1346                      int in_byte, int in_bit, int vb)
1347 {
1348     bool ds = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false;
1349     int asc, n;
1350     uint8_t * sbp = (uint8_t *)ptp->sense;
1351     uint8_t sks[4];
1352 
1353     ptp->scsi_status = SAM_STAT_CHECK_CONDITION;
1354     asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
1355     n = ptp->sense_len;
1356     if ((n < 8) || ((! ds) && (n < 14))) {
1357         if (vb)
1358             pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
1359                   __func__, n);
1360         return;
1361     } else
1362         ptp->sense_resid = ptp->sense_len - (ds ? 8 : ((n < 18) ? n : 18));
1363     memset(sbp, 0, n);
1364     sg_build_sense_buffer(ds, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
1365     memset(sks, 0, sizeof(sks));
1366     sks[0] = 0x80;
1367     if (in_cdb)
1368         sks[0] |= 0x40;
1369     if (in_bit >= 0) {
1370         sks[0] |= 0x8;
1371         sks[0] |= (0x7 & in_bit);
1372     }
1373     sg_put_unaligned_be16(in_byte, sks + 1);
1374     if (ds) {
1375         int sl = sbp[7] + 8;
1376 
1377         sbp[7] = sl;
1378         sbp[sl] = 0x2;
1379         sbp[sl + 1] = 0x6;
1380         memcpy(sbp + sl + 4, sks, 3);
1381     } else
1382         memcpy(sbp + 15, sks, 3);
1383     if (vb > 3)
1384         pr2ws("%s:  [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
1385               __func__, asc, in_cdb ? 'C' : 'D', in_byte,
1386               ((in_bit > 0) ? (0x7 & in_bit) : 0));
1387 }
1388 
1389 #if 0
1390 static void
1391 nvme_cbfcn(struct cam_periph * camperp, union ccb * ccb)
1392 {
1393     pr2ws("%s: >>>> called, camperp=%p, ccb=%p\n", __func__, camperp, ccb);
1394 }
1395 #endif
1396 
1397 /* Does actual ioctl(NVME_PASSTHROUGH_CMD) or uses NVME(CAM) interface.
1398  * Returns 0 on success; negative values are Unix negated errno values;
1399  * positive values are NVMe status (i.e. ((SCT << 8) | SC) ). */
1400 static int
nvme_pt_low(struct sg_pt_freebsd_scsi * ptp,void * dxferp,uint32_t len,bool is_admin,bool is_read,struct nvme_pt_command * npcp,int time_secs,int vb)1401 nvme_pt_low(struct sg_pt_freebsd_scsi * ptp, void * dxferp, uint32_t len,
1402             bool is_admin, bool is_read, struct nvme_pt_command * npcp,
1403             int time_secs, int vb)
1404 {
1405     int err, dev_fd;
1406     uint16_t sct_sc;
1407     uint8_t opcode;
1408     struct freebsd_dev_channel *fdc_p = ptp->mchanp;
1409 
1410     if (vb > 6)
1411         pr2ws("%s: is_read=%d, time_secs=%d, is_cam_nvme=%d, is_admin=%d\n",
1412               __func__, (int)is_read, time_secs, (int)fdc_p->is_cam_nvme,
1413              (int)is_admin);
1414     ptp->is_nvme_dev = fdc_p->is_nvme_dev;
1415     npcp->buf = dxferp;
1416     npcp->len = len;
1417     npcp->is_read = (uint32_t)is_read;
1418     opcode = npcp->cmd.opc;
1419 #if __FreeBSD_version >= 1100000
1420     if (fdc_p->is_cam_nvme)
1421         goto cam_nvme;
1422 #endif
1423 
1424     /* non-CAM NVMe processing follows */
1425     if (is_admin) {
1426         if (fdc_p->nvme_fd_ctrl < 0) {
1427             if (vb > 4)
1428                 pr2ws("%s: not CAM but nvme_fd_ctrl<0, try to open "
1429                       "controller\n", __func__);
1430             if ((fdc_p->nsid > 0) && fdc_p->devname && *fdc_p->devname) {
1431                 int fd;
1432                 char dev_nm[PATH_MAX];
1433 
1434                 if ((fdc_p->devname[0] == '/') || (fdc_p->devname[0] == '.'))
1435                     strncpy(dev_nm, fdc_p->devname, PATH_MAX);
1436                 else
1437                     snprintf(dev_nm, PATH_MAX, "/dev/%s", fdc_p->devname);
1438                 fd = open(dev_nm, O_RDWR);
1439                 if (fd < 0) {
1440                     if (vb > 1)
1441                         pr2ws("%s: Unable to open %s of NVMe controller: "
1442                               "%s\n", __func__, dev_nm, strerror(errno));
1443                 } else
1444                     fdc_p->nvme_fd_ctrl = fd;
1445             }
1446             if (fdc_p->nvme_fd_ctrl < 0)
1447                 return -EINVAL;
1448         }
1449         dev_fd = fdc_p->nvme_fd_ctrl;
1450     } else {
1451         if (fdc_p->nvme_fd_ns < 0) {
1452             if (vb > 1)
1453                 pr2ws("%s: not CAM but nvme_fd_ns<0, inconsistent\n",
1454                       __func__);
1455             return -EINVAL;
1456         }
1457         dev_fd = fdc_p->nvme_fd_ns;
1458     }
1459     err = ioctl(dev_fd, NVME_PASSTHROUGH_CMD, npcp);
1460     if (err < 0) {
1461         err = errno;
1462         if (vb)
1463             pr2ws("%s: ioctl(NVME_PASSTHROUGH_CMD) errno: %s\n", __func__,
1464                   strerror(err));
1465         /* when that ioctl returns an error npcp->cpl is not populated */
1466         return -err;
1467     }
1468 
1469 #if __FreeBSD_version <= 1200058
1470     sct_sc = ((npcp->cpl.status.sct << 8) | npcp->cpl.status.sc);
1471 #else
1472     sct_sc = (NVME_STATUS_GET_SCT(npcp->cpl.status) << 8) |
1473              NVME_STATUS_GET_SC(npcp->cpl.status);
1474 #endif
1475     ptp->nvme_result = npcp->cpl.cdw0;
1476     sg_put_unaligned_le32(npcp->cpl.cdw0,
1477                           ptp->cq_dw0_3 + SG_NVME_PT_CQ_RESULT);
1478     sg_put_unaligned_le32(npcp->cpl.rsvd1, ptp->cq_dw0_3 + 4);
1479     sg_put_unaligned_le16(npcp->cpl.sqhd, ptp->cq_dw0_3 + 8);
1480     sg_put_unaligned_le16(npcp->cpl.sqid, ptp->cq_dw0_3 + 10);
1481     sg_put_unaligned_le16(npcp->cpl.cid, ptp->cq_dw0_3 + 12);
1482     sg_put_unaligned_le16(*((const uint16_t *)&(npcp->cpl.status)),
1483                           ptp->cq_dw0_3 + SG_NVME_PT_CQ_STATUS_P);
1484     if (sct_sc && (vb > 1)) {
1485         char nam[64];
1486         char b[80];
1487 
1488         sg_get_nvme_opcode_name(opcode, is_admin, sizeof(nam), nam);
1489         pr2ws("%s: %s [0x%x], status: %s\n", __func__, nam, opcode,
1490               sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b));
1491     }
1492     return sct_sc;
1493 
1494 #if __FreeBSD_version >= 1100000
1495 cam_nvme:
1496     {
1497         cam_status ccb_status;
1498         union ccb *ccb;
1499         struct ccb_nvmeio *nviop;
1500         FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr;
1501 
1502         if (NULL == ptp->ccb) {     /* re-use if we have one already */
1503             if (! (ccb = cam_getccb(fdc_p->cam_dev))) {
1504                 if (vb)
1505                     pr2ws("%s: cam_getccb: failed\n", __func__);
1506                 ptp->os_err = ENOMEM;
1507                 return -ptp->os_err;
1508             }
1509             ptp->ccb = ccb;
1510         } else
1511             ccb = ptp->ccb;
1512         nviop = &ccb->nvmeio;
1513         CCB_CLEAR_ALL_EXCEPT_HDR(nviop);
1514 
1515         memcpy(&nviop->cmd, &npcp->cmd, sizeof(nviop->cmd));
1516         ptp->timeout_ms = (time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT;
1517         if (is_admin)
1518             cam_fill_nvmeadmin(nviop,
1519                                1 /* retries */,
1520                                NULL,
1521                                is_read ? CAM_DIR_IN : CAM_DIR_OUT,
1522                                dxferp,
1523                                len,
1524                                ptp->timeout_ms);
1525 
1526         else {   /* NVM command set, rather than Admin */
1527             if (fdc_p->nsid != npcp->cmd.nsid) {
1528                 if (vb)
1529                     pr2ws("%s: device node nsid [%u] not equal to cmd nsid "
1530                           "[%u]\n", __func__, fdc_p->nsid, npcp->cmd.nsid);
1531                 return -EINVAL;
1532             }
1533             cam_fill_nvmeio(nviop,
1534                             1 /* retries */,
1535                             NULL,
1536                             is_read ? CAM_DIR_IN : CAM_DIR_OUT,
1537                             dxferp,
1538                             len,
1539                             ptp->timeout_ms);
1540         }
1541 
1542         if (cam_send_ccb(fdc_p->cam_dev, ccb) < 0) {
1543             if (vb) {
1544                 pr2ws("%s: cam_send_ccb(NVME) %s ccb error\n", __func__,
1545                       (is_admin ? "Admin" : "NVM"));
1546                 CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL,
1547                                 CAM_EPF_ALL, ferrp);
1548             }
1549             cam_freeccb(ptp->ccb);
1550             ptp->ccb = NULL;
1551             ptp->os_err = EIO;
1552             return -ptp->os_err;
1553         }
1554         ccb_status = ccb->ccb_h.status & CAM_STATUS_MASK;
1555         if (ccb_status == CAM_REQ_CMP) {
1556             ptp->nvme_result = 0;
1557             ptp->os_err = 0;
1558             return 0;
1559         }
1560         /* error processing follows ... */
1561         ptp->os_err = EIO;
1562         if (vb) {
1563             pr2ws("%s: ccb_status != CAM_REQ_CMP\n", __func__);
1564             CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL,
1565                             CAM_EPF_ALL, ferrp);
1566         }
1567 #if __FreeBSD_version <= 1200058
1568         sct_sc = ((nviop->cpl.status.sct << 8) | nviop->cpl.status.sc);
1569 #else
1570         sct_sc = (NVME_STATUS_GET_SCT(nviop->cpl.status) << 8) |
1571              NVME_STATUS_GET_SC(nviop->cpl.status);
1572 #endif
1573         ptp->nvme_result = nviop->cpl.cdw0;
1574         sg_put_unaligned_le32(nviop->cpl.cdw0,
1575                               ptp->cq_dw0_3 + SG_NVME_PT_CQ_RESULT);
1576         sg_put_unaligned_le32(nviop->cpl.rsvd1, ptp->cq_dw0_3 + 4);
1577         sg_put_unaligned_le16(nviop->cpl.sqhd, ptp->cq_dw0_3 + 8);
1578         sg_put_unaligned_le16(nviop->cpl.sqid, ptp->cq_dw0_3 + 10);
1579         sg_put_unaligned_le16(nviop->cpl.cid, ptp->cq_dw0_3 + 12);
1580         sg_put_unaligned_le16(*((const uint16_t *)&(nviop->cpl.status)),
1581                               ptp->cq_dw0_3 + SG_NVME_PT_CQ_STATUS_P);
1582         if (sct_sc && (vb > 1)) {
1583             char nam[64];
1584             char b[80];
1585 
1586             sg_get_nvme_opcode_name(opcode, is_admin, sizeof(nam),
1587                                     nam);
1588             pr2ws("%s: %s [0x%x], status: %s\n", __func__, nam, opcode,
1589                   sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b));
1590         }
1591         return sct_sc ? sct_sc : ptp->os_err;
1592     }
1593 #endif
1594     return 0;
1595 }
1596 
1597 static void
sntl_check_enclosure_override(struct freebsd_dev_channel * fdc_p,int vb)1598 sntl_check_enclosure_override(struct freebsd_dev_channel * fdc_p, int vb)
1599 {
1600     uint8_t * up = fdc_p->nvme_id_ctlp;
1601     uint8_t nvmsr;
1602 
1603     if (NULL == up)
1604         return;
1605     nvmsr = up[253];
1606     if (vb > 5)
1607         pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr);
1608     fdc_p->dev_stat.id_ctl253 = nvmsr;
1609     switch (fdc_p->dev_stat.enclosure_override) {
1610     case 0x0:       /* no override */
1611         if (0x3 == (0x3 & nvmsr)) {
1612             fdc_p->dev_stat.pdt = PDT_DISK;
1613             fdc_p->dev_stat.enc_serv = 1;
1614         } else if (0x2 & nvmsr) {
1615             fdc_p->dev_stat.pdt = PDT_SES;
1616             fdc_p->dev_stat.enc_serv = 1;
1617         } else if (0x1 & nvmsr) {
1618             fdc_p->dev_stat.pdt = PDT_DISK;
1619             fdc_p->dev_stat.enc_serv = 0;
1620         } else {
1621             uint32_t nn = sg_get_unaligned_le32(up + 516);
1622 
1623             fdc_p->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN;
1624             fdc_p->dev_stat.enc_serv = 0;
1625         }
1626         break;
1627     case 0x1:       /* override to SES device */
1628         fdc_p->dev_stat.pdt = PDT_SES;
1629         fdc_p->dev_stat.enc_serv = 1;
1630         break;
1631     case 0x2:       /* override to disk with attached SES device */
1632         fdc_p->dev_stat.pdt = PDT_DISK;
1633         fdc_p->dev_stat.enc_serv = 1;
1634         break;
1635     case 0x3:       /* override to SAFTE device (PDT_PROCESSOR) */
1636         fdc_p->dev_stat.pdt = PDT_PROCESSOR;
1637         fdc_p->dev_stat.enc_serv = 1;
1638         break;
1639     case 0xff:      /* override to normal disk */
1640         fdc_p->dev_stat.pdt = PDT_DISK;
1641         fdc_p->dev_stat.enc_serv = 0;
1642         break;
1643     default:
1644         pr2ws("%s: unknown enclosure_override value: %d\n", __func__,
1645               fdc_p->dev_stat.enclosure_override);
1646         break;
1647     }
1648 }
1649 
1650 static int
sntl_do_identify(struct sg_pt_freebsd_scsi * ptp,int cns,int nsid,int u_len,uint8_t * up,int time_secs,int vb)1651 sntl_do_identify(struct sg_pt_freebsd_scsi * ptp, int cns, int nsid,
1652                  int u_len, uint8_t * up, int time_secs, int vb)
1653 {
1654     int err;
1655     struct nvme_pt_command npc;
1656     uint8_t * npc_up = (uint8_t *)&npc;
1657 
1658     if (vb > 5)
1659         pr2ws("%s: nsid=%d\n", __func__, nsid);
1660     memset(npc_up, 0, sizeof(npc));
1661     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_IDENTIFY;
1662     sg_put_unaligned_le32(nsid, npc_up + SG_NVME_PT_NSID);
1663     /* CNS=0x1 Identify: controller */
1664     sg_put_unaligned_le32(cns, npc_up + SG_NVME_PT_CDW10);
1665     sg_put_unaligned_le64((sg_uintptr_t)up, npc_up + SG_NVME_PT_ADDR);
1666     sg_put_unaligned_le32(u_len, npc_up + SG_NVME_PT_DATA_LEN);
1667     err = nvme_pt_low(ptp, up, u_len, true, true, &npc, time_secs, vb);
1668     if (err) {
1669         if (err < 0) {
1670             if (vb > 1)
1671                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__,
1672                       strerror(-err), -err);
1673             return err;
1674         } else {        /* non-zero NVMe command status */
1675             ptp->nvme_status = err;
1676             return SG_LIB_NVME_STATUS;
1677         }
1678     }
1679     return 0;
1680 }
1681 
1682 /* Currently only caches associated controller response (4096 bytes) */
1683 static int
sntl_cache_identity(struct sg_pt_freebsd_scsi * ptp,int time_secs,int vb)1684 sntl_cache_identity(struct sg_pt_freebsd_scsi * ptp, int time_secs, int vb)
1685 {
1686     int ret;
1687     uint32_t pg_sz = sg_get_page_size();
1688     struct freebsd_dev_channel * fdc_p = ptp->mchanp;
1689 
1690     fdc_p->nvme_id_ctlp = sg_memalign(pg_sz, pg_sz,
1691                                       &fdc_p->free_nvme_id_ctlp, vb > 3);
1692     if (NULL == fdc_p->nvme_id_ctlp) {
1693         if (vb)
1694             pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
1695         return -ENOMEM;
1696     }
1697     ret = sntl_do_identify(ptp, 0x1 /* CNS */, 0 /* nsid */, pg_sz,
1698                            fdc_p->nvme_id_ctlp, time_secs, vb);
1699     if (0 == ret)
1700         sntl_check_enclosure_override(fdc_p, vb);
1701     return (ret < 0) ? sg_convert_errno(-ret) : ret;
1702 }
1703 
1704 static const char * nvme_scsi_vendor_str = "NVMe    ";
1705 static const uint16_t inq_resp_len = 36;
1706 
1707 static int
sntl_inq(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1708 sntl_inq(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs,
1709          int vb)
1710 {
1711     bool evpd;
1712     int res;
1713     uint16_t n, alloc_len, pg_cd;
1714     uint32_t pg_sz = sg_get_page_size();
1715     struct freebsd_dev_channel * fdc_p;
1716     uint8_t * nvme_id_ns = NULL;
1717     uint8_t * free_nvme_id_ns = NULL;
1718     uint8_t inq_dout[256];
1719 
1720     if (vb > 5)
1721         pr2ws("%s: starting\n", __func__);
1722 
1723     if (0x2 & cdbp[1]) {        /* Reject CmdDt=1 */
1724         mk_sense_invalid_fld(ptp, true, 1, 1, vb);
1725         return 0;
1726     }
1727     fdc_p = get_fdc_p(ptp);
1728     if (NULL == fdc_p) {
1729         if (vb)
1730             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
1731         return -EINVAL;
1732     }
1733     if (NULL == fdc_p->nvme_id_ctlp) {
1734         res = sntl_cache_identity(ptp, time_secs, vb);
1735         if (SG_LIB_NVME_STATUS == res) {
1736             mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb);
1737             return 0;
1738         } else if (res)         /* should be negative errno */
1739             return res;
1740     }
1741     memset(inq_dout, 0, sizeof(inq_dout));
1742     alloc_len = sg_get_unaligned_be16(cdbp + 3);
1743     evpd = !!(0x1 & cdbp[1]);
1744     pg_cd = cdbp[2];
1745     if (evpd) {         /* VPD page responses */
1746         bool cp_id_ctl = false;
1747 
1748         switch (pg_cd) {
1749         case 0:         /* Supported VPD pages VPD page */
1750             /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
1751             inq_dout[1] = pg_cd;
1752             n = 11;
1753             sg_put_unaligned_be16(n - 4, inq_dout + 2);
1754             inq_dout[4] = 0x0;
1755             inq_dout[5] = 0x80;
1756             inq_dout[6] = 0x83;
1757             inq_dout[7] = 0x86;
1758             inq_dout[8] = 0x87;
1759             inq_dout[9] = 0x92;
1760             inq_dout[n - 1] = SG_NVME_VPD_NICR;     /* last VPD number */
1761             break;
1762         case 0x80:      /* Serial number VPD page */
1763             /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
1764             inq_dout[1] = pg_cd;
1765             n = 24;
1766             sg_put_unaligned_be16(n - 4, inq_dout + 2);
1767             memcpy(inq_dout + 4, fdc_p->nvme_id_ctlp + 4, 20);    /* SN */
1768             break;
1769         case 0x83:      /* Device identification VPD page */
1770             if ((fdc_p->nsid > 0) && (fdc_p->nsid < SG_NVME_BROADCAST_NSID)) {
1771                 nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns,
1772                                          vb > 3);
1773                 if (nvme_id_ns) {
1774                     struct nvme_pt_command npc;
1775                     uint8_t * npc_up = (uint8_t *)&npc;
1776 
1777                     memset(npc_up, 0, sizeof(npc));
1778                     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_IDENTIFY;
1779                     sg_put_unaligned_le32(fdc_p->nsid,
1780                                           npc_up + SG_NVME_PT_NSID);
1781                     /* CNS=0x0 Identify: namespace */
1782                     sg_put_unaligned_le32(0x0, npc_up + SG_NVME_PT_CDW10);
1783                     sg_put_unaligned_le64((sg_uintptr_t)nvme_id_ns,
1784                                           npc_up + SG_NVME_PT_ADDR);
1785                     sg_put_unaligned_le32(pg_sz,
1786                                           npc_up + SG_NVME_PT_DATA_LEN);
1787                     res = nvme_pt_low(ptp, nvme_id_ns, pg_sz, true, true,
1788                                       &npc, time_secs, vb > 3);
1789                     if (res) {
1790                         free(free_nvme_id_ns);
1791                         free_nvme_id_ns = NULL;
1792                         nvme_id_ns = NULL;
1793                     }
1794                 }
1795             }
1796             n = sg_make_vpd_devid_for_nvme(fdc_p->nvme_id_ctlp, nvme_id_ns, 0,
1797                                            -1, inq_dout, sizeof(inq_dout));
1798             if (n > 3)
1799                 sg_put_unaligned_be16(n - 4, inq_dout + 2);
1800             if (free_nvme_id_ns) {
1801                 free(free_nvme_id_ns);
1802                 free_nvme_id_ns = NULL;
1803                 nvme_id_ns = NULL;
1804             }
1805             break;
1806         case 0x86:      /* Extended INQUIRY (per SFS SPC Discovery 2016) */
1807             inq_dout[1] = pg_cd;
1808             n = 64;
1809             sg_put_unaligned_be16(n - 4, inq_dout + 2);
1810             inq_dout[5] = 0x1;          /* SIMPSUP=1 */
1811             inq_dout[7] = 0x1;          /* LUICLR=1 */
1812             inq_dout[13] = 0x40;        /* max supported sense data length */
1813             break;
1814         case 0x87:      /* Mode page policy (per SFS SPC Discovery 2016) */
1815             inq_dout[1] = pg_cd;
1816             n = 8;
1817             sg_put_unaligned_be16(n - 4, inq_dout + 2);
1818             inq_dout[4] = 0x3f;         /* all mode pages */
1819             inq_dout[5] = 0xff;         /*     and their sub-pages */
1820             inq_dout[6] = 0x80;         /* MLUS=1, policy=shared */
1821             break;
1822         case 0x92:      /* SCSI Feature set: only SPC Discovery 2016 */
1823             inq_dout[1] = pg_cd;
1824             n = 10;
1825             sg_put_unaligned_be16(n - 4, inq_dout + 2);
1826             inq_dout[9] = 0x1;  /* SFS SPC Discovery 2016 */
1827             break;
1828         case SG_NVME_VPD_NICR:  /* 0xde */
1829             inq_dout[1] = pg_cd;
1830             sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
1831             n = 16 + 4096;
1832             cp_id_ctl = true;
1833             break;
1834         default:        /* Point to page_code field in cdb */
1835             mk_sense_invalid_fld(ptp, true, 2, 7, vb);
1836             return 0;
1837         }
1838         if (alloc_len > 0) {
1839             n = (alloc_len < n) ? alloc_len : n;
1840             n = (n < ptp->dxfer_len) ? n : ptp->dxfer_len;
1841             ptp->resid = ptp->dxfer_len - n;
1842             if (n > 0) {
1843                 if (cp_id_ctl) {
1844                     memcpy((uint8_t *)ptp->dxferp, inq_dout,
1845                            (n < 16 ? n : 16));
1846                     if (n > 16)
1847                         memcpy((uint8_t *)ptp->dxferp + 16,
1848                                fdc_p->nvme_id_ctlp, n - 16);
1849                 } else
1850                     memcpy((uint8_t *)ptp->dxferp, inq_dout, n);
1851             }
1852         }
1853     } else {            /* Standard INQUIRY response */
1854         /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */
1855         inq_dout[0] = (PDT_MASK & fdc_p->dev_stat.pdt);  /* (PQ=0)<<5 */
1856         /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6; rest reserved */
1857         inq_dout[2] = 6;   /* version: SPC-4 */
1858         inq_dout[3] = 2;   /* NORMACA=0, HISUP=0, response data format: 2 */
1859         inq_dout[4] = 31;  /* so response length is (or could be) 36 bytes */
1860         inq_dout[6] = fdc_p->dev_stat.enc_serv ? 0x40 : 0;
1861         inq_dout[7] = 0x2;    /* CMDQUE=1 */
1862         memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8);  /* NVMe not Intel */
1863         memcpy(inq_dout + 16, fdc_p->nvme_id_ctlp + 24, 16);/* Prod <-- MN */
1864         memcpy(inq_dout + 32, fdc_p->nvme_id_ctlp + 64, 4); /* Rev <-- FR */
1865         if (alloc_len > 0) {
1866             n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len;
1867             n = (n < ptp->dxfer_len) ? n : ptp->dxfer_len;
1868             if (n > 0)
1869                 memcpy((uint8_t *)ptp->dxferp, inq_dout, n);
1870         }
1871     }
1872     return 0;
1873 }
1874 
1875 static int
sntl_rluns(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)1876 sntl_rluns(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
1877            int time_secs, int vb)
1878 {
1879     int res;
1880     uint16_t sel_report;
1881     uint32_t alloc_len, k, n, num, max_nsid;
1882     struct freebsd_dev_channel * fdc_p;
1883     uint8_t * rl_doutp;
1884     uint8_t * up;
1885 
1886     if (vb > 5)
1887         pr2ws("%s: starting\n", __func__);
1888     fdc_p = get_fdc_p(ptp);
1889     if (NULL == fdc_p) {
1890         if (vb)
1891             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
1892         return -EINVAL;
1893     }
1894     sel_report = cdbp[2];
1895     alloc_len = sg_get_unaligned_be32(cdbp + 6);
1896     if (NULL == fdc_p->nvme_id_ctlp) {
1897         res = sntl_cache_identity(ptp, time_secs, vb);
1898         if (SG_LIB_NVME_STATUS == res) {
1899             mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb);
1900             return 0;
1901         } else if (res)
1902             return res;
1903     }
1904     max_nsid = sg_get_unaligned_le32(fdc_p->nvme_id_ctlp + 516);
1905     switch (sel_report) {
1906     case 0:
1907     case 2:
1908         num = max_nsid;
1909         break;
1910     case 1:
1911     case 0x10:
1912     case 0x12:
1913         num = 0;
1914         break;
1915     case 0x11:
1916         num = (1 == fdc_p->nsid) ? max_nsid :  0;
1917         break;
1918     default:
1919         if (vb > 1)
1920             pr2ws("%s: bad select_report value: 0x%x\n", __func__,
1921                   sel_report);
1922         mk_sense_invalid_fld(ptp, true, 2, 7, vb);
1923         return 0;
1924     }
1925     rl_doutp = (uint8_t *)calloc(num + 1, 8);
1926     if (NULL == rl_doutp) {
1927         if (vb)
1928             pr2ws("%s: calloc() failed to get memory\n", __func__);
1929         return -ENOMEM;
1930     }
1931     for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8)
1932         sg_put_unaligned_be16(k, up);
1933     n = num * 8;
1934     sg_put_unaligned_be32(n, rl_doutp);
1935     n+= 8;
1936     if (alloc_len > 0) {
1937         n = (alloc_len < n) ? alloc_len : n;
1938         n = (n < (uint32_t)ptp->dxfer_len) ? n : (uint32_t)ptp->dxfer_len;
1939         ptp->resid = ptp->dxfer_len - (int)n;
1940         if (n > 0)
1941             memcpy((uint8_t *)ptp->dxferp, rl_doutp, n);
1942     }
1943     res = 0;
1944     free(rl_doutp);
1945     return res;
1946 }
1947 
1948 static int
sntl_tur(struct sg_pt_freebsd_scsi * ptp,int time_secs,int vb)1949 sntl_tur(struct sg_pt_freebsd_scsi * ptp, int time_secs, int vb)
1950 {
1951     int err;
1952     uint32_t pow_state;
1953     struct nvme_pt_command npc;
1954     uint8_t * npc_up = (uint8_t *)&npc;
1955     struct freebsd_dev_channel * fdc_p;
1956 
1957     if (vb > 5)
1958         pr2ws("%s: starting\n", __func__);
1959     fdc_p = get_fdc_p(ptp);
1960     if (NULL == fdc_p) {
1961         if (vb)
1962             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
1963         return -EINVAL;
1964     }
1965     if (NULL == fdc_p->nvme_id_ctlp) {
1966         int res = sntl_cache_identity(ptp, time_secs, vb);
1967 
1968         if (SG_LIB_NVME_STATUS == res) {
1969             mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb);
1970             return 0;
1971         } else if (res)
1972             return res;
1973     }
1974     memset(npc_up, 0, sizeof(npc));
1975     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_GET_FEATURE;
1976     sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, npc_up + SG_NVME_PT_NSID);
1977     /* SEL=0 (current), Feature=2 Power Management */
1978     sg_put_unaligned_le32(0x2, npc_up + SG_NVME_PT_CDW10);
1979     err = nvme_pt_low(ptp, NULL, 0, true, false, &npc, time_secs, vb);
1980     if (err) {
1981         if (err < 0) {
1982             if (vb > 1)
1983                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__,
1984                       strerror(-err), -err);
1985             return err;
1986         } else {
1987             ptp->nvme_status = err;
1988             mk_sense_from_nvme_status(ptp, err, vb);
1989             return 0;
1990         }
1991     }
1992     pow_state = (0x1f & ptp->nvme_result);
1993     if (vb > 3)
1994         pr2ws("%s: pow_state=%u\n", __func__, pow_state);
1995 #if 0   /* pow_state bounces around too much on laptop */
1996     if (pow_state)
1997         mk_sense_asc_ascq(ptp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0,
1998                           vb);
1999 #endif
2000     return 0;
2001 }
2002 
2003 static int
sntl_req_sense(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2004 sntl_req_sense(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2005                int time_secs, int vb)
2006 {
2007     bool desc;
2008     int err;
2009     uint32_t pow_state, alloc_len, n;
2010     struct nvme_pt_command npc;
2011     uint8_t * npc_up = (uint8_t *)&npc;
2012     struct freebsd_dev_channel * fdc_p;
2013     uint8_t rs_dout[64];
2014 
2015     if (vb > 5)
2016         pr2ws("%s: starting\n", __func__);
2017     fdc_p = get_fdc_p(ptp);
2018     if (NULL == fdc_p) {
2019         if (vb)
2020             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
2021         return -EINVAL;
2022     }
2023     if (NULL == fdc_p->nvme_id_ctlp) {
2024         int res = sntl_cache_identity(ptp, time_secs, vb);
2025 
2026         if (SG_LIB_NVME_STATUS == res) {
2027             mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb);
2028             return 0;
2029         } else if (res)
2030             return res;
2031     }
2032     desc = !!(0x1 & cdbp[1]);
2033     alloc_len = cdbp[4];
2034     memset(npc_up, 0, sizeof(npc));
2035     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_GET_FEATURE;
2036     sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, npc_up + SG_NVME_PT_NSID);
2037     /* SEL=0 (current), Feature=2 Power Management */
2038     sg_put_unaligned_le32(0x2, npc_up + SG_NVME_PT_CDW10);
2039     err = nvme_pt_low(ptp, NULL, 0, true, false, &npc, time_secs, vb);
2040     if (err) {
2041         if (err < 0) {
2042             if (vb > 1)
2043                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__,
2044                       strerror(-err), -err);
2045             return err;
2046         } else {
2047             ptp->nvme_status = err;
2048             mk_sense_from_nvme_status(ptp, err, vb);
2049             return 0;
2050         }
2051     }
2052     pow_state = (0x1f & ptp->nvme_result);
2053     if (vb > 3)
2054         pr2ws("%s: pow_state=%u\n", __func__, pow_state);
2055     memset(rs_dout, 0, sizeof(rs_dout));
2056     if (pow_state)
2057             sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
2058                                   LOW_POWER_COND_ON_ASC, 0);
2059     else
2060             sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
2061                                   NO_ADDITIONAL_SENSE, 0);
2062     n = desc ? 8 : 18;
2063     n = (n < alloc_len) ? n : alloc_len;
2064         n = (n < (uint32_t)ptp->dxfer_len) ? n : (uint32_t)ptp->dxfer_len;
2065     ptp->resid = ptp->dxfer_len - (int)n;
2066     if (n > 0)
2067         memcpy((uint8_t *)ptp->dxferp, rs_dout, n);
2068     return 0;
2069 }
2070 
2071 static int
sntl_mode_ss(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2072 sntl_mode_ss(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2073              int time_secs, int vb)
2074 {
2075     bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]);
2076     int n, len;
2077     uint8_t * bp;
2078     struct freebsd_dev_channel * fdc_p;
2079     struct sg_sntl_result_t sntl_result;
2080 
2081     if (vb > 5)
2082         pr2ws("%s: mse%s\n", __func__, (is_msense ? "nse" : "lect"));
2083     fdc_p = get_fdc_p(ptp);
2084     if (NULL == fdc_p) {
2085         if (vb)
2086             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
2087         return -EINVAL;
2088     }
2089     if (NULL == fdc_p->nvme_id_ctlp) {
2090         int res = sntl_cache_identity(ptp, time_secs, vb);
2091 
2092         if (SG_LIB_NVME_STATUS == res) {
2093             mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb);
2094             return 0;
2095         } else if (res)
2096             return res;
2097     }
2098     if (is_msense) {    /* MODE SENSE(10) */
2099         len = ptp->dxfer_len;
2100         bp = ptp->dxferp;
2101         n = sntl_resp_mode_sense10(&fdc_p->dev_stat, cdbp, bp, len,
2102                                    &sntl_result);
2103         ptp->resid = (n >= 0) ? len - n : len;
2104     } else {            /* MODE SELECT(10) */
2105         uint8_t pre_enc_ov = fdc_p->dev_stat.enclosure_override;
2106 
2107         len = ptp->dxfer_len;
2108         bp = ptp->dxferp;
2109         n = sntl_resp_mode_select10(&fdc_p->dev_stat, cdbp, bp, len,
2110                                     &sntl_result);
2111         if (pre_enc_ov != fdc_p->dev_stat.enclosure_override)
2112             sntl_check_enclosure_override(fdc_p, vb);  /* ENC_OV has changed */
2113     }
2114     if (n < 0) {
2115         int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit :
2116                                                    -1;
2117         if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) &&
2118             (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) {
2119             if (INVALID_FIELD_IN_CDB == sntl_result.asc)
2120                 mk_sense_invalid_fld(ptp, true, sntl_result.in_byte, in_bit,
2121                                      vb);
2122             else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc)
2123                 mk_sense_invalid_fld(ptp, false, sntl_result.in_byte, in_bit,
2124                                      vb);
2125             else
2126                 mk_sense_asc_ascq(ptp, sntl_result.sk, sntl_result.asc,
2127                                   sntl_result.ascq, vb);
2128         } else if (vb)
2129             pr2ws("%s: error but no sense?? n=%d\n", __func__, n);
2130     }
2131     return 0;
2132 }
2133 
2134 /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI
2135  * has a special command (SES Send) to tunnel through pages to an
2136  * enclosure. The NVMe enclosure is meant to understand the SES
2137  * (SCSI Enclosure Services) use of diagnostics pages that are
2138  * related to SES. */
2139 static int
sntl_senddiag(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2140 sntl_senddiag(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2141               int time_secs, int vb)
2142 {
2143     bool pf, self_test;
2144     int err;
2145     uint8_t st_cd, dpg_cd;
2146     uint32_t alloc_len, n, dout_len, dpg_len, nvme_dst;
2147     const uint8_t * dop;
2148     struct nvme_pt_command npc;
2149     uint8_t * npc_up = (uint8_t *)&npc;
2150     struct freebsd_dev_channel * fdc_p;
2151 
2152     st_cd = 0x7 & (cdbp[1] >> 5);
2153     pf = !! (0x4 & cdbp[1]);
2154     self_test = !! (0x10 & cdbp[1]);
2155     if (vb > 5)
2156         pr2ws("%s: pf=%d, self_test=%d, st_code=%d\n", __func__, (int)pf,
2157               (int)self_test, (int)st_cd);
2158     fdc_p = get_fdc_p(ptp);
2159     if (NULL == fdc_p) {
2160         if (vb)
2161             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
2162         return -EINVAL;
2163     }
2164     if (self_test || st_cd) {
2165         memset(npc_up, 0, sizeof(npc));
2166         npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_DEV_SELT_TEST;
2167         /* just this namespace (if there is one) and controller */
2168         sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2169         switch (st_cd) {
2170         case 0: /* Here if self_test is set, do short self-test */
2171         case 1: /* Background short */
2172         case 5: /* Foreground short */
2173             nvme_dst = 1;
2174             break;
2175         case 2: /* Background extended */
2176         case 6: /* Foreground extended */
2177             nvme_dst = 2;
2178             break;
2179         case 4: /* Abort self-test */
2180             nvme_dst = 0xf;
2181             break;
2182         default:
2183             pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd);
2184             mk_sense_invalid_fld(ptp, true, 1, 7, vb);
2185             return 0;
2186         }
2187         sg_put_unaligned_le32(nvme_dst, npc_up + SG_NVME_PT_CDW10);
2188         err = nvme_pt_low(ptp, NULL, 0x0, true, false, &npc, time_secs, vb);
2189         goto do_low;
2190     }
2191     alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
2192     dout_len = ptp->dxfer_len;
2193     if (pf) {
2194         if (0 == alloc_len) {
2195             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
2196             if (vb)
2197                 pr2ws("%s: PF bit set bit param_list_len=0\n", __func__);
2198             return 0;
2199         }
2200     } else {    /* PF bit clear */
2201         if (alloc_len) {
2202             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
2203             if (vb)
2204                 pr2ws("%s: param_list_len>0 but PF clear\n", __func__);
2205             return 0;
2206         } else
2207             return 0;     /* nothing to do */
2208         if (dout_len > 0) {
2209             if (vb)
2210                 pr2ws("%s: dout given but PF clear\n", __func__);
2211             return SCSI_PT_DO_BAD_PARAMS;
2212         }
2213     }
2214     if (dout_len < 4) {
2215         if (vb)
2216             pr2ws("%s: dout length (%u bytes) too short\n", __func__,
2217                   dout_len);
2218         return SCSI_PT_DO_BAD_PARAMS;
2219     }
2220     n = dout_len;
2221     n = (n < alloc_len) ? n : alloc_len;
2222     dop = (const uint8_t *)ptp->dxferp;
2223     if (! sg_is_aligned(dop, 0)) {
2224         if (vb)
2225             pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__,
2226                   (uint64_t)ptp->dxferp);
2227         return SCSI_PT_DO_BAD_PARAMS;
2228     }
2229     dpg_cd = dop[0];
2230     dpg_len = sg_get_unaligned_be16(dop + 2) + 4;
2231     /* should we allow for more than one D_PG is dout ?? */
2232     n = (n < dpg_len) ? n : dpg_len;    /* not yet ... */
2233 
2234     if (vb)
2235         pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n",
2236               __func__, dpg_cd, dpg_len);
2237     memset(npc_up, 0, sizeof(npc));
2238     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_MI_SEND;
2239     sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferp,
2240                           npc_up + SG_NVME_PT_ADDR);
2241     /* NVMe 4k page size. Maybe determine this? */
2242     /* dout_len > 0x1000, is this a problem?? */
2243     sg_put_unaligned_le32(0x1000, npc_up + SG_NVME_PT_DATA_LEN);
2244     /* NVMe Message Header */
2245     sg_put_unaligned_le32(0x0804, npc_up + SG_NVME_PT_CDW10);
2246     /* nvme_mi_ses_send; (0x8 -> mi_ses_recv) */
2247     sg_put_unaligned_le32(0x9, npc_up + SG_NVME_PT_CDW11);
2248     /* data-out length I hope */
2249     sg_put_unaligned_le32(n, npc_up + SG_NVME_PT_CDW13);
2250     err = nvme_pt_low(ptp, ptp->dxferp, 0x1000, true, false, &npc, time_secs,
2251                       vb);
2252 do_low:
2253     if (err) {
2254         if (err < 0) {
2255             if (vb > 1)
2256                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2257                       __func__, strerror(-err), -err);
2258             return err;
2259         } else {
2260             ptp->nvme_status = err;
2261             mk_sense_from_nvme_status(ptp, err, vb);
2262             return 0;
2263         }
2264     }
2265     return 0;
2266 }
2267 
2268 /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1)
2269  * NVMe-MI has a special command (SES Receive) to read pages through a
2270  * tunnel from an enclosure. The NVMe enclosure is meant to understand the
2271  * SES (SCSI Enclosure Services) use of diagnostics pages that are
2272  * related to SES. */
2273 static int
sntl_recvdiag(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2274 sntl_recvdiag(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2275               int time_secs, int vb)
2276 {
2277     bool pcv;
2278     int err;
2279     uint8_t dpg_cd;
2280     uint32_t alloc_len, n, din_len;
2281     const uint8_t * dip;
2282     struct nvme_pt_command npc;
2283     uint8_t * npc_up = (uint8_t *)&npc;
2284     struct freebsd_dev_channel * fdc_p;
2285 
2286     pcv = !! (0x1 & cdbp[1]);
2287     dpg_cd = cdbp[2];
2288     alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
2289     if (vb > 5)
2290         pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__,
2291               dpg_cd, (int)pcv, alloc_len);
2292     fdc_p = get_fdc_p(ptp);
2293     if (NULL == fdc_p) {
2294         if (vb)
2295             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
2296         return -EINVAL;
2297     }
2298     din_len = ptp->dxfer_len;
2299     if (pcv) {
2300         if (0 == alloc_len) {
2301             /* T10 says not an error, hmmm */
2302             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
2303             if (vb)
2304                 pr2ws("%s: PCV bit set bit but alloc_len=0\n", __func__);
2305             return 0;
2306         }
2307     } else {    /* PCV bit clear */
2308         if (alloc_len) {
2309             mk_sense_invalid_fld(ptp, true, 3, 7, vb);
2310             if (vb)
2311                 pr2ws("%s: alloc_len>0 but PCV clear\n", __func__);
2312             return 0;
2313         } else
2314             return 0;     /* nothing to do */
2315         if (din_len > 0) {
2316             if (vb)
2317                 pr2ws("%s: din given but PCV clear\n", __func__);
2318             return SCSI_PT_DO_BAD_PARAMS;
2319         }
2320     }
2321     n = din_len;
2322     n = (n < alloc_len) ? n : alloc_len;
2323     dip = (const uint8_t *)ptp->dxferp;
2324     if (! sg_is_aligned(dip, 0)) {
2325         if (vb)
2326             pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__,
2327                   (uint64_t)ptp->dxferp);
2328         return SCSI_PT_DO_BAD_PARAMS;
2329     }
2330 
2331     if (vb)
2332         pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__,
2333               dpg_cd);
2334     memset(npc_up, 0, sizeof(npc));
2335     npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_MI_RECEIVE;
2336     sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferp,
2337                           npc_up + SG_NVME_PT_ADDR);
2338     /* NVMe 4k page size. Maybe determine this? */
2339     /* dout_len > 0x1000, is this a problem?? */
2340     sg_put_unaligned_le32(0x1000, npc_up + SG_NVME_PT_DATA_LEN);
2341     /* NVMe Message Header */
2342     sg_put_unaligned_le32(0x0804, npc_up + SG_NVME_PT_CDW10);
2343     /* nvme_mi_ses_receive */
2344     sg_put_unaligned_le32(0x8, npc_up + SG_NVME_PT_CDW11);
2345     sg_put_unaligned_le32(dpg_cd, npc_up + SG_NVME_PT_CDW12);
2346     /* data-in length I hope */
2347     sg_put_unaligned_le32(n, npc_up + SG_NVME_PT_CDW13);
2348     err = nvme_pt_low(ptp, ptp->dxferp, 0x1000, true, true, &npc, time_secs,
2349                       vb);
2350     if (err) {
2351         if (err < 0) {
2352             if (vb > 1)
2353                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2354                       __func__, strerror(-err), -err);
2355             return err;
2356         } else {
2357             ptp->nvme_status = err;
2358             mk_sense_from_nvme_status(ptp, err, vb);
2359             return 0;
2360         }
2361     }
2362     ptp->resid = din_len - n;
2363     return 0;
2364 }
2365 
2366 #define F_SA_LOW                0x80    /* cdb byte 1, bits 4 to 0 */
2367 #define F_SA_HIGH               0x100   /* as used by variable length cdbs */
2368 #define FF_SA (F_SA_HIGH | F_SA_LOW)
2369 #define F_INV_OP                0x200
2370 
2371 static int
sntl_rep_opcodes(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2372 sntl_rep_opcodes(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2373                  int time_secs, int vb)
2374 {
2375     bool rctd;
2376     uint8_t reporting_opts, req_opcode, supp;
2377     uint16_t req_sa;
2378     uint32_t alloc_len, offset, a_len;
2379     uint32_t pg_sz = sg_get_page_size();
2380     int len, count, bump;
2381     const struct sg_opcode_info_t *oip;
2382     uint8_t *arr;
2383     uint8_t *free_arr;
2384 
2385     if (vb > 5)
2386         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2387     rctd = !!(cdbp[2] & 0x80);      /* report command timeout desc. */
2388     reporting_opts = cdbp[2] & 0x7;
2389     req_opcode = cdbp[3];
2390     req_sa = sg_get_unaligned_be16(cdbp + 4);
2391     alloc_len = sg_get_unaligned_be32(cdbp + 6);
2392     if (alloc_len < 4 || alloc_len > 0xffff) {
2393         mk_sense_invalid_fld(ptp, true, 6, -1, vb);
2394         return 0;
2395     }
2396     a_len = pg_sz - 72;
2397     arr = sg_memalign(pg_sz, pg_sz, &free_arr, vb > 3);
2398     if (NULL == arr) {
2399         if (vb)
2400             pr2ws("%s: calloc() failed to get memory\n", __func__);
2401         return -ENOMEM;
2402     }
2403     switch (reporting_opts) {
2404     case 0: /* all commands */
2405         count = 0;
2406         bump = rctd ? 20 : 8;
2407         for (offset = 4, oip = sg_get_opcode_translation();
2408              (oip->flags != 0xffff) && (offset < a_len); ++oip) {
2409             if (F_INV_OP & oip->flags)
2410                 continue;
2411             ++count;
2412             arr[offset] = oip->opcode;
2413             sg_put_unaligned_be16(oip->sa, arr + offset + 2);
2414             if (rctd)
2415                 arr[offset + 5] |= 0x2;
2416             if (FF_SA & oip->flags)
2417                 arr[offset + 5] |= 0x1;
2418             sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2419             if (rctd)
2420                 sg_put_unaligned_be16(0xa, arr + offset + 8);
2421             offset += bump;
2422         }
2423         sg_put_unaligned_be32(count * bump, arr + 0);
2424         break;
2425     case 1: /* one command: opcode only */
2426     case 2: /* one command: opcode plus service action */
2427     case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2428         for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
2429             if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
2430                 break;
2431         }
2432         if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) {
2433             supp = 1;
2434             offset = 4;
2435         } else {
2436             if (1 == reporting_opts) {
2437                 if (FF_SA & oip->flags) {
2438                     mk_sense_invalid_fld(ptp, true, 2, 2, vb);
2439                     free(free_arr);
2440                     return 0;
2441                 }
2442                 req_sa = 0;
2443             } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) {
2444                 mk_sense_invalid_fld(ptp, true, 4, -1, vb);
2445                 free(free_arr);
2446                 return 0;
2447             }
2448             if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode))
2449                 supp = 3;
2450             else if (0 == (FF_SA & oip->flags))
2451                 supp = 1;
2452             else if (req_sa != oip->sa)
2453                 supp = 1;
2454             else
2455                 supp = 3;
2456             if (3 == supp) {
2457                 uint16_t u = oip->len_mask[0];
2458                 int k;
2459 
2460                 sg_put_unaligned_be16(u, arr + 2);
2461                 arr[4] = oip->opcode;
2462                 for (k = 1; k < u; ++k)
2463                     arr[4 + k] = (k < 16) ?
2464                 oip->len_mask[k] : 0xff;
2465                 offset = 4 + u;
2466             } else
2467                 offset = 4;
2468         }
2469         arr[1] = (rctd ? 0x80 : 0) | supp;
2470         if (rctd) {
2471             sg_put_unaligned_be16(0xa, arr + offset);
2472             offset += 12;
2473         }
2474         break;
2475     default:
2476         mk_sense_invalid_fld(ptp, true, 2, 2, vb);
2477         free(free_arr);
2478         return 0;
2479     }
2480     offset = (offset < a_len) ? offset : a_len;
2481     len = (offset < alloc_len) ? offset : alloc_len;
2482     ptp->resid = ptp->dxfer_len - (int)len;
2483     if (len > 0)
2484         memcpy((uint8_t *)ptp->dxferp, arr, len);
2485     free(free_arr);
2486     return 0;
2487 }
2488 
2489 static int
sntl_rep_tmfs(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2490 sntl_rep_tmfs(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2491               int time_secs, int vb)
2492 {
2493     bool repd;
2494     uint32_t alloc_len, len;
2495     uint8_t arr[16];
2496 
2497     if (vb > 5)
2498         pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2499     memset(arr, 0, sizeof(arr));
2500     repd = !!(cdbp[2] & 0x80);
2501     alloc_len = sg_get_unaligned_be32(cdbp + 6);
2502     if (alloc_len < 4) {
2503         mk_sense_invalid_fld(ptp, true, 6, -1, vb);
2504         return 0;
2505     }
2506     arr[0] = 0xc8;          /* ATS | ATSS | LURS */
2507     arr[1] = 0x1;           /* ITNRS */
2508     if (repd) {
2509         arr[3] = 0xc;
2510         len = 16;
2511     } else
2512         len = 4;
2513 
2514     len = (len < alloc_len) ? len : alloc_len;
2515     ptp->resid = ptp->dxfer_len - (int)len;
2516     if (len > 0)
2517         memcpy((uint8_t *)ptp->dxferp, arr, len);
2518     return 0;
2519 }
2520 
2521 static int
sntl_rread(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2522 sntl_rread(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2523            int time_secs, int vb)
2524 {
2525     bool is_read10 = (SCSI_READ10_OPC == cdbp[0]);
2526     bool have_fua = !!(cdbp[1] & 0x8);
2527     int err;
2528     uint32_t nblks_t10 = 0;     /* 'control' in upper 16 bits */
2529     uint64_t lba;
2530     struct nvme_pt_command npc;
2531     uint8_t * npc_up = (uint8_t *)&npc;
2532     struct freebsd_dev_channel * fdc_p;
2533 
2534     if (vb > 5)
2535         pr2ws("%s: fua=%d\n", __func__, (int)have_fua);
2536     fdc_p = get_fdc_p(ptp);
2537     memset(&npc, 0, sizeof(npc));
2538     npc.cmd.opc = SG_NVME_NVM_READ;
2539     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2540     if (is_read10) {
2541         lba = sg_get_unaligned_be32(cdbp + 2);
2542         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
2543     } else {
2544         lba = sg_get_unaligned_be64(cdbp + 2);
2545         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
2546         if (nblks_t10 > (UINT16_MAX + 1)) {
2547             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
2548             return 0;
2549         }
2550     }
2551     if (0 == nblks_t10) {         /* NOP in SCSI */
2552         if (vb > 4)
2553             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
2554                   __func__);
2555         return 0;
2556     }
2557     --nblks_t10;       /* crazy "0's based" counts */
2558     sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */
2559     if (have_fua)
2560         nblks_t10 |= SG_NVME_RW_CDW12_FUA;
2561     sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12);
2562     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2563 
2564     err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, true, &npc,
2565                       time_secs, vb);
2566     if (err) {
2567         if (err < 0) {
2568             if (vb > 1)
2569                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2570                       __func__, strerror(-err), -err);
2571             return err;
2572         } else {
2573             ptp->nvme_status = err;
2574             mk_sense_from_nvme_status(ptp, err, vb);
2575             return 0;
2576         }
2577     }
2578     ptp->resid = 0;     /* hoping */
2579     return 0;
2580 }
2581 
2582 static int
sntl_write(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2583 sntl_write(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2584            int time_secs, int vb)
2585 {
2586     bool is_write10 = (SCSI_WRITE10_OPC == cdbp[0]);
2587     bool have_fua = !!(cdbp[1] & 0x8);
2588     int err;
2589     uint32_t nblks_t10 = 0;
2590     uint64_t lba;
2591     struct nvme_pt_command npc;
2592     uint8_t * npc_up = (uint8_t *)&npc;
2593     struct freebsd_dev_channel * fdc_p;
2594 
2595     if (vb > 5)
2596         pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua,
2597               time_secs);
2598     fdc_p = get_fdc_p(ptp);
2599     memset(&npc, 0, sizeof(npc));
2600     npc.cmd.opc = SG_NVME_NVM_WRITE;
2601     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2602     if (is_write10) {
2603         lba = sg_get_unaligned_be32(cdbp + 2);
2604         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
2605     } else {
2606         lba = sg_get_unaligned_be64(cdbp + 2);
2607         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
2608         if (nblks_t10 > (UINT16_MAX + 1)) {
2609             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
2610             return 0;
2611         }
2612     }
2613     if (0 == nblks_t10) { /* NOP in SCSI */
2614         if (vb > 4)
2615             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
2616                   __func__);
2617         return 0;
2618     }
2619     --nblks_t10;
2620     sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */
2621     if (have_fua)
2622         nblks_t10 |= SG_NVME_RW_CDW12_FUA;
2623     sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12);
2624     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2625 
2626     err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc,
2627                       time_secs, vb);
2628     if (err) {
2629         if (err < 0) {
2630             if (vb > 1)
2631                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2632                       __func__, strerror(-err), -err);
2633             return err;
2634         } else {
2635             ptp->nvme_status = err;
2636             mk_sense_from_nvme_status(ptp, err, vb);
2637             return 0;
2638         }
2639     }
2640     ptp->resid = 0;
2641     return 0;
2642 }
2643 
2644 static int
sntl_verify(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2645 sntl_verify(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2646            int time_secs, int vb)
2647 {
2648     bool is_verify10 = (SCSI_VERIFY10_OPC == cdbp[0]);
2649     uint8_t bytchk = (cdbp[1] >> 1) & 0x3;
2650     int err;
2651     uint32_t nblks_t10 = 0;
2652     uint64_t lba;
2653     struct nvme_pt_command npc;
2654     uint8_t * npc_up = (uint8_t *)&npc;
2655     struct freebsd_dev_channel * fdc_p;
2656 
2657     if (vb > 5)
2658         pr2ws("%s: bytchk=%d, time_secs=%d\n", __func__, bytchk, time_secs);
2659     if (bytchk > 1) {
2660         mk_sense_invalid_fld(ptp, true, 1, 2, vb);
2661         return 0;
2662     }
2663     fdc_p = get_fdc_p(ptp);
2664     memset(&npc, 0, sizeof(npc));
2665     npc.cmd.opc = bytchk ? SG_NVME_NVM_COMPARE : SG_NVME_NVM_VERIFY;
2666     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2667     if (is_verify10) {
2668         lba = sg_get_unaligned_be32(cdbp + 2);
2669         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
2670     } else {
2671         lba = sg_get_unaligned_be64(cdbp + 2);
2672         nblks_t10 = sg_get_unaligned_be32(cdbp + 10);
2673         if (nblks_t10 > (UINT16_MAX + 1)) {
2674             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
2675             return 0;
2676         }
2677     }
2678     if (0 == nblks_t10) { /* NOP in SCSI */
2679         if (vb > 4)
2680             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
2681                   __func__);
2682         return 0;
2683     }
2684     --nblks_t10;
2685     sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */
2686     sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12);
2687     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2688 
2689     err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc,
2690                       time_secs, vb);
2691     if (err) {
2692         if (err < 0) {
2693             if (vb > 1)
2694                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2695                       __func__, strerror(-err), -err);
2696             return err;
2697         } else {
2698             ptp->nvme_status = err;
2699             mk_sense_from_nvme_status(ptp, err, vb);
2700             return 0;
2701         }
2702     }
2703     ptp->resid = 0;
2704     return 0;
2705 }
2706 
2707 static int
sntl_write_same(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2708 sntl_write_same(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2709                 int time_secs, int vb)
2710 {
2711     bool is_ws10 = (SCSI_WRITE_SAME10_OPC == cdbp[0]);
2712     bool ndob = is_ws10 ? false : !!(0x1 & cdbp[1]);
2713     int err;
2714     int nblks_t10 = 0;
2715     uint64_t lba;
2716     struct nvme_pt_command npc;
2717     uint8_t * npc_up = (uint8_t *)&npc;
2718     struct freebsd_dev_channel * fdc_p;
2719 
2720     if (vb > 5)
2721         pr2ws("%s: ndob=%d, time_secs=%d\n", __func__, (int)ndob, time_secs);
2722     if (! ndob) {
2723         int flbas, index, lbafx, lbads, lbsize;
2724         uint8_t * up;
2725         uint8_t * dp;
2726 
2727         dp = ptp->dxferp;
2728         up = ptp->mchanp->nvme_id_ctlp;
2729         if ((dp == NULL) || (up == NULL))
2730             return sg_convert_errno(ENOMEM);
2731         flbas = up[26];     /* NVME FLBAS field from Identify */
2732         index = 128 + (4 * (flbas & 0xf));
2733         lbafx = sg_get_unaligned_le32(up + index);
2734         lbads = (lbafx >> 16) & 0xff;  /* bits 16 to 23 inclusive, pow2 */
2735         lbsize = 1 << lbads;
2736         if (! sg_all_zeros(dp, lbsize)) {
2737             mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, PCIE_ERR_ASC,
2738                               PCIE_UNSUPP_REQ_ASCQ, vb);
2739             return 0;
2740         }
2741         /* so given single LB full of zeros, can translate .... */
2742     }
2743     fdc_p = ptp->mchanp;
2744     memset(&npc, 0, sizeof(npc));
2745     npc.cmd.opc = SG_NVME_NVM_WRITE_ZEROES;
2746     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2747     if (is_ws10) {
2748         lba = sg_get_unaligned_be32(cdbp + 2);
2749         nblks_t10 = sg_get_unaligned_be16(cdbp + 7);
2750     } else {
2751         uint32_t num = sg_get_unaligned_be32(cdbp + 10);
2752 
2753         lba = sg_get_unaligned_be64(cdbp + 2);
2754         if (num > (UINT16_MAX + 1)) {
2755             mk_sense_invalid_fld(ptp, true, 11, -1, vb);
2756             return 0;
2757         } else
2758             nblks_t10 = num;
2759     }
2760     if (0 == nblks_t10) { /* NOP in SCSI */
2761         if (vb > 4)
2762             pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n",
2763                   __func__);
2764         return 0;
2765     }
2766     --nblks_t10;
2767     sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */
2768     sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12);
2769     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2770 
2771     err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc,
2772                       time_secs, vb);
2773     if (err) {
2774         if (err < 0) {
2775             if (vb > 1)
2776                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2777                       __func__, strerror(-err), -err);
2778             return err;
2779         } else {
2780             ptp->nvme_status = err;
2781             mk_sense_from_nvme_status(ptp, err, vb);
2782             return 0;
2783         }
2784     }
2785     ptp->resid = 0;
2786     return 0;
2787 }
2788 
2789 static int
sntl_sync_cache(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2790 sntl_sync_cache(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2791                 int time_secs, int vb)
2792 {
2793     bool immed = !!(0x2 & cdbp[1]);
2794     int err;
2795     struct nvme_pt_command npc;
2796     uint8_t * npc_up = (uint8_t *)&npc;
2797     struct freebsd_dev_channel * fdc_p;
2798 
2799     if (vb > 5)
2800         pr2ws("%s: immed=%d, time_secs=%d\n", __func__, (int)immed,
2801               time_secs);
2802     fdc_p = ptp->mchanp;
2803     memset(&npc, 0, sizeof(npc));
2804     npc.cmd.opc = SG_NVME_NVM_FLUSH;
2805     sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID);
2806     if (vb > 4)
2807         pr2ws("%s: immed bit, lba and num_lbs fields ignored\n", __func__);
2808     err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc,
2809                       time_secs, vb);
2810     if (err) {
2811         if (err < 0) {
2812             if (vb > 1)
2813                 pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
2814                       __func__, strerror(-err), -err);
2815             return err;
2816         } else {
2817             ptp->nvme_status = err;
2818             mk_sense_from_nvme_status(ptp, err, vb);
2819             return 0;
2820         }
2821     }
2822     ptp->resid = 0;
2823     return 0;
2824 }
2825 
2826 static int
sntl_start_stop(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2827 sntl_start_stop(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2828                 int time_secs, int vb)
2829 {
2830     bool immed = !!(0x1 & cdbp[1]);
2831 
2832     if (vb > 5)
2833         pr2ws("%s: immed=%d, time_secs=%d, ignore\n", __func__, (int)immed,
2834               time_secs);
2835     if (ptp) { }        /* suppress warning */
2836     return 0;
2837 }
2838 
2839 /* Note that the "Returned logical block address" (RLBA) field in the SCSI
2840  * READ CAPACITY (10+16) command's response provides the address of the _last_
2841  * LBA (counting origin 0) which will be one less that the "size" in the
2842  * NVMe Identify command response's NSZE field. One problem is that in
2843  * some situations NSZE can be zero: temporarily set RLBA field to 0
2844  * (implying a 1 LB logical units size) pending further research. The LBLIB
2845  * is the "Logical Block Length In Bytes" field in the RCAP response. */
2846 static int
sntl_readcap(struct sg_pt_freebsd_scsi * ptp,const uint8_t * cdbp,int time_secs,int vb)2847 sntl_readcap(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp,
2848              int time_secs, int vb)
2849 {
2850     bool is_rcap10 = (SCSI_READ_CAPACITY10_OPC == cdbp[0]);
2851     int res, n, len, alloc_len, dps;
2852     uint8_t flbas, index, lbads;  /* NVMe: 2**LBADS --> Logical Block size */
2853     uint32_t lbafx;     /* NVME: LBAF0...LBAF15, each 16 bytes */
2854     uint32_t pg_sz = sg_get_page_size();
2855     uint64_t nsze;
2856     uint8_t * bp;
2857     uint8_t * up;
2858     uint8_t * free_up = NULL;
2859     struct freebsd_dev_channel * fdc_p;
2860     uint8_t resp[32];
2861 
2862     if (vb > 5)
2863         pr2ws("%s: RCAP%d\n", __func__, (is_rcap10 ? 10 : 16));
2864     fdc_p = ptp->mchanp;
2865     if (NULL == fdc_p) {
2866         if (vb)
2867             pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__);
2868         return -EINVAL;
2869     }
2870     up = sg_memalign(pg_sz, pg_sz, &free_up, false);
2871     if (NULL == up) {
2872         if (vb)
2873             pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
2874         return sg_convert_errno(ENOMEM);
2875     }
2876     res = sntl_do_identify(ptp, 0x0 /* CNS */, fdc_p->nsid, pg_sz, up,
2877                            time_secs, vb);
2878     if (res < 0) {
2879         res = sg_convert_errno(-res);
2880         goto fini;
2881     }
2882     memset(resp, 0, sizeof(resp));
2883     nsze = sg_get_unaligned_le64(up + 0);
2884     flbas = up[26];     /* NVME FLBAS field from Identify, want LBAF[flbas] */
2885     index = 128 + (4 * (flbas & 0xf));
2886     lbafx = sg_get_unaligned_le32(up + index);
2887     lbads = (lbafx >> 16) & 0xff;       /* bits 16 to 23 inclusive, pow2 */
2888     if (is_rcap10) {
2889         alloc_len = 8;  /* implicit, not in cdb */
2890         if (nsze > 0xffffffff)
2891             sg_put_unaligned_be32(0xffffffff, resp + 0);
2892         else if (0 == nsze)     /* no good answer here */
2893             sg_put_unaligned_be32(0, resp + 0);         /* SCSI RLBA field */
2894         else
2895             sg_put_unaligned_be32((uint32_t)(nsze - 1), resp + 0);
2896         sg_put_unaligned_be32(1 << lbads, resp + 4);    /* SCSI LBLIB field */
2897     } else {
2898         alloc_len = sg_get_unaligned_be32(cdbp + 10);
2899         dps = up[29];
2900         if (0x7 & dps) {
2901             resp[12] = 0x1;
2902             n = (0x7 & dps) - 1;
2903             if (n > 0)
2904                 resp[12] |= (n + n);
2905         }
2906         if (0 == nsze)  /* no good answer here */
2907             sg_put_unaligned_be64(0, resp + 0);
2908         else
2909             sg_put_unaligned_be64(nsze - 1, resp + 0);
2910         sg_put_unaligned_be32(1 << lbads, resp + 8);    /* SCSI LBLIB field */
2911     }
2912     len = ptp->dxfer_len;
2913     bp = ptp->dxferp;
2914     n = 32;
2915     n = (n < alloc_len) ? n : alloc_len;
2916     n = (n < len) ? n : len;
2917     ptp->resid = len - n;
2918     if (n > 0)
2919         memcpy(bp, resp, n);
2920 fini:
2921     if (free_up)
2922         free(free_up);
2923     return res;
2924 }
2925 
2926 /* Executes NVMe Admin command (or at least forwards it to lower layers).
2927  * Depending on the device, this could be NVME(via CAM) or NVME(non-CAM).
2928  * is_admin will be overridden if the SNTL functions are called.
2929  * Returns 0 for success, negative numbers are negated 'errno' values from
2930  * OS system calls. Positive return values are errors from this package. */
2931 static int
sg_do_nvme_pt(struct sg_pt_freebsd_scsi * ptp,int fd,bool is_admin,int time_secs,int vb)2932 sg_do_nvme_pt(struct sg_pt_freebsd_scsi * ptp, int fd, bool is_admin,
2933               int time_secs, int vb)
2934 {
2935     bool scsi_cdb, in_xfer;
2936     int n, err, len, io_len;
2937     uint16_t sct_sc, sa;
2938     uint8_t * dxferp;
2939     uint8_t * npc_up;
2940     struct freebsd_dev_channel * fdc_p;
2941     const uint8_t * cdbp;
2942     struct nvme_pt_command npc;
2943 
2944     npc_up = (uint8_t *)&npc;
2945     if (vb > 6)
2946         pr2ws("%s: fd=%d, is_admin=%d\n", __func__, fd, (int)is_admin);
2947     if (! ptp->cdb) {
2948         if (vb)
2949             pr2ws("%s: No NVMe command given (set_scsi_pt_cdb())\n",
2950                   __func__);
2951         return SCSI_PT_DO_BAD_PARAMS;
2952     }
2953     fdc_p = ptp->mchanp;
2954     if (fd < 0) {
2955         if (NULL == fdc_p) {
2956             if (vb)
2957                 pr2ws("%s: no device handle in object or fd ?\n", __func__);
2958             return -EINVAL;
2959         }
2960         /* no fd, but have fdc_p so that is okay */
2961     } else {
2962         int han = fd - FREEBSD_FDOFFSET;
2963 
2964         if ((han < 0) || (han >= FREEBSD_MAXDEV)) {
2965             if (vb)
2966                 pr2ws("%s: argument 'fd' is bad\n", __func__);
2967             return SCSI_PT_DO_BAD_PARAMS;
2968         }
2969         if (NULL == devicetable[han]) {
2970             if (vb)
2971                 pr2ws("%s: argument 'fd' is bad (2)\n", __func__);
2972             return SCSI_PT_DO_BAD_PARAMS;
2973         }
2974         if (fdc_p && (fdc_p != devicetable[han])) {
2975             if (vb)
2976                 pr2ws("%s: different device handle in object and fd ?\n",
2977                       __func__);
2978             return SCSI_PT_DO_BAD_PARAMS;
2979         }
2980         if (NULL == fdc_p) {
2981             ptp->dev_han = fd;
2982             fdc_p = devicetable[han];
2983         }
2984     }
2985 
2986     ptp->is_nvme_dev = fdc_p->is_nvme_dev;
2987     n = ptp->cdb_len;
2988     cdbp = (const uint8_t *)ptp->cdb;
2989     if (vb > 3)
2990         pr2ws("%s: opcode=0x%x, fd=%d\n", __func__, cdbp[0], fd);
2991     scsi_cdb = sg_is_scsi_cdb(cdbp, n);
2992     /* nvme_our_sntl is false when NVMe command (64 byte) has been given */
2993     ptp->nvme_our_sntl = scsi_cdb;
2994     if (scsi_cdb) {
2995         switch (cdbp[0]) {
2996         case SCSI_INQUIRY_OPC:
2997             return sntl_inq(ptp, cdbp, time_secs, vb);
2998         case SCSI_REPORT_LUNS_OPC:
2999             return sntl_rluns(ptp, cdbp, time_secs, vb);
3000         case SCSI_TEST_UNIT_READY_OPC:
3001             return sntl_tur(ptp, time_secs, vb);
3002         case SCSI_REQUEST_SENSE_OPC:
3003             return sntl_req_sense(ptp, cdbp, time_secs, vb);
3004         case SCSI_READ10_OPC:
3005         case SCSI_READ16_OPC:
3006             return sntl_rread(ptp, cdbp, time_secs, vb);
3007         case SCSI_WRITE10_OPC:
3008         case SCSI_WRITE16_OPC:
3009             return sntl_write(ptp, cdbp, time_secs, vb);
3010         case SCSI_START_STOP_OPC:
3011             return sntl_start_stop(ptp, cdbp, time_secs, vb);
3012         case SCSI_SEND_DIAGNOSTIC_OPC:
3013             return sntl_senddiag(ptp, cdbp, time_secs, vb);
3014         case SCSI_RECEIVE_DIAGNOSTIC_OPC:
3015             return sntl_recvdiag(ptp, cdbp, time_secs, vb);
3016         case SCSI_MODE_SENSE10_OPC:
3017         case SCSI_MODE_SELECT10_OPC:
3018             return sntl_mode_ss(ptp, cdbp, time_secs, vb);
3019         case SCSI_READ_CAPACITY10_OPC:
3020             return sntl_readcap(ptp, cdbp, time_secs, vb);
3021         case SCSI_VERIFY10_OPC:
3022         case SCSI_VERIFY16_OPC:
3023             return sntl_verify(ptp, cdbp, time_secs, vb);
3024         case SCSI_WRITE_SAME10_OPC:
3025         case SCSI_WRITE_SAME16_OPC:
3026             return sntl_write_same(ptp, cdbp, time_secs, vb);
3027         case SCSI_SYNC_CACHE10_OPC:
3028         case SCSI_SYNC_CACHE16_OPC:
3029             return sntl_sync_cache(ptp, cdbp, time_secs, vb);
3030         case SCSI_SERVICE_ACT_IN_OPC:
3031             if (SCSI_READ_CAPACITY16_SA == (cdbp[1] & SCSI_SA_MSK))
3032                 return sntl_readcap(ptp, cdbp, time_secs, vb);
3033             goto fini;
3034         case SCSI_MAINT_IN_OPC:
3035             sa = SCSI_SA_MSK & cdbp[1];        /* service action */
3036             if (SCSI_REP_SUP_OPCS_OPC == sa)
3037                 return sntl_rep_opcodes(ptp, cdbp, time_secs, vb);
3038             else if (SCSI_REP_SUP_TMFS_OPC == sa)
3039                 return sntl_rep_tmfs(ptp, cdbp, time_secs, vb);
3040             /* fall through */
3041         default:
3042 fini:
3043             if (vb > 2) {
3044                 char b[64];
3045 
3046                 sg_get_command_name(cdbp, -1, sizeof(b), b);
3047                 pr2ws("%s: no translation to NVMe for SCSI %s command\n",
3048                       __func__, b);
3049             }
3050             mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE,
3051                               0, vb);
3052             return 0;
3053         }
3054     }
3055 
3056     /* NVMe command given to pass-through */
3057     if (vb > 4)
3058         pr2ws("%s: NVMe pass-through command, admin=%d\n", __func__,
3059               is_admin);
3060     len = (int)sizeof(npc.cmd);
3061     n = (n < len) ? n : len;
3062     if (n < 64) {
3063         if (vb)
3064             pr2ws("%s: command length of %d bytes is too short\n", __func__,
3065                   n);
3066         return SCSI_PT_DO_BAD_PARAMS;
3067     }
3068     memcpy(npc_up, (const uint8_t *)ptp->cdb, n);
3069     if (n < len)        /* zero out rest of 'npc' */
3070         memset(npc_up + n, 0, len - n);
3071     in_xfer = false;
3072     io_len = 0;
3073     dxferp = NULL;
3074     if (ptp->dxfer_ilen > 0) {
3075         in_xfer = true;
3076         io_len = ptp->dxfer_ilen;
3077         dxferp = ptp->dxferip;
3078         sg_put_unaligned_le32(ptp->dxfer_ilen, npc_up + SG_NVME_PT_DATA_LEN);
3079         sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferip,
3080                               npc_up + SG_NVME_PT_ADDR);
3081     } else if (ptp->dxfer_olen > 0) {
3082         in_xfer = false;
3083         io_len = ptp->dxfer_olen;
3084         dxferp = ptp->dxferop;
3085         sg_put_unaligned_le32(ptp->dxfer_olen, npc_up + SG_NVME_PT_DATA_LEN);
3086         sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferop,
3087                               npc_up + SG_NVME_PT_ADDR);
3088     }
3089     err = nvme_pt_low(ptp, dxferp, io_len, is_admin, in_xfer, &npc, time_secs,
3090                       vb);
3091     if (err < 0) {
3092         if (vb > 1)
3093             pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n",
3094                   __func__, strerror(-err), -err);
3095         return err;
3096     }
3097     sct_sc = err;       /* ((SCT << 8) | SC) which may be 0 */
3098     ptp->nvme_status = sct_sc;
3099     if (ptp->sense && (ptp->sense_len > 0)) {
3100         uint32_t k = sizeof(ptp->cq_dw0_3);
3101 
3102         if ((int)k < ptp->sense_len)
3103             ptp->sense_resid = ptp->sense_len - (int)k;
3104         else {
3105             k = ptp->sense_len;
3106             ptp->sense_resid = 0;
3107         }
3108         memcpy(ptp->sense, ptp->cq_dw0_3, k);
3109     }
3110     if (in_xfer)
3111         ptp->resid = 0; /* Just hoping ... */
3112     return sct_sc ? SG_LIB_NVME_STATUS : 0;
3113 }
3114 
3115 #endif          /* (HAVE_NVME && (! IGNORE_NVME)) */
3116 
3117 
3118 #if (HAVE_NVME && (! IGNORE_NVME))
3119 
3120 /* Requires pass-through file to be open and associated with vp */
3121 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int vb)3122 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb)
3123 {
3124     struct sg_pt_freebsd_scsi * ptp = &vp->impl;
3125     struct freebsd_dev_channel *fdc_p;
3126 
3127     if (vb && (submq != 0))
3128         pr2ws("%s: warning, uses submit queue 0\n", __func__);
3129     fdc_p = ptp->mchanp;
3130     if (NULL == fdc_p) {
3131         fdc_p = get_fdc_p(ptp);
3132         if (NULL == fdc_p) {
3133             if (vb > 2)
3134                 pr2ws("%s: no open file associated with pt object\n",
3135                       __func__);
3136             return -EINVAL;
3137         }
3138         ptp->mchanp = fdc_p;
3139     }
3140     return sg_do_nvme_pt(ptp, -1, false, timeout_secs, vb);
3141 }
3142 
3143 #else           /* (HAVE_NVME && (! IGNORE_NVME)) */
3144 
3145 int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int vb)3146 do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb)
3147 {
3148     if (vb) {
3149         pr2ws("%s: not supported, ", __func__);
3150 #ifdef HAVE_NVME
3151         pr2ws("HAVE_NVME, ");
3152 #else
3153         pr2ws("don't HAVE_NVME, ");
3154 #endif
3155 
3156 #ifdef IGNORE_NVME
3157         pr2ws("IGNORE_NVME");
3158 #else
3159         pr2ws("don't IGNORE_NVME");
3160 #endif
3161     }
3162     if (vp) { }
3163     if (submq) { }
3164     if (timeout_secs) { }
3165     return SCSI_PT_DO_NOT_SUPPORTED;
3166 }
3167 
3168 #endif          /* (HAVE_NVME && (! IGNORE_NVME)) */
3169