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