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