1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * Copyright (c) 2006-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_win32 version 1.34 20210503 */
11*44704f69SBart Van Assche
12*44704f69SBart Van Assche #include <stdio.h>
13*44704f69SBart Van Assche #include <stdlib.h>
14*44704f69SBart Van Assche #include <stddef.h>
15*44704f69SBart Van Assche #include <stdarg.h>
16*44704f69SBart Van Assche #include <string.h>
17*44704f69SBart Van Assche #include <errno.h>
18*44704f69SBart Van Assche #include <ctype.h>
19*44704f69SBart Van Assche #include <fcntl.h>
20*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
21*44704f69SBart Van Assche #include <inttypes.h>
22*44704f69SBart Van Assche
23*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
24*44704f69SBart Van Assche #include "config.h"
25*44704f69SBart Van Assche #endif
26*44704f69SBart Van Assche
27*44704f69SBart Van Assche #include "sg_lib.h"
28*44704f69SBart Van Assche #include "sg_unaligned.h"
29*44704f69SBart Van Assche #include "sg_pt.h"
30*44704f69SBart Van Assche #include "sg_pt_win32.h"
31*44704f69SBart Van Assche #include "sg_pt_nvme.h"
32*44704f69SBart Van Assche #include "sg_pr2serr.h"
33*44704f69SBart Van Assche
34*44704f69SBart Van Assche
35*44704f69SBart Van Assche /* Comment the following line out to use the pre-W10 NVMe pass-through */
36*44704f69SBart Van Assche #define W10_NVME_NON_PASSTHRU 1
37*44704f69SBart Van Assche
38*44704f69SBart Van Assche #ifndef O_EXCL
39*44704f69SBart Van Assche // #define O_EXCL 0x80 // cygwin ??
40*44704f69SBart Van Assche // #define O_EXCL 0x80 // Linux
41*44704f69SBart Van Assche #define O_EXCL 0x400 // mingw
42*44704f69SBart Van Assche #warning "O_EXCL not defined"
43*44704f69SBart Van Assche #endif
44*44704f69SBart Van Assche
45*44704f69SBart Van Assche #define SCSI_INQUIRY_OPC 0x12
46*44704f69SBart Van Assche #define SCSI_REPORT_LUNS_OPC 0xa0
47*44704f69SBart Van Assche #define SCSI_TEST_UNIT_READY_OPC 0x0
48*44704f69SBart Van Assche #define SCSI_REQUEST_SENSE_OPC 0x3
49*44704f69SBart Van Assche #define SCSI_SEND_DIAGNOSTIC_OPC 0x1d
50*44704f69SBart Van Assche #define SCSI_RECEIVE_DIAGNOSTIC_OPC 0x1c
51*44704f69SBart Van Assche #define SCSI_MAINT_IN_OPC 0xa3
52*44704f69SBart Van Assche #define SCSI_REP_SUP_OPCS_OPC 0xc
53*44704f69SBart Van Assche #define SCSI_REP_SUP_TMFS_OPC 0xd
54*44704f69SBart Van Assche #define SCSI_MODE_SENSE10_OPC 0x5a
55*44704f69SBart Van Assche #define SCSI_MODE_SELECT10_OPC 0x55
56*44704f69SBart Van Assche
57*44704f69SBart Van Assche /* Additional Sense Code (ASC) */
58*44704f69SBart Van Assche #define NO_ADDITIONAL_SENSE 0x0
59*44704f69SBart Van Assche #define LOGICAL_UNIT_NOT_READY 0x4
60*44704f69SBart Van Assche #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
61*44704f69SBart Van Assche #define UNRECOVERED_READ_ERR 0x11
62*44704f69SBart Van Assche #define PARAMETER_LIST_LENGTH_ERR 0x1a
63*44704f69SBart Van Assche #define INVALID_OPCODE 0x20
64*44704f69SBart Van Assche #define LBA_OUT_OF_RANGE 0x21
65*44704f69SBart Van Assche #define INVALID_FIELD_IN_CDB 0x24
66*44704f69SBart Van Assche #define INVALID_FIELD_IN_PARAM_LIST 0x26
67*44704f69SBart Van Assche #define UA_RESET_ASC 0x29
68*44704f69SBart Van Assche #define UA_CHANGED_ASC 0x2a
69*44704f69SBart Van Assche #define TARGET_CHANGED_ASC 0x3f
70*44704f69SBart Van Assche #define LUNS_CHANGED_ASCQ 0x0e
71*44704f69SBart Van Assche #define INSUFF_RES_ASC 0x55
72*44704f69SBart Van Assche #define INSUFF_RES_ASCQ 0x3
73*44704f69SBart Van Assche #define LOW_POWER_COND_ON_ASC 0x5e /* ASCQ=0 */
74*44704f69SBart Van Assche #define POWER_ON_RESET_ASCQ 0x0
75*44704f69SBart Van Assche #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
76*44704f69SBart Van Assche #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
77*44704f69SBart Van Assche #define CAPACITY_CHANGED_ASCQ 0x9
78*44704f69SBart Van Assche #define SAVING_PARAMS_UNSUP 0x39
79*44704f69SBart Van Assche #define TRANSPORT_PROBLEM 0x4b
80*44704f69SBart Van Assche #define THRESHOLD_EXCEEDED 0x5d
81*44704f69SBart Van Assche #define LOW_POWER_COND_ON 0x5e
82*44704f69SBart Van Assche #define MISCOMPARE_VERIFY_ASC 0x1d
83*44704f69SBart Van Assche #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
84*44704f69SBart Van Assche #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
85*44704f69SBart Van Assche
86*44704f69SBart Van Assche /* Use the Microsoft SCSI Pass Through (SPT) interface. It has two
87*44704f69SBart Van Assche * variants: "SPT" where data is double buffered; and "SPTD" where data
88*44704f69SBart Van Assche * pointers to the user space are passed to the OS. Only Windows
89*44704f69SBart Van Assche * 2000 and later (i.e. not 95,98 or ME).
90*44704f69SBart Van Assche * There is no ASPI interface which relies on a dll from adaptec.
91*44704f69SBart Van Assche * This code uses cygwin facilities and is built in a cygwin
92*44704f69SBart Van Assche * shell. It can be run in a normal DOS shell if the cygwin1.dll
93*44704f69SBart Van Assche * file is put in an appropriate place.
94*44704f69SBart Van Assche * This code can build in a MinGW environment.
95*44704f69SBart Van Assche *
96*44704f69SBart Van Assche * N.B. MSDN says that the "SPT" interface (i.e. double buffered)
97*44704f69SBart Van Assche * should be used for small amounts of data (it says "< 16 KB").
98*44704f69SBart Van Assche * The direct variant (i.e. IOCTL_SCSI_PASS_THROUGH_DIRECT) should
99*44704f69SBart Van Assche * be used for larger amounts of data but the buffer needs to be
100*44704f69SBart Van Assche * "cache aligned". Is that 16 byte alignment or greater?
101*44704f69SBart Van Assche *
102*44704f69SBart Van Assche * This code will default to indirect (i.e. double buffered) access
103*44704f69SBart Van Assche * unless the WIN32_SPT_DIRECT preprocessor constant is defined in
104*44704f69SBart Van Assche * config.h . In version 1.12 runtime selection of direct and indirect
105*44704f69SBart Van Assche * access was added; the default is still determined by the
106*44704f69SBart Van Assche * WIN32_SPT_DIRECT preprocessor constant.
107*44704f69SBart Van Assche */
108*44704f69SBart Van Assche
109*44704f69SBart Van Assche #define DEF_TIMEOUT 60 /* 60 seconds */
110*44704f69SBart Van Assche #define MAX_OPEN_SIMULT 8
111*44704f69SBart Van Assche #define WIN32_FDOFFSET 32
112*44704f69SBart Van Assche
113*44704f69SBart Van Assche union STORAGE_DEVICE_DESCRIPTOR_DATA {
114*44704f69SBart Van Assche STORAGE_DEVICE_DESCRIPTOR desc;
115*44704f69SBart Van Assche char raw[256];
116*44704f69SBart Van Assche };
117*44704f69SBart Van Assche
118*44704f69SBart Van Assche union STORAGE_DEVICE_UID_DATA {
119*44704f69SBart Van Assche STORAGE_DEVICE_UNIQUE_IDENTIFIER desc;
120*44704f69SBart Van Assche char raw[1060];
121*44704f69SBart Van Assche };
122*44704f69SBart Van Assche
123*44704f69SBart Van Assche
124*44704f69SBart Van Assche struct sg_pt_handle {
125*44704f69SBart Van Assche bool in_use;
126*44704f69SBart Van Assche bool not_claimed;
127*44704f69SBart Van Assche bool checked_handle;
128*44704f69SBart Van Assche bool bus_type_failed;
129*44704f69SBart Van Assche bool is_nvme;
130*44704f69SBart Van Assche bool got_physical_drive;
131*44704f69SBart Van Assche HANDLE fh;
132*44704f69SBart Van Assche char adapter[32]; /* for example: '\\.\scsi3' */
133*44704f69SBart Van Assche int bus; /* a.k.a. PathId in MS docs */
134*44704f69SBart Van Assche int target;
135*44704f69SBart Van Assche int lun;
136*44704f69SBart Van Assche int scsi_pdt; /* Peripheral Device Type, PDT_ALL if not known */
137*44704f69SBart Van Assche // uint32_t nvme_nsid; /* how do we find this given file handle ?? */
138*44704f69SBart Van Assche int verbose; /* tunnel verbose through to scsi_pt_close_device */
139*44704f69SBart Van Assche char dname[20];
140*44704f69SBart Van Assche struct sg_sntl_dev_state_t dev_stat; // owner
141*44704f69SBart Van Assche };
142*44704f69SBart Van Assche
143*44704f69SBart Van Assche /* Start zeroed but need to zeroed before use because could be re-use */
144*44704f69SBart Van Assche static struct sg_pt_handle handle_arr[MAX_OPEN_SIMULT];
145*44704f69SBart Van Assche
146*44704f69SBart Van Assche struct sg_pt_win32_scsi {
147*44704f69SBart Van Assche bool is_nvme;
148*44704f69SBart Van Assche bool nvme_direct; /* false: our SNTL; true: received NVMe command */
149*44704f69SBart Van Assche bool mdxfer_out; /* direction of metadata xfer, true->data-out */
150*44704f69SBart Van Assche bool have_nvme_cmd;
151*44704f69SBart Van Assche bool is_read;
152*44704f69SBart Van Assche int sense_len;
153*44704f69SBart Van Assche int scsi_status;
154*44704f69SBart Van Assche int resid;
155*44704f69SBart Van Assche int sense_resid;
156*44704f69SBart Van Assche int in_err;
157*44704f69SBart Van Assche int os_err; /* pseudo unix error */
158*44704f69SBart Van Assche int transport_err; /* windows error number */
159*44704f69SBart Van Assche int dev_fd; /* -1 for no "file descriptor" given */
160*44704f69SBart Van Assche uint32_t nvme_nsid; /* 1 to 0xfffffffe are possibly valid, 0
161*44704f69SBart Van Assche * implies dev_fd is not a NVMe device
162*44704f69SBart Van Assche * (is_nvme=false) or has no storage (e.g.
163*44704f69SBart Van Assche * enclosure rather than disk) */
164*44704f69SBart Van Assche uint32_t nvme_result; /* DW0 from completion queue */
165*44704f69SBart Van Assche uint32_t nvme_status; /* SCT|SC: DW3 27:17 from completion queue,
166*44704f69SBart Van Assche * note: the DNR+More bit are not there.
167*44704f69SBart Van Assche * The whole 16 byte completion q entry is
168*44704f69SBart Van Assche * sent back as sense data */
169*44704f69SBart Van Assche uint32_t dxfer_len;
170*44704f69SBart Van Assche uint32_t mdxfer_len;
171*44704f69SBart Van Assche uint8_t * dxferp;
172*44704f69SBart Van Assche uint8_t * mdxferp; /* NVMe has metadata buffer */
173*44704f69SBart Van Assche uint8_t * sensep;
174*44704f69SBart Van Assche uint8_t * nvme_id_ctlp;
175*44704f69SBart Van Assche uint8_t * free_nvme_id_ctlp;
176*44704f69SBart Van Assche struct sg_sntl_dev_state_t * dev_statp; /* points to handle's dev_stat */
177*44704f69SBart Van Assche uint8_t nvme_cmd[64];
178*44704f69SBart Van Assche union {
179*44704f69SBart Van Assche SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb_d;
180*44704f69SBart Van Assche /* Last entry in structure so data buffer can be extended */
181*44704f69SBart Van Assche SCSI_PASS_THROUGH_WITH_BUFFERS swb_i;
182*44704f69SBart Van Assche };
183*44704f69SBart Van Assche };
184*44704f69SBart Van Assche
185*44704f69SBart Van Assche /* embed pointer so can change on fly if (non-direct) data buffer
186*44704f69SBart Van Assche * is not big enough */
187*44704f69SBart Van Assche struct sg_pt_base {
188*44704f69SBart Van Assche struct sg_pt_win32_scsi * implp;
189*44704f69SBart Van Assche };
190*44704f69SBart Van Assche
191*44704f69SBart Van Assche #ifdef WIN32_SPT_DIRECT
192*44704f69SBart Van Assche static int spt_direct = 1;
193*44704f69SBart Van Assche #else
194*44704f69SBart Van Assche static int spt_direct = 0;
195*44704f69SBart Van Assche #endif
196*44704f69SBart Van Assche
197*44704f69SBart Van Assche static int nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
198*44704f69SBart Van Assche int time_secs, int vb);
199*44704f69SBart Van Assche
200*44704f69SBart Van Assche
201*44704f69SBart Van Assche /* Request SPT direct interface when state_direct is 1, state_direct set
202*44704f69SBart Van Assche * to 0 for the SPT indirect interface. */
203*44704f69SBart Van Assche void
scsi_pt_win32_direct(int state_direct)204*44704f69SBart Van Assche scsi_pt_win32_direct(int state_direct)
205*44704f69SBart Van Assche {
206*44704f69SBart Van Assche spt_direct = state_direct;
207*44704f69SBart Van Assche }
208*44704f69SBart Van Assche
209*44704f69SBart Van Assche /* Returns current SPT interface state, 1 for direct, 0 for indirect */
210*44704f69SBart Van Assche int
scsi_pt_win32_spt_state(void)211*44704f69SBart Van Assche scsi_pt_win32_spt_state(void)
212*44704f69SBart Van Assche {
213*44704f69SBart Van Assche return spt_direct;
214*44704f69SBart Van Assche }
215*44704f69SBart Van Assche
216*44704f69SBart Van Assche static const char *
bus_type_str(int bt)217*44704f69SBart Van Assche bus_type_str(int bt)
218*44704f69SBart Van Assche {
219*44704f69SBart Van Assche switch (bt)
220*44704f69SBart Van Assche {
221*44704f69SBart Van Assche case BusTypeUnknown:
222*44704f69SBart Van Assche return "Unknown";
223*44704f69SBart Van Assche case BusTypeScsi:
224*44704f69SBart Van Assche return "Scsi";
225*44704f69SBart Van Assche case BusTypeAtapi:
226*44704f69SBart Van Assche return "Atapi";
227*44704f69SBart Van Assche case BusTypeAta:
228*44704f69SBart Van Assche return "Ata";
229*44704f69SBart Van Assche case BusType1394:
230*44704f69SBart Van Assche return "1394";
231*44704f69SBart Van Assche case BusTypeSsa:
232*44704f69SBart Van Assche return "Ssa";
233*44704f69SBart Van Assche case BusTypeFibre:
234*44704f69SBart Van Assche return "Fibre";
235*44704f69SBart Van Assche case BusTypeUsb:
236*44704f69SBart Van Assche return "Usb";
237*44704f69SBart Van Assche case BusTypeRAID:
238*44704f69SBart Van Assche return "RAID";
239*44704f69SBart Van Assche case BusTypeiScsi:
240*44704f69SBart Van Assche return "iScsi";
241*44704f69SBart Van Assche case BusTypeSas:
242*44704f69SBart Van Assche return "Sas";
243*44704f69SBart Van Assche case BusTypeSata:
244*44704f69SBart Van Assche return "Sata";
245*44704f69SBart Van Assche case BusTypeSd:
246*44704f69SBart Van Assche return "Sd";
247*44704f69SBart Van Assche case BusTypeMmc:
248*44704f69SBart Van Assche return "Mmc";
249*44704f69SBart Van Assche case BusTypeVirtual:
250*44704f69SBart Van Assche return "Virt";
251*44704f69SBart Van Assche case BusTypeFileBackedVirtual:
252*44704f69SBart Van Assche return "FBVir";
253*44704f69SBart Van Assche #ifdef BusTypeSpaces
254*44704f69SBart Van Assche case BusTypeSpaces:
255*44704f69SBart Van Assche #else
256*44704f69SBart Van Assche case 0x10:
257*44704f69SBart Van Assche #endif
258*44704f69SBart Van Assche return "Spaces";
259*44704f69SBart Van Assche #ifdef BusTypeNvme
260*44704f69SBart Van Assche case BusTypeNvme:
261*44704f69SBart Van Assche #else
262*44704f69SBart Van Assche case 0x11:
263*44704f69SBart Van Assche #endif
264*44704f69SBart Van Assche return "NVMe";
265*44704f69SBart Van Assche #ifdef BusTypeSCM
266*44704f69SBart Van Assche case BusTypeSCM:
267*44704f69SBart Van Assche #else
268*44704f69SBart Van Assche case 0x12:
269*44704f69SBart Van Assche #endif
270*44704f69SBart Van Assche return "SCM";
271*44704f69SBart Van Assche #ifdef BusTypeUfs
272*44704f69SBart Van Assche case BusTypeUfs:
273*44704f69SBart Van Assche #else
274*44704f69SBart Van Assche case 0x13:
275*44704f69SBart Van Assche #endif
276*44704f69SBart Van Assche return "Ufs";
277*44704f69SBart Van Assche case 0x14:
278*44704f69SBart Van Assche return "Max";
279*44704f69SBart Van Assche case 0x7f:
280*44704f69SBart Van Assche return "Max Reserved";
281*44704f69SBart Van Assche default:
282*44704f69SBart Van Assche return "_unknown";
283*44704f69SBart Van Assche }
284*44704f69SBart Van Assche }
285*44704f69SBart Van Assche
286*44704f69SBart Van Assche static char *
get_err_str(DWORD err,int max_b_len,char * b)287*44704f69SBart Van Assche get_err_str(DWORD err, int max_b_len, char * b)
288*44704f69SBart Van Assche {
289*44704f69SBart Van Assche LPVOID lpMsgBuf;
290*44704f69SBart Van Assche int k, num, ch;
291*44704f69SBart Van Assche
292*44704f69SBart Van Assche memset(b, 0, max_b_len);
293*44704f69SBart Van Assche FormatMessage(
294*44704f69SBart Van Assche FORMAT_MESSAGE_ALLOCATE_BUFFER |
295*44704f69SBart Van Assche FORMAT_MESSAGE_FROM_SYSTEM,
296*44704f69SBart Van Assche NULL,
297*44704f69SBart Van Assche err,
298*44704f69SBart Van Assche MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
299*44704f69SBart Van Assche (LPTSTR) &lpMsgBuf,
300*44704f69SBart Van Assche 0, NULL );
301*44704f69SBart Van Assche num = lstrlen((LPCTSTR)lpMsgBuf);
302*44704f69SBart Van Assche if (num < 1)
303*44704f69SBart Van Assche return b;
304*44704f69SBart Van Assche num = (num < max_b_len) ? num : (max_b_len - 1);
305*44704f69SBart Van Assche for (k = 0; k < num; ++k) {
306*44704f69SBart Van Assche ch = *((LPCTSTR)lpMsgBuf + k);
307*44704f69SBart Van Assche if ((ch >= 0x0) && (ch < 0x7f))
308*44704f69SBart Van Assche b[k] = ch & 0x7f;
309*44704f69SBart Van Assche else
310*44704f69SBart Van Assche b[k] = '?';
311*44704f69SBart Van Assche }
312*44704f69SBart Van Assche return b;
313*44704f69SBart Van Assche }
314*44704f69SBart Van Assche
315*44704f69SBart Van Assche /* Returns pointer to sg_pt_handle object given Unix like device_fd. If
316*44704f69SBart Van Assche * device_fd is invalid or not open returns NULL. If psp is non-NULL and
317*44704f69SBart Van Assche * NULL is returned then ENODEV is placed in psp->os_err. */
318*44704f69SBart Van Assche static struct sg_pt_handle *
get_open_pt_handle(struct sg_pt_win32_scsi * psp,int device_fd,bool vbb)319*44704f69SBart Van Assche get_open_pt_handle(struct sg_pt_win32_scsi * psp, int device_fd, bool vbb)
320*44704f69SBart Van Assche {
321*44704f69SBart Van Assche int index = device_fd - WIN32_FDOFFSET;
322*44704f69SBart Van Assche struct sg_pt_handle * shp;
323*44704f69SBart Van Assche
324*44704f69SBart Van Assche if ((index < 0) || (index >= WIN32_FDOFFSET)) {
325*44704f69SBart Van Assche if (vbb)
326*44704f69SBart Van Assche pr2ws("Bad file descriptor\n");
327*44704f69SBart Van Assche if (psp)
328*44704f69SBart Van Assche psp->os_err = EBADF;
329*44704f69SBart Van Assche return NULL;
330*44704f69SBart Van Assche }
331*44704f69SBart Van Assche shp = handle_arr + index;
332*44704f69SBart Van Assche if (! shp->in_use) {
333*44704f69SBart Van Assche if (vbb)
334*44704f69SBart Van Assche pr2ws("File descriptor closed??\n");
335*44704f69SBart Van Assche if (psp)
336*44704f69SBart Van Assche psp->os_err = ENODEV;
337*44704f69SBart Van Assche return NULL;
338*44704f69SBart Van Assche }
339*44704f69SBart Van Assche return shp;
340*44704f69SBart Van Assche }
341*44704f69SBart Van Assche
342*44704f69SBart Van Assche
343*44704f69SBart Van Assche /* Returns >= 0 if successful. If error in Unix returns negated errno. */
344*44704f69SBart Van Assche int
scsi_pt_open_device(const char * device_name,bool read_only,int vb)345*44704f69SBart Van Assche scsi_pt_open_device(const char * device_name, bool read_only, int vb)
346*44704f69SBart Van Assche {
347*44704f69SBart Van Assche int oflags = 0 /* O_NONBLOCK*/ ;
348*44704f69SBart Van Assche
349*44704f69SBart Van Assche oflags |= (read_only ? 0 : 0); /* was ... ? O_RDONLY : O_RDWR) */
350*44704f69SBart Van Assche return scsi_pt_open_flags(device_name, oflags, vb);
351*44704f69SBart Van Assche }
352*44704f69SBart Van Assche
353*44704f69SBart Van Assche /*
354*44704f69SBart Van Assche * Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed
355*44704f69SBart Van Assche * together. The 'flags' argument is ignored in Windows.
356*44704f69SBart Van Assche * Returns >= 0 if successful, otherwise returns negated errno.
357*44704f69SBart Van Assche * Optionally accept leading "\\.\". If given something of the form
358*44704f69SBart Van Assche * "SCSI<num>:<bus>,<target>,<lun>" where the values in angle brackets
359*44704f69SBart Van Assche * are integers, then will attempt to open "\\.\SCSI<num>:" and save the
360*44704f69SBart Van Assche * other three values for the DeviceIoControl call. The trailing ".<lun>"
361*44704f69SBart Van Assche * is optionally and if not given 0 is assumed. Since "PhysicalDrive"
362*44704f69SBart Van Assche * is a lot of keystrokes, "PD" is accepted and converted to the longer
363*44704f69SBart Van Assche * form.
364*44704f69SBart Van Assche */
365*44704f69SBart Van Assche int
scsi_pt_open_flags(const char * device_name,int flags,int vb)366*44704f69SBart Van Assche scsi_pt_open_flags(const char * device_name, int flags, int vb)
367*44704f69SBart Van Assche {
368*44704f69SBart Van Assche bool got_scsi_name = false;
369*44704f69SBart Van Assche int len, k, adapter_num, bus, target, lun, off, index, num, pd_num;
370*44704f69SBart Van Assche int share_mode;
371*44704f69SBart Van Assche struct sg_pt_handle * shp;
372*44704f69SBart Van Assche char buff[8];
373*44704f69SBart Van Assche
374*44704f69SBart Van Assche share_mode = (O_EXCL & flags) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
375*44704f69SBart Van Assche /* lock */
376*44704f69SBart Van Assche for (k = 0; k < MAX_OPEN_SIMULT; k++)
377*44704f69SBart Van Assche if (! handle_arr[k].in_use)
378*44704f69SBart Van Assche break;
379*44704f69SBart Van Assche if (k == MAX_OPEN_SIMULT) {
380*44704f69SBart Van Assche if (vb)
381*44704f69SBart Van Assche pr2ws("too many open handles (%d)\n", MAX_OPEN_SIMULT);
382*44704f69SBart Van Assche return -EMFILE;
383*44704f69SBart Van Assche } else {
384*44704f69SBart Van Assche /* clear any previous contents */
385*44704f69SBart Van Assche memset(handle_arr + k, 0, sizeof(struct sg_pt_handle));
386*44704f69SBart Van Assche handle_arr[k].in_use = true;
387*44704f69SBart Van Assche }
388*44704f69SBart Van Assche /* unlock */
389*44704f69SBart Van Assche index = k;
390*44704f69SBart Van Assche shp = handle_arr + index;
391*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
392*44704f69SBart Van Assche sntl_init_dev_stat(&shp->dev_stat);
393*44704f69SBart Van Assche #endif
394*44704f69SBart Van Assche adapter_num = 0;
395*44704f69SBart Van Assche bus = 0; /* also known as 'PathId' in MS docs */
396*44704f69SBart Van Assche target = 0;
397*44704f69SBart Van Assche lun = 0;
398*44704f69SBart Van Assche len = (int)strlen(device_name);
399*44704f69SBart Van Assche k = (int)sizeof(shp->dname);
400*44704f69SBart Van Assche if (len < k)
401*44704f69SBart Van Assche strcpy(shp->dname, device_name);
402*44704f69SBart Van Assche else if (len == k)
403*44704f69SBart Van Assche memcpy(shp->dname, device_name, k - 1);
404*44704f69SBart Van Assche else /* trim on left */
405*44704f69SBart Van Assche memcpy(shp->dname, device_name + (len - k), k - 1);
406*44704f69SBart Van Assche shp->dname[k - 1] = '\0';
407*44704f69SBart Van Assche if ((len > 4) && (0 == strncmp("\\\\.\\", device_name, 4)))
408*44704f69SBart Van Assche off = 4;
409*44704f69SBart Van Assche else
410*44704f69SBart Van Assche off = 0;
411*44704f69SBart Van Assche if (len > (off + 2)) {
412*44704f69SBart Van Assche buff[0] = toupper((int)device_name[off + 0]);
413*44704f69SBart Van Assche buff[1] = toupper((int)device_name[off + 1]);
414*44704f69SBart Van Assche if (0 == strncmp("PD", buff, 2)) {
415*44704f69SBart Van Assche num = sscanf(device_name + off + 2, "%d", &pd_num);
416*44704f69SBart Van Assche if (1 == num)
417*44704f69SBart Van Assche shp->got_physical_drive = true;
418*44704f69SBart Van Assche }
419*44704f69SBart Van Assche if (! shp->got_physical_drive) {
420*44704f69SBart Van Assche buff[2] = toupper((int)device_name[off + 2]);
421*44704f69SBart Van Assche buff[3] = toupper((int)device_name[off + 3]);
422*44704f69SBart Van Assche if (0 == strncmp("SCSI", buff, 4)) {
423*44704f69SBart Van Assche num = sscanf(device_name + off + 4, "%d:%d,%d,%d",
424*44704f69SBart Van Assche &adapter_num, &bus, &target, &lun);
425*44704f69SBart Van Assche if (num < 3) {
426*44704f69SBart Van Assche if (vb)
427*44704f69SBart Van Assche pr2ws("expected format like: "
428*44704f69SBart Van Assche "'SCSI<port>:<bus>,<target>[,<lun>]'\n");
429*44704f69SBart Van Assche shp->in_use = false;
430*44704f69SBart Van Assche return -EINVAL;
431*44704f69SBart Van Assche }
432*44704f69SBart Van Assche got_scsi_name = true;
433*44704f69SBart Van Assche }
434*44704f69SBart Van Assche }
435*44704f69SBart Van Assche }
436*44704f69SBart Van Assche shp->bus = bus;
437*44704f69SBart Van Assche shp->target = target;
438*44704f69SBart Van Assche shp->lun = lun;
439*44704f69SBart Van Assche shp->scsi_pdt = PDT_ALL;
440*44704f69SBart Van Assche shp->verbose = vb;
441*44704f69SBart Van Assche memset(shp->adapter, 0, sizeof(shp->adapter));
442*44704f69SBart Van Assche memcpy(shp->adapter, "\\\\.\\", 4);
443*44704f69SBart Van Assche if (shp->got_physical_drive)
444*44704f69SBart Van Assche snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5,
445*44704f69SBart Van Assche "PhysicalDrive%d", pd_num);
446*44704f69SBart Van Assche else if (got_scsi_name)
447*44704f69SBart Van Assche snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5, "SCSI%d:",
448*44704f69SBart Van Assche adapter_num);
449*44704f69SBart Van Assche else
450*44704f69SBart Van Assche snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5, "%s",
451*44704f69SBart Van Assche device_name + off);
452*44704f69SBart Van Assche if (vb > 4)
453*44704f69SBart Van Assche pr2ws("%s: CreateFile('%s'), bus=%d, target=%d, lun=%d\n", __func__,
454*44704f69SBart Van Assche shp->adapter, bus, target, lun);
455*44704f69SBart Van Assche #if 1
456*44704f69SBart Van Assche shp->fh = CreateFile(shp->adapter, GENERIC_READ | GENERIC_WRITE,
457*44704f69SBart Van Assche share_mode, NULL, OPEN_EXISTING, 0, NULL);
458*44704f69SBart Van Assche #endif
459*44704f69SBart Van Assche
460*44704f69SBart Van Assche #if 0
461*44704f69SBart Van Assche shp->fh = CreateFileA(shp->adapter, GENERIC_READ|GENERIC_WRITE,
462*44704f69SBart Van Assche FILE_SHARE_READ|FILE_SHARE_WRITE,
463*44704f69SBart Van Assche (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
464*44704f69SBart Van Assche // No GENERIC_READ/WRITE access required, works without admin rights (W10)
465*44704f69SBart Van Assche shp->fh = CreateFileA(shp->adapter, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
466*44704f69SBart Van Assche (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, (HANDLE)0);
467*44704f69SBart Van Assche #endif
468*44704f69SBart Van Assche if (shp->fh == INVALID_HANDLE_VALUE) {
469*44704f69SBart Van Assche if (vb) {
470*44704f69SBart Van Assche uint32_t err = (uint32_t)GetLastError();
471*44704f69SBart Van Assche char b[128];
472*44704f69SBart Van Assche
473*44704f69SBart Van Assche pr2ws("%s: CreateFile error: %s [%u]\n", __func__,
474*44704f69SBart Van Assche get_err_str(err, sizeof(b), b), err);
475*44704f69SBart Van Assche }
476*44704f69SBart Van Assche shp->in_use = false;
477*44704f69SBart Van Assche return -ENODEV;
478*44704f69SBart Van Assche }
479*44704f69SBart Van Assche return index + WIN32_FDOFFSET;
480*44704f69SBart Van Assche }
481*44704f69SBart Van Assche
482*44704f69SBart Van Assche /* Returns 0 if successful. If device_id seems wild returns -ENODEV,
483*44704f69SBart Van Assche * other errors return 0. If CloseHandle() fails and verbose > 0 then
484*44704f69SBart Van Assche * outputs warning with value from GetLastError(). The verbose value
485*44704f69SBart Van Assche * defaults to zero and is potentially set from the most recent call
486*44704f69SBart Van Assche * to scsi_pt_open_device() or do_scsi_pt(). */
487*44704f69SBart Van Assche int
scsi_pt_close_device(int device_fd)488*44704f69SBart Van Assche scsi_pt_close_device(int device_fd)
489*44704f69SBart Van Assche {
490*44704f69SBart Van Assche struct sg_pt_handle * shp = get_open_pt_handle(NULL, device_fd, false);
491*44704f69SBart Van Assche
492*44704f69SBart Van Assche if (NULL == shp)
493*44704f69SBart Van Assche return -ENODEV;
494*44704f69SBart Van Assche if ((! CloseHandle(shp->fh)) && shp->verbose)
495*44704f69SBart Van Assche pr2ws("Windows CloseHandle error=%u\n", (unsigned int)GetLastError());
496*44704f69SBart Van Assche shp->bus = 0;
497*44704f69SBart Van Assche shp->target = 0;
498*44704f69SBart Van Assche shp->lun = 0;
499*44704f69SBart Van Assche memset(shp->adapter, 0, sizeof(shp->adapter));
500*44704f69SBart Van Assche shp->in_use = false;
501*44704f69SBart Van Assche shp->verbose = 0;
502*44704f69SBart Van Assche shp->dname[0] = '\0';
503*44704f69SBart Van Assche return 0;
504*44704f69SBart Van Assche }
505*44704f69SBart Van Assche
506*44704f69SBart Van Assche /* Attempt to return device's SCSI peripheral device type (pdt), a number
507*44704f69SBart Van Assche * between 0 (disks) and 31 (not given) by calling IOCTL_SCSI_GET_INQUIRY_DATA
508*44704f69SBart Van Assche * on the adapter. Returns -EIO on error and -999 if not found. */
509*44704f69SBart Van Assche static int
get_scsi_pdt(struct sg_pt_handle * shp,int vb)510*44704f69SBart Van Assche get_scsi_pdt(struct sg_pt_handle *shp, int vb)
511*44704f69SBart Van Assche {
512*44704f69SBart Van Assche const int alloc_sz = 8192;
513*44704f69SBart Van Assche int j;
514*44704f69SBart Van Assche int ret = -999;
515*44704f69SBart Van Assche BOOL ok;
516*44704f69SBart Van Assche ULONG dummy;
517*44704f69SBart Van Assche DWORD err;
518*44704f69SBart Van Assche BYTE wbus;
519*44704f69SBart Van Assche uint8_t * inqBuf;
520*44704f69SBart Van Assche uint8_t * free_inqBuf;
521*44704f69SBart Van Assche char b[128];
522*44704f69SBart Van Assche
523*44704f69SBart Van Assche if (vb > 2)
524*44704f69SBart Van Assche pr2ws("%s: enter, adapter: %s\n", __func__, shp->adapter);
525*44704f69SBart Van Assche inqBuf = sg_memalign(alloc_sz, 0 /* page size */, &free_inqBuf, false);
526*44704f69SBart Van Assche if (NULL == inqBuf) {
527*44704f69SBart Van Assche pr2ws("%s: unable to allocate %d bytes\n", __func__, alloc_sz);
528*44704f69SBart Van Assche return -ENOMEM;
529*44704f69SBart Van Assche }
530*44704f69SBart Van Assche ok = DeviceIoControl(shp->fh, IOCTL_SCSI_GET_INQUIRY_DATA,
531*44704f69SBart Van Assche NULL, 0, inqBuf, alloc_sz, &dummy, NULL);
532*44704f69SBart Van Assche if (ok) {
533*44704f69SBart Van Assche PSCSI_ADAPTER_BUS_INFO ai;
534*44704f69SBart Van Assche PSCSI_BUS_DATA pbd;
535*44704f69SBart Van Assche PSCSI_INQUIRY_DATA pid;
536*44704f69SBart Van Assche int num_lus, off;
537*44704f69SBart Van Assche
538*44704f69SBart Van Assche ai = (PSCSI_ADAPTER_BUS_INFO)inqBuf;
539*44704f69SBart Van Assche for (wbus = 0; wbus < ai->NumberOfBusses; ++wbus) {
540*44704f69SBart Van Assche pbd = ai->BusData + wbus;
541*44704f69SBart Van Assche num_lus = pbd->NumberOfLogicalUnits;
542*44704f69SBart Van Assche off = pbd->InquiryDataOffset;
543*44704f69SBart Van Assche for (j = 0; j < num_lus; ++j) {
544*44704f69SBart Van Assche if ((off < (int)sizeof(SCSI_ADAPTER_BUS_INFO)) ||
545*44704f69SBart Van Assche (off > (alloc_sz - (int)sizeof(SCSI_INQUIRY_DATA))))
546*44704f69SBart Van Assche break;
547*44704f69SBart Van Assche pid = (PSCSI_INQUIRY_DATA)(inqBuf + off);
548*44704f69SBart Van Assche if ((shp->bus == pid->PathId) &&
549*44704f69SBart Van Assche (shp->target == pid->TargetId) &&
550*44704f69SBart Van Assche (shp->lun == pid->Lun)) { /* got match */
551*44704f69SBart Van Assche shp->scsi_pdt = pid->InquiryData[0] & PDT_MASK;
552*44704f69SBart Van Assche shp->not_claimed = ! pid->DeviceClaimed;
553*44704f69SBart Van Assche shp->checked_handle = true;
554*44704f69SBart Van Assche shp->bus_type_failed = false;
555*44704f69SBart Van Assche if (vb > 3)
556*44704f69SBart Van Assche pr2ws("%s: found, scsi_pdt=%d, claimed=%d, "
557*44704f69SBart Van Assche "target=%d, lun=%d\n", __func__, shp->scsi_pdt,
558*44704f69SBart Van Assche pid->DeviceClaimed, shp->target, shp->lun);
559*44704f69SBart Van Assche ret = shp->scsi_pdt;
560*44704f69SBart Van Assche goto fini;
561*44704f69SBart Van Assche }
562*44704f69SBart Van Assche off = pid->NextInquiryDataOffset;
563*44704f69SBart Van Assche }
564*44704f69SBart Van Assche }
565*44704f69SBart Van Assche } else {
566*44704f69SBart Van Assche err = GetLastError();
567*44704f69SBart Van Assche if (vb > 1)
568*44704f69SBart Van Assche pr2ws("%s: IOCTL_SCSI_GET_INQUIRY_DATA failed err=%u\n\t%s",
569*44704f69SBart Van Assche shp->adapter, (unsigned int)err,
570*44704f69SBart Van Assche get_err_str(err, sizeof(b), b));
571*44704f69SBart Van Assche ret = -EIO;
572*44704f69SBart Van Assche }
573*44704f69SBart Van Assche fini:
574*44704f69SBart Van Assche if (free_inqBuf)
575*44704f69SBart Van Assche free(free_inqBuf);
576*44704f69SBart Van Assche return ret; /* no match after checking all PathIds, Targets and LUs */
577*44704f69SBart Van Assche }
578*44704f69SBart Van Assche
579*44704f69SBart Van Assche /* Returns 0 on success, negated errno if error */
580*44704f69SBart Van Assche static int
get_bus_type(struct sg_pt_handle * shp,const char * dname,STORAGE_BUS_TYPE * btp,int vb)581*44704f69SBart Van Assche get_bus_type(struct sg_pt_handle *shp, const char *dname,
582*44704f69SBart Van Assche STORAGE_BUS_TYPE * btp, int vb)
583*44704f69SBart Van Assche {
584*44704f69SBart Van Assche DWORD num_out, err;
585*44704f69SBart Van Assche STORAGE_BUS_TYPE bt;
586*44704f69SBart Van Assche union STORAGE_DEVICE_DESCRIPTOR_DATA sddd;
587*44704f69SBart Van Assche STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty,
588*44704f69SBart Van Assche PropertyStandardQuery, {0} };
589*44704f69SBart Van Assche char b[256];
590*44704f69SBart Van Assche
591*44704f69SBart Van Assche memset(&sddd, 0, sizeof(sddd));
592*44704f69SBart Van Assche if (! DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY,
593*44704f69SBart Van Assche &query, sizeof(query), &sddd, sizeof(sddd),
594*44704f69SBart Van Assche &num_out, NULL)) {
595*44704f69SBart Van Assche if (vb > 2) {
596*44704f69SBart Van Assche err = GetLastError();
597*44704f69SBart Van Assche pr2ws("%s IOCTL_STORAGE_QUERY_PROPERTY(Devprop) failed, "
598*44704f69SBart Van Assche "Error: %s [%u]\n", dname, get_err_str(err, sizeof(b), b),
599*44704f69SBart Van Assche (uint32_t)err);
600*44704f69SBart Van Assche }
601*44704f69SBart Van Assche shp->bus_type_failed = true;
602*44704f69SBart Van Assche return -EIO;
603*44704f69SBart Van Assche }
604*44704f69SBart Van Assche bt = sddd.desc.BusType;
605*44704f69SBart Van Assche if (vb > 2) {
606*44704f69SBart Van Assche pr2ws("%s: Bus type: %s\n", __func__, bus_type_str((int)bt));
607*44704f69SBart Van Assche if (vb > 3) {
608*44704f69SBart Van Assche pr2ws("Storage Device Descriptor Data:\n");
609*44704f69SBart Van Assche hex2stderr((const uint8_t *)&sddd, num_out, 0);
610*44704f69SBart Van Assche }
611*44704f69SBart Van Assche }
612*44704f69SBart Van Assche if (shp) {
613*44704f69SBart Van Assche shp->checked_handle = true;
614*44704f69SBart Van Assche shp->bus_type_failed = false;
615*44704f69SBart Van Assche shp->is_nvme = (BusTypeNvme == bt);
616*44704f69SBart Van Assche }
617*44704f69SBart Van Assche if (btp)
618*44704f69SBart Van Assche *btp = bt;
619*44704f69SBart Van Assche return 0;
620*44704f69SBart Van Assche }
621*44704f69SBart Van Assche
622*44704f69SBart Van Assche /* Assumes dev_fd is an "open" file handle associated with device_name. If
623*44704f69SBart Van Assche * the implementation (possibly for one OS) cannot determine from dev_fd if
624*44704f69SBart Van Assche * a SCSI or NVMe pass-through is referenced, then it might guess based on
625*44704f69SBart Van Assche * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if
626*44704f69SBart Van Assche * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is
627*44704f69SBart Van Assche * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes
628*44704f69SBart Van Assche * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0.
629*44704f69SBart Van Assche * If error, returns negated errno (operating system) value. */
630*44704f69SBart Van Assche int
check_pt_file_handle(int device_fd,const char * device_name,int vb)631*44704f69SBart Van Assche check_pt_file_handle(int device_fd, const char * device_name, int vb)
632*44704f69SBart Van Assche {
633*44704f69SBart Van Assche int res;
634*44704f69SBart Van Assche STORAGE_BUS_TYPE bt;
635*44704f69SBart Van Assche const char * dnp = device_name;
636*44704f69SBart Van Assche struct sg_pt_handle * shp;
637*44704f69SBart Van Assche
638*44704f69SBart Van Assche if (vb > 3)
639*44704f69SBart Van Assche pr2ws("%s: device_name: %s\n", __func__, dnp);
640*44704f69SBart Van Assche shp = get_open_pt_handle(NULL, device_fd, vb > 1);
641*44704f69SBart Van Assche if (NULL == shp) {
642*44704f69SBart Van Assche pr2ws("%s: device_fd (%s) bad or not in_use ??\n", __func__,
643*44704f69SBart Van Assche dnp ? dnp : "");
644*44704f69SBart Van Assche return -ENODEV;
645*44704f69SBart Van Assche }
646*44704f69SBart Van Assche if (shp->bus_type_failed) {
647*44704f69SBart Van Assche if (vb > 2)
648*44704f69SBart Van Assche pr2ws("%s: skip because get_bus_type() has failed\n", __func__);
649*44704f69SBart Van Assche return 0;
650*44704f69SBart Van Assche }
651*44704f69SBart Van Assche dnp = dnp ? dnp : shp->dname;
652*44704f69SBart Van Assche res = get_bus_type(shp, dnp, &bt, vb);
653*44704f69SBart Van Assche if (res < 0) {
654*44704f69SBart Van Assche if (! shp->got_physical_drive) {
655*44704f69SBart Van Assche res = get_scsi_pdt(shp, vb);
656*44704f69SBart Van Assche if (res >= 0)
657*44704f69SBart Van Assche return 1;
658*44704f69SBart Van Assche }
659*44704f69SBart Van Assche return res;
660*44704f69SBart Van Assche }
661*44704f69SBart Van Assche return (BusTypeNvme == bt) ? 3 : 1;
662*44704f69SBart Van Assche /* NVMe "char" ?? device, could be enclosure: 3 */
663*44704f69SBart Van Assche /* SCSI generic pass-though device: 1 */
664*44704f69SBart Van Assche }
665*44704f69SBart Van Assche
666*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
667*44704f69SBart Van Assche static bool checked_ev_dsense = false;
668*44704f69SBart Van Assche static bool ev_dsense = false;
669*44704f69SBart Van Assche #endif
670*44704f69SBart Van Assche
671*44704f69SBart Van Assche struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int dev_fd,int vb)672*44704f69SBart Van Assche construct_scsi_pt_obj_with_fd(int dev_fd, int vb)
673*44704f69SBart Van Assche {
674*44704f69SBart Van Assche int res;
675*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp;
676*44704f69SBart Van Assche struct sg_pt_base * vp = NULL;
677*44704f69SBart Van Assche struct sg_pt_handle * shp = NULL;
678*44704f69SBart Van Assche
679*44704f69SBart Van Assche if (dev_fd >= 0) {
680*44704f69SBart Van Assche shp = get_open_pt_handle(NULL, dev_fd, vb > 1);
681*44704f69SBart Van Assche if (NULL == shp) {
682*44704f69SBart Van Assche if (vb)
683*44704f69SBart Van Assche pr2ws("%s: dev_fd is not open\n", __func__);
684*44704f69SBart Van Assche return NULL;
685*44704f69SBart Van Assche }
686*44704f69SBart Van Assche if (! (shp->bus_type_failed || shp->checked_handle)) {
687*44704f69SBart Van Assche res = get_bus_type(shp, shp->dname, NULL, vb);
688*44704f69SBart Van Assche if (res < 0) {
689*44704f69SBart Van Assche if (! shp->got_physical_drive)
690*44704f69SBart Van Assche res = get_scsi_pdt(shp, vb);
691*44704f69SBart Van Assche if ((res < 0) && (vb > 1))
692*44704f69SBart Van Assche pr2ws("%s: get_bus_type() errno=%d, continue\n", __func__,
693*44704f69SBart Van Assche -res);
694*44704f69SBart Van Assche }
695*44704f69SBart Van Assche }
696*44704f69SBart Van Assche }
697*44704f69SBart Van Assche psp = (struct sg_pt_win32_scsi *)calloc(sizeof(struct sg_pt_win32_scsi),
698*44704f69SBart Van Assche 1);
699*44704f69SBart Van Assche if (psp) {
700*44704f69SBart Van Assche psp->dev_fd = (dev_fd < 0) ? -1 : dev_fd;
701*44704f69SBart Van Assche if (shp) {
702*44704f69SBart Van Assche psp->is_nvme = shp->is_nvme;
703*44704f69SBart Van Assche psp->dev_statp = &shp->dev_stat;
704*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
705*44704f69SBart Van Assche sntl_init_dev_stat(psp->dev_statp);
706*44704f69SBart Van Assche if (! checked_ev_dsense) {
707*44704f69SBart Van Assche ev_dsense = sg_get_initial_dsense();
708*44704f69SBart Van Assche checked_ev_dsense = true;
709*44704f69SBart Van Assche }
710*44704f69SBart Van Assche shp->dev_stat.scsi_dsense = ev_dsense;
711*44704f69SBart Van Assche #endif
712*44704f69SBart Van Assche }
713*44704f69SBart Van Assche if (psp->is_nvme) {
714*44704f69SBart Van Assche ; /* should be 'psp->nvme_nsid = shp->nvme_nsid' */
715*44704f69SBart Van Assche } else if (spt_direct) {
716*44704f69SBart Van Assche psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
717*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
718*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoOffset =
719*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
720*44704f69SBart Van Assche psp->swb_d.spt.TimeOutValue = DEF_TIMEOUT;
721*44704f69SBart Van Assche } else {
722*44704f69SBart Van Assche psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
723*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
724*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoOffset =
725*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
726*44704f69SBart Van Assche psp->swb_i.spt.TimeOutValue = DEF_TIMEOUT;
727*44704f69SBart Van Assche }
728*44704f69SBart Van Assche vp = (struct sg_pt_base *)malloc(sizeof(struct sg_pt_win32_scsi *));
729*44704f69SBart Van Assche /* yes, allocating the size of a pointer (4 or 8 bytes) */
730*44704f69SBart Van Assche if (vp)
731*44704f69SBart Van Assche vp->implp = psp;
732*44704f69SBart Van Assche else
733*44704f69SBart Van Assche free(psp);
734*44704f69SBart Van Assche }
735*44704f69SBart Van Assche if ((NULL == vp) && vb)
736*44704f69SBart Van Assche pr2ws("%s: about to return NULL, space problem\n", __func__);
737*44704f69SBart Van Assche return vp;
738*44704f69SBart Van Assche }
739*44704f69SBart Van Assche
740*44704f69SBart Van Assche struct sg_pt_base *
construct_scsi_pt_obj(void)741*44704f69SBart Van Assche construct_scsi_pt_obj(void)
742*44704f69SBart Van Assche {
743*44704f69SBart Van Assche return construct_scsi_pt_obj_with_fd(-1, 0);
744*44704f69SBart Van Assche }
745*44704f69SBart Van Assche
746*44704f69SBart Van Assche void
destruct_scsi_pt_obj(struct sg_pt_base * vp)747*44704f69SBart Van Assche destruct_scsi_pt_obj(struct sg_pt_base * vp)
748*44704f69SBart Van Assche {
749*44704f69SBart Van Assche if (vp) {
750*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
751*44704f69SBart Van Assche
752*44704f69SBart Van Assche if (psp) {
753*44704f69SBart Van Assche free(psp);
754*44704f69SBart Van Assche }
755*44704f69SBart Van Assche free(vp);
756*44704f69SBart Van Assche }
757*44704f69SBart Van Assche }
758*44704f69SBart Van Assche
759*44704f69SBart Van Assche /* Forget any previous dev_han and install the one given. May attempt to
760*44704f69SBart Van Assche * find file type (e.g. if pass-though) from OS so there could be an error.
761*44704f69SBart Van Assche * Returns 0 for success or the same value as get_scsi_pt_os_err()
762*44704f69SBart Van Assche * will return. dev_han should be >= 0 for a valid file handle or -1 . */
763*44704f69SBart Van Assche int
set_pt_file_handle(struct sg_pt_base * vp,int dev_han,int vb)764*44704f69SBart Van Assche set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb)
765*44704f69SBart Van Assche {
766*44704f69SBart Van Assche int res;
767*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp;
768*44704f69SBart Van Assche
769*44704f69SBart Van Assche if (NULL == vp) {
770*44704f69SBart Van Assche if (vb)
771*44704f69SBart Van Assche pr2ws(">>>> %s: pointer to object is NULL\n", __func__);
772*44704f69SBart Van Assche return EINVAL;
773*44704f69SBart Van Assche }
774*44704f69SBart Van Assche if ((psp = vp->implp)) {
775*44704f69SBart Van Assche struct sg_pt_handle * shp;
776*44704f69SBart Van Assche
777*44704f69SBart Van Assche if (dev_han < 0) {
778*44704f69SBart Van Assche psp->dev_fd = -1;
779*44704f69SBart Van Assche psp->is_nvme = false;
780*44704f69SBart Van Assche psp->nvme_nsid = 0;
781*44704f69SBart Van Assche return 0;
782*44704f69SBart Van Assche }
783*44704f69SBart Van Assche shp = get_open_pt_handle(psp, dev_han, vb > 1);
784*44704f69SBart Van Assche if (NULL == shp) {
785*44704f69SBart Van Assche if (vb)
786*44704f69SBart Van Assche pr2ws("%s: dev_han (%d) is invalid\n", __func__, dev_han);
787*44704f69SBart Van Assche psp->os_err = EINVAL;
788*44704f69SBart Van Assche return psp->os_err;
789*44704f69SBart Van Assche }
790*44704f69SBart Van Assche psp->os_err = 0;
791*44704f69SBart Van Assche psp->transport_err = 0;
792*44704f69SBart Van Assche psp->in_err = 0;
793*44704f69SBart Van Assche psp->scsi_status = 0;
794*44704f69SBart Van Assche psp->dev_fd = dev_han;
795*44704f69SBart Van Assche if (! (shp->bus_type_failed || shp->checked_handle)) {
796*44704f69SBart Van Assche res = get_bus_type(shp, shp->dname, NULL, vb);
797*44704f69SBart Van Assche if (res < 0) {
798*44704f69SBart Van Assche res = get_scsi_pdt(shp, vb);
799*44704f69SBart Van Assche if (res >= 0) /* clears shp->bus_type_failed on success */
800*44704f69SBart Van Assche psp->os_err = 0;
801*44704f69SBart Van Assche }
802*44704f69SBart Van Assche if ((res < 0) && (vb > 2))
803*44704f69SBart Van Assche pr2ws("%s: get_bus_type() errno=%d\n", __func__, -res);
804*44704f69SBart Van Assche }
805*44704f69SBart Van Assche if (shp->bus_type_failed)
806*44704f69SBart Van Assche psp->os_err = EIO;
807*44704f69SBart Van Assche if (psp->os_err)
808*44704f69SBart Van Assche return psp->os_err;
809*44704f69SBart Van Assche psp->is_nvme = shp->is_nvme;
810*44704f69SBart Van Assche psp->nvme_nsid = 0; /* should be 'psp->nvme_nsid = shp->nvme_nsid' */
811*44704f69SBart Van Assche psp->dev_statp = &shp->dev_stat;
812*44704f69SBart Van Assche }
813*44704f69SBart Van Assche return 0;
814*44704f69SBart Van Assche }
815*44704f69SBart Van Assche
816*44704f69SBart Van Assche /* Valid file handles (which is the return value) are >= 0 . Returns -1
817*44704f69SBart Van Assche * if there is no valid file handle. */
818*44704f69SBart Van Assche int
get_pt_file_handle(const struct sg_pt_base * vp)819*44704f69SBart Van Assche get_pt_file_handle(const struct sg_pt_base * vp)
820*44704f69SBart Van Assche {
821*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp;
822*44704f69SBart Van Assche
823*44704f69SBart Van Assche if (vp) {
824*44704f69SBart Van Assche psp = vp->implp;
825*44704f69SBart Van Assche return psp ? psp->dev_fd : -1;
826*44704f69SBart Van Assche }
827*44704f69SBart Van Assche return -1;
828*44704f69SBart Van Assche }
829*44704f69SBart Van Assche
830*44704f69SBart Van Assche /* Keep state information such as dev_fd and nvme_nsid */
831*44704f69SBart Van Assche void
clear_scsi_pt_obj(struct sg_pt_base * vp)832*44704f69SBart Van Assche clear_scsi_pt_obj(struct sg_pt_base * vp)
833*44704f69SBart Van Assche {
834*44704f69SBart Van Assche bool is_nvme;
835*44704f69SBart Van Assche int dev_fd;
836*44704f69SBart Van Assche uint32_t nvme_nsid;
837*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
838*44704f69SBart Van Assche struct sg_sntl_dev_state_t * dsp;
839*44704f69SBart Van Assche
840*44704f69SBart Van Assche if (psp) {
841*44704f69SBart Van Assche dev_fd = psp->dev_fd;
842*44704f69SBart Van Assche is_nvme = psp->is_nvme;
843*44704f69SBart Van Assche nvme_nsid = psp->nvme_nsid;
844*44704f69SBart Van Assche dsp = psp->dev_statp;
845*44704f69SBart Van Assche memset(psp, 0, sizeof(struct sg_pt_win32_scsi));
846*44704f69SBart Van Assche if (spt_direct) {
847*44704f69SBart Van Assche psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
848*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
849*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoOffset =
850*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
851*44704f69SBart Van Assche psp->swb_d.spt.TimeOutValue = DEF_TIMEOUT;
852*44704f69SBart Van Assche } else {
853*44704f69SBart Van Assche psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
854*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
855*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoOffset =
856*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
857*44704f69SBart Van Assche psp->swb_i.spt.TimeOutValue = DEF_TIMEOUT;
858*44704f69SBart Van Assche }
859*44704f69SBart Van Assche psp->dev_fd = dev_fd;
860*44704f69SBart Van Assche psp->is_nvme = is_nvme;
861*44704f69SBart Van Assche psp->nvme_nsid = nvme_nsid;
862*44704f69SBart Van Assche psp->dev_statp = dsp;
863*44704f69SBart Van Assche }
864*44704f69SBart Van Assche }
865*44704f69SBart Van Assche
866*44704f69SBart Van Assche void
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)867*44704f69SBart Van Assche partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
868*44704f69SBart Van Assche {
869*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
870*44704f69SBart Van Assche
871*44704f69SBart Van Assche if (NULL == psp)
872*44704f69SBart Van Assche return;
873*44704f69SBart Van Assche psp->in_err = 0;
874*44704f69SBart Van Assche psp->os_err = 0;
875*44704f69SBart Van Assche psp->transport_err = 0;
876*44704f69SBart Van Assche psp->scsi_status = 0;
877*44704f69SBart Van Assche if (spt_direct) {
878*44704f69SBart Van Assche psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
879*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
880*44704f69SBart Van Assche psp->swb_d.spt.SenseInfoOffset =
881*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
882*44704f69SBart Van Assche psp->swb_d.spt.TimeOutValue = DEF_TIMEOUT;
883*44704f69SBart Van Assche } else {
884*44704f69SBart Van Assche psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
885*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN;
886*44704f69SBart Van Assche psp->swb_i.spt.SenseInfoOffset =
887*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
888*44704f69SBart Van Assche psp->swb_i.spt.TimeOutValue = DEF_TIMEOUT;
889*44704f69SBart Van Assche }
890*44704f69SBart Van Assche }
891*44704f69SBart Van Assche
892*44704f69SBart Van Assche void
set_scsi_pt_cdb(struct sg_pt_base * vp,const uint8_t * cdb,int cdb_len)893*44704f69SBart Van Assche set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb,
894*44704f69SBart Van Assche int cdb_len)
895*44704f69SBart Van Assche {
896*44704f69SBart Van Assche bool scsi_cdb = sg_is_scsi_cdb(cdb, cdb_len);
897*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
898*44704f69SBart Van Assche
899*44704f69SBart Van Assche if (! scsi_cdb) {
900*44704f69SBart Van Assche psp->have_nvme_cmd = true;
901*44704f69SBart Van Assche memcpy(psp->nvme_cmd, cdb, cdb_len);
902*44704f69SBart Van Assche } else if (spt_direct) {
903*44704f69SBart Van Assche if (cdb_len > (int)sizeof(psp->swb_d.spt.Cdb)) {
904*44704f69SBart Van Assche ++psp->in_err;
905*44704f69SBart Van Assche return;
906*44704f69SBart Van Assche }
907*44704f69SBart Van Assche memcpy(psp->swb_d.spt.Cdb, cdb, cdb_len);
908*44704f69SBart Van Assche psp->swb_d.spt.CdbLength = cdb_len;
909*44704f69SBart Van Assche } else {
910*44704f69SBart Van Assche if (cdb_len > (int)sizeof(psp->swb_i.spt.Cdb)) {
911*44704f69SBart Van Assche ++psp->in_err;
912*44704f69SBart Van Assche return;
913*44704f69SBart Van Assche }
914*44704f69SBart Van Assche memcpy(psp->swb_i.spt.Cdb, cdb, cdb_len);
915*44704f69SBart Van Assche psp->swb_i.spt.CdbLength = cdb_len;
916*44704f69SBart Van Assche }
917*44704f69SBart Van Assche }
918*44704f69SBart Van Assche
919*44704f69SBart Van Assche int
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)920*44704f69SBart Van Assche get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
921*44704f69SBart Van Assche {
922*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
923*44704f69SBart Van Assche
924*44704f69SBart Van Assche return spt_direct ? psp->swb_d.spt.CdbLength : psp->swb_i.spt.CdbLength;
925*44704f69SBart Van Assche }
926*44704f69SBart Van Assche
927*44704f69SBart Van Assche uint8_t *
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)928*44704f69SBart Van Assche get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
929*44704f69SBart Van Assche {
930*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
931*44704f69SBart Van Assche
932*44704f69SBart Van Assche if (spt_direct) {
933*44704f69SBart Van Assche if (psp->swb_d.spt.CdbLength > 0)
934*44704f69SBart Van Assche return (uint8_t *)(psp->swb_d.spt.Cdb);
935*44704f69SBart Van Assche else
936*44704f69SBart Van Assche return NULL;
937*44704f69SBart Van Assche } else {
938*44704f69SBart Van Assche if (psp->swb_i.spt.CdbLength > 0)
939*44704f69SBart Van Assche return (uint8_t *)(psp->swb_i.spt.Cdb);
940*44704f69SBart Van Assche else
941*44704f69SBart Van Assche return NULL;
942*44704f69SBart Van Assche }
943*44704f69SBart Van Assche }
944*44704f69SBart Van Assche
945*44704f69SBart Van Assche void
set_scsi_pt_sense(struct sg_pt_base * vp,uint8_t * sense,int sense_len)946*44704f69SBart Van Assche set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int sense_len)
947*44704f69SBart Van Assche {
948*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
949*44704f69SBart Van Assche
950*44704f69SBart Van Assche if (sense && (sense_len > 0))
951*44704f69SBart Van Assche memset(sense, 0, sense_len);
952*44704f69SBart Van Assche psp->sensep = sense;
953*44704f69SBart Van Assche psp->sense_len = sense_len;
954*44704f69SBart Van Assche }
955*44704f69SBart Van Assche
956*44704f69SBart Van Assche /* from device */
957*44704f69SBart Van Assche void
set_scsi_pt_data_in(struct sg_pt_base * vp,uint8_t * dxferp,int dxfer_len)958*44704f69SBart Van Assche set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp,
959*44704f69SBart Van Assche int dxfer_len)
960*44704f69SBart Van Assche {
961*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
962*44704f69SBart Van Assche
963*44704f69SBart Van Assche if (psp->dxferp)
964*44704f69SBart Van Assche ++psp->in_err;
965*44704f69SBart Van Assche if (dxfer_len > 0) {
966*44704f69SBart Van Assche psp->dxferp = dxferp;
967*44704f69SBart Van Assche psp->dxfer_len = (uint32_t)dxfer_len;
968*44704f69SBart Van Assche psp->is_read = true;
969*44704f69SBart Van Assche if (spt_direct)
970*44704f69SBart Van Assche psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_IN;
971*44704f69SBart Van Assche else
972*44704f69SBart Van Assche psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_IN;
973*44704f69SBart Van Assche }
974*44704f69SBart Van Assche }
975*44704f69SBart Van Assche
976*44704f69SBart Van Assche /* to device */
977*44704f69SBart Van Assche void
set_scsi_pt_data_out(struct sg_pt_base * vp,const uint8_t * dxferp,int dxfer_len)978*44704f69SBart Van Assche set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp,
979*44704f69SBart Van Assche int dxfer_len)
980*44704f69SBart Van Assche {
981*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
982*44704f69SBart Van Assche
983*44704f69SBart Van Assche if (psp->dxferp)
984*44704f69SBart Van Assche ++psp->in_err;
985*44704f69SBart Van Assche if (dxfer_len > 0) {
986*44704f69SBart Van Assche psp->dxferp = (uint8_t *)dxferp;
987*44704f69SBart Van Assche psp->dxfer_len = (uint32_t)dxfer_len;
988*44704f69SBart Van Assche if (spt_direct)
989*44704f69SBart Van Assche psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_OUT;
990*44704f69SBart Van Assche else
991*44704f69SBart Van Assche psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_OUT;
992*44704f69SBart Van Assche }
993*44704f69SBart Van Assche }
994*44704f69SBart Van Assche
995*44704f69SBart Van Assche void
set_pt_metadata_xfer(struct sg_pt_base * vp,uint8_t * mdxferp,uint32_t mdxfer_len,bool out_true)996*44704f69SBart Van Assche set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp,
997*44704f69SBart Van Assche uint32_t mdxfer_len, bool out_true)
998*44704f69SBart Van Assche {
999*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1000*44704f69SBart Van Assche
1001*44704f69SBart Van Assche if (psp->mdxferp)
1002*44704f69SBart Van Assche ++psp->in_err;
1003*44704f69SBart Van Assche if (mdxfer_len > 0) {
1004*44704f69SBart Van Assche psp->mdxferp = mdxferp;
1005*44704f69SBart Van Assche psp->mdxfer_len = mdxfer_len;
1006*44704f69SBart Van Assche psp->mdxfer_out = out_true;
1007*44704f69SBart Van Assche }
1008*44704f69SBart Van Assche }
1009*44704f69SBart Van Assche
1010*44704f69SBart Van Assche void
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)1011*44704f69SBart Van Assche set_scsi_pt_packet_id(struct sg_pt_base * vp __attribute__ ((unused)),
1012*44704f69SBart Van Assche int pack_id __attribute__ ((unused)))
1013*44704f69SBart Van Assche {
1014*44704f69SBart Van Assche }
1015*44704f69SBart Van Assche
1016*44704f69SBart Van Assche void
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)1017*44704f69SBart Van Assche set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag __attribute__ ((unused)))
1018*44704f69SBart Van Assche {
1019*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1020*44704f69SBart Van Assche
1021*44704f69SBart Van Assche ++psp->in_err;
1022*44704f69SBart Van Assche }
1023*44704f69SBart Van Assche
1024*44704f69SBart Van Assche void
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)1025*44704f69SBart Van Assche set_scsi_pt_task_management(struct sg_pt_base * vp,
1026*44704f69SBart Van Assche int tmf_code __attribute__ ((unused)))
1027*44704f69SBart Van Assche {
1028*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1029*44704f69SBart Van Assche
1030*44704f69SBart Van Assche ++psp->in_err;
1031*44704f69SBart Van Assche }
1032*44704f69SBart Van Assche
1033*44704f69SBart Van Assche void
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attrib,int priority)1034*44704f69SBart Van Assche set_scsi_pt_task_attr(struct sg_pt_base * vp,
1035*44704f69SBart Van Assche int attrib __attribute__ ((unused)),
1036*44704f69SBart Van Assche int priority __attribute__ ((unused)))
1037*44704f69SBart Van Assche {
1038*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1039*44704f69SBart Van Assche
1040*44704f69SBart Van Assche ++psp->in_err;
1041*44704f69SBart Van Assche }
1042*44704f69SBart Van Assche
1043*44704f69SBart Van Assche void
set_scsi_pt_flags(struct sg_pt_base * objp,int flags)1044*44704f69SBart Van Assche set_scsi_pt_flags(struct sg_pt_base * objp, int flags)
1045*44704f69SBart Van Assche {
1046*44704f69SBart Van Assche /* do nothing, suppress warnings */
1047*44704f69SBart Van Assche objp = objp;
1048*44704f69SBart Van Assche flags = flags;
1049*44704f69SBart Van Assche }
1050*44704f69SBart Van Assche
1051*44704f69SBart Van Assche /* Executes SCSI command (or at least forwards it to lower layers)
1052*44704f69SBart Van Assche * using direct interface. Clears os_err field prior to active call (whose
1053*44704f69SBart Van Assche * result may set it again). */
1054*44704f69SBart Van Assche static int
scsi_pt_direct(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int time_secs,int vb)1055*44704f69SBart Van Assche scsi_pt_direct(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1056*44704f69SBart Van Assche int time_secs, int vb)
1057*44704f69SBart Van Assche {
1058*44704f69SBart Van Assche BOOL status;
1059*44704f69SBart Van Assche DWORD returned;
1060*44704f69SBart Van Assche
1061*44704f69SBart Van Assche psp->os_err = 0;
1062*44704f69SBart Van Assche if (0 == psp->swb_d.spt.CdbLength) {
1063*44704f69SBart Van Assche if (vb)
1064*44704f69SBart Van Assche pr2ws("%s: No command (cdb) given\n", __func__);
1065*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1066*44704f69SBart Van Assche }
1067*44704f69SBart Van Assche psp->swb_d.spt.Length = sizeof (SCSI_PASS_THROUGH_DIRECT);
1068*44704f69SBart Van Assche psp->swb_d.spt.PathId = shp->bus;
1069*44704f69SBart Van Assche psp->swb_d.spt.TargetId = shp->target;
1070*44704f69SBart Van Assche psp->swb_d.spt.Lun = shp->lun;
1071*44704f69SBart Van Assche psp->swb_d.spt.TimeOutValue = time_secs;
1072*44704f69SBart Van Assche psp->swb_d.spt.DataTransferLength = psp->dxfer_len;
1073*44704f69SBart Van Assche if (vb > 4) {
1074*44704f69SBart Van Assche pr2ws(" spt_direct, adapter: %s Length=%d ScsiStatus=%d PathId=%d "
1075*44704f69SBart Van Assche "TargetId=%d Lun=%d\n", shp->adapter,
1076*44704f69SBart Van Assche (int)psp->swb_d.spt.Length, (int)psp->swb_d.spt.ScsiStatus,
1077*44704f69SBart Van Assche (int)psp->swb_d.spt.PathId, (int)psp->swb_d.spt.TargetId,
1078*44704f69SBart Van Assche (int)psp->swb_d.spt.Lun);
1079*44704f69SBart Van Assche pr2ws(" CdbLength=%d SenseInfoLength=%d DataIn=%d "
1080*44704f69SBart Van Assche "DataTransferLength=%u\n",
1081*44704f69SBart Van Assche (int)psp->swb_d.spt.CdbLength,
1082*44704f69SBart Van Assche (int)psp->swb_d.spt.SenseInfoLength,
1083*44704f69SBart Van Assche (int)psp->swb_d.spt.DataIn,
1084*44704f69SBart Van Assche (unsigned int)psp->swb_d.spt.DataTransferLength);
1085*44704f69SBart Van Assche pr2ws(" TimeOutValue=%u SenseInfoOffset=%u\n",
1086*44704f69SBart Van Assche (unsigned int)psp->swb_d.spt.TimeOutValue,
1087*44704f69SBart Van Assche (unsigned int)psp->swb_d.spt.SenseInfoOffset);
1088*44704f69SBart Van Assche }
1089*44704f69SBart Van Assche psp->swb_d.spt.DataBuffer = psp->dxferp;
1090*44704f69SBart Van Assche status = DeviceIoControl(shp->fh, IOCTL_SCSI_PASS_THROUGH_DIRECT,
1091*44704f69SBart Van Assche &psp->swb_d,
1092*44704f69SBart Van Assche sizeof(psp->swb_d),
1093*44704f69SBart Van Assche &psp->swb_d,
1094*44704f69SBart Van Assche sizeof(psp->swb_d),
1095*44704f69SBart Van Assche &returned,
1096*44704f69SBart Van Assche NULL);
1097*44704f69SBart Van Assche if (! status) {
1098*44704f69SBart Van Assche unsigned int u;
1099*44704f69SBart Van Assche
1100*44704f69SBart Van Assche u = (unsigned int)GetLastError();
1101*44704f69SBart Van Assche if (vb) {
1102*44704f69SBart Van Assche char b[128];
1103*44704f69SBart Van Assche
1104*44704f69SBart Van Assche pr2ws("%s: DeviceIoControl: %s [%u]\n", __func__,
1105*44704f69SBart Van Assche get_err_str(u, sizeof(b), b), u);
1106*44704f69SBart Van Assche }
1107*44704f69SBart Van Assche psp->transport_err = (int)u;
1108*44704f69SBart Van Assche psp->os_err = EIO;
1109*44704f69SBart Van Assche return 0; /* let app find transport error */
1110*44704f69SBart Van Assche }
1111*44704f69SBart Van Assche
1112*44704f69SBart Van Assche psp->scsi_status = psp->swb_d.spt.ScsiStatus;
1113*44704f69SBart Van Assche if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) ||
1114*44704f69SBart Van Assche (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status))
1115*44704f69SBart Van Assche memcpy(psp->sensep, psp->swb_d.ucSenseBuf, psp->sense_len);
1116*44704f69SBart Van Assche else
1117*44704f69SBart Van Assche psp->sense_len = 0;
1118*44704f69SBart Van Assche psp->sense_resid = 0;
1119*44704f69SBart Van Assche if ((psp->dxfer_len > 0) && (psp->swb_d.spt.DataTransferLength > 0))
1120*44704f69SBart Van Assche psp->resid = psp->dxfer_len - psp->swb_d.spt.DataTransferLength;
1121*44704f69SBart Van Assche else
1122*44704f69SBart Van Assche psp->resid = 0;
1123*44704f69SBart Van Assche
1124*44704f69SBart Van Assche return 0;
1125*44704f69SBart Van Assche }
1126*44704f69SBart Van Assche
1127*44704f69SBart Van Assche /* Executes SCSI command (or at least forwards it to lower layers) using
1128*44704f69SBart Van Assche * indirect interface. Clears os_err field prior to active call (whose
1129*44704f69SBart Van Assche * result may set it again). */
1130*44704f69SBart Van Assche static int
scsi_pt_indirect(struct sg_pt_base * vp,struct sg_pt_handle * shp,int time_secs,int vb)1131*44704f69SBart Van Assche scsi_pt_indirect(struct sg_pt_base * vp, struct sg_pt_handle * shp,
1132*44704f69SBart Van Assche int time_secs, int vb)
1133*44704f69SBart Van Assche {
1134*44704f69SBart Van Assche BOOL status;
1135*44704f69SBart Van Assche DWORD returned;
1136*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1137*44704f69SBart Van Assche
1138*44704f69SBart Van Assche psp->os_err = 0;
1139*44704f69SBart Van Assche if (0 == psp->swb_i.spt.CdbLength) {
1140*44704f69SBart Van Assche if (vb)
1141*44704f69SBart Van Assche pr2ws("%s: No command (cdb) given\n", __func__);
1142*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1143*44704f69SBart Van Assche }
1144*44704f69SBart Van Assche if (psp->dxfer_len > (int)sizeof(psp->swb_i.ucDataBuf)) {
1145*44704f69SBart Van Assche int extra = psp->dxfer_len - (int)sizeof(psp->swb_i.ucDataBuf);
1146*44704f69SBart Van Assche struct sg_pt_win32_scsi * epsp;
1147*44704f69SBart Van Assche
1148*44704f69SBart Van Assche if (vb > 4)
1149*44704f69SBart Van Assche pr2ws("spt_indirect: dxfer_len (%d) too large for initial data\n"
1150*44704f69SBart Van Assche " buffer (%d bytes), try enlarging\n", psp->dxfer_len,
1151*44704f69SBart Van Assche (int)sizeof(psp->swb_i.ucDataBuf));
1152*44704f69SBart Van Assche epsp = (struct sg_pt_win32_scsi *)
1153*44704f69SBart Van Assche calloc(sizeof(struct sg_pt_win32_scsi) + extra, 1);
1154*44704f69SBart Van Assche if (NULL == epsp) {
1155*44704f69SBart Van Assche pr2ws("%s: failed to enlarge data buffer to %d bytes\n", __func__,
1156*44704f69SBart Van Assche psp->dxfer_len);
1157*44704f69SBart Van Assche psp->os_err = ENOMEM;
1158*44704f69SBart Van Assche return -psp->os_err;
1159*44704f69SBart Van Assche }
1160*44704f69SBart Van Assche memcpy(epsp, psp, sizeof(struct sg_pt_win32_scsi));
1161*44704f69SBart Van Assche free(psp);
1162*44704f69SBart Van Assche vp->implp = epsp;
1163*44704f69SBart Van Assche psp = epsp;
1164*44704f69SBart Van Assche }
1165*44704f69SBart Van Assche psp->swb_i.spt.Length = sizeof (SCSI_PASS_THROUGH);
1166*44704f69SBart Van Assche psp->swb_i.spt.DataBufferOffset =
1167*44704f69SBart Van Assche offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
1168*44704f69SBart Van Assche psp->swb_i.spt.PathId = shp->bus;
1169*44704f69SBart Van Assche psp->swb_i.spt.TargetId = shp->target;
1170*44704f69SBart Van Assche psp->swb_i.spt.Lun = shp->lun;
1171*44704f69SBart Van Assche psp->swb_i.spt.TimeOutValue = time_secs;
1172*44704f69SBart Van Assche psp->swb_i.spt.DataTransferLength = psp->dxfer_len;
1173*44704f69SBart Van Assche if (vb > 4) {
1174*44704f69SBart Van Assche pr2ws(" spt_indirect, adapter: %s Length=%d ScsiStatus=%d PathId=%d "
1175*44704f69SBart Van Assche "TargetId=%d Lun=%d\n", shp->adapter,
1176*44704f69SBart Van Assche (int)psp->swb_i.spt.Length, (int)psp->swb_i.spt.ScsiStatus,
1177*44704f69SBart Van Assche (int)psp->swb_i.spt.PathId, (int)psp->swb_i.spt.TargetId,
1178*44704f69SBart Van Assche (int)psp->swb_i.spt.Lun);
1179*44704f69SBart Van Assche pr2ws(" CdbLength=%d SenseInfoLength=%d DataIn=%d "
1180*44704f69SBart Van Assche "DataTransferLength=%u\n",
1181*44704f69SBart Van Assche (int)psp->swb_i.spt.CdbLength,
1182*44704f69SBart Van Assche (int)psp->swb_i.spt.SenseInfoLength,
1183*44704f69SBart Van Assche (int)psp->swb_i.spt.DataIn,
1184*44704f69SBart Van Assche (unsigned int)psp->swb_i.spt.DataTransferLength);
1185*44704f69SBart Van Assche pr2ws(" TimeOutValue=%u DataBufferOffset=%u "
1186*44704f69SBart Van Assche "SenseInfoOffset=%u\n",
1187*44704f69SBart Van Assche (unsigned int)psp->swb_i.spt.TimeOutValue,
1188*44704f69SBart Van Assche (unsigned int)psp->swb_i.spt.DataBufferOffset,
1189*44704f69SBart Van Assche (unsigned int)psp->swb_i.spt.SenseInfoOffset);
1190*44704f69SBart Van Assche }
1191*44704f69SBart Van Assche if ((psp->dxfer_len > 0) &&
1192*44704f69SBart Van Assche (SCSI_IOCTL_DATA_OUT == psp->swb_i.spt.DataIn))
1193*44704f69SBart Van Assche memcpy(psp->swb_i.ucDataBuf, psp->dxferp, psp->dxfer_len);
1194*44704f69SBart Van Assche status = DeviceIoControl(shp->fh, IOCTL_SCSI_PASS_THROUGH,
1195*44704f69SBart Van Assche &psp->swb_i,
1196*44704f69SBart Van Assche sizeof(psp->swb_i),
1197*44704f69SBart Van Assche &psp->swb_i,
1198*44704f69SBart Van Assche sizeof(psp->swb_i),
1199*44704f69SBart Van Assche &returned,
1200*44704f69SBart Van Assche NULL);
1201*44704f69SBart Van Assche if (! status) {
1202*44704f69SBart Van Assche uint32_t u = (uint32_t)GetLastError();
1203*44704f69SBart Van Assche
1204*44704f69SBart Van Assche if (vb) {
1205*44704f69SBart Van Assche char b[128];
1206*44704f69SBart Van Assche
1207*44704f69SBart Van Assche pr2ws("%s: DeviceIoControl: %s [%u]\n", __func__,
1208*44704f69SBart Van Assche get_err_str(u, sizeof(b), b), u);
1209*44704f69SBart Van Assche }
1210*44704f69SBart Van Assche psp->transport_err = (int)u;
1211*44704f69SBart Van Assche psp->os_err = EIO;
1212*44704f69SBart Van Assche return 0; /* let app find transport error */
1213*44704f69SBart Van Assche }
1214*44704f69SBart Van Assche if ((psp->dxfer_len > 0) && (SCSI_IOCTL_DATA_IN == psp->swb_i.spt.DataIn))
1215*44704f69SBart Van Assche memcpy(psp->dxferp, psp->swb_i.ucDataBuf, psp->dxfer_len);
1216*44704f69SBart Van Assche
1217*44704f69SBart Van Assche psp->scsi_status = psp->swb_i.spt.ScsiStatus;
1218*44704f69SBart Van Assche if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) ||
1219*44704f69SBart Van Assche (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status))
1220*44704f69SBart Van Assche memcpy(psp->sensep, psp->swb_i.ucSenseBuf, psp->sense_len);
1221*44704f69SBart Van Assche else
1222*44704f69SBart Van Assche psp->sense_len = 0;
1223*44704f69SBart Van Assche psp->sense_resid = 0;
1224*44704f69SBart Van Assche if ((psp->dxfer_len > 0) && (psp->swb_i.spt.DataTransferLength > 0))
1225*44704f69SBart Van Assche psp->resid = psp->dxfer_len - psp->swb_i.spt.DataTransferLength;
1226*44704f69SBart Van Assche else
1227*44704f69SBart Van Assche psp->resid = 0;
1228*44704f69SBart Van Assche
1229*44704f69SBart Van Assche return 0;
1230*44704f69SBart Van Assche }
1231*44704f69SBart Van Assche
1232*44704f69SBart Van Assche /* Executes SCSI or NVME command (or at least forwards it to lower layers).
1233*44704f69SBart Van Assche * Clears os_err field prior to active call (whose result may set it
1234*44704f69SBart Van Assche * again). Returns 0 on success, positive SCSI_PT_DO_* errors for syntax
1235*44704f69SBart Van Assche * like errors and negated errnos for OS errors. For Windows its errors
1236*44704f69SBart Van Assche * are placed in psp->transport_err and a errno is simulated. */
1237*44704f69SBart Van Assche int
do_scsi_pt(struct sg_pt_base * vp,int dev_fd,int time_secs,int vb)1238*44704f69SBart Van Assche do_scsi_pt(struct sg_pt_base * vp, int dev_fd, int time_secs, int vb)
1239*44704f69SBart Van Assche {
1240*44704f69SBart Van Assche int res;
1241*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1242*44704f69SBart Van Assche struct sg_pt_handle * shp;
1243*44704f69SBart Van Assche
1244*44704f69SBart Van Assche if (! (vp && ((psp = vp->implp)))) {
1245*44704f69SBart Van Assche if (vb)
1246*44704f69SBart Van Assche pr2ws("%s: NULL 1st argument to this function\n", __func__);
1247*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1248*44704f69SBart Van Assche }
1249*44704f69SBart Van Assche psp->os_err = 0;
1250*44704f69SBart Van Assche if (dev_fd >= 0) {
1251*44704f69SBart Van Assche if ((psp->dev_fd >= 0) && (dev_fd != psp->dev_fd)) {
1252*44704f69SBart Van Assche if (vb)
1253*44704f69SBart Van Assche pr2ws("%s: file descriptor given to create() and here "
1254*44704f69SBart Van Assche "differ\n", __func__);
1255*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1256*44704f69SBart Van Assche }
1257*44704f69SBart Van Assche psp->dev_fd = dev_fd;
1258*44704f69SBart Van Assche } else if (psp->dev_fd < 0) { /* so no dev_fd in ctor */
1259*44704f69SBart Van Assche if (vb)
1260*44704f69SBart Van Assche pr2ws("%s: missing device file descriptor\n", __func__);
1261*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1262*44704f69SBart Van Assche } else
1263*44704f69SBart Van Assche dev_fd = psp->dev_fd;
1264*44704f69SBart Van Assche shp = get_open_pt_handle(psp, dev_fd, vb > 3);
1265*44704f69SBart Van Assche if (NULL == shp)
1266*44704f69SBart Van Assche return -psp->os_err;
1267*44704f69SBart Van Assche
1268*44704f69SBart Van Assche if (! (shp->bus_type_failed || shp->checked_handle)) {
1269*44704f69SBart Van Assche res = get_bus_type(shp, shp->dname, NULL, vb);
1270*44704f69SBart Van Assche if (res < 0) {
1271*44704f69SBart Van Assche res = get_scsi_pdt(shp, vb);
1272*44704f69SBart Van Assche if (res >= 0) /* clears shp->bus_type_failed on success */
1273*44704f69SBart Van Assche psp->os_err = 0;
1274*44704f69SBart Van Assche }
1275*44704f69SBart Van Assche if ((res < 0) && (vb > 2))
1276*44704f69SBart Van Assche pr2ws("%s: get_bus_type() errno=%d\n", __func__, -res);
1277*44704f69SBart Van Assche }
1278*44704f69SBart Van Assche if (shp->bus_type_failed)
1279*44704f69SBart Van Assche psp->os_err = EIO;
1280*44704f69SBart Van Assche if (psp->os_err)
1281*44704f69SBart Van Assche return -psp->os_err;
1282*44704f69SBart Van Assche psp->is_nvme = shp->is_nvme;
1283*44704f69SBart Van Assche psp->dev_statp = &shp->dev_stat;
1284*44704f69SBart Van Assche
1285*44704f69SBart Van Assche if (psp->is_nvme)
1286*44704f69SBart Van Assche return nvme_pt(psp, shp, time_secs, vb);
1287*44704f69SBart Van Assche else if (spt_direct)
1288*44704f69SBart Van Assche return scsi_pt_direct(psp, shp, time_secs, vb);
1289*44704f69SBart Van Assche else
1290*44704f69SBart Van Assche return scsi_pt_indirect(vp, shp, time_secs, vb);
1291*44704f69SBart Van Assche }
1292*44704f69SBart Van Assche
1293*44704f69SBart Van Assche int
get_scsi_pt_result_category(const struct sg_pt_base * vp)1294*44704f69SBart Van Assche get_scsi_pt_result_category(const struct sg_pt_base * vp)
1295*44704f69SBart Van Assche {
1296*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1297*44704f69SBart Van Assche
1298*44704f69SBart Van Assche if (psp->transport_err) /* give transport error highest priority */
1299*44704f69SBart Van Assche return SCSI_PT_RESULT_TRANSPORT_ERR;
1300*44704f69SBart Van Assche else if (psp->os_err)
1301*44704f69SBart Van Assche return SCSI_PT_RESULT_OS_ERR;
1302*44704f69SBart Van Assche else if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) ||
1303*44704f69SBart Van Assche (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status))
1304*44704f69SBart Van Assche return SCSI_PT_RESULT_SENSE;
1305*44704f69SBart Van Assche else if (psp->scsi_status)
1306*44704f69SBart Van Assche return SCSI_PT_RESULT_STATUS;
1307*44704f69SBart Van Assche else
1308*44704f69SBart Van Assche return SCSI_PT_RESULT_GOOD;
1309*44704f69SBart Van Assche }
1310*44704f69SBart Van Assche
1311*44704f69SBart Van Assche int
get_scsi_pt_resid(const struct sg_pt_base * vp)1312*44704f69SBart Van Assche get_scsi_pt_resid(const struct sg_pt_base * vp)
1313*44704f69SBart Van Assche {
1314*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1315*44704f69SBart Van Assche
1316*44704f69SBart Van Assche return psp->resid;
1317*44704f69SBart Van Assche }
1318*44704f69SBart Van Assche
1319*44704f69SBart Van Assche void
get_pt_req_lengths(const struct sg_pt_base * vp,int * req_dinp,int * req_doutp)1320*44704f69SBart Van Assche get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
1321*44704f69SBart Van Assche int * req_doutp)
1322*44704f69SBart Van Assche {
1323*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1324*44704f69SBart Van Assche
1325*44704f69SBart Van Assche if (req_dinp) {
1326*44704f69SBart Van Assche if (psp->is_read && (psp->dxfer_len > 0))
1327*44704f69SBart Van Assche *req_dinp = psp->dxfer_len;
1328*44704f69SBart Van Assche else
1329*44704f69SBart Van Assche *req_dinp = 0;
1330*44704f69SBart Van Assche }
1331*44704f69SBart Van Assche if (req_doutp) {
1332*44704f69SBart Van Assche if ((! psp->is_read) && (psp->dxfer_len > 0))
1333*44704f69SBart Van Assche *req_doutp = psp->dxfer_len;
1334*44704f69SBart Van Assche else
1335*44704f69SBart Van Assche *req_doutp = 0;
1336*44704f69SBart Van Assche }
1337*44704f69SBart Van Assche }
1338*44704f69SBart Van Assche
1339*44704f69SBart Van Assche void
get_pt_actual_lengths(const struct sg_pt_base * vp,int * act_dinp,int * act_doutp)1340*44704f69SBart Van Assche get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
1341*44704f69SBart Van Assche int * act_doutp)
1342*44704f69SBart Van Assche {
1343*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1344*44704f69SBart Van Assche
1345*44704f69SBart Van Assche if (act_dinp) {
1346*44704f69SBart Van Assche if (psp->is_read && (psp->dxfer_len > 0))
1347*44704f69SBart Van Assche *act_dinp = psp->dxfer_len - psp->resid;
1348*44704f69SBart Van Assche else
1349*44704f69SBart Van Assche *act_dinp = 0;
1350*44704f69SBart Van Assche }
1351*44704f69SBart Van Assche if (act_doutp) {
1352*44704f69SBart Van Assche if ((! psp->is_read) && (psp->dxfer_len > 0))
1353*44704f69SBart Van Assche *act_doutp = psp->dxfer_len - psp->resid;
1354*44704f69SBart Van Assche else
1355*44704f69SBart Van Assche *act_doutp = 0;
1356*44704f69SBart Van Assche }
1357*44704f69SBart Van Assche }
1358*44704f69SBart Van Assche
1359*44704f69SBart Van Assche
1360*44704f69SBart Van Assche int
get_scsi_pt_status_response(const struct sg_pt_base * vp)1361*44704f69SBart Van Assche get_scsi_pt_status_response(const struct sg_pt_base * vp)
1362*44704f69SBart Van Assche {
1363*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1364*44704f69SBart Van Assche
1365*44704f69SBart Van Assche if (NULL == psp)
1366*44704f69SBart Van Assche return 0;
1367*44704f69SBart Van Assche return psp->nvme_direct ? (int)psp->nvme_status : psp->scsi_status;
1368*44704f69SBart Van Assche }
1369*44704f69SBart Van Assche
1370*44704f69SBart Van Assche uint32_t
get_pt_result(const struct sg_pt_base * vp)1371*44704f69SBart Van Assche get_pt_result(const struct sg_pt_base * vp)
1372*44704f69SBart Van Assche {
1373*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1374*44704f69SBart Van Assche
1375*44704f69SBart Van Assche if (NULL == psp)
1376*44704f69SBart Van Assche return 0;
1377*44704f69SBart Van Assche return psp->nvme_direct ? psp->nvme_result : (uint32_t)psp->scsi_status;
1378*44704f69SBart Van Assche }
1379*44704f69SBart Van Assche
1380*44704f69SBart Van Assche int
get_scsi_pt_sense_len(const struct sg_pt_base * vp)1381*44704f69SBart Van Assche get_scsi_pt_sense_len(const struct sg_pt_base * vp)
1382*44704f69SBart Van Assche {
1383*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1384*44704f69SBart Van Assche int len;
1385*44704f69SBart Van Assche
1386*44704f69SBart Van Assche len = psp->sense_len - psp->sense_resid;
1387*44704f69SBart Van Assche return (len > 0) ? len : 0;
1388*44704f69SBart Van Assche }
1389*44704f69SBart Van Assche
1390*44704f69SBart Van Assche uint8_t *
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)1391*44704f69SBart Van Assche get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
1392*44704f69SBart Van Assche {
1393*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1394*44704f69SBart Van Assche
1395*44704f69SBart Van Assche return psp->sensep;
1396*44704f69SBart Van Assche }
1397*44704f69SBart Van Assche
1398*44704f69SBart Van Assche
1399*44704f69SBart Van Assche int
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)1400*44704f69SBart Van Assche get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused)))
1401*44704f69SBart Van Assche {
1402*44704f69SBart Van Assche // const struct sg_pt_win32_scsi * psp = vp->implp;
1403*44704f69SBart Van Assche
1404*44704f69SBart Van Assche return -1;
1405*44704f69SBart Van Assche }
1406*44704f69SBart Van Assche
1407*44704f69SBart Van Assche /* If not available return 0 otherwise return number of nanoseconds that the
1408*44704f69SBart Van Assche * lower layers (and hardware) took to execute the command just completed. */
1409*44704f69SBart Van Assche uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp)1410*44704f69SBart Van Assche get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused)))
1411*44704f69SBart Van Assche {
1412*44704f69SBart Van Assche return 0;
1413*44704f69SBart Van Assche }
1414*44704f69SBart Van Assche
1415*44704f69SBart Van Assche int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)1416*44704f69SBart Van Assche get_scsi_pt_transport_err(const struct sg_pt_base * vp)
1417*44704f69SBart Van Assche {
1418*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1419*44704f69SBart Van Assche
1420*44704f69SBart Van Assche return psp->transport_err;
1421*44704f69SBart Van Assche }
1422*44704f69SBart Van Assche
1423*44704f69SBart Van Assche void
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)1424*44704f69SBart Van Assche set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
1425*44704f69SBart Van Assche {
1426*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = vp->implp;
1427*44704f69SBart Van Assche
1428*44704f69SBart Van Assche psp->transport_err = err;
1429*44704f69SBart Van Assche }
1430*44704f69SBart Van Assche
1431*44704f69SBart Van Assche int
get_scsi_pt_os_err(const struct sg_pt_base * vp)1432*44704f69SBart Van Assche get_scsi_pt_os_err(const struct sg_pt_base * vp)
1433*44704f69SBart Van Assche {
1434*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1435*44704f69SBart Van Assche
1436*44704f69SBart Van Assche return psp->os_err;
1437*44704f69SBart Van Assche }
1438*44704f69SBart Van Assche
1439*44704f69SBart Van Assche bool
pt_device_is_nvme(const struct sg_pt_base * vp)1440*44704f69SBart Van Assche pt_device_is_nvme(const struct sg_pt_base * vp)
1441*44704f69SBart Van Assche {
1442*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1443*44704f69SBart Van Assche
1444*44704f69SBart Van Assche return psp ? psp->is_nvme : false;
1445*44704f69SBart Van Assche }
1446*44704f69SBart Van Assche
1447*44704f69SBart Van Assche /* If a NVMe block device (which includes the NSID) handle is associated
1448*44704f69SBart Van Assche * with 'vp', then its NSID is returned (values range from 0x1 to
1449*44704f69SBart Van Assche * 0xffffffe). Otherwise 0 is returned. */
1450*44704f69SBart Van Assche uint32_t
get_pt_nvme_nsid(const struct sg_pt_base * vp)1451*44704f69SBart Van Assche get_pt_nvme_nsid(const struct sg_pt_base * vp)
1452*44704f69SBart Van Assche {
1453*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1454*44704f69SBart Van Assche
1455*44704f69SBart Van Assche return psp->nvme_nsid;
1456*44704f69SBart Van Assche }
1457*44704f69SBart Van Assche
1458*44704f69SBart Van Assche /* Use the transport_err for Windows errors. */
1459*44704f69SBart Van Assche char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)1460*44704f69SBart Van Assche get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
1461*44704f69SBart Van Assche char * b)
1462*44704f69SBart Van Assche {
1463*44704f69SBart Van Assche struct sg_pt_win32_scsi * psp = (struct sg_pt_win32_scsi *)vp->implp;
1464*44704f69SBart Van Assche
1465*44704f69SBart Van Assche if ((max_b_len < 2) || (NULL == psp) || (NULL == b)) {
1466*44704f69SBart Van Assche if (b && (max_b_len > 0))
1467*44704f69SBart Van Assche b[0] = '\0';
1468*44704f69SBart Van Assche return b;
1469*44704f69SBart Van Assche }
1470*44704f69SBart Van Assche return get_err_str(psp->transport_err, max_b_len, b);
1471*44704f69SBart Van Assche }
1472*44704f69SBart Van Assche
1473*44704f69SBart Van Assche char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)1474*44704f69SBart Van Assche get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
1475*44704f69SBart Van Assche {
1476*44704f69SBart Van Assche const struct sg_pt_win32_scsi * psp = vp->implp;
1477*44704f69SBart Van Assche const char * cp;
1478*44704f69SBart Van Assche
1479*44704f69SBart Van Assche cp = safe_strerror(psp->os_err);
1480*44704f69SBart Van Assche strncpy(b, cp, max_b_len);
1481*44704f69SBart Van Assche if ((int)strlen(cp) >= max_b_len)
1482*44704f69SBart Van Assche b[max_b_len - 1] = '\0';
1483*44704f69SBart Van Assche return b;
1484*44704f69SBart Van Assche }
1485*44704f69SBart Van Assche
1486*44704f69SBart Van Assche #if (HAVE_NVME && (! IGNORE_NVME))
1487*44704f69SBart Van Assche
1488*44704f69SBart Van Assche static void
mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp,int sk,int asc,int ascq,int vb)1489*44704f69SBart Van Assche mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp, int sk, int asc, int ascq,
1490*44704f69SBart Van Assche int vb)
1491*44704f69SBart Van Assche {
1492*44704f69SBart Van Assche bool dsense = psp->dev_statp->scsi_dsense;
1493*44704f69SBart Van Assche int slen = psp->sense_len;
1494*44704f69SBart Van Assche int n;
1495*44704f69SBart Van Assche uint8_t * sbp = (uint8_t *)psp->sensep;
1496*44704f69SBart Van Assche
1497*44704f69SBart Van Assche psp->scsi_status = SAM_STAT_CHECK_CONDITION;
1498*44704f69SBart Van Assche if ((slen < 8) || ((! dsense) && (slen < 14))) {
1499*44704f69SBart Van Assche if (vb)
1500*44704f69SBart Van Assche pr2ws("%s: sense_len=%d too short, want 14 or more\n",
1501*44704f69SBart Van Assche __func__, slen);
1502*44704f69SBart Van Assche return;
1503*44704f69SBart Van Assche }
1504*44704f69SBart Van Assche if (dsense)
1505*44704f69SBart Van Assche n = (slen > 32) ? 32 : slen;
1506*44704f69SBart Van Assche else
1507*44704f69SBart Van Assche n = (slen < 18) ? slen : 18;
1508*44704f69SBart Van Assche psp->sense_resid = (slen > n) ? (slen - n) : 0;
1509*44704f69SBart Van Assche memset(sbp, 0, slen);
1510*44704f69SBart Van Assche sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
1511*44704f69SBart Van Assche if (vb > 3)
1512*44704f69SBart Van Assche pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk,
1513*44704f69SBart Van Assche asc, ascq);
1514*44704f69SBart Van Assche }
1515*44704f69SBart Van Assche
1516*44704f69SBart Van Assche static void
mk_sense_from_nvme_status(struct sg_pt_win32_scsi * psp,int vb)1517*44704f69SBart Van Assche mk_sense_from_nvme_status(struct sg_pt_win32_scsi * psp, int vb)
1518*44704f69SBart Van Assche {
1519*44704f69SBart Van Assche bool ok;
1520*44704f69SBart Van Assche bool dsense = psp->dev_statp->scsi_dsense;
1521*44704f69SBart Van Assche int n;
1522*44704f69SBart Van Assche int slen = psp->sense_len;
1523*44704f69SBart Van Assche uint8_t sstatus, sk, asc, ascq;
1524*44704f69SBart Van Assche uint8_t * sbp = (uint8_t *)psp->sensep;
1525*44704f69SBart Van Assche
1526*44704f69SBart Van Assche ok = sg_nvme_status2scsi(psp->nvme_status, &sstatus, &sk, &asc, &ascq);
1527*44704f69SBart Van Assche if (! ok) { /* can't find a mapping to a SCSI error, so ... */
1528*44704f69SBart Van Assche sstatus = SAM_STAT_CHECK_CONDITION;
1529*44704f69SBart Van Assche sk = SPC_SK_ILLEGAL_REQUEST;
1530*44704f69SBart Van Assche asc = 0xb;
1531*44704f69SBart Van Assche ascq = 0x0; /* asc: "WARNING" purposely vague */
1532*44704f69SBart Van Assche }
1533*44704f69SBart Van Assche
1534*44704f69SBart Van Assche psp->scsi_status = sstatus;
1535*44704f69SBart Van Assche if ((slen < 8) || ((! dsense) && (slen < 14))) {
1536*44704f69SBart Van Assche if (vb)
1537*44704f69SBart Van Assche pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__,
1538*44704f69SBart Van Assche slen);
1539*44704f69SBart Van Assche return;
1540*44704f69SBart Van Assche }
1541*44704f69SBart Van Assche if (dsense)
1542*44704f69SBart Van Assche n = (slen > 32) ? 32 : slen;
1543*44704f69SBart Van Assche else
1544*44704f69SBart Van Assche n = (slen < 18) ? slen : 18;
1545*44704f69SBart Van Assche psp->sense_resid = (slen > n) ? slen - n : 0;
1546*44704f69SBart Van Assche memset(sbp, 0, slen);
1547*44704f69SBart Van Assche sg_build_sense_buffer(dsense, sbp, sk, asc, ascq);
1548*44704f69SBart Van Assche if (dsense && (psp->nvme_status > 0))
1549*44704f69SBart Van Assche sg_nvme_desc2sense(sbp, false /* dnr */, false /* more */,
1550*44704f69SBart Van Assche psp->nvme_status);
1551*44704f69SBart Van Assche if (vb > 3)
1552*44704f69SBart Van Assche pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n",
1553*44704f69SBart Van Assche __func__, sstatus, sk, asc, ascq);
1554*44704f69SBart Van Assche }
1555*44704f69SBart Van Assche
1556*44704f69SBart Van Assche /* Set in_bit to -1 to indicate no bit position of invalid field */
1557*44704f69SBart Van Assche static void
mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp,bool in_cdb,int in_byte,int in_bit,int vb)1558*44704f69SBart Van Assche mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp, bool in_cdb, int in_byte,
1559*44704f69SBart Van Assche int in_bit, int vb)
1560*44704f69SBart Van Assche {
1561*44704f69SBart Van Assche bool dsense = psp->dev_statp->scsi_dsense;
1562*44704f69SBart Van Assche int sl, asc, n;
1563*44704f69SBart Van Assche int slen = psp->sense_len;
1564*44704f69SBart Van Assche uint8_t * sbp = (uint8_t *)psp->sensep;
1565*44704f69SBart Van Assche uint8_t sks[4];
1566*44704f69SBart Van Assche
1567*44704f69SBart Van Assche psp->scsi_status = SAM_STAT_CHECK_CONDITION;
1568*44704f69SBart Van Assche asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
1569*44704f69SBart Van Assche if ((slen < 8) || ((! dsense) && (slen < 14))) {
1570*44704f69SBart Van Assche if (vb)
1571*44704f69SBart Van Assche pr2ws("%s: max_response_len=%d too short, want 14 or more\n",
1572*44704f69SBart Van Assche __func__, slen);
1573*44704f69SBart Van Assche return;
1574*44704f69SBart Van Assche }
1575*44704f69SBart Van Assche if (dsense)
1576*44704f69SBart Van Assche n = (slen > 32) ? 32 : slen;
1577*44704f69SBart Van Assche else
1578*44704f69SBart Van Assche n = (slen < 18) ? slen : 18;
1579*44704f69SBart Van Assche psp->sense_resid = (slen > n) ? (slen - n) : 0;
1580*44704f69SBart Van Assche memset(sbp, 0, slen);
1581*44704f69SBart Van Assche sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0);
1582*44704f69SBart Van Assche memset(sks, 0, sizeof(sks));
1583*44704f69SBart Van Assche sks[0] = 0x80;
1584*44704f69SBart Van Assche if (in_cdb)
1585*44704f69SBart Van Assche sks[0] |= 0x40;
1586*44704f69SBart Van Assche if (in_bit >= 0) {
1587*44704f69SBart Van Assche sks[0] |= 0x8;
1588*44704f69SBart Van Assche sks[0] |= (0x7 & in_bit);
1589*44704f69SBart Van Assche }
1590*44704f69SBart Van Assche sg_put_unaligned_be16(in_byte, sks + 1);
1591*44704f69SBart Van Assche if (dsense) {
1592*44704f69SBart Van Assche sl = sbp[7] + 8;
1593*44704f69SBart Van Assche sbp[7] = sl;
1594*44704f69SBart Van Assche sbp[sl] = 0x2;
1595*44704f69SBart Van Assche sbp[sl + 1] = 0x6;
1596*44704f69SBart Van Assche memcpy(sbp + sl + 4, sks, 3);
1597*44704f69SBart Van Assche } else
1598*44704f69SBart Van Assche memcpy(sbp + 15, sks, 3);
1599*44704f69SBart Van Assche if (vb > 3)
1600*44704f69SBart Van Assche pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
1601*44704f69SBart Van Assche __func__, asc, in_cdb ? 'C' : 'D', in_byte,
1602*44704f69SBart Van Assche ((in_bit > 0) ? (0x7 & in_bit) : 0));
1603*44704f69SBart Van Assche }
1604*44704f69SBart Van Assche
1605*44704f69SBart Van Assche #if W10_NVME_NON_PASSTHRU /* W10 and later, no real pass-through ?? */
1606*44704f69SBart Van Assche
1607*44704f69SBart Van Assche #ifndef NVME_MAX_LOG_SIZE
1608*44704f69SBart Van Assche #define NVME_MAX_LOG_SIZE 4096
1609*44704f69SBart Van Assche #endif
1610*44704f69SBart Van Assche
1611*44704f69SBart Van Assche static int
nvme_identify(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,int vb)1612*44704f69SBart Van Assche nvme_identify(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1613*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb)
1614*44704f69SBart Van Assche {
1615*44704f69SBart Van Assche bool id_ctrl;
1616*44704f69SBart Van Assche int res = 0;
1617*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
1618*44704f69SBart Van Assche uint32_t cdw10, nsid, n;
1619*44704f69SBart Van Assche const uint8_t * bp;
1620*44704f69SBart Van Assche BOOL result;
1621*44704f69SBart Van Assche PVOID buffer = NULL;
1622*44704f69SBart Van Assche uint8_t * free_buffer = NULL;
1623*44704f69SBart Van Assche ULONG bufferLength = 0;
1624*44704f69SBart Van Assche ULONG returnedLength = 0;
1625*44704f69SBart Van Assche STORAGE_PROPERTY_QUERY * query = NULL;
1626*44704f69SBart Van Assche STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL;
1627*44704f69SBart Van Assche STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL;
1628*44704f69SBart Van Assche
1629*44704f69SBart Van Assche nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID);
1630*44704f69SBart Van Assche cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10);
1631*44704f69SBart Van Assche id_ctrl = (0x1 == cdw10);
1632*44704f69SBart Van Assche n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen;
1633*44704f69SBart Van Assche bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) +
1634*44704f69SBart Van Assche sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n;
1635*44704f69SBart Van Assche buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false);
1636*44704f69SBart Van Assche if (buffer == NULL) {
1637*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
1638*44704f69SBart Van Assche if (vb > 1)
1639*44704f69SBart Van Assche pr2ws("%s: unable to allocate memory\n", __func__);
1640*44704f69SBart Van Assche psp->os_err = res;
1641*44704f69SBart Van Assche return -res;
1642*44704f69SBart Van Assche }
1643*44704f69SBart Van Assche query = (STORAGE_PROPERTY_QUERY *)buffer;
1644*44704f69SBart Van Assche
1645*44704f69SBart Van Assche query->PropertyId = id_ctrl ? StorageAdapterProtocolSpecificProperty :
1646*44704f69SBart Van Assche StorageDeviceProtocolSpecificProperty;
1647*44704f69SBart Van Assche query->QueryType = PropertyStandardQuery;
1648*44704f69SBart Van Assche protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer;
1649*44704f69SBart Van Assche protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *)
1650*44704f69SBart Van Assche query->AdditionalParameters;
1651*44704f69SBart Van Assche
1652*44704f69SBart Van Assche protocolData->ProtocolType = ProtocolTypeNvme;
1653*44704f69SBart Van Assche protocolData->DataType = NVMeDataTypeIdentify;
1654*44704f69SBart Van Assche protocolData->ProtocolDataRequestValue = cdw10;
1655*44704f69SBart Van Assche if (! id_ctrl)
1656*44704f69SBart Van Assche protocolData->ProtocolDataRequestSubValue = nsid;
1657*44704f69SBart Van Assche protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
1658*44704f69SBart Van Assche protocolData->ProtocolDataLength = dlen;
1659*44704f69SBart Van Assche
1660*44704f69SBart Van Assche result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY,
1661*44704f69SBart Van Assche buffer, bufferLength, buffer, bufferLength,
1662*44704f69SBart Van Assche &returnedLength, (OVERLAPPED*)0);
1663*44704f69SBart Van Assche if ((! result) || (0 == returnedLength)) {
1664*44704f69SBart Van Assche n = (uint32_t)GetLastError();
1665*44704f69SBart Van Assche psp->transport_err = n;
1666*44704f69SBart Van Assche psp->os_err = EIO; /* simulate Unix error, */
1667*44704f69SBart Van Assche if (vb > 2) {
1668*44704f69SBart Van Assche char b[128];
1669*44704f69SBart Van Assche
1670*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_%s) failed: %s "
1671*44704f69SBart Van Assche "[%u]\n", __func__, (id_ctrl ? "ctrl" : "ns"),
1672*44704f69SBart Van Assche get_err_str(n, sizeof(b), b), n);
1673*44704f69SBart Van Assche }
1674*44704f69SBart Van Assche res = -psp->os_err;
1675*44704f69SBart Van Assche goto err_out;
1676*44704f69SBart Van Assche }
1677*44704f69SBart Van Assche if (dlen > 0) {
1678*44704f69SBart Van Assche protocolData = &protocolDataDescr->ProtocolSpecificData;
1679*44704f69SBart Van Assche bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset;
1680*44704f69SBart Van Assche memcpy(dp, bp, dlen);
1681*44704f69SBart Van Assche if (0 == psp->nvme_nsid) {
1682*44704f69SBart Van Assche uint32_t nn = sg_get_unaligned_le32(bp + 516);
1683*44704f69SBart Van Assche
1684*44704f69SBart Van Assche if (1 == nn) /* if physical drive has only 1 namespace */
1685*44704f69SBart Van Assche psp->nvme_nsid = 1; /* then its nsid must be 1 */
1686*44704f69SBart Van Assche /* N.B. Need better get_nsid_from _handle technique when 2 or
1687*44704f69SBart Van Assche * more namespaces. Suggestions? */
1688*44704f69SBart Van Assche }
1689*44704f69SBart Van Assche }
1690*44704f69SBart Van Assche psp->nvme_status = 0;
1691*44704f69SBart Van Assche psp->nvme_result =
1692*44704f69SBart Van Assche protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData;
1693*44704f69SBart Van Assche if (vb > 3)
1694*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, "
1695*44704f69SBart Van Assche "returnedLength=%u\n", __func__, (uint32_t)returnedLength);
1696*44704f69SBart Van Assche res = 0;
1697*44704f69SBart Van Assche err_out:
1698*44704f69SBart Van Assche if (free_buffer)
1699*44704f69SBart Van Assche free(free_buffer);
1700*44704f69SBart Van Assche return res;
1701*44704f69SBart Van Assche }
1702*44704f69SBart Van Assche
1703*44704f69SBart Van Assche static int
nvme_get_features(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,int vb)1704*44704f69SBart Van Assche nvme_get_features(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1705*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb)
1706*44704f69SBart Van Assche {
1707*44704f69SBart Van Assche int res = 0;
1708*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
1709*44704f69SBart Van Assche uint32_t cdw10, nsid, n;
1710*44704f69SBart Van Assche const uint8_t * bp;
1711*44704f69SBart Van Assche BOOL result;
1712*44704f69SBart Van Assche PVOID buffer = NULL;
1713*44704f69SBart Van Assche uint8_t * free_buffer = NULL;
1714*44704f69SBart Van Assche ULONG bufferLength = 0;
1715*44704f69SBart Van Assche ULONG returnedLength = 0;
1716*44704f69SBart Van Assche STORAGE_PROPERTY_QUERY * query = NULL;
1717*44704f69SBart Van Assche STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL;
1718*44704f69SBart Van Assche STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL;
1719*44704f69SBart Van Assche
1720*44704f69SBart Van Assche nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID);
1721*44704f69SBart Van Assche cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10);
1722*44704f69SBart Van Assche n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen;
1723*44704f69SBart Van Assche bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) +
1724*44704f69SBart Van Assche sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n;
1725*44704f69SBart Van Assche buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false);
1726*44704f69SBart Van Assche if (buffer == NULL) {
1727*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
1728*44704f69SBart Van Assche if (vb > 1)
1729*44704f69SBart Van Assche pr2ws("%s: unable to allocate memory\n", __func__);
1730*44704f69SBart Van Assche psp->os_err = res;
1731*44704f69SBart Van Assche return -res;
1732*44704f69SBart Van Assche }
1733*44704f69SBart Van Assche query = (STORAGE_PROPERTY_QUERY *)buffer;
1734*44704f69SBart Van Assche
1735*44704f69SBart Van Assche query->PropertyId = StorageDeviceProtocolSpecificProperty;
1736*44704f69SBart Van Assche query->QueryType = PropertyStandardQuery;
1737*44704f69SBart Van Assche protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer;
1738*44704f69SBart Van Assche protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *)
1739*44704f69SBart Van Assche query->AdditionalParameters;
1740*44704f69SBart Van Assche
1741*44704f69SBart Van Assche protocolData->ProtocolType = ProtocolTypeNvme;
1742*44704f69SBart Van Assche protocolData->DataType = NVMeDataTypeFeature; /* Get Features */
1743*44704f69SBart Van Assche protocolData->ProtocolDataRequestValue = cdw10;
1744*44704f69SBart Van Assche protocolData->ProtocolDataRequestSubValue = nsid;
1745*44704f69SBart Van Assche protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
1746*44704f69SBart Van Assche protocolData->ProtocolDataLength = dlen;
1747*44704f69SBart Van Assche
1748*44704f69SBart Van Assche result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY,
1749*44704f69SBart Van Assche buffer, bufferLength, buffer, bufferLength,
1750*44704f69SBart Van Assche &returnedLength, (OVERLAPPED*)0);
1751*44704f69SBart Van Assche if ((! result) || (0 == returnedLength)) {
1752*44704f69SBart Van Assche n = (uint32_t)GetLastError();
1753*44704f69SBart Van Assche psp->transport_err = n;
1754*44704f69SBart Van Assche psp->os_err = EIO; /* simulate Unix error, */
1755*44704f69SBart Van Assche if (vb > 2) {
1756*44704f69SBart Van Assche char b[128];
1757*44704f69SBart Van Assche
1758*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) failed: %s "
1759*44704f69SBart Van Assche "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n);
1760*44704f69SBart Van Assche }
1761*44704f69SBart Van Assche res = -psp->os_err;
1762*44704f69SBart Van Assche goto err_out;
1763*44704f69SBart Van Assche }
1764*44704f69SBart Van Assche if (dlen > 0) {
1765*44704f69SBart Van Assche protocolData = &protocolDataDescr->ProtocolSpecificData;
1766*44704f69SBart Van Assche bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset;
1767*44704f69SBart Van Assche memcpy(dp, bp, dlen);
1768*44704f69SBart Van Assche }
1769*44704f69SBart Van Assche psp->nvme_status = 0;
1770*44704f69SBart Van Assche psp->nvme_result =
1771*44704f69SBart Van Assche protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData;
1772*44704f69SBart Van Assche if (vb > 3)
1773*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, "
1774*44704f69SBart Van Assche "returnedLength=%u\n", __func__, (uint32_t)returnedLength);
1775*44704f69SBart Van Assche res = 0;
1776*44704f69SBart Van Assche err_out:
1777*44704f69SBart Van Assche if (free_buffer)
1778*44704f69SBart Van Assche free(free_buffer);
1779*44704f69SBart Van Assche return res;
1780*44704f69SBart Van Assche }
1781*44704f69SBart Van Assche
1782*44704f69SBart Van Assche static int
nvme_get_log_page(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,int vb)1783*44704f69SBart Van Assche nvme_get_log_page(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1784*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb)
1785*44704f69SBart Van Assche {
1786*44704f69SBart Van Assche int res = 0;
1787*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
1788*44704f69SBart Van Assche uint32_t cdw10, nsid, n;
1789*44704f69SBart Van Assche const uint8_t * bp;
1790*44704f69SBart Van Assche BOOL result;
1791*44704f69SBart Van Assche PVOID buffer = NULL;
1792*44704f69SBart Van Assche uint8_t * free_buffer = NULL;
1793*44704f69SBart Van Assche ULONG bufferLength = 0;
1794*44704f69SBart Van Assche ULONG returnedLength = 0;
1795*44704f69SBart Van Assche STORAGE_PROPERTY_QUERY * query = NULL;
1796*44704f69SBart Van Assche STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL;
1797*44704f69SBart Van Assche STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL;
1798*44704f69SBart Van Assche
1799*44704f69SBart Van Assche nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID);
1800*44704f69SBart Van Assche cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10);
1801*44704f69SBart Van Assche n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen;
1802*44704f69SBart Van Assche bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) +
1803*44704f69SBart Van Assche sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n;
1804*44704f69SBart Van Assche buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false);
1805*44704f69SBart Van Assche if (buffer == NULL) {
1806*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
1807*44704f69SBart Van Assche if (vb > 1)
1808*44704f69SBart Van Assche pr2ws("%s: unable to allocate memory\n", __func__);
1809*44704f69SBart Van Assche psp->os_err = res;
1810*44704f69SBart Van Assche return -res;
1811*44704f69SBart Van Assche }
1812*44704f69SBart Van Assche query = (STORAGE_PROPERTY_QUERY *)buffer;
1813*44704f69SBart Van Assche
1814*44704f69SBart Van Assche query->PropertyId = StorageDeviceProtocolSpecificProperty;
1815*44704f69SBart Van Assche query->QueryType = PropertyStandardQuery;
1816*44704f69SBart Van Assche protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer;
1817*44704f69SBart Van Assche protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *)
1818*44704f69SBart Van Assche query->AdditionalParameters;
1819*44704f69SBart Van Assche
1820*44704f69SBart Van Assche protocolData->ProtocolType = ProtocolTypeNvme;
1821*44704f69SBart Van Assche protocolData->DataType = NVMeDataTypeLogPage; /* Get Log Page */
1822*44704f69SBart Van Assche protocolData->ProtocolDataRequestValue = cdw10;
1823*44704f69SBart Van Assche protocolData->ProtocolDataRequestSubValue = nsid;
1824*44704f69SBart Van Assche protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
1825*44704f69SBart Van Assche protocolData->ProtocolDataLength = dlen;
1826*44704f69SBart Van Assche
1827*44704f69SBart Van Assche result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY,
1828*44704f69SBart Van Assche buffer, bufferLength, buffer, bufferLength,
1829*44704f69SBart Van Assche &returnedLength, (OVERLAPPED*)0);
1830*44704f69SBart Van Assche if ((! result) || (0 == returnedLength)) {
1831*44704f69SBart Van Assche n = (uint32_t)GetLastError();
1832*44704f69SBart Van Assche psp->transport_err = n;
1833*44704f69SBart Van Assche psp->os_err = EIO; /* simulate Unix error, */
1834*44704f69SBart Van Assche if (vb > 2) {
1835*44704f69SBart Van Assche char b[128];
1836*44704f69SBart Van Assche
1837*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) failed: %s "
1838*44704f69SBart Van Assche "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n);
1839*44704f69SBart Van Assche }
1840*44704f69SBart Van Assche res = -psp->os_err;
1841*44704f69SBart Van Assche goto err_out;
1842*44704f69SBart Van Assche }
1843*44704f69SBart Van Assche if (dlen > 0) {
1844*44704f69SBart Van Assche protocolData = &protocolDataDescr->ProtocolSpecificData;
1845*44704f69SBart Van Assche bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset;
1846*44704f69SBart Van Assche memcpy(dp, bp, dlen);
1847*44704f69SBart Van Assche }
1848*44704f69SBart Van Assche psp->nvme_status = 0;
1849*44704f69SBart Van Assche psp->nvme_result =
1850*44704f69SBart Van Assche protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData;
1851*44704f69SBart Van Assche if (vb > 3)
1852*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, "
1853*44704f69SBart Van Assche "returnedLength=%u\n", __func__, (uint32_t)returnedLength);
1854*44704f69SBart Van Assche res = 0;
1855*44704f69SBart Van Assche err_out:
1856*44704f69SBart Van Assche if (free_buffer)
1857*44704f69SBart Van Assche free(free_buffer);
1858*44704f69SBart Van Assche return res;
1859*44704f69SBart Van Assche }
1860*44704f69SBart Van Assche
1861*44704f69SBart Van Assche static int
nvme_real_pt(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,bool is_read,int time_secs,int vb)1862*44704f69SBart Van Assche nvme_real_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1863*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, bool is_read,
1864*44704f69SBart Van Assche int time_secs, int vb)
1865*44704f69SBart Van Assche {
1866*44704f69SBart Van Assche int res = 0;
1867*44704f69SBart Van Assche const uint32_t cmd_len = 64;
1868*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
1869*44704f69SBart Van Assche uint32_t n, k;
1870*44704f69SBart Van Assche uint32_t rd_off = 0;
1871*44704f69SBart Van Assche uint32_t slen = psp->sense_len;
1872*44704f69SBart Van Assche uint8_t * bp;
1873*44704f69SBart Van Assche uint8_t * sbp = psp->sensep;
1874*44704f69SBart Van Assche BOOL ok;
1875*44704f69SBart Van Assche PVOID buffer = NULL;
1876*44704f69SBart Van Assche uint8_t * free_buffer = NULL;
1877*44704f69SBart Van Assche ULONG bufferLength = 0;
1878*44704f69SBart Van Assche ULONG returnLength = 0;
1879*44704f69SBart Van Assche STORAGE_PROTOCOL_COMMAND * protoCmdp;
1880*44704f69SBart Van Assche const NVME_ERROR_INFO_LOG * neilp;
1881*44704f69SBart Van Assche
1882*44704f69SBart Van Assche n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen;
1883*44704f69SBart Van Assche bufferLength = offsetof(STORAGE_PROTOCOL_COMMAND, Command) +
1884*44704f69SBart Van Assche cmd_len +
1885*44704f69SBart Van Assche sizeof(NVME_ERROR_INFO_LOG) + n;
1886*44704f69SBart Van Assche buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false);
1887*44704f69SBart Van Assche if (buffer == NULL) {
1888*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
1889*44704f69SBart Van Assche if (vb > 1)
1890*44704f69SBart Van Assche pr2ws("%s: unable to allocate memory\n", __func__);
1891*44704f69SBart Van Assche psp->os_err = res;
1892*44704f69SBart Van Assche return -res;
1893*44704f69SBart Van Assche }
1894*44704f69SBart Van Assche protoCmdp = (STORAGE_PROTOCOL_COMMAND *)buffer;
1895*44704f69SBart Van Assche protoCmdp->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION;
1896*44704f69SBart Van Assche protoCmdp->Length = sizeof(STORAGE_PROTOCOL_COMMAND);
1897*44704f69SBart Van Assche protoCmdp->ProtocolType = ProtocolTypeNvme;
1898*44704f69SBart Van Assche /* without *_ADAPTER_REQUEST flag, goes to device */
1899*44704f69SBart Van Assche protoCmdp->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST;
1900*44704f69SBart Van Assche /* protoCmdp->Flags = 0; */
1901*44704f69SBart Van Assche protoCmdp->CommandLength = cmd_len;
1902*44704f69SBart Van Assche protoCmdp->ErrorInfoLength = sizeof(NVME_ERROR_INFO_LOG);
1903*44704f69SBart Van Assche if (dlen > 0) {
1904*44704f69SBart Van Assche if (is_read)
1905*44704f69SBart Van Assche protoCmdp->DataFromDeviceTransferLength = dlen;
1906*44704f69SBart Van Assche else
1907*44704f69SBart Van Assche protoCmdp->DataToDeviceTransferLength = dlen;
1908*44704f69SBart Van Assche }
1909*44704f69SBart Van Assche protoCmdp->TimeOutValue = (time_secs > 0) ? time_secs : DEF_TIMEOUT;
1910*44704f69SBart Van Assche protoCmdp->ErrorInfoOffset =
1911*44704f69SBart Van Assche offsetof(STORAGE_PROTOCOL_COMMAND, Command) + cmd_len;
1912*44704f69SBart Van Assche n = protoCmdp->ErrorInfoOffset + protoCmdp->ErrorInfoLength;
1913*44704f69SBart Van Assche if (is_read) {
1914*44704f69SBart Van Assche protoCmdp->DataFromDeviceBufferOffset = n;
1915*44704f69SBart Van Assche rd_off = n;
1916*44704f69SBart Van Assche } else
1917*44704f69SBart Van Assche protoCmdp->DataToDeviceBufferOffset = n;
1918*44704f69SBart Van Assche protoCmdp->CommandSpecific =
1919*44704f69SBart Van Assche STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;
1920*44704f69SBart Van Assche memcpy(protoCmdp->Command, cmdp, cmd_len);
1921*44704f69SBart Van Assche if ((dlen > 0) && (! is_read)) {
1922*44704f69SBart Van Assche bp = (uint8_t *)protoCmdp + n;
1923*44704f69SBart Van Assche memcpy(bp, dp, dlen);
1924*44704f69SBart Van Assche }
1925*44704f69SBart Van Assche
1926*44704f69SBart Van Assche ok = DeviceIoControl(shp->fh, IOCTL_STORAGE_PROTOCOL_COMMAND,
1927*44704f69SBart Van Assche buffer, bufferLength, buffer, bufferLength,
1928*44704f69SBart Van Assche &returnLength, (OVERLAPPED*)0);
1929*44704f69SBart Van Assche if (! ok) {
1930*44704f69SBart Van Assche n = (uint32_t)GetLastError();
1931*44704f69SBart Van Assche psp->transport_err = n;
1932*44704f69SBart Van Assche psp->os_err = EIO; /* simulate Unix error, */
1933*44704f69SBart Van Assche if (vb > 2) {
1934*44704f69SBart Van Assche char b[128];
1935*44704f69SBart Van Assche
1936*44704f69SBart Van Assche pr2ws("%s: IOCTL_STORAGE_PROTOCOL_COMMAND failed: %s "
1937*44704f69SBart Van Assche "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n);
1938*44704f69SBart Van Assche pr2ws(" ... ReturnStatus=0x%x, ReturnLength=%u\n",
1939*44704f69SBart Van Assche (uint32_t)protoCmdp->ReturnStatus, (uint32_t)returnLength);
1940*44704f69SBart Van Assche }
1941*44704f69SBart Van Assche res = -psp->os_err;
1942*44704f69SBart Van Assche goto err_out;
1943*44704f69SBart Van Assche }
1944*44704f69SBart Van Assche bp = (uint8_t *)protoCmdp + protoCmdp->ErrorInfoOffset;
1945*44704f69SBart Van Assche neilp = (const NVME_ERROR_INFO_LOG *)bp;
1946*44704f69SBart Van Assche /* Shift over top of Phase tag bit */
1947*44704f69SBart Van Assche psp->nvme_status = 0x3ff & (neilp->Status.AsUshort >> 1);
1948*44704f69SBart Van Assche if ((dlen > 0) && is_read) {
1949*44704f69SBart Van Assche bp = (uint8_t *)protoCmdp + rd_off;
1950*44704f69SBart Van Assche memcpy(dp, bp, dlen);
1951*44704f69SBart Van Assche }
1952*44704f69SBart Van Assche psp->nvme_result = protoCmdp->FixedProtocolReturnData;
1953*44704f69SBart Van Assche if (psp->nvme_direct && sbp && (slen > 3)) {
1954*44704f69SBart Van Assche /* build 16 byte "sense" buffer from completion queue entry */
1955*44704f69SBart Van Assche n = (slen < 16) ? slen : 16;
1956*44704f69SBart Van Assche memset(sbp, 0 , n);
1957*44704f69SBart Van Assche psp->sense_resid = (slen > 16) ? (slen - 16) : 0;
1958*44704f69SBart Van Assche sg_put_unaligned_le32(psp->nvme_result, sbp + SG_NVME_PT_CQ_DW0);
1959*44704f69SBart Van Assche if (n > 11) {
1960*44704f69SBart Van Assche k = neilp->SQID;
1961*44704f69SBart Van Assche sg_put_unaligned_le32((k << 16), sbp + SG_NVME_PT_CQ_DW2);
1962*44704f69SBart Van Assche if (n > 15) {
1963*44704f69SBart Van Assche k = ((uint32_t)neilp->Status.AsUshort << 16) | neilp->CMDID;
1964*44704f69SBart Van Assche sg_put_unaligned_le32(k, sbp + SG_NVME_PT_CQ_DW3);
1965*44704f69SBart Van Assche }
1966*44704f69SBart Van Assche }
1967*44704f69SBart Van Assche }
1968*44704f69SBart Van Assche if (vb > 3)
1969*44704f69SBart Van Assche pr2ws("%s: opcode=0x%x, status=0x%x, result=0x%x\n",
1970*44704f69SBart Van Assche __func__, cmdp[0], psp->nvme_status, psp->nvme_result);
1971*44704f69SBart Van Assche res = psp->nvme_status ? SG_LIB_NVME_STATUS : 0;
1972*44704f69SBart Van Assche err_out:
1973*44704f69SBart Van Assche if (free_buffer)
1974*44704f69SBart Van Assche free(free_buffer);
1975*44704f69SBart Van Assche return res;
1976*44704f69SBart Van Assche }
1977*44704f69SBart Van Assche
1978*44704f69SBart Van Assche static int
do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,bool is_read,int time_secs,int vb)1979*44704f69SBart Van Assche do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
1980*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen,
1981*44704f69SBart Van Assche bool is_read, int time_secs, int vb)
1982*44704f69SBart Van Assche {
1983*44704f69SBart Van Assche const uint32_t cmd_len = 64;
1984*44704f69SBart Van Assche int res;
1985*44704f69SBart Van Assche uint32_t n;
1986*44704f69SBart Van Assche uint8_t opcode;
1987*44704f69SBart Van Assche
1988*44704f69SBart Van Assche psp->os_err = 0;
1989*44704f69SBart Van Assche psp->transport_err = 0;
1990*44704f69SBart Van Assche if (NULL == cmdp) {
1991*44704f69SBart Van Assche if (! psp->have_nvme_cmd)
1992*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
1993*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
1994*44704f69SBart Van Assche is_read = psp->is_read;
1995*44704f69SBart Van Assche dlen = psp->dxfer_len;
1996*44704f69SBart Van Assche dp = psp->dxferp;
1997*44704f69SBart Van Assche }
1998*44704f69SBart Van Assche if (vb > 2) {
1999*44704f69SBart Van Assche pr2ws("NVMe is_read=%s, dlen=%u, command:\n",
2000*44704f69SBart Van Assche (is_read ? "true" : "false"), dlen);
2001*44704f69SBart Van Assche hex2stderr((const uint8_t *)cmdp, cmd_len, 1);
2002*44704f69SBart Van Assche if ((vb > 3) && (! is_read) && dp) {
2003*44704f69SBart Van Assche if (dlen > 0) {
2004*44704f69SBart Van Assche n = dlen;
2005*44704f69SBart Van Assche if ((dlen < 512) || (vb > 5))
2006*44704f69SBart Van Assche pr2ws("\nData-out buffer (%u bytes):\n", n);
2007*44704f69SBart Van Assche else {
2008*44704f69SBart Van Assche pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n);
2009*44704f69SBart Van Assche n = 512;
2010*44704f69SBart Van Assche }
2011*44704f69SBart Van Assche hex2stderr((const uint8_t *)dp, n, 0);
2012*44704f69SBart Van Assche }
2013*44704f69SBart Van Assche }
2014*44704f69SBart Van Assche }
2015*44704f69SBart Van Assche opcode = cmdp[0];
2016*44704f69SBart Van Assche switch (opcode) { /* The matches below are cached by W10 */
2017*44704f69SBart Van Assche case 0x6: /* Identify (controller + namespace */
2018*44704f69SBart Van Assche res = nvme_identify(psp, shp, cmdp, dp, dlen, vb);
2019*44704f69SBart Van Assche if (res)
2020*44704f69SBart Van Assche goto err_out;
2021*44704f69SBart Van Assche break;
2022*44704f69SBart Van Assche case 0xa: /* Get features */
2023*44704f69SBart Van Assche res = nvme_get_features(psp, shp, cmdp, dp, dlen, vb);
2024*44704f69SBart Van Assche if (res)
2025*44704f69SBart Van Assche goto err_out;
2026*44704f69SBart Van Assche break;
2027*44704f69SBart Van Assche case 0x2: /* Get Log Page */
2028*44704f69SBart Van Assche res = nvme_get_log_page(psp, shp, cmdp, dp, dlen, vb);
2029*44704f69SBart Van Assche if (res)
2030*44704f69SBart Van Assche goto err_out;
2031*44704f69SBart Van Assche break;
2032*44704f69SBart Van Assche default:
2033*44704f69SBart Van Assche res = nvme_real_pt(psp, shp, cmdp, dp, dlen, is_read, time_secs, vb);
2034*44704f69SBart Van Assche if (res)
2035*44704f69SBart Van Assche goto err_out;
2036*44704f69SBart Van Assche break;
2037*44704f69SBart Van Assche /* IOCTL_STORAGE_PROTOCOL_COMMAND base pass-through goes here */
2038*44704f69SBart Van Assche res = -EINVAL;
2039*44704f69SBart Van Assche goto err_out;
2040*44704f69SBart Van Assche }
2041*44704f69SBart Van Assche
2042*44704f69SBart Van Assche if ((vb > 3) && is_read && dp && (dlen > 0)) {
2043*44704f69SBart Van Assche n = dlen;
2044*44704f69SBart Van Assche if ((dlen < 1024) || (vb > 5))
2045*44704f69SBart Van Assche pr2ws("\nData-in buffer (%u bytes):\n", n);
2046*44704f69SBart Van Assche else {
2047*44704f69SBart Van Assche pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n);
2048*44704f69SBart Van Assche n = 1024;
2049*44704f69SBart Van Assche }
2050*44704f69SBart Van Assche hex2stderr((const uint8_t *)dp, n, 0);
2051*44704f69SBart Van Assche }
2052*44704f69SBart Van Assche err_out:
2053*44704f69SBart Van Assche return res;
2054*44704f69SBart Van Assche }
2055*44704f69SBart Van Assche
2056*44704f69SBart Van Assche #else /* W10_NVME_NON_PASSTHRU */
2057*44704f69SBart Van Assche
2058*44704f69SBart Van Assche /* If cmdp is NULL then dp, dlen and is_read are ignored, those values are
2059*44704f69SBart Van Assche * obtained from psp. Returns 0 for success. Returns SG_LIB_NVME_STATUS if
2060*44704f69SBart Van Assche * there is non-zero NVMe status (SCT|SC from the completion queue) with the
2061*44704f69SBart Van Assche * value placed in psp->nvme_status. If Unix error from ioctl then return
2062*44704f69SBart Van Assche * negated value (equivalent -errno from basic Unix system functions like
2063*44704f69SBart Van Assche * open()). CDW0 from the completion queue is placed in psp->nvme_result in
2064*44704f69SBart Van Assche * the absence of an error.
2065*44704f69SBart Van Assche * The following code is based on os_win32.cpp in smartmontools:
2066*44704f69SBart Van Assche * Copyright (C) 2004-17 Christian Franke
2067*44704f69SBart Van Assche * The code is licensed with a GPL-2. */
2068*44704f69SBart Van Assche static int
do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cmdp,uint8_t * dp,uint32_t dlen,bool is_read,int time_secs,int vb)2069*44704f69SBart Van Assche do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2070*44704f69SBart Van Assche const uint8_t * cmdp, uint8_t * dp, uint32_t dlen,
2071*44704f69SBart Van Assche bool is_read, int time_secs, int vb)
2072*44704f69SBart Van Assche {
2073*44704f69SBart Van Assche const uint32_t cmd_len = 64;
2074*44704f69SBart Van Assche int res;
2075*44704f69SBart Van Assche uint32_t n, alloc_len;
2076*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
2077*44704f69SBart Van Assche uint32_t slen = psp->sense_len;
2078*44704f69SBart Van Assche uint8_t * sbp = psp->sensep;
2079*44704f69SBart Van Assche NVME_PASS_THROUGH_IOCTL * pthru;
2080*44704f69SBart Van Assche uint8_t * free_pthru;
2081*44704f69SBart Van Assche DWORD num_out = 0;
2082*44704f69SBart Van Assche BOOL ok;
2083*44704f69SBart Van Assche
2084*44704f69SBart Van Assche psp->os_err = 0;
2085*44704f69SBart Van Assche psp->transport_err = 0;
2086*44704f69SBart Van Assche if (NULL == cmdp) {
2087*44704f69SBart Van Assche if (! psp->have_nvme_cmd)
2088*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
2089*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2090*44704f69SBart Van Assche is_read = psp->is_read;
2091*44704f69SBart Van Assche dlen = psp->dxfer_len;
2092*44704f69SBart Van Assche dp = psp->dxferp;
2093*44704f69SBart Van Assche }
2094*44704f69SBart Van Assche if (vb > 2) {
2095*44704f69SBart Van Assche pr2ws("NVMe is_read=%s, dlen=%u, command:\n",
2096*44704f69SBart Van Assche (is_read ? "true" : "false"), dlen);
2097*44704f69SBart Van Assche hex2stderr((const uint8_t *)cmdp, cmd_len, 1);
2098*44704f69SBart Van Assche if ((vb > 3) && (! is_read) && dp) {
2099*44704f69SBart Van Assche if (dlen > 0) {
2100*44704f69SBart Van Assche n = dlen;
2101*44704f69SBart Van Assche if ((dlen < 512) || (vb > 5))
2102*44704f69SBart Van Assche pr2ws("\nData-out buffer (%u bytes):\n", n);
2103*44704f69SBart Van Assche else {
2104*44704f69SBart Van Assche pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n);
2105*44704f69SBart Van Assche n = 512;
2106*44704f69SBart Van Assche }
2107*44704f69SBart Van Assche hex2stderr((const uint8_t *)dp, n, 0);
2108*44704f69SBart Van Assche }
2109*44704f69SBart Van Assche }
2110*44704f69SBart Van Assche }
2111*44704f69SBart Van Assche alloc_len = sizeof(NVME_PASS_THROUGH_IOCTL) + dlen;
2112*44704f69SBart Van Assche pthru = (NVME_PASS_THROUGH_IOCTL *)sg_memalign(alloc_len, pg_sz,
2113*44704f69SBart Van Assche &free_pthru, false);
2114*44704f69SBart Van Assche if (NULL == pthru) {
2115*44704f69SBart Van Assche res = sg_convert_errno(ENOMEM);
2116*44704f69SBart Van Assche if (vb > 1)
2117*44704f69SBart Van Assche pr2ws("%s: unable to allocate memory\n", __func__);
2118*44704f69SBart Van Assche psp->os_err = res;
2119*44704f69SBart Van Assche return -res;
2120*44704f69SBart Van Assche }
2121*44704f69SBart Van Assche if (dp && (dlen > 0) && (! is_read))
2122*44704f69SBart Van Assche memcpy(pthru->DataBuffer, dp, dlen); /* dout-out buffer */
2123*44704f69SBart Van Assche /* Set NVMe command */
2124*44704f69SBart Van Assche pthru->SrbIoCtrl.HeaderLength = sizeof(SRB_IO_CONTROL);
2125*44704f69SBart Van Assche memcpy(pthru->SrbIoCtrl.Signature, NVME_SIG_STR, sizeof(NVME_SIG_STR)-1);
2126*44704f69SBart Van Assche pthru->SrbIoCtrl.Timeout = (time_secs > 0) ? time_secs : DEF_TIMEOUT;
2127*44704f69SBart Van Assche pthru->SrbIoCtrl.ControlCode = NVME_PASS_THROUGH_SRB_IO_CODE;
2128*44704f69SBart Van Assche pthru->SrbIoCtrl.ReturnCode = 0;
2129*44704f69SBart Van Assche pthru->SrbIoCtrl.Length = alloc_len - sizeof(SRB_IO_CONTROL);
2130*44704f69SBart Van Assche
2131*44704f69SBart Van Assche memcpy(pthru->NVMeCmd, cmdp, cmd_len);
2132*44704f69SBart Van Assche if (dlen > 0)
2133*44704f69SBart Van Assche pthru->Direction = is_read ? 2 : 1;
2134*44704f69SBart Van Assche else
2135*44704f69SBart Van Assche pthru->Direction = 0;
2136*44704f69SBart Van Assche pthru->ReturnBufferLen = alloc_len;
2137*44704f69SBart Van Assche shp = get_open_pt_handle(psp, psp->dev_fd, vb > 1);
2138*44704f69SBart Van Assche if (NULL == shp) {
2139*44704f69SBart Van Assche res = -psp->os_err; /* -ENODEV */
2140*44704f69SBart Van Assche goto err_out;
2141*44704f69SBart Van Assche }
2142*44704f69SBart Van Assche
2143*44704f69SBart Van Assche ok = DeviceIoControl(shp->fh, IOCTL_SCSI_MINIPORT, pthru, alloc_len,
2144*44704f69SBart Van Assche pthru, alloc_len, &num_out, (OVERLAPPED*)0);
2145*44704f69SBart Van Assche if (! ok) {
2146*44704f69SBart Van Assche n = (uint32_t)GetLastError();
2147*44704f69SBart Van Assche psp->transport_err = n;
2148*44704f69SBart Van Assche psp->os_err = EIO; /* simulate Unix error, */
2149*44704f69SBart Van Assche if (vb > 2) {
2150*44704f69SBart Van Assche char b[128];
2151*44704f69SBart Van Assche
2152*44704f69SBart Van Assche pr2ws("%s: IOCTL_SCSI_MINIPORT failed: %s [%u]\n", __func__,
2153*44704f69SBart Van Assche get_err_str(n, sizeof(b), b), n);
2154*44704f69SBart Van Assche }
2155*44704f69SBart Van Assche }
2156*44704f69SBart Van Assche /* nvme_status is SCT|SC, therefore it excludes DNR+More */
2157*44704f69SBart Van Assche psp->nvme_status = 0x3ff & (pthru->CplEntry[3] >> 17);
2158*44704f69SBart Van Assche if (psp->nvme_status && (vb > 1)) {
2159*44704f69SBart Van Assche uint16_t s = psp->nvme_status;
2160*44704f69SBart Van Assche char b[80];
2161*44704f69SBart Van Assche
2162*44704f69SBart Van Assche pr2ws("%s: opcode=0x%x failed: NVMe status: %s [0x%x]\n", __func__,
2163*44704f69SBart Van Assche cmdp[0], sg_get_nvme_cmd_status_str(s, sizeof(b), b), s);
2164*44704f69SBart Van Assche }
2165*44704f69SBart Van Assche psp->nvme_result = sg_get_unaligned_le32(pthru->CplEntry + 0);
2166*44704f69SBart Van Assche
2167*44704f69SBart Van Assche psp->sense_resid = 0;
2168*44704f69SBart Van Assche if (psp->nvme_direct && sbp && (slen > 3)) {
2169*44704f69SBart Van Assche /* build 16 byte "sense" buffer */
2170*44704f69SBart Van Assche n = (slen < 16) ? slen : 16;
2171*44704f69SBart Van Assche memset(sbp, 0 , n);
2172*44704f69SBart Van Assche psp->sense_resid = (slen > 16) ? (slen - 16) : 0;
2173*44704f69SBart Van Assche sg_put_unaligned_le32(pthru->CplEntry[0], sbp + SG_NVME_PT_CQ_DW0);
2174*44704f69SBart Van Assche if (n > 7) {
2175*44704f69SBart Van Assche sg_put_unaligned_le32(pthru->CplEntry[1],
2176*44704f69SBart Van Assche sbp + SG_NVME_PT_CQ_DW1);
2177*44704f69SBart Van Assche if (n > 11) {
2178*44704f69SBart Van Assche sg_put_unaligned_le32(pthru->CplEntry[2],
2179*44704f69SBart Van Assche sbp + SG_NVME_PT_CQ_DW2);
2180*44704f69SBart Van Assche if (n > 15)
2181*44704f69SBart Van Assche sg_put_unaligned_le32(pthru->CplEntry[3],
2182*44704f69SBart Van Assche sbp + SG_NVME_PT_CQ_DW3);
2183*44704f69SBart Van Assche }
2184*44704f69SBart Van Assche }
2185*44704f69SBart Van Assche }
2186*44704f69SBart Van Assche if (! ok) {
2187*44704f69SBart Van Assche res = -psp->os_err;
2188*44704f69SBart Van Assche goto err_out;
2189*44704f69SBart Van Assche } else if (psp->nvme_status) {
2190*44704f69SBart Van Assche res = SG_LIB_NVME_STATUS;
2191*44704f69SBart Van Assche goto err_out;
2192*44704f69SBart Van Assche }
2193*44704f69SBart Van Assche
2194*44704f69SBart Van Assche if (dp && (dlen > 0) && is_read) {
2195*44704f69SBart Van Assche memcpy(dp, pthru->DataBuffer, dlen); /* data-in buffer */
2196*44704f69SBart Van Assche if (vb > 3) {
2197*44704f69SBart Van Assche n = dlen;
2198*44704f69SBart Van Assche if ((dlen < 1024) || (vb > 5))
2199*44704f69SBart Van Assche pr2ws("\nData-in buffer (%u bytes):\n", n);
2200*44704f69SBart Van Assche else {
2201*44704f69SBart Van Assche pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n);
2202*44704f69SBart Van Assche n = 1024;
2203*44704f69SBart Van Assche }
2204*44704f69SBart Van Assche hex2stderr((const uint8_t *)dp, n, 0);
2205*44704f69SBart Van Assche }
2206*44704f69SBart Van Assche }
2207*44704f69SBart Van Assche res = 0;
2208*44704f69SBart Van Assche err_out:
2209*44704f69SBart Van Assche if (free_pthru)
2210*44704f69SBart Van Assche free(free_pthru);
2211*44704f69SBart Van Assche return res;
2212*44704f69SBart Van Assche }
2213*44704f69SBart Van Assche
2214*44704f69SBart Van Assche #endif /* W10_NVME_NON_PASSTHRU */
2215*44704f69SBart Van Assche
2216*44704f69SBart Van Assche
2217*44704f69SBart Van Assche static void
sntl_check_enclosure_override(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int vb)2218*44704f69SBart Van Assche sntl_check_enclosure_override(struct sg_pt_win32_scsi * psp,
2219*44704f69SBart Van Assche struct sg_pt_handle * shp, int vb)
2220*44704f69SBart Van Assche {
2221*44704f69SBart Van Assche uint8_t * up = psp->nvme_id_ctlp;
2222*44704f69SBart Van Assche uint8_t nvmsr;
2223*44704f69SBart Van Assche
2224*44704f69SBart Van Assche if (NULL == up)
2225*44704f69SBart Van Assche return;
2226*44704f69SBart Van Assche nvmsr = up[253];
2227*44704f69SBart Van Assche if (vb > 3)
2228*44704f69SBart Van Assche pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr);
2229*44704f69SBart Van Assche shp->dev_stat.id_ctl253 = nvmsr;
2230*44704f69SBart Van Assche switch (shp->dev_stat.enclosure_override) {
2231*44704f69SBart Van Assche case 0x0: /* no override */
2232*44704f69SBart Van Assche if (0x3 & nvmsr) {
2233*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_DISK;
2234*44704f69SBart Van Assche shp->dev_stat.enc_serv = 1;
2235*44704f69SBart Van Assche } else if (0x2 & nvmsr) {
2236*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_SES;
2237*44704f69SBart Van Assche shp->dev_stat.enc_serv = 1;
2238*44704f69SBart Van Assche } else if (0x1 & nvmsr) {
2239*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_DISK;
2240*44704f69SBart Van Assche shp->dev_stat.enc_serv = 0;
2241*44704f69SBart Van Assche } else {
2242*44704f69SBart Van Assche uint32_t nn = sg_get_unaligned_le32(up + 516);
2243*44704f69SBart Van Assche
2244*44704f69SBart Van Assche shp->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN;
2245*44704f69SBart Van Assche shp->dev_stat.enc_serv = 0;
2246*44704f69SBart Van Assche }
2247*44704f69SBart Van Assche break;
2248*44704f69SBart Van Assche case 0x1: /* override to SES device */
2249*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_SES;
2250*44704f69SBart Van Assche shp->dev_stat.enc_serv = 1;
2251*44704f69SBart Van Assche break;
2252*44704f69SBart Van Assche case 0x2: /* override to disk with attached SES device */
2253*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_DISK;
2254*44704f69SBart Van Assche shp->dev_stat.enc_serv = 1;
2255*44704f69SBart Van Assche break;
2256*44704f69SBart Van Assche case 0x3: /* override to SAFTE device (PDT_PROCESSOR) */
2257*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_PROCESSOR;
2258*44704f69SBart Van Assche shp->dev_stat.enc_serv = 1;
2259*44704f69SBart Van Assche break;
2260*44704f69SBart Van Assche case 0xff: /* override to normal disk */
2261*44704f69SBart Van Assche shp->dev_stat.pdt = PDT_DISK;
2262*44704f69SBart Van Assche shp->dev_stat.enc_serv = 0;
2263*44704f69SBart Van Assche break;
2264*44704f69SBart Van Assche default:
2265*44704f69SBart Van Assche pr2ws("%s: unknown enclosure_override value: %d\n", __func__,
2266*44704f69SBart Van Assche shp->dev_stat.enclosure_override);
2267*44704f69SBart Van Assche break;
2268*44704f69SBart Van Assche }
2269*44704f69SBart Van Assche }
2270*44704f69SBart Van Assche
2271*44704f69SBart Van Assche /* Returns 0 on success; otherwise a positive value is returned */
2272*44704f69SBart Van Assche static int
sntl_cache_identity(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int time_secs,int vb)2273*44704f69SBart Van Assche sntl_cache_identity(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2274*44704f69SBart Van Assche int time_secs, int vb)
2275*44704f69SBart Van Assche {
2276*44704f69SBart Van Assche static const bool is_read = true;
2277*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
2278*44704f69SBart Van Assche int ret;
2279*44704f69SBart Van Assche uint8_t * up;
2280*44704f69SBart Van Assche uint8_t * cmdp;
2281*44704f69SBart Van Assche
2282*44704f69SBart Van Assche up = sg_memalign(((pg_sz < 4096) ? 4096 : pg_sz), pg_sz,
2283*44704f69SBart Van Assche &psp->free_nvme_id_ctlp, false);
2284*44704f69SBart Van Assche psp->nvme_id_ctlp = up;
2285*44704f69SBart Van Assche if (NULL == up) {
2286*44704f69SBart Van Assche pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
2287*44704f69SBart Van Assche return -ENOMEM;
2288*44704f69SBart Van Assche }
2289*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2290*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2291*44704f69SBart Van Assche cmdp[0] = 0x6; /* Identify */
2292*44704f69SBart Van Assche /* leave nsid as 0, should it be broadcast (0xffffffff) ? */
2293*44704f69SBart Van Assche /* CNS=0x1 Identify controller: */
2294*44704f69SBart Van Assche sg_put_unaligned_le32(0x1, cmdp + SG_NVME_PT_CDW10);
2295*44704f69SBart Van Assche sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)up, cmdp + SG_NVME_PT_ADDR);
2296*44704f69SBart Van Assche sg_put_unaligned_le32(pg_sz, cmdp + SG_NVME_PT_DATA_LEN);
2297*44704f69SBart Van Assche ret = do_nvme_admin_cmd(psp, shp, cmdp, up, 4096, is_read, time_secs,
2298*44704f69SBart Van Assche vb);
2299*44704f69SBart Van Assche if (0 == ret)
2300*44704f69SBart Van Assche sntl_check_enclosure_override(psp, shp, vb);
2301*44704f69SBart Van Assche return ret;
2302*44704f69SBart Van Assche }
2303*44704f69SBart Van Assche
2304*44704f69SBart Van Assche
2305*44704f69SBart Van Assche static const char * nvme_scsi_vendor_str = "NVMe ";
2306*44704f69SBart Van Assche static const uint16_t inq_resp_len = 36;
2307*44704f69SBart Van Assche
2308*44704f69SBart Van Assche static int
sntl_inq(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2309*44704f69SBart Van Assche sntl_inq(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2310*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2311*44704f69SBart Van Assche {
2312*44704f69SBart Van Assche bool evpd;
2313*44704f69SBart Van Assche bool cp_id_ctl = false;
2314*44704f69SBart Van Assche int res;
2315*44704f69SBart Van Assche uint16_t n, alloc_len, pg_cd;
2316*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
2317*44704f69SBart Van Assche uint8_t * nvme_id_ns = NULL;
2318*44704f69SBart Van Assche uint8_t * free_nvme_id_ns = NULL;
2319*44704f69SBart Van Assche uint8_t inq_dout[256];
2320*44704f69SBart Van Assche uint8_t * cmdp;
2321*44704f69SBart Van Assche
2322*44704f69SBart Van Assche if (vb > 3)
2323*44704f69SBart Van Assche pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2324*44704f69SBart Van Assche if (0x2 & cdbp[1]) { /* Reject CmdDt=1 */
2325*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 1, 1, vb);
2326*44704f69SBart Van Assche return 0;
2327*44704f69SBart Van Assche }
2328*44704f69SBart Van Assche if (NULL == psp->nvme_id_ctlp) {
2329*44704f69SBart Van Assche res = sntl_cache_identity(psp, shp, time_secs, vb);
2330*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2331*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2332*44704f69SBart Van Assche return 0;
2333*44704f69SBart Van Assche } else if (res) /* should be negative errno */
2334*44704f69SBart Van Assche return res;
2335*44704f69SBart Van Assche }
2336*44704f69SBart Van Assche memset(inq_dout, 0, sizeof(inq_dout));
2337*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be16(cdbp + 3);
2338*44704f69SBart Van Assche evpd = !!(0x1 & cdbp[1]);
2339*44704f69SBart Van Assche pg_cd = cdbp[2];
2340*44704f69SBart Van Assche if (evpd) { /* VPD page responses */
2341*44704f69SBart Van Assche switch (pg_cd) {
2342*44704f69SBart Van Assche case 0:
2343*44704f69SBart Van Assche /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
2344*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2345*44704f69SBart Van Assche n = 11;
2346*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2347*44704f69SBart Van Assche inq_dout[4] = 0x0;
2348*44704f69SBart Van Assche inq_dout[5] = 0x80;
2349*44704f69SBart Van Assche inq_dout[6] = 0x83;
2350*44704f69SBart Van Assche inq_dout[7] = 0x86;
2351*44704f69SBart Van Assche inq_dout[8] = 0x87;
2352*44704f69SBart Van Assche inq_dout[9] = 0x92;
2353*44704f69SBart Van Assche inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */
2354*44704f69SBart Van Assche break;
2355*44704f69SBart Van Assche case 0x80:
2356*44704f69SBart Van Assche /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */
2357*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2358*44704f69SBart Van Assche n = 24;
2359*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2360*44704f69SBart Van Assche memcpy(inq_dout + 4, psp->nvme_id_ctlp + 4, 20); /* SN */
2361*44704f69SBart Van Assche break;
2362*44704f69SBart Van Assche case 0x83:
2363*44704f69SBart Van Assche if ((psp->nvme_nsid > 0) &&
2364*44704f69SBart Van Assche (psp->nvme_nsid < SG_NVME_BROADCAST_NSID)) {
2365*44704f69SBart Van Assche nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns,
2366*44704f69SBart Van Assche false);
2367*44704f69SBart Van Assche if (nvme_id_ns) {
2368*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2369*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2370*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0x6; /* Identify */
2371*44704f69SBart Van Assche sg_put_unaligned_le32(psp->nvme_nsid,
2372*44704f69SBart Van Assche cmdp + SG_NVME_PT_NSID);
2373*44704f69SBart Van Assche /* CNS=0x0 Identify controller: */
2374*44704f69SBart Van Assche sg_put_unaligned_le32(0x0, cmdp + SG_NVME_PT_CDW10);
2375*44704f69SBart Van Assche sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)nvme_id_ns,
2376*44704f69SBart Van Assche cmdp + SG_NVME_PT_ADDR);
2377*44704f69SBart Van Assche sg_put_unaligned_le32(pg_sz, cmdp + SG_NVME_PT_DATA_LEN);
2378*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, nvme_id_ns, pg_sz,
2379*44704f69SBart Van Assche true, time_secs, vb > 3);
2380*44704f69SBart Van Assche if (res) {
2381*44704f69SBart Van Assche free(free_nvme_id_ns);
2382*44704f69SBart Van Assche free_nvme_id_ns = NULL;
2383*44704f69SBart Van Assche nvme_id_ns = NULL;
2384*44704f69SBart Van Assche }
2385*44704f69SBart Van Assche }
2386*44704f69SBart Van Assche }
2387*44704f69SBart Van Assche n = sg_make_vpd_devid_for_nvme(psp->nvme_id_ctlp, nvme_id_ns,
2388*44704f69SBart Van Assche 0 /* pdt */, -1 /*tproto */,
2389*44704f69SBart Van Assche inq_dout, sizeof(inq_dout));
2390*44704f69SBart Van Assche if (n > 3)
2391*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2392*44704f69SBart Van Assche if (free_nvme_id_ns) {
2393*44704f69SBart Van Assche free(free_nvme_id_ns);
2394*44704f69SBart Van Assche free_nvme_id_ns = NULL;
2395*44704f69SBart Van Assche nvme_id_ns = NULL;
2396*44704f69SBart Van Assche }
2397*44704f69SBart Van Assche break;
2398*44704f69SBart Van Assche case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */
2399*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2400*44704f69SBart Van Assche n = 64;
2401*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2402*44704f69SBart Van Assche inq_dout[5] = 0x1; /* SIMPSUP=1 */
2403*44704f69SBart Van Assche inq_dout[7] = 0x1; /* LUICLR=1 */
2404*44704f69SBart Van Assche inq_dout[13] = 0x40; /* max supported sense data length */
2405*44704f69SBart Van Assche break;
2406*44704f69SBart Van Assche case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */
2407*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2408*44704f69SBart Van Assche n = 8;
2409*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2410*44704f69SBart Van Assche inq_dout[4] = 0x3f; /* all mode pages */
2411*44704f69SBart Van Assche inq_dout[5] = 0xff; /* and their sub-pages */
2412*44704f69SBart Van Assche inq_dout[6] = 0x80; /* MLUS=1, policy=shared */
2413*44704f69SBart Van Assche break;
2414*44704f69SBart Van Assche case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */
2415*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2416*44704f69SBart Van Assche n = 10;
2417*44704f69SBart Van Assche sg_put_unaligned_be16(n - 4, inq_dout + 2);
2418*44704f69SBart Van Assche inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */
2419*44704f69SBart Van Assche break;
2420*44704f69SBart Van Assche case SG_NVME_VPD_NICR: /* 0xde */
2421*44704f69SBart Van Assche inq_dout[1] = pg_cd;
2422*44704f69SBart Van Assche sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2);
2423*44704f69SBart Van Assche n = 16 + 4096;
2424*44704f69SBart Van Assche cp_id_ctl = true;
2425*44704f69SBart Van Assche break;
2426*44704f69SBart Van Assche default: /* Point to page_code field in cdb */
2427*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 2, 7, vb);
2428*44704f69SBart Van Assche return 0;
2429*44704f69SBart Van Assche }
2430*44704f69SBart Van Assche if (alloc_len > 0) {
2431*44704f69SBart Van Assche n = (alloc_len < n) ? alloc_len : n;
2432*44704f69SBart Van Assche n = (n < psp->dxfer_len) ? n : psp->dxfer_len;
2433*44704f69SBart Van Assche psp->resid = psp->dxfer_len - n;
2434*44704f69SBart Van Assche if (n > 0) {
2435*44704f69SBart Van Assche if (cp_id_ctl) {
2436*44704f69SBart Van Assche memcpy(psp->dxferp, inq_dout, (n < 16 ? n : 16));
2437*44704f69SBart Van Assche if (n > 16)
2438*44704f69SBart Van Assche memcpy(psp->dxferp + 16,
2439*44704f69SBart Van Assche psp->nvme_id_ctlp, n - 16);
2440*44704f69SBart Van Assche } else
2441*44704f69SBart Van Assche memcpy(psp->dxferp, inq_dout, n);
2442*44704f69SBart Van Assche }
2443*44704f69SBart Van Assche }
2444*44704f69SBart Van Assche } else { /* Standard INQUIRY response */
2445*44704f69SBart Van Assche /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */
2446*44704f69SBart Van Assche inq_dout[0] = (PDT_MASK & shp->dev_stat.pdt); /* (PQ=0)<<5 */
2447*44704f69SBart Van Assche /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6; rest reserved */
2448*44704f69SBart Van Assche inq_dout[2] = 6; /* version: SPC-4 */
2449*44704f69SBart Van Assche inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */
2450*44704f69SBart Van Assche inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */
2451*44704f69SBart Van Assche inq_dout[6] = shp->dev_stat.enc_serv ? 0x40 : 0;
2452*44704f69SBart Van Assche inq_dout[7] = 0x2; /* CMDQUE=1 */
2453*44704f69SBart Van Assche memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8); /* NVMe not Intel */
2454*44704f69SBart Van Assche memcpy(inq_dout + 16, psp->nvme_id_ctlp + 24, 16); /* Prod <-- MN */
2455*44704f69SBart Van Assche memcpy(inq_dout + 32, psp->nvme_id_ctlp + 64, 4); /* Rev <-- FR */
2456*44704f69SBart Van Assche if (alloc_len > 0) {
2457*44704f69SBart Van Assche n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len;
2458*44704f69SBart Van Assche n = (n < psp->dxfer_len) ? n : psp->dxfer_len;
2459*44704f69SBart Van Assche psp->resid = psp->dxfer_len - n;
2460*44704f69SBart Van Assche if (n > 0)
2461*44704f69SBart Van Assche memcpy(psp->dxferp, inq_dout, n);
2462*44704f69SBart Van Assche }
2463*44704f69SBart Van Assche }
2464*44704f69SBart Van Assche return 0;
2465*44704f69SBart Van Assche }
2466*44704f69SBart Van Assche
2467*44704f69SBart Van Assche static int
sntl_rluns(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2468*44704f69SBart Van Assche sntl_rluns(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2469*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2470*44704f69SBart Van Assche {
2471*44704f69SBart Van Assche int res;
2472*44704f69SBart Van Assche uint16_t sel_report;
2473*44704f69SBart Van Assche uint32_t alloc_len, k, n, num, max_nsid;
2474*44704f69SBart Van Assche uint8_t * rl_doutp;
2475*44704f69SBart Van Assche uint8_t * up;
2476*44704f69SBart Van Assche
2477*44704f69SBart Van Assche if (vb > 3)
2478*44704f69SBart Van Assche pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2479*44704f69SBart Van Assche
2480*44704f69SBart Van Assche sel_report = cdbp[2];
2481*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be32(cdbp + 6);
2482*44704f69SBart Van Assche if (NULL == psp->nvme_id_ctlp) {
2483*44704f69SBart Van Assche res = sntl_cache_identity(psp, shp, time_secs, vb);
2484*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2485*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2486*44704f69SBart Van Assche return 0;
2487*44704f69SBart Van Assche } else if (res)
2488*44704f69SBart Van Assche return res;
2489*44704f69SBart Van Assche }
2490*44704f69SBart Van Assche max_nsid = sg_get_unaligned_le32(psp->nvme_id_ctlp + 516);
2491*44704f69SBart Van Assche switch (sel_report) {
2492*44704f69SBart Van Assche case 0:
2493*44704f69SBart Van Assche case 2:
2494*44704f69SBart Van Assche num = max_nsid;
2495*44704f69SBart Van Assche break;
2496*44704f69SBart Van Assche case 1:
2497*44704f69SBart Van Assche case 0x10:
2498*44704f69SBart Van Assche case 0x12:
2499*44704f69SBart Van Assche num = 0;
2500*44704f69SBart Van Assche break;
2501*44704f69SBart Van Assche case 0x11:
2502*44704f69SBart Van Assche num = (1 == psp->nvme_nsid) ? max_nsid : 0;
2503*44704f69SBart Van Assche break;
2504*44704f69SBart Van Assche default:
2505*44704f69SBart Van Assche if (vb > 1)
2506*44704f69SBart Van Assche pr2ws("%s: bad select_report value: 0x%x\n", __func__,
2507*44704f69SBart Van Assche sel_report);
2508*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 2, 7, vb);
2509*44704f69SBart Van Assche return 0;
2510*44704f69SBart Van Assche }
2511*44704f69SBart Van Assche rl_doutp = (uint8_t *)calloc(num + 1, 8);
2512*44704f69SBart Van Assche if (NULL == rl_doutp) {
2513*44704f69SBart Van Assche pr2ws("%s: calloc() failed to get memory\n", __func__);
2514*44704f69SBart Van Assche return -ENOMEM;
2515*44704f69SBart Van Assche }
2516*44704f69SBart Van Assche for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8)
2517*44704f69SBart Van Assche sg_put_unaligned_be16(k, up);
2518*44704f69SBart Van Assche n = num * 8;
2519*44704f69SBart Van Assche sg_put_unaligned_be32(n, rl_doutp);
2520*44704f69SBart Van Assche n+= 8;
2521*44704f69SBart Van Assche if (alloc_len > 0) {
2522*44704f69SBart Van Assche n = (alloc_len < n) ? alloc_len : n;
2523*44704f69SBart Van Assche n = (n < psp->dxfer_len) ? n : psp->dxfer_len;
2524*44704f69SBart Van Assche psp->resid = psp->dxfer_len - n;
2525*44704f69SBart Van Assche if (n > 0)
2526*44704f69SBart Van Assche memcpy(psp->dxferp, rl_doutp, n);
2527*44704f69SBart Van Assche }
2528*44704f69SBart Van Assche res = 0;
2529*44704f69SBart Van Assche free(rl_doutp);
2530*44704f69SBart Van Assche return res;
2531*44704f69SBart Van Assche }
2532*44704f69SBart Van Assche
2533*44704f69SBart Van Assche static int
sntl_tur(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int time_secs,int vb)2534*44704f69SBart Van Assche sntl_tur(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2535*44704f69SBart Van Assche int time_secs, int vb)
2536*44704f69SBart Van Assche {
2537*44704f69SBart Van Assche int res;
2538*44704f69SBart Van Assche uint32_t pow_state;
2539*44704f69SBart Van Assche uint8_t * cmdp;
2540*44704f69SBart Van Assche
2541*44704f69SBart Van Assche if (vb > 4)
2542*44704f69SBart Van Assche pr2ws("%s: enter\n", __func__);
2543*44704f69SBart Van Assche if (NULL == psp->nvme_id_ctlp) {
2544*44704f69SBart Van Assche res = sntl_cache_identity(psp, shp, time_secs, vb);
2545*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2546*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2547*44704f69SBart Van Assche return 0;
2548*44704f69SBart Van Assche } else if (res)
2549*44704f69SBart Van Assche return res;
2550*44704f69SBart Van Assche }
2551*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2552*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2553*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0xa; /* Get features */
2554*44704f69SBart Van Assche sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, cmdp + SG_NVME_PT_NSID);
2555*44704f69SBart Van Assche /* SEL=0 (current), Feature=2 Power Management */
2556*44704f69SBart Van Assche sg_put_unaligned_le32(0x2, cmdp + SG_NVME_PT_CDW10);
2557*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs, vb);
2558*44704f69SBart Van Assche if (0 != res) {
2559*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2560*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2561*44704f69SBart Van Assche return 0;
2562*44704f69SBart Van Assche } else
2563*44704f69SBart Van Assche return res;
2564*44704f69SBart Van Assche } else {
2565*44704f69SBart Van Assche psp->os_err = 0;
2566*44704f69SBart Van Assche psp->nvme_status = 0;
2567*44704f69SBart Van Assche }
2568*44704f69SBart Van Assche pow_state = (0x1f & psp->nvme_result);
2569*44704f69SBart Van Assche if (vb > 3)
2570*44704f69SBart Van Assche pr2ws("%s: pow_state=%u\n", __func__, pow_state);
2571*44704f69SBart Van Assche #if 0 /* pow_state bounces around too much on laptop */
2572*44704f69SBart Van Assche if (pow_state)
2573*44704f69SBart Van Assche mk_sense_asc_ascq(psp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0,
2574*44704f69SBart Van Assche vb);
2575*44704f69SBart Van Assche #endif
2576*44704f69SBart Van Assche return 0;
2577*44704f69SBart Van Assche }
2578*44704f69SBart Van Assche
2579*44704f69SBart Van Assche static int
sntl_req_sense(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2580*44704f69SBart Van Assche sntl_req_sense(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2581*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2582*44704f69SBart Van Assche {
2583*44704f69SBart Van Assche bool desc;
2584*44704f69SBart Van Assche int res;
2585*44704f69SBart Van Assche uint32_t pow_state, alloc_len, n;
2586*44704f69SBart Van Assche uint8_t rs_dout[64];
2587*44704f69SBart Van Assche uint8_t * cmdp;
2588*44704f69SBart Van Assche
2589*44704f69SBart Van Assche if (vb > 3)
2590*44704f69SBart Van Assche pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2591*44704f69SBart Van Assche if (NULL == psp->nvme_id_ctlp) {
2592*44704f69SBart Van Assche res = sntl_cache_identity(psp, shp, time_secs, vb);
2593*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2594*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2595*44704f69SBart Van Assche return 0;
2596*44704f69SBart Van Assche } else if (res)
2597*44704f69SBart Van Assche return res;
2598*44704f69SBart Van Assche }
2599*44704f69SBart Van Assche desc = !!(0x1 & cdbp[1]);
2600*44704f69SBart Van Assche alloc_len = cdbp[4];
2601*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2602*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2603*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0xa; /* Get features */
2604*44704f69SBart Van Assche sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, cmdp + SG_NVME_PT_NSID);
2605*44704f69SBart Van Assche /* SEL=0 (current), Feature=2 Power Management */
2606*44704f69SBart Van Assche sg_put_unaligned_le32(0x2, cmdp + SG_NVME_PT_CDW10);
2607*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs, vb);
2608*44704f69SBart Van Assche if (0 != res) {
2609*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2610*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2611*44704f69SBart Van Assche return 0;
2612*44704f69SBart Van Assche } else
2613*44704f69SBart Van Assche return res;
2614*44704f69SBart Van Assche } else {
2615*44704f69SBart Van Assche psp->os_err = 0;
2616*44704f69SBart Van Assche psp->nvme_status = 0;
2617*44704f69SBart Van Assche }
2618*44704f69SBart Van Assche psp->sense_resid = psp->sense_len;
2619*44704f69SBart Van Assche pow_state = (0x1f & psp->nvme_result);
2620*44704f69SBart Van Assche if (vb > 3)
2621*44704f69SBart Van Assche pr2ws("%s: pow_state=%u\n", __func__, pow_state);
2622*44704f69SBart Van Assche memset(rs_dout, 0, sizeof(rs_dout));
2623*44704f69SBart Van Assche if (pow_state)
2624*44704f69SBart Van Assche sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
2625*44704f69SBart Van Assche LOW_POWER_COND_ON_ASC, 0);
2626*44704f69SBart Van Assche else
2627*44704f69SBart Van Assche sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE,
2628*44704f69SBart Van Assche NO_ADDITIONAL_SENSE, 0);
2629*44704f69SBart Van Assche n = desc ? 8 : 18;
2630*44704f69SBart Van Assche n = (n < alloc_len) ? n : alloc_len;
2631*44704f69SBart Van Assche n = (n < psp->dxfer_len) ? n : psp->dxfer_len;
2632*44704f69SBart Van Assche psp->resid = psp->dxfer_len - n;
2633*44704f69SBart Van Assche if (n > 0)
2634*44704f69SBart Van Assche memcpy(psp->dxferp, rs_dout, n);
2635*44704f69SBart Van Assche return 0;
2636*44704f69SBart Van Assche }
2637*44704f69SBart Van Assche
2638*44704f69SBart Van Assche static int
sntl_mode_ss(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2639*44704f69SBart Van Assche sntl_mode_ss(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2640*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2641*44704f69SBart Van Assche {
2642*44704f69SBart Van Assche bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]);
2643*44704f69SBart Van Assche int res, n, len;
2644*44704f69SBart Van Assche uint8_t * bp;
2645*44704f69SBart Van Assche struct sg_sntl_result_t sntl_result;
2646*44704f69SBart Van Assche
2647*44704f69SBart Van Assche if (vb > 3)
2648*44704f69SBart Van Assche pr2ws("%s: mse%s, time_secs=%d\n", __func__,
2649*44704f69SBart Van Assche (is_msense ? "nse" : "lect"), time_secs);
2650*44704f69SBart Van Assche if (NULL == psp->nvme_id_ctlp) {
2651*44704f69SBart Van Assche res = sntl_cache_identity(psp, shp, time_secs, vb);
2652*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2653*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2654*44704f69SBart Van Assche return 0;
2655*44704f69SBart Van Assche } else if (res)
2656*44704f69SBart Van Assche return res;
2657*44704f69SBart Van Assche }
2658*44704f69SBart Van Assche if (is_msense) { /* MODE SENSE(10) */
2659*44704f69SBart Van Assche len = psp->dxfer_len;
2660*44704f69SBart Van Assche bp = psp->dxferp;
2661*44704f69SBart Van Assche n = sntl_resp_mode_sense10(&shp->dev_stat, cdbp, bp, len,
2662*44704f69SBart Van Assche &sntl_result);
2663*44704f69SBart Van Assche psp->resid = (n >= 0) ? len - n : len;
2664*44704f69SBart Van Assche } else { /* MODE SELECT(10) */
2665*44704f69SBart Van Assche uint8_t pre_enc_ov = shp->dev_stat.enclosure_override;
2666*44704f69SBart Van Assche
2667*44704f69SBart Van Assche len = psp->dxfer_len;
2668*44704f69SBart Van Assche bp = psp->dxferp;
2669*44704f69SBart Van Assche n = sntl_resp_mode_select10(&shp->dev_stat, cdbp, bp, len,
2670*44704f69SBart Van Assche &sntl_result);
2671*44704f69SBart Van Assche if (pre_enc_ov != shp->dev_stat.enclosure_override)
2672*44704f69SBart Van Assche sntl_check_enclosure_override(psp, shp, vb); /* ENC_OV changed */
2673*44704f69SBart Van Assche }
2674*44704f69SBart Van Assche if (n < 0) {
2675*44704f69SBart Van Assche int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit :
2676*44704f69SBart Van Assche -1;
2677*44704f69SBart Van Assche if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) &&
2678*44704f69SBart Van Assche (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) {
2679*44704f69SBart Van Assche if (INVALID_FIELD_IN_CDB == sntl_result.asc)
2680*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, sntl_result.in_byte, in_bit,
2681*44704f69SBart Van Assche vb);
2682*44704f69SBart Van Assche else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc)
2683*44704f69SBart Van Assche mk_sense_invalid_fld(psp, false, sntl_result.in_byte, in_bit,
2684*44704f69SBart Van Assche vb);
2685*44704f69SBart Van Assche else
2686*44704f69SBart Van Assche mk_sense_asc_ascq(psp, sntl_result.sk, sntl_result.asc,
2687*44704f69SBart Van Assche sntl_result.ascq, vb);
2688*44704f69SBart Van Assche } else
2689*44704f69SBart Van Assche pr2ws("%s: error but no sense?? n=%d\n", __func__, n);
2690*44704f69SBart Van Assche }
2691*44704f69SBart Van Assche return 0;
2692*44704f69SBart Van Assche }
2693*44704f69SBart Van Assche
2694*44704f69SBart Van Assche /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI
2695*44704f69SBart Van Assche * has a special command (SES Send) to tunnel through pages to an
2696*44704f69SBart Van Assche * enclosure. The NVMe enclosure is meant to understand the SES
2697*44704f69SBart Van Assche * (SCSI Enclosure Services) use of diagnostics pages that are
2698*44704f69SBart Van Assche * related to SES. */
2699*44704f69SBart Van Assche static int
sntl_senddiag(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2700*44704f69SBart Van Assche sntl_senddiag(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2701*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2702*44704f69SBart Van Assche {
2703*44704f69SBart Van Assche bool pf, self_test;
2704*44704f69SBart Van Assche int res;
2705*44704f69SBart Van Assche uint8_t st_cd, dpg_cd;
2706*44704f69SBart Van Assche uint32_t alloc_len, n, dout_len, dpg_len, nvme_dst;
2707*44704f69SBart Van Assche uint8_t * dop;
2708*44704f69SBart Van Assche uint8_t * cmdp;
2709*44704f69SBart Van Assche
2710*44704f69SBart Van Assche st_cd = 0x7 & (cdbp[1] >> 5);
2711*44704f69SBart Van Assche self_test = !! (0x4 & cdbp[1]);
2712*44704f69SBart Van Assche pf = !! (0x10 & cdbp[1]);
2713*44704f69SBart Van Assche if (vb > 3)
2714*44704f69SBart Van Assche pr2ws("%s: pf=%d, self_test=%d (st_code=%d)\n", __func__, (int)pf,
2715*44704f69SBart Van Assche (int)self_test, (int)st_cd);
2716*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2717*44704f69SBart Van Assche if (self_test || st_cd) {
2718*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2719*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0x14; /* Device self-test */
2720*44704f69SBart Van Assche /* just this namespace (if there is one) and controller */
2721*44704f69SBart Van Assche sg_put_unaligned_le32(psp->nvme_nsid, cmdp + SG_NVME_PT_NSID);
2722*44704f69SBart Van Assche switch (st_cd) {
2723*44704f69SBart Van Assche case 0: /* Here if self_test is set, do short self-test */
2724*44704f69SBart Van Assche case 1: /* Background short */
2725*44704f69SBart Van Assche case 5: /* Foreground short */
2726*44704f69SBart Van Assche nvme_dst = 1;
2727*44704f69SBart Van Assche break;
2728*44704f69SBart Van Assche case 2: /* Background extended */
2729*44704f69SBart Van Assche case 6: /* Foreground extended */
2730*44704f69SBart Van Assche nvme_dst = 2;
2731*44704f69SBart Van Assche break;
2732*44704f69SBart Van Assche case 4: /* Abort self-test */
2733*44704f69SBart Van Assche nvme_dst = 0xf;
2734*44704f69SBart Van Assche break;
2735*44704f69SBart Van Assche default:
2736*44704f69SBart Van Assche pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd);
2737*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 1, 7, vb);
2738*44704f69SBart Van Assche return 0;
2739*44704f69SBart Van Assche }
2740*44704f69SBart Van Assche sg_put_unaligned_le32(nvme_dst, cmdp + SG_NVME_PT_CDW10);
2741*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs,
2742*44704f69SBart Van Assche vb);
2743*44704f69SBart Van Assche if (0 != res) {
2744*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2745*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2746*44704f69SBart Van Assche return 0;
2747*44704f69SBart Van Assche } else
2748*44704f69SBart Van Assche return res;
2749*44704f69SBart Van Assche }
2750*44704f69SBart Van Assche }
2751*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
2752*44704f69SBart Van Assche dout_len = psp->dxfer_len;
2753*44704f69SBart Van Assche if (pf) {
2754*44704f69SBart Van Assche if (0 == alloc_len) {
2755*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 3, 7, vb);
2756*44704f69SBart Van Assche if (vb)
2757*44704f69SBart Van Assche pr2ws("%s: PF bit set bit param_list_len=0\n", __func__);
2758*44704f69SBart Van Assche return 0;
2759*44704f69SBart Van Assche }
2760*44704f69SBart Van Assche } else { /* PF bit clear */
2761*44704f69SBart Van Assche if (alloc_len) {
2762*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 3, 7, vb);
2763*44704f69SBart Van Assche if (vb)
2764*44704f69SBart Van Assche pr2ws("%s: param_list_len>0 but PF clear\n", __func__);
2765*44704f69SBart Van Assche return 0;
2766*44704f69SBart Van Assche } else
2767*44704f69SBart Van Assche return 0; /* nothing to do */
2768*44704f69SBart Van Assche if (dout_len > 0) {
2769*44704f69SBart Van Assche if (vb)
2770*44704f69SBart Van Assche pr2ws("%s: dout given but PF clear\n", __func__);
2771*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
2772*44704f69SBart Van Assche }
2773*44704f69SBart Van Assche }
2774*44704f69SBart Van Assche if (dout_len < 4) {
2775*44704f69SBart Van Assche if (vb)
2776*44704f69SBart Van Assche pr2ws("%s: dout length (%u bytes) too short\n", __func__,
2777*44704f69SBart Van Assche dout_len);
2778*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
2779*44704f69SBart Van Assche }
2780*44704f69SBart Van Assche n = dout_len;
2781*44704f69SBart Van Assche n = (n < alloc_len) ? n : alloc_len;
2782*44704f69SBart Van Assche dop = psp->dxferp;
2783*44704f69SBart Van Assche if (! sg_is_aligned(dop, 0)) { /* page aligned ? */
2784*44704f69SBart Van Assche if (vb)
2785*44704f69SBart Van Assche pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__,
2786*44704f69SBart Van Assche (uint64_t)(sg_uintptr_t)psp->dxferp);
2787*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
2788*44704f69SBart Van Assche }
2789*44704f69SBart Van Assche dpg_cd = dop[0];
2790*44704f69SBart Van Assche dpg_len = sg_get_unaligned_be16(dop + 2) + 4;
2791*44704f69SBart Van Assche /* should we allow for more than one D_PG is dout ?? */
2792*44704f69SBart Van Assche n = (n < dpg_len) ? n : dpg_len; /* not yet ... */
2793*44704f69SBart Van Assche
2794*44704f69SBart Van Assche if (vb)
2795*44704f69SBart Van Assche pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n",
2796*44704f69SBart Van Assche __func__, dpg_cd, dpg_len);
2797*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2798*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0x1d; /* MI Send */
2799*44704f69SBart Van Assche /* And 0x1d is same opcode as the SCSI SEND DIAGNOSTIC command */
2800*44704f69SBart Van Assche sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)dop,
2801*44704f69SBart Van Assche cmdp + SG_NVME_PT_ADDR);
2802*44704f69SBart Van Assche /* NVMe 4k page size. Maybe determine this? */
2803*44704f69SBart Van Assche /* N.B. Maybe n > 0x1000, is this a problem?? */
2804*44704f69SBart Van Assche sg_put_unaligned_le32(0x1000, cmdp + SG_NVME_PT_DATA_LEN);
2805*44704f69SBart Van Assche /* NVMe Message Header */
2806*44704f69SBart Van Assche sg_put_unaligned_le32(0x0804, cmdp + SG_NVME_PT_CDW10);
2807*44704f69SBart Van Assche /* NVME-MI SES Send; (0x8 -> NVME-MI SES Receive) */
2808*44704f69SBart Van Assche sg_put_unaligned_le32(0x9, cmdp + SG_NVME_PT_CDW11);
2809*44704f69SBart Van Assche /* 'n' is number of bytes SEND DIAGNOSTIC dpage */
2810*44704f69SBart Van Assche sg_put_unaligned_le32(n, cmdp + SG_NVME_PT_CDW13);
2811*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, dop, n, false, time_secs, vb);
2812*44704f69SBart Van Assche if (0 != res) {
2813*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2814*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2815*44704f69SBart Van Assche return 0;
2816*44704f69SBart Van Assche }
2817*44704f69SBart Van Assche }
2818*44704f69SBart Van Assche return res;
2819*44704f69SBart Van Assche }
2820*44704f69SBart Van Assche
2821*44704f69SBart Van Assche /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1)
2822*44704f69SBart Van Assche * NVMe-MI has a special command (SES Receive) to read pages through a
2823*44704f69SBart Van Assche * tunnel from an enclosure. The NVMe enclosure is meant to understand the
2824*44704f69SBart Van Assche * SES (SCSI Enclosure Services) use of diagnostics pages that are
2825*44704f69SBart Van Assche * related to SES. */
2826*44704f69SBart Van Assche static int
sntl_recvdiag(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2827*44704f69SBart Van Assche sntl_recvdiag(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2828*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2829*44704f69SBart Van Assche {
2830*44704f69SBart Van Assche bool pcv;
2831*44704f69SBart Van Assche int res;
2832*44704f69SBart Van Assche uint8_t dpg_cd;
2833*44704f69SBart Van Assche uint32_t alloc_len, n, din_len;
2834*44704f69SBart Van Assche uint8_t * dip;
2835*44704f69SBart Van Assche uint8_t * cmdp;
2836*44704f69SBart Van Assche
2837*44704f69SBart Van Assche pcv = !! (0x1 & cdbp[1]);
2838*44704f69SBart Van Assche dpg_cd = cdbp[2];
2839*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */
2840*44704f69SBart Van Assche if (vb > 3)
2841*44704f69SBart Van Assche pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__,
2842*44704f69SBart Van Assche dpg_cd, (int)pcv, alloc_len);
2843*44704f69SBart Van Assche din_len = psp->dxfer_len;
2844*44704f69SBart Van Assche n = (din_len < alloc_len) ? din_len : alloc_len;
2845*44704f69SBart Van Assche dip = psp->dxferp;
2846*44704f69SBart Van Assche if (! sg_is_aligned(dip, 0)) { /* page aligned ? */
2847*44704f69SBart Van Assche if (vb)
2848*44704f69SBart Van Assche pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__,
2849*44704f69SBart Van Assche (uint64_t)(sg_uintptr_t)psp->dxferp);
2850*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
2851*44704f69SBart Van Assche }
2852*44704f69SBart Van Assche
2853*44704f69SBart Van Assche if (vb)
2854*44704f69SBart Van Assche pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__,
2855*44704f69SBart Van Assche dpg_cd);
2856*44704f69SBart Van Assche cmdp = psp->nvme_cmd;
2857*44704f69SBart Van Assche memset(cmdp, 0, sizeof(psp->nvme_cmd));
2858*44704f69SBart Van Assche cmdp[SG_NVME_PT_OPCODE] = 0x1e; /* MI Receive */
2859*44704f69SBart Van Assche sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)dip,
2860*44704f69SBart Van Assche cmdp + SG_NVME_PT_ADDR);
2861*44704f69SBart Van Assche /* NVMe 4k page size. Maybe determine this? */
2862*44704f69SBart Van Assche /* N.B. Maybe n > 0x1000, is this a problem?? */
2863*44704f69SBart Van Assche sg_put_unaligned_le32(0x1000, cmdp + SG_NVME_PT_DATA_LEN);
2864*44704f69SBart Van Assche /* NVMe Message Header */
2865*44704f69SBart Van Assche sg_put_unaligned_le32(0x0804, cmdp + SG_NVME_PT_CDW10);
2866*44704f69SBart Van Assche /* NVME-MI SES Receive */
2867*44704f69SBart Van Assche sg_put_unaligned_le32(0x8, cmdp + SG_NVME_PT_CDW11);
2868*44704f69SBart Van Assche /* Diagnostic page code */
2869*44704f69SBart Van Assche sg_put_unaligned_le32(dpg_cd, cmdp + SG_NVME_PT_CDW12);
2870*44704f69SBart Van Assche /* 'n' is number of bytes expected in diagnostic page */
2871*44704f69SBart Van Assche sg_put_unaligned_le32(n, cmdp + SG_NVME_PT_CDW13);
2872*44704f69SBart Van Assche res = do_nvme_admin_cmd(psp, shp, cmdp, dip, n, true, time_secs, vb);
2873*44704f69SBart Van Assche if (0 != res) {
2874*44704f69SBart Van Assche if (SG_LIB_NVME_STATUS == res) {
2875*44704f69SBart Van Assche mk_sense_from_nvme_status(psp, vb);
2876*44704f69SBart Van Assche return 0;
2877*44704f69SBart Van Assche } else
2878*44704f69SBart Van Assche return res;
2879*44704f69SBart Van Assche }
2880*44704f69SBart Van Assche psp->resid = din_len - n;
2881*44704f69SBart Van Assche return res;
2882*44704f69SBart Van Assche }
2883*44704f69SBart Van Assche
2884*44704f69SBart Van Assche #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
2885*44704f69SBart Van Assche #define F_SA_HIGH 0x100 /* as used by variable length cdbs */
2886*44704f69SBart Van Assche #define FF_SA (F_SA_HIGH | F_SA_LOW)
2887*44704f69SBart Van Assche #define F_INV_OP 0x200
2888*44704f69SBart Van Assche
2889*44704f69SBart Van Assche static int
sntl_rep_opcodes(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)2890*44704f69SBart Van Assche sntl_rep_opcodes(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
2891*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
2892*44704f69SBart Van Assche {
2893*44704f69SBart Van Assche bool rctd;
2894*44704f69SBart Van Assche uint8_t reporting_opts, req_opcode, supp;
2895*44704f69SBart Van Assche uint16_t req_sa, u;
2896*44704f69SBart Van Assche uint32_t alloc_len, offset, a_len;
2897*44704f69SBart Van Assche const uint32_t pg_sz = sg_get_page_size();
2898*44704f69SBart Van Assche int k, len, count, bump;
2899*44704f69SBart Van Assche const struct sg_opcode_info_t *oip;
2900*44704f69SBart Van Assche uint8_t *arr;
2901*44704f69SBart Van Assche uint8_t *free_arr;
2902*44704f69SBart Van Assche
2903*44704f69SBart Van Assche if (vb > 3)
2904*44704f69SBart Van Assche pr2ws("%s: time_secs=%d\n", __func__, time_secs);
2905*44704f69SBart Van Assche if (shp) { ; } /* suppress warning */
2906*44704f69SBart Van Assche rctd = !!(cdbp[2] & 0x80); /* report command timeout desc. */
2907*44704f69SBart Van Assche reporting_opts = cdbp[2] & 0x7;
2908*44704f69SBart Van Assche req_opcode = cdbp[3];
2909*44704f69SBart Van Assche req_sa = sg_get_unaligned_be16(cdbp + 4);
2910*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be32(cdbp + 6);
2911*44704f69SBart Van Assche if (alloc_len < 4 || alloc_len > 0xffff) {
2912*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 6, -1, vb);
2913*44704f69SBart Van Assche return 0;
2914*44704f69SBart Van Assche }
2915*44704f69SBart Van Assche a_len = pg_sz - 72;
2916*44704f69SBart Van Assche arr = sg_memalign(pg_sz, pg_sz, &free_arr, false);
2917*44704f69SBart Van Assche if (NULL == arr) {
2918*44704f69SBart Van Assche pr2ws("%s: sg_memalign() failed to get memory\n", __func__);
2919*44704f69SBart Van Assche return -ENOMEM;
2920*44704f69SBart Van Assche }
2921*44704f69SBart Van Assche switch (reporting_opts) {
2922*44704f69SBart Van Assche case 0: /* all commands */
2923*44704f69SBart Van Assche count = 0;
2924*44704f69SBart Van Assche bump = rctd ? 20 : 8;
2925*44704f69SBart Van Assche for (offset = 4, oip = sg_get_opcode_translation();
2926*44704f69SBart Van Assche (oip->flags != 0xffff) && (offset < a_len); ++oip) {
2927*44704f69SBart Van Assche if (F_INV_OP & oip->flags)
2928*44704f69SBart Van Assche continue;
2929*44704f69SBart Van Assche ++count;
2930*44704f69SBart Van Assche arr[offset] = oip->opcode;
2931*44704f69SBart Van Assche sg_put_unaligned_be16(oip->sa, arr + offset + 2);
2932*44704f69SBart Van Assche if (rctd)
2933*44704f69SBart Van Assche arr[offset + 5] |= 0x2;
2934*44704f69SBart Van Assche if (FF_SA & oip->flags)
2935*44704f69SBart Van Assche arr[offset + 5] |= 0x1;
2936*44704f69SBart Van Assche sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2937*44704f69SBart Van Assche if (rctd)
2938*44704f69SBart Van Assche sg_put_unaligned_be16(0xa, arr + offset + 8);
2939*44704f69SBart Van Assche offset += bump;
2940*44704f69SBart Van Assche }
2941*44704f69SBart Van Assche sg_put_unaligned_be32(count * bump, arr + 0);
2942*44704f69SBart Van Assche break;
2943*44704f69SBart Van Assche case 1: /* one command: opcode only */
2944*44704f69SBart Van Assche case 2: /* one command: opcode plus service action */
2945*44704f69SBart Van Assche case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2946*44704f69SBart Van Assche for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) {
2947*44704f69SBart Van Assche if ((req_opcode == oip->opcode) && (req_sa == oip->sa))
2948*44704f69SBart Van Assche break;
2949*44704f69SBart Van Assche }
2950*44704f69SBart Van Assche if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) {
2951*44704f69SBart Van Assche supp = 1;
2952*44704f69SBart Van Assche offset = 4;
2953*44704f69SBart Van Assche } else {
2954*44704f69SBart Van Assche if (1 == reporting_opts) {
2955*44704f69SBart Van Assche if (FF_SA & oip->flags) {
2956*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 2, 2, vb);
2957*44704f69SBart Van Assche free(free_arr);
2958*44704f69SBart Van Assche return 0;
2959*44704f69SBart Van Assche }
2960*44704f69SBart Van Assche req_sa = 0;
2961*44704f69SBart Van Assche } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) {
2962*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 4, -1, vb);
2963*44704f69SBart Van Assche free(free_arr);
2964*44704f69SBart Van Assche return 0;
2965*44704f69SBart Van Assche }
2966*44704f69SBart Van Assche if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode))
2967*44704f69SBart Van Assche supp = 3;
2968*44704f69SBart Van Assche else if (0 == (FF_SA & oip->flags))
2969*44704f69SBart Van Assche supp = 1;
2970*44704f69SBart Van Assche else if (req_sa != oip->sa)
2971*44704f69SBart Van Assche supp = 1;
2972*44704f69SBart Van Assche else
2973*44704f69SBart Van Assche supp = 3;
2974*44704f69SBart Van Assche if (3 == supp) {
2975*44704f69SBart Van Assche u = oip->len_mask[0];
2976*44704f69SBart Van Assche sg_put_unaligned_be16(u, arr + 2);
2977*44704f69SBart Van Assche arr[4] = oip->opcode;
2978*44704f69SBart Van Assche for (k = 1; k < u; ++k)
2979*44704f69SBart Van Assche arr[4 + k] = (k < 16) ?
2980*44704f69SBart Van Assche oip->len_mask[k] : 0xff;
2981*44704f69SBart Van Assche offset = 4 + u;
2982*44704f69SBart Van Assche } else
2983*44704f69SBart Van Assche offset = 4;
2984*44704f69SBart Van Assche }
2985*44704f69SBart Van Assche arr[1] = (rctd ? 0x80 : 0) | supp;
2986*44704f69SBart Van Assche if (rctd) {
2987*44704f69SBart Van Assche sg_put_unaligned_be16(0xa, arr + offset);
2988*44704f69SBart Van Assche offset += 12;
2989*44704f69SBart Van Assche }
2990*44704f69SBart Van Assche break;
2991*44704f69SBart Van Assche default:
2992*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 2, 2, vb);
2993*44704f69SBart Van Assche free(free_arr);
2994*44704f69SBart Van Assche return 0;
2995*44704f69SBart Van Assche }
2996*44704f69SBart Van Assche offset = (offset < a_len) ? offset : a_len;
2997*44704f69SBart Van Assche len = (offset < alloc_len) ? offset : alloc_len;
2998*44704f69SBart Van Assche psp->resid = psp->dxfer_len - len;
2999*44704f69SBart Van Assche if (len > 0)
3000*44704f69SBart Van Assche memcpy(psp->dxferp, arr, len);
3001*44704f69SBart Van Assche free(free_arr);
3002*44704f69SBart Van Assche return 0;
3003*44704f69SBart Van Assche }
3004*44704f69SBart Van Assche
3005*44704f69SBart Van Assche static int
sntl_rep_tmfs(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,const uint8_t * cdbp,int time_secs,int vb)3006*44704f69SBart Van Assche sntl_rep_tmfs(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
3007*44704f69SBart Van Assche const uint8_t * cdbp, int time_secs, int vb)
3008*44704f69SBart Van Assche {
3009*44704f69SBart Van Assche bool repd;
3010*44704f69SBart Van Assche uint32_t alloc_len, len;
3011*44704f69SBart Van Assche uint8_t arr[16];
3012*44704f69SBart Van Assche
3013*44704f69SBart Van Assche if (vb > 3)
3014*44704f69SBart Van Assche pr2ws("%s: time_secs=%d\n", __func__, time_secs);
3015*44704f69SBart Van Assche if (shp) { ; } /* suppress warning */
3016*44704f69SBart Van Assche memset(arr, 0, sizeof(arr));
3017*44704f69SBart Van Assche repd = !!(cdbp[2] & 0x80);
3018*44704f69SBart Van Assche alloc_len = sg_get_unaligned_be32(cdbp + 6);
3019*44704f69SBart Van Assche if (alloc_len < 4) {
3020*44704f69SBart Van Assche mk_sense_invalid_fld(psp, true, 6, -1, vb);
3021*44704f69SBart Van Assche return 0;
3022*44704f69SBart Van Assche }
3023*44704f69SBart Van Assche arr[0] = 0xc8; /* ATS | ATSS | LURS */
3024*44704f69SBart Van Assche arr[1] = 0x1; /* ITNRS */
3025*44704f69SBart Van Assche if (repd) {
3026*44704f69SBart Van Assche arr[3] = 0xc;
3027*44704f69SBart Van Assche len = 16;
3028*44704f69SBart Van Assche } else
3029*44704f69SBart Van Assche len = 4;
3030*44704f69SBart Van Assche
3031*44704f69SBart Van Assche len = (len < alloc_len) ? len : alloc_len;
3032*44704f69SBart Van Assche psp->resid = psp->dxfer_len - len;
3033*44704f69SBart Van Assche if (len > 0)
3034*44704f69SBart Van Assche memcpy(psp->dxferp, arr, len);
3035*44704f69SBart Van Assche return 0;
3036*44704f69SBart Van Assche }
3037*44704f69SBart Van Assche
3038*44704f69SBart Van Assche /* Executes NVMe Admin command (or at least forwards it to lower layers).
3039*44704f69SBart Van Assche * Returns 0 for success, negative numbers are negated 'errno' values from
3040*44704f69SBart Van Assche * OS system calls. Positive return values are errors from this package.
3041*44704f69SBart Van Assche * When time_secs is 0 the Linux NVMe Admin command default of 60 seconds
3042*44704f69SBart Van Assche * is used. */
3043*44704f69SBart Van Assche static int
nvme_pt(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int time_secs,int vb)3044*44704f69SBart Van Assche nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
3045*44704f69SBart Van Assche int time_secs, int vb)
3046*44704f69SBart Van Assche {
3047*44704f69SBart Van Assche bool scsi_cdb = false;
3048*44704f69SBart Van Assche uint32_t cmd_len = 0;
3049*44704f69SBart Van Assche uint16_t sa;
3050*44704f69SBart Van Assche const uint8_t * cdbp = NULL;
3051*44704f69SBart Van Assche
3052*44704f69SBart Van Assche if (psp->have_nvme_cmd) {
3053*44704f69SBart Van Assche cdbp = psp->nvme_cmd;
3054*44704f69SBart Van Assche cmd_len = 64;
3055*44704f69SBart Van Assche psp->nvme_direct = true;
3056*44704f69SBart Van Assche } else if (spt_direct) {
3057*44704f69SBart Van Assche if (psp->swb_d.spt.CdbLength > 0) {
3058*44704f69SBart Van Assche cdbp = psp->swb_d.spt.Cdb;
3059*44704f69SBart Van Assche cmd_len = psp->swb_d.spt.CdbLength;
3060*44704f69SBart Van Assche scsi_cdb = true;
3061*44704f69SBart Van Assche psp->nvme_direct = false;
3062*44704f69SBart Van Assche }
3063*44704f69SBart Van Assche } else {
3064*44704f69SBart Van Assche if (psp->swb_i.spt.CdbLength > 0) {
3065*44704f69SBart Van Assche cdbp = psp->swb_i.spt.Cdb;
3066*44704f69SBart Van Assche cmd_len = psp->swb_i.spt.CdbLength;
3067*44704f69SBart Van Assche scsi_cdb = true;
3068*44704f69SBart Van Assche psp->nvme_direct = false;
3069*44704f69SBart Van Assche }
3070*44704f69SBart Van Assche }
3071*44704f69SBart Van Assche if (NULL == cdbp) {
3072*44704f69SBart Van Assche if (vb)
3073*44704f69SBart Van Assche pr2ws("%s: Missing NVMe or SCSI command (set_scsi_pt_cdb())"
3074*44704f69SBart Van Assche " cmd_len=%u\n", __func__, cmd_len);
3075*44704f69SBart Van Assche return SCSI_PT_DO_BAD_PARAMS;
3076*44704f69SBart Van Assche }
3077*44704f69SBart Van Assche if (vb > 3)
3078*44704f69SBart Van Assche pr2ws("%s: opcode=0x%x, cmd_len=%u, fdev_name: %s, dlen=%u\n",
3079*44704f69SBart Van Assche __func__, cdbp[0], cmd_len, shp->dname, psp->dxfer_len);
3080*44704f69SBart Van Assche /* direct NVMe command (i.e. 64 bytes long) or SNTL */
3081*44704f69SBart Van Assche if (scsi_cdb) {
3082*44704f69SBart Van Assche switch (cdbp[0]) {
3083*44704f69SBart Van Assche case SCSI_INQUIRY_OPC:
3084*44704f69SBart Van Assche return sntl_inq(psp, shp, cdbp, time_secs, vb);
3085*44704f69SBart Van Assche case SCSI_REPORT_LUNS_OPC:
3086*44704f69SBart Van Assche return sntl_rluns(psp, shp, cdbp, time_secs, vb);
3087*44704f69SBart Van Assche case SCSI_TEST_UNIT_READY_OPC:
3088*44704f69SBart Van Assche return sntl_tur(psp, shp, time_secs, vb);
3089*44704f69SBart Van Assche case SCSI_REQUEST_SENSE_OPC:
3090*44704f69SBart Van Assche return sntl_req_sense(psp, shp, cdbp, time_secs, vb);
3091*44704f69SBart Van Assche case SCSI_SEND_DIAGNOSTIC_OPC:
3092*44704f69SBart Van Assche return sntl_senddiag(psp, shp, cdbp, time_secs, vb);
3093*44704f69SBart Van Assche case SCSI_RECEIVE_DIAGNOSTIC_OPC:
3094*44704f69SBart Van Assche return sntl_recvdiag(psp, shp, cdbp, time_secs, vb);
3095*44704f69SBart Van Assche case SCSI_MODE_SENSE10_OPC:
3096*44704f69SBart Van Assche case SCSI_MODE_SELECT10_OPC:
3097*44704f69SBart Van Assche return sntl_mode_ss(psp, shp, cdbp, time_secs, vb);
3098*44704f69SBart Van Assche case SCSI_MAINT_IN_OPC:
3099*44704f69SBart Van Assche sa = 0x1f & cdbp[1]; /* service action */
3100*44704f69SBart Van Assche if (SCSI_REP_SUP_OPCS_OPC == sa)
3101*44704f69SBart Van Assche return sntl_rep_opcodes(psp, shp, cdbp, time_secs,
3102*44704f69SBart Van Assche vb);
3103*44704f69SBart Van Assche else if (SCSI_REP_SUP_TMFS_OPC == sa)
3104*44704f69SBart Van Assche return sntl_rep_tmfs(psp, shp, cdbp, time_secs, vb);
3105*44704f69SBart Van Assche /* fall through */
3106*44704f69SBart Van Assche default:
3107*44704f69SBart Van Assche if (vb > 2) {
3108*44704f69SBart Van Assche char b[64];
3109*44704f69SBart Van Assche
3110*44704f69SBart Van Assche sg_get_command_name(cdbp, -1, sizeof(b), b);
3111*44704f69SBart Van Assche pr2ws("%s: no translation to NVMe for SCSI %s command\n",
3112*44704f69SBart Van Assche __func__, b);
3113*44704f69SBart Van Assche }
3114*44704f69SBart Van Assche mk_sense_asc_ascq(psp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE,
3115*44704f69SBart Van Assche 0, vb);
3116*44704f69SBart Van Assche return 0;
3117*44704f69SBart Van Assche }
3118*44704f69SBart Van Assche }
3119*44704f69SBart Van Assche if(psp->dxfer_len > 0) {
3120*44704f69SBart Van Assche uint8_t * cmdp = psp->nvme_cmd;
3121*44704f69SBart Van Assche
3122*44704f69SBart Van Assche sg_put_unaligned_le32(psp->dxfer_len, cmdp + SG_NVME_PT_DATA_LEN);
3123*44704f69SBart Van Assche sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)psp->dxferp,
3124*44704f69SBart Van Assche cmdp + SG_NVME_PT_ADDR);
3125*44704f69SBart Van Assche if (vb > 2)
3126*44704f69SBart Van Assche pr2ws("%s: NVMe command, dlen=%u, dxferp=0x%p\n", __func__,
3127*44704f69SBart Van Assche psp->dxfer_len, psp->dxferp);
3128*44704f69SBart Van Assche }
3129*44704f69SBart Van Assche return do_nvme_admin_cmd(psp, shp, NULL, NULL, 0, true, time_secs, vb);
3130*44704f69SBart Van Assche }
3131*44704f69SBart Van Assche
3132*44704f69SBart Van Assche #else /* (HAVE_NVME && (! IGNORE_NVME)) */
3133*44704f69SBart Van Assche
3134*44704f69SBart Van Assche static int
nvme_pt(struct sg_pt_win32_scsi * psp,struct sg_pt_handle * shp,int time_secs,int vb)3135*44704f69SBart Van Assche nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp,
3136*44704f69SBart Van Assche int time_secs, int vb)
3137*44704f69SBart Van Assche {
3138*44704f69SBart Van Assche if (vb)
3139*44704f69SBart Van Assche pr2ws("%s: not supported [time_secs=%d]\n", __func__, time_secs);
3140*44704f69SBart Van Assche if (psp) { ; } /* suppress warning */
3141*44704f69SBart Van Assche if (shp) { ; } /* suppress warning */
3142*44704f69SBart Van Assche return -ENOTTY; /* inappropriate ioctl error */
3143*44704f69SBart Van Assche }
3144*44704f69SBart Van Assche
3145*44704f69SBart Van Assche #endif /* (HAVE_NVME && (! IGNORE_NVME)) */
3146*44704f69SBart Van Assche
3147*44704f69SBart Van Assche int
do_nvm_pt(struct sg_pt_base * vp,int submq,int timeout_secs,int verbose)3148*44704f69SBart Van Assche do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose)
3149*44704f69SBart Van Assche {
3150*44704f69SBart Van Assche if (vp) { }
3151*44704f69SBart Van Assche if (submq) { }
3152*44704f69SBart Van Assche if (timeout_secs) { }
3153*44704f69SBart Van Assche if (verbose) { }
3154*44704f69SBart Van Assche return SCSI_PT_DO_NOT_SUPPORTED;
3155*44704f69SBart Van Assche }
3156