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