smartmontools  SVN Rev 4078
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://smartmontools.sourceforge.net
5  *
6  * Copyright (C) 2004-15 Christian Franke <smartmontools-support@lists.sourceforge.net>
7  * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * You should have received a copy of the GNU General Public License
15  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #include "config.h"
20 #define WINVER 0x0502
21 #define _WIN32_WINNT WINVER
22 
23 #include "int64.h"
24 #include "atacmds.h"
25 #include "scsicmds.h"
26 #include "utility.h"
27 #include "smartctl.h" // TODO: Do not use smartctl only variables here
28 
29 #include "dev_interface.h"
30 #include "dev_ata_cmd_set.h"
31 #include "dev_areca.h"
32 
33 #include "os_win32/wmiquery.h"
34 
35 #include <errno.h>
36 
37 #ifdef _DEBUG
38 #include <assert.h>
39 #else
40 #undef assert
41 #define assert(x) /* */
42 #endif
43 
44 #include <stddef.h> // offsetof()
45 #include <io.h> // access()
46 
47 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
48 #define WIN32_LEAN_AND_MEAN
49 #include <windows.h>
50 
51 #if HAVE_NTDDDISK_H
52 // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32
53 // (Missing: FILE_DEVICE_SCSI)
54 #include <devioctl.h>
55 #include <ntdddisk.h>
56 #include <ntddscsi.h>
57 #include <ntddstor.h>
58 #elif HAVE_DDK_NTDDDISK_H
59 // older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
60 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
61 #include <ddk/ntdddisk.h>
62 #include <ddk/ntddscsi.h>
63 #include <ddk/ntddstor.h>
64 #else
65 // MSVC10, older MinGW
66 // (Missing: IOCTL_SCSI_MINIPORT_*)
67 #include <ntddscsi.h>
68 #include <winioctl.h>
69 #endif
70 
71 #ifndef _WIN32
72 // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
73 #define _WIN32
74 #endif
75 
76 // CSMI support
77 #include "csmisas.h"
78 
79 // Silence -Wunused-local-typedefs warning from g++ >= 4.8
80 #if __GNUC__ >= 4
81 #define ATTR_UNUSED __attribute__((unused))
82 #else
83 #define ATTR_UNUSED /**/
84 #endif
85 
86 // Macro to check constants at compile time using a dummy typedef
87 #define ASSERT_CONST(c, n) \
88  typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED
89 #define ASSERT_SIZEOF(t, n) \
90  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
91 
92 #ifndef _WIN64
93 #define SELECT_WIN_32_64(x32, x64) (x32)
94 #else
95 #define SELECT_WIN_32_64(x32, x64) (x64)
96 #endif
97 
98 // Cygwin does no longer provide strnicmp() compatibility macro
99 // MSVCRT does not provide strncasecmp()
100 #if defined(__CYGWIN__) && !defined(strnicmp)
101 #define strnicmp strncasecmp
102 #endif
103 
104 const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4058 2015-04-18 16:47:36Z chrfranke $";
105 
106 /////////////////////////////////////////////////////////////////////////////
107 // Windows I/O-controls, some declarations are missing in the include files
108 
109 extern "C" {
110 
111 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
112 
113 ASSERT_CONST(SMART_GET_VERSION, 0x074080);
114 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
115 ASSERT_CONST(SMART_RCV_DRIVE_DATA, 0x07c088);
116 ASSERT_SIZEOF(GETVERSIONINPARAMS, 24);
117 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
118 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
119 
120 
121 // IDE PASS THROUGH (2000, XP, undocumented)
122 
123 #ifndef IOCTL_IDE_PASS_THROUGH
124 
125 #define IOCTL_IDE_PASS_THROUGH \
126  CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
127 
128 #endif // IOCTL_IDE_PASS_THROUGH
129 
130 #pragma pack(1)
131 
132 typedef struct {
135  UCHAR DataBuffer[1];
137 
138 #pragma pack()
139 
142 
143 
144 // ATA PASS THROUGH (Win2003, XP SP2)
145 
146 #ifndef IOCTL_ATA_PASS_THROUGH
147 
148 #define IOCTL_ATA_PASS_THROUGH \
149  CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
150 
151 typedef struct _ATA_PASS_THROUGH_EX {
152  USHORT Length;
153  USHORT AtaFlags;
154  UCHAR PathId;
155  UCHAR TargetId;
156  UCHAR Lun;
161  ULONG_PTR DataBufferOffset;
163  UCHAR CurrentTaskFile[8];
165 
166 #define ATA_FLAGS_DRDY_REQUIRED 0x01
167 #define ATA_FLAGS_DATA_IN 0x02
168 #define ATA_FLAGS_DATA_OUT 0x04
169 #define ATA_FLAGS_48BIT_COMMAND 0x08
170 #define ATA_FLAGS_USE_DMA 0x10
171 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
172 
173 #endif // IOCTL_ATA_PASS_THROUGH
174 
177 
178 
179 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
180 
181 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
182 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT, 0x04d014);
183 ASSERT_SIZEOF(SCSI_PASS_THROUGH, SELECT_WIN_32_64(44, 56));
184 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56));
185 
186 
187 // SMART IOCTL via SCSI MINIPORT ioctl
188 
189 #ifndef FILE_DEVICE_SCSI
190 #define FILE_DEVICE_SCSI 0x001b
191 #endif
192 
193 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
194 
195 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
196 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
197 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
198 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
199 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
200 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
201 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
202 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
203 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
204 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
205 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
206 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
207 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
208 
209 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
210 
211 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
212 ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
213 
214 
215 // IOCTL_STORAGE_QUERY_PROPERTY
216 
217 #ifndef IOCTL_STORAGE_QUERY_PROPERTY
218 
219 #define IOCTL_STORAGE_QUERY_PROPERTY \
220  CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
221 
223  ULONG Version;
224  ULONG Size;
225  UCHAR DeviceType;
227  BOOLEAN RemovableMedia;
233  STORAGE_BUS_TYPE BusType;
237 
238 typedef enum _STORAGE_QUERY_TYPE {
244 
245 typedef enum _STORAGE_PROPERTY_ID {
254 
255 typedef struct _STORAGE_PROPERTY_QUERY {
260 
261 #endif // IOCTL_STORAGE_QUERY_PROPERTY
262 
266 
267 
268 // IOCTL_STORAGE_PREDICT_FAILURE
269 
270 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100);
271 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);
272 
273 
274 // 3ware specific versions of SMART ioctl structs
275 
276 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
277 
278 #pragma pack(1)
279 
280 typedef struct _GETVERSIONINPARAMS_EX {
281  BYTE bVersion;
282  BYTE bRevision;
283  BYTE bReserved;
286  DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map
287  WORD wIdentifier; // Vendor specific identifier
288  WORD wControllerId; // 3ware specific: Controller ID (0,1,...)
289  ULONG dwReserved[2];
291 
292 typedef struct _SENDCMDINPARAMS_EX {
293  DWORD cBufferSize;
296  BYTE bPortNumber; // 3ware specific: port number
297  WORD wIdentifier; // Vendor specific identifier
298  DWORD dwReserved[4];
299  BYTE bBuffer[1];
301 
302 #pragma pack()
303 
304 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS));
305 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
306 
307 
308 // CSMI structs
309 
310 ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL));
314 
315 } // extern "C"
316 
317 /////////////////////////////////////////////////////////////////////////////
318 
319 namespace os_win32 { // no need to publish anything, name provided for Doxygen
320 
321 #ifdef _MSC_VER
322 #pragma warning(disable:4250)
323 #endif
324 
326 : virtual public /*implements*/ smart_device
327 {
328 public:
331  m_fh(INVALID_HANDLE_VALUE)
332  { }
333 
334  virtual ~win_smart_device() throw();
335 
336  virtual bool is_open() const;
337 
338  virtual bool close();
339 
340 protected:
341  /// Set handle for open() in derived classes.
342  void set_fh(HANDLE fh)
343  { m_fh = fh; }
344 
345  /// Return handle for derived classes.
346  HANDLE get_fh() const
347  { return m_fh; }
348 
349 private:
350  HANDLE m_fh; ///< File handle
351 };
352 
353 
354 /////////////////////////////////////////////////////////////////////////////
355 
357 : public /*implements*/ ata_device,
358  public /*extends*/ win_smart_device
359 {
360 public:
361  win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
362 
363  virtual ~win_ata_device() throw();
364 
365  virtual bool open();
366 
367  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
368 
369  virtual bool ata_identify_is_cached() const;
370 
371 private:
372  bool open(int phydrive, int logdrive, const char * options, int port);
373 
374  std::string m_options;
375  bool m_usr_options; // options set by user?
376  bool m_admin; // open with admin access?
377  int m_phydrive; // PhysicalDriveN or -1
378  bool m_id_is_cached; // ata_identify_is_cached() return value.
379  bool m_is_3ware; // LSI/3ware controller detected?
380  int m_port; // LSI/3ware port
382 };
383 
384 
385 /////////////////////////////////////////////////////////////////////////////
386 
388 : public /*implements*/ scsi_device,
389  virtual public /*extends*/ win_smart_device
390 {
391 public:
392  win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
393 
394  virtual bool open();
395 
396  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
397 
398 private:
399  bool open(int pd_num, int ld_num, int tape_num, int sub_addr);
400 };
401 
402 
403 /////////////////////////////////////////////////////////////////////////////
404 
406 : virtual public /*extends*/ smart_device
407 {
408 public:
409  /// Get bitmask of used ports
410  unsigned get_ports_used();
411 
412 protected:
415  { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); }
416 
417  /// Get phy info
418  bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info);
419 
420  /// Select physical drive
421  bool select_port(int port);
422 
423  /// Get info for selected physical drive
425  { return m_phy_ent; }
426 
427  /// Call platform-specific CSMI ioctl
428  virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
429  unsigned csmi_bufsiz) = 0;
430 
431 private:
432  CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy
433 };
434 
435 
437 : virtual public /*extends*/ csmi_device,
438  virtual public /*implements*/ ata_device
439 {
440 public:
441  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
442 
443 protected:
446 };
447 
448 
449 //////////////////////////////////////////////////////////////////////
450 
452 : public /*implements*/ csmi_ata_device
453 {
454 public:
455  win_csmi_device(smart_interface * intf, const char * dev_name,
456  const char * req_type);
457 
458  virtual ~win_csmi_device() throw();
459 
460  virtual bool open();
461 
462  virtual bool close();
463 
464  virtual bool is_open() const;
465 
466  bool open_scsi();
467 
468 protected:
469  virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
470  unsigned csmi_bufsiz);
471 
472 private:
473  HANDLE m_fh; ///< Controller device handle
474  int m_port; ///< Port number
475 };
476 
477 
478 //////////////////////////////////////////////////////////////////////
479 
481 : public /*implements*/ ata_device_with_command_set
482 {
483 public:
484  win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type);
485 
486  virtual bool is_open() const;
487 
488  virtual bool open();
489 
490  virtual bool close();
491 
492 protected:
493  virtual int ata_command_interface(smart_command_set command, int select, char * data);
494 
495 private:
499 };
500 
501 
502 /////////////////////////////////////////////////////////////////////////////
503 /// Areca RAID support
504 
505 ///////////////////////////////////////////////////////////////////
506 // SATA(ATA) device behind Areca RAID Controller
508 : public /*implements*/ areca_ata_device,
509  public /*extends*/ win_smart_device
510 {
511 public:
512  win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
513  virtual bool open();
514  virtual smart_device * autodetect_open();
515  virtual bool arcmsr_lock();
516  virtual bool arcmsr_unlock();
517  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
518 
519 private:
520  HANDLE m_mutex;
521 };
522 
523 ///////////////////////////////////////////////////////////////////
524 // SAS(SCSI) device behind Areca RAID Controller
526 : public /*implements*/ areca_scsi_device,
527  public /*extends*/ win_smart_device
528 {
529 public:
530  win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
531  virtual bool open();
532  virtual smart_device * autodetect_open();
533  virtual bool arcmsr_lock();
534  virtual bool arcmsr_unlock();
535  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
536 
537 private:
538  HANDLE m_mutex;
539 };
540 
541 
542 //////////////////////////////////////////////////////////////////////
543 // Platform specific interface
544 
546 : public /*implements part of*/ smart_interface
547 {
548 public:
549  virtual std::string get_os_version_str();
550 
551  virtual std::string get_app_examples(const char * appname);
552 
553 #ifndef __CYGWIN__
554  virtual int64_t get_timer_usec();
555 #endif
556 
557  virtual bool disable_system_auto_standby(bool disable);
558 
559  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
560  const char * pattern = 0);
561 
562 protected:
563  virtual ata_device * get_ata_device(const char * name, const char * type);
564 
565  virtual scsi_device * get_scsi_device(const char * name, const char * type);
566 
567  virtual smart_device * autodetect_smart_device(const char * name);
568 
569  virtual smart_device * get_custom_smart_device(const char * name, const char * type);
570 
571  virtual std::string get_valid_custom_dev_types_str();
572 };
573 
574 
575 //////////////////////////////////////////////////////////////////////
576 
577 #ifndef _WIN64
578 // Running on 64-bit Windows as 32-bit app ?
579 static bool is_wow64()
580 {
581  BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) =
582  (BOOL (WINAPI *)(HANDLE, PBOOL))
583  GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
584  if (!IsWow64Process_p)
585  return false;
586  BOOL w64 = FALSE;
587  if (!IsWow64Process_p(GetCurrentProcess(), &w64))
588  return false;
589  return !!w64;
590 }
591 #endif // _WIN64
592 
593 // Return info string about build host and OS version
595 {
596  char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13]
597  = SMARTMONTOOLS_BUILD_HOST;
598  if (vstr[1] < '6')
599  vstr[1] = '6';
600  char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1;
601  const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
602  assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
603 
604  OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
605  vi.dwOSVersionInfoSize = sizeof(vi);
606  if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
607  memset(&vi, 0, sizeof(vi));
608  vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
609  if (!GetVersionExA((OSVERSIONINFOA *)&vi))
610  return vstr;
611  }
612 
613  const char * w = 0;
614  if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
615 
616  if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
617  // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
618  // actual OS version, see:
619  // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
620 
621  ULONGLONG major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
622  for (unsigned major = vi.dwMajorVersion; major <= 9; major++) {
623  OSVERSIONINFOEXA vi2; memset(&vi2, 0, sizeof(vi2));
624  vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
625  if (!VerifyVersionInfo(&vi2, VER_MAJORVERSION, major_equal))
626  continue;
627  if (vi.dwMajorVersion < major) {
628  vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
629  }
630 
631  ULONGLONG minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
632  for (unsigned minor = vi.dwMinorVersion; minor <= 9; minor++) {
633  memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
634  vi2.dwMinorVersion = minor;
635  if (!VerifyVersionInfo(&vi2, VER_MINORVERSION, minor_equal))
636  continue;
637  vi.dwMinorVersion = minor;
638  break;
639  }
640 
641  break;
642  }
643  }
644 
645  if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
646  bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
647  switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
648  case 0x50: w = "2000"; break;
649  case 0x51: w = "xp"; break;
650  case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
651  ? "2003" : "2003r2"); break;
652  case 0x60: w = (ws ? "vista" : "2008" ); break;
653  case 0x61: w = (ws ? "win7" : "2008r2"); break;
654  case 0x62: w = (ws ? "win8" : "2012" ); break;
655  case 0x63: w = (ws ? "win8.1": "2012r2"); break;
656  case 0x64: w = (ws ? "win10" : "w10srv"); break;
657  }
658  }
659  }
660 
661  const char * w64 = "";
662 #ifndef _WIN64
663  if (is_wow64())
664  w64 = "(64)";
665 #endif
666 
667  if (!w)
668  snprintf(vptr, vlen, "-%s%u.%u%s",
669  (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"),
670  (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
671  else if (vi.wServicePackMinor)
672  snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
673  else if (vi.wServicePackMajor)
674  snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor);
675  else
676  snprintf(vptr, vlen, "-%s%s", w, w64);
677  return vstr;
678 }
679 
680 #ifndef __CYGWIN__
681 // MSVCRT only provides ftime() which uses GetSystemTime()
682 // This provides only ~15ms resolution by default.
683 // Use QueryPerformanceCounter instead (~300ns).
684 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
686 {
687  static int64_t freq = 0;
688 
689  LARGE_INTEGER t;
690  if (freq == 0)
691  freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1);
692  if (freq <= 0)
694 
695  if (!QueryPerformanceCounter(&t))
696  return -1;
697  if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000))
698  return -1;
699 
700  return (t.QuadPart * 1000000LL) / freq;
701 }
702 #endif // __CYGWIN__
703 
704 
705 // Return value for device detection functions
707 
708 static win_dev_type get_phy_drive_type(int drive);
709 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex);
710 static win_dev_type get_log_drive_type(int drive);
711 static bool get_usb_id(int drive, unsigned short & vendor_id,
712  unsigned short & product_id);
713 
714 static const char * ata_get_def_options(void);
715 
716 
717 static int is_permissive()
718 {
719  if (!failuretest_permissive) {
720  pout("To continue, add one or more '-T permissive' options.\n");
721  return 0;
722  }
724  return 1;
725 }
726 
727 // return number for drive letter, -1 on error
728 // "[A-Za-z]:([/\\][.]?)?" => 0-25
729 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
730 static int drive_letter(const char * s)
731 {
732  return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z'))
733  && s[1] == ':'
734  && (!s[2] || ( strchr("/\\\"", s[2])
735  && (!s[3] || (s[3] == '.' && !s[4]))) ) ?
736  (s[0] & 0x1f) - 1 : -1);
737 }
738 
739 // Skip trailing "/dev/", do not allow "/dev/X:"
740 static const char * skipdev(const char * s)
741 {
742  return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);
743 }
744 
745 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type)
746 {
747  const char * testname = skipdev(name);
748  if (!strncmp(testname, "csmi", 4))
749  return new win_csmi_device(this, name, type);
750  if (!strncmp(testname, "tw_cli", 6))
751  return new win_tw_cli_device(this, name, type);
752  return new win_ata_device(this, name, type);
753 }
754 
755 scsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type)
756 {
757  return new win_scsi_device(this, name, type);
758 }
759 
760 static int sdxy_to_phydrive(const char (& xy)[2+1])
761 {
762  int phydrive = xy[0] - 'a';
763  if (xy[1])
764  phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a');
765  return phydrive;
766 }
767 
768 static win_dev_type get_dev_type(const char * name, int & phydrive)
769 {
770  phydrive = -1;
771  name = skipdev(name);
772  if (!strncmp(name, "st", 2))
773  return DEV_SCSI;
774  if (!strncmp(name, "nst", 3))
775  return DEV_SCSI;
776  if (!strncmp(name, "tape", 4))
777  return DEV_SCSI;
778 
779  int logdrive = drive_letter(name);
780  if (logdrive >= 0) {
781  win_dev_type type = get_log_drive_type(logdrive);
782  return (type != DEV_UNKNOWN ? type : DEV_SCSI);
783  }
784 
785  char drive[2+1] = "";
786  if (sscanf(name, "sd%2[a-z]", drive) == 1) {
787  phydrive = sdxy_to_phydrive(drive);
788  return get_phy_drive_type(phydrive);
789  }
790 
791  phydrive = -1;
792  if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
793  return get_phy_drive_type(phydrive);
794  return DEV_UNKNOWN;
795 }
796 
797 smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type)
798 {
799  // Areca?
800  int disknum = -1, n1 = -1, n2 = -1;
801  int encnum = 1;
802  char devpath[32];
803 
804  if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
805  if (!(1 <= disknum && disknum <= 128)) {
806  set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
807  return 0;
808  }
809  if (!(1 <= encnum && encnum <= 8)) {
810  set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
811  return 0;
812  }
813 
814  name = skipdev(name);
815 #define ARECA_MAX_CTLR_NUM 16
816  n1 = -1;
817  int ctlrindex = 0;
818  if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
819  /*
820  1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
821  2. map arcmsrX into "\\\\.\\scsiX"
822  */
823  for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
824  memset(devpath, 0, sizeof(devpath));
825  snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx);
826  win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum);
827  if(arcdev->arcmsr_probe()) {
828  if(ctlrindex-- == 0) {
829  return arcdev;
830  }
831  }
832  delete arcdev;
833  }
834  set_err(ENOENT, "No Areca controller found");
835  }
836  else
837  set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
838  }
839 
840  return 0;
841 }
842 
844 {
845  return "areca,N[/E]";
846 }
847 
848 
850 {
851  const char * testname = skipdev(name);
852  if (str_starts_with(testname, "hd"))
853  return new win_ata_device(this, name, "");
854 
855  if (str_starts_with(testname, "tw_cli"))
856  return new win_tw_cli_device(this, name, "");
857 
858  if (str_starts_with(testname, "csmi"))
859  return new win_csmi_device(this, name, "");
860 
861  int phydrive = -1;
862  win_dev_type type = get_dev_type(name, phydrive);
863 
864  if (type == DEV_ATA)
865  return new win_ata_device(this, name, "");
866 
867  if (type == DEV_SCSI)
868  return new win_scsi_device(this, name, "");
869 
870  if (type == DEV_SAT)
871  return get_sat_device("sat", new win_scsi_device(this, name, ""));
872 
873  if (type == DEV_USB) {
874  // Get USB bridge ID
875  unsigned short vendor_id = 0, product_id = 0;
876  if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) {
877  set_err(EINVAL, "Unable to read USB device ID");
878  return 0;
879  }
880  // Get type name for this ID
881  const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
882  if (!usbtype)
883  return 0;
884  // Return SAT/USB device for this type
885  return get_sat_device(usbtype, new win_scsi_device(this, name, ""));
886  }
887 
888  return 0;
889 }
890 
891 
892 // Scan for devices
893 
895  const char * type, const char * pattern /* = 0*/)
896 {
897  if (pattern) {
898  set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
899  return false;
900  }
901 
902  // Check for "[*,]pd" type
903  bool pd = false;
904  char type2[16+1] = "";
905  if (type) {
906  int nc = -1;
907  if (!strcmp(type, "pd")) {
908  pd = true;
909  type = 0;
910  }
911  else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 &&
912  nc == (int)strlen(type)) {
913  pd = true;
914  type = type2;
915  }
916  }
917 
918  // Set valid types
919  bool ata, scsi, sat, usb, csmi;
920  if (!type) {
921  ata = scsi = usb = sat = csmi = true;
922  }
923  else {
924  ata = scsi = usb = sat = csmi = false;
925  if (!strcmp(type, "ata"))
926  ata = true;
927  else if (!strcmp(type, "scsi"))
928  scsi = true;
929  else if (!strcmp(type, "sat"))
930  sat = true;
931  else if (!strcmp(type, "usb"))
932  usb = true;
933  else if (!strcmp(type, "csmi"))
934  csmi = true;
935  else {
936  set_err(EINVAL,
937  "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], sat[,pd], usb[,pd], csmi, pd",
938  type);
939  return false;
940  }
941  }
942 
943  char name[20];
944 
945  if (ata || scsi || sat || usb) {
946  // Scan up to 128 drives and 2 3ware controllers
947  const int max_raid = 2;
948  bool raid_seen[max_raid] = {false, false};
949 
950  for (int i = 0; i < 128; i++) {
951  if (pd)
952  snprintf(name, sizeof(name), "/dev/pd%d", i);
953  else if (i + 'a' <= 'z')
954  snprintf(name, sizeof(name), "/dev/sd%c", i + 'a');
955  else
956  snprintf(name, sizeof(name), "/dev/sd%c%c",
957  i / ('z'-'a'+1) - 1 + 'a',
958  i % ('z'-'a'+1) + 'a');
959 
960  GETVERSIONINPARAMS_EX vers_ex;
961 
962  switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
963  case DEV_ATA:
964  // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
965  if (!ata)
966  continue;
967 
968  // Interpret RAID drive map if present
969  if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
970  // Skip if too many controllers or logical drive from this controller already seen
971  if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
972  continue;
973  raid_seen[vers_ex.wControllerId] = true;
974  // Add physical drives
975  int len = strlen(name);
976  for (int pi = 0; pi < 32; pi++) {
977  if (vers_ex.dwDeviceMapEx & (1L << pi)) {
978  snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
979  devlist.push_back( new win_ata_device(this, name, "ata") );
980  }
981  }
982  }
983  else {
984  devlist.push_back( new win_ata_device(this, name, "ata") );
985  }
986  break;
987 
988  case DEV_SCSI:
989  // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
990  if (!scsi)
991  continue;
992  devlist.push_back( new win_scsi_device(this, name, "scsi") );
993  break;
994 
995  case DEV_SAT:
996  // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
997  if (!sat)
998  continue;
999  devlist.push_back( get_sat_device("sat", new win_scsi_device(this, name, "")) );
1000  break;
1001 
1002  case DEV_USB:
1003  // STORAGE_QUERY_PROPERTY returned USB
1004  if (!usb)
1005  continue;
1006  {
1007  // TODO: Use common function for this and autodetect_smart_device()
1008  // Get USB bridge ID
1009  unsigned short vendor_id = 0, product_id = 0;
1010  if (!get_usb_id(i, vendor_id, product_id))
1011  continue;
1012  // Get type name for this ID
1013  const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
1014  if (!usbtype)
1015  continue;
1016  // Return SAT/USB device for this type
1017  ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
1018  if (!dev)
1019  continue;
1020  devlist.push_back(dev);
1021  }
1022  break;
1023 
1024  default:
1025  // Unknown type
1026  break;
1027  }
1028  }
1029  }
1030 
1031  if (csmi) {
1032  // Scan CSMI devices
1033  for (int i = 0; i <= 9; i++) {
1034  snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i);
1035  win_csmi_device test_dev(this, name, "");
1036  if (!test_dev.open_scsi())
1037  continue;
1038 
1039  unsigned ports_used = test_dev.get_ports_used();
1040  if (!ports_used)
1041  continue;
1042 
1043  for (int pi = 0; pi < 32; pi++) {
1044  if (!(ports_used & (1 << pi)))
1045  continue;
1046  snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi);
1047  devlist.push_back( new win_csmi_device(this, name, "ata") );
1048  }
1049  }
1050  }
1051  return true;
1052 }
1053 
1054 
1055 // get examples for smartctl
1056 std::string win_smart_interface::get_app_examples(const char * appname)
1057 {
1058  if (strcmp(appname, "smartctl"))
1059  return "";
1060  return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1061  " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1062  " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1063  " (Enables SMART on first disk)\n\n"
1064  " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1065  " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1066  " (Prints Self-Test & Attribute errors)\n"
1067  " smartctl -a /dev/sda\n"
1068  " (Prints all information for disk on PhysicalDrive 0)\n"
1069  " smartctl -a /dev/pd3\n"
1070  " (Prints all information for disk on PhysicalDrive 3)\n"
1071  " smartctl -a /dev/tape1\n"
1072  " (Prints all information for SCSI tape on Tape 1)\n"
1073  " smartctl -A /dev/hdb,3\n"
1074  " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1075  " smartctl -A /dev/tw_cli/c0/p1\n"
1076  " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1077  " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1078  " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1079  " on 1st Areca RAID controller)\n"
1080  "\n"
1081  " ATA SMART access methods and ordering may be specified by modifiers\n"
1082  " following the device name: /dev/hdX:[saicm], where\n"
1083  " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1084  " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1085  " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1086  + strprintf(
1087  " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1088  );
1089 }
1090 
1091 
1093 {
1094  if (disable) {
1095  SYSTEM_POWER_STATUS ps;
1096  if (!GetSystemPowerStatus(&ps))
1097  return set_err(ENOSYS, "Unknown power status");
1098  if (ps.ACLineStatus != 1) {
1099  SetThreadExecutionState(ES_CONTINUOUS);
1100  if (ps.ACLineStatus == 0)
1101  set_err(EIO, "AC offline");
1102  else
1103  set_err(EIO, "Unknown AC line status");
1104  return false;
1105  }
1106  }
1107 
1108  if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
1109  return set_err(ENOSYS);
1110  return true;
1111 }
1112 
1113 
1114 /////////////////////////////////////////////////////////////////////////////
1115 // ATA Interface
1116 /////////////////////////////////////////////////////////////////////////////
1117 
1118 #define SMART_CYL_LOW 0x4F
1119 #define SMART_CYL_HI 0xC2
1120 
1121 static void print_ide_regs(const IDEREGS * r, int out)
1122 {
1123  pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1124  (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
1126 }
1127 
1128 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
1129 {
1130  pout(" Input : "); print_ide_regs(ri, 0);
1131  if (ro) {
1132  pout(" Output: "); print_ide_regs(ro, 1);
1133  }
1134 }
1135 
1136 /////////////////////////////////////////////////////////////////////////////
1137 
1138 // call SMART_GET_VERSION, return device map or -1 on error
1139 
1140 static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
1141 {
1142  GETVERSIONINPARAMS vers; memset(&vers, 0, sizeof(vers));
1143  const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers;
1144  DWORD num_out;
1145 
1146  if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
1147  NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
1148  if (ata_debugmode)
1149  pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1150  errno = ENOSYS;
1151  return -1;
1152  }
1153  assert(num_out == sizeof(GETVERSIONINPARAMS));
1154 
1155  if (ata_debugmode > 1) {
1156  pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1157  " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1158  (unsigned)num_out, vers.bVersion, vers.bRevision,
1159  (unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
1160  if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
1161  pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1162  vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx);
1163  }
1164 
1165  if (ata_version_ex)
1166  *ata_version_ex = vers_ex;
1167 
1168  // TODO: Check vers.fCapabilities here?
1169  return vers.bIDEDeviceMap;
1170 }
1171 
1172 
1173 // call SMART_* ioctl
1174 
1175 static int smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize, int port)
1176 {
1177  SENDCMDINPARAMS inpar;
1178  SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
1179 
1180  unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512];
1181  const SENDCMDOUTPARAMS * outpar;
1182  DWORD code, num_out;
1183  unsigned int size_out;
1184  const char * name;
1185 
1186  memset(&inpar, 0, sizeof(inpar));
1187  inpar.irDriveRegs = *regs;
1188 
1189  // Older drivers may require bits 5 and 7 set
1190  // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1191  inpar.irDriveRegs.bDriveHeadReg |= 0xa0;
1192 
1193  // Drive number 0-3 was required on Win9x/ME only
1194  //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1195  //inpar.bDriveNumber = drive;
1196 
1197  if (port >= 0) {
1198  // Set RAID port
1199  inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
1200  inpar_ex.bPortNumber = port;
1201  }
1202 
1203  if (datasize == 512) {
1204  code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA";
1205  inpar.cBufferSize = size_out = 512;
1206  }
1207  else if (datasize == 0) {
1208  code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND";
1209  if (regs->bFeaturesReg == ATA_SMART_STATUS)
1210  size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data
1211  // Note: cBufferSize must be 0 on Win9x
1212  else
1213  size_out = 0;
1214  }
1215  else {
1216  errno = EINVAL;
1217  return -1;
1218  }
1219 
1220  memset(&outbuf, 0, sizeof(outbuf));
1221 
1222  if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
1223  outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
1224  // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1225  long err = GetLastError();
1226  if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
1227  pout(" %s failed, Error=%ld\n", name, err);
1228  print_ide_regs_io(regs, NULL);
1229  }
1230  errno = ( err == ERROR_INVALID_FUNCTION/*9x*/
1231  || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/
1232  || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1233  return -1;
1234  }
1235  // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1236 
1237  outpar = (const SENDCMDOUTPARAMS *)outbuf;
1238 
1239  if (outpar->DriverStatus.bDriverError) {
1240  if (ata_debugmode) {
1241  pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1242  outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError);
1243  print_ide_regs_io(regs, NULL);
1244  }
1245  errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO);
1246  return -1;
1247  }
1248 
1249  if (ata_debugmode > 1) {
1250  pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name,
1251  (unsigned)num_out, (unsigned)outpar->cBufferSize);
1253  (const IDEREGS *)(outpar->bBuffer) : NULL));
1254  }
1255 
1256  if (datasize)
1257  memcpy(data, outpar->bBuffer, 512);
1258  else if (regs->bFeaturesReg == ATA_SMART_STATUS) {
1259  if (nonempty(outpar->bBuffer, sizeof(IDEREGS)))
1260  memcpy(regs, outpar->bBuffer, sizeof(IDEREGS));
1261  else { // Workaround for driver not returning regs
1262  if (ata_debugmode)
1263  pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1264  *regs = inpar.irDriveRegs;
1265  }
1266  }
1267 
1268  return 0;
1269 }
1270 
1271 
1272 /////////////////////////////////////////////////////////////////////////////
1273 // IDE PASS THROUGH (2000, XP, undocumented)
1274 //
1275 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1276 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1277 
1278 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)
1279 {
1280  if (datasize > 512) {
1281  errno = EINVAL;
1282  return -1;
1283  }
1284  unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize;
1285  ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
1286  DWORD num_out;
1287  const unsigned char magic = 0xcf;
1288 
1289  if (!buf) {
1290  errno = ENOMEM;
1291  return -1;
1292  }
1293 
1294  buf->IdeReg = *regs;
1295  buf->DataBufferSize = datasize;
1296  if (datasize)
1297  buf->DataBuffer[0] = magic;
1298 
1299  if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH,
1300  buf, size, buf, size, &num_out, NULL)) {
1301  long err = GetLastError();
1302  if (ata_debugmode) {
1303  pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err);
1304  print_ide_regs_io(regs, NULL);
1305  }
1306  VirtualFree(buf, 0, MEM_RELEASE);
1307  errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1308  return -1;
1309  }
1310 
1311  // Check ATA status
1312  if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) {
1313  if (ata_debugmode) {
1314  pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1315  print_ide_regs_io(regs, &buf->IdeReg);
1316  }
1317  VirtualFree(buf, 0, MEM_RELEASE);
1318  errno = EIO;
1319  return -1;
1320  }
1321 
1322  // Check and copy data
1323  if (datasize) {
1324  if ( num_out != size
1325  || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
1326  if (ata_debugmode) {
1327  pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1328  (unsigned)num_out, (unsigned)buf->DataBufferSize);
1329  print_ide_regs_io(regs, &buf->IdeReg);
1330  }
1331  VirtualFree(buf, 0, MEM_RELEASE);
1332  errno = EIO;
1333  return -1;
1334  }
1335  memcpy(data, buf->DataBuffer, datasize);
1336  }
1337 
1338  if (ata_debugmode > 1) {
1339  pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1340  (unsigned)num_out, (unsigned)buf->DataBufferSize);
1341  print_ide_regs_io(regs, &buf->IdeReg);
1342  }
1343  *regs = buf->IdeReg;
1344 
1345  // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1346  VirtualFree(buf, 0, MEM_RELEASE);
1347  return 0;
1348 }
1349 
1350 
1351 /////////////////////////////////////////////////////////////////////////////
1352 // ATA PASS THROUGH (Win2003, XP SP2)
1353 
1354 // Warning:
1355 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1356 // transfer per command. Therefore, multi-sector transfers are only supported
1357 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1358 // or READ/WRITE LOG EXT work only with single sector transfers.
1359 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1360 // See:
1361 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1362 
1363 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize)
1364 {
1365  const int max_sectors = 32; // TODO: Allocate dynamic buffer
1366 
1367  typedef struct {
1368  ATA_PASS_THROUGH_EX apt;
1369  ULONG Filler;
1370  UCHAR ucDataBuf[max_sectors * 512];
1371  } ATA_PASS_THROUGH_EX_WITH_BUFFERS;
1372 
1373  const unsigned char magic = 0xcf;
1374 
1375  ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab));
1376  ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX);
1377  //ab.apt.PathId = 0;
1378  //ab.apt.TargetId = 0;
1379  //ab.apt.Lun = 0;
1380  ab.apt.TimeOutValue = 10;
1381  unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf);
1382  ab.apt.DataBufferOffset = size;
1383 
1384  if (datasize > 0) {
1385  if (datasize > (int)sizeof(ab.ucDataBuf)) {
1386  errno = EINVAL;
1387  return -1;
1388  }
1389  ab.apt.AtaFlags = ATA_FLAGS_DATA_IN;
1390  ab.apt.DataTransferLength = datasize;
1391  size += datasize;
1392  ab.ucDataBuf[0] = magic;
1393  }
1394  else if (datasize < 0) {
1395  if (-datasize > (int)sizeof(ab.ucDataBuf)) {
1396  errno = EINVAL;
1397  return -1;
1398  }
1399  ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT;
1400  ab.apt.DataTransferLength = -datasize;
1401  size += -datasize;
1402  memcpy(ab.ucDataBuf, data, -datasize);
1403  }
1404  else {
1405  assert(ab.apt.AtaFlags == 0);
1406  assert(ab.apt.DataTransferLength == 0);
1407  }
1408 
1409  assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS));
1410  IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile;
1411  IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile;
1412  *ctfregs = *regs;
1413 
1414  if (prev_regs) {
1415  *ptfregs = *prev_regs;
1416  ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
1417  }
1418 
1419  DWORD num_out;
1420  if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH,
1421  &ab, size, &ab, size, &num_out, NULL)) {
1422  long err = GetLastError();
1423  if (ata_debugmode) {
1424  pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err);
1425  print_ide_regs_io(regs, NULL);
1426  }
1427  errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1428  return -1;
1429  }
1430 
1431  // Check ATA status
1432  if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1433  if (ata_debugmode) {
1434  pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1435  print_ide_regs_io(regs, ctfregs);
1436  }
1437  errno = EIO;
1438  return -1;
1439  }
1440 
1441  // Check and copy data
1442  if (datasize > 0) {
1443  if ( num_out != size
1444  || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
1445  if (ata_debugmode) {
1446  pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out);
1447  print_ide_regs_io(regs, ctfregs);
1448  }
1449  errno = EIO;
1450  return -1;
1451  }
1452  memcpy(data, ab.ucDataBuf, datasize);
1453  }
1454 
1455  if (ata_debugmode > 1) {
1456  pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out);
1457  print_ide_regs_io(regs, ctfregs);
1458  }
1459  *regs = *ctfregs;
1460  if (prev_regs)
1461  *prev_regs = *ptfregs;
1462 
1463  return 0;
1464 }
1465 
1466 
1467 /////////////////////////////////////////////////////////////////////////////
1468 // SMART IOCTL via SCSI MINIPORT ioctl
1469 
1470 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1471 // miniport driver (via SCSI port driver scsiport.sys).
1472 // It can be used to skip the missing or broken handling of some SMART
1473 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1474 
1475 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize)
1476 {
1477  // Select code
1478  DWORD code = 0; const char * name = 0;
1479  if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) {
1480  code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY";
1481  }
1482  else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) {
1483  case ATA_SMART_READ_VALUES:
1484  code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break;
1486  code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break;
1487  case ATA_SMART_ENABLE:
1488  code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break;
1489  case ATA_SMART_DISABLE:
1490  code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break;
1491  case ATA_SMART_STATUS:
1492  code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break;
1493  case ATA_SMART_AUTOSAVE:
1494  code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break;
1495  //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1496  // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1498  code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break;
1500  code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1502  code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break;
1504  code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break;
1505  }
1506  if (!code) {
1507  errno = ENOSYS;
1508  return -1;
1509  }
1510 
1511  // Set SRB
1512  struct {
1513  SRB_IO_CONTROL srbc;
1514  union {
1515  SENDCMDINPARAMS in;
1516  SENDCMDOUTPARAMS out;
1517  } params;
1518  char space[512-1];
1519  } sb;
1520  ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
1521  memset(&sb, 0, sizeof(sb));
1522 
1523  unsigned size;
1524  if (datasize > 0) {
1525  if (datasize > (int)sizeof(sb.space)+1) {
1526  errno = EINVAL;
1527  return -1;
1528  }
1529  size = datasize;
1530  }
1531  else if (datasize < 0) {
1532  if (-datasize > (int)sizeof(sb.space)+1) {
1533  errno = EINVAL;
1534  return -1;
1535  }
1536  size = -datasize;
1537  memcpy(sb.params.in.bBuffer, data, size);
1538  }
1539  else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1540  size = sizeof(IDEREGS);
1541  else
1542  size = 0;
1543  sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1544  memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys
1545  sb.srbc.Timeout = 60; // seconds
1546  sb.srbc.ControlCode = code;
1547  //sb.srbc.ReturnCode = 0;
1548  sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size;
1549  sb.params.in.irDriveRegs = *regs;
1550  sb.params.in.cBufferSize = size;
1551 
1552  // Call miniport ioctl
1553  size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1;
1554  DWORD num_out;
1555  if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1556  &sb, size, &sb, size, &num_out, NULL)) {
1557  long err = GetLastError();
1558  if (ata_debugmode) {
1559  pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err);
1560  print_ide_regs_io(regs, NULL);
1561  }
1562  errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);
1563  return -1;
1564  }
1565 
1566  // Check result
1567  if (sb.srbc.ReturnCode) {
1568  if (ata_debugmode) {
1569  pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (unsigned)sb.srbc.ReturnCode);
1570  print_ide_regs_io(regs, NULL);
1571  }
1572  errno = EIO;
1573  return -1;
1574  }
1575 
1576  if (sb.params.out.DriverStatus.bDriverError) {
1577  if (ata_debugmode) {
1578  pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name,
1579  sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError);
1580  print_ide_regs_io(regs, NULL);
1581  }
1582  errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO);
1583  return -1;
1584  }
1585 
1586  if (ata_debugmode > 1) {
1587  pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name,
1588  (unsigned)num_out, (unsigned)sb.params.out.cBufferSize);
1590  (const IDEREGS *)(sb.params.out.bBuffer) : 0));
1591  }
1592 
1593  if (datasize > 0)
1594  memcpy(data, sb.params.out.bBuffer, datasize);
1595  else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS)
1596  memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS));
1597 
1598  return 0;
1599 }
1600 
1601 
1602 /////////////////////////////////////////////////////////////////////////////
1603 
1604 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1605 
1606 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port)
1607 {
1608  struct {
1609  SRB_IO_CONTROL srbc;
1610  IDEREGS regs;
1611  UCHAR buffer[512];
1612  } sb;
1613  ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
1614 
1615  if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
1616  errno = EINVAL;
1617  return -1;
1618  }
1619  memset(&sb, 0, sizeof(sb));
1620  strncpy((char *)sb.srbc.Signature, "<3ware>", sizeof(sb.srbc.Signature));
1621  sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1622  sb.srbc.Timeout = 60; // seconds
1623  sb.srbc.ControlCode = 0xA0000000;
1624  sb.srbc.ReturnCode = 0;
1625  sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
1626  sb.regs = *regs;
1627  sb.regs.bReserved = port;
1628 
1629  DWORD num_out;
1630  if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1631  &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) {
1632  long err = GetLastError();
1633  if (ata_debugmode) {
1634  pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1635  print_ide_regs_io(regs, NULL);
1636  }
1637  errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1638  return -1;
1639  }
1640 
1641  if (sb.srbc.ReturnCode) {
1642  if (ata_debugmode) {
1643  pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb.srbc.ReturnCode);
1644  print_ide_regs_io(regs, NULL);
1645  }
1646  errno = EIO;
1647  return -1;
1648  }
1649 
1650  // Copy data
1651  if (datasize > 0)
1652  memcpy(data, sb.buffer, datasize);
1653 
1654  if (ata_debugmode > 1) {
1655  pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out);
1656  print_ide_regs_io(regs, &sb.regs);
1657  }
1658  *regs = sb.regs;
1659 
1660  return 0;
1661 }
1662 
1663 
1664 /////////////////////////////////////////////////////////////////////////////
1665 
1666 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1667 // 3DM/CLI "Rescan Controller" function does not to always update it.
1668 
1669 static int update_3ware_devicemap_ioctl(HANDLE hdevice)
1670 {
1671  SRB_IO_CONTROL srbc;
1672  memset(&srbc, 0, sizeof(srbc));
1673  strncpy((char *)srbc.Signature, "<3ware>", sizeof(srbc.Signature));
1674  srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
1675  srbc.Timeout = 60; // seconds
1676  srbc.ControlCode = 0xCC010014;
1677  srbc.ReturnCode = 0;
1678  srbc.Length = 0;
1679 
1680  DWORD num_out;
1681  if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT,
1682  &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) {
1683  long err = GetLastError();
1684  if (ata_debugmode)
1685  pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err);
1686  errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
1687  return -1;
1688  }
1689  if (srbc.ReturnCode) {
1690  if (ata_debugmode)
1691  pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc.ReturnCode);
1692  errno = EIO;
1693  return -1;
1694  }
1695  if (ata_debugmode > 1)
1696  pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1697  return 0;
1698 }
1699 
1700 
1701 
1702 /////////////////////////////////////////////////////////////////////////////
1703 
1704 // Routines for pseudo device /dev/tw_cli/*
1705 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1706 
1707 
1708 // Get clipboard data
1709 
1710 static int get_clipboard(char * data, int datasize)
1711 {
1712  if (!OpenClipboard(NULL))
1713  return -1;
1714  HANDLE h = GetClipboardData(CF_TEXT);
1715  if (!h) {
1716  CloseClipboard();
1717  return 0;
1718  }
1719  const void * p = GlobalLock(h);
1720  int n = GlobalSize(h);
1721  if (n > datasize)
1722  n = datasize;
1723  memcpy(data, p, n);
1724  GlobalFree(h);
1725  CloseClipboard();
1726  return n;
1727 }
1728 
1729 
1730 // Run a command, write stdout to dataout
1731 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1732 
1733 static int run_cmd(const char * cmd, char * dataout, int outsize)
1734 {
1735  // Create stdout pipe
1736  SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
1737  HANDLE pipe_out_w, h;
1738  if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize))
1739  return -1;
1740  HANDLE self = GetCurrentProcess();
1741  HANDLE pipe_out_r;
1742  if (!DuplicateHandle(self, h, self, &pipe_out_r,
1743  GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
1744  CloseHandle(pipe_out_w);
1745  return -1;
1746  }
1747  HANDLE pipe_err_w;
1748  if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
1749  0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
1750  CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1751  return -1;
1752  }
1753 
1754  // Create process
1755  STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
1756  si.hStdInput = INVALID_HANDLE_VALUE;
1757  si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w;
1758  si.dwFlags = STARTF_USESTDHANDLES;
1759  PROCESS_INFORMATION pi;
1760  if (!CreateProcess(
1761  NULL, const_cast<char *>(cmd),
1762  NULL, NULL, TRUE/*inherit*/,
1763  CREATE_NO_WINDOW/*do not create a new console window*/,
1764  NULL, NULL, &si, &pi)) {
1765  CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
1766  return -1;
1767  }
1768  CloseHandle(pi.hThread);
1769  CloseHandle(pipe_err_w); CloseHandle(pipe_out_w);
1770 
1771  // Copy stdout to output buffer
1772  int i = 0;
1773  while (i < outsize) {
1774  DWORD num_read;
1775  if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0)
1776  break;
1777  i += num_read;
1778  }
1779  CloseHandle(pipe_out_r);
1780  // Wait for process
1781  WaitForSingleObject(pi.hProcess, INFINITE);
1782  CloseHandle(pi.hProcess);
1783  return i;
1784 }
1785 
1786 
1787 static const char * findstr(const char * str, const char * sub)
1788 {
1789  const char * s = strstr(str, sub);
1790  return (s ? s+strlen(sub) : "");
1791 }
1792 
1793 
1794 static void copy_swapped(unsigned char * dest, const char * src, int destsize)
1795 {
1796  int srclen = strcspn(src, "\r\n");
1797  int i;
1798  for (i = 0; i < destsize-1 && i < srclen-1; i+=2) {
1799  dest[i] = src[i+1]; dest[i+1] = src[i];
1800  }
1801  if (i < destsize-1 && i < srclen)
1802  dest[i+1] = src[i];
1803 }
1804 
1805 
1806 // TODO: This is OS independent
1807 
1808 win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type)
1809 : smart_device(intf, dev_name, "tw_cli", req_type),
1810  m_ident_valid(false), m_smart_valid(false)
1811 {
1812  memset(&m_ident_buf, 0, sizeof(m_ident_buf));
1813  memset(&m_smart_buf, 0, sizeof(m_smart_buf));
1814 }
1815 
1816 
1818 {
1819  return (m_ident_valid || m_smart_valid);
1820 }
1821 
1822 
1824 {
1825  m_ident_valid = m_smart_valid = false;
1826  const char * name = skipdev(get_dev_name());
1827  // Read tw_cli or 3DM browser output into buffer
1828  char buffer[4096];
1829  int size = -1, n1 = -1, n2 = -1;
1830  if (!strcmp(name, "tw_cli/clip")) { // read clipboard
1831  size = get_clipboard(buffer, sizeof(buffer));
1832  }
1833  else if (!strcmp(name, "tw_cli/stdin")) { // read stdin
1834  size = fread(buffer, 1, sizeof(buffer), stdin);
1835  }
1836  else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) {
1837  // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1838  char cmd[100];
1839  snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1);
1840  if (ata_debugmode > 1)
1841  pout("%s: Run: \"%s\"\n", name, cmd);
1842  size = run_cmd(cmd, buffer, sizeof(buffer));
1843  }
1844  else {
1845  return set_err(EINVAL);
1846  }
1847 
1848  if (ata_debugmode > 1)
1849  pout("%s: Read %d bytes\n", name, size);
1850  if (size <= 0)
1851  return set_err(ENOENT);
1852  if (size >= (int)sizeof(buffer))
1853  return set_err(EIO);
1854 
1855  buffer[size] = 0;
1856  if (ata_debugmode > 1)
1857  pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
1858 
1859  // Fake identify sector
1862  memset(id, 0, sizeof(*id));
1863  copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model));
1864  copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev));
1865  copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no));
1866  unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)"
1867  sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks);
1868  if (nblocks) {
1869  id->words047_079[49-47] = 0x0200; // size valid
1870  id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16
1871  id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32
1872  }
1873  id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
1874  id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
1875 
1876  // Parse smart data hex dump
1877  const char * s = findstr(buffer, "Drive Smart Data:");
1878  if (!*s)
1879  s = findstr(buffer, "Drive SMART Data:"); // tw_cli from 9.5.x
1880  if (!*s) {
1881  s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window
1882  if (*s) {
1883  const char * s1 = findstr(s, "<td class"); // html version
1884  if (*s1)
1885  s = s1;
1886  s += strcspn(s, "\r\n");
1887  }
1888  else
1889  s = buffer; // try raw hex dump without header
1890  }
1891  unsigned char * sd = (unsigned char *)&m_smart_buf;
1892  int i = 0;
1893  for (;;) {
1894  unsigned x = ~0; int n = -1;
1895  if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff)))
1896  break;
1897  sd[i] = (unsigned char)x;
1898  if (!(++i < 512 && n > 0))
1899  break;
1900  s += n;
1901  if (*s == '<') // "<br>"
1902  s += strcspn(s, "\r\n");
1903  }
1904  if (i < 512) {
1905  if (!id->model[1]) {
1906  // No useful data found
1907  char * err = strstr(buffer, "Error:");
1908  if (!err)
1909  err = strstr(buffer, "error :");
1910  if (err && (err = strchr(err, ':'))) {
1911  // Show tw_cli error message
1912  err++;
1913  err[strcspn(err, "\r\n")] = 0;
1914  return set_err(EIO, "%s", err);
1915  }
1916  return set_err(EIO);
1917  }
1918  sd = 0;
1919  }
1920 
1921  m_ident_valid = true;
1922  m_smart_valid = !!sd;
1923  return true;
1924 }
1925 
1926 
1928 {
1929  m_ident_valid = m_smart_valid = false;
1930  return true;
1931 }
1932 
1933 
1935 {
1936  switch (command) {
1937  case IDENTIFY:
1938  if (!m_ident_valid)
1939  break;
1940  memcpy(data, &m_ident_buf, 512);
1941  return 0;
1942  case READ_VALUES:
1943  if (!m_smart_valid)
1944  break;
1945  memcpy(data, &m_smart_buf, 512);
1946  return 0;
1947  case ENABLE:
1948  case STATUS:
1949  case STATUS_CHECK: // Fake "good" SMART status
1950  return 0;
1951  default:
1952  break;
1953  }
1954  // Arrive here for all unsupported commands
1955  set_err(ENOSYS);
1956  return -1;
1957 }
1958 
1959 
1960 /////////////////////////////////////////////////////////////////////////////
1961 // IOCTL_STORAGE_QUERY_PROPERTY
1962 
1965  char raw[256];
1966 };
1967 
1968 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1969 // (This works without admin rights)
1970 
1972 {
1974  memset(data, 0, sizeof(*data));
1975 
1976  DWORD num_out;
1977  if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
1978  &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
1979  if (ata_debugmode > 1 || scsi_debugmode > 1)
1980  pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
1981  errno = ENOSYS;
1982  return -1;
1983  }
1984 
1985  if (ata_debugmode > 1 || scsi_debugmode > 1) {
1986  pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1987  " Vendor: \"%s\"\n"
1988  " Product: \"%s\"\n"
1989  " Revision: \"%s\"\n"
1990  " Removable: %s\n"
1991  " BusType: 0x%02x\n",
1992  (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : "(null)"),
1993  (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : "(null)"),
1994  (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : "(null)"),
1995  (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType
1996  );
1997  }
1998  return 0;
1999 }
2000 
2001 
2002 /////////////////////////////////////////////////////////////////////////////
2003 // IOCTL_STORAGE_PREDICT_FAILURE
2004 
2005 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
2006 // or -1 on error, opionally return VendorSpecific data.
2007 // (This works without admin rights)
2008 
2009 static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
2010 {
2011  STORAGE_PREDICT_FAILURE pred;
2012  memset(&pred, 0, sizeof(pred));
2013 
2014  DWORD num_out;
2015  if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
2016  0, 0, &pred, sizeof(pred), &num_out, NULL)) {
2017  if (ata_debugmode > 1)
2018  pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
2019  errno = ENOSYS;
2020  return -1;
2021  }
2022 
2023  if (ata_debugmode > 1) {
2024  pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2025  " PredictFailure: 0x%08x\n"
2026  " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2027  (unsigned)pred.PredictFailure,
2028  pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
2029  pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
2030  );
2031  }
2032  if (data)
2033  memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific));
2034  return (!pred.PredictFailure ? 0 : 1);
2035 }
2036 
2037 
2038 /////////////////////////////////////////////////////////////////////////////
2039 
2040 // Return true if ATA drive behind a SAT layer
2042 {
2043  if (!data->desc.VendorIdOffset)
2044  return false;
2045  if (strcmp(data->raw + data->desc.VendorIdOffset, "ATA "))
2046  return false;
2047  return true;
2048 }
2049 
2050 // Return true if Intel ICHxR RAID volume
2052 {
2053  if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset))
2054  return false;
2055  const char * vendor = data->raw + data->desc.VendorIdOffset;
2056  if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5)))
2057  return false;
2058  if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5))
2059  return false;
2060  return true;
2061 }
2062 
2063 // get DEV_* for open handle
2064 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex)
2065 {
2066  // Get BusType from device descriptor
2068  if (storage_query_property_ioctl(hdevice, &data))
2069  return DEV_UNKNOWN;
2070 
2071  // Newer BusType* values are missing in older includes
2072  switch ((int)data.desc.BusType) {
2073  case BusTypeAta:
2074  case 0x0b: // BusTypeSata
2075  // Certain Intel AHCI drivers (C600+/C220+) have broken
2076  // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
2077  if (is_sat(&data))
2078  return DEV_SAT;
2079 
2080  if (ata_version_ex)
2081  memset(ata_version_ex, 0, sizeof(*ata_version_ex));
2082  return DEV_ATA;
2083 
2084  case BusTypeScsi:
2085  case BusTypeRAID:
2086  if (is_sat(&data))
2087  return DEV_SAT;
2088 
2089  // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2090  if (is_intel_raid_volume(&data))
2091  return DEV_SCSI;
2092  // LSI/3ware RAID volume: supports SMART_*
2093  if (admin && smart_get_version(hdevice, ata_version_ex) >= 0)
2094  return DEV_ATA;
2095 
2096  return DEV_SCSI;
2097 
2098  case 0x09: // BusTypeiScsi
2099  case 0x0a: // BusTypeSas
2100  if (is_sat(&data))
2101  return DEV_SAT;
2102 
2103  return DEV_SCSI;
2104 
2105  case BusTypeUsb:
2106  return DEV_USB;
2107 
2108  default:
2109  return DEV_UNKNOWN;
2110  }
2111  /*NOTREACHED*/
2112 }
2113 
2114 // get DEV_* for device path
2115 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0)
2116 {
2117  bool admin = true;
2118  HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE,
2119  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
2120  if (h == INVALID_HANDLE_VALUE) {
2121  admin = false;
2122  h = CreateFileA(path, 0,
2123  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
2124  if (h == INVALID_HANDLE_VALUE)
2125  return DEV_UNKNOWN;
2126  }
2127  if (ata_debugmode > 1 || scsi_debugmode > 1)
2128  pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :""));
2129  win_dev_type type = get_controller_type(h, admin, ata_version_ex);
2130  CloseHandle(h);
2131  return type;
2132 }
2133 
2134 // get DEV_* for physical drive number
2135 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex)
2136 {
2137  char path[30];
2138  snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive);
2139  return get_controller_type(path, ata_version_ex);
2140 }
2141 
2143 {
2144  return get_phy_drive_type(drive, 0);
2145 }
2146 
2147 // get DEV_* for logical drive number
2149 {
2150  char path[30];
2151  snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive);
2152  return get_controller_type(path);
2153 }
2154 
2155 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2157 {
2159  if (storage_query_property_ioctl(hdevice, &data))
2160  return -1;
2161 
2162  memset(id, 0, sizeof(*id));
2163 
2164  // Some drivers split ATA model string into VendorId and ProductId,
2165  // others return it as ProductId only.
2166  char model[sizeof(id->model) + 1] = "";
2167 
2168  unsigned i = 0;
2169  if (data.desc.VendorIdOffset) {
2170  for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++)
2171  model[i] = data.raw[data.desc.VendorIdOffset+i];
2172  }
2173 
2174  if (data.desc.ProductIdOffset) {
2175  while (i > 1 && model[i-2] == ' ') // Keep last blank from VendorId
2176  i--;
2177  // Ignore VendorId "ATA"
2178  if (i <= 4 && !strncmp(model, "ATA", 3) && (i == 3 || model[3] == ' '))
2179  i = 0;
2180  for (unsigned j = 0; i < sizeof(model)-1 && data.raw[data.desc.ProductIdOffset+j]; i++, j++)
2181  model[i] = data.raw[data.desc.ProductIdOffset+j];
2182  }
2183 
2184  while (i > 0 && model[i-1] == ' ')
2185  i--;
2186  model[i] = 0;
2187  copy_swapped(id->model, model, sizeof(id->model));
2188 
2189  if (data.desc.ProductRevisionOffset)
2190  copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev));
2191 
2192  id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid
2193  id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid
2194  return 0;
2195 }
2196 
2197 // Get Serial Number in IDENTIFY from WMI
2198 static bool get_serial_from_wmi(int drive, ata_identify_device * id)
2199 {
2200  bool debug = (ata_debugmode > 1);
2201 
2202  wbem_services ws;
2203  if (!ws.connect()) {
2204  if (debug)
2205  pout("WMI connect failed\n");
2206  return false;
2207  }
2208 
2209  wbem_object wo;
2210  if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2211  "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
2212  return false;
2213 
2214  std::string serial = wo.get_str("SerialNumber");
2215  if (debug)
2216  pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str("Model").c_str(), serial.c_str());
2217 
2218  copy_swapped(id->serial_no, serial.c_str(), sizeof(id->serial_no));
2219  return true;
2220 }
2221 
2222 
2223 /////////////////////////////////////////////////////////////////////////////
2224 // USB ID detection using WMI
2225 
2226 // Get USB ID for a physical drive number
2227 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
2228 {
2229  bool debug = (scsi_debugmode > 1);
2230 
2231  wbem_services ws;
2232  if (!ws.connect()) {
2233  if (debug)
2234  pout("WMI connect failed\n");
2235  return false;
2236  }
2237 
2238  // Get device name
2239  wbem_object wo;
2240  if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
2241  return false;
2242 
2243  std::string name = wo.get_str("Model");
2244  if (debug)
2245  pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str());
2246 
2247  // Get USB_CONTROLLER -> DEVICE associations
2248  wbem_enumerator we;
2249  if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2250  return false;
2251 
2252  unsigned short usb_venid = 0, prev_usb_venid = 0;
2253  unsigned short usb_proid = 0, prev_usb_proid = 0;
2254  std::string prev_usb_ant;
2255  std::string prev_ant, ant, dep;
2256 
2257  const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED);
2258 
2259  while (we.next(wo)) {
2260  prev_ant = ant;
2261  // Find next 'USB_CONTROLLER, DEVICE' pair
2262  ant = wo.get_str("Antecedent");
2263  dep = wo.get_str("Dependent");
2264 
2265  if (debug && ant != prev_ant)
2266  pout(" %s:\n", ant.c_str());
2267 
2268  // Extract DeviceID
2269  regmatch_t match[2];
2270  if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) {
2271  if (debug)
2272  pout(" | (\"%s\")\n", dep.c_str());
2273  continue;
2274  }
2275 
2276  std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so);
2277 
2278  if (str_starts_with(devid, "USB\\\\VID_")) {
2279  // USB bridge entry, save CONTROLLER, ID
2280  int nc = -1;
2281  if (!(sscanf(devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2282  &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) {
2283  prev_usb_venid = prev_usb_proid = 0;
2284  }
2285  prev_usb_ant = ant;
2286  if (debug)
2287  pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
2288  continue;
2289  }
2290  else if (str_starts_with(devid, "USBSTOR\\\\")) {
2291  // USBSTOR device found
2292  if (debug)
2293  pout(" +--> \"%s\"\n", devid.c_str());
2294 
2295  // Retrieve name
2296  wbem_object wo2;
2297  if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str()))
2298  continue;
2299  std::string name2 = wo2.get_str("Name");
2300 
2301  // Continue if not name of physical disk drive
2302  if (name2 != name) {
2303  if (debug)
2304  pout(" +---> (\"%s\")\n", name2.c_str());
2305  continue;
2306  }
2307 
2308  // Fail if previous USB bridge is associated to other controller or ID is unknown
2309  if (!(ant == prev_usb_ant && prev_usb_venid)) {
2310  if (debug)
2311  pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
2312  return false;
2313  }
2314 
2315  // Handle multiple devices with same name
2316  if (usb_venid) {
2317  // Fail if multiple devices with same name have different USB bridge types
2318  if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) {
2319  if (debug)
2320  pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str());
2321  return false;
2322  }
2323  }
2324 
2325  // Found
2326  usb_venid = prev_usb_venid;
2327  usb_proid = prev_usb_proid;
2328  if (debug)
2329  pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid);
2330 
2331  // Continue to check for duplicate names ...
2332  }
2333  else {
2334  if (debug)
2335  pout(" | \"%s\"\n", devid.c_str());
2336  }
2337  }
2338 
2339  if (!usb_venid)
2340  return false;
2341 
2342  vendor_id = usb_venid;
2343  product_id = usb_proid;
2344 
2345  return true;
2346 }
2347 
2348 
2349 /////////////////////////////////////////////////////////////////////////////
2350 
2351 // Call GetDevicePowerState()
2352 // returns: 1=active, 0=standby, -1=error
2353 // (This would also work for SCSI drives)
2354 
2355 static int get_device_power_state(HANDLE hdevice)
2356 {
2357  BOOL state = TRUE;
2358  if (!GetDevicePowerState(hdevice, &state)) {
2359  long err = GetLastError();
2360  if (ata_debugmode)
2361  pout(" GetDevicePowerState() failed, Error=%ld\n", err);
2362  errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO);
2363  // TODO: This may not work as expected on transient errors,
2364  // because smartd interprets -1 as SLEEP mode regardless of errno.
2365  return -1;
2366  }
2367 
2368  if (ata_debugmode > 1)
2369  pout(" GetDevicePowerState() succeeded, state=%d\n", state);
2370  return state;
2371 }
2372 
2373 
2374 /////////////////////////////////////////////////////////////////////////////
2375 
2376 // Get default ATA device options
2377 
2378 static const char * ata_get_def_options()
2379 {
2380  return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2381  // STORAGE_*, SCSI_MINIPORT_*
2382 }
2383 
2384 
2385 // Common routines for devices with HANDLEs
2386 
2388 {
2389  if (m_fh != INVALID_HANDLE_VALUE)
2390  ::CloseHandle(m_fh);
2391 }
2392 
2394 {
2395  return (m_fh != INVALID_HANDLE_VALUE);
2396 }
2397 
2399 {
2400  if (m_fh == INVALID_HANDLE_VALUE)
2401  return true;
2402  BOOL rc = ::CloseHandle(m_fh);
2403  m_fh = INVALID_HANDLE_VALUE;
2404  return !!rc;
2405 }
2406 
2407 // ATA
2408 
2409 win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
2410 : smart_device(intf, dev_name, "ata", req_type),
2411  m_usr_options(false),
2412  m_admin(false),
2413  m_phydrive(-1),
2414  m_id_is_cached(false),
2415  m_is_3ware(false),
2416  m_port(-1),
2417  m_smartver_state(0)
2418 {
2419 }
2420 
2422 {
2423 }
2424 
2425 
2426 // Open ATA device
2427 
2429 {
2430  const char * name = skipdev(get_dev_name()); int len = strlen(name);
2431  // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2432  char drive[2+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
2433  if ( sscanf(name, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1
2434  && ((n1 == len && !options[0]) || n2 == len) ) {
2435  return open(sdxy_to_phydrive(drive), -1, options, -1);
2436  }
2437  // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2438  drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
2439  unsigned port = ~0;
2440  if ( sscanf(name, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2
2441  && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) {
2442  return open(sdxy_to_phydrive(drive), -1, options, port);
2443  }
2444  // pd<m>,N => Physical drive <m>, RAID port N
2445  int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
2446  if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1
2447  && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) {
2448  return open(phydrive, -1, "", (int)port);
2449  }
2450  // [a-zA-Z]: => Physical drive behind logical drive 0-25
2451  int logdrive = drive_letter(name);
2452  if (logdrive >= 0) {
2453  return open(-1, logdrive, "", -1);
2454  }
2455 
2456  return set_err(EINVAL);
2457 }
2458 
2459 
2460 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)
2461 {
2462  m_phydrive = -1;
2463  char devpath[30];
2464  if (0 <= phydrive && phydrive <= 255)
2465  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive));
2466  else if (0 <= logdrive && logdrive <= 'Z'-'A')
2467  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
2468  else
2469  return set_err(ENOENT);
2470 
2471  // Open device
2472  HANDLE h = INVALID_HANDLE_VALUE;
2473  if (!(*options && !options[strspn(options, "fp")])) {
2474  // Open with admin rights
2475  m_admin = true;
2476  h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
2477  FILE_SHARE_READ|FILE_SHARE_WRITE,
2478  NULL, OPEN_EXISTING, 0, 0);
2479  }
2480  if (h == INVALID_HANDLE_VALUE) {
2481  // Open without admin rights
2482  m_admin = false;
2483  h = CreateFileA(devpath, 0,
2484  FILE_SHARE_READ|FILE_SHARE_WRITE,
2485  NULL, OPEN_EXISTING, 0, 0);
2486  }
2487  if (h == INVALID_HANDLE_VALUE) {
2488  long err = GetLastError();
2489  if (err == ERROR_FILE_NOT_FOUND)
2490  set_err(ENOENT, "%s: not found", devpath);
2491  else if (err == ERROR_ACCESS_DENIED)
2492  set_err(EACCES, "%s: access denied", devpath);
2493  else
2494  set_err(EIO, "%s: Error=%ld", devpath, err);
2495  return false;
2496  }
2497  set_fh(h);
2498 
2499  // Warn once if admin rights are missing
2500  if (!m_admin) {
2501  static bool noadmin_warning = false;
2502  if (!noadmin_warning) {
2503  pout("Warning: Limited functionality due to missing admin rights\n");
2504  noadmin_warning = true;
2505  }
2506  }
2507 
2508  if (ata_debugmode > 1)
2509  pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :""));
2510 
2511  m_usr_options = false;
2512  if (*options) {
2513  // Save user options
2514  m_options = options; m_usr_options = true;
2515  }
2516  else if (port >= 0)
2517  // RAID: SMART_* and SCSI_MINIPORT
2518  m_options = "s3";
2519  else {
2520  // Set default options according to Windows version
2521  static const char * def_options = ata_get_def_options();
2522  m_options = def_options;
2523  }
2524 
2525  // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2526  m_port = port;
2527  if (port < 0)
2528  return true;
2529 
2530  // 3ware RAID: Get port map
2531  GETVERSIONINPARAMS_EX vers_ex;
2532  int devmap = smart_get_version(h, &vers_ex);
2533 
2534  // 3ware RAID if vendor id present
2535  m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
2536 
2537  unsigned long portmap = 0;
2538  if (port >= 0 && devmap >= 0) {
2539  // 3ware RAID: check vendor id
2540  if (!m_is_3ware) {
2541  pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2542  "This is no 3ware 9000 controller or driver has no SMART support.\n",
2543  vers_ex.wIdentifier);
2544  devmap = -1;
2545  }
2546  else
2547  portmap = vers_ex.dwDeviceMapEx;
2548  }
2549  if (devmap < 0) {
2550  pout("%s: ATA driver has no SMART support\n", devpath);
2551  if (!is_permissive()) {
2552  close();
2553  return set_err(ENOSYS);
2554  }
2555  devmap = 0x0f;
2556  }
2557  m_smartver_state = 1;
2558 
2559  {
2560  // 3ware RAID: update devicemap first
2561 
2562  if (!update_3ware_devicemap_ioctl(h)) {
2563  if ( smart_get_version(h, &vers_ex) >= 0
2564  && vers_ex.wIdentifier == SMART_VENDOR_3WARE )
2565  portmap = vers_ex.dwDeviceMapEx;
2566  }
2567  // Check port existence
2568  if (!(portmap & (1L << port))) {
2569  if (!is_permissive()) {
2570  close();
2571  return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
2572  }
2573  }
2574  }
2575 
2576  return true;
2577 }
2578 
2579 
2580 /////////////////////////////////////////////////////////////////////////////
2581 
2582 // Interface to ATA devices
2584 {
2585  // No multi-sector support for now, see above
2586  // warning about IOCTL_ATA_PASS_THROUGH
2587  if (!ata_cmd_is_supported(in,
2591  )
2592  return false;
2593 
2594  // 3ware RAID: SMART DISABLE without port number disables SMART functions
2595  if ( m_is_3ware && m_port < 0
2596  && in.in_regs.command == ATA_SMART_CMD
2598  return set_err(ENOSYS, "SMART DISABLE requires 3ware port number");
2599 
2600  // Determine ioctl functions valid for this ATA cmd
2601  const char * valid_options = 0;
2602 
2603  switch (in.in_regs.command) {
2604  case ATA_IDENTIFY_DEVICE:
2606  // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2607  // and SCSI_MINIPORT_* if requested by user
2608  valid_options = (m_usr_options ? "saimf" : "saif");
2609  break;
2610 
2611  case ATA_CHECK_POWER_MODE:
2612  // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2613  valid_options = "pai3";
2614  break;
2615 
2616  case ATA_SMART_CMD:
2617  switch (in.in_regs.features) {
2618  case ATA_SMART_READ_VALUES:
2620  case ATA_SMART_AUTOSAVE:
2621  case ATA_SMART_ENABLE:
2622  case ATA_SMART_DISABLE:
2624  // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2625  // and SCSI_MINIPORT_* if requested by user
2626  valid_options = (m_usr_options ? "saimf" : "saif");
2627  break;
2628 
2630  // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2631  valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ?
2632  "saim3" : "aim3");
2633  break;
2634 
2636  // SMART_RCV_DRIVE_DATA does not support READ_LOG
2637  // Try SCSI_MINIPORT also to skip buggy class driver
2638  // SMART functions do not support multi sector I/O.
2639  if (in.size == 512)
2640  valid_options = (m_usr_options ? "saim3" : "aim3");
2641  else
2642  valid_options = "a";
2643  break;
2644 
2646  // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2647  // but SCSI_MINIPORT_* only if requested by user and single sector.
2648  valid_options = (in.size == 512 && m_usr_options ? "am" : "a");
2649  break;
2650 
2651  case ATA_SMART_STATUS:
2652  valid_options = (m_usr_options ? "saimf" : "saif");
2653  break;
2654 
2655  default:
2656  // Unknown SMART command, handle below
2657  break;
2658  }
2659  break;
2660 
2661  default:
2662  // Other ATA command, handle below
2663  break;
2664  }
2665 
2666  if (!valid_options) {
2667  // No special ATA command found above, select a generic pass through ioctl.
2668  if (!( in.direction == ata_cmd_in::no_data
2669  || (in.direction == ata_cmd_in::data_in && in.size == 512))
2670  || in.in_regs.is_48bit_cmd() )
2671  // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2672  valid_options = "a";
2673  else
2674  // ATA/IDE_PASS_THROUGH
2675  valid_options = "ai";
2676  }
2677 
2678  if (!m_admin) {
2679  // Restrict to IOCTL_STORAGE_*
2680  if (strchr(valid_options, 'f'))
2681  valid_options = "f";
2682  else if (strchr(valid_options, 'p'))
2683  valid_options = "p";
2684  else
2685  return set_err(ENOSYS, "Function requires admin rights");
2686  }
2687 
2688  // Set IDEREGS
2689  IDEREGS regs, prev_regs;
2690  {
2691  const ata_in_regs & lo = in.in_regs;
2692  regs.bFeaturesReg = lo.features;
2693  regs.bSectorCountReg = lo.sector_count;
2694  regs.bSectorNumberReg = lo.lba_low;
2695  regs.bCylLowReg = lo.lba_mid;
2696  regs.bCylHighReg = lo.lba_high;
2697  regs.bDriveHeadReg = lo.device;
2698  regs.bCommandReg = lo.command;
2699  regs.bReserved = 0;
2700  }
2701  if (in.in_regs.is_48bit_cmd()) {
2702  const ata_in_regs & hi = in.in_regs.prev;
2703  prev_regs.bFeaturesReg = hi.features;
2704  prev_regs.bSectorCountReg = hi.sector_count;
2705  prev_regs.bSectorNumberReg = hi.lba_low;
2706  prev_regs.bCylLowReg = hi.lba_mid;
2707  prev_regs.bCylHighReg = hi.lba_high;
2708  prev_regs.bDriveHeadReg = hi.device;
2709  prev_regs.bCommandReg = hi.command;
2710  prev_regs.bReserved = 0;
2711  }
2712 
2713  // Set data direction
2714  int datasize = 0;
2715  char * data = 0;
2716  switch (in.direction) {
2717  case ata_cmd_in::no_data:
2718  break;
2719  case ata_cmd_in::data_in:
2720  datasize = (int)in.size;
2721  data = (char *)in.buffer;
2722  break;
2723  case ata_cmd_in::data_out:
2724  datasize = -(int)in.size;
2725  data = (char *)in.buffer;
2726  break;
2727  default:
2728  return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d",
2729  (int)in.direction);
2730  }
2731 
2732 
2733  // Try all valid ioctls in the order specified in m_options
2734  bool powered_up = false;
2735  bool out_regs_set = false;
2736  bool id_is_cached = false;
2737  const char * options = m_options.c_str();
2738 
2739  for (int i = 0; ; i++) {
2740  char opt = options[i];
2741 
2742  if (!opt) {
2743  if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) {
2744  // Power up reported by GetDevicePowerState() and no ioctl available
2745  // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2746  regs.bSectorCountReg = 0xff;
2747  out_regs_set = true;
2748  break;
2749  }
2750  // No IOCTL found
2751  return set_err(ENOSYS);
2752  }
2753  if (!strchr(valid_options, opt))
2754  // Invalid for this command
2755  continue;
2756 
2757  errno = 0;
2758  assert( datasize == 0 || datasize == 512
2759  || (datasize == -512 && strchr("am", opt))
2760  || (datasize > 512 && opt == 'a'));
2761  int rc;
2762  switch (opt) {
2763  default: assert(0);
2764  case 's':
2765  // call SMART_GET_VERSION once for each drive
2766  if (m_smartver_state > 1) {
2767  rc = -1; errno = ENOSYS;
2768  break;
2769  }
2770  if (!m_smartver_state) {
2771  assert(m_port == -1);
2772  GETVERSIONINPARAMS_EX vers_ex;
2773  if (smart_get_version(get_fh(), &vers_ex) < 0) {
2774  if (!failuretest_permissive) {
2775  m_smartver_state = 2;
2776  rc = -1; errno = ENOSYS;
2777  break;
2778  }
2780  }
2781  else {
2782  // 3ware RAID if vendor id present
2783  m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE);
2784  }
2785 
2786  m_smartver_state = 1;
2787  }
2788  rc = smart_ioctl(get_fh(), &regs, data, datasize, m_port);
2789  out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
2790  id_is_cached = (m_port < 0); // Not cached by 3ware driver
2791  break;
2792  case 'm':
2793  rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
2794  id_is_cached = (m_port < 0);
2795  break;
2796  case 'a':
2797  rc = ata_pass_through_ioctl(get_fh(), &regs,
2798  (in.in_regs.is_48bit_cmd() ? &prev_regs : 0),
2799  data, datasize);
2800  out_regs_set = true;
2801  break;
2802  case 'i':
2803  rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
2804  out_regs_set = true;
2805  break;
2806  case 'f':
2807  if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
2809  if (rc == 0 && m_phydrive >= 0)
2811  id_is_cached = true;
2812  }
2813  else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
2814  case ATA_SMART_READ_VALUES:
2815  rc = storage_predict_failure_ioctl(get_fh(), data);
2816  if (rc > 0)
2817  rc = 0;
2818  break;
2819  case ATA_SMART_ENABLE:
2820  rc = 0;
2821  break;
2822  case ATA_SMART_STATUS:
2824  if (rc == 0) {
2825  // Good SMART status
2826  out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f;
2827  }
2828  else if (rc > 0) {
2829  // Bad SMART status
2830  out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4;
2831  rc = 0;
2832  }
2833  break;
2834  default:
2835  errno = ENOSYS; rc = -1;
2836  }
2837  else {
2838  errno = ENOSYS; rc = -1;
2839  }
2840  break;
2841  case '3':
2842  rc = ata_via_3ware_miniport_ioctl(get_fh(), &regs, data, datasize, m_port);
2843  out_regs_set = true;
2844  break;
2845  case 'p':
2846  assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0);
2848  if (rc == 0) {
2849  // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2850  // spin up the drive => simulate ATA result STANDBY.
2851  regs.bSectorCountReg = 0x00;
2852  out_regs_set = true;
2853  }
2854  else if (rc > 0) {
2855  // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2856  // only if it is selected by the device driver => try a passthrough ioctl to get the
2857  // actual mode, if none available simulate ACTIVE/IDLE.
2858  powered_up = true;
2859  rc = -1; errno = ENOSYS;
2860  }
2861  break;
2862  }
2863 
2864  if (!rc)
2865  // Working ioctl found
2866  break;
2867 
2868  if (errno != ENOSYS)
2869  // Abort on I/O error
2870  return set_err(errno);
2871 
2872  out_regs_set = false;
2873  // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2874  }
2875 
2876  // Return IDEREGS if set
2877  if (out_regs_set) {
2878  ata_out_regs & lo = out.out_regs;
2879  lo.error = regs.bFeaturesReg;
2880  lo.sector_count = regs.bSectorCountReg;
2881  lo.lba_low = regs.bSectorNumberReg;
2882  lo.lba_mid = regs.bCylLowReg;
2883  lo.lba_high = regs.bCylHighReg;
2884  lo.device = regs.bDriveHeadReg;
2885  lo.status = regs.bCommandReg;
2886  if (in.in_regs.is_48bit_cmd()) {
2887  ata_out_regs & hi = out.out_regs.prev;
2888  hi.sector_count = prev_regs.bSectorCountReg;
2889  hi.lba_low = prev_regs.bSectorNumberReg;
2890  hi.lba_mid = prev_regs.bCylLowReg;
2891  hi.lba_high = prev_regs.bCylHighReg;
2892  }
2893  }
2894 
2897  // Update ata_identify_is_cached() result according to ioctl used.
2898  m_id_is_cached = id_is_cached;
2899 
2900  return true;
2901 }
2902 
2903 // Return true if OS caches the ATA identify sector
2905 {
2906  return m_id_is_cached;
2907 }
2908 
2909 
2910 //////////////////////////////////////////////////////////////////////
2911 // csmi_ata_device
2912 
2914 {
2915  // Get driver info to check CSMI support
2916  CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
2917  memset(&driver_info_buf, 0, sizeof(driver_info_buf));
2918  if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf)))
2919  return false;
2920 
2921  if (scsi_debugmode > 1) {
2922  const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information;
2923  pout("CSMI_SAS_DRIVER_INFO:\n");
2924  pout(" Name: \"%.81s\"\n", driver_info.szName);
2925  pout(" Description: \"%.81s\"\n", driver_info.szDescription);
2926  pout(" Revision: %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision);
2927  }
2928 
2929  // Get Phy info
2930  CSMI_SAS_PHY_INFO_BUFFER phy_info_buf;
2931  memset(&phy_info_buf, 0, sizeof(phy_info_buf));
2932  if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf)))
2933  return false;
2934 
2935  phy_info = phy_info_buf.Information;
2936 
2937  const int max_number_of_phys = sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]);
2938  if (phy_info.bNumberOfPhys > max_number_of_phys)
2939  return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys);
2940 
2941  if (scsi_debugmode > 1) {
2942  pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys);
2943  for (int i = 0; i < max_number_of_phys; i++) {
2944  const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
2945  const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached;
2946  if (id.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED)
2947  continue;
2948 
2949  pout("Phy[%d] Port: 0x%02x\n", i, pe.bPortIdentifier);
2950  pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType);
2951  pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol);
2952  pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol);
2953  pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier);
2954  const unsigned char * b = id.bSASAddress;
2955  pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2956  b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
2957  b = at.bSASAddress;
2958  pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2959  b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
2960  }
2961  }
2962 
2963  return true;
2964 }
2965 
2967 {
2968  CSMI_SAS_PHY_INFO phy_info;
2969  if (!get_phy_info(phy_info))
2970  return 0;
2971 
2972  unsigned ports_used = 0;
2973  for (unsigned i = 0; i < sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]); i++) {
2974  const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
2976  continue;
2978  continue;
2979  switch (pe.Attached.bTargetPortProtocol) {
2981  case CSMI_SAS_PROTOCOL_STP:
2982  break;
2983  default:
2984  continue;
2985  }
2986 
2987  if (pe.bPortIdentifier == 0xff)
2988  // Older (<= 9.*) Intel RST driver
2989  ports_used |= (1 << i);
2990  else
2991  ports_used |= (1 << pe.bPortIdentifier);
2992  }
2993 
2994  return ports_used;
2995 }
2996 
2997 
2999 {
3000  CSMI_SAS_PHY_INFO phy_info;
3001  if (!get_phy_info(phy_info))
3002  return false;
3003 
3004  // Find port
3005  int max_port = -1, port_index = -1;
3006  for (unsigned i = 0; i < sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0]); i++) {
3007  const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i];
3009  continue;
3010 
3011  if (pe.bPortIdentifier == 0xff) {
3012  // Older (<= 9.*) Intel RST driver
3013  max_port = phy_info.bNumberOfPhys - 1;
3014  if (i >= phy_info.bNumberOfPhys)
3015  break;
3016  if ((int)i != port)
3017  continue;
3018  }
3019  else {
3020  if (pe.bPortIdentifier > max_port)
3021  max_port = pe.bPortIdentifier;
3022  if (pe.bPortIdentifier != port)
3023  continue;
3024  }
3025 
3026  port_index = i;
3027  break;
3028  }
3029 
3030  if (port_index < 0) {
3031  if (port <= max_port)
3032  return set_err(ENOENT, "Port %d is disabled", port);
3033  else
3034  return set_err(ENOENT, "Port %d does not exist (#ports: %d)", port,
3035  max_port + 1);
3036  }
3037 
3038  const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[port_index];
3040  return set_err(ENOENT, "No device on port %d", port);
3041 
3042  switch (phy_ent.Attached.bTargetPortProtocol) {
3044  case CSMI_SAS_PROTOCOL_STP:
3045  break;
3046  default:
3047  return set_err(ENOENT, "No SATA device on port %d (protocol: %d)",
3048  port, phy_ent.Attached.bTargetPortProtocol);
3049  }
3050 
3051  m_phy_ent = phy_ent;
3052  return true;
3053 }
3054 
3055 
3057 {
3058  if (!ata_cmd_is_supported(in,
3063  "CMSI")
3064  )
3065  return false;
3066 
3067  // Create buffer with appropriate size
3068  raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size);
3069  CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data();
3070 
3071  // Set addresses from Phy info
3072  CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters;
3073  const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent();
3074  pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier;
3075  pthru.bPortIdentifier = phy_ent.bPortIdentifier;
3076  memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress,
3077  sizeof(pthru.bDestinationSASAddress));
3079 
3080  // Set transfer mode
3081  switch (in.direction) {
3082  case ata_cmd_in::no_data:
3084  break;
3085  case ata_cmd_in::data_in:
3087  pthru.uDataLength = in.size;
3088  break;
3089  case ata_cmd_in::data_out:
3091  pthru.uDataLength = in.size;
3092  memcpy(pthru_buf->bDataBuffer, in.buffer, in.size);
3093  break;
3094  default:
3095  return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d",
3096  (int)in.direction);
3097  }
3098 
3099  // Set host-to-device FIS
3100  {
3101  unsigned char * fis = pthru.bCommandFIS;
3102  const ata_in_regs & lo = in.in_regs;
3103  const ata_in_regs & hi = in.in_regs.prev;
3104  fis[ 0] = 0x27; // Type: host-to-device FIS
3105  fis[ 1] = 0x80; // Bit7: Update command register
3106  fis[ 2] = lo.command;
3107  fis[ 3] = lo.features;
3108  fis[ 4] = lo.lba_low;
3109  fis[ 5] = lo.lba_mid;
3110  fis[ 6] = lo.lba_high;
3111  fis[ 7] = lo.device;
3112  fis[ 8] = hi.lba_low;
3113  fis[ 9] = hi.lba_mid;
3114  fis[10] = hi.lba_high;
3115  fis[11] = hi.features;
3116  fis[12] = lo.sector_count;
3117  fis[13] = hi.sector_count;
3118  }
3119 
3120  // Call ioctl
3121  if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) {
3122  return false;
3123  }
3124 
3125  // Get device-to-host FIS
3126  {
3127  const unsigned char * fis = pthru_buf->Status.bStatusFIS;
3128  ata_out_regs & lo = out.out_regs;
3129  lo.status = fis[ 2];
3130  lo.error = fis[ 3];
3131  lo.lba_low = fis[ 4];
3132  lo.lba_mid = fis[ 5];
3133  lo.lba_high = fis[ 6];
3134  lo.device = fis[ 7];
3135  lo.sector_count = fis[12];
3136  if (in.in_regs.is_48bit_cmd()) {
3137  ata_out_regs & hi = out.out_regs.prev;
3138  hi.lba_low = fis[ 8];
3139  hi.lba_mid = fis[ 9];
3140  hi.lba_high = fis[10];
3141  hi.sector_count = fis[13];
3142  }
3143  }
3144 
3145  // Get data
3146  if (in.direction == ata_cmd_in::data_in)
3147  // TODO: Check ptru_buf->Status.uDataBytes
3148  memcpy(in.buffer, pthru_buf->bDataBuffer, in.size);
3149 
3150  return true;
3151 }
3152 
3153 
3154 //////////////////////////////////////////////////////////////////////
3155 // win_csmi_device
3156 
3158  const char * req_type)
3159 : smart_device(intf, dev_name, "ata", req_type),
3160  m_fh(INVALID_HANDLE_VALUE), m_port(-1)
3161 {
3162 }
3163 
3165 {
3166  if (m_fh != INVALID_HANDLE_VALUE)
3167  CloseHandle(m_fh);
3168 }
3169 
3171 {
3172  return (m_fh != INVALID_HANDLE_VALUE);
3173 }
3174 
3176 {
3177  if (m_fh == INVALID_HANDLE_VALUE)
3178  return true;
3179  BOOL rc = CloseHandle(m_fh);
3180  m_fh = INVALID_HANDLE_VALUE;
3181  return !!rc;
3182 }
3183 
3184 
3186 {
3187  // Parse name
3188  unsigned contr_no = ~0, port = ~0; int nc = -1;
3189  const char * name = skipdev(get_dev_name());
3190  if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &port, &nc) >= 0
3191  && nc == (int)strlen(name) && contr_no <= 9 && port < 32) )
3192  return set_err(EINVAL);
3193 
3194  // Open controller handle
3195  char devpath[30];
3196  snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no);
3197 
3198  HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
3199  FILE_SHARE_READ|FILE_SHARE_WRITE,
3200  (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0);
3201 
3202  if (h == INVALID_HANDLE_VALUE) {
3203  long err = GetLastError();
3204  if (err == ERROR_FILE_NOT_FOUND)
3205  set_err(ENOENT, "%s: not found", devpath);
3206  else if (err == ERROR_ACCESS_DENIED)
3207  set_err(EACCES, "%s: access denied", devpath);
3208  else
3209  set_err(EIO, "%s: Error=%ld", devpath, err);
3210  return false;
3211  }
3212 
3213  if (scsi_debugmode > 1)
3214  pout(" %s: successfully opened\n", devpath);
3215 
3216  m_fh = h;
3217  m_port = port;
3218  return true;
3219 }
3220 
3221 
3223 {
3224  if (!open_scsi())
3225  return false;
3226 
3227  // Get Phy info for this drive
3228  if (!select_port(m_port)) {
3229  close();
3230  return false;
3231  }
3232 
3233  return true;
3234 }
3235 
3236 
3237 bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
3238  unsigned csmi_bufsiz)
3239 {
3240  // Determine signature
3241  const char * sig;
3242  switch (code) {
3243  case CC_CSMI_SAS_GET_DRIVER_INFO:
3244  sig = CSMI_ALL_SIGNATURE; break;
3245  case CC_CSMI_SAS_GET_PHY_INFO:
3246  case CC_CSMI_SAS_STP_PASSTHRU:
3247  sig = CSMI_SAS_SIGNATURE; break;
3248  default:
3249  return set_err(ENOSYS, "Unknown CSMI code=%u", code);
3250  }
3251 
3252  // Set header
3253  csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER);
3254  strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature));
3255  csmi_buffer->Timeout = CSMI_SAS_TIMEOUT;
3256  csmi_buffer->ControlCode = code;
3257  csmi_buffer->ReturnCode = 0;
3258  csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER);
3259 
3260  // Call function
3261  DWORD num_out = 0;
3262  if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT,
3263  csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) {
3264  long err = GetLastError();
3265  if (scsi_debugmode)
3266  pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err);
3267  if ( err == ERROR_INVALID_FUNCTION
3268  || err == ERROR_NOT_SUPPORTED
3269  || err == ERROR_DEV_NOT_EXIST)
3270  return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err);
3271  else
3272  return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err);
3273  }
3274 
3275  // Check result
3276  if (csmi_buffer->ReturnCode) {
3277  if (scsi_debugmode) {
3278  pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3279  code, (unsigned)csmi_buffer->ReturnCode);
3280  }
3281  return set_err(EIO, "CSMI(%u) failed with ReturnCode=%u", code, (unsigned)csmi_buffer->ReturnCode);
3282  }
3283 
3284  if (scsi_debugmode > 1)
3285  pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out);
3286 
3287  return true;
3288 }
3289 
3290 
3291 /////////////////////////////////////////////////////////////////////////////
3292 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3293 // Only supported in NT and later
3294 /////////////////////////////////////////////////////////////////////////////
3295 
3297  const char * dev_name, const char * req_type)
3298 : smart_device(intf, dev_name, "scsi", req_type)
3299 {
3300 }
3301 
3303 {
3304  const char * name = skipdev(get_dev_name()); int len = strlen(name);
3305  // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3306  char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
3307  if ( sscanf(name, "sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
3308  && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) {
3309  return open(sdxy_to_phydrive(drive), -1, -1, sub_addr);
3310  }
3311  // pd<m>,N => Physical drive <m>, RAID port N
3312  int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
3313  if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1
3314  && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) {
3315  return open(pd_num, -1, -1, sub_addr);
3316  }
3317  // [a-zA-Z]: => Physical drive behind logical drive 0-25
3318  int logdrive = drive_letter(name);
3319  if (logdrive >= 0) {
3320  return open(-1, logdrive, -1, -1);
3321  }
3322  // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3323  int tape_num = -1; n1 = -1;
3324  if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3325  return open(-1, -1, tape_num, -1);
3326  }
3327  tape_num = -1; n1 = -1;
3328  if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3329  return open(-1, -1, tape_num, -1);
3330  }
3331  // tape<m> => tape drive <m>
3332  tape_num = -1; n1 = -1;
3333  if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) {
3334  return open(-1, -1, tape_num, -1);
3335  }
3336 
3337  return set_err(EINVAL);
3338 }
3339 
3340 bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/)
3341 {
3342  char b[128];
3343  b[sizeof(b) - 1] = '\0';
3344  if (pd_num >= 0)
3345  snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num);
3346  else if (ld_num >= 0)
3347  snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num);
3348  else if (tape_num >= 0)
3349  snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num);
3350  else {
3351  set_err(EINVAL);
3352  return false;
3353  }
3354 
3355  // Open device
3356  HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE,
3357  FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
3358  OPEN_EXISTING, 0, 0);
3359  if (h == INVALID_HANDLE_VALUE) {
3360  set_err(ENODEV, "%s: Open failed, Error=%u", b, (unsigned)GetLastError());
3361  return false;
3362  }
3363  set_fh(h);
3364  return true;
3365 }
3366 
3367 
3368 typedef struct {
3369  SCSI_PASS_THROUGH_DIRECT spt;
3370  ULONG Filler;
3371  UCHAR ucSenseBuf[64];
3373 
3374 
3375 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3376 // Used if DataTransferLength not supported by *_DIRECT.
3377 static long scsi_pass_through_indirect(HANDLE h,
3379 {
3380  struct SCSI_PASS_THROUGH_WITH_BUFFERS {
3381  SCSI_PASS_THROUGH spt;
3382  ULONG Filler;
3383  UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)];
3384  UCHAR ucDataBuf[512];
3385  };
3386 
3387  SCSI_PASS_THROUGH_WITH_BUFFERS sb;
3388  memset(&sb, 0, sizeof(sb));
3389 
3390  // DATA_OUT not implemented yet
3391  if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN
3392  && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf)))
3393  return ERROR_INVALID_PARAMETER;
3394 
3395  sb.spt.Length = sizeof(sb.spt);
3396  sb.spt.CdbLength = sbd->spt.CdbLength;
3397  memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb));
3398  sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3399  sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);
3400  sb.spt.DataIn = sbd->spt.DataIn;
3401  sb.spt.DataTransferLength = sbd->spt.DataTransferLength;
3402  sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
3403  sb.spt.TimeOutValue = sbd->spt.TimeOutValue;
3404 
3405  DWORD num_out;
3406  if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH,
3407  &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3408  return GetLastError();
3409 
3410  sbd->spt.ScsiStatus = sb.spt.ScsiStatus;
3411  if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION)
3412  memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf));
3413 
3414  sbd->spt.DataTransferLength = sb.spt.DataTransferLength;
3415  if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0)
3416  memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength);
3417  return 0;
3418 }
3419 
3420 
3421 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3423 {
3424  int report = scsi_debugmode; // TODO
3425 
3426  if (report > 0) {
3427  int k, j;
3428  const unsigned char * ucp = iop->cmnd;
3429  const char * np;
3430  char buff[256];
3431  const int sz = (int)sizeof(buff);
3432 
3433  np = scsi_get_opcode_name(ucp[0]);
3434  j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3435  for (k = 0; k < (int)iop->cmnd_len; ++k)
3436  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3437  if ((report > 1) &&
3438  (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3439  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3440 
3441  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3442  "data, len=%d%s:\n", (int)iop->dxfer_len,
3443  (trunc ? " [only first 256 bytes shown]" : ""));
3444  dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3445  }
3446  else
3447  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3448  pout("%s", buff);
3449  }
3450 
3452  if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
3453  set_err(EINVAL, "cmnd_len too large");
3454  return false;
3455  }
3456 
3457  memset(&sb, 0, sizeof(sb));
3458  sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
3459  sb.spt.CdbLength = iop->cmnd_len;
3460  memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
3461  sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3462  sb.spt.SenseInfoOffset =
3463  offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
3464  sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
3465 
3466  bool direct = true;
3467  switch (iop->dxfer_dir) {
3468  case DXFER_NONE:
3469  sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3470  break;
3471  case DXFER_FROM_DEVICE:
3472  sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3473  sb.spt.DataTransferLength = iop->dxfer_len;
3474  sb.spt.DataBuffer = iop->dxferp;
3475  // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3476  // transfers (needed for SMART STATUS check of JMicron USB bridges)
3477  if (sb.spt.DataTransferLength == 1)
3478  direct = false;
3479  break;
3480  case DXFER_TO_DEVICE:
3481  sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3482  sb.spt.DataTransferLength = iop->dxfer_len;
3483  sb.spt.DataBuffer = iop->dxferp;
3484  break;
3485  default:
3486  set_err(EINVAL, "bad dxfer_dir");
3487  return false;
3488  }
3489 
3490  long err = 0;
3491  if (direct) {
3492  DWORD num_out;
3493  if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT,
3494  &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3495  err = GetLastError();
3496  }
3497  else
3498  err = scsi_pass_through_indirect(get_fh(), &sb);
3499 
3500  if (err)
3501  return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO),
3502  "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3503  (direct ? "_DIRECT" : ""), err);
3504 
3505  iop->scsi_status = sb.spt.ScsiStatus;
3507  int slen = sb.ucSenseBuf[7] + 8;
3508 
3509  if (slen > (int)sizeof(sb.ucSenseBuf))
3510  slen = sizeof(sb.ucSenseBuf);
3511  if (slen > (int)iop->max_sense_len)
3512  slen = iop->max_sense_len;
3513  memcpy(iop->sensep, sb.ucSenseBuf, slen);
3514  iop->resp_sense_len = slen;
3515  if (report) {
3516  if (report > 1) {
3517  pout(" >>> Sense buffer, len=%d:\n", slen);
3518  dStrHex(iop->sensep, slen , 1);
3519  }
3520  if ((iop->sensep[0] & 0x7f) > 0x71)
3521  pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3522  iop->scsi_status, iop->sensep[1] & 0xf,
3523  iop->sensep[2], iop->sensep[3]);
3524  else
3525  pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3526  iop->scsi_status, iop->sensep[2] & 0xf,
3527  iop->sensep[12], iop->sensep[13]);
3528  }
3529  } else
3530  iop->resp_sense_len = 0;
3531 
3532  if (iop->dxfer_len > sb.spt.DataTransferLength)
3533  iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3534  else
3535  iop->resid = 0;
3536 
3537  if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3538  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3539  pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
3540  (trunc ? " [only first 256 bytes shown]" : ""));
3541  dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3542  }
3543  return true;
3544 }
3545 
3546 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3547 static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop)
3548 {
3549  int report = scsi_debugmode; // TODO
3550 
3551  if (report > 0) {
3552  int k, j;
3553  const unsigned char * ucp = iop->cmnd;
3554  const char * np;
3555  char buff[256];
3556  const int sz = (int)sizeof(buff);
3557 
3558  np = scsi_get_opcode_name(ucp[0]);
3559  j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
3560  for (k = 0; k < (int)iop->cmnd_len; ++k)
3561  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
3562  if ((report > 1) &&
3563  (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
3564  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3565 
3566  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing "
3567  "data, len=%d%s:\n", (int)iop->dxfer_len,
3568  (trunc ? " [only first 256 bytes shown]" : ""));
3569  dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3570  }
3571  else
3572  j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
3573  pout("%s", buff);
3574  }
3575 
3577  if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
3578  return EINVAL;
3579  }
3580 
3581  memset(&sb, 0, sizeof(sb));
3582  sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
3583  //sb.spt.PathId = 0;
3584  sb.spt.TargetId = targetid;
3585  //sb.spt.Lun = 0;
3586  sb.spt.CdbLength = iop->cmnd_len;
3587  memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
3588  sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
3589  sb.spt.SenseInfoOffset =
3590  offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
3591  sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
3592 
3593  bool direct = true;
3594  switch (iop->dxfer_dir) {
3595  case DXFER_NONE:
3596  sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
3597  break;
3598  case DXFER_FROM_DEVICE:
3599  sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
3600  sb.spt.DataTransferLength = iop->dxfer_len;
3601  sb.spt.DataBuffer = iop->dxferp;
3602  // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3603  // transfers (needed for SMART STATUS check of JMicron USB bridges)
3604  if (sb.spt.DataTransferLength == 1)
3605  direct = false;
3606  break;
3607  case DXFER_TO_DEVICE:
3608  sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
3609  sb.spt.DataTransferLength = iop->dxfer_len;
3610  sb.spt.DataBuffer = iop->dxferp;
3611  break;
3612  default:
3613  return EINVAL;
3614  }
3615 
3616  long err = 0;
3617  if (direct) {
3618  DWORD num_out;
3619  if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
3620  &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
3621  err = GetLastError();
3622  }
3623  else
3624  err = scsi_pass_through_indirect(fd, &sb);
3625 
3626  if (err)
3627  {
3628  return err;
3629  }
3630 
3631  iop->scsi_status = sb.spt.ScsiStatus;
3633  int slen = sb.ucSenseBuf[7] + 8;
3634 
3635  if (slen > (int)sizeof(sb.ucSenseBuf))
3636  slen = sizeof(sb.ucSenseBuf);
3637  if (slen > (int)iop->max_sense_len)
3638  slen = iop->max_sense_len;
3639  memcpy(iop->sensep, sb.ucSenseBuf, slen);
3640  iop->resp_sense_len = slen;
3641  if (report) {
3642  if (report > 1) {
3643  pout(" >>> Sense buffer, len=%d:\n", slen);
3644  dStrHex(iop->sensep, slen , 1);
3645  }
3646  if ((iop->sensep[0] & 0x7f) > 0x71)
3647  pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3648  iop->scsi_status, iop->sensep[1] & 0xf,
3649  iop->sensep[2], iop->sensep[3]);
3650  else
3651  pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3652  iop->scsi_status, iop->sensep[2] & 0xf,
3653  iop->sensep[12], iop->sensep[13]);
3654  }
3655  } else
3656  iop->resp_sense_len = 0;
3657 
3658  if (iop->dxfer_len > sb.spt.DataTransferLength)
3659  iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
3660  else
3661  iop->resid = 0;
3662 
3663  if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
3664  int trunc = (iop->dxfer_len > 256) ? 1 : 0;
3665  pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop->dxfer_len, iop->resid,
3666  (trunc ? " [only first 256 bytes shown]" : ""));
3667  dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
3668  }
3669 
3670  return 0;
3671 }
3672 
3673 // Areca RAID Controller(SAS Device)
3674 win_areca_scsi_device::win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
3675 : smart_device(intf, dev_name, "areca", "areca")
3676 {
3677  set_fh(INVALID_HANDLE_VALUE);
3678  set_disknum(disknum);
3679  set_encnum(encnum);
3680  set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
3681 }
3682 
3684 {
3685  HANDLE hFh;
3686 
3687  if( is_open() )
3688  {
3689  return true;
3690  }
3691  hFh = CreateFile( get_dev_name(),
3692  GENERIC_READ|GENERIC_WRITE,
3693  FILE_SHARE_READ|FILE_SHARE_WRITE,
3694  NULL,
3695  OPEN_EXISTING,
3696  0,
3697  NULL );
3698  if(hFh == INVALID_HANDLE_VALUE)
3699  {
3700  return false;
3701  }
3702 
3703  set_fh(hFh);
3704  return true;
3705 }
3706 
3708 {
3709  return this;
3710 }
3711 
3713 {
3714  int ioctlreturn = 0;
3715 
3716  ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
3717  if ( ioctlreturn || iop->scsi_status )
3718  {
3719  ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
3720  if ( ioctlreturn || iop->scsi_status )
3721  {
3722  // errors found
3723  return -1;
3724  }
3725  }
3726 
3727  return ioctlreturn;
3728 }
3729 
3731 {
3732 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3733  int ctlrnum = -1;
3734  char mutexstr[64];
3735 
3736  if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
3737  return set_err(EINVAL, "unable to parse device name");
3738 
3739  snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
3740  m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3741  if ( m_mutex == NULL )
3742  {
3743  return set_err(EIO, "CreateMutex failed");
3744  }
3745 
3746  // atomic access to driver
3747  WaitForSingleObject(m_mutex, INFINITE);
3748 
3749  return true;
3750 }
3751 
3752 
3754 {
3755  if( m_mutex != NULL)
3756  {
3757  ReleaseMutex(m_mutex);
3758  CloseHandle(m_mutex);
3759  }
3760 
3761  return true;
3762 }
3763 
3764 
3765 // Areca RAID Controller(SATA Disk)
3766 win_areca_ata_device::win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
3767 : smart_device(intf, dev_name, "areca", "areca")
3768 {
3769  set_fh(INVALID_HANDLE_VALUE);
3770  set_disknum(disknum);
3771  set_encnum(encnum);
3772  set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
3773 }
3774 
3776 {
3777  HANDLE hFh;
3778 
3779  if( is_open() )
3780  {
3781  return true;
3782  }
3783  hFh = CreateFile( get_dev_name(),
3784  GENERIC_READ|GENERIC_WRITE,
3785  FILE_SHARE_READ|FILE_SHARE_WRITE,
3786  NULL,
3787  OPEN_EXISTING,
3788  0,
3789  NULL );
3790  if(hFh == INVALID_HANDLE_VALUE)
3791  {
3792  return false;
3793  }
3794 
3795  set_fh(hFh);
3796  return true;
3797 }
3798 
3800 {
3801  int is_ata = 1;
3802 
3803  // autodetect device type
3804  is_ata = arcmsr_get_dev_type();
3805  if(is_ata < 0)
3806  {
3807  set_err(EIO);
3808  return this;
3809  }
3810 
3811  if(is_ata == 1)
3812  {
3813  // SATA device
3814  return this;
3815  }
3816 
3817  // SAS device
3819  close();
3820  delete this;
3821  newdev->open(); // TODO: Can possibly pass open fd
3822 
3823  return newdev.release();
3824 }
3825 
3827 {
3828  int ioctlreturn = 0;
3829 
3830  ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
3831  if ( ioctlreturn || iop->scsi_status )
3832  {
3833  ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
3834  if ( ioctlreturn || iop->scsi_status )
3835  {
3836  // errors found
3837  return -1;
3838  }
3839  }
3840 
3841  return ioctlreturn;
3842 }
3843 
3845 {
3846 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3847  int ctlrnum = -1;
3848  char mutexstr[64];
3849 
3850  if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
3851  return set_err(EINVAL, "unable to parse device name");
3852 
3853  snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
3854  m_mutex = CreateMutex(NULL, FALSE, mutexstr);
3855  if ( m_mutex == NULL )
3856  {
3857  return set_err(EIO, "CreateMutex failed");
3858  }
3859 
3860  // atomic access to driver
3861  WaitForSingleObject(m_mutex, INFINITE);
3862 
3863  return true;
3864 }
3865 
3866 
3868 {
3869  if( m_mutex != NULL)
3870  {
3871  ReleaseMutex(m_mutex);
3872  CloseHandle(m_mutex);
3873  }
3874 
3875  return true;
3876 }
3877 
3878 
3879 //////////////////////////////////////////////////////////////////////////////////////////////////
3880 
3881 
3882 } // namespace
3883 
3884 /////////////////////////////////////////////////////////////////////////////
3885 
3886 // Initialize platform interface and register with smi()
3887 void smart_interface::init()
3888 {
3889  {
3890  // Remove "." from DLL search path if supported
3891  // to prevent DLL preloading attacks
3892  BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR))
3893  GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
3894  if (SetDllDirectoryA_p)
3895  SetDllDirectoryA_p("");
3896  }
3897 
3898  static os_win32::win_smart_interface the_win_interface;
3899  smart_interface::set(&the_win_interface);
3900 }
3901 
3902 
3903 #ifndef __CYGWIN__
3904 
3905 // Get exe directory
3906 // (prototype in utiliy.h)
3907 std::string get_exe_dir()
3908 {
3909  char path[MAX_PATH];
3910  // Get path of this exe
3911  if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path)))
3912  throw std::runtime_error("GetModuleFileName() failed");
3913  // Replace backslash by slash
3914  int sl = -1;
3915  for (int i = 0; path[i]; i++)
3916  if (path[i] == '\\') {
3917  path[i] = '/'; sl = i;
3918  }
3919  // Remove filename
3920  if (sl >= 0)
3921  path[sl] = 0;
3922  return path;
3923 }
3924 
3925 #endif
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3222
#define ATA_SMART_READ_LOG_SECTOR
Definition: atacmds.h:100
virtual int64_t get_timer_usec()
Get microseconds since some unspecified starting point.
#define ATA_SMART_WRITE_LOG_SECTOR
Definition: atacmds.h:101
#define CSMI_SAS_STP_UNSPECIFIED
Definition: csmisas.h:859
static const char * skipdev(const char *s)
Definition: os_win32.cpp:740
virtual bool ata_identify_is_cached() const
Return true if OS caches ATA identify sector.
Definition: os_win32.cpp:2904
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:424
#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG
Definition: os_win32.cpp:206
u16 s[6]
Definition: megaraid.h:97
#define assert(x)
Definition: os_win32.cpp:41
virtual int64_t get_timer_usec()
Get microseconds since some unspecified starting point.
Definition: os_win32.cpp:685
virtual std::string get_valid_custom_dev_types_str()
Return valid 'type' args accepted by above.
Definition: os_win32.cpp:843
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)
Call platform-specific CSMI ioctl.
Definition: os_win32.cpp:3237
u32 size
Definition: megaraid.h:79
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:260
UINT8 * sensep
Definition: scsicmds.h:124
void set_disknum(int disknum)
Definition: dev_areca.h:125
UCHAR bSectorNumberReg
Definition: os_os2.cpp:52
_STORAGE_QUERY_TYPE
Definition: os_win32.cpp:238
virtual smart_device * get_custom_smart_device(const char *name, const char *type)
Return device for platform specific 'type'.
Definition: os_win32.cpp:797
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for SAT or USB.
Definition: scsiata.cpp:1476
ata_in_regs prev
"previous content"
ata_identify_device m_ident_buf
Definition: os_win32.cpp:497
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:2064
ata_register lba_mid
static bool is_wow64()
Definition: os_win32.cpp:579
static int update_3ware_devicemap_ioctl(HANDLE hdevice)
Definition: os_win32.cpp:1669
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:1817
struct _SENDCMDINPARAMS_EX SENDCMDINPARAMS_EX
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:113
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:278
#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:1092
Smart pointer class for device pointers.
unsigned size() const
Definition: utility.h:163
#define CSMI_SAS_SIGNATURE
Definition: csmisas.h:714
static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io *iop)
Definition: os_win32.cpp:3547
ULONG DataBufferSize
Definition: os_win32.cpp:134
ata_register device
const char * scsi_get_opcode_name(UINT8 opcode)
Definition: scsicmds.cpp:176
static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize)
Definition: os_win32.cpp:1278
#define SYNCOBJNAME
int m_port
Port number.
Definition: os_win32.cpp:474
CSMI_SAS_IDENTIFY Attached
Definition: csmisas.h:1539
ata_register sector_count
ULONG_PTR DataBufferOffset
Definition: os_win32.cpp:161
#define CSMI_SAS_NO_DEVICE_ATTACHED
Definition: csmisas.h:725
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
Definition: os_win32.cpp:202
unsigned timeout
Definition: scsicmds.h:127
#define ATA_SMART_DISABLE
Definition: atacmds.h:104
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:3175
#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:2583
#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:1808
#define ATA_SMART_AUTOSAVE
Definition: atacmds.h:97
virtual std::string get_os_version_str()
Return info string about build host and/or OS version.
Definition: os_win32.cpp:594
device_info & set_info()
R/W access to device info struct.
#define snprintf
Definition: utility.h:68
virtual int arcmsr_get_dev_type()
Definition: dev_areca.cpp:350
#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
Definition: os_win32.cpp:197
const char * os_win32_cpp_cvsid
Definition: os_win32.cpp:104
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:3170
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:346
unsigned char ata_debugmode
Definition: atacmds.cpp:42
static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX *ata_version_ex=0)
Definition: os_win32.cpp:1140
virtual bool scsi_pass_through(scsi_cmnd_io *iop)
SCSI pass through.
Definition: os_win32.cpp:3422
size_t resp_sense_len
Definition: scsicmds.h:128
#define IOCTL_SCSI_MINIPORT_DISABLE_SMART
Definition: os_win32.cpp:200
UCHAR PreviousTaskFile[8]
Definition: os_win32.cpp:162
void push_back(smart_device *dev)
#define IOCTL_ATA_PASS_THROUGH
Definition: os_win32.cpp:148
#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:745
ata_register lba_mid
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3302
bool get_phy_info(CSMI_SAS_PHY_INFO &phy_info)
Get phy info.
Definition: os_win32.cpp:2913
bool nonempty(const void *data, int size)
Definition: utility.cpp:695
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:3157
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
Definition: os_win32.cpp:1056
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:93
ata_in_regs_48bit in_regs
Input registers.
UINT8 * dxferp
Definition: scsicmds.h:122
std::string get_exe_dir()
Definition: os_win32.cpp:3907
Definition: scsiata.cpp:102
UCHAR DataBuffer[1]
Definition: os_win32.cpp:135
ata_out_regs_48bit out_regs
Output registers.
UINT8 * cmnd
Definition: scsicmds.h:118
enum _STORAGE_PROPERTY_ID STORAGE_PROPERTY_ID
ptr_t data
Definition: megaraid.h:94
static int drive_letter(const char *s)
Definition: os_win32.cpp:730
static bool match(const char *pattern, const char *str)
static int run_cmd(const char *cmd, char *dataout, int outsize)
Definition: os_win32.cpp:1733
List of devices for DEVICESCAN.
enum ata_cmd_in::@27 direction
I/O direction.
device_type * release()
Return the pointer and release ownership.
#define ATA_CHECK_POWER_MODE
Definition: atacmds.h:71
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:338
#define IOCTL_STORAGE_QUERY_PROPERTY
Definition: os_win32.cpp:219
The platform interface abstraction.
static const char * ata_get_def_options(void)
Definition: os_win32.cpp:2378
static int get_device_power_state(HANDLE hdevice)
Definition: os_win32.cpp:2355
CSMI_SAS_DRIVER_INFO Information
Definition: csmisas.h:1026
static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:2041
static void set(smart_interface *intf)
Set interface to use, must be called from init().
static int smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, unsigned datasize, int port)
Definition: os_win32.cpp:1175
static int is_permissive()
Definition: os_win32.cpp:717
win_areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3766
__u8 bDestinationSASAddress[8]
Definition: csmisas.h:1679
long long int64_t
Definition: int64.h:51
static win_dev_type get_phy_drive_type(int drive)
Definition: os_win32.cpp:2142
#define ATA_FLAGS_DATA_OUT
Definition: os_win32.cpp:168
static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize)
Definition: os_win32.cpp:1475
void dStrHex(const char *str, int len, int no_ascii)
Definition: scsicmds.cpp:91
unsigned char failuretest_permissive
Definition: smartctl.cpp:1110
#define CSMI_ALL_SIGNATURE
Definition: csmisas.h:403
UCHAR bDriveHeadReg
Definition: os_os2.cpp:55
unsigned char scsi_debugmode
Definition: scsicmds.cpp:56
#define IOCTL_SCSI_MINIPORT_ENABLE_SMART
Definition: os_win32.cpp:199
mega_passthru pthru
Definition: megaraid.h:93
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:92
void pout(const char *fmt,...)
Definition: smartctl.cpp:1091
size_t max_sense_len
Definition: scsicmds.h:126
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:2398
static bool get_usb_id(int drive, unsigned short &vendor_id, unsigned short &product_id)
Definition: os_win32.cpp:2227
HANDLE m_fh
Controller device handle.
Definition: os_win32.cpp:473
unsigned char fw_rev[8]
Definition: atacmds.h:133
ptr_t buffer
Definition: megaraid.h:89
#define CSMI_SAS_PROTOCOL_SATA
Definition: csmisas.h:733
#define ASSERT_CONST(c, n)
Definition: os_win32.cpp:87
UCHAR bCommandReg
Definition: os_os2.cpp:56
ata_register status
int dxfer_dir
Definition: scsicmds.h:120
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:125
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:1934
#define ATA_SMART_READ_VALUES
Definition: atacmds.h:95
void set_encnum(int encnum)
Definition: dev_areca.h:128
unsigned size
Size of buffer.
static int sdxy_to_phydrive(const char(&xy)[2+1])
Definition: os_win32.cpp:760
Wrapper class for regex(3).
Definition: utility.h:235
win_areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Definition: os_win32.cpp:3674
ata_register lba_low
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:1823
SCSI device access.
Definition: atacmds.h:55
ata_register features
u8 b[12]
Definition: megaraid.h:96
#define DXFER_NONE
Definition: scsicmds.h:112
#define IOCTL_SCSI_MINIPORT_IDENTIFY
Definition: os_win32.cpp:196
#define ATA_SMART_AUTO_OFFLINE
Definition: atacmds.h:108
CSMI_SAS_IDENTIFY Identify
Definition: csmisas.h:1530
static int storage_predict_failure_ioctl(HANDLE hdevice, char *data=0)
Definition: os_win32.cpp:2009
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:894
smart_command_set
Definition: atacmds.h:48
virtual smart_device * autodetect_open()
Open device with autodetection support.
Definition: os_win32.cpp:3799
#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:114
virtual bool is_open() const
Return true if device is open.
Definition: os_win32.cpp:2393
STORAGE_BUS_TYPE BusType
Definition: os_win32.cpp:233
virtual bool arcmsr_probe()
Definition: dev_areca.cpp:264
#define ATA_SMART_READ_THRESHOLDS
Definition: atacmds.h:96
bool is_48bit_cmd() const
Return true if 48-bit command.
virtual scsi_device * get_scsi_device(const char *name, const char *type)
Return standard SCSI device.
Definition: os_win32.cpp:755
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:1572
#define ASSERT_SIZEOF(t, n)
Definition: os_win32.cpp:89
enum _STORAGE_QUERY_TYPE STORAGE_QUERY_TYPE
ata_register device
Base class for all devices.
Definition: dev_interface.h:38
virtual smart_device * autodetect_open()
Open device with autodetection support.
Definition: os_win32.cpp:3707
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:207
bool select_port(int port)
Select physical drive.
Definition: os_win32.cpp:2998
static win_dev_type get_log_drive_type(int drive)
Definition: os_win32.cpp:2148
#define IOCTL_SCSI_MINIPORT_RETURN_STATUS
Definition: os_win32.cpp:201
size_t cmnd_len
Definition: scsicmds.h:119
UCHAR bFeaturesReg
Definition: os_os2.cpp:50
ATA device access.
ata_register sector_count
#define ATA_SMART_IMMEDIATE_OFFLINE
Definition: atacmds.h:99
#define ATA_FLAGS_48BIT_COMMAND
Definition: os_win32.cpp:169
static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:1971
unsigned char serial_no[20]
Definition: atacmds.h:131
STORAGE_QUERY_TYPE QueryType
Definition: os_win32.cpp:257
unsigned char * data()
Definition: utility.h:166
unsigned long long uint64_t
Definition: int64.h:54
__u8 bTargetPortProtocol
Definition: csmisas.h:1520
_STORAGE_PROPERTY_ID
Definition: os_win32.cpp:245
static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA *data)
Definition: os_win32.cpp:2051
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:2428
UCHAR CurrentTaskFile[8]
Definition: os_win32.cpp:163
static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS *regs, IDEREGS *prev_regs, char *data, int datasize)
Definition: os_win32.cpp:1363
CSMI_SAS_STP_PASSTHRU_STATUS Status
Definition: csmisas.h:1699
ata_register command
__u8 bSASAddress[8]
Definition: csmisas.h:1522
static long scsi_pass_through_indirect(HANDLE h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *sbd)
Definition: os_win32.cpp:3377
static const char * findstr(const char *str, const char *sub)
Definition: os_win32.cpp:1787
HANDLE m_fh
File handle.
Definition: os_win32.cpp:350
UINT8 scsi_status
Definition: scsicmds.h:129
Areca RAID support.
Definition: os_win32.cpp:507
UCHAR bCylHighReg
Definition: os_os2.cpp:54
ata_smart_values m_smart_buf
Definition: os_win32.cpp:498
ATA pass through input parameters.
static int get_clipboard(char *data, int datasize)
Definition: os_win32.cpp:1710
#define CSMI_SAS_STP_WRITE
Definition: csmisas.h:858
static win_dev_type get_dev_type(const char *name, int &phydrive)
Definition: os_win32.cpp:768
STORAGE_PROPERTY_ID PropertyId
Definition: os_win32.cpp:256
#define ATA_SMART_ENABLE
Definition: atacmds.h:103
CSMI_SAS_STP_PASSTHRU Parameters
Definition: csmisas.h:1698
CSMI_SAS_PHY_INFO Information
Definition: csmisas.h:1552
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop)
Definition: os_win32.cpp:3826
virtual bool close()
Close device, return false on error.
Definition: os_win32.cpp:1927
#define SMART_VENDOR_3WARE
Definition: os_win32.cpp:276
virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER *csmi_buffer, unsigned csmi_bufsiz)=0
Call platform-specific CSMI ioctl.
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:787
UCHAR AdditionalParameters[1]
Definition: os_win32.cpp:258
STORAGE_DEVICE_DESCRIPTOR desc
Definition: os_win32.cpp:1964
static bool get_serial_from_wmi(int drive, ata_identify_device *id)
Definition: os_win32.cpp:2198
#define CSMI_SAS_STP_PIO
Definition: csmisas.h:860
#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
Definition: os_win32.cpp:198
ata_register lba_low
unsigned char model[40]
Definition: atacmds.h:134
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop)
Definition: os_win32.cpp:3712
#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
Definition: os_win32.cpp:205
static void copy_swapped(unsigned char *dest, const char *src, int destsize)
Definition: os_win32.cpp:1794
#define ATA_FLAGS_DATA_IN
Definition: os_win32.cpp:167
static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device *id)
Definition: os_win32.cpp:2156
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
ATA pass through.
Definition: os_win32.cpp:3056
ata_register lba_high
struct _GETVERSIONINPARAMS_EX GETVERSIONINPARAMS_EX
u8 cmd
Definition: megaraid.h:80
smart_interface * smi()
Get interface which produced this object.
unsigned get_ports_used()
Get bitmask of used ports.
Definition: os_win32.cpp:2966
CSMI_SAS_PHY_ENTITY Phy[32]
Definition: csmisas.h:1546
size_t dxfer_len
Definition: scsicmds.h:123
const char * get_dev_name() const
Get device (path)name.
Definition: atacmds.h:50
std::string info_name
Informal name.
Definition: dev_interface.h:52
win_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:3296
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS *regs, char *data, int datasize, int port)
Definition: os_win32.cpp:1606
ATA Output registers (for 28-bit commands)
static void print_ide_regs(const IDEREGS *r, int out)
Definition: os_win32.cpp:1121
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3683
static void print_ide_regs_io(const IDEREGS *ri, const IDEREGS *ro)
Definition: os_win32.cpp:1128
win_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: os_win32.cpp:2409
virtual bool open()
Open device, return false on error.
Definition: os_win32.cpp:3775
ATA pass through output parameters.
void set_fh(HANDLE fh)
Set handle for open() in derived classes.
Definition: os_win32.cpp:342
CSMI_SAS_PHY_ENTITY m_phy_ent
CSMI info for this phy.
Definition: os_win32.cpp:432
#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
Definition: os_win32.cpp:204
virtual smart_device * autodetect_smart_device(const char *name)
Autodetect device if no device type specified.
Definition: os_win32.cpp:849
#define ATA_SMART_STATUS
Definition: atacmds.h:105