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