smartmontools SVN Rev 5406
Utility to control and monitor storage systems with "S.M.A.R.T."
os_win32.cpp
Go to the documentation of this file.
1/*
2 * os_win32.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2004-21 Christian Franke
7 *
8 * Original AACRaid code:
9 * Copyright (C) 2015 Nidhi Malhotra <nidhi.malhotra@pmcs.com>
10 *
11 * Original Areca code:
12 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
13 *
14 * SPDX-License-Identifier: GPL-2.0-or-later
15 */
16
17#include "config.h"
18#define WINVER 0x0502
19#define _WIN32_WINNT WINVER
20
21#include "atacmds.h"
22#include "scsicmds.h"
23#include "nvmecmds.h"
24#include "utility.h"
25
26#include "dev_interface.h"
27#include "dev_ata_cmd_set.h"
28#include "dev_areca.h"
29
30#include "os_win32/wmiquery.h"
31#include "os_win32/popen.h"
32
33// TODO: Move from smartctl.h to other include file
34extern unsigned char failuretest_permissive;
35
36#include <errno.h>
37
38#ifdef _DEBUG
39#include <assert.h>
40#else
41#undef assert
42#define assert(x) /* */
43#endif
44
45#include <stddef.h> // offsetof()
46
47#include <windows.h>
48#include <ntddscsi.h> // IOCTL_ATA_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH, ...
49
50#ifndef _WIN32
51// csmisas.h and aacraid.h require _WIN32 but w32api-headers no longer define it on Cygwin
52// (aacraid.h also checks for _WIN64 which is also set on Cygwin x64)
53#define _WIN32
54#endif
55
56// CSMI support
57#include "csmisas.h"
58
59// aacraid support
60#include "aacraid.h"
61
62#ifndef _WIN64
63#define SELECT_WIN_32_64(x32, x64) (x32)
64#else
65#define SELECT_WIN_32_64(x32, x64) (x64)
66#endif
67
68// Cygwin does no longer provide strn?icmp() compatibility macros
69// MSVCRT does not provide strn?casecmp()
70#if defined(__CYGWIN__) && !defined(stricmp)
71#define stricmp strcasecmp
72#define strnicmp strncasecmp
73#endif
74
75const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 5393 2022-05-29 05:08:10Z dpgilbert $";
76
77/////////////////////////////////////////////////////////////////////////////
78// Windows I/O-controls, some declarations are missing in the include files
79
80extern "C" {
81
82// SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
83
84STATIC_ASSERT(SMART_GET_VERSION == 0x074080);
85STATIC_ASSERT(SMART_SEND_DRIVE_COMMAND == 0x07c084);
86STATIC_ASSERT(SMART_RCV_DRIVE_DATA == 0x07c088);
87STATIC_ASSERT(sizeof(GETVERSIONINPARAMS) == 24);
88STATIC_ASSERT(sizeof(SENDCMDINPARAMS) == 32+1);
89STATIC_ASSERT(sizeof(SENDCMDOUTPARAMS) == 16+1);
90
91
92// IDE PASS THROUGH (2000, XP, undocumented)
93
94#ifndef IOCTL_IDE_PASS_THROUGH
95
96#define IOCTL_IDE_PASS_THROUGH \
97 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
98
99#endif // IOCTL_IDE_PASS_THROUGH
100
101#pragma pack(1)
102
103typedef struct {
104 IDEREGS IdeReg;
106 UCHAR DataBuffer[1];
108
109#pragma pack()
110
113
114
115// ATA PASS THROUGH (Win2003, XP SP2)
116
117STATIC_ASSERT(IOCTL_ATA_PASS_THROUGH == 0x04d02c);
118STATIC_ASSERT(sizeof(ATA_PASS_THROUGH_EX) == SELECT_WIN_32_64(40, 48));
119
120
121// IOCTL_SCSI_PASS_THROUGH[_DIRECT]
122
123STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH == 0x04d004);
124STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH_DIRECT == 0x04d014);
125STATIC_ASSERT(sizeof(SCSI_PASS_THROUGH) == SELECT_WIN_32_64(44, 56));
126STATIC_ASSERT(sizeof(SCSI_PASS_THROUGH_DIRECT) == SELECT_WIN_32_64(44, 56));
127
128
129// SMART IOCTL via SCSI MINIPORT ioctl
130
131#ifndef FILE_DEVICE_SCSI
132#define FILE_DEVICE_SCSI 0x001b
133#endif
134
135#ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
136
137#define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
138#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
139#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
140#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
141#define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
142#define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
143#define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
144#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
145#define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
146#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
147#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
148#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
149#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
150
151#endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
152
153STATIC_ASSERT(IOCTL_SCSI_MINIPORT == 0x04d008);
155STATIC_ASSERT(sizeof(SRB_IO_CONTROL) == 28);
156
157
158// IOCTL_STORAGE_QUERY_PROPERTY
159
160STATIC_ASSERT(IOCTL_STORAGE_QUERY_PROPERTY == 0x002d1400);
161STATIC_ASSERT(sizeof(STORAGE_DEVICE_DESCRIPTOR) == 36+1+3);
162STATIC_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) == 8+1+3);
163
164
165// IOCTL_STORAGE_QUERY_PROPERTY: Windows 10 enhancements
166
167namespace win10 {
168
169 // enum STORAGE_PROPERTY_ID: new values
170 const STORAGE_PROPERTY_ID StorageAdapterProtocolSpecificProperty = (STORAGE_PROPERTY_ID)49;
171 const STORAGE_PROPERTY_ID StorageDeviceProtocolSpecificProperty = (STORAGE_PROPERTY_ID)50;
172
180
187
190 ULONG DataType;
196 ULONG Reserved[3];
198
200
201} // namespace win10
202
203
204// IOCTL_STORAGE_PREDICT_FAILURE
205
206STATIC_ASSERT(IOCTL_STORAGE_PREDICT_FAILURE == 0x002d1100);
207STATIC_ASSERT(sizeof(STORAGE_PREDICT_FAILURE) == 4+512);
208
209
210// 3ware specific versions of SMART ioctl structs
211
212#define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
213
214#pragma pack(1)
215
222 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
223 WORD wIdentifier; // Vendor specific identifier
224 WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
225 ULONG dwReserved[2];
227
228typedef struct _SENDCMDINPARAMS_EX {
230 IDEREGS irDriveRegs;
232 BYTE bPortNumber; // 3ware specific: port number
233 WORD wIdentifier; // Vendor specific identifier
234 DWORD dwReserved[4];
235 BYTE bBuffer[1];
237
238#pragma pack()
239
240STATIC_ASSERT(sizeof(GETVERSIONINPARAMS_EX) == sizeof(GETVERSIONINPARAMS));
241STATIC_ASSERT(sizeof(SENDCMDINPARAMS_EX) == sizeof(SENDCMDINPARAMS));
242
243
244// NVME_PASS_THROUGH
245
246#ifndef NVME_PASS_THROUGH_SRB_IO_CODE
247
248#define NVME_SIG_STR "NvmeMini"
249#define NVME_STORPORT_DRIVER 0xe000
250
251#define NVME_PASS_THROUGH_SRB_IO_CODE \
252 CTL_CODE(NVME_STORPORT_DRIVER, 0x0800, METHOD_BUFFERED, FILE_ANY_ACCESS)
253
254#pragma pack(1)
256{
257 SRB_IO_CONTROL SrbIoCtrl;
259 ULONG NVMeCmd[16]; // Command DW[0...15]
260 ULONG CplEntry[4]; // Completion DW[0...3]
261 ULONG Direction; // 0=No, 1=Out, 2=In, 3=I/O
262 ULONG QueueId; // 0=AdminQ
263 ULONG DataBufferLen; // sizeof(DataBuffer) if Data In
265 ULONG ReturnBufferLen; // offsetof(DataBuffer), plus sizeof(DataBuffer) if Data Out
266 UCHAR DataBuffer[1];
268#pragma pack()
269
270#endif // NVME_PASS_THROUGH_SRB_IO_CODE
271
274STATIC_ASSERT(sizeof(NVME_PASS_THROUGH_IOCTL) == offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer)+1);
275
276
277// CSMI structs
278
279STATIC_ASSERT(sizeof(IOCTL_HEADER) == sizeof(SRB_IO_CONTROL));
283
284// aacraid struct
285
286STATIC_ASSERT(sizeof(SCSI_REQUEST_BLOCK) == SELECT_WIN_32_64(64, 88));
287
288} // extern "C"
289
290/////////////////////////////////////////////////////////////////////////////
291
292namespace os_win32 { // no need to publish anything, name provided for Doxygen
293
294#ifdef _MSC_VER
295#pragma warning(disable:4250)
296#endif
297
298static int is_permissive()
299{
301 pout("To continue, add one or more '-T permissive' options.\n");
302 return 0;
303 }
305 return 1;
306}
307
308// return number for drive letter, -1 on error
309// "[A-Za-z]:([/\\][.]?)?" => 0-25
310// Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
311static int drive_letter(const char * s)
312{
313 return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z'))
314 && s[1] == ':'
315 && (!s[2] || ( strchr("/\\\"", s[2])
316 && (!s[3] || (s[3] == '.' && !s[4]))) ) ?
317 (s[0] & 0x1f) - 1 : -1);
318}
319
320// Skip trailing "/dev/", do not allow "/dev/X:"
321static const char * skipdev(const char * s)
322{
323 return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);
324}
325
326// "sd[a-z]" -> 0-25, "sd[a-z][a-z]" -> 26-701
327static int sdxy_to_phydrive(const char (& xy)[2+1])
328{
329 int phydrive = xy[0] - 'a';
330 if (xy[1])
331 phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a');
332 return phydrive;
333}
334
335static void copy_swapped(unsigned char * dest, const char * src, int destsize)
336{
337 int srclen = strcspn(src, "\r\n");
338 int i;
339 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
340 dest[i] = src[i+1]; dest[i+1] = src[i];
341 }
342 if (i < destsize-1 && i < srclen)
343 dest[i+1] = src[i];
344}
345
346
347/////////////////////////////////////////////////////////////////////////////
348// win_smart_device
349
351: virtual public /*implements*/ smart_device
352{
353public:
356 m_fh(INVALID_HANDLE_VALUE)
357 { }
358
359 virtual ~win_smart_device();
360
361 virtual bool is_open() const;
362
363 virtual bool close();
364
365protected:
366 /// Set handle for open() in derived classes.
367 void set_fh(HANDLE fh)
368 { m_fh = fh; }
369
370 /// Return handle for derived classes.
371 HANDLE get_fh() const
372 { return m_fh; }
373
374private:
375 HANDLE m_fh; ///< File handle
376};
377
378
379// Common routines for devices with HANDLEs
380
382{
383 if (m_fh != INVALID_HANDLE_VALUE)
384 ::CloseHandle(m_fh);
385}
386
388{
389 return (m_fh != INVALID_HANDLE_VALUE);
390}
391
393{
394 if (m_fh == INVALID_HANDLE_VALUE)
395 return true;
396 BOOL rc = ::CloseHandle(m_fh);
397 m_fh = INVALID_HANDLE_VALUE;
398 return !!rc;
399}
400
401
402/////////////////////////////////////////////////////////////////////////////
403
404#define SMART_CYL_LOW 0x4F
405#define SMART_CYL_HI 0xC2
406
407static void print_ide_regs(const IDEREGS * r, int out)
408{
409 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
410 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
411 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
412}
413
414static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
415{
416 pout(" Input : "); print_ide_regs(ri, 0);
417 if (ro) {
418 pout(" Output: "); print_ide_regs(ro, 1);
419 }
420}
421
422/////////////////////////////////////////////////////////////////////////////
423
424// call SMART_GET_VERSION, return device map or -1 on error
425
426static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
427{
428 GETVERSIONINPARAMS vers; memset(&vers, 0, sizeof(vers));
429 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
430 DWORD num_out;
431
432 if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
433 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
434 if (ata_debugmode)
435 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
436 errno = ENOSYS;
437 return -1;
438 }
439 assert(num_out == sizeof(GETVERSIONINPARAMS));
440
441 if (ata_debugmode > 1) {
442 pout(" SMART_GET_VERSION succeeded, bytes returned: %u\n"
443 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
444 (unsigned)num_out, vers.bVersion, vers.bRevision,
445 (unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
446 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
447 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
448 vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx);
449 }
450
451 if (ata_version_ex)
452 *ata_version_ex = vers_ex;
453
454 // TODO: Check vers.fCapabilities here?
455 return vers.bIDEDeviceMap;
456}
457
458
459// call SMART_* ioctl
460
461static int smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize, int port)
462{
463 SENDCMDINPARAMS inpar;
464 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
465
466 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
467 const SENDCMDOUTPARAMS * outpar;
468 DWORD code, num_out;
469 unsigned int size_out;
470 const char * name;
471
472 memset(&inpar, 0, sizeof(inpar));
473 inpar.irDriveRegs = *regs;
474
475 // Older drivers may require bits 5 and 7 set
476 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
477 inpar.irDriveRegs.bDriveHeadReg |= 0xa0;
478
479 // Drive number 0-3 was required on Win9x/ME only
480 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
481 //inpar.bDriveNumber = drive;
482
483 if (port >= 0) {
484 // Set RAID port
486 inpar_ex.bPortNumber = port;
487 }
488
489 if (datasize == 512) {
490 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
491 inpar.cBufferSize = size_out = 512;
492 }
493 else if (datasize == 0) {
494 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
495 if (regs->bFeaturesReg == ATA_SMART_STATUS)
496 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
497 // Note: cBufferSize must be 0 on Win9x
498 else
499 size_out = 0;
500 }
501 else {
502 errno = EINVAL;
503 return -1;
504 }
505
506 memset(&outbuf, 0, sizeof(outbuf));
507
508 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
509 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
510 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
511 long err = GetLastError();
512 if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
513 pout(" %s failed, Error=%ld\n", name, err);
514 print_ide_regs_io(regs, NULL);
515 }
516 errno = ( err == ERROR_INVALID_FUNCTION/*9x*/
517 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
518 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
519 return -1;
520 }
521 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
522
523 outpar = (const SENDCMDOUTPARAMS *)outbuf;
524
525 if (outpar->DriverStatus.bDriverError) {
526 if (ata_debugmode) {
527 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
528 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
529 print_ide_regs_io(regs, NULL);
530 }
531 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
532 return -1;
533 }
534
535 if (ata_debugmode > 1) {
536 pout(" %s succeeded, bytes returned: %u (buffer %u)\n", name,
537 (unsigned)num_out, (unsigned)outpar->cBufferSize);
538 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
539 (const IDEREGS *)(outpar->bBuffer) : NULL));
540 }
541
542 if (datasize)
543 memcpy(data, outpar->bBuffer, 512);
544 else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
545 if (nonempty(outpar->bBuffer, sizeof(IDEREGS)))
546 memcpy(regs, outpar->bBuffer, sizeof(IDEREGS));
547 else { // Workaround for driver not returning regs
548 if (ata_debugmode)
549 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
550 *regs = inpar.irDriveRegs;
551 }
552 }
553
554 return 0;
555}
556
557
558/////////////////////////////////////////////////////////////////////////////
559// IDE PASS THROUGH (2000, XP, undocumented)
560//
561// Based on WinATA.cpp, 2002 c't/Matthias Withopf
562// ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
563
564static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
565{
566 if (datasize > 512) {
567 errno = EINVAL;
568 return -1;
569 }
570 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
571 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
572 DWORD num_out;
573 const unsigned char magic = 0xcf;
574
575 if (!buf) {
576 errno = ENOMEM;
577 return -1;
578 }
579
580 buf->IdeReg = *regs;
581 buf->DataBufferSize = datasize;
582 if (datasize)
583 buf->DataBuffer[0] = magic;
584
585 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
586 buf, size, buf, size, &num_out, NULL)) {
587 long err = GetLastError();
588 if (ata_debugmode) {
589 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
590 print_ide_regs_io(regs, NULL);
591 }
592 VirtualFree(buf, 0, MEM_RELEASE);
593 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
594 return -1;
595 }
596
597 // Check ATA status
598 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
599 if (ata_debugmode) {
600 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
601 print_ide_regs_io(regs, &buf->IdeReg);
602 }
603 VirtualFree(buf, 0, MEM_RELEASE);
604 errno = EIO;
605 return -1;
606 }
607
608 // Check and copy data
609 if (datasize) {
610 if ( num_out != size
611 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
612 if (ata_debugmode) {
613 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
614 (unsigned)num_out, (unsigned)buf->DataBufferSize);
615 print_ide_regs_io(regs, &buf->IdeReg);
616 }
617 VirtualFree(buf, 0, MEM_RELEASE);
618 errno = EIO;
619 return -1;
620 }
621 memcpy(data, buf->DataBuffer, datasize);
622 }
623
624 if (ata_debugmode > 1) {
625 pout(" IOCTL_IDE_PASS_THROUGH succeeded, bytes returned: %u (buffer %u)\n",
626 (unsigned)num_out, (unsigned)buf->DataBufferSize);
627 print_ide_regs_io(regs, &buf->IdeReg);
628 }
629 *regs = buf->IdeReg;
630
631 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
632 VirtualFree(buf, 0, MEM_RELEASE);
633 return 0;
634}
635
636
637/////////////////////////////////////////////////////////////////////////////
638// ATA PASS THROUGH (Win2003, XP SP2)
639
640// Warning:
641// IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
642// transfer per command. Therefore, multi-sector transfers are only supported
643// for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
644// or READ/WRITE LOG EXT work only with single sector transfers.
645// The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
646// See:
647// http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
648
649static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize)
650{
651 const int max_sectors = 32; // TODO: Allocate dynamic buffer
652
653 typedef struct {
654 ATA_PASS_THROUGH_EX apt;
655 ULONG Filler;
656 UCHAR ucDataBuf[max_sectors * 512];
657 } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
658
659 const unsigned char magic = 0xcf;
660
661 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
662 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
663 //ab.apt.PathId = 0;
664 //ab.apt.TargetId = 0;
665 //ab.apt.Lun = 0;
666 ab.apt.TimeOutValue = 60; // seconds
667 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
668 ab.apt.DataBufferOffset = size;
669
670 if (datasize > 0) {
671 if (datasize > (int)sizeof(ab.ucDataBuf)) {
672 errno = EINVAL;
673 return -1;
674 }
675 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
676 ab.apt.DataTransferLength = datasize;
677 size += datasize;
678 ab.ucDataBuf[0] = magic;
679 }
680 else if (datasize < 0) {
681 if (-datasize > (int)sizeof(ab.ucDataBuf)) {
682 errno = EINVAL;
683 return -1;
684 }
685 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
686 ab.apt.DataTransferLength = -datasize;
687 size += -datasize;
688 memcpy(ab.ucDataBuf, data, -datasize);
689 }
690 else {
691 assert(ab.apt.AtaFlags == 0);
692 assert(ab.apt.DataTransferLength == 0);
693 }
694
695 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
696 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
697 IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile;
698 *ctfregs = *regs;
699
700 if (prev_regs) {
701 *ptfregs = *prev_regs;
702 ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
703 }
704
705 DWORD num_out;
706 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
707 &ab, size, &ab, size, &num_out, NULL)) {
708 long err = GetLastError();
709 if (ata_debugmode) {
710 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
711 print_ide_regs_io(regs, NULL);
712 }
713 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
714 return -1;
715 }
716
717 // Check ATA status
718 if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
719 if (ata_debugmode) {
720 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
721 print_ide_regs_io(regs, ctfregs);
722 }
723 errno = EIO;
724 return -1;
725 }
726
727 // Check and copy data
728 if (datasize > 0) {
729 if ( num_out != size
730 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
731 if (ata_debugmode) {
732 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out);
733 print_ide_regs_io(regs, ctfregs);
734 }
735 errno = EIO;
736 return -1;
737 }
738 memcpy(data, ab.ucDataBuf, datasize);
739 }
740
741 if (ata_debugmode > 1) {
742 pout(" IOCTL_ATA_PASS_THROUGH succeeded, bytes returned: %u\n", (unsigned)num_out);
743 print_ide_regs_io(regs, ctfregs);
744 }
745 *regs = *ctfregs;
746 if (prev_regs)
747 *prev_regs = *ptfregs;
748
749 return 0;
750}
751
752
753/////////////////////////////////////////////////////////////////////////////
754// SMART IOCTL via SCSI MINIPORT ioctl
755
756// This function is handled by ATAPI port driver (atapi.sys) or by SCSI
757// miniport driver (via SCSI port driver scsiport.sys).
758// It can be used to skip the missing or broken handling of some SMART
759// command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
760
761static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
762{
763 // Select code
764 DWORD code = 0; const char * name = 0;
765 if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
766 code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
767 }
768 else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
770 code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
772 code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
773 case ATA_SMART_ENABLE:
774 code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
776 code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
777 case ATA_SMART_STATUS:
778 code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
780 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
781 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
782 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
784 code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
786 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
788 code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
790 code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
791 }
792 if (!code) {
793 errno = ENOSYS;
794 return -1;
795 }
796
797 // Set SRB
798 struct {
799 SRB_IO_CONTROL srbc;
800 union {
801 SENDCMDINPARAMS in;
802 SENDCMDOUTPARAMS out;
803 } params;
804 char space[512-1];
805 } sb;
806 STATIC_ASSERT(sizeof(sb) == sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
807 memset(&sb, 0, sizeof(sb));
808
809 unsigned size;
810 if (datasize > 0) {
811 if (datasize > (int)sizeof(sb.space)+1) {
812 errno = EINVAL;
813 return -1;
814 }
815 size = datasize;
816 }
817 else if (datasize < 0) {
818 if (-datasize > (int)sizeof(sb.space)+1) {
819 errno = EINVAL;
820 return -1;
821 }
822 size = -datasize;
823 memcpy(sb.params.in.bBuffer, data, size);
824 }
825 else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
826 size = sizeof(IDEREGS);
827 else
828 size = 0;
829 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
830 memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
831 sb.srbc.Timeout = 60; // seconds
832 sb.srbc.ControlCode = code;
833 //sb.srbc.ReturnCode = 0;
834 sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
835 sb.params.in.irDriveRegs = *regs;
836 sb.params.in.cBufferSize = size;
837
838 // Call miniport ioctl
839 size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
840 DWORD num_out;
841 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
842 &sb, size, &sb, size, &num_out, NULL)) {
843 long err = GetLastError();
844 if (ata_debugmode) {
845 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
846 print_ide_regs_io(regs, NULL);
847 }
848 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
849 return -1;
850 }
851
852 // Check result
853 if (sb.srbc.ReturnCode) {
854 if (ata_debugmode) {
855 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (unsigned)sb.srbc.ReturnCode);
856 print_ide_regs_io(regs, NULL);
857 }
858 errno = EIO;
859 return -1;
860 }
861
862 if (sb.params.out.DriverStatus.bDriverError) {
863 if (ata_debugmode) {
864 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
865 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
866 print_ide_regs_io(regs, NULL);
867 }
868 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
869 return -1;
870 }
871
872 if (ata_debugmode > 1) {
873 pout(" IOCTL_SCSI_MINIPORT_%s succeeded, bytes returned: %u (buffer %u)\n", name,
874 (unsigned)num_out, (unsigned)sb.params.out.cBufferSize);
876 (const IDEREGS *)(sb.params.out.bBuffer) : 0));
877 }
878
879 if (datasize > 0)
880 memcpy(data, sb.params.out.bBuffer, datasize);
881 else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
882 memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS));
883
884 return 0;
885}
886
887
888/////////////////////////////////////////////////////////////////////////////
889// ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
890
891static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
892{
893 struct {
894 SRB_IO_CONTROL srbc;
895 IDEREGS regs;
896 UCHAR buffer[512];
897 } sb;
898 STATIC_ASSERT(sizeof(sb) == sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
899
900 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
901 errno = EINVAL;
902 return -1;
903 }
904 memset(&sb, 0, sizeof(sb));
905 strncpy((char *)sb.srbc.Signature, "<3ware>", sizeof(sb.srbc.Signature));
906 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
907 sb.srbc.Timeout = 60; // seconds
908 sb.srbc.ControlCode = 0xA0000000;
909 sb.srbc.ReturnCode = 0;
910 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
911 sb.regs = *regs;
912 sb.regs.bReserved = port;
913
914 DWORD num_out;
915 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
916 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
917 long err = GetLastError();
918 if (ata_debugmode) {
919 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
920 print_ide_regs_io(regs, NULL);
921 }
922 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
923 return -1;
924 }
925
926 if (sb.srbc.ReturnCode) {
927 if (ata_debugmode) {
928 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb.srbc.ReturnCode);
929 print_ide_regs_io(regs, NULL);
930 }
931 errno = EIO;
932 return -1;
933 }
934
935 // Copy data
936 if (datasize > 0)
937 memcpy(data, sb.buffer, datasize);
938
939 if (ata_debugmode > 1) {
940 pout(" ATA via IOCTL_SCSI_MINIPORT succeeded, bytes returned: %u\n", (unsigned)num_out);
941 print_ide_regs_io(regs, &sb.regs);
942 }
943 *regs = sb.regs;
944
945 return 0;
946}
947
948
949/////////////////////////////////////////////////////////////////////////////
950
951// 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
952// 3DM/CLI "Rescan Controller" function does not to always update it.
953
954static int update_3ware_devicemap_ioctl(HANDLE hdevice)
955{
956 SRB_IO_CONTROL srbc;
957 memset(&srbc, 0, sizeof(srbc));
958 strncpy((char *)srbc.Signature, "<3ware>", sizeof(srbc.Signature));
959 srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
960 srbc.Timeout = 60; // seconds
961 srbc.ControlCode = 0xCC010014;
962 srbc.ReturnCode = 0;
963 srbc.Length = 0;
964
965 DWORD num_out;
966 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
967 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
968 long err = GetLastError();
969 if (ata_debugmode)
970 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
971 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
972 return -1;
973 }
974 if (srbc.ReturnCode) {
975 if (ata_debugmode)
976 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc.ReturnCode);
977 errno = EIO;
978 return -1;
979 }
980 if (ata_debugmode > 1)
981 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT succeeded\n");
982 return 0;
983}
984
985
986/////////////////////////////////////////////////////////////////////////////
987// IOCTL_STORAGE_QUERY_PROPERTY
988
990 STORAGE_DEVICE_DESCRIPTOR desc;
991 char raw[256];
992};
993
994// Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
995// (This works without admin rights)
996
998{
999 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} };
1000 memset(data, 0, sizeof(*data));
1001
1002 DWORD num_out;
1003 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1004 &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
1005 if (ata_debugmode > 1 || scsi_debugmode > 1)
1006 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
1007 errno = ENOSYS;
1008 return -1;
1009 }
1010
1011 if (ata_debugmode > 1 || scsi_debugmode > 1) {
1012 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1013 " Vendor: \"%s\"\n"
1014 " Product: \"%s\"\n"
1015 " Revision: \"%s\"\n"
1016 " Removable: %s\n"
1017 " BusType: 0x%02x\n",
1018 (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : "(null)"),
1019 (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : "(null)"),
1020 (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : "(null)"),
1021 (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType
1022 );
1023 }
1024 return 0;
1025}
1026
1027
1028/////////////////////////////////////////////////////////////////////////////
1029// IOCTL_STORAGE_PREDICT_FAILURE
1030
1031// Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1032// or -1 on error, optionally return VendorSpecific data.
1033// (This works without admin rights)
1034
1035static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
1036{
1037 STORAGE_PREDICT_FAILURE pred;
1038 memset(&pred, 0, sizeof(pred));
1039
1040 DWORD num_out;
1041 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
1042 0, 0, &pred, sizeof(pred), &num_out, NULL)) {
1043 if (ata_debugmode > 1)
1044 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
1045 errno = ENOSYS;
1046 return -1;
1047 }
1048
1049 if (ata_debugmode > 1) {
1050 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
1051 " PredictFailure: 0x%08x\n"
1052 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
1053 (unsigned)pred.PredictFailure,
1054 pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
1055 pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
1056 );
1057 }
1058 if (data)
1059 memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
1060 return (!pred.PredictFailure ? 0 : 1);
1061}
1062
1063
1064// Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
1066{
1068 if (storage_query_property_ioctl(hdevice, &data))
1069 return -1;
1070
1071 memset(id, 0, sizeof(*id));
1072
1073 // Some drivers split ATA model string into VendorId and ProductId,
1074 // others return it as ProductId only.
1075 char model[sizeof(id->model) + 1] = "";
1076
1077 unsigned i = 0;
1078 if (data.desc.VendorIdOffset) {
1079 for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++)
1080 model[i] = data.raw[data.desc.VendorIdOffset+i];
1081 }
1082
1083 if (data.desc.ProductIdOffset) {
1084 // Keep only first trailing blank after VendorId
1085 while (i > 0 && model[i-1] == ' ' && (i < 2 || model[i-2] == ' '))
1086 i--;
1087 // Ignore VendorId "ATA"
1088 if (i <= 4 && !memcmp(model, "ATA", 3) && (i == 3 || model[3] == ' '))
1089 i = 0;
1090 for (unsigned j = 0; i < sizeof(model)-1 && data.raw[data.desc.ProductIdOffset+j]; i++, j++)
1091 model[i] = data.raw[data.desc.ProductIdOffset+j];
1092 }
1093
1094 while (i > 0 && model[i-1] == ' ')
1095 i--;
1096 model[i] = 0;
1097 copy_swapped(id->model, model, sizeof(id->model));
1098
1099 if (data.desc.ProductRevisionOffset)
1100 copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev));
1101
1102 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1103 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1104 return 0;
1105}
1106
1107// Get Serial Number in IDENTIFY from WMI
1108static bool get_serial_from_wmi(int drive, ata_identify_device * id)
1109{
1110 bool debug = (ata_debugmode > 1);
1111
1112 wbem_services ws;
1113 if (!ws.connect()) {
1114 if (debug)
1115 pout("WMI connect failed\n");
1116 return false;
1117 }
1118
1119 wbem_object wo;
1120 if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
1121 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
1122 return false;
1123
1124 std::string serial = wo.get_str("SerialNumber");
1125 if (debug)
1126 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str("Model").c_str(), serial.c_str());
1127
1128 copy_swapped(id->serial_no, serial.c_str(), sizeof(id->serial_no));
1129 return true;
1130}
1131
1132
1133/////////////////////////////////////////////////////////////////////////////
1134// USB ID detection using WMI
1135
1136// Get USB ID for a physical or logical drive number
1137static bool get_usb_id(int phydrive, int logdrive,
1138 unsigned short & vendor_id,
1139 unsigned short & product_id)
1140{
1141 bool debug = (scsi_debugmode > 1);
1142
1143 wbem_services ws;
1144 if (!ws.connect()) {
1145 if (debug)
1146 pout("WMI connect failed\n");
1147 return false;
1148 }
1149
1150 // Get device name
1151 std::string name;
1152
1153 wbem_object wo;
1154 if (0 <= logdrive && logdrive <= 'Z'-'A') {
1155 // Drive letter -> Partition info
1156 if (!ws.query1(wo, "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"%c:\"} WHERE ResultClass = Win32_DiskPartition",
1157 'A'+logdrive))
1158 return false;
1159
1160 std::string partid = wo.get_str("DeviceID");
1161 if (debug)
1162 pout("%c: --> \"%s\" -->\n", 'A'+logdrive, partid.c_str());
1163
1164 // Partition ID -> Physical drive info
1165 if (!ws.query1(wo, "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE ResultClass = Win32_DiskDrive",
1166 partid.c_str()))
1167 return false;
1168
1169 name = wo.get_str("Model");
1170 if (debug)
1171 pout("%s --> \"%s\":\n", wo.get_str("DeviceID").c_str(), name.c_str());
1172 }
1173
1174 else if (phydrive >= 0) {
1175 // Physical drive number -> Physical drive info
1176 if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", phydrive))
1177 return false;
1178
1179 name = wo.get_str("Model");
1180 if (debug)
1181 pout("\\.\\\\PHYSICALDRIVE%d --> \"%s\":\n", phydrive, name.c_str());
1182 }
1183 else
1184 return false;
1185
1186
1187 // Get USB_CONTROLLER -> DEVICE associations
1188 wbem_enumerator we;
1189 if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
1190 return false;
1191
1192 unsigned short usb_venid = 0, prev_usb_venid = 0;
1193 unsigned short usb_proid = 0, prev_usb_proid = 0;
1194 std::string prev_usb_ant;
1195 std::string prev_ant, ant, dep;
1196
1197 const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"");
1198
1199 while (we.next(wo)) {
1200 prev_ant = ant;
1201 // Find next 'USB_CONTROLLER, DEVICE' pair
1202 ant = wo.get_str("Antecedent");
1203 dep = wo.get_str("Dependent");
1204
1205 if (debug && ant != prev_ant)
1206 pout(" %s:\n", ant.c_str());
1207
1208 // Extract DeviceID
1210 if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) {
1211 if (debug)
1212 pout(" | (\"%s\")\n", dep.c_str());
1213 continue;
1214 }
1215
1216 std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so);
1217
1218 if (str_starts_with(devid, "USB\\\\VID_")) {
1219 // USB bridge entry, save CONTROLLER, ID
1220 int nc = -1;
1221 if (!(sscanf(devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
1222 &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) {
1223 prev_usb_venid = prev_usb_proid = 0;
1224 }
1225 prev_usb_ant = ant;
1226 if (debug)
1227 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
1228 }
1229 else if (str_starts_with(devid, "USBSTOR\\\\") || str_starts_with(devid, "SCSI\\\\")) {
1230 // USBSTORage or SCSI device found
1231 if (debug)
1232 pout(" +--> \"%s\"\n", devid.c_str());
1233
1234 // Retrieve name
1235 wbem_object wo2;
1236 if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str()))
1237 continue;
1238 std::string name2 = wo2.get_str("Name");
1239
1240 // Continue if not name of physical disk drive
1241 if (name2 != name) {
1242 if (debug)
1243 pout(" +---> (\"%s\")\n", name2.c_str());
1244 continue;
1245 }
1246
1247 // Fail if previous USB bridge is associated to other controller or ID is unknown
1248 if (!(ant == prev_usb_ant && prev_usb_venid)) {
1249 if (debug)
1250 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
1251 return false;
1252 }
1253
1254 // Handle multiple devices with same name
1255 if (usb_venid) {
1256 // Fail if multiple devices with same name have different USB bridge types
1257 if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) {
1258 if (debug)
1259 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str());
1260 return false;
1261 }
1262 }
1263
1264 // Found
1265 usb_venid = prev_usb_venid;
1266 usb_proid = prev_usb_proid;
1267 if (debug)
1268 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid);
1269
1270 // Continue to check for duplicate names ...
1271 }
1272 else {
1273 if (debug)
1274 pout(" | \"%s\"\n", devid.c_str());
1275 }
1276 }
1277
1278 if (!usb_venid)
1279 return false;
1280
1281 vendor_id = usb_venid;
1282 product_id = usb_proid;
1283
1284 return true;
1285}
1286
1287
1288/////////////////////////////////////////////////////////////////////////////
1289
1290// Call GetDevicePowerState()
1291// returns: 1=active, 0=standby, -1=error
1292// (This would also work for SCSI drives)
1293
1294static int get_device_power_state(HANDLE hdevice)
1295{
1296 BOOL state = TRUE;
1297 if (!GetDevicePowerState(hdevice, &state)) {
1298 long err = GetLastError();
1299 if (ata_debugmode)
1300 pout(" GetDevicePowerState() failed, Error=%ld\n", err);
1301 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1302 // TODO: This may not work as expected on transient errors,
1303 // because smartd interprets -1 as SLEEP mode regardless of errno.
1304 return -1;
1305 }
1306
1307 if (ata_debugmode > 1)
1308 pout(" GetDevicePowerState() succeeded, state=%d\n", state);
1309 return state;
1310}
1311
1312
1313/////////////////////////////////////////////////////////////////////////////
1314// win_ata_device
1315
1317: public /*implements*/ ata_device,
1318 public /*extends*/ win_smart_device
1319{
1320public:
1321 win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
1322
1323 virtual ~win_ata_device();
1324
1325 virtual bool open() override;
1326
1327 virtual bool is_powered_down() override;
1328
1329 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) override;
1330
1331 virtual bool ata_identify_is_cached() const override;
1332
1333private:
1334 bool open(bool query_device);
1335
1336 bool open(int phydrive, int logdrive, const char * options, int port, bool query_device);
1337
1338 std::string m_options;
1339 bool m_usr_options; // options set by user?
1340 bool m_admin; // open with admin access?
1341 int m_phydrive; // PhysicalDriveN or -1
1342 bool m_id_is_cached; // ata_identify_is_cached() return value.
1343 bool m_is_3ware; // LSI/3ware controller detected?
1344 int m_port; // LSI/3ware port
1346};
1347
1348
1349win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
1350: smart_device(intf, dev_name, "ata", req_type),
1351 m_usr_options(false),
1352 m_admin(false),
1353 m_phydrive(-1),
1354 m_id_is_cached(false),
1355 m_is_3ware(false),
1356 m_port(-1),
1357 m_smartver_state(0)
1358{
1359}
1360
1362{
1363}
1364
1365// Get default ATA device options
1366
1367static const char * ata_get_def_options()
1368{
1369 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
1370 // STORAGE_*, SCSI_MINIPORT_*
1371}
1372
1373// Open ATA device
1374
1376{
1377 // Open device for r/w operations
1378 return open(false);
1379}
1380
1381bool win_ata_device::open(bool query_device)
1382{
1383 const char * name = skipdev(get_dev_name()); int len = strlen(name);
1384 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
1385 char drive[2+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
1386 if ( sscanf(name, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1
1387 && ((n1 == len && !options[0]) || n2 == len) ) {
1388 return open(sdxy_to_phydrive(drive), -1, options, -1, query_device);
1389 }
1390 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
1391 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
1392 unsigned port = ~0;
1393 if ( sscanf(name, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2
1394 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
1395 return open(sdxy_to_phydrive(drive), -1, options, port, query_device);
1396 }
1397 // pd<m>,N => Physical drive <m>, RAID port N
1398 int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
1399 if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
1400 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
1401 return open(phydrive, -1, "", (int)port, query_device);
1402 }
1403 // [a-zA-Z]: => Physical drive behind logical drive 0-25
1404 int logdrive = drive_letter(name);
1405 if (logdrive >= 0) {
1406 return open(-1, logdrive, "", -1, query_device);
1407 }
1408
1409 return set_err(EINVAL);
1410}
1411
1412
1413bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port, bool query_device)
1414{
1415 m_phydrive = -1;
1416 char devpath[30];
1417 if (0 <= phydrive && phydrive <= 255)
1418 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive));
1419 else if (0 <= logdrive && logdrive <= 'Z'-'A')
1420 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
1421 else
1422 return set_err(ENOENT);
1423
1424 // Open device
1425 HANDLE h = INVALID_HANDLE_VALUE;
1426 if (!(*options && !options[strspn(options, "fp")]) && !query_device) {
1427 // Open with admin rights
1428 m_admin = true;
1429 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
1430 FILE_SHARE_READ|FILE_SHARE_WRITE,
1431 NULL, OPEN_EXISTING, 0, 0);
1432 }
1433 if (h == INVALID_HANDLE_VALUE) {
1434 // Open without admin rights
1435 m_admin = false;
1436 h = CreateFileA(devpath, 0,
1437 FILE_SHARE_READ|FILE_SHARE_WRITE,
1438 NULL, OPEN_EXISTING, 0, 0);
1439 }
1440 if (h == INVALID_HANDLE_VALUE) {
1441 long err = GetLastError();
1442 if (err == ERROR_FILE_NOT_FOUND)
1443 set_err(ENOENT, "%s: not found", devpath);
1444 else if (err == ERROR_ACCESS_DENIED)
1445 set_err(EACCES, "%s: access denied", devpath);
1446 else
1447 set_err(EIO, "%s: Error=%ld", devpath, err);
1448 return false;
1449 }
1450 set_fh(h);
1451
1452 // Warn once if admin rights are missing
1453 if (!m_admin && !query_device) {
1454 static bool noadmin_warning = false;
1455 if (!noadmin_warning) {
1456 pout("Warning: Limited functionality due to missing admin rights\n");
1457 noadmin_warning = true;
1458 }
1459 }
1460
1461 if (ata_debugmode > 1)
1462 pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
1463
1464 m_usr_options = false;
1465 if (*options) {
1466 // Save user options
1467 m_options = options; m_usr_options = true;
1468 }
1469 else if (port >= 0)
1470 // RAID: SMART_* and SCSI_MINIPORT
1471 m_options = "s3";
1472 else {
1473 // Set default options according to Windows version
1474 static const char * def_options = ata_get_def_options();
1475 m_options = def_options;
1476 }
1477
1478 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
1479 m_port = port;
1480 if (port < 0)
1481 return true;
1482
1483 // 3ware RAID: Get port map
1484 GETVERSIONINPARAMS_EX vers_ex;
1485 int devmap = smart_get_version(h, &vers_ex);
1486
1487 // 3ware RAID if vendor id present
1489
1490 unsigned portmap = 0;
1491 if (devmap >= 0) {
1492 // 3ware RAID: check vendor id
1493 if (!m_is_3ware) {
1494 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
1495 "This is no 3ware 9000 controller or driver has no SMART support.\n",
1496 vers_ex.wIdentifier);
1497 devmap = -1;
1498 }
1499 else
1500 portmap = vers_ex.dwDeviceMapEx;
1501 }
1502 if (devmap < 0) {
1503 pout("%s: ATA driver has no SMART support\n", devpath);
1504 if (!is_permissive()) {
1505 close();
1506 return set_err(ENOSYS);
1507 }
1508 }
1509 m_smartver_state = 1;
1510
1511 {
1512 // 3ware RAID: update devicemap first
1514 if ( smart_get_version(h, &vers_ex) >= 0
1515 && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
1516 portmap = vers_ex.dwDeviceMapEx;
1517 }
1518 // Check port existence
1519 if (!(portmap & (1U << port))) {
1520 if (!is_permissive()) {
1521 close();
1522 return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
1523 }
1524 }
1525 }
1526
1527 return true;
1528}
1529
1530
1531/////////////////////////////////////////////////////////////////////////////
1532
1533// Query OS if device is powered up or down.
1535{
1536 // To check power mode, we open device for query operations only.
1537 // Opening for SMART r/w operations can already spin up the disk.
1538 bool self_open = !is_open();
1539 if (self_open)
1540 if (!open(true))
1541 return false;
1542 int rc = get_device_power_state(get_fh());
1543 if (self_open)
1544 close();
1545 return !rc;
1546}
1547
1548/////////////////////////////////////////////////////////////////////////////
1549
1550// Interface to ATA devices
1552{
1553 // No multi-sector support for now, see above
1554 // warning about IOCTL_ATA_PASS_THROUGH
1555 if (!ata_cmd_is_supported(in,
1559 )
1560 return false;
1561
1562 // 3ware RAID: SMART DISABLE without port number disables SMART functions
1563 if ( m_is_3ware && m_port < 0
1566 return set_err(ENOSYS, "SMART DISABLE requires 3ware port number");
1567
1568 // Determine ioctl functions valid for this ATA cmd
1569 const char * valid_options = 0;
1570
1571 switch (in.in_regs.command) {
1574 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
1575 // and SCSI_MINIPORT_* if requested by user
1576 valid_options = (m_usr_options ? "saimf" : "saif");
1577 break;
1578
1580 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
1581 valid_options = "pai3";
1582 break;
1583
1584 case ATA_SMART_CMD:
1585 switch (in.in_regs.features) {
1588 case ATA_SMART_AUTOSAVE:
1589 case ATA_SMART_ENABLE:
1590 case ATA_SMART_DISABLE:
1592 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
1593 // and SCSI_MINIPORT_* if requested by user
1594 valid_options = (m_usr_options ? "saimf" : "saif");
1595 break;
1596
1598 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
1599 valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ?
1600 "saim3" : "aim3");
1601 break;
1602
1604 // SMART_RCV_DRIVE_DATA does not support READ_LOG
1605 // Try SCSI_MINIPORT also to skip buggy class driver
1606 // SMART functions do not support multi sector I/O.
1607 if (in.size == 512)
1608 valid_options = (m_usr_options ? "saim3" : "aim3");
1609 else
1610 valid_options = "a";
1611 break;
1612
1614 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
1615 // but SCSI_MINIPORT_* only if requested by user and single sector.
1616 valid_options = (in.size == 512 && m_usr_options ? "am" : "a");
1617 break;
1618
1619 case ATA_SMART_STATUS:
1620 valid_options = (m_usr_options ? "saimf" : "saif");
1621 break;
1622
1623 default:
1624 // Unknown SMART command, handle below
1625 break;
1626 }
1627 break;
1628
1629 default:
1630 // Other ATA command, handle below
1631 break;
1632 }
1633
1634 if (!valid_options) {
1635 // No special ATA command found above, select a generic pass through ioctl.
1636 if (!( in.direction == ata_cmd_in::no_data
1637 || (in.direction == ata_cmd_in::data_in && in.size == 512))
1638 || in.in_regs.is_48bit_cmd() )
1639 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
1640 valid_options = "a";
1641 else
1642 // ATA/IDE_PASS_THROUGH
1643 valid_options = "ai";
1644 }
1645
1646 if (!m_admin) {
1647 // Restrict to IOCTL_STORAGE_*
1648 if (strchr(valid_options, 'f'))
1649 valid_options = "f";
1650 else if (strchr(valid_options, 'p'))
1651 valid_options = "p";
1652 else
1653 return set_err(ENOSYS, "Function requires admin rights");
1654 }
1655
1656 // Set IDEREGS
1657 IDEREGS regs, prev_regs;
1658 {
1659 const ata_in_regs & lo = in.in_regs;
1660 regs.bFeaturesReg = lo.features;
1661 regs.bSectorCountReg = lo.sector_count;
1662 regs.bSectorNumberReg = lo.lba_low;
1663 regs.bCylLowReg = lo.lba_mid;
1664 regs.bCylHighReg = lo.lba_high;
1665 regs.bDriveHeadReg = lo.device;
1666 regs.bCommandReg = lo.command;
1667 regs.bReserved = 0;
1668 }
1669 if (in.in_regs.is_48bit_cmd()) {
1670 const ata_in_regs & hi = in.in_regs.prev;
1671 prev_regs.bFeaturesReg = hi.features;
1672 prev_regs.bSectorCountReg = hi.sector_count;
1673 prev_regs.bSectorNumberReg = hi.lba_low;
1674 prev_regs.bCylLowReg = hi.lba_mid;
1675 prev_regs.bCylHighReg = hi.lba_high;
1676 prev_regs.bDriveHeadReg = hi.device;
1677 prev_regs.bCommandReg = hi.command;
1678 prev_regs.bReserved = 0;
1679 }
1680
1681 // Set data direction
1682 int datasize = 0;
1683 char * data = 0;
1684 switch (in.direction) {
1686 break;
1688 datasize = (int)in.size;
1689 data = (char *)in.buffer;
1690 break;
1692 datasize = -(int)in.size;
1693 data = (char *)in.buffer;
1694 break;
1695 default:
1696 return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d",
1697 (int)in.direction);
1698 }
1699
1700
1701 // Try all valid ioctls in the order specified in m_options
1702 bool powered_up = false;
1703 bool out_regs_set = false;
1704 bool id_is_cached = false;
1705 const char * options = m_options.c_str();
1706
1707 for (int i = 0; ; i++) {
1708 char opt = options[i];
1709
1710 if (!opt) {
1711 if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) {
1712 // Power up reported by GetDevicePowerState() and no ioctl available
1713 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
1714 regs.bSectorCountReg = 0xff;
1715 out_regs_set = true;
1716 break;
1717 }
1718 // No IOCTL found
1719 return set_err(ENOSYS);
1720 }
1721 if (!strchr(valid_options, opt))
1722 // Invalid for this command
1723 continue;
1724
1725 errno = 0;
1726 assert( datasize == 0 || datasize == 512
1727 || (datasize == -512 && strchr("am", opt))
1728 || (datasize > 512 && opt == 'a'));
1729 int rc;
1730 switch (opt) {
1731 default: assert(0);
1732 case 's':
1733 // call SMART_GET_VERSION once for each drive
1734 if (m_smartver_state > 1) {
1735 rc = -1; errno = ENOSYS;
1736 break;
1737 }
1738 if (!m_smartver_state) {
1739 assert(m_port == -1);
1740 GETVERSIONINPARAMS_EX vers_ex;
1741 if (smart_get_version(get_fh(), &vers_ex) < 0) {
1743 m_smartver_state = 2;
1744 rc = -1; errno = ENOSYS;
1745 break;
1746 }
1748 }
1749 else {
1750 // 3ware RAID if vendor id present
1752 }
1753
1754 m_smartver_state = 1;
1755 }
1756 rc = smart_ioctl(get_fh(), &regs, data, datasize, m_port);
1757 out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
1758 id_is_cached = (m_port < 0); // Not cached by 3ware driver
1759 break;
1760 case 'm':
1761 rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
1762 id_is_cached = (m_port < 0);
1763 break;
1764 case 'a':
1765 rc = ata_pass_through_ioctl(get_fh(), &regs,
1766 (in.in_regs.is_48bit_cmd() ? &prev_regs : 0),
1767 data, datasize);
1768 out_regs_set = true;
1769 break;
1770 case 'i':
1771 rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
1772 out_regs_set = true;
1773 break;
1774 case 'f':
1776 ata_identify_device * id = reinterpret_cast<ata_identify_device *>(data);
1778 if (rc == 0 && m_phydrive >= 0)
1780 id_is_cached = true;
1781 }
1782 else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
1785 if (rc > 0)
1786 rc = 0;
1787 break;
1788 case ATA_SMART_ENABLE:
1789 rc = 0;
1790 break;
1791 case ATA_SMART_STATUS:
1793 if (rc == 0) {
1794 // Good SMART status
1795 out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f;
1796 }
1797 else if (rc > 0) {
1798 // Bad SMART status
1799 out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4;
1800 rc = 0;
1801 }
1802 break;
1803 default:
1804 errno = ENOSYS; rc = -1;
1805 }
1806 else {
1807 errno = ENOSYS; rc = -1;
1808 }
1809 break;
1810 case '3':
1811 rc = ata_via_3ware_miniport_ioctl(get_fh(), &regs, data, datasize, m_port);
1812 out_regs_set = true;
1813 break;
1814 case 'p':
1817 if (rc == 0) {
1818 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
1819 // spin up the drive => simulate ATA result STANDBY.
1820 regs.bSectorCountReg = 0x00;
1821 out_regs_set = true;
1822 }
1823 else if (rc > 0) {
1824 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
1825 // only if it is selected by the device driver => try a passthrough ioctl to get the
1826 // actual mode, if none available simulate ACTIVE/IDLE.
1827 powered_up = true;
1828 rc = -1; errno = ENOSYS;
1829 }
1830 break;
1831 }
1832
1833 if (!rc)
1834 // Working ioctl found
1835 break;
1836
1837 if (errno != ENOSYS)
1838 // Abort on I/O error
1839 return set_err(errno);
1840
1841 out_regs_set = false;
1842 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
1843 }
1844
1845 // Return IDEREGS if set
1846 if (out_regs_set) {
1847 ata_out_regs & lo = out.out_regs;
1848 lo.error = regs.bFeaturesReg;
1849 lo.sector_count = regs.bSectorCountReg;
1850 lo.lba_low = regs.bSectorNumberReg;
1851 lo.lba_mid = regs.bCylLowReg;
1852 lo.lba_high = regs.bCylHighReg;
1853 lo.device = regs.bDriveHeadReg;
1854 lo.status = regs.bCommandReg;
1855 if (in.in_regs.is_48bit_cmd()) {
1856 ata_out_regs & hi = out.out_regs.prev;
1857 hi.sector_count = prev_regs.bSectorCountReg;
1858 hi.lba_low = prev_regs.bSectorNumberReg;
1859 hi.lba_mid = prev_regs.bCylLowReg;
1860 hi.lba_high = prev_regs.bCylHighReg;
1861 }
1862 }
1863
1866 // Update ata_identify_is_cached() result according to ioctl used.
1867 m_id_is_cached = id_is_cached;
1868
1869 return true;
1870}
1871
1872// Return true if OS caches the ATA identify sector
1874{
1875 return m_id_is_cached;
1876}
1877
1878
1879//////////////////////////////////////////////////////////////////////
1880// csmi_device
1881
1883: virtual public /*extends*/ smart_device
1884{
1885public:
1886 enum { max_number_of_ports = 32 };
1887
1888 /// Get bitmask of used ports
1889 unsigned get_ports_used();
1890
1891protected:
1894 { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); }
1895
1897
1898 /// Get phy info and port mapping, return #ports or -1 on error
1899 int get_phy_info(CSMI_SAS_PHY_INFO & phy_info, port_2_index_map & p2i);
1900
1901 /// Select physical drive
1902 bool select_port(int port);
1903
1904 /// Get info for selected physical drive
1906 { return m_phy_ent; }
1907
1908 /// Call platform-specific CSMI ioctl
1909 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
1910 unsigned csmi_bufsiz) = 0;
1911
1912private:
1913 CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy
1914
1915 static bool guess_amd_drives(CSMI_SAS_PHY_INFO & phy_info, unsigned max_phy_drives);
1916};
1917
1918
1919/////////////////////////////////////////////////////////////////////////////
1920
1921bool csmi_device::guess_amd_drives(CSMI_SAS_PHY_INFO & phy_info, unsigned max_phy_drives)
1922{
1923 if (max_phy_drives > max_number_of_ports)
1924 return false;
1925 if (max_phy_drives <= phy_info.bNumberOfPhys)
1926 return false;
1927 if (nonempty(phy_info.Phy + phy_info.bNumberOfPhys,
1928 (max_number_of_ports - phy_info.bNumberOfPhys) * sizeof(phy_info.Phy[0])))
1929 return false; // Phy[phy_info.bNumberOfPhys...] nonempty
1930
1931 // Get range of used ports, abort on unexpected values
1932 int min_pi = max_number_of_ports, max_pi = 0, i;
1933 for (i = 0; i < phy_info.bNumberOfPhys; i++) {
1934 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
1935 if (pe.Identify.bPhyIdentifier != i)
1936 return false;
1937 if (pe.bPortIdentifier >= max_phy_drives)
1938 return false;
1939 if (nonempty(&pe.Attached.bSASAddress, sizeof(pe.Attached.bSASAddress)))
1940 return false;
1941 if (min_pi > pe.bPortIdentifier)
1942 min_pi = pe.bPortIdentifier;
1943 if (max_pi < pe.bPortIdentifier)
1944 max_pi = pe.bPortIdentifier;
1945 }
1946
1947 // Append possibly used ports
1948 for (int pi = 0; i < (int)max_phy_drives; i++, pi++) {
1949 if (min_pi <= pi && pi <= max_pi)
1950 pi = max_pi + 1;
1951 if (pi >= (int)max_phy_drives)
1952 break;
1953 CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
1956 pe.Identify.bPhyIdentifier = i;
1957 pe.bPortIdentifier = pi;
1958 }
1959
1960 return true;
1961}
1962
1963int csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info, port_2_index_map & p2i)
1964{
1965 // max_number_of_ports must match CSMI_SAS_PHY_INFO.Phy[] array size
1966 STATIC_ASSERT(sizeof(phy_info.Phy) == max_number_of_ports * sizeof(phy_info.Phy[0]));
1967
1968 // Get driver info to check CSMI support
1969 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
1970 memset(&driver_info_buf, 0, sizeof(driver_info_buf));
1971 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf)))
1972 return -1;
1973
1974 const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information;
1975
1976 if (scsi_debugmode > 1) {
1977 pout("CSMI_SAS_DRIVER_INFO:\n");
1978 pout(" Name: \"%.81s\"\n", driver_info.szName);
1979 pout(" Description: \"%.81s\"\n", driver_info.szDescription);
1980 pout(" Revision: %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision);
1981 }
1982
1983 // Get Phy info
1984 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf;
1985 memset(&phy_info_buf, 0, sizeof(phy_info_buf));
1986 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf)))
1987 return -1;
1988
1989 phy_info = phy_info_buf.Information;
1990
1991 if (phy_info.bNumberOfPhys > max_number_of_ports) {
1992 set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
1993 return -1;
1994 }
1995
1996 // Get RAID info
1997 CSMI_SAS_RAID_INFO_BUFFER raid_info_buf;
1998 memset(&raid_info_buf, 0, sizeof(raid_info_buf));
1999 if (!csmi_ioctl(CC_CSMI_SAS_GET_RAID_INFO, &raid_info_buf.IoctlHeader, sizeof(raid_info_buf))) {
2000 memset(&raid_info_buf, 0, sizeof(raid_info_buf)); // Ignore error
2001 }
2002
2003 const CSMI_SAS_RAID_INFO & raid_info = raid_info_buf.Information;
2004
2005 if (scsi_debugmode > 1 && nonempty(&raid_info_buf, sizeof(raid_info_buf))) {
2006 pout("CSMI_SAS_RAID_INFO:\n");
2007 pout(" NumRaidSets: %u\n", (unsigned)raid_info.uNumRaidSets);
2008 pout(" MaxDrvPerSet: %u\n", (unsigned)raid_info.uMaxDrivesPerSet);
2009 pout(" MaxRaidSets: %u\n", (unsigned)raid_info.uMaxRaidSets);
2010 pout(" MaxRaidTypes: %d\n", raid_info.bMaxRaidTypes);
2011 pout(" MaxPhyDrives: %u\n", (unsigned)raid_info.uMaxPhysicalDrives);
2012 }
2013
2014 // Create port -> index map
2015 // Intel RST AMD rcraid
2016 // Phy[i].Value 9/10.x 14.8 15.2 16.0/17.7 9.2
2017 // ---------------------------------------------------------------------
2018 // bPortIdentifier 0xff port 0x00 port (port)
2019 // Identify.bPhyIdentifier index? index index port index
2020 // Attached.bPhyIdentifier 0x00 0x00 index 0x00 0x00
2021 //
2022 // AMD: Phy[] may be incomplete (single drives not counted) and port
2023 // numbers may be invalid (single drives skipped).
2024 // IRST: Empty ports with hotplug support may appear in Phy[].
2025
2026 int first_guessed_index = max_number_of_ports;
2027 if (!memcmp(driver_info.szName, "rcraid", 6+1)) {
2028 // Workaround for AMD driver
2029 if (guess_amd_drives(phy_info, raid_info.uMaxPhysicalDrives))
2030 first_guessed_index = phy_info.bNumberOfPhys;
2031 }
2032
2033 int number_of_ports;
2034 for (int mode = 0; ; mode++) {
2035 for (int i = 0; i < max_number_of_ports; i++)
2036 p2i[i] = -1;
2037
2038 number_of_ports = 0;
2039 bool found = false;
2040 for (int i = 0; i < max_number_of_ports; i++) {
2041 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
2043 continue;
2044
2045 // Try to detect which field contains the actual port number.
2046 // Use a bPhyIdentifier or the bPortIdentifier if unique
2047 // and not always identical to table index, otherwise use index.
2048 int port;
2049 switch (mode) {
2050 case 0: port = pe.Attached.bPhyIdentifier; break;
2051 case 1: port = pe.Identify.bPhyIdentifier; break;
2052 case 2: port = pe.bPortIdentifier; break;
2053 default: port = i; break;
2054 }
2055 if (!(port < max_number_of_ports && p2i[port] == -1)) {
2056 found = false;
2057 break;
2058 }
2059
2060 p2i[port] = i;
2061 if (number_of_ports <= port)
2062 number_of_ports = port + 1;
2063 if (port != i)
2064 found = true;
2065 }
2066
2067 if (found || mode > 2)
2068 break;
2069 }
2070
2071 if (scsi_debugmode > 1) {
2072 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
2073 for (int i = 0; i < max_number_of_ports; i++) {
2074 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
2075 if (!nonempty(&pe, sizeof(pe)))
2076 continue;
2077 const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached;
2078
2079 int port = -1;
2080 for (int p = 0; p < max_number_of_ports && port < 0; p++) {
2081 if (p2i[p] == i)
2082 port = p;
2083 }
2084
2085 pout("Phy[%d] Port: %2d%s\n", i, port, (i >= first_guessed_index ? " (*guessed*)" : ""));
2086 pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
2087 pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
2088 pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol);
2089 pout(" PortIdent: 0x%02x\n", pe.bPortIdentifier);
2090 pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier);
2091 pout(" SignalClass: 0x%02x, 0x%02x\n", id.bSignalClass, at.bSignalClass);
2092 pout(" Restricted: 0x%02x, 0x%02x\n", id.bRestricted, at.bRestricted);
2093 const unsigned char * b = id.bSASAddress;
2094 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2095 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
2096 b = at.bSASAddress;
2097 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2098 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
2099 }
2100 }
2101
2102 return number_of_ports;
2103}
2104
2106{
2107 CSMI_SAS_PHY_INFO phy_info;
2108 port_2_index_map p2i;
2109 int number_of_ports = get_phy_info(phy_info, p2i);
2110 if (number_of_ports < 0)
2111 return 0;
2112
2113 unsigned ports_used = 0;
2114 for (int p = 0; p < max_number_of_ports; p++) {
2115 int i = p2i[p];
2116 if (i < 0)
2117 continue;
2118 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
2120 continue;
2121 switch (pe.Attached.bTargetPortProtocol) {
2124 break;
2125 default:
2126 continue;
2127 }
2128
2129 ports_used |= (1U << p);
2130 }
2131
2132 return ports_used;
2133}
2134
2136{
2137 if (!(0 <= port && port < max_number_of_ports))
2138 return set_err(EINVAL, "Invalid port number %d", port);
2139
2140 CSMI_SAS_PHY_INFO phy_info;
2141 port_2_index_map p2i;
2142 int number_of_ports = get_phy_info(phy_info, p2i);
2143 if (number_of_ports < 0)
2144 return false;
2145
2146 int port_index = p2i[port];
2147 if (port_index < 0) {
2148 if (port < number_of_ports)
2149 return set_err(ENOENT, "Port %d is disabled", port);
2150 else
2151 return set_err(ENOENT, "Port %d does not exist (#ports: %d)", port,
2152 number_of_ports);
2153 }
2154
2155 const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[port_index];
2157 return set_err(ENOENT, "No device on port %d", port);
2158
2159 switch (phy_ent.Attached.bTargetPortProtocol) {
2162 break;
2163 default:
2164 return set_err(ENOENT, "No SATA device on port %d (protocol: %d)",
2165 port, phy_ent.Attached.bTargetPortProtocol);
2166 }
2167
2168 m_phy_ent = phy_ent;
2169 return true;
2170}
2171
2172
2173//////////////////////////////////////////////////////////////////////
2174// csmi_ata_device
2175
2177: virtual public /*extends*/ csmi_device,
2178 virtual public /*implements*/ ata_device
2179{
2180public:
2181 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) override;
2182
2183protected:
2186};
2187
2188
2189//////////////////////////////////////////////////////////////////////
2190
2192{
2193 if (!ata_cmd_is_supported(in,
2198 "CSMI")
2199 )
2200 return false;
2201
2202 // Create buffer with appropriate size
2203 raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size);
2204 CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data();
2205
2206 // Set addresses from Phy info
2207 CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters;
2208 const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent();
2209 pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier; // Used by AMD, ignored by IRST
2210 pthru.bPortIdentifier = phy_ent.bPortIdentifier; // Ignored
2211 memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress,
2212 sizeof(pthru.bDestinationSASAddress)); // Used by IRST (at index 1), ignored by AMD
2213 pthru.bConnectionRate = CSMI_SAS_LINK_RATE_NEGOTIATED;
2214
2215 // Set transfer mode
2216 switch (in.direction) {
2219 break;
2222 pthru.uDataLength = in.size;
2223 break;
2226 pthru.uDataLength = in.size;
2227 memcpy(pthru_buf->bDataBuffer, in.buffer, in.size);
2228 break;
2229 default:
2230 return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d",
2231 (int)in.direction);
2232 }
2233
2234 // Set host-to-device FIS
2235 {
2236 unsigned char * fis = pthru.bCommandFIS;
2237 const ata_in_regs & lo = in.in_regs;
2238 const ata_in_regs & hi = in.in_regs.prev;
2239 fis[ 0] = 0x27; // Type: host-to-device FIS
2240 fis[ 1] = 0x80; // Bit7: Update command register
2241 fis[ 2] = lo.command;
2242 fis[ 3] = lo.features;
2243 fis[ 4] = lo.lba_low;
2244 fis[ 5] = lo.lba_mid;
2245 fis[ 6] = lo.lba_high;
2246 fis[ 7] = lo.device;
2247 fis[ 8] = hi.lba_low;
2248 fis[ 9] = hi.lba_mid;
2249 fis[10] = hi.lba_high;
2250 fis[11] = hi.features;
2251 fis[12] = lo.sector_count;
2252 fis[13] = hi.sector_count;
2253 }
2254
2255 // Call ioctl
2256 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) {
2257 return false;
2258 }
2259
2260 // Get device-to-host FIS
2261 // Assume values are unavailable if all register fields are zero (AMD RAID driver)
2262 if (nonempty(pthru_buf->Status.bStatusFIS + 2, 13 - 2 + 1)) {
2263 const unsigned char * fis = pthru_buf->Status.bStatusFIS;
2264 ata_out_regs & lo = out.out_regs;
2265 lo.status = fis[ 2];
2266 lo.error = fis[ 3];
2267 lo.lba_low = fis[ 4];
2268 lo.lba_mid = fis[ 5];
2269 lo.lba_high = fis[ 6];
2270 lo.device = fis[ 7];
2271 lo.sector_count = fis[12];
2272 if (in.in_regs.is_48bit_cmd()) {
2273 ata_out_regs & hi = out.out_regs.prev;
2274 hi.lba_low = fis[ 8];
2275 hi.lba_mid = fis[ 9];
2276 hi.lba_high = fis[10];
2277 hi.sector_count = fis[13];
2278 }
2279 }
2280
2281 // Get data
2283 // TODO: Check ptru_buf->Status.uDataBytes
2284 memcpy(in.buffer, pthru_buf->bDataBuffer, in.size);
2285
2286 return true;
2287}
2288
2289
2290//////////////////////////////////////////////////////////////////////
2291// win_csmi_device
2292
2294: public /*implements*/ csmi_ata_device
2295{
2296public:
2297 win_csmi_device(smart_interface * intf, const char * dev_name,
2298 const char * req_type);
2299
2300 virtual ~win_csmi_device();
2301
2302 virtual bool open() override;
2303
2304 virtual bool close() override;
2305
2306 virtual bool is_open() const override;
2307
2308 bool open_scsi();
2309
2310protected:
2311 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
2312 unsigned csmi_bufsiz) override;
2313
2314private:
2315 HANDLE m_fh; ///< Controller device handle
2316 int m_port; ///< Port number
2317};
2318
2319
2320//////////////////////////////////////////////////////////////////////
2321
2323 const char * req_type)
2324: smart_device(intf, dev_name, "ata", req_type),
2325 m_fh(INVALID_HANDLE_VALUE), m_port(-1)
2326{
2327}
2328
2330{
2331 if (m_fh != INVALID_HANDLE_VALUE)
2332 CloseHandle(m_fh);
2333}
2334
2336{
2337 return (m_fh != INVALID_HANDLE_VALUE);
2338}
2339
2341{
2342 if (m_fh == INVALID_HANDLE_VALUE)
2343 return true;
2344 BOOL rc = CloseHandle(m_fh);
2345 m_fh = INVALID_HANDLE_VALUE;
2346 return !!rc;
2347}
2348
2349
2351{
2352 // Parse name
2353 unsigned contr_no = ~0, port = ~0; int nc = -1;
2354 const char * name = skipdev(get_dev_name());
2355 if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &port, &nc) >= 0
2356 && nc == (int)strlen(name) && contr_no <= 9 && port < 32) )
2357 return set_err(EINVAL);
2358
2359 // Open controller handle
2360 char devpath[30];
2361 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no);
2362
2363 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2364 FILE_SHARE_READ|FILE_SHARE_WRITE,
2365 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
2366
2367 if (h == INVALID_HANDLE_VALUE) {
2368 long err = GetLastError();
2369 if (err == ERROR_FILE_NOT_FOUND)
2370 set_err(ENOENT, "%s: not found", devpath);
2371 else if (err == ERROR_ACCESS_DENIED)
2372 set_err(EACCES, "%s: access denied", devpath);
2373 else
2374 set_err(EIO, "%s: Error=%ld", devpath, err);
2375 return false;
2376 }
2377
2378 if (scsi_debugmode > 1)
2379 pout(" %s: successfully opened\n", devpath);
2380
2381 m_fh = h;
2382 m_port = port;
2383 return true;
2384}
2385
2386
2388{
2389 if (!open_scsi())
2390 return false;
2391
2392 // Get Phy info for this drive
2393 if (!select_port(m_port)) {
2394 close();
2395 return false;
2396 }
2397
2398 return true;
2399}
2400
2401
2402bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
2403 unsigned csmi_bufsiz)
2404{
2405 // Determine signature
2406 const char * sig;
2407 switch (code) {
2408 case CC_CSMI_SAS_GET_DRIVER_INFO:
2409 sig = CSMI_ALL_SIGNATURE; break;
2410 case CC_CSMI_SAS_GET_RAID_INFO:
2411 sig = CSMI_RAID_SIGNATURE; break;
2412 case CC_CSMI_SAS_GET_PHY_INFO:
2413 case CC_CSMI_SAS_STP_PASSTHRU:
2414 sig = CSMI_SAS_SIGNATURE; break;
2415 default:
2416 return set_err(ENOSYS, "Unknown CSMI code=%u", code);
2417 }
2418
2419 // Set header
2420 csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER);
2421 strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature));
2422 csmi_buffer->Timeout = CSMI_SAS_TIMEOUT;
2423 csmi_buffer->ControlCode = code;
2424 csmi_buffer->ReturnCode = 0;
2425 csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER);
2426
2427 // Call function
2428 DWORD num_out = 0;
2429 if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT,
2430 csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) {
2431 long err = GetLastError();
2432 if (scsi_debugmode)
2433 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err);
2434 if ( err == ERROR_INVALID_FUNCTION
2435 || err == ERROR_NOT_SUPPORTED
2436 || err == ERROR_DEV_NOT_EXIST)
2437 return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err);
2438 else
2439 return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err);
2440 }
2441
2442 // Check result
2443 if (csmi_buffer->ReturnCode) {
2444 if (scsi_debugmode) {
2445 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
2446 code, (unsigned)csmi_buffer->ReturnCode);
2447 }
2448 return set_err(EIO, "CSMI(%u) failed with ReturnCode=%u", code, (unsigned)csmi_buffer->ReturnCode);
2449 }
2450
2451 if (scsi_debugmode > 1)
2452 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out);
2453
2454 return true;
2455}
2456
2457
2458//////////////////////////////////////////////////////////////////////
2459// win_tw_cli_device
2460
2461// Routines for pseudo device /dev/tw_cli/*
2462// Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
2463// TODO: This is OS independent
2464
2466: public /*implements*/ ata_device_with_command_set
2467{
2468public:
2469 win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type);
2470
2471 virtual bool is_open() const override;
2472
2473 virtual bool open() override;
2474
2475 virtual bool close() override;
2476
2477protected:
2478 virtual int ata_command_interface(smart_command_set command, int select, char * data);
2479
2480private:
2484};
2485
2486
2487/////////////////////////////////////////////////////////////////////////////
2488
2489win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type)
2490: smart_device(intf, dev_name, "tw_cli", req_type),
2491 m_ident_valid(false), m_smart_valid(false)
2492{
2493 memset(&m_ident_buf, 0, sizeof(m_ident_buf));
2494 memset(&m_smart_buf, 0, sizeof(m_smart_buf));
2495}
2496
2497
2499{
2500 return (m_ident_valid || m_smart_valid);
2501}
2502
2503
2504// Get clipboard data
2505
2506static int get_clipboard(char * data, int datasize)
2507{
2508 if (!OpenClipboard(NULL))
2509 return -1;
2510 HANDLE h = GetClipboardData(CF_TEXT);
2511 if (!h) {
2512 CloseClipboard();
2513 return 0;
2514 }
2515 const void * p = GlobalLock(h);
2516 int n = GlobalSize(h);
2517 if (n > datasize)
2518 n = datasize;
2519 memcpy(data, p, n);
2520 GlobalFree(h);
2521 CloseClipboard();
2522 return n;
2523}
2524
2525
2526static const char * findstr(const char * str, const char * sub)
2527{
2528 const char * s = strstr(str, sub);
2529 return (s ? s+strlen(sub) : "");
2530}
2531
2532
2534{
2535 m_ident_valid = m_smart_valid = false;
2536 const char * name = skipdev(get_dev_name());
2537 // Read tw_cli or 3DM browser output into buffer
2538 char buffer[4096];
2539 int size = -1, n1 = -1, n2 = -1;
2540 if (!strcmp(name, "tw_cli/clip")) { // read clipboard
2541 size = get_clipboard(buffer, sizeof(buffer));
2542 }
2543 else if (!strcmp(name, "tw_cli/stdin")) { // read stdin
2544 size = fread(buffer, 1, sizeof(buffer), stdin);
2545 }
2546 else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) {
2547 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
2548 char cmd[100];
2549 snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
2550 if (ata_debugmode > 1)
2551 pout("%s: Run: \"%s\"\n", name, cmd);
2552 FILE * f = popen(cmd, "rb");
2553 if (f) {
2554 size = fread(buffer, 1, sizeof(buffer), f);
2555 pclose(f);
2556 }
2557 }
2558 else {
2559 return set_err(EINVAL);
2560 }
2561
2562 if (ata_debugmode > 1)
2563 pout("%s: Read %d bytes\n", name, size);
2564 if (size <= 0)
2565 return set_err(ENOENT);
2566 if (size >= (int)sizeof(buffer))
2567 return set_err(EIO);
2568
2569 buffer[size] = 0;
2570 if (ata_debugmode > 1)
2571 pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
2572
2573 // Fake identify sector
2574 STATIC_ASSERT(sizeof(ata_identify_device) == 512);
2576 memset(id, 0, sizeof(*id));
2577 copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model));
2578 copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev));
2579 copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no));
2580 unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)"
2581 sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks);
2582 if (nblocks) {
2583 id->words047_079[49-47] = 0x0200; // size valid
2584 id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16
2585 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32
2586 }
2587 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
2588 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
2589
2590 // Parse smart data hex dump
2591 const char * s = findstr(buffer, "Drive Smart Data:");
2592 if (!*s)
2593 s = findstr(buffer, "Drive SMART Data:"); // tw_cli from 9.5.x
2594 if (!*s) {
2595 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
2596 if (*s) {
2597 const char * s1 = findstr(s, "<td class"); // html version
2598 if (*s1)
2599 s = s1;
2600 s += strcspn(s, "\r\n");
2601 }
2602 else
2603 s = buffer; // try raw hex dump without header
2604 }
2605 unsigned char * sd = (unsigned char *)&m_smart_buf;
2606 int i = 0;
2607 for (;;) {
2608 unsigned x = ~0; int n = -1;
2609 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
2610 break;
2611 sd[i] = (unsigned char)x;
2612 if (!(++i < 512 && n > 0))
2613 break;
2614 s += n;
2615 if (*s == '<') // "<br>"
2616 s += strcspn(s, "\r\n");
2617 }
2618 if (i < 512) {
2619 if (!id->model[1]) {
2620 // No useful data found
2621 char * err = strstr(buffer, "Error:");
2622 if (!err)
2623 err = strstr(buffer, "error :");
2624 if (err && (err = strchr(err, ':'))) {
2625 // Show tw_cli error message
2626 err++;
2627 err[strcspn(err, "\r\n")] = 0;
2628 return set_err(EIO, "%s", err);
2629 }
2630 return set_err(EIO);
2631 }
2632 sd = 0;
2633 }
2634
2635 m_ident_valid = true;
2636 m_smart_valid = !!sd;
2637 return true;
2638}
2639
2640
2642{
2643 m_ident_valid = m_smart_valid = false;
2644 return true;
2645}
2646
2647
2649{
2650 switch (command) {
2651 case IDENTIFY:
2652 if (!m_ident_valid)
2653 break;
2654 memcpy(data, &m_ident_buf, 512);
2655 return 0;
2656 case READ_VALUES:
2657 if (!m_smart_valid)
2658 break;
2659 memcpy(data, &m_smart_buf, 512);
2660 return 0;
2661 case ENABLE:
2662 case STATUS:
2663 case STATUS_CHECK: // Fake "good" SMART status
2664 return 0;
2665 default:
2666 break;
2667 }
2668 // Arrive here for all unsupported commands
2669 set_err(ENOSYS);
2670 return -1;
2671}
2672
2673
2674/////////////////////////////////////////////////////////////////////////////
2675// win_scsi_device
2676// SPT Interface (for SCSI devices and ATA devices behind SATLs)
2677
2679: public /*implements*/ scsi_device,
2680 virtual public /*extends*/ win_smart_device
2681{
2682public:
2683 win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
2684
2685 virtual bool open() override;
2686
2687 virtual bool scsi_pass_through(scsi_cmnd_io * iop) override;
2688
2689private:
2690 bool open(int pd_num, int ld_num, int tape_num, int sub_addr);
2691};
2692
2693
2694/////////////////////////////////////////////////////////////////////////////
2695
2697 const char * dev_name, const char * req_type)
2698: smart_device(intf, dev_name, "scsi", req_type)
2699{
2700}
2701
2703{
2704 const char * name = skipdev(get_dev_name()); int len = strlen(name);
2705 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
2706 char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
2707 if ( sscanf(name, "sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
2708 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
2709 return open(sdxy_to_phydrive(drive), -1, -1, sub_addr);
2710 }
2711 // pd<m>,N => Physical drive <m>, RAID port N
2712 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
2713 if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
2714 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
2715 return open(pd_num, -1, -1, sub_addr);
2716 }
2717 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2718 int logdrive = drive_letter(name);
2719 if (logdrive >= 0) {
2720 return open(-1, logdrive, -1, -1);
2721 }
2722 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
2723 int tape_num = -1; n1 = -1;
2724 if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2725 return open(-1, -1, tape_num, -1);
2726 }
2727 tape_num = -1; n1 = -1;
2728 if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2729 return open(-1, -1, tape_num, -1);
2730 }
2731 // tape<m> => tape drive <m>
2732 tape_num = -1; n1 = -1;
2733 if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
2734 return open(-1, -1, tape_num, -1);
2735 }
2736
2737 return set_err(EINVAL);
2738}
2739
2740bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/)
2741{
2742 char b[128];
2743 b[sizeof(b) - 1] = '\0';
2744 if (pd_num >= 0)
2745 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
2746 else if (ld_num >= 0)
2747 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
2748 else if (tape_num >= 0)
2749 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
2750 else {
2751 set_err(EINVAL);
2752 return false;
2753 }
2754
2755 // Open device
2756 HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
2757 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2758 OPEN_EXISTING, 0, 0);
2759 if (h == INVALID_HANDLE_VALUE) {
2760 set_err(ENODEV, "%s: Open failed, Error=%u", b, (unsigned)GetLastError());
2761 return false;
2762 }
2763 set_fh(h);
2764 return true;
2765}
2766
2767
2768typedef struct {
2769 SCSI_PASS_THROUGH_DIRECT spt;
2770 ULONG Filler;
2771 UCHAR ucSenseBuf[64];
2773
2774
2775// Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
2776// Used if DataTransferLength not supported by *_DIRECT.
2777static long scsi_pass_through_indirect(HANDLE h,
2779{
2780 struct SCSI_PASS_THROUGH_WITH_BUFFERS {
2781 SCSI_PASS_THROUGH spt;
2782 ULONG Filler;
2783 UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)];
2784 UCHAR ucDataBuf[512];
2785 };
2786
2787 SCSI_PASS_THROUGH_WITH_BUFFERS sb;
2788 memset(&sb, 0, sizeof(sb));
2789
2790 // DATA_OUT not implemented yet
2791 if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN
2792 && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf)))
2793 return ERROR_INVALID_PARAMETER;
2794
2795 sb.spt.Length = sizeof(sb.spt);
2796 sb.spt.CdbLength = sbd->spt.CdbLength;
2797 memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb));
2798 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
2799 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
2800 sb.spt.DataIn = sbd->spt.DataIn;
2801 sb.spt.DataTransferLength = sbd->spt.DataTransferLength;
2802 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
2803 sb.spt.TimeOutValue = sbd->spt.TimeOutValue;
2804
2805 DWORD num_out;
2806 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
2807 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
2808 return GetLastError();
2809
2810 sbd->spt.ScsiStatus = sb.spt.ScsiStatus;
2811 if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION)
2812 memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf));
2813
2814 sbd->spt.DataTransferLength = sb.spt.DataTransferLength;
2815 if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
2816 memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
2817 return 0;
2818}
2819
2820
2821// Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
2823{
2824 int report = scsi_debugmode; // TODO
2825
2826 if (report > 0) {
2827 int k, j;
2828 const unsigned char * ucp = iop->cmnd;
2829 const char * np;
2830 char buff[256];
2831 const int sz = (int)sizeof(buff);
2832
2833 np = scsi_get_opcode_name(ucp);
2834 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
2835 for (k = 0; k < (int)iop->cmnd_len; ++k)
2836 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
2837 if ((report > 1) &&
2838 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
2839 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2840
2841 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
2842 "data, len=%d%s:\n", (int)iop->dxfer_len,
2843 (trunc ? " [only first 256 bytes shown]" : ""));
2844 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2845 }
2846 else
2847 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
2848 pout("%s", buff);
2849 }
2850
2852 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
2853 set_err(EINVAL, "cmnd_len too large");
2854 return false;
2855 }
2856
2857 memset(&sb, 0, sizeof(sb));
2858 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
2859 sb.spt.CdbLength = iop->cmnd_len;
2860 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
2861 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
2862 sb.spt.SenseInfoOffset =
2863 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
2864 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
2865
2866 bool direct = true;
2867 switch (iop->dxfer_dir) {
2868 case DXFER_NONE:
2869 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
2870 break;
2871 case DXFER_FROM_DEVICE:
2872 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
2873 sb.spt.DataTransferLength = iop->dxfer_len;
2874 sb.spt.DataBuffer = iop->dxferp;
2875 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
2876 // transfers (needed for SMART STATUS check of JMicron USB bridges)
2877 if (sb.spt.DataTransferLength == 1)
2878 direct = false;
2879 break;
2880 case DXFER_TO_DEVICE:
2881 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
2882 sb.spt.DataTransferLength = iop->dxfer_len;
2883 sb.spt.DataBuffer = iop->dxferp;
2884 break;
2885 default:
2886 set_err(EINVAL, "bad dxfer_dir");
2887 return false;
2888 }
2889
2890 long err = 0;
2891 if (direct) {
2892 DWORD num_out;
2893 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
2894 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
2895 err = GetLastError();
2896 }
2897 else
2898 err = scsi_pass_through_indirect(get_fh(), &sb);
2899
2900 if (err)
2901 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
2902 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
2903 (direct ? "_DIRECT" : ""), err);
2904
2905 iop->scsi_status = sb.spt.ScsiStatus;
2907 int slen = sb.ucSenseBuf[7] + 8;
2908
2909 if (slen > (int)sizeof(sb.ucSenseBuf))
2910 slen = sizeof(sb.ucSenseBuf);
2911 if (slen > (int)iop->max_sense_len)
2912 slen = iop->max_sense_len;
2913 memcpy(iop->sensep, sb.ucSenseBuf, slen);
2914 iop->resp_sense_len = slen;
2915 if (report) {
2916 if (report > 1) {
2917 pout(" >>> Sense buffer, len=%d:\n", slen);
2918 dStrHex(iop->sensep, slen , 1);
2919 }
2920 if ((iop->sensep[0] & 0x7f) > 0x71)
2921 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
2922 iop->scsi_status, iop->sensep[1] & 0xf,
2923 iop->sensep[2], iop->sensep[3]);
2924 else
2925 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
2926 iop->scsi_status, iop->sensep[2] & 0xf,
2927 iop->sensep[12], iop->sensep[13]);
2928 }
2929 } else
2930 iop->resp_sense_len = 0;
2931
2932 if (iop->dxfer_len > sb.spt.DataTransferLength)
2933 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
2934 else
2935 iop->resid = 0;
2936
2937 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
2938 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2939 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
2940 (trunc ? " [only first 256 bytes shown]" : ""));
2941 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2942 }
2943 return true;
2944}
2945
2946
2947/////////////////////////////////////////////////////////////////////////////
2948/// Areca RAID support
2949
2950// TODO: combine with above scsi_pass_through_direct()
2951static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop)
2952{
2953 int report = scsi_debugmode; // TODO
2954
2955 if (report > 0) {
2956 int k, j;
2957 const unsigned char * ucp = iop->cmnd;
2958 const char * np;
2959 char buff[256];
2960 const int sz = (int)sizeof(buff);
2961
2962 np = scsi_get_opcode_name(ucp);
2963 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
2964 for (k = 0; k < (int)iop->cmnd_len; ++k)
2965 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
2966 if ((report > 1) &&
2967 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
2968 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
2969
2970 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
2971 "data, len=%d%s:\n", (int)iop->dxfer_len,
2972 (trunc ? " [only first 256 bytes shown]" : ""));
2973 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
2974 }
2975 else
2976 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
2977 pout("%s", buff);
2978 }
2979
2981 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
2982 return EINVAL;
2983 }
2984
2985 memset(&sb, 0, sizeof(sb));
2986 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
2987 //sb.spt.PathId = 0;
2988 sb.spt.TargetId = targetid;
2989 //sb.spt.Lun = 0;
2990 sb.spt.CdbLength = iop->cmnd_len;
2991 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
2992 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
2993 sb.spt.SenseInfoOffset =
2994 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
2995 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
2996
2997 bool direct = true;
2998 switch (iop->dxfer_dir) {
2999 case DXFER_NONE:
3000 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3001 break;
3002 case DXFER_FROM_DEVICE:
3003 sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3004 sb.spt.DataTransferLength = iop->dxfer_len;
3005 sb.spt.DataBuffer = iop->dxferp;
3006 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3007 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3008 if (sb.spt.DataTransferLength == 1)
3009 direct = false;
3010 break;
3011 case DXFER_TO_DEVICE:
3012 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3013 sb.spt.DataTransferLength = iop->dxfer_len;
3014 sb.spt.DataBuffer = iop->dxferp;
3015 break;
3016 default:
3017 return EINVAL;
3018 }
3019
3020 long err = 0;
3021 if (direct) {
3022 DWORD num_out;
3023 if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
3024 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3025 err = GetLastError();
3026 }
3027 else
3028 err = scsi_pass_through_indirect(fd, &sb);
3029
3030 if (err)
3031 {
3032 return err;
3033 }
3034
3035 iop->scsi_status = sb.spt.ScsiStatus;
3037 int slen = sb.ucSenseBuf[7] + 8;
3038
3039 if (slen > (int)sizeof(sb.ucSenseBuf))
3040 slen = sizeof(sb.ucSenseBuf);
3041 if (slen > (int)iop->max_sense_len)
3042 slen = iop->max_sense_len;
3043 memcpy(iop->sensep, sb.ucSenseBuf, slen);
3044 iop->resp_sense_len = slen;
3045 if (report) {
3046 if (report > 1) {
3047 pout(" >>> Sense buffer, len=%d:\n", slen);
3048 dStrHex(iop->sensep, slen , 1);
3049 }
3050 if ((iop->sensep[0] & 0x7f) > 0x71)
3051 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3052 iop->scsi_status, iop->sensep[1] & 0xf,
3053 iop->sensep[2], iop->sensep[3]);
3054 else
3055 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3056 iop->scsi_status, iop->sensep[2] & 0xf,
3057 iop->sensep[12], iop->sensep[13]);
3058 }
3059 } else
3060 iop->resp_sense_len = 0;
3061
3062 if (iop->dxfer_len > sb.spt.DataTransferLength)
3063 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3064 else
3065 iop->resid = 0;
3066
3067 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3068 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3069 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
3070 (trunc ? " [only first 256 bytes shown]" : ""));
3071 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3072 }
3073
3074 return 0;
3075}
3076
3077
3078/////////////////////////////////////////////////////////////////////////////
3079// win_areca_scsi_device
3080// SAS(SCSI) device behind Areca RAID Controller
3081
3083: public /*implements*/ areca_scsi_device,
3084 public /*extends*/ win_smart_device
3085{
3086public:
3087 win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
3088 virtual bool open() override;
3089 virtual smart_device * autodetect_open() override;
3090 virtual bool arcmsr_lock() override;
3091 virtual bool arcmsr_unlock() override;
3092 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) override;
3093
3094private:
3095 HANDLE m_mutex;
3096};
3097
3098
3099/////////////////////////////////////////////////////////////////////////////
3100
3101win_areca_scsi_device::win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
3102: smart_device(intf, dev_name, "areca", "areca")
3103{
3104 set_fh(INVALID_HANDLE_VALUE);
3105 set_disknum(disknum);
3106 set_encnum(encnum);
3107 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
3108}
3109
3111{
3112 HANDLE hFh;
3113
3114 if( is_open() )
3115 {
3116 return true;
3117 }
3118 hFh = CreateFile( get_dev_name(),
3119 GENERIC_READ|GENERIC_WRITE,
3120 FILE_SHARE_READ|FILE_SHARE_WRITE,
3121 NULL,
3122 OPEN_EXISTING,
3123 0,
3124 NULL );
3125 if(hFh == INVALID_HANDLE_VALUE)
3126 {
3127 return false;
3128 }
3129
3130 set_fh(hFh);
3131 return true;
3132}
3133
3135{
3136 return this;
3137}
3138
3140{
3141 int ioctlreturn = 0;
3142
3143 ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
3144 if ( ioctlreturn || iop->scsi_status )
3145 {
3146 ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
3147 if ( ioctlreturn || iop->scsi_status )
3148 {
3149 // errors found
3150 return -1;
3151 }
3152 }
3153
3154 return ioctlreturn;
3155}
3156
3158{
3159#define SYNCOBJNAME "Global\\SynIoctlMutex"
3160 int ctlrnum = -1;
3161 char mutexstr[64];
3162
3163 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
3164 return set_err(EINVAL, "unable to parse device name");
3165
3166 snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
3167 m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3168 if ( m_mutex == NULL )
3169 {
3170 return set_err(EIO, "CreateMutex failed");
3171 }
3172
3173 // atomic access to driver
3174 WaitForSingleObject(m_mutex, INFINITE);
3175
3176 return true;
3177}
3178
3179
3181{
3182 if( m_mutex != NULL)
3183 {
3184 ReleaseMutex(m_mutex);
3185 CloseHandle(m_mutex);
3186 }
3187
3188 return true;
3189}
3190
3191
3192/////////////////////////////////////////////////////////////////////////////
3193// win_areca_ata_device
3194// SATA(ATA) device behind Areca RAID Controller
3195
3197: public /*implements*/ areca_ata_device,
3198 public /*extends*/ win_smart_device
3199{
3200public:
3201 win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
3202 virtual bool open() override;
3203 virtual smart_device * autodetect_open() override;
3204 virtual bool arcmsr_lock() override;
3205 virtual bool arcmsr_unlock() override;
3206 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) override;
3207
3208private:
3209 HANDLE m_mutex;
3210};
3211
3212
3213/////////////////////////////////////////////////////////////////////////////
3214
3215win_areca_ata_device::win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
3216: smart_device(intf, dev_name, "areca", "areca")
3217{
3218 set_fh(INVALID_HANDLE_VALUE);
3219 set_disknum(disknum);
3220 set_encnum(encnum);
3221 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
3222}
3223
3225{
3226 HANDLE hFh;
3227
3228 if( is_open() )
3229 {
3230 return true;
3231 }
3232 hFh = CreateFile( get_dev_name(),
3233 GENERIC_READ|GENERIC_WRITE,
3234 FILE_SHARE_READ|FILE_SHARE_WRITE,
3235 NULL,
3236 OPEN_EXISTING,
3237 0,
3238 NULL );
3239 if(hFh == INVALID_HANDLE_VALUE)
3240 {
3241 return false;
3242 }
3243
3244 set_fh(hFh);
3245 return true;
3246}
3247
3249{
3250 // autodetect device type
3252 if(is_ata < 0)
3253 {
3254 set_err(EIO);
3255 return this;
3256 }
3257
3258 if(is_ata == 1)
3259 {
3260 // SATA device
3261 return this;
3262 }
3263
3264 // SAS device
3266 close();
3267 delete this;
3268 newdev->open(); // TODO: Can possibly pass open fd
3269
3270 return newdev.release();
3271}
3272
3274{
3275 int ioctlreturn = 0;
3276
3277 ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
3278 if ( ioctlreturn || iop->scsi_status )
3279 {
3280 ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
3281 if ( ioctlreturn || iop->scsi_status )
3282 {
3283 // errors found
3284 return -1;
3285 }
3286 }
3287
3288 return ioctlreturn;
3289}
3290
3292{
3293#define SYNCOBJNAME "Global\\SynIoctlMutex"
3294 int ctlrnum = -1;
3295 char mutexstr[64];
3296
3297 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
3298 return set_err(EINVAL, "unable to parse device name");
3299
3300 snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
3301 m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3302 if ( m_mutex == NULL )
3303 {
3304 return set_err(EIO, "CreateMutex failed");
3305 }
3306
3307 // atomic access to driver
3308 WaitForSingleObject(m_mutex, INFINITE);
3309
3310 return true;
3311}
3312
3313
3315{
3316 if( m_mutex != NULL)
3317 {
3318 ReleaseMutex(m_mutex);
3319 CloseHandle(m_mutex);
3320 }
3321
3322 return true;
3323}
3324
3325
3326/////////////////////////////////////////////////////////////////////////////
3327// win_aacraid_device
3328// PMC aacraid Support
3329
3331:public /*implements*/ scsi_device,
3332public /*extends*/ win_smart_device
3333{
3334public:
3335 win_aacraid_device(smart_interface *intf, const char *dev_name,unsigned int ctrnum, unsigned int target, unsigned int lun);
3336
3337 virtual ~win_aacraid_device();
3338
3339 virtual bool open() override;
3340
3341 virtual bool scsi_pass_through(struct scsi_cmnd_io *iop) override;
3342
3343private:
3344 //Device Host number
3346
3347 //Channel(Lun) of the device
3349
3350 //Id of the device
3352};
3353
3354
3355/////////////////////////////////////////////////////////////////////////////
3356
3358 const char *dev_name, unsigned ctrnum, unsigned target, unsigned lun)
3359: smart_device(intf, dev_name, "aacraid", "aacraid"),
3360 m_ctrnum(ctrnum), m_lun(lun), m_target(target)
3361{
3362 set_info().info_name = strprintf("%s [aacraid_disk_%02d_%02d_%d]", dev_name, m_ctrnum, m_lun, m_target);
3363 set_info().dev_type = strprintf("aacraid,%d,%d,%d", m_ctrnum, m_lun, m_target);
3364}
3365
3367{
3368}
3369
3371{
3372 if (is_open())
3373 return true;
3374
3375 HANDLE hFh = CreateFile( get_dev_name(),
3376 GENERIC_READ|GENERIC_WRITE,
3377 FILE_SHARE_READ|FILE_SHARE_WRITE,
3378 NULL,
3379 OPEN_EXISTING,
3380 0,
3381 0);
3382 if (hFh == INVALID_HANDLE_VALUE)
3383 return set_err(ENODEV, "Open failed, Error=%u", (unsigned)GetLastError());
3384
3385 set_fh(hFh);
3386 return true;
3387}
3388
3390{
3391 int report = scsi_debugmode;
3392 if (report > 0)
3393 {
3394 int k, j;
3395 const unsigned char * ucp = iop->cmnd;
3396 const char * np;
3397 char buff[256];
3398 const int sz = (int)sizeof(buff);
3399 np = scsi_get_opcode_name(ucp);
3400 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3401 for (k = 0; k < (int)iop->cmnd_len; ++k)
3402 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3403 if ((report > 1) &&
3404 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3405 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3406
3407 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3408 "data, len=%d%s:\n", (int)iop->dxfer_len,
3409 (trunc ? " [only first 256 bytes shown]" : ""));
3410 dStrHex(iop->dxferp, (trunc ? 256 : (int)iop->dxfer_len) , 1);
3411 }
3412 else
3413 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3414 pout("buff %s\n",buff);
3415 }
3416
3417 // Create buffer with appropriate size
3418 constexpr unsigned scsiRequestBlockSize = sizeof(SCSI_REQUEST_BLOCK);
3419 constexpr unsigned dataOffset = (sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize + 7) & 0xfffffff8;
3420 raw_buffer pthru_raw_buf(dataOffset + iop->dxfer_len + 8); // 32|64-bit: 96|120 + ...
3421
3422 char * ioBuffer = reinterpret_cast<char *>(pthru_raw_buf.data());
3423 SRB_IO_CONTROL * pSrbIO = (SRB_IO_CONTROL *) ioBuffer;
3424 SCSI_REQUEST_BLOCK * pScsiIO = (SCSI_REQUEST_BLOCK *) (ioBuffer + sizeof(SRB_IO_CONTROL));
3425 char *pRequestSenseIO = (char *) (ioBuffer + sizeof(SRB_IO_CONTROL) + scsiRequestBlockSize);
3426 char *pDataIO = (char *) (ioBuffer + dataOffset);
3427 memset(pScsiIO, 0, scsiRequestBlockSize);
3428 pScsiIO->Length = (USHORT) scsiRequestBlockSize;
3429 pScsiIO->Function = SRB_FUNCTION_EXECUTE_SCSI;
3430 pScsiIO->PathId = 0;
3431 pScsiIO->TargetId = m_target;
3432 pScsiIO->Lun = m_lun;
3433 pScsiIO->CdbLength = (int)iop->cmnd_len;
3434 switch(iop->dxfer_dir){
3435 case DXFER_NONE:
3436 pScsiIO->SrbFlags = SRB_NoDataXfer;
3437 break;
3438 case DXFER_FROM_DEVICE:
3439 pScsiIO->SrbFlags |= SRB_DataIn;
3440 break;
3441 case DXFER_TO_DEVICE:
3442 pScsiIO->SrbFlags |= SRB_DataOut;
3443 break;
3444 default:
3445 pout("aacraid: bad dxfer_dir\n");
3446 return set_err(EINVAL, "aacraid: bad dxfer_dir\n");
3447 }
3448 pScsiIO->DataTransferLength = (ULONG)iop->dxfer_len;
3449 pScsiIO->TimeOutValue = iop->timeout;
3450 UCHAR *pCdb = (UCHAR *) pScsiIO->Cdb;
3451 memcpy(pCdb, iop->cmnd, 16);
3452 if (iop->max_sense_len){
3453 memset(pRequestSenseIO, 0, iop->max_sense_len);
3454 }
3455 if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_OUT){
3456 memcpy(pDataIO, iop->dxferp, iop->dxfer_len);
3457 }
3458 else if (pScsiIO->SrbFlags & SRB_FLAGS_DATA_IN){
3459 memset(pDataIO, 0, iop->dxfer_len);
3460 }
3461
3462 DWORD bytesReturned = 0;
3463 memset(pSrbIO, 0, sizeof(SRB_IO_CONTROL));
3464 pSrbIO->HeaderLength = sizeof(SRB_IO_CONTROL);
3465 memcpy(pSrbIO->Signature, "AACAPI", 7);
3466 pSrbIO->ControlCode = ARCIOCTL_SEND_RAW_SRB;
3467 pSrbIO->Length = (dataOffset + iop->dxfer_len - sizeof(SRB_IO_CONTROL) + 7) & 0xfffffff8;
3468 pSrbIO->Timeout = 3*60;
3469
3470 if (!DeviceIoControl(
3471 get_fh(),
3472 IOCTL_SCSI_MINIPORT,
3473 ioBuffer,
3474 sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
3475 ioBuffer,
3476 sizeof(SRB_IO_CONTROL) + pSrbIO->Length,
3477 &bytesReturned,
3478 NULL)
3479 ) {
3480 return set_err(EIO, "ARCIOCTL_SEND_RAW_SRB failed, Error=%u", (unsigned)GetLastError());
3481 }
3482
3483 iop->scsi_status = pScsiIO->ScsiStatus;
3485 int slen = sizeof(pRequestSenseIO) + 8;
3486 if (slen > (int)sizeof(pRequestSenseIO))
3487 slen = sizeof(pRequestSenseIO);
3488 if (slen > (int)iop->max_sense_len)
3489 slen = (int)iop->max_sense_len;
3490 memcpy(iop->sensep, pRequestSenseIO, slen);
3491 iop->resp_sense_len = slen;
3492 if (report) {
3493 if (report > 1) {
3494 pout(" >>> Sense buffer, len=%d:\n", slen);
3495 dStrHex(iop->sensep, slen , 1);
3496 }
3497 if ((iop->sensep[0] & 0x7f) > 0x71)
3498 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3499 iop->scsi_status, iop->sensep[1] & 0xf,
3500 iop->sensep[2], iop->sensep[3]);
3501 else
3502 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3503 iop->scsi_status, iop->sensep[2] & 0xf,
3504 iop->sensep[12], iop->sensep[13]);
3505 }
3506 }
3507 else {
3508 iop->resp_sense_len = 0;
3509 }
3510
3511 if (iop->dxfer_dir == DXFER_FROM_DEVICE){
3512 memcpy(iop->dxferp,pDataIO, iop->dxfer_len);
3513 }
3514 if((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)){
3515 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3516 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
3517 (trunc ? " [only first 256 bytes shown]" : ""));
3518 dStrHex((const uint8_t *)pDataIO, (trunc ? 256 : (int)(iop->dxfer_len)) , 1);
3519 }
3520 return true;
3521}
3522
3523
3524/////////////////////////////////////////////////////////////////////////////
3525// win_nvme_device
3526
3528: public /*implements*/ nvme_device,
3529 public /*extends*/ win_smart_device
3530{
3531public:
3532 win_nvme_device(smart_interface * intf, const char * dev_name,
3533 const char * req_type, unsigned nsid);
3534
3535 virtual bool open() override;
3536
3537 virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out) override;
3538
3539 bool open_scsi(int n);
3540
3541 bool probe();
3542
3543private:
3545};
3546
3547
3548/////////////////////////////////////////////////////////////////////////////
3549
3551 const char * req_type, unsigned nsid)
3552: smart_device(intf, dev_name, "nvme", req_type),
3554 m_scsi_no(-1)
3555{
3556}
3557
3559{
3560 // TODO: Use common open function for all devices using "\\.\ScsiN:"
3561 char devpath[32];
3562 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%d:", n);
3563
3564 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
3565 FILE_SHARE_READ|FILE_SHARE_WRITE,
3566 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
3567
3568 if (h == INVALID_HANDLE_VALUE) {
3569 long err = GetLastError();
3570 if (nvme_debugmode > 1)
3571 pout(" %s: Open failed, Error=%ld\n", devpath, err);
3572 if (err == ERROR_FILE_NOT_FOUND)
3573 set_err(ENOENT, "%s: not found", devpath);
3574 else if (err == ERROR_ACCESS_DENIED)
3575 set_err(EACCES, "%s: access denied", devpath);
3576 else
3577 set_err(EIO, "%s: Error=%ld", devpath, err);
3578 return false;
3579 }
3580
3581 if (nvme_debugmode > 1)
3582 pout(" %s: successfully opened\n", devpath);
3583
3584 set_fh(h);
3585 return true;
3586}
3587
3588// Check if NVMe DeviceIoControl(IOCTL_SCSI_MINIPORT) pass-through works.
3589// On Win10 and later that returns false with an errorNumber of 1
3590// ("Incorrect function"). Win10 has new pass-through:
3591// DeviceIoControl(IOCTL_STORAGE_PROTOCOL_COMMAND). However for commonly
3592// requested NVMe commands like Identify and Get Features Microsoft want
3593// "Protocol specific queries" sent.
3595{
3597 nvme_cmd_in in;
3598 in.set_data_in(smartmontools::nvme_admin_identify, &id_ctrl, sizeof(id_ctrl));
3599 // in.nsid = 0;
3600 in.cdw10 = 0x1;
3601 nvme_cmd_out out;
3602
3603 bool ok = nvme_pass_through(in, out);
3604 if (!ok && nvme_debugmode > 1)
3605 pout(" nvme probe failed: %s\n", get_errmsg());
3606 return ok;
3607}
3608
3610{
3611 if (m_scsi_no < 0) {
3612 // First open -> search of NVMe devices
3613 const char * name = skipdev(get_dev_name());
3614 char s[2+1] = ""; int n1 = -1, n2 = -1, len = strlen(name);
3615 unsigned no = ~0, nsid = 0xffffffff;
3616 sscanf(name, "nvm%2[es]%u%nn%u%n", s, &no, &n1, &nsid, &n2);
3617
3618 if (!( (n1 == len || (n2 == len && nsid > 0))
3619 && s[0] == 'e' && (!s[1] || s[1] == 's') ))
3620 return set_err(EINVAL);
3621
3622 if (!s[1]) {
3623 // /dev/nvmeN* -> search for nth NVMe device
3624 unsigned nvme_cnt = 0;
3625 for (int i = 0; i < 32; i++) {
3626 if (!open_scsi(i)) {
3627 if (get_errno() == EACCES)
3628 return false;
3629 continue;
3630 }
3631 // Done if pass-through works and correct number
3632 if (probe()) {
3633 if (nvme_cnt == no) {
3634 m_scsi_no = i;
3635 break;
3636 }
3637 nvme_cnt++;
3638 }
3639 close();
3640 }
3641
3642 if (!is_open())
3643 return set_err(ENOENT);
3644 clear_err();
3645 }
3646 else {
3647 // /dev/nvmesN* -> use "\\.\ScsiN:"
3648 if (!open_scsi(no))
3649 return false;
3650 m_scsi_no = no;
3651 }
3652
3653 if (!get_nsid())
3654 set_nsid(nsid);
3655 }
3656 else {
3657 // Reopen same "\\.\ScsiN:"
3658 if (!open_scsi(m_scsi_no))
3659 return false;
3660 }
3661
3662 return true;
3663}
3664
3666{
3667 // Create buffer with appropriate size
3668 raw_buffer pthru_raw_buf(offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer) + in.size);
3670 reinterpret_cast<NVME_PASS_THROUGH_IOCTL *>(pthru_raw_buf.data());
3671
3672 // Set NVMe command
3673 pthru->SrbIoCtrl.HeaderLength = sizeof(SRB_IO_CONTROL);
3674 memcpy(pthru->SrbIoCtrl.Signature, NVME_SIG_STR, sizeof(NVME_SIG_STR)-1);
3675 pthru->SrbIoCtrl.Timeout = 60;
3676 pthru->SrbIoCtrl.ControlCode = NVME_PASS_THROUGH_SRB_IO_CODE;
3677 pthru->SrbIoCtrl.ReturnCode = 0;
3678 pthru->SrbIoCtrl.Length = pthru_raw_buf.size() - sizeof(SRB_IO_CONTROL);
3679
3680 pthru->NVMeCmd[0] = in.opcode;
3681 pthru->NVMeCmd[1] = in.nsid;
3682 pthru->NVMeCmd[10] = in.cdw10;
3683 pthru->NVMeCmd[11] = in.cdw11;
3684 pthru->NVMeCmd[12] = in.cdw12;
3685 pthru->NVMeCmd[13] = in.cdw13;
3686 pthru->NVMeCmd[14] = in.cdw14;
3687 pthru->NVMeCmd[15] = in.cdw15;
3688
3689 pthru->Direction = in.direction();
3690 // pthru->QueueId = 0; // AdminQ
3691 // pthru->DataBufferLen = 0;
3692 if (in.direction() & nvme_cmd_in::data_out) {
3693 pthru->DataBufferLen = in.size;
3694 memcpy(pthru->DataBuffer, in.buffer, in.size);
3695 }
3696 // pthru->MetaDataLen = 0;
3697 pthru->ReturnBufferLen = pthru_raw_buf.size();
3698
3699 // Call NVME_PASS_THROUGH
3700 DWORD num_out = 0;
3701 BOOL ok = DeviceIoControl(get_fh(), IOCTL_SCSI_MINIPORT,
3702 pthru, pthru_raw_buf.size(), pthru, pthru_raw_buf.size(),
3703 &num_out, (OVERLAPPED*)0);
3704
3705 // Check status
3706 unsigned status = pthru->CplEntry[3] >> 17;
3707 if (status)
3708 return set_nvme_err(out, status);
3709
3710 if (!ok)
3711 return set_err(EIO, "NVME_PASS_THROUGH failed, Error=%u", (unsigned)GetLastError());
3712
3714 memcpy(in.buffer, pthru->DataBuffer, in.size);
3715
3716 out.result = pthru->CplEntry[0];
3717 return true;
3718}
3719
3720
3721/////////////////////////////////////////////////////////////////////////////
3722// win10_nvme_device
3723
3725: public /*implements*/ nvme_device,
3726 public /*extends*/ win_smart_device
3727{
3728public:
3729 win10_nvme_device(smart_interface * intf, const char * dev_name,
3730 const char * req_type, unsigned nsid);
3731
3732 virtual bool open() override;
3733
3734 virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & out) override;
3735
3736private:
3737 bool open(int phydrive, int logdrive);
3738};
3739
3740
3741/////////////////////////////////////////////////////////////////////////////
3742
3744 const char * req_type, unsigned nsid)
3745: smart_device(intf, dev_name, "nvme", req_type),
3747{
3748}
3749
3751{
3752 // TODO: Use common /dev/ parsing functions
3753 const char * name = skipdev(get_dev_name()); int len = strlen(name);
3754 // sd[a-z]([a-z])? => Physical drive 0-701
3755 char drive[2 + 1] = ""; int n = -1;
3756 if (sscanf(name, "sd%2[a-z]%n", drive, &n) == 1 && n == len)
3757 return open(sdxy_to_phydrive(drive), -1);
3758
3759 // pdN => Physical drive N
3760 int phydrive = -1; n = -1;
3761 if (sscanf(name, "pd%d%n", &phydrive, &n) == 1 && phydrive >= 0 && n == len)
3762 return open(phydrive, -1);
3763
3764 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3765 int logdrive = drive_letter(name);
3766 if (logdrive >= 0)
3767 return open(-1, logdrive);
3768
3769 return set_err(EINVAL);
3770}
3771
3772bool win10_nvme_device::open(int phydrive, int logdrive)
3773{
3774 // TODO: Use common open function for all devices using "\\.\PhysicalDriveN"
3775 char devpath[64];
3776 if (phydrive >= 0)
3777 snprintf(devpath, sizeof(devpath), "\\\\.\\PhysicalDrive%d", phydrive);
3778 else
3779 snprintf(devpath, sizeof(devpath), "\\\\.\\%c:", 'A'+logdrive);
3780
3781 // No GENERIC_READ/WRITE access required, this works without admin rights
3782 HANDLE h = CreateFileA(devpath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
3783 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, (HANDLE)0);
3784
3785 if (h == INVALID_HANDLE_VALUE) {
3786 long err = GetLastError();
3787 if (nvme_debugmode > 1)
3788 pout(" %s: Open failed, Error=%ld\n", devpath, err);
3789 if (err == ERROR_FILE_NOT_FOUND)
3790 set_err(ENOENT, "%s: not found", devpath);
3791 else if (err == ERROR_ACCESS_DENIED)
3792 set_err(EACCES, "%s: access denied", devpath);
3793 else
3794 set_err(EIO, "%s: Error=%ld", devpath, err);
3795 return false;
3796 }
3797
3798 if (nvme_debugmode > 1)
3799 pout(" %s: successfully opened\n", devpath);
3800
3801 set_fh(h);
3802
3803 // Use broadcast namespace if no NSID specified
3804 // TODO: Get NSID of current device
3805 if (!get_nsid())
3806 set_nsid(0xffffffff);
3807 return true;
3808}
3809
3811{
3812 struct { // STORAGE_PROPERTY_QUERY without AdditionalsParameters[1]
3813 STORAGE_PROPERTY_ID PropertyId;
3814 STORAGE_QUERY_TYPE QueryType;
3817 BYTE DataBuffer[1];
3818};
3819
3821{
3822 // Create buffer with appropriate size
3823 raw_buffer spsq_raw_buf(offsetof(STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER, DataBuffer) + in.size);
3825 reinterpret_cast<STORAGE_PROTOCOL_SPECIFIC_QUERY_WITH_BUFFER *>(spsq_raw_buf.data());
3826
3827 // Set NVMe specific STORAGE_PROPERTY_QUERY
3828 spsq->PropertyQuery.QueryType = PropertyStandardQuery;
3830
3831 switch (in.opcode) {
3833 if (!in.nsid) // Identify controller
3835 else
3840 break;
3844 spsq->ProtocolSpecific.ProtocolDataRequestValue = in.cdw10 & 0xff; // LID only ?
3845 // Older drivers (Win10 1607) ignore SubValue
3846 // Newer drivers (Win10 1809) pass SubValue to CDW12 (DW aligned)
3847 spsq->ProtocolSpecific.ProtocolDataRequestSubValue = 0; // in.cdw12 (LPOL, NVMe 1.2.1+) ?
3848 break;
3849 // TODO: nvme_admin_get_features
3850 default:
3851 return set_err(ENOSYS, "NVMe admin command 0x%02x not supported", in.opcode);
3852 }
3853
3854 if (in.cdw11 || in.cdw12 || in.cdw13 || in.cdw14 || in.cdw15)
3855 return set_err(ENOSYS, "Nonzero NVMe command dwords 11-15 not supported");
3856
3859
3861 memcpy(spsq->DataBuffer, in.buffer, in.size);
3862
3863 if (nvme_debugmode > 1)
3864 pout(" [STORAGE_QUERY_PROPERTY: Id=%u, Type=%u, Value=0x%08x, SubVal=0x%08x]\n",
3865 (unsigned)spsq->PropertyQuery.PropertyId,
3866 (unsigned)spsq->ProtocolSpecific.DataType,
3869
3870 // Call IOCTL_STORAGE_QUERY_PROPERTY
3871 DWORD num_out = 0;
3872 long err = 0;
3873 if (!DeviceIoControl(get_fh(), IOCTL_STORAGE_QUERY_PROPERTY,
3874 spsq, spsq_raw_buf.size(), spsq, spsq_raw_buf.size(),
3875 &num_out, (OVERLAPPED*)0)) {
3876 err = GetLastError();
3877 }
3878
3879 if (nvme_debugmode > 1)
3880 pout(" [STORAGE_QUERY_PROPERTY: ReturnData=0x%08x, Reserved[3]={0x%x, 0x%x, 0x%x}]\n",
3882 (unsigned)spsq->ProtocolSpecific.Reserved[0],
3883 (unsigned)spsq->ProtocolSpecific.Reserved[1],
3884 (unsigned)spsq->ProtocolSpecific.Reserved[2]);
3885
3886 // NVMe status is checked by IOCTL
3887 if (err)
3888 return set_err(EIO, "IOCTL_STORAGE_QUERY_PROPERTY(NVMe) failed, Error=%ld", err);
3889
3891 memcpy(in.buffer, spsq->DataBuffer, in.size);
3892
3893 out.result = spsq->ProtocolSpecific.FixedProtocolReturnData; // Completion DW0 ?
3894 return true;
3895}
3896
3897
3898/////////////////////////////////////////////////////////////////////////////
3899// win_smart_interface
3900// Platform specific interface
3901
3903: public /*implements*/ smart_interface
3904{
3905public:
3906 virtual std::string get_os_version_str() override;
3907
3908 virtual std::string get_app_examples(const char * appname) override;
3909
3910 virtual bool disable_system_auto_standby(bool disable) override;
3911
3912 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
3913 const char * pattern = 0) override;
3914
3915protected:
3916 virtual ata_device * get_ata_device(const char * name, const char * type) override;
3917
3918 virtual scsi_device * get_scsi_device(const char * name, const char * type) override;
3919
3920 virtual nvme_device * get_nvme_device(const char * name, const char * type, unsigned nsid) override;
3921
3922 virtual smart_device * autodetect_smart_device(const char * name) override;
3923
3924 virtual smart_device * get_custom_smart_device(const char * name, const char * type) override;
3925
3926 virtual std::string get_valid_custom_dev_types_str() override;
3927
3928private:
3929 smart_device * get_usb_device(const char * name, int phydrive, int logdrive = -1);
3930};
3931
3932
3933/////////////////////////////////////////////////////////////////////////////
3934
3935#ifndef _WIN64
3936// Running on 64-bit Windows as 32-bit app ?
3937static bool is_wow64()
3938{
3939 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
3940 (BOOL (WINAPI *)(HANDLE, PBOOL))(void *)
3941 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
3942 if (!IsWow64Process_p)
3943 return false;
3944 BOOL w64 = FALSE;
3945 if (!IsWow64Process_p(GetCurrentProcess(), &w64))
3946 return false;
3947 return !!w64;
3948}
3949#endif // _WIN64
3950
3951// Return info string about build host and OS version
3953{
3954 char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13]
3955 = SMARTMONTOOLS_BUILD_HOST;
3956 if (vstr[1] < '6')
3957 vstr[1] = '6';
3958 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1;
3959 const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
3960 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
3961
3962 // Starting with Windows 8.1, GetVersionEx() does no longer report the
3963 // actual OS version. RtlGetVersion() is not affected.
3964 LONG /*NTSTATUS*/ (WINAPI /*NTAPI*/ * RtlGetVersion_p)(LPOSVERSIONINFOEXW) =
3965 (LONG (WINAPI *)(LPOSVERSIONINFOEXW))(void *)
3966 GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
3967
3968 OSVERSIONINFOEXW vi; memset(&vi, 0, sizeof(vi));
3969 vi.dwOSVersionInfoSize = sizeof(vi);
3970 if (!RtlGetVersion_p || RtlGetVersion_p(&vi)) {
3971 if (!GetVersionExW((OSVERSIONINFOW *)&vi))
3972 return vstr;
3973 }
3974
3975 const char * w = 0;
3976 unsigned build = 0;
3977 if ( vi.dwPlatformId == VER_PLATFORM_WIN32_NT
3978 && vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
3979 switch ( (vi.dwMajorVersion << 4 | vi.dwMinorVersion) << 1
3980 | (vi.wProductType > VER_NT_WORKSTATION ? 1 : 0) ) {
3981 case 0x50<<1 :
3982 case 0x50<<1 | 1: w = "2000"; break;
3983 case 0x51<<1 : w = "xp"; break;
3984 case 0x52<<1 : w = "xp64"; break;
3985 case 0x52<<1 | 1: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
3986 ? "2003"
3987 : "2003r2"); break;
3988 case 0x60<<1 : w = "vista"; break;
3989 case 0x60<<1 | 1: w = "2008"; break;
3990 case 0x61<<1 : w = "win7"; break;
3991 case 0x61<<1 | 1: w = "2008r2"; break;
3992 case 0x62<<1 : w = "win8"; break;
3993 case 0x62<<1 | 1: w = "2012"; break;
3994 case 0x63<<1 : w = "win8.1"; break;
3995 case 0x63<<1 | 1: w = "2012r2"; break;
3996 case 0xa0<<1 :
3997 switch (vi.dwBuildNumber) {
3998 case 10240: w = "w10-1507"; break;
3999 case 10586: w = "w10-1511"; break;
4000 case 14393: w = "w10-1607"; break;
4001 case 15063: w = "w10-1703"; break;
4002 case 16299: w = "w10-1709"; break;
4003 case 17134: w = "w10-1803"; break;
4004 case 17763: w = "w10-1809"; break;
4005 case 18362: w = "w10-1903"; break;
4006 case 18363: w = "w10-1909"; break;
4007 case 19041: w = "w10-2004"; break;
4008 case 19042: w = "w10-20H2"; break;
4009 case 19043: w = "w10-21H1"; break;
4010 case 19044: w = "w10-21H2"; break;
4011 case 22000: w = "w11-21H2"; break;
4012 default: w = (vi.dwBuildNumber < 22000
4013 ? "w10"
4014 : "w11");
4015 build = vi.dwBuildNumber; break;
4016 } break;
4017 case 0xa0<<1 | 1:
4018 switch (vi.dwBuildNumber) {
4019 case 14393: w = "2016-1607"; break;
4020 case 16299: w = "2016-1709"; break;
4021 case 17134: w = "2016-1803"; break;
4022 case 17763: w = "2019-1809"; break;
4023 case 18362: w = "2019-1903"; break;
4024 case 18363: w = "2019-1909"; break;
4025 case 19041: w = "2019-2004"; break;
4026 case 19042: w = "2019-20H2"; break;
4027 case 20348: w = "2022-21H2"; break;
4028 default: w = (vi.dwBuildNumber < 17763
4029 ? "2016"
4030 : vi.dwBuildNumber < 20348
4031 ? "2019"
4032 : "2022");
4033 build = vi.dwBuildNumber; break;
4034 } break;
4035 }
4036 }
4037
4038 const char * w64 = "";
4039#ifndef _WIN64
4040 if (is_wow64())
4041 w64 = "(64)";
4042#endif
4043
4044 if (!w)
4045 snprintf(vptr, vlen, "-%s%u.%u%s",
4046 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"),
4047 (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
4048 else if (build)
4049 snprintf(vptr, vlen, "-%s-b%u%s", w, build, w64);
4050 else if (vi.wServicePackMinor)
4051 snprintf(vptr, vlen, "-%s-sp%u.%u%s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64);
4052 else if (vi.wServicePackMajor)
4053 snprintf(vptr, vlen, "-%s-sp%u%s", w, vi.wServicePackMajor, w64);
4054 else
4055 snprintf(vptr, vlen, "-%s%s", w, w64);
4056 return vstr;
4057}
4058
4059
4060ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
4061{
4062 const char * testname = skipdev(name);
4063 if (!strncmp(testname, "csmi", 4))
4064 return new win_csmi_device(this, name, type);
4065 if (!strncmp(testname, "tw_cli", 6))
4066 return new win_tw_cli_device(this, name, type);
4067 return new win_ata_device(this, name, type);
4068}
4069
4070scsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type)
4071{
4072 return new win_scsi_device(this, name, type);
4073}
4074
4075nvme_device * win_smart_interface::get_nvme_device(const char * name, const char * type,
4076 unsigned nsid)
4077{
4078 if (str_starts_with(skipdev(name), "nvme"))
4079 return new win_nvme_device(this, name, type, nsid);
4080 return new win10_nvme_device(this, name, type, nsid);
4081}
4082
4083
4084smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type)
4085{
4086 // Areca?
4087 int disknum = -1, n1 = -1, n2 = -1;
4088 int encnum = 1;
4089 char devpath[32];
4090
4091 if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
4092 if (!(1 <= disknum && disknum <= 128)) {
4093 set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
4094 return 0;
4095 }
4096 if (!(1 <= encnum && encnum <= 8)) {
4097 set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
4098 return 0;
4099 }
4100
4101 name = skipdev(name);
4102#define ARECA_MAX_CTLR_NUM 16
4103 n1 = -1;
4104 int ctlrindex = 0;
4105 if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
4106 /*
4107 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
4108 2. map arcmsrX into "\\\\.\\scsiX"
4109 */
4110 for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
4111 memset(devpath, 0, sizeof(devpath));
4112 snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx);
4113 win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum);
4114 if(arcdev->arcmsr_probe()) {
4115 if(ctlrindex-- == 0) {
4116 return arcdev;
4117 }
4118 }
4119 delete arcdev;
4120 }
4121 set_err(ENOENT, "No Areca controller found");
4122 }
4123 else
4124 set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
4125 return 0;
4126 }
4127
4128 // aacraid?
4129 unsigned ctrnum, lun, target;
4130 n1 = -1; n2 = -1;
4131
4132 if ( sscanf(type, "aacraid,%u,%u,%u%n,force%n", &ctrnum, &lun, &target, &n1, &n2) >= 3
4133 && (n1 == (int)strlen(type) || n2 == (int)strlen(type))) {
4134
4135 if (n2 < 0) {
4136 set_err(ENOSYS,
4137 "smartmontools AACRAID support is reportedly broken on Windows.\n"
4138 "See https://www.smartmontools.org/ticket/1515 for details.\n"
4139 "Use '-d aacraid,H,L,ID,force' to try anyway at your own risk.\n"
4140 "If you could provide help to fix the problem, please inform\n"
4141 PACKAGE_BUGREPORT "\n");
4142 return 0;
4143 }
4144
4145#define aacraid_MAX_CTLR_NUM 16
4146 if (ctrnum >= aacraid_MAX_CTLR_NUM) {
4147 set_err(EINVAL, "aacraid: invalid host number %u", ctrnum);
4148 return 0;
4149 }
4150
4151 /*
4152 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[AACRAID_MAX_CTLR_NUM]:" and
4153 2. map ARCX into "\\\\.\\scsiX"
4154 */
4155 memset(devpath, 0, sizeof(devpath));
4156 unsigned ctlrindex = 0;
4157 for (int portNum = 0; portNum < aacraid_MAX_CTLR_NUM; portNum++){
4158 char subKey[63];
4159 snprintf(subKey, sizeof(subKey), "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum);
4160 HKEY hScsiKey = 0;
4161 long regStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hScsiKey);
4162 if (regStatus == ERROR_SUCCESS){
4163 char driverName[20];
4164 DWORD driverNameSize = sizeof(driverName);
4165 DWORD regType = 0;
4166 regStatus = RegQueryValueExA(hScsiKey, "Driver", NULL, &regType, (LPBYTE) driverName, &driverNameSize);
4167 if (regStatus == ERROR_SUCCESS){
4168 if (regType == REG_SZ){
4169 if (stricmp(driverName, "arcsas") == 0){
4170 if(ctrnum == ctlrindex){
4171 snprintf(devpath, sizeof(devpath), "\\\\.\\Scsi%d:", portNum);
4172 return get_sat_device("sat,auto",
4173 new win_aacraid_device(this, devpath, ctrnum, target, lun));
4174 }
4175 ctlrindex++;
4176 }
4177 }
4178 }
4179 RegCloseKey(hScsiKey);
4180 }
4181 }
4182
4183 set_err(EINVAL, "aacraid: host %u not found", ctrnum);
4184 return 0;
4185 }
4186
4187 return 0;
4188}
4189
4191{
4192 return "aacraid,H,L,ID, areca,N[/E]";
4193}
4194
4195
4196// Return value for device detection functions
4198
4199// Return true if ATA drive behind a SAT layer
4201{
4202 if (!data->desc.VendorIdOffset)
4203 return false;
4204 if (strcmp(data->raw + data->desc.VendorIdOffset, "ATA "))
4205 return false;
4206 return true;
4207}
4208
4209// Return true if Intel ICHxR RAID volume
4211{
4212 if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset))
4213 return false;
4214 const char * vendor = data->raw + data->desc.VendorIdOffset;
4215 if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5)))
4216 return false;
4217 if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5))
4218 return false;
4219 return true;
4220}
4221
4222// get DEV_* for open handle
4223static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
4224{
4225 // Get BusType from device descriptor
4227 if (storage_query_property_ioctl(hdevice, &data))
4228 return DEV_UNKNOWN;
4229
4230 // Newer BusType* values are missing in older includes
4231 switch ((int)data.desc.BusType) {
4232 case BusTypeAta:
4233 case 0x0b: // BusTypeSata
4234 // Certain Intel AHCI drivers (C600+/C220+) have broken
4235 // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
4236 if (is_sat(&data))
4237 return DEV_SAT;
4238
4239 if (ata_version_ex)
4240 memset(ata_version_ex, 0, sizeof(*ata_version_ex));
4241 return DEV_ATA;
4242
4243 case BusTypeScsi:
4244 case BusTypeRAID:
4245 if (is_sat(&data))
4246 return DEV_SAT;
4247
4248 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
4250 return DEV_SCSI;
4251 // LSI/3ware RAID volume: supports SMART_*
4252 if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
4253 return DEV_ATA;
4254
4255 return DEV_SCSI;
4256
4257 case 0x09: // BusTypeiScsi
4258 case 0x0a: // BusTypeSas
4259 if (is_sat(&data))
4260 return DEV_SAT;
4261
4262 return DEV_SCSI;
4263
4264 case BusTypeUsb:
4265 return DEV_USB;
4266
4267 case 0x11: // BusTypeNvme
4268 return DEV_NVME;
4269
4270 case 0x12: //BusTypeSCM
4271 case 0x13: //BusTypeUfs
4272 case 0x14: //BusTypeMax,
4273 default:
4274 return DEV_UNKNOWN;
4275 }
4276 /*NOTREACHED*/
4277}
4278
4279// get DEV_* for device path
4280static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
4281{
4282 bool admin = true;
4283 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
4284 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4285 if (h == INVALID_HANDLE_VALUE) {
4286 admin = false;
4287 h = CreateFileA(path, 0,
4288 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
4289 if (h == INVALID_HANDLE_VALUE)
4290 return DEV_UNKNOWN;
4291 }
4292 if (ata_debugmode > 1 || scsi_debugmode > 1)
4293 pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
4294 win_dev_type type = get_controller_type(h, admin, ata_version_ex);
4295 CloseHandle(h);
4296 return type;
4297}
4298
4299// get DEV_* for physical drive number
4300static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
4301{
4302 char path[30];
4303 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
4304 return get_controller_type(path, ata_version_ex);
4305}
4306
4308{
4309 return get_phy_drive_type(drive, 0);
4310}
4311
4312// get DEV_* for logical drive number
4314{
4315 char path[30];
4316 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
4317 return get_controller_type(path);
4318}
4319
4320static win_dev_type get_dev_type(const char * name, int & phydrive, int & logdrive)
4321{
4322 phydrive = logdrive = -1;
4323
4324 name = skipdev(name);
4325 if (!strncmp(name, "st", 2))
4326 return DEV_SCSI;
4327 if (!strncmp(name, "nst", 3))
4328 return DEV_SCSI;
4329 if (!strncmp(name, "tape", 4))
4330 return DEV_SCSI;
4331
4332 logdrive = drive_letter(name);
4333 if (logdrive >= 0) {
4334 win_dev_type type = get_log_drive_type(logdrive);
4335 return (type != DEV_UNKNOWN ? type : DEV_SCSI);
4336 }
4337
4338 char drive[2+1] = "";
4339 if (sscanf(name, "sd%2[a-z]", drive) == 1) {
4340 phydrive = sdxy_to_phydrive(drive);
4341 return get_phy_drive_type(phydrive);
4342 }
4343
4344 if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
4345 return get_phy_drive_type(phydrive);
4346
4347 return DEV_UNKNOWN;
4348}
4349
4350
4352 int phydrive, int logdrive /* = -1 */)
4353{
4354 // Get USB bridge ID
4355 unsigned short vendor_id = 0, product_id = 0;
4356 if (!get_usb_id(phydrive, logdrive, vendor_id, product_id)) {
4357 set_err(EINVAL, "Unable to read USB device ID");
4358 return 0;
4359 }
4360
4361 // Get type name for this ID
4362 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
4363 if (!usbtype)
4364 return 0;
4365
4366 // Return SAT/USB device for this type
4367 return get_scsi_passthrough_device(usbtype, new win_scsi_device(this, name, ""));
4368}
4369
4371{
4372 const char * testname = skipdev(name);
4373 if (str_starts_with(testname, "hd"))
4374 return new win_ata_device(this, name, "");
4375
4376 if (str_starts_with(testname, "tw_cli"))
4377 return new win_tw_cli_device(this, name, "");
4378
4379 if (str_starts_with(testname, "csmi"))
4380 return new win_csmi_device(this, name, "");
4381
4382 if (str_starts_with(testname, "nvme"))
4383 return new win_nvme_device(this, name, "", 0 /* use default nsid */);
4384
4385 int phydrive = -1, logdrive = -1;
4386 win_dev_type type = get_dev_type(name, phydrive, logdrive);
4387
4388 if (type == DEV_ATA)
4389 return new win_ata_device(this, name, "");
4390
4391 if (type == DEV_SCSI)
4392 return new win_scsi_device(this, name, "");
4393
4394 if (type == DEV_SAT)
4395 return get_sat_device("sat", new win_scsi_device(this, name, ""));
4396
4397 if (type == DEV_USB)
4398 return get_usb_device(name, phydrive, logdrive);
4399
4400 if (type == DEV_NVME)
4401 return new win10_nvme_device(this, name, "", 0 /* use default nsid */);
4402
4403 return 0;
4404}
4405
4406
4407// Scan for devices
4409 const char * type, const char * pattern /* = 0*/)
4410{
4411 if (pattern) {
4412 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
4413 return false;
4414 }
4415
4416 // Check for "[*,]pd" type
4417 bool pd = false;
4418 char type2[16+1] = "";
4419 if (type) {
4420 int nc = -1;
4421 if (!strcmp(type, "pd")) {
4422 pd = true;
4423 type = 0;
4424 }
4425 else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 &&
4426 nc == (int)strlen(type)) {
4427 pd = true;
4428 type = type2;
4429 }
4430 }
4431
4432 // Set valid types
4433 bool ata, scsi, sat, usb, csmi, nvme;
4434 if (!type) {
4435 ata = scsi = usb = sat = csmi = true;
4436#ifdef WITH_NVME_DEVICESCAN // TODO: Remove when NVMe support is no longer EXPERIMENTAL
4437 nvme = true;
4438#else
4439 nvme = false;
4440#endif
4441 }
4442 else {
4443 ata = scsi = usb = sat = csmi = nvme = false;
4444 if (!strcmp(type, "ata"))
4445 ata = true;
4446 else if (!strcmp(type, "scsi"))
4447 scsi = true;
4448 else if (!strcmp(type, "sat"))
4449 sat = true;
4450 else if (!strcmp(type, "usb"))
4451 usb = true;
4452 else if (!strcmp(type, "csmi"))
4453 csmi = true;
4454 else if (!strcmp(type, "nvme"))
4455 nvme = true;
4456 else {
4457 set_err(EINVAL,
4458 "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], "
4459 "sat[,pd], usb[,pd], csmi, nvme, pd", type);
4460 return false;
4461 }
4462 }
4463
4464 char name[32];
4465
4466 if (ata || scsi || sat || usb || nvme) {
4467 // Scan up to 128 drives and 2 3ware controllers
4468 const int max_raid = 2;
4469 bool raid_seen[max_raid] = {false, false};
4470
4471 for (int i = 0; i < 128; i++) {
4472 if (pd)
4473 snprintf(name, sizeof(name), "/dev/pd%d", i);
4474 else if (i + 'a' <= 'z')
4475 snprintf(name, sizeof(name), "/dev/sd%c", i + 'a');
4476 else
4477 snprintf(name, sizeof(name), "/dev/sd%c%c",
4478 i / ('z'-'a'+1) - 1 + 'a',
4479 i % ('z'-'a'+1) + 'a');
4480
4481 smart_device * dev = 0;
4482 GETVERSIONINPARAMS_EX vers_ex;
4483
4484 switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
4485 case DEV_ATA:
4486 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
4487 if (!ata)
4488 continue;
4489
4490 // Interpret RAID drive map if present
4491 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
4492 // Skip if too many controllers or logical drive from this controller already seen
4493 if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
4494 continue;
4495 raid_seen[vers_ex.wControllerId] = true;
4496 // Add physical drives
4497 int len = strlen(name);
4498 for (unsigned int pi = 0; pi < 32; pi++) {
4499 if (vers_ex.dwDeviceMapEx & (1U << pi)) {
4500 snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
4501 devlist.push_back( new win_ata_device(this, name, "ata") );
4502 }
4503 }
4504 continue;
4505 }
4506
4507 dev = new win_ata_device(this, name, "ata");
4508 break;
4509
4510 case DEV_SCSI:
4511 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
4512 if (!scsi)
4513 continue;
4514 dev = new win_scsi_device(this, name, "scsi");
4515 break;
4516
4517 case DEV_SAT:
4518 // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
4519 if (!sat)
4520 continue;
4521 dev = get_sat_device("sat", new win_scsi_device(this, name, ""));
4522 break;
4523
4524 case DEV_USB:
4525 // STORAGE_QUERY_PROPERTY returned USB
4526 if (!usb)
4527 continue;
4528 dev = get_usb_device(name, i);
4529 if (!dev)
4530 // Unknown or unsupported USB ID, return as SCSI
4531 dev = new win_scsi_device(this, name, "");
4532 break;
4533
4534 case DEV_NVME:
4535 // STORAGE_QUERY_PROPERTY returned NVMe
4536 if (!nvme)
4537 continue;
4538 dev = new win10_nvme_device(this, name, "", 0 /* use default nsid */);
4539 break;
4540
4541 default:
4542 // Unknown type
4543 continue;
4544 }
4545
4546 devlist.push_back(dev);
4547 }
4548 }
4549
4550 if (csmi) {
4551 // Scan CSMI devices
4552 for (int i = 0; i <= 9; i++) {
4553 snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i);
4554 win_csmi_device test_dev(this, name, "");
4555 if (!test_dev.open_scsi())
4556 continue;
4557
4558 unsigned ports_used = test_dev.get_ports_used();
4559 if (!ports_used)
4560 continue;
4561
4562 for (int pi = 0; pi < 32; pi++) {
4563 if (!(ports_used & (1U << pi)))
4564 continue;
4565 snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
4566 devlist.push_back( new win_csmi_device(this, name, "ata") );
4567 }
4568 }
4569 }
4570
4571 if (nvme) {
4572 // Scan \\.\Scsi[0-31] for up to 10 NVMe devices
4573 int nvme_cnt = 0;
4574 for (int i = 0; i < 32; i++) {
4575 snprintf(name, sizeof(name)-1, "/dev/nvme%d", i);
4576 win_nvme_device test_dev(this, name, "", 0);
4577 if (!test_dev.open_scsi(i)) {
4578 if (test_dev.get_errno() == EACCES)
4579 break;
4580 continue;
4581 }
4582
4583 if (!test_dev.probe())
4584 continue;
4585 if (++nvme_cnt >= 10)
4586 break;
4587 }
4588
4589 for (int i = 0; i < nvme_cnt; i++) {
4590 snprintf(name, sizeof(name)-1, "/dev/nvme%d", i);
4591 devlist.push_back( new win_nvme_device(this, name, "nvme", 0) );
4592 }
4593 }
4594 return true;
4595}
4596
4597
4598// get examples for smartctl
4599std::string win_smart_interface::get_app_examples(const char * appname)
4600{
4601 if (strcmp(appname, "smartctl"))
4602 return "";
4603 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
4604 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
4605 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
4606 " (Enables SMART on first disk)\n\n"
4607 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
4608 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
4609 " (Prints Self-Test & Attribute errors)\n"
4610 " smartctl -a /dev/sda\n"
4611 " (Prints all information for disk on PhysicalDrive 0)\n"
4612 " smartctl -a /dev/pd3\n"
4613 " (Prints all information for disk on PhysicalDrive 3)\n"
4614 " smartctl -a /dev/tape1\n"
4615 " (Prints all information for SCSI tape on Tape 1)\n"
4616 " smartctl -A /dev/hdb,3\n"
4617 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
4618 " smartctl -A /dev/tw_cli/c0/p1\n"
4619 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
4620 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
4621 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
4622 " on 1st Areca RAID controller)\n"
4623 "\n"
4624 " ATA SMART access methods and ordering may be specified by modifiers\n"
4625 " following the device name: /dev/hdX:[saicm], where\n"
4626 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
4627 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
4628 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
4629 + strprintf(
4630 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
4631 );
4632}
4633
4634
4636{
4637 if (disable) {
4638 SYSTEM_POWER_STATUS ps;
4639 if (!GetSystemPowerStatus(&ps))
4640 return set_err(ENOSYS, "Unknown power status");
4641 if (ps.ACLineStatus != 1) {
4642 SetThreadExecutionState(ES_CONTINUOUS);
4643 if (ps.ACLineStatus == 0)
4644 set_err(EIO, "AC offline");
4645 else
4646 set_err(EIO, "Unknown AC line status");
4647 return false;
4648 }
4649 }
4650
4651 if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
4652 return set_err(ENOSYS);
4653 return true;
4654}
4655
4656
4657} // namespace
4658
4659/////////////////////////////////////////////////////////////////////////////
4660
4661// Initialize platform interface and register with smi()
4663{
4664 {
4665 // Remove "." from DLL search path if supported
4666 // to prevent DLL preloading attacks
4667 BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) =
4668 (BOOL (WINAPI *)(LPCSTR))(void *)
4669 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
4670 if (SetDllDirectoryA_p)
4671 SetDllDirectoryA_p("");
4672 }
4673
4674 static os_win32::win_smart_interface the_win_interface;
4675 smart_interface::set(&the_win_interface);
4676}
4677
4678
4679#ifndef __CYGWIN__
4680
4681// Get exe directory
4682// (prototype in utiliy.h)
4683std::string get_exe_dir()
4684{
4685 char path[MAX_PATH];
4686 // Get path of this exe
4687 if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path)))
4688 throw std::runtime_error("GetModuleFileName() failed");
4689 // Replace backslash by slash
4690 int sl = -1;
4691 for (int i = 0; path[i]; i++)
4692 if (path[i] == '\\') {
4693 path[i] = '/'; sl = i;
4694 }
4695 // Remove filename
4696 if (sl >= 0)
4697 path[sl] = 0;
4698 return path;
4699}
4700
4701#endif
#define SRB_DataIn
Definition: aacraid.h:43
#define SRB_DataOut
Definition: aacraid.h:44
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: aacraid.h:41
#define SRB_NoDataXfer
Definition: aacraid.h:45
unsigned char ata_debugmode
Definition: atacmds.cpp:33
#define ATA_SMART_AUTO_OFFLINE
Definition: atacmds.h:94
#define ATA_IDENTIFY_DEVICE
Definition: atacmds.h:53
#define ATA_SMART_WRITE_LOG_SECTOR
Definition: atacmds.h:87
#define ATA_IDENTIFY_PACKET_DEVICE
Definition: atacmds.h:54
#define ATA_SMART_STATUS
Definition: atacmds.h:91
#define ATA_SMART_READ_VALUES
Definition: atacmds.h:81
#define ATA_SMART_READ_THRESHOLDS
Definition: atacmds.h:82
#define ATA_SMART_READ_LOG_SECTOR
Definition: atacmds.h:86
#define ATA_SMART_CMD
Definition: atacmds.h:56
#define ATA_SMART_IMMEDIATE_OFFLINE
Definition: atacmds.h:85
smart_command_set
Definition: atacmds.h:29
@ IDENTIFY
Definition: atacmds.h:42
@ STATUS_CHECK
Definition: atacmds.h:37
@ ENABLE
Definition: atacmds.h:31
@ READ_VALUES
Definition: atacmds.h:39
@ STATUS
Definition: atacmds.h:36
#define ATA_SMART_ENABLE
Definition: atacmds.h:89
#define ATA_SMART_AUTOSAVE
Definition: atacmds.h:83
#define ATA_SMART_DISABLE
Definition: atacmds.h:90
#define ATA_CHECK_POWER_MODE
Definition: atacmds.h:52
Smart pointer class for device pointers.
device_type * release()
Return the pointer and release ownership.
Adapter class to implement new ATA pass through old interface.
ATA device access.
@ supports_output_regs
@ supports_multi_sector
bool ata_cmd_is_supported(const ata_cmd_in &in, unsigned flags, const char *type=0)
Check command input parameters.
virtual int arcmsr_get_dev_type()
Definition: dev_areca.cpp:342
void set_disknum(int disknum)
Definition: dev_areca.h:119
void set_encnum(int encnum)
Definition: dev_areca.h:122
virtual bool arcmsr_probe()
Definition: dev_areca.cpp:256
NVMe device access.
unsigned get_nsid() const
Get namespace id.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
void set_nsid(unsigned nsid)
Set namespace id.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
Definition: os_win32.cpp:2191
unsigned get_ports_used()
Get bitmask of used ports.
Definition: os_win32.cpp:2105
bool select_port(int port)
Select physical drive.
Definition: os_win32.cpp:2135
CSMI_SAS_PHY_ENTITY m_phy_ent
CSMI info for this phy.
Definition: os_win32.cpp:1913
signed char port_2_index_map[max_number_of_ports]
Definition: os_win32.cpp:1896
static bool guess_amd_drives(CSMI_SAS_PHY_INFO &phy_info, unsigned max_phy_drives)
Definition: os_win32.cpp:1921
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)=0
Call platform-specific CSMI ioctl.
const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
Get info for selected physical drive.
Definition: os_win32.cpp:1905
int get_phy_info(CSMI_SAS_PHY_INFO &phy_info, port_2_index_map &p2i)
Get phy info and port mapping, return #ports or -1 on error.
Definition: os_win32.cpp:1963
win10_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
Definition: os_win32.cpp:3743
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:3750
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
Definition: os_win32.cpp:3820
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:3370
virtual bool scsi_pass_through(struct scsi_cmnd_io *iop) override
SCSI pass through.
Definition: os_win32.cpp:3389
win_aacraid_device(smart_interface *intf, const char *dev_name, unsigned int ctrnum, unsigned int target, unsigned int lun)
Definition: os_win32.cpp:3357
virtual bool arcmsr_unlock() override
Definition: os_win32.cpp:3314
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:3224
virtual smart_device * autodetect_open() override
Open device with autodetection support.
Definition: os_win32.cpp:3248
win_areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3215
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
Definition: os_win32.cpp:3273
virtual bool arcmsr_lock() override
Definition: os_win32.cpp:3291
virtual smart_device * autodetect_open() override
Open device with autodetection support.
Definition: os_win32.cpp:3134
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:3110
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
Definition: os_win32.cpp:3139
virtual bool arcmsr_lock() override
Definition: os_win32.cpp:3157
virtual bool arcmsr_unlock() override
Definition: os_win32.cpp:3180
win_areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3101
virtual bool is_powered_down() override
Early test if device is powered up or down.
Definition: os_win32.cpp:1534
win_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:1349
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
Definition: os_win32.cpp:1551
virtual bool ata_identify_is_cached() const override
Return true if OS caches ATA identify sector.
Definition: os_win32.cpp:1873
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:1375
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:2387
win_csmi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2322
virtual bool is_open() const override
Return true if device is open.
Definition: os_win32.cpp:2335
virtual bool close() override
Close device, return false on error.
Definition: os_win32.cpp:2340
HANDLE m_fh
Controller device handle.
Definition: os_win32.cpp:2315
int m_port
Port number.
Definition: os_win32.cpp:2316
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz) override
Call platform-specific CSMI ioctl.
Definition: os_win32.cpp:2402
win_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
Definition: os_win32.cpp:3550
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:3609
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
Definition: os_win32.cpp:3665
win_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2696
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
Definition: os_win32.cpp:2822
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:2702
HANDLE m_fh
File handle.
Definition: os_win32.cpp:375
HANDLE get_fh() const
Return handle for derived classes.
Definition: os_win32.cpp:371
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:392
void set_fh(HANDLE fh)
Set handle for open() in derived classes.
Definition: os_win32.cpp:367
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:387
virtual std::string get_os_version_str() override
Return info string about build host and/or OS version.
Definition: os_win32.cpp:3952
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid) override
Return standard NVMe device.
Definition: os_win32.cpp:4075
virtual scsi_device * get_scsi_device(const char *name, const char *type) override
Return standard SCSI device.
Definition: os_win32.cpp:4070
virtual bool disable_system_auto_standby(bool disable) override
Disable/Enable system auto standby/sleep mode.
Definition: os_win32.cpp:4635
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0) override
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'.
Definition: os_win32.cpp:4408
virtual ata_device * get_ata_device(const char *name, const char *type) override
Return standard ATA device.
Definition: os_win32.cpp:4060
virtual std::string get_valid_custom_dev_types_str() override
Return valid 'type' args accepted by above.
Definition: os_win32.cpp:4190
virtual smart_device * get_custom_smart_device(const char *name, const char *type) override
Return device for platform specific 'type'.
Definition: os_win32.cpp:4084
virtual std::string get_app_examples(const char *appname) override
Return example string for program 'appname'.
Definition: os_win32.cpp:4599
virtual smart_device * autodetect_smart_device(const char *name) override
Autodetect device if no device type specified.
Definition: os_win32.cpp:4370
smart_device * get_usb_device(const char *name, int phydrive, int logdrive=-1)
Definition: os_win32.cpp:4351
virtual bool close() override
Close device, return false on error.
Definition: os_win32.cpp:2641
virtual bool open() override
Open device, return false on error.
Definition: os_win32.cpp:2533
virtual bool is_open() const override
Return true if device is open.
Definition: os_win32.cpp:2498
ata_identify_device m_ident_buf
Definition: os_win32.cpp:2482
win_tw_cli_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2489
virtual int ata_command_interface(smart_command_set command, int select, char *data)
Old ATA interface called by ata_pass_through()
Definition: os_win32.cpp:2648
ata_smart_values m_smart_buf
Definition: os_win32.cpp:2483
unsigned size() const
Definition: utility.h:144
unsigned char * data()
Definition: utility.h:147
Wrapper class for POSIX regex(3) or std::regex Supports copy & assignment and is compatible with STL ...
Definition: utility.h:221
regmatch_t match_range
Definition: utility.h:261
bool execute(const char *str, unsigned nmatch, match_range *pmatch) const
Return true if substring matches pattern, fill match_range array.
Definition: utility.cpp:585
SCSI device access.
List of devices for DEVICESCAN.
void push_back(smart_device *dev)
Base class for all devices.
Definition: dev_interface.h:33
int get_errno() const
Get last error number.
smart_interface * smi()
Get interface which produced this object.
const char * get_errmsg() const
Get last error message.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:86
device_info & set_info()
R/W access to device info struct.
const char * get_dev_name() const
Get device (path)name.
void clear_err()
Clear last error info.
The platform interface abstraction.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version=-1)
Get type name for USB device with known VENDOR:PRODUCT ID.
Definition: scsiata.cpp:1502
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
Definition: scsiata.cpp:1389
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:334
virtual smart_device * get_scsi_passthrough_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI of NVMe->SCSI filter for a SAT, SNT or USB 'type'.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define CSMI_SAS_LINK_RATE_NEGOTIATED
Definition: csmisas.h:804
#define CSMI_SAS_STP_PIO
Definition: csmisas.h:860
#define CSMI_SAS_END_DEVICE
Definition: csmisas.h:726
#define CSMI_SAS_TIMEOUT
Definition: csmisas.h:719
#define CSMI_RAID_SIGNATURE
Definition: csmisas.h:495
#define CSMI_SAS_STP_READ
Definition: csmisas.h:857
#define CSMI_SAS_NO_DEVICE_ATTACHED
Definition: csmisas.h:725
#define CSMI_SAS_STP_WRITE
Definition: csmisas.h:858
#define CSMI_SAS_STP_UNSPECIFIED
Definition: csmisas.h:859
#define CSMI_SAS_PROTOCOL_STP
Definition: csmisas.h:735
#define CSMI_SAS_PROTOCOL_SATA
Definition: csmisas.h:733
#define CSMI_SAS_SIGNATURE
Definition: csmisas.h:714
#define CSMI_ALL_SIGNATURE
Definition: csmisas.h:403
static bool match(const char *pattern, const char *str)
u8 cmd
Definition: megaraid.h:1
mega_passthru pthru
Definition: megaraid.h:14
u8 lun
Definition: megaraid.h:7
u32 w[3]
Definition: megaraid.h:19
u8 b[12]
Definition: megaraid.h:17
ptr_t buffer
Definition: megaraid.h:3
u16 s[6]
Definition: megaraid.h:18
ptr_t data
Definition: megaraid.h:15
u32 size
Definition: megaraid.h:0
static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX *ata_version_ex)
Definition: os_win32.cpp:4300
static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io *iop)
Areca RAID support.
Definition: os_win32.cpp:2951
static void print_ide_regs_io(const IDEREGS *ri, const IDEREGS *ro)
Definition: os_win32.cpp:414
static int get_clipboard(char *data, int datasize)
Definition: os_win32.cpp:2506
static int update_3ware_devicemap_ioctl(HANDLE hdevice)
Definition: os_win32.cpp:954
static win_dev_type get_log_drive_type(int drive)
Definition: os_win32.cpp:4313