smartmontools  SVN Rev 5304
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
34 extern 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 
75 const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 5239 2021-10-31 18:34:22Z chrfranke $";
76 
77 /////////////////////////////////////////////////////////////////////////////
78 // Windows I/O-controls, some declarations are missing in the include files
79 
80 extern "C" {
81 
82 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
83 
84 STATIC_ASSERT(SMART_GET_VERSION == 0x074080);
85 STATIC_ASSERT(SMART_SEND_DRIVE_COMMAND == 0x07c084);
86 STATIC_ASSERT(SMART_RCV_DRIVE_DATA == 0x07c088);
87 STATIC_ASSERT(sizeof(GETVERSIONINPARAMS) == 24);
88 STATIC_ASSERT(sizeof(SENDCMDINPARAMS) == 32+1);
89 STATIC_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 
103 typedef struct {
104  IDEREGS IdeReg;
106  UCHAR DataBuffer[1];
108 
109 #pragma pack()
110 
113 
114 
115 // ATA PASS THROUGH (Win2003, XP SP2)
116 
117 STATIC_ASSERT(IOCTL_ATA_PASS_THROUGH == 0x04d02c);
118 STATIC_ASSERT(sizeof(ATA_PASS_THROUGH_EX) == SELECT_WIN_32_64(40, 48));
119 
120 
121 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
122 
123 STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH == 0x04d004);
124 STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH_DIRECT == 0x04d014);
125 STATIC_ASSERT(sizeof(SCSI_PASS_THROUGH) == SELECT_WIN_32_64(44, 56));
126 STATIC_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 
153 STATIC_ASSERT(IOCTL_SCSI_MINIPORT == 0x04d008);
155 STATIC_ASSERT(sizeof(SRB_IO_CONTROL) == 28);
156 
157 
158 // IOCTL_STORAGE_QUERY_PROPERTY
159 
160 STATIC_ASSERT(IOCTL_STORAGE_QUERY_PROPERTY == 0x002d1400);
161 STATIC_ASSERT(sizeof(STORAGE_DEVICE_DESCRIPTOR) == 36+1+3);
162 STATIC_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) == 8+1+3);
163 
164 
165 // IOCTL_STORAGE_QUERY_PROPERTY: Windows 10 enhancements
166 
167 namespace 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 
173  typedef enum _STORAGE_PROTOCOL_TYPE {
180 
187 
190  ULONG DataType;
196  ULONG Reserved[3];
198 
200 
201 } // namespace win10
202 
203 
204 // IOCTL_STORAGE_PREDICT_FAILURE
205 
206 STATIC_ASSERT(IOCTL_STORAGE_PREDICT_FAILURE == 0x002d1100);
207 STATIC_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 
216 typedef struct _GETVERSIONINPARAMS_EX {
217  BYTE bVersion;
218  BYTE bRevision;
219  BYTE bReserved;
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 
228 typedef struct _SENDCMDINPARAMS_EX {
229  DWORD cBufferSize;
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 
240 STATIC_ASSERT(sizeof(GETVERSIONINPARAMS_EX) == sizeof(GETVERSIONINPARAMS));
241 STATIC_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;
258  ULONG VendorSpecific[6];
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
264  ULONG MetaDataLen;
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 
274 STATIC_ASSERT(sizeof(NVME_PASS_THROUGH_IOCTL) == offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer)+1);
275 
276 
277 // CSMI structs
278 
279 STATIC_ASSERT(sizeof(IOCTL_HEADER) == sizeof(SRB_IO_CONTROL));
283 
284 // aacraid struct
285 
286 STATIC_ASSERT(sizeof(SCSI_REQUEST_BLOCK) == SELECT_WIN_32_64(64, 88));
287 
288 } // extern "C"
289 
290 /////////////////////////////////////////////////////////////////////////////
291 
292 namespace os_win32 { // no need to publish anything, name provided for Doxygen
293 
294 #ifdef _MSC_VER
295 #pragma warning(disable:4250)
296 #endif
297 
298 static int is_permissive()
299 {
300  if (!failuretest_permissive) {
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
311 static 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:"
321 static 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
327 static 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 
335 static 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 {
353 public:
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 
365 protected:
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 
374 private:
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 
407 static 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 
414 static 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 
426 static 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 
461 static 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
485  inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
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 
564 static 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 
649 static 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 
761 static 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;
775  case ATA_SMART_DISABLE:
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;
779  case ATA_SMART_AUTOSAVE:
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 
891 static 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 
954 static 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 
1035 static 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
1108 static 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
1137 static 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 
1294 static 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 {
1320 public:
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 
1333 private:
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 
1349 win_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 
1367 static 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 
1381 bool 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 
1413 bool 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
1488  m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
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
1513  if (!update_3ware_devicemap_ioctl(h)) {
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
1564  && in.in_regs.command == ATA_SMART_CMD
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) {
1572  case ATA_IDENTIFY_DEVICE:
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 
1579  case ATA_CHECK_POWER_MODE:
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) {
1586  case ATA_SMART_READ_VALUES:
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) {
1685  case ata_cmd_in::no_data:
1686  break;
1687  case ata_cmd_in::data_in:
1688  datasize = (int)in.size;
1689  data = (char *)in.buffer;
1690  break;
1691  case ata_cmd_in::data_out:
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) {
1742  if (!failuretest_permissive) {
1743  m_smartver_state = 2;
1744  rc = -1; errno = ENOSYS;
1745  break;
1746  }
1748  }
1749  else {
1750  // 3ware RAID if vendor id present
1751  m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
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':
1775  if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
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) {
1783  case ATA_SMART_READ_VALUES:
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':
1815  assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0);
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 {
1885 public:
1886  enum { max_number_of_ports = 32 };
1887 
1888  /// Get bitmask of used ports
1889  unsigned get_ports_used();
1890 
1891 protected:
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 
1912 private:
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 
1921 bool 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 
1963 int 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) {
2123  case CSMI_SAS_PROTOCOL_STP:
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) {
2161  case CSMI_SAS_PROTOCOL_STP:
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 {
2180 public:
2181  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) override;
2182 
2183 protected:
2185  : smart_device(never_called) { }
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) {
2217  case ata_cmd_in::no_data:
2219  break;
2220  case ata_cmd_in::data_in:
2222  pthru.uDataLength = in.size;
2223  break;
2224  case ata_cmd_in::data_out:
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
2282  if (in.direction == ata_cmd_in::data_in)
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 {
2296 public:
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 
2310 protected:
2311  virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
2312  unsigned csmi_bufsiz) override;
2313 
2314 private:
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 
2402 bool 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 {
2468 public:
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 
2477 protected:
2478  virtual int ata_command_interface(smart_command_set command, int select, char * data);
2479 
2480 private:
2484 };
2485 
2486 
2487 /////////////////////////////////////////////////////////////////////////////
2488 
2489 win_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 
2506 static 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 
2526 static 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 {
2682 public:
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 
2689 private:
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 
2740 bool 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 
2768 typedef 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.
2777 static 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[0]);
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()
2951 static 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[0]);
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 {
3086 public:
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 
3094 private:
3095  HANDLE m_mutex;
3096 };
3097 
3098 
3099 /////////////////////////////////////////////////////////////////////////////
3100 
3101 win_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 {
3200 public:
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 
3208 private:
3209  HANDLE m_mutex;
3210 };
3211 
3212 
3213 /////////////////////////////////////////////////////////////////////////////
3214 
3215 win_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
3251  int is_ata = arcmsr_get_dev_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,
3332 public /*extends*/ win_smart_device
3333 {
3334 public:
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 
3343 private:
3344  //Device Host number
3346 
3347  //Channel(Lun) of the device
3348  int m_lun;
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[0]);
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 {
3531 public:
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 
3543 private:
3545 };
3546 
3547 
3548 /////////////////////////////////////////////////////////////////////////////
3549 
3551  const char * req_type, unsigned nsid)
3552 : smart_device(intf, dev_name, "nvme", req_type),
3553  nvme_device(nsid),
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 
3713  if (in.direction() & nvme_cmd_in::data_in)
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 {
3728 public:
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 
3736 private:
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),
3746  nvme_device(nsid)
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 
3772 bool 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 
3860  if (in.direction() & nvme_cmd_in::data_out)
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",
3881  (unsigned)spsq->ProtocolSpecific.FixedProtocolReturnData,
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 
3890  if (in.direction() & nvme_cmd_in::data_in)
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 {
3905 public:
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 
3915 protected:
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 
3928 private:
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 ?
3937 static 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 
4060 ata_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 
4070 scsi_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 
4075 nvme_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 
4084 smart_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
4223 static 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_*
4249  if (is_intel_raid_volume(&data))
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
4280 static 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
4300 static 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 
4320 static 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
4599 std::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()
4662 void smart_interface::init()
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)
4683 std::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:343
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:257
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.
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
const CSMI_SAS_PHY_ENTITY & get_phy_ent() const
Get info for selected physical drive.
Definition: os_win32.cpp:1905
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 char * data()
Definition: utility.h:147
unsigned size() const
Definition: utility.h:144
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:577
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.
const char * get_errmsg() const
Get last error message.
smart_interface * smi()
Get interface which produced this object.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
const char * get_dev_name() const
Get device (path)name.
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:86
void clear_err()
Clear last error info.
device_info & set_info()
R/W access to device info struct.
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:1514
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:1401
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 const char * findstr(const char *str, const char *sub)
Definition: os_win32.cpp:2526
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
static bool get_serial_from_wmi(int drive, ata_identify_device *id)
Definition: os_win32.cpp:1108
static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:4210
static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device *id)
Definition: os_win32.cpp:1065
static bool is_wow64()
Definition: os_win32.cpp:3937
static int get_device_power_state(HANDLE hdevice)
Definition: os_win32.cpp:1294
static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX *ata_version_ex)
Definition: os_win32.cpp:4223
static const char * ata_get_def_options()
Definition: os_win32.cpp:1367
static win_dev_type get_dev_type(const char *name, int &phydrive, int &logdrive)
Definition: os_win32.cpp:4320
static bool get_usb_id(int phydrive, int logdrive, unsigned short &vendor_id, unsigned short &product_id)
Definition: os_win32.cpp:1137
static void print_ide_regs(const IDEREGS *r, int out)
Definition: os_win32.cpp:407
static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, IDEREGS *prev_regs, char *data, int datasize)
Definition: os_win32.cpp:649
static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX *ata_version_ex=0)
Definition: os_win32.cpp:426
static int storage_predict_failure_ioctl(HANDLE hdevice, char *data=0)
Definition: os_win32.cpp:1035
static int is_permissive()
Definition: os_win32.cpp:298
static int drive_letter(const char *s)
Definition: os_win32.cpp:311
static int smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize, int port)
Definition: os_win32.cpp:461
static const char * skipdev(const char *s)
Definition: os_win32.cpp:321
static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize)
Definition: os_win32.cpp:761
static long scsi_pass_through_indirect(HANDLE h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *sbd)
Definition: os_win32.cpp:2777
static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:4200
static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize)
Definition: os_win32.cpp:564
static int sdxy_to_phydrive(const char(&xy)[2+1])
Definition: os_win32.cpp:327
static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize, int port)
Definition: os_win32.cpp:891
static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:997
static void copy_swapped(unsigned char *dest, const char *src, int destsize)
Definition: os_win32.cpp:335
Definition: scsiata.cpp:95
@ nvme_admin_identify
Definition: nvmecmds.h:208
@ nvme_admin_get_log_page
Definition: nvmecmds.h:205
_STORAGE_PROTOCOL_TYPE
Definition: os_win32.cpp:173
@ ProtocolTypeAta
Definition: os_win32.cpp:176
@ ProtocolTypeNvme
Definition: os_win32.cpp:177
@ ProtocolTypeScsi
Definition: os_win32.cpp:175
@ ProtocolTypeSd
Definition: os_win32.cpp:178
@ ProtocolTypeUnknown
Definition: os_win32.cpp:174
struct win10::_STORAGE_PROTOCOL_SPECIFIC_DATA STORAGE_PROTOCOL_SPECIFIC_DATA
enum win10::_STORAGE_PROTOCOL_TYPE STORAGE_PROTOCOL_TYPE
enum win10::_STORAGE_PROTOCOL_NVME_DATA_TYPE STORAGE_PROTOCOL_NVME_DATA_TYPE
const STORAGE_PROPERTY_ID StorageDeviceProtocolSpecificProperty
Definition: os_win32.cpp:171
STATIC_ASSERT(sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)==40)
const STORAGE_PROPERTY_ID StorageAdapterProtocolSpecificProperty
Definition: os_win32.cpp:170
_STORAGE_PROTOCOL_NVME_DATA_TYPE
Definition: os_win32.cpp:181
@ NVMeDataTypeFeature
Definition: os_win32.cpp:185
@ NVMeDataTypeUnknown
Definition: os_win32.cpp:182
@ NVMeDataTypeLogPage
Definition: os_win32.cpp:184
@ NVMeDataTypeIdentify
Definition: os_win32.cpp:183
uint8_t id
uint32_t nsid
unsigned char nvme_debugmode
Definition: nvmecmds.cpp:27
struct _NVME_PASS_THROUGH_IOCTL NVME_PASS_THROUGH_IOCTL
unsigned char failuretest_permissive
Definition: smartctl.cpp:1427
#define NVME_SIG_STR
Definition: os_win32.cpp:248
const char * os_win32_cpp_cvsid
Definition: os_win32.cpp:75
#define ARECA_MAX_CTLR_NUM
#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
Definition: os_win32.cpp:139
#define IOCTL_SCSI_MINIPORT_DISABLE_SMART
Definition: os_win32.cpp:142
std::string get_exe_dir()
Definition: os_win32.cpp:4683
struct _SENDCMDINPARAMS_EX SENDCMDINPARAMS_EX
STATIC_ASSERT(SMART_GET_VERSION==0x074080)
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
Definition: os_win32.cpp:144
#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
Definition: os_win32.cpp:149
#define SELECT_WIN_32_64(x32, x64)
Definition: os_win32.cpp:63
#define IOCTL_SCSI_MINIPORT_IDENTIFY
Definition: os_win32.cpp:138
#define aacraid_MAX_CTLR_NUM
#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
Definition: os_win32.cpp:146
#define SMART_VENDOR_3WARE
Definition: os_win32.cpp:212
#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
Definition: os_win32.cpp:140
#define IOCTL_SCSI_MINIPORT_ENABLE_SMART
Definition: os_win32.cpp:141
#define NVME_PASS_THROUGH_SRB_IO_CODE
Definition: os_win32.cpp:251
#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG
Definition: os_win32.cpp:148
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
Definition: os_win32.cpp:147
#define IOCTL_IDE_PASS_THROUGH
Definition: os_win32.cpp:96
#define IOCTL_SCSI_MINIPORT_RETURN_STATUS
Definition: os_win32.cpp:143
struct _GETVERSIONINPARAMS_EX GETVERSIONINPARAMS_EX
#define IOCTL_SCSI_MINIPORT_SMART_VERSION
Definition: os_win32.cpp:137
#define SYNCOBJNAME
#define assert(x)
Definition: os_win32.cpp:42
const char * scsi_get_opcode_name(uint8_t opcode)
Definition: scsicmds.cpp:233
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:78
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45
#define DXFER_NONE
Definition: scsicmds.h:96
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:97
#define DXFER_TO_DEVICE
Definition: scsicmds.h:98
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:298
void pout(const char *fmt,...)
Definition: smartd.cpp:1308
UCHAR DataBuffer[1]
Definition: os_win32.cpp:106
ULONG DataBufferSize
Definition: os_win32.cpp:105
CSMI_SAS_DRIVER_INFO Information
Definition: csmisas.h:1026
__u8 szDescription[81]
Definition: csmisas.h:1014
__u8 bTargetPortProtocol
Definition: csmisas.h:1520
__u8 bSASAddress[8]
Definition: csmisas.h:1522
CSMI_SAS_IDENTIFY Identify
Definition: csmisas.h:1530
CSMI_SAS_IDENTIFY Attached
Definition: csmisas.h:1539
IOCTL_HEADER IoctlHeader
Definition: csmisas.h:1551
CSMI_SAS_PHY_INFO Information
Definition: csmisas.h:1552
CSMI_SAS_PHY_ENTITY Phy[32]
Definition: csmisas.h:1546
CSMI_SAS_RAID_INFO Information
Definition: csmisas.h:1147
IOCTL_HEADER IoctlHeader
Definition: csmisas.h:1146
__u32 uMaxPhysicalDrives
Definition: csmisas.h:1136
__u32 uMaxDrivesPerSet
Definition: csmisas.h:1122
CSMI_SAS_STP_PASSTHRU Parameters
Definition: csmisas.h:1698
CSMI_SAS_STP_PASSTHRU_STATUS Status
Definition: csmisas.h:1699