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