4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
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)
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/>.
21 #define _WIN32_WINNT WINVER
27 #include "smartctl.h" // TODO: Do not use smartctl only variables here
29 #include "dev_interface.h"
30 #include "dev_ata_cmd_set.h"
31 #include "dev_areca.h"
33 #include "os_win32/wmiquery.h"
41 #define assert(x) /* */
44 #include <stddef.h> // offsetof()
45 #include <io.h> // access()
47 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
48 #define WIN32_LEAN_AND_MEAN
52 // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32
53 // (Missing: FILE_DEVICE_SCSI)
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>
65 // MSVC10, older MinGW
66 // (Missing: IOCTL_SCSI_MINIPORT_*)
72 // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
79 // Silence -Wunused-local-typedefs warning from g++ >= 4.8
81 #define ATTR_UNUSED __attribute__((unused))
83 #define ATTR_UNUSED /**/
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
93 #define SELECT_WIN_32_64(x32, x64) (x32)
95 #define SELECT_WIN_32_64(x32, x64) (x64)
98 const char * os_win32_cpp_cvsid
= "$Id: os_win32.cpp 3804 2013-03-27 20:39:41Z chrfranke $";
100 /////////////////////////////////////////////////////////////////////////////
101 // Windows I/O-controls, some declarations are missing in the include files
105 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
107 ASSERT_CONST(SMART_GET_VERSION
, 0x074080);
108 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND
, 0x07c084);
109 ASSERT_CONST(SMART_RCV_DRIVE_DATA
, 0x07c088);
110 ASSERT_SIZEOF(GETVERSIONINPARAMS
, 24);
111 ASSERT_SIZEOF(SENDCMDINPARAMS
, 32+1);
112 ASSERT_SIZEOF(SENDCMDOUTPARAMS
, 16+1);
115 // IDE PASS THROUGH (2000, XP, undocumented)
117 #ifndef IOCTL_IDE_PASS_THROUGH
119 #define IOCTL_IDE_PASS_THROUGH \
120 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
122 #endif // IOCTL_IDE_PASS_THROUGH
128 ULONG DataBufferSize
;
134 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH
, 0x04d028);
135 ASSERT_SIZEOF(ATA_PASS_THROUGH
, 12+1);
138 // ATA PASS THROUGH (Win2003, XP SP2)
140 #ifndef IOCTL_ATA_PASS_THROUGH
142 #define IOCTL_ATA_PASS_THROUGH \
143 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
145 typedef struct _ATA_PASS_THROUGH_EX
{
151 UCHAR ReservedAsUchar
;
152 ULONG DataTransferLength
;
154 ULONG ReservedAsUlong
;
155 ULONG_PTR DataBufferOffset
;
156 UCHAR PreviousTaskFile
[8];
157 UCHAR CurrentTaskFile
[8];
158 } ATA_PASS_THROUGH_EX
;
160 #define ATA_FLAGS_DRDY_REQUIRED 0x01
161 #define ATA_FLAGS_DATA_IN 0x02
162 #define ATA_FLAGS_DATA_OUT 0x04
163 #define ATA_FLAGS_48BIT_COMMAND 0x08
164 #define ATA_FLAGS_USE_DMA 0x10
165 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
167 #endif // IOCTL_ATA_PASS_THROUGH
169 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH
, 0x04d02c);
170 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX
, SELECT_WIN_32_64(40, 48));
173 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
175 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH
, 0x04d004);
176 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT
, 0x04d014);
177 ASSERT_SIZEOF(SCSI_PASS_THROUGH
, SELECT_WIN_32_64(44, 56));
178 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT
, SELECT_WIN_32_64(44, 56));
181 // SMART IOCTL via SCSI MINIPORT ioctl
183 #ifndef FILE_DEVICE_SCSI
184 #define FILE_DEVICE_SCSI 0x001b
187 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
189 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
190 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
191 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
192 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
193 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
194 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
195 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
196 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
197 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
198 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
199 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
200 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
201 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
203 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
205 ASSERT_CONST(IOCTL_SCSI_MINIPORT
, 0x04d008);
206 ASSERT_SIZEOF(SRB_IO_CONTROL
, 28);
209 // IOCTL_STORAGE_QUERY_PROPERTY
211 #ifndef IOCTL_STORAGE_QUERY_PROPERTY
213 #define IOCTL_STORAGE_QUERY_PROPERTY \
214 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
216 typedef struct _STORAGE_DEVICE_DESCRIPTOR
{
220 UCHAR DeviceTypeModifier
;
221 BOOLEAN RemovableMedia
;
222 BOOLEAN CommandQueueing
;
223 ULONG VendorIdOffset
;
224 ULONG ProductIdOffset
;
225 ULONG ProductRevisionOffset
;
226 ULONG SerialNumberOffset
;
227 STORAGE_BUS_TYPE BusType
;
228 ULONG RawPropertiesLength
;
229 UCHAR RawDeviceProperties
[1];
230 } STORAGE_DEVICE_DESCRIPTOR
;
232 typedef enum _STORAGE_QUERY_TYPE
{
233 PropertyStandardQuery
= 0,
236 PropertyQueryMaxDefined
237 } STORAGE_QUERY_TYPE
;
239 typedef enum _STORAGE_PROPERTY_ID
{
240 StorageDeviceProperty
= 0,
241 StorageAdapterProperty
,
242 StorageDeviceIdProperty
,
243 StorageDeviceUniqueIdProperty
,
244 StorageDeviceWriteCacheProperty
,
245 StorageMiniportProperty
,
246 StorageAccessAlignmentProperty
247 } STORAGE_PROPERTY_ID
;
249 typedef struct _STORAGE_PROPERTY_QUERY
{
250 STORAGE_PROPERTY_ID PropertyId
;
251 STORAGE_QUERY_TYPE QueryType
;
252 UCHAR AdditionalParameters
[1];
253 } STORAGE_PROPERTY_QUERY
;
255 #endif // IOCTL_STORAGE_QUERY_PROPERTY
257 ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY
, 0x002d1400);
258 ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR
, 36+1+3);
259 ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY
, 8+1+3);
262 // IOCTL_STORAGE_PREDICT_FAILURE
264 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE
, 0x002d1100);
265 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE
, 4+512);
268 // 3ware specific versions of SMART ioctl structs
270 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
274 typedef struct _GETVERSIONINPARAMS_EX
{
280 DWORD dwDeviceMapEx
; // 3ware specific: RAID drive bit map
281 WORD wIdentifier
; // Vendor specific identifier
282 WORD wControllerId
; // 3ware specific: Controller ID (0,1,...)
284 } GETVERSIONINPARAMS_EX
;
286 typedef struct _SENDCMDINPARAMS_EX
{
290 BYTE bPortNumber
; // 3ware specific: port number
291 WORD wIdentifier
; // Vendor specific identifier
294 } SENDCMDINPARAMS_EX
;
298 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX
, sizeof(GETVERSIONINPARAMS
));
299 ASSERT_SIZEOF(SENDCMDINPARAMS_EX
, sizeof(SENDCMDINPARAMS
));
304 ASSERT_SIZEOF(IOCTL_HEADER
, sizeof(SRB_IO_CONTROL
));
305 ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER
, 204);
306 ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER
, 2080);
307 ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER
, 168);
311 /////////////////////////////////////////////////////////////////////////////
313 namespace os_win32
{ // no need to publish anything, name provided for Doxygen
316 #pragma warning(disable:4250)
319 class win_smart_device
320 : virtual public /*implements*/ smart_device
324 : smart_device(never_called
),
325 m_fh(INVALID_HANDLE_VALUE
)
328 virtual ~win_smart_device() throw();
330 virtual bool is_open() const;
332 virtual bool close();
335 /// Set handle for open() in derived classes.
336 void set_fh(HANDLE fh
)
339 /// Return handle for derived classes.
340 HANDLE
get_fh() const
344 HANDLE m_fh
; ///< File handle
348 /////////////////////////////////////////////////////////////////////////////
351 : public /*implements*/ ata_device
,
352 public /*extends*/ win_smart_device
355 win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
357 virtual ~win_ata_device() throw();
361 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
363 virtual bool ata_identify_is_cached() const;
366 bool open(int phydrive
, int logdrive
, const char * options
, int port
);
368 std::string m_options
;
369 bool m_usr_options
; // options set by user?
370 bool m_admin
; // open with admin access?
371 int m_phydrive
; // PhysicalDriveN or -1
372 bool m_id_is_cached
; // ata_identify_is_cached() return value.
373 bool m_is_3ware
; // LSI/3ware controller detected?
374 int m_port
; // LSI/3ware port
375 int m_smartver_state
;
379 /////////////////////////////////////////////////////////////////////////////
381 class win_scsi_device
382 : public /*implements*/ scsi_device
,
383 virtual public /*extends*/ win_smart_device
386 win_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
390 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
393 bool open(int pd_num
, int ld_num
, int tape_num
, int sub_addr
);
397 /////////////////////////////////////////////////////////////////////////////
400 : virtual public /*extends*/ smart_device
404 bool get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
);
406 /// Check physical drive existence
407 bool check_phy(const CSMI_SAS_PHY_INFO
& phy_info
, unsigned phy_no
);
411 : smart_device(never_called
)
412 { memset(&m_phy_ent
, 0, sizeof(m_phy_ent
)); }
414 /// Select physical drive
415 bool select_phy(unsigned phy_no
);
417 /// Get info for selected physical drive
418 const CSMI_SAS_PHY_ENTITY
& get_phy_ent() const
419 { return m_phy_ent
; }
421 /// Call platform-specific CSMI ioctl
422 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
423 unsigned csmi_bufsiz
) = 0;
426 CSMI_SAS_PHY_ENTITY m_phy_ent
; ///< CSMI info for this phy
430 class csmi_ata_device
431 : virtual public /*extends*/ csmi_device
,
432 virtual public /*implements*/ ata_device
435 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
439 : smart_device(never_called
) { }
443 //////////////////////////////////////////////////////////////////////
445 class win_csmi_device
446 : public /*implements*/ csmi_ata_device
449 win_csmi_device(smart_interface
* intf
, const char * dev_name
,
450 const char * req_type
);
452 virtual ~win_csmi_device() throw();
456 virtual bool close();
458 virtual bool is_open() const;
463 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
464 unsigned csmi_bufsiz
);
467 HANDLE m_fh
; ///< Controller device handle
468 unsigned m_phy_no
; ///< Physical drive number
472 //////////////////////////////////////////////////////////////////////
474 class win_tw_cli_device
475 : public /*implements*/ ata_device_with_command_set
478 win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
480 virtual bool is_open() const;
484 virtual bool close();
487 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
490 bool m_ident_valid
, m_smart_valid
;
491 ata_identify_device m_ident_buf
;
492 ata_smart_values m_smart_buf
;
496 /////////////////////////////////////////////////////////////////////////////
497 /// Areca RAID support
499 ///////////////////////////////////////////////////////////////////
500 // SATA(ATA) device behind Areca RAID Controller
501 class win_areca_ata_device
502 : public /*implements*/ areca_ata_device
,
503 public /*extends*/ win_smart_device
506 win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
508 virtual smart_device
* autodetect_open();
509 virtual bool arcmsr_lock();
510 virtual bool arcmsr_unlock();
511 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
517 ///////////////////////////////////////////////////////////////////
518 // SAS(SCSI) device behind Areca RAID Controller
519 class win_areca_scsi_device
520 : public /*implements*/ areca_scsi_device
,
521 public /*extends*/ win_smart_device
524 win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
526 virtual smart_device
* autodetect_open();
527 virtual bool arcmsr_lock();
528 virtual bool arcmsr_unlock();
529 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
536 //////////////////////////////////////////////////////////////////////
537 // Platform specific interface
539 class win_smart_interface
540 : public /*implements part of*/ smart_interface
543 virtual std::string
get_os_version_str();
545 virtual std::string
get_app_examples(const char * appname
);
548 virtual int64_t get_timer_usec();
551 virtual bool disable_system_auto_standby(bool disable
);
553 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
554 const char * pattern
= 0);
557 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
559 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
561 virtual smart_device
* autodetect_smart_device(const char * name
);
563 virtual smart_device
* get_custom_smart_device(const char * name
, const char * type
);
565 virtual std::string
get_valid_custom_dev_types_str();
569 //////////////////////////////////////////////////////////////////////
572 // Running on 64-bit Windows as 32-bit app ?
573 static bool is_wow64()
575 BOOL (WINAPI
* IsWow64Process_p
)(HANDLE
, PBOOL
) =
576 (BOOL (WINAPI
*)(HANDLE
, PBOOL
))
577 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
578 if (!IsWow64Process_p
)
581 if (!IsWow64Process_p(GetCurrentProcess(), &w64
))
587 // Return info string about build host and OS version
588 std::string
win_smart_interface::get_os_version_str()
590 char vstr
[sizeof(SMARTMONTOOLS_BUILD_HOST
)-1+sizeof("-2003r2(64)-sp2.1")+13]
591 = SMARTMONTOOLS_BUILD_HOST
;
594 char * const vptr
= vstr
+sizeof(SMARTMONTOOLS_BUILD_HOST
)-1;
595 const int vlen
= sizeof(vstr
)-sizeof(SMARTMONTOOLS_BUILD_HOST
);
596 assert(vptr
== vstr
+strlen(vstr
) && vptr
+vlen
+1 == vstr
+sizeof(vstr
));
598 OSVERSIONINFOEXA vi
; memset(&vi
, 0, sizeof(vi
));
599 vi
.dwOSVersionInfoSize
= sizeof(vi
);
600 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
)) {
601 memset(&vi
, 0, sizeof(vi
));
602 vi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
603 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
))
607 if (vi
.dwPlatformId
> 0xff || vi
.dwMajorVersion
> 0xff || vi
.dwMinorVersion
> 0xff)
611 switch (vi
.dwPlatformId
<< 16 | vi
.dwMajorVersion
<< 8 | vi
.dwMinorVersion
) {
612 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400| 0:
613 w
= (vi
.szCSDVersion
[1] == 'B' ||
614 vi
.szCSDVersion
[1] == 'C' ? "95-osr2" : "95"); break;
615 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400|10:
616 w
= (vi
.szCSDVersion
[1] == 'A' ? "98se" : "98"); break;
617 case VER_PLATFORM_WIN32_WINDOWS
<<16|0x0400|90: w
= "me"; break;
618 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break;
619 case VER_PLATFORM_WIN32_NT
<<16|0x0400| 0: w
= "nt4"; break;
620 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 0: w
= "2000"; break;
621 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 1:
622 w
= (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp"
624 case VER_PLATFORM_WIN32_NT
<<16|0x0500| 2:
625 w
= (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003"
627 case VER_PLATFORM_WIN32_NT
<<16|0x0600| 0:
628 w
= (vi
.wProductType
== VER_NT_WORKSTATION
? "vista"
630 case VER_PLATFORM_WIN32_NT
<<16|0x0600| 1:
631 w
= (vi
.wProductType
== VER_NT_WORKSTATION
? "win7"
633 case VER_PLATFORM_WIN32_NT
<<16|0x0600| 2:
634 w
= (vi
.wProductType
== VER_NT_WORKSTATION
? "win8"
636 default: w
= 0; break;
639 const char * w64
= "";
646 snprintf(vptr
, vlen
, "-%s%u.%u%s",
647 (vi
.dwPlatformId
==VER_PLATFORM_WIN32_NT
? "nt" : "9x"),
648 (unsigned)vi
.dwMajorVersion
, (unsigned)vi
.dwMinorVersion
, w64
);
649 else if (vi
.wServicePackMinor
)
650 snprintf(vptr
, vlen
, "-%s%s-sp%u.%u", w
, w64
, vi
.wServicePackMajor
, vi
.wServicePackMinor
);
651 else if (vi
.wServicePackMajor
)
652 snprintf(vptr
, vlen
, "-%s%s-sp%u", w
, w64
, vi
.wServicePackMajor
);
654 snprintf(vptr
, vlen
, "-%s%s", w
, w64
);
659 // MSVCRT only provides ftime() which uses GetSystemTime()
660 // This provides only ~15ms resolution by default.
661 // Use QueryPerformanceCounter instead (~300ns).
662 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
663 int64_t win_smart_interface::get_timer_usec()
665 static int64_t freq
= 0;
669 freq
= (QueryPerformanceFrequency(&t
) ? t
.QuadPart
: -1);
671 return smart_interface::get_timer_usec();
673 if (!QueryPerformanceCounter(&t
))
675 if (!(0 <= t
.QuadPart
&& t
.QuadPart
<= (int64_t)(~(uint64_t)0 >> 1)/1000000))
678 return (t
.QuadPart
* 1000000LL) / freq
;
683 // Return value for device detection functions
684 enum win_dev_type
{ DEV_UNKNOWN
= 0, DEV_ATA
, DEV_SCSI
, DEV_USB
};
686 static win_dev_type
get_phy_drive_type(int drive
);
687 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
);
688 static win_dev_type
get_log_drive_type(int drive
);
689 static bool get_usb_id(int drive
, unsigned short & vendor_id
,
690 unsigned short & product_id
);
692 static const char * ata_get_def_options(void);
695 static int is_permissive()
697 if (!failuretest_permissive
) {
698 pout("To continue, add one or more '-T permissive' options.\n");
701 failuretest_permissive
--;
705 // return number for drive letter, -1 on error
706 // "[A-Za-z]:([/\\][.]?)?" => 0-25
707 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
708 static int drive_letter(const char * s
)
710 return ( (('A' <= s
[0] && s
[0] <= 'Z') || ('a' <= s
[0] && s
[0] <= 'z'))
712 && (!s
[2] || ( strchr("/\\\"", s
[2])
713 && (!s
[3] || (s
[3] == '.' && !s
[4]))) ) ?
714 (s
[0] & 0x1f) - 1 : -1);
717 // Skip trailing "/dev/", do not allow "/dev/X:"
718 static const char * skipdev(const char * s
)
720 return (!strncmp(s
, "/dev/", 5) && drive_letter(s
+5) < 0 ? s
+5 : s
);
723 ata_device
* win_smart_interface::get_ata_device(const char * name
, const char * type
)
725 const char * testname
= skipdev(name
);
726 if (!strncmp(testname
, "csmi", 4))
727 return new win_csmi_device(this, name
, type
);
728 if (!strncmp(testname
, "tw_cli", 6))
729 return new win_tw_cli_device(this, name
, type
);
730 return new win_ata_device(this, name
, type
);
733 scsi_device
* win_smart_interface::get_scsi_device(const char * name
, const char * type
)
735 return new win_scsi_device(this, name
, type
);
738 static int sdxy_to_phydrive(const char (& xy
)[2+1])
740 int phydrive
= xy
[0] - 'a';
742 phydrive
= (phydrive
+ 1) * ('z' - 'a' + 1) + (xy
[1] - 'a');
746 static win_dev_type
get_dev_type(const char * name
, int & phydrive
)
749 name
= skipdev(name
);
750 if (!strncmp(name
, "st", 2))
752 if (!strncmp(name
, "nst", 3))
754 if (!strncmp(name
, "tape", 4))
757 int logdrive
= drive_letter(name
);
759 win_dev_type type
= get_log_drive_type(logdrive
);
760 return (type
!= DEV_UNKNOWN
? type
: DEV_SCSI
);
763 char drive
[2+1] = "";
764 if (sscanf(name
, "sd%2[a-z]", drive
) == 1) {
765 phydrive
= sdxy_to_phydrive(drive
);
766 return get_phy_drive_type(phydrive
);
770 if (sscanf(name
, "pd%d", &phydrive
) == 1 && phydrive
>= 0)
771 return get_phy_drive_type(phydrive
);
775 smart_device
* win_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
778 int disknum
= -1, n1
= -1, n2
= -1;
782 if (sscanf(type
, "areca,%n%d/%d%n", &n1
, &disknum
, &encnum
, &n2
) >= 1 || n1
== 6) {
783 if (!(1 <= disknum
&& disknum
<= 128)) {
784 set_err(EINVAL
, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum
);
787 if (!(1 <= encnum
&& encnum
<= 8)) {
788 set_err(EINVAL
, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum
);
792 name
= skipdev(name
);
793 #define ARECA_MAX_CTLR_NUM 16
796 if (sscanf(name
, "arcmsr%d%n", &ctlrindex
, &n1
) >= 1 && n1
== (int)strlen(name
)) {
798 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
799 2. map arcmsrX into "\\\\.\\scsiX"
801 for (int idx
= 0; idx
< ARECA_MAX_CTLR_NUM
; idx
++) {
802 memset(devpath
, 0, sizeof(devpath
));
803 snprintf(devpath
, sizeof(devpath
), "\\\\.\\scsi%d:", idx
);
804 win_areca_ata_device
*arcdev
= new win_areca_ata_device(this, devpath
, disknum
, encnum
);
805 if(arcdev
->arcmsr_probe()) {
806 if(ctlrindex
-- == 0) {
812 set_err(ENOENT
, "No Areca controller found");
815 set_err(EINVAL
, "Option -d areca,N/E requires device name /dev/arcmsrX");
821 std::string
win_smart_interface::get_valid_custom_dev_types_str()
823 return "areca,N[/E]";
827 smart_device
* win_smart_interface::autodetect_smart_device(const char * name
)
829 const char * testname
= skipdev(name
);
830 if (str_starts_with(testname
, "hd"))
831 return new win_ata_device(this, name
, "");
833 if (str_starts_with(testname
, "tw_cli"))
834 return new win_tw_cli_device(this, name
, "");
836 if (str_starts_with(testname
, "csmi"))
837 return new win_csmi_device(this, name
, "");
840 win_dev_type type
= get_dev_type(name
, phydrive
);
843 return new win_ata_device(this, name
, "");
844 if (type
== DEV_SCSI
)
845 return new win_scsi_device(this, name
, "");
847 if (type
== DEV_USB
) {
849 unsigned short vendor_id
= 0, product_id
= 0;
850 if (!(phydrive
>= 0 && get_usb_id(phydrive
, vendor_id
, product_id
))) {
851 set_err(EINVAL
, "Unable to read USB device ID");
854 // Get type name for this ID
855 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
858 // Return SAT/USB device for this type
859 return get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
868 bool win_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
869 const char * type
, const char * pattern
/* = 0*/)
872 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
876 // Check for "[*,]pd" type
878 char type2
[16+1] = "";
881 if (!strcmp(type
, "pd")) {
885 else if (sscanf(type
, "%16[^,],pd%n", type2
, &nc
) == 1 &&
886 nc
== (int)strlen(type
)) {
893 bool ata
, scsi
, usb
, csmi
;
895 ata
= scsi
= usb
= csmi
= true;
898 ata
= scsi
= usb
= csmi
= false;
899 if (!strcmp(type
, "ata"))
901 else if (!strcmp(type
, "scsi"))
903 else if (!strcmp(type
, "usb"))
905 else if (!strcmp(type
, "csmi"))
908 set_err(EINVAL
, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type
);
915 if (ata
|| scsi
|| usb
) {
916 // Scan up to 128 drives and 2 3ware controllers
917 const int max_raid
= 2;
918 bool raid_seen
[max_raid
] = {false, false};
920 for (int i
= 0; i
< 128; i
++) {
922 snprintf(name
, sizeof(name
), "/dev/pd%d", i
);
923 else if (i
+ 'a' <= 'z')
924 snprintf(name
, sizeof(name
), "/dev/sd%c", i
+ 'a');
926 snprintf(name
, sizeof(name
), "/dev/sd%c%c",
927 i
/ ('z'-'a'+1) - 1 + 'a',
928 i
% ('z'-'a'+1) + 'a');
930 GETVERSIONINPARAMS_EX vers_ex
;
932 switch (get_phy_drive_type(i
, (ata
? &vers_ex
: 0))) {
934 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
938 // Interpret RAID drive map if present
939 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
) {
940 // Skip if too many controllers or logical drive from this controller already seen
941 if (!(vers_ex
.wControllerId
< max_raid
&& !raid_seen
[vers_ex
.wControllerId
]))
943 raid_seen
[vers_ex
.wControllerId
] = true;
944 // Add physical drives
945 int len
= strlen(name
);
946 for (int pi
= 0; pi
< 32; pi
++) {
947 if (vers_ex
.dwDeviceMapEx
& (1L << pi
)) {
948 snprintf(name
+len
, sizeof(name
)-1-len
, ",%u", pi
);
949 devlist
.push_back( new win_ata_device(this, name
, "ata") );
954 devlist
.push_back( new win_ata_device(this, name
, "ata") );
959 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
962 devlist
.push_back( new win_scsi_device(this, name
, "scsi") );
966 // STORAGE_QUERY_PROPERTY returned USB
970 // TODO: Use common function for this and autodetect_smart_device()
972 unsigned short vendor_id
= 0, product_id
= 0;
973 if (!get_usb_id(i
, vendor_id
, product_id
))
975 // Get type name for this ID
976 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
979 // Return SAT/USB device for this type
980 ata_device
* dev
= get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
983 devlist
.push_back(dev
);
996 for (int i
= 0; i
<= 9; i
++) {
997 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,0", i
);
998 win_csmi_device
test_dev(this, name
, "");
999 if (!test_dev
.open_scsi())
1001 CSMI_SAS_PHY_INFO phy_info
;
1002 if (!test_dev
.get_phy_info(phy_info
))
1005 for (int pi
= 0; pi
< phy_info
.bNumberOfPhys
; pi
++) {
1006 if (!test_dev
.check_phy(phy_info
, pi
))
1008 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,%d", i
, pi
);
1009 devlist
.push_back( new win_csmi_device(this, name
, "ata") );
1017 // get examples for smartctl
1018 std::string
win_smart_interface::get_app_examples(const char * appname
)
1020 if (strcmp(appname
, "smartctl"))
1022 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1023 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1024 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1025 " (Enables SMART on first disk)\n\n"
1026 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1027 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1028 " (Prints Self-Test & Attribute errors)\n"
1029 " smartctl -a /dev/sda\n"
1030 " (Prints all information for disk on PhysicalDrive 0)\n"
1031 " smartctl -a /dev/pd3\n"
1032 " (Prints all information for disk on PhysicalDrive 3)\n"
1033 " smartctl -a /dev/tape1\n"
1034 " (Prints all information for SCSI tape on Tape 1)\n"
1035 " smartctl -A /dev/hdb,3\n"
1036 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1037 " smartctl -A /dev/tw_cli/c0/p1\n"
1038 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1039 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1040 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1041 " on 1st Areca RAID controller)\n"
1043 " ATA SMART access methods and ordering may be specified by modifiers\n"
1044 " following the device name: /dev/hdX:[saicm], where\n"
1045 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1046 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1047 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1049 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1054 bool win_smart_interface::disable_system_auto_standby(bool disable
)
1057 SYSTEM_POWER_STATUS ps
;
1058 if (!GetSystemPowerStatus(&ps
))
1059 return set_err(ENOSYS
, "Unknown power status");
1060 if (ps
.ACLineStatus
!= 1) {
1061 SetThreadExecutionState(ES_CONTINUOUS
);
1062 if (ps
.ACLineStatus
== 0)
1063 set_err(EIO
, "AC offline");
1065 set_err(EIO
, "Unknown AC line status");
1070 if (!SetThreadExecutionState(ES_CONTINUOUS
| (disable
? ES_SYSTEM_REQUIRED
: 0)))
1071 return set_err(ENOSYS
);
1076 /////////////////////////////////////////////////////////////////////////////
1078 /////////////////////////////////////////////////////////////////////////////
1080 #define SMART_CYL_LOW 0x4F
1081 #define SMART_CYL_HI 0xC2
1083 static void print_ide_regs(const IDEREGS
* r
, int out
)
1085 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1086 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
1087 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
1090 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
1092 pout(" Input : "); print_ide_regs(ri
, 0);
1094 pout(" Output: "); print_ide_regs(ro
, 1);
1098 /////////////////////////////////////////////////////////////////////////////
1100 // call SMART_GET_VERSION, return device map or -1 on error
1102 static int smart_get_version(HANDLE hdevice
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
1104 GETVERSIONINPARAMS vers
; memset(&vers
, 0, sizeof(vers
));
1105 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1108 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
1109 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1111 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1115 assert(num_out
== sizeof(GETVERSIONINPARAMS
));
1117 if (ata_debugmode
> 1) {
1118 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1119 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1120 (unsigned)num_out
, vers
.bVersion
, vers
.bRevision
,
1121 (unsigned)vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1122 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1123 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1124 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, (unsigned)vers_ex
.dwDeviceMapEx
);
1128 *ata_version_ex
= vers_ex
;
1130 // TODO: Check vers.fCapabilities here?
1131 return vers
.bIDEDeviceMap
;
1135 // call SMART_* ioctl
1137 static int smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
1139 SENDCMDINPARAMS inpar
;
1140 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
1142 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
1143 const SENDCMDOUTPARAMS
* outpar
;
1144 DWORD code
, num_out
;
1145 unsigned int size_out
;
1148 memset(&inpar
, 0, sizeof(inpar
));
1149 inpar
.irDriveRegs
= *regs
;
1151 // Older drivers may require bits 5 and 7 set
1152 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1153 inpar
.irDriveRegs
.bDriveHeadReg
|= 0xa0;
1155 // Drive number 0-3 was required on Win9x/ME only
1156 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1157 //inpar.bDriveNumber = drive;
1161 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
1162 inpar_ex
.bPortNumber
= port
;
1165 if (datasize
== 512) {
1166 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
1167 inpar
.cBufferSize
= size_out
= 512;
1169 else if (datasize
== 0) {
1170 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
1171 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
1172 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
1173 // Note: cBufferSize must be 0 on Win9x
1182 memset(&outbuf
, 0, sizeof(outbuf
));
1184 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
1185 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
1186 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1187 long err
= GetLastError();
1188 if (ata_debugmode
&& (err
!= ERROR_INVALID_PARAMETER
|| ata_debugmode
> 1)) {
1189 pout(" %s failed, Error=%ld\n", name
, err
);
1190 print_ide_regs_io(regs
, NULL
);
1192 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
1193 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/
1194 || err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1197 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1199 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
1201 if (outpar
->DriverStatus
.bDriverError
) {
1202 if (ata_debugmode
) {
1203 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1204 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
1205 print_ide_regs_io(regs
, NULL
);
1207 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1211 if (ata_debugmode
> 1) {
1212 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name
,
1213 (unsigned)num_out
, (unsigned)outpar
->cBufferSize
);
1214 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
1215 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
1219 memcpy(data
, outpar
->bBuffer
, 512);
1220 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
1221 if (nonempty(outpar
->bBuffer
, sizeof(IDEREGS
)))
1222 memcpy(regs
, outpar
->bBuffer
, sizeof(IDEREGS
));
1223 else { // Workaround for driver not returning regs
1225 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1226 *regs
= inpar
.irDriveRegs
;
1234 /////////////////////////////////////////////////////////////////////////////
1235 // IDE PASS THROUGH (2000, XP, undocumented)
1237 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1238 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1240 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
1242 if (datasize
> 512) {
1246 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
1247 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1249 const unsigned char magic
= 0xcf;
1256 buf
->IdeReg
= *regs
;
1257 buf
->DataBufferSize
= datasize
;
1259 buf
->DataBuffer
[0] = magic
;
1261 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
1262 buf
, size
, buf
, size
, &num_out
, NULL
)) {
1263 long err
= GetLastError();
1264 if (ata_debugmode
) {
1265 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
1266 print_ide_regs_io(regs
, NULL
);
1268 VirtualFree(buf
, 0, MEM_RELEASE
);
1269 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1274 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
1275 if (ata_debugmode
) {
1276 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1277 print_ide_regs_io(regs
, &buf
->IdeReg
);
1279 VirtualFree(buf
, 0, MEM_RELEASE
);
1284 // Check and copy data
1286 if ( num_out
!= size
1287 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
1288 if (ata_debugmode
) {
1289 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1290 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1291 print_ide_regs_io(regs
, &buf
->IdeReg
);
1293 VirtualFree(buf
, 0, MEM_RELEASE
);
1297 memcpy(data
, buf
->DataBuffer
, datasize
);
1300 if (ata_debugmode
> 1) {
1301 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1302 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1303 print_ide_regs_io(regs
, &buf
->IdeReg
);
1305 *regs
= buf
->IdeReg
;
1307 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1308 VirtualFree(buf
, 0, MEM_RELEASE
);
1313 /////////////////////////////////////////////////////////////////////////////
1314 // ATA PASS THROUGH (Win2003, XP SP2)
1317 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1318 // transfer per command. Therefore, multi-sector transfers are only supported
1319 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1320 // or READ/WRITE LOG EXT work only with single sector transfers.
1321 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1323 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1325 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, IDEREGS
* prev_regs
, char * data
, int datasize
)
1327 const int max_sectors
= 32; // TODO: Allocate dynamic buffer
1330 ATA_PASS_THROUGH_EX apt
;
1332 UCHAR ucDataBuf
[max_sectors
* 512];
1333 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
1335 const unsigned char magic
= 0xcf;
1337 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
1338 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
1339 //ab.apt.PathId = 0;
1340 //ab.apt.TargetId = 0;
1342 ab
.apt
.TimeOutValue
= 10;
1343 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
1344 ab
.apt
.DataBufferOffset
= size
;
1347 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1351 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
1352 ab
.apt
.DataTransferLength
= datasize
;
1354 ab
.ucDataBuf
[0] = magic
;
1356 else if (datasize
< 0) {
1357 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1361 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
1362 ab
.apt
.DataTransferLength
= -datasize
;
1364 memcpy(ab
.ucDataBuf
, data
, -datasize
);
1367 assert(ab
.apt
.AtaFlags
== 0);
1368 assert(ab
.apt
.DataTransferLength
== 0);
1371 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
1372 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
1373 IDEREGS
* ptfregs
= (IDEREGS
*)ab
.apt
.PreviousTaskFile
;
1377 *ptfregs
= *prev_regs
;
1378 ab
.apt
.AtaFlags
|= ATA_FLAGS_48BIT_COMMAND
;
1382 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
1383 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
1384 long err
= GetLastError();
1385 if (ata_debugmode
) {
1386 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
1387 print_ide_regs_io(regs
, NULL
);
1389 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1394 if (ctfregs
->bCommandReg
/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1395 if (ata_debugmode
) {
1396 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1397 print_ide_regs_io(regs
, ctfregs
);
1403 // Check and copy data
1405 if ( num_out
!= size
1406 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
1407 if (ata_debugmode
) {
1408 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out
);
1409 print_ide_regs_io(regs
, ctfregs
);
1414 memcpy(data
, ab
.ucDataBuf
, datasize
);
1417 if (ata_debugmode
> 1) {
1418 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out
);
1419 print_ide_regs_io(regs
, ctfregs
);
1423 *prev_regs
= *ptfregs
;
1429 /////////////////////////////////////////////////////////////////////////////
1430 // SMART IOCTL via SCSI MINIPORT ioctl
1432 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1433 // miniport driver (via SCSI port driver scsiport.sys).
1434 // It can be used to skip the missing or broken handling of some SMART
1435 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1437 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
1440 DWORD code
= 0; const char * name
= 0;
1441 if (regs
->bCommandReg
== ATA_IDENTIFY_DEVICE
) {
1442 code
= IOCTL_SCSI_MINIPORT_IDENTIFY
; name
= "IDENTIFY";
1444 else if (regs
->bCommandReg
== ATA_SMART_CMD
) switch (regs
->bFeaturesReg
) {
1445 case ATA_SMART_READ_VALUES
:
1446 code
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
; name
= "READ_SMART_ATTRIBS"; break;
1447 case ATA_SMART_READ_THRESHOLDS
:
1448 code
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
; name
= "READ_SMART_THRESHOLDS"; break;
1449 case ATA_SMART_ENABLE
:
1450 code
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
; name
= "ENABLE_SMART"; break;
1451 case ATA_SMART_DISABLE
:
1452 code
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
; name
= "DISABLE_SMART"; break;
1453 case ATA_SMART_STATUS
:
1454 code
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
; name
= "RETURN_STATUS"; break;
1455 case ATA_SMART_AUTOSAVE
:
1456 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
; name
= "ENABLE_DISABLE_AUTOSAVE"; break;
1457 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1458 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1459 case ATA_SMART_IMMEDIATE_OFFLINE
:
1460 code
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
; name
= "EXECUTE_OFFLINE_DIAGS"; break;
1461 case ATA_SMART_AUTO_OFFLINE
:
1462 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
; name
= "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1463 case ATA_SMART_READ_LOG_SECTOR
:
1464 code
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
; name
= "READ_SMART_LOG"; break;
1465 case ATA_SMART_WRITE_LOG_SECTOR
:
1466 code
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
; name
= "WRITE_SMART_LOG"; break;
1475 SRB_IO_CONTROL srbc
;
1478 SENDCMDOUTPARAMS out
;
1482 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(SENDCMDINPARAMS
)-1+512);
1483 memset(&sb
, 0, sizeof(sb
));
1487 if (datasize
> (int)sizeof(sb
.space
)+1) {
1493 else if (datasize
< 0) {
1494 if (-datasize
> (int)sizeof(sb
.space
)+1) {
1499 memcpy(sb
.params
.in
.bBuffer
, data
, size
);
1501 else if (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1502 size
= sizeof(IDEREGS
);
1505 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1506 memcpy(sb
.srbc
.Signature
, "SCSIDISK", 8); // atapi.sys
1507 sb
.srbc
.Timeout
= 60; // seconds
1508 sb
.srbc
.ControlCode
= code
;
1509 //sb.srbc.ReturnCode = 0;
1510 sb
.srbc
.Length
= sizeof(SENDCMDINPARAMS
)-1 + size
;
1511 sb
.params
.in
.irDriveRegs
= *regs
;
1512 sb
.params
.in
.cBufferSize
= size
;
1514 // Call miniport ioctl
1515 size
+= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)-1;
1517 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1518 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
1519 long err
= GetLastError();
1520 if (ata_debugmode
) {
1521 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name
, err
);
1522 print_ide_regs_io(regs
, NULL
);
1524 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1529 if (sb
.srbc
.ReturnCode
) {
1530 if (ata_debugmode
) {
1531 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name
, (unsigned)sb
.srbc
.ReturnCode
);
1532 print_ide_regs_io(regs
, NULL
);
1538 if (sb
.params
.out
.DriverStatus
.bDriverError
) {
1539 if (ata_debugmode
) {
1540 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1541 sb
.params
.out
.DriverStatus
.bDriverError
, sb
.params
.out
.DriverStatus
.bIDEError
);
1542 print_ide_regs_io(regs
, NULL
);
1544 errno
= (!sb
.params
.out
.DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1548 if (ata_debugmode
> 1) {
1549 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name
,
1550 (unsigned)num_out
, (unsigned)sb
.params
.out
.cBufferSize
);
1551 print_ide_regs_io(regs
, (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
?
1552 (const IDEREGS
*)(sb
.params
.out
.bBuffer
) : 0));
1556 memcpy(data
, sb
.params
.out
.bBuffer
, datasize
);
1557 else if (datasize
== 0 && code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1558 memcpy(regs
, sb
.params
.out
.bBuffer
, sizeof(IDEREGS
));
1564 /////////////////////////////////////////////////////////////////////////////
1566 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1568 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1571 SRB_IO_CONTROL srbc
;
1575 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1577 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1581 memset(&sb
, 0, sizeof(sb
));
1582 strncpy((char *)sb
.srbc
.Signature
, "<3ware>", sizeof(sb
.srbc
.Signature
));
1583 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1584 sb
.srbc
.Timeout
= 60; // seconds
1585 sb
.srbc
.ControlCode
= 0xA0000000;
1586 sb
.srbc
.ReturnCode
= 0;
1587 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1589 sb
.regs
.bReserved
= port
;
1592 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1593 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1594 long err
= GetLastError();
1595 if (ata_debugmode
) {
1596 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1597 print_ide_regs_io(regs
, NULL
);
1599 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1603 if (sb
.srbc
.ReturnCode
) {
1604 if (ata_debugmode
) {
1605 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb
.srbc
.ReturnCode
);
1606 print_ide_regs_io(regs
, NULL
);
1614 memcpy(data
, sb
.buffer
, datasize
);
1616 if (ata_debugmode
> 1) {
1617 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out
);
1618 print_ide_regs_io(regs
, &sb
.regs
);
1626 /////////////////////////////////////////////////////////////////////////////
1628 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1629 // 3DM/CLI "Rescan Controller" function does not to always update it.
1631 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1633 SRB_IO_CONTROL srbc
;
1634 memset(&srbc
, 0, sizeof(srbc
));
1635 strncpy((char *)srbc
.Signature
, "<3ware>", sizeof(srbc
.Signature
));
1636 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1637 srbc
.Timeout
= 60; // seconds
1638 srbc
.ControlCode
= 0xCC010014;
1639 srbc
.ReturnCode
= 0;
1643 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1644 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1645 long err
= GetLastError();
1647 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1648 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1651 if (srbc
.ReturnCode
) {
1653 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc
.ReturnCode
);
1657 if (ata_debugmode
> 1)
1658 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1664 /////////////////////////////////////////////////////////////////////////////
1666 // Routines for pseudo device /dev/tw_cli/*
1667 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1670 // Get clipboard data
1672 static int get_clipboard(char * data
, int datasize
)
1674 if (!OpenClipboard(NULL
))
1676 HANDLE h
= GetClipboardData(CF_TEXT
);
1681 const void * p
= GlobalLock(h
);
1682 int n
= GlobalSize(h
);
1692 // Run a command, write stdout to dataout
1693 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1695 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1697 // Create stdout pipe
1698 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1699 HANDLE pipe_out_w
, h
;
1700 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1702 HANDLE self
= GetCurrentProcess();
1704 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1705 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1706 CloseHandle(pipe_out_w
);
1710 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1711 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1712 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1717 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1718 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1719 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1720 si
.dwFlags
= STARTF_USESTDHANDLES
;
1721 PROCESS_INFORMATION pi
;
1723 NULL
, const_cast<char *>(cmd
),
1724 NULL
, NULL
, TRUE
/*inherit*/,
1725 CREATE_NO_WINDOW
/*do not create a new console window*/,
1726 NULL
, NULL
, &si
, &pi
)) {
1727 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1730 CloseHandle(pi
.hThread
);
1731 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1733 // Copy stdout to output buffer
1735 while (i
< outsize
) {
1737 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1741 CloseHandle(pipe_out_r
);
1743 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1744 CloseHandle(pi
.hProcess
);
1749 static const char * findstr(const char * str
, const char * sub
)
1751 const char * s
= strstr(str
, sub
);
1752 return (s
? s
+strlen(sub
) : "");
1756 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1758 int srclen
= strcspn(src
, "\r\n");
1760 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1761 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1763 if (i
< destsize
-1 && i
< srclen
)
1768 // TODO: This is OS independent
1770 win_tw_cli_device::win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
1771 : smart_device(intf
, dev_name
, "tw_cli", req_type
),
1772 m_ident_valid(false), m_smart_valid(false)
1774 memset(&m_ident_buf
, 0, sizeof(m_ident_buf
));
1775 memset(&m_smart_buf
, 0, sizeof(m_smart_buf
));
1779 bool win_tw_cli_device::is_open() const
1781 return (m_ident_valid
|| m_smart_valid
);
1785 bool win_tw_cli_device::open()
1787 m_ident_valid
= m_smart_valid
= false;
1788 const char * name
= skipdev(get_dev_name());
1789 // Read tw_cli or 3DM browser output into buffer
1791 int size
= -1, n1
= -1, n2
= -1;
1792 if (!strcmp(name
, "tw_cli/clip")) { // read clipboard
1793 size
= get_clipboard(buffer
, sizeof(buffer
));
1795 else if (!strcmp(name
, "tw_cli/stdin")) { // read stdin
1796 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1798 else if (sscanf(name
, "tw_cli/%nc%*u/p%*u%n", &n1
, &n2
) >= 0 && n2
== (int)strlen(name
)) {
1799 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1801 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
+n1
);
1802 if (ata_debugmode
> 1)
1803 pout("%s: Run: \"%s\"\n", name
, cmd
);
1804 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1807 return set_err(EINVAL
);
1810 if (ata_debugmode
> 1)
1811 pout("%s: Read %d bytes\n", name
, size
);
1813 return set_err(ENOENT
);
1814 if (size
>= (int)sizeof(buffer
))
1815 return set_err(EIO
);
1818 if (ata_debugmode
> 1)
1819 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1821 // Fake identify sector
1822 ASSERT_SIZEOF(ata_identify_device
, 512);
1823 ata_identify_device
* id
= &m_ident_buf
;
1824 memset(id
, 0, sizeof(*id
));
1825 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1826 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1827 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1828 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1829 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1831 id
->words047_079
[49-47] = 0x0200; // size valid
1832 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1833 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1835 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1836 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1838 // Parse smart data hex dump
1839 const char * s
= findstr(buffer
, "Drive Smart Data:");
1841 s
= findstr(buffer
, "Drive SMART Data:"); // tw_cli from 9.5.x
1843 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1845 const char * s1
= findstr(s
, "<td class"); // html version
1848 s
+= strcspn(s
, "\r\n");
1851 s
= buffer
; // try raw hex dump without header
1853 unsigned char * sd
= (unsigned char *)&m_smart_buf
;
1856 unsigned x
= ~0; int n
= -1;
1857 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1859 sd
[i
] = (unsigned char)x
;
1860 if (!(++i
< 512 && n
> 0))
1863 if (*s
== '<') // "<br>"
1864 s
+= strcspn(s
, "\r\n");
1867 if (!id
->model
[1]) {
1868 // No useful data found
1869 char * err
= strstr(buffer
, "Error:");
1871 err
= strstr(buffer
, "error :");
1872 if (err
&& (err
= strchr(err
, ':'))) {
1873 // Show tw_cli error message
1875 err
[strcspn(err
, "\r\n")] = 0;
1876 return set_err(EIO
, "%s", err
);
1878 return set_err(EIO
);
1883 m_ident_valid
= true;
1884 m_smart_valid
= !!sd
;
1889 bool win_tw_cli_device::close()
1891 m_ident_valid
= m_smart_valid
= false;
1896 int win_tw_cli_device::ata_command_interface(smart_command_set command
, int /*select*/, char * data
)
1902 memcpy(data
, &m_ident_buf
, 512);
1907 memcpy(data
, &m_smart_buf
, 512);
1911 case STATUS_CHECK
: // Fake "good" SMART status
1916 // Arrive here for all unsupported commands
1922 /////////////////////////////////////////////////////////////////////////////
1923 // IOCTL_STORAGE_QUERY_PROPERTY
1925 union STORAGE_DEVICE_DESCRIPTOR_DATA
{
1926 STORAGE_DEVICE_DESCRIPTOR desc
;
1930 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1931 // (This works without admin rights)
1933 static int storage_query_property_ioctl(HANDLE hdevice
, STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
1935 STORAGE_PROPERTY_QUERY query
= {StorageDeviceProperty
, PropertyStandardQuery
, {0} };
1936 memset(data
, 0, sizeof(*data
));
1939 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_QUERY_PROPERTY
,
1940 &query
, sizeof(query
), data
, sizeof(*data
), &num_out
, NULL
)) {
1941 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
1942 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
1947 if (ata_debugmode
> 1 || scsi_debugmode
> 1) {
1948 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1950 " Product: \"%s\"\n"
1951 " Revision: \"%s\"\n"
1953 " BusType: 0x%02x\n",
1954 (data
->desc
.VendorIdOffset
? data
->raw
+data
->desc
.VendorIdOffset
: "(null)"),
1955 (data
->desc
.ProductIdOffset
? data
->raw
+data
->desc
.ProductIdOffset
: "(null)"),
1956 (data
->desc
.ProductRevisionOffset
? data
->raw
+data
->desc
.ProductRevisionOffset
: "(null)"),
1957 (data
->desc
.RemovableMedia
? "Yes":"No"), data
->desc
.BusType
1964 /////////////////////////////////////////////////////////////////////////////
1965 // IOCTL_STORAGE_PREDICT_FAILURE
1967 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1968 // or -1 on error, opionally return VendorSpecific data.
1969 // (This works without admin rights)
1971 static int storage_predict_failure_ioctl(HANDLE hdevice
, char * data
= 0)
1973 STORAGE_PREDICT_FAILURE pred
;
1974 memset(&pred
, 0, sizeof(pred
));
1977 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_PREDICT_FAILURE
,
1978 0, 0, &pred
, sizeof(pred
), &num_out
, NULL
)) {
1979 if (ata_debugmode
> 1)
1980 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
1985 if (ata_debugmode
> 1) {
1986 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
1987 " PredictFailure: 0x%08x\n"
1988 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
1989 (unsigned)pred
.PredictFailure
,
1990 pred
.VendorSpecific
[0], pred
.VendorSpecific
[1], pred
.VendorSpecific
[2],
1991 pred
.VendorSpecific
[sizeof(pred
.VendorSpecific
)-1]
1995 memcpy(data
, pred
.VendorSpecific
, sizeof(pred
.VendorSpecific
));
1996 return (!pred
.PredictFailure
? 0 : 1);
2000 /////////////////////////////////////////////////////////////////////////////
2002 // Return true if Intel ICHxR RAID volume
2003 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2005 if (!(data
->desc
.VendorIdOffset
&& data
->desc
.ProductIdOffset
))
2007 const char * vendor
= data
->raw
+ data
->desc
.VendorIdOffset
;
2008 if (!(!strnicmp(vendor
, "Intel", 5) && strspn(vendor
+5, " ") == strlen(vendor
+5)))
2010 if (strnicmp(data
->raw
+ data
->desc
.ProductIdOffset
, "Raid ", 5))
2015 // get DEV_* for open handle
2016 static win_dev_type
get_controller_type(HANDLE hdevice
, bool admin
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2018 // Get BusType from device descriptor
2019 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2020 if (storage_query_property_ioctl(hdevice
, &data
))
2023 // Newer BusType* values are missing in older includes
2024 switch ((int)data
.desc
.BusType
) {
2026 case 0x0b: // BusTypeSata
2028 memset(ata_version_ex
, 0, sizeof(*ata_version_ex
));
2033 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2034 if (is_intel_raid_volume(&data
))
2036 // LSI/3ware RAID volume: supports SMART_*
2037 if (admin
&& smart_get_version(hdevice
, ata_version_ex
) >= 0)
2041 case 0x09: // BusTypeiScsi
2042 case 0x0a: // BusTypeSas
2054 // get DEV_* for device path
2055 static win_dev_type
get_controller_type(const char * path
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
2058 HANDLE h
= CreateFileA(path
, GENERIC_READ
|GENERIC_WRITE
,
2059 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2060 if (h
== INVALID_HANDLE_VALUE
) {
2062 h
= CreateFileA(path
, 0,
2063 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2064 if (h
== INVALID_HANDLE_VALUE
)
2067 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2068 pout(" %s: successfully opened%s\n", path
, (!admin
? " (without admin rights)" :""));
2069 win_dev_type type
= get_controller_type(h
, admin
, ata_version_ex
);
2074 // get DEV_* for physical drive number
2075 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2078 snprintf(path
, sizeof(path
)-1, "\\\\.\\PhysicalDrive%d", drive
);
2079 return get_controller_type(path
, ata_version_ex
);
2082 static win_dev_type
get_phy_drive_type(int drive
)
2084 return get_phy_drive_type(drive
, 0);
2087 // get DEV_* for logical drive number
2088 static win_dev_type
get_log_drive_type(int drive
)
2091 snprintf(path
, sizeof(path
)-1, "\\\\.\\%c:", 'A'+drive
);
2092 return get_controller_type(path
);
2095 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2096 static int get_identify_from_device_property(HANDLE hdevice
, ata_identify_device
* id
)
2098 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2099 if (storage_query_property_ioctl(hdevice
, &data
))
2102 memset(id
, 0, sizeof(*id
));
2104 // Some drivers split ATA model string into VendorId and ProductId,
2105 // others return it as ProductId only.
2106 char model
[sizeof(id
->model
) + 1] = "";
2109 if (data
.desc
.VendorIdOffset
) {
2110 for ( ;i
< sizeof(model
)-1 && data
.raw
[data
.desc
.VendorIdOffset
+i
]; i
++)
2111 model
[i
] = data
.raw
[data
.desc
.VendorIdOffset
+i
];
2114 if (data
.desc
.ProductIdOffset
) {
2115 while (i
> 1 && model
[i
-2] == ' ') // Keep last blank from VendorId
2117 // Ignore VendorId "ATA"
2118 if (i
<= 4 && !strncmp(model
, "ATA", 3) && (i
== 3 || model
[3] == ' '))
2120 for (unsigned j
= 0; i
< sizeof(model
)-1 && data
.raw
[data
.desc
.ProductIdOffset
+j
]; i
++, j
++)
2121 model
[i
] = data
.raw
[data
.desc
.ProductIdOffset
+j
];
2124 while (i
> 0 && model
[i
-1] == ' ')
2127 copy_swapped(id
->model
, model
, sizeof(id
->model
));
2129 if (data
.desc
.ProductRevisionOffset
)
2130 copy_swapped(id
->fw_rev
, data
.raw
+data
.desc
.ProductRevisionOffset
, sizeof(id
->fw_rev
));
2132 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
2133 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
2137 // Get Serial Number in IDENTIFY from WMI
2138 static bool get_serial_from_wmi(int drive
, ata_identify_device
* id
)
2140 bool debug
= (ata_debugmode
> 1);
2143 if (!ws
.connect()) {
2145 pout("WMI connect failed\n");
2150 if (!ws
.query1(wo
, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2151 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2154 std::string serial
= wo
.get_str("SerialNumber");
2156 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive
, wo
.get_str("Model").c_str(), serial
.c_str());
2158 copy_swapped(id
->serial_no
, serial
.c_str(), sizeof(id
->serial_no
));
2163 /////////////////////////////////////////////////////////////////////////////
2164 // USB ID detection using WMI
2166 // Get USB ID for a physical drive number
2167 static bool get_usb_id(int drive
, unsigned short & vendor_id
, unsigned short & product_id
)
2169 bool debug
= (scsi_debugmode
> 1);
2172 if (!ws
.connect()) {
2174 pout("WMI connect failed\n");
2180 if (!ws
.query1(wo
, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2183 std::string name
= wo
.get_str("Model");
2185 pout("PhysicalDrive%d, \"%s\":\n", drive
, name
.c_str());
2187 // Get USB_CONTROLLER -> DEVICE associations
2189 if (!ws
.query(we
, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2192 unsigned short usb_venid
= 0, prev_usb_venid
= 0;
2193 unsigned short usb_proid
= 0, prev_usb_proid
= 0;
2194 std::string prev_usb_ant
;
2195 std::string prev_ant
, ant
, dep
;
2197 const regular_expression
regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED
);
2199 while (we
.next(wo
)) {
2201 // Find next 'USB_CONTROLLER, DEVICE' pair
2202 ant
= wo
.get_str("Antecedent");
2203 dep
= wo
.get_str("Dependent");
2205 if (debug
&& ant
!= prev_ant
)
2206 pout(" %s:\n", ant
.c_str());
2209 regmatch_t match
[2];
2210 if (!(regex
.execute(dep
.c_str(), 2, match
) && match
[1].rm_so
>= 0)) {
2212 pout(" | (\"%s\")\n", dep
.c_str());
2216 std::string
devid(dep
.c_str()+match
[1].rm_so
, match
[1].rm_eo
-match
[1].rm_so
);
2218 if (str_starts_with(devid
, "USB\\\\VID_")) {
2219 // USB bridge entry, save CONTROLLER, ID
2221 if (!(sscanf(devid
.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2222 &prev_usb_venid
, &prev_usb_proid
, &nc
) == 2 && nc
== 9+4+5+4)) {
2223 prev_usb_venid
= prev_usb_proid
= 0;
2227 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid
.c_str(), prev_usb_venid
, prev_usb_proid
);
2230 else if (str_starts_with(devid
, "USBSTOR\\\\")) {
2231 // USBSTOR device found
2233 pout(" +--> \"%s\"\n", devid
.c_str());
2237 if (!ws
.query1(wo2
, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid
.c_str()))
2239 std::string name2
= wo2
.get_str("Name");
2241 // Continue if not name of physical disk drive
2242 if (name2
!= name
) {
2244 pout(" +---> (\"%s\")\n", name2
.c_str());
2248 // Fail if previous USB bridge is associated to other controller or ID is unknown
2249 if (!(ant
== prev_usb_ant
&& prev_usb_venid
)) {
2251 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2
.c_str());
2255 // Handle multiple devices with same name
2257 // Fail if multiple devices with same name have different USB bridge types
2258 if (!(usb_venid
== prev_usb_venid
&& usb_proid
== prev_usb_proid
)) {
2260 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2
.c_str());
2266 usb_venid
= prev_usb_venid
;
2267 usb_proid
= prev_usb_proid
;
2269 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2
.c_str(), usb_venid
, usb_proid
);
2271 // Continue to check for duplicate names ...
2275 pout(" | \"%s\"\n", devid
.c_str());
2282 vendor_id
= usb_venid
;
2283 product_id
= usb_proid
;
2289 /////////////////////////////////////////////////////////////////////////////
2291 // Call GetDevicePowerState()
2292 // returns: 1=active, 0=standby, -1=error
2293 // (This would also work for SCSI drives)
2295 static int get_device_power_state(HANDLE hdevice
)
2298 if (!GetDevicePowerState(hdevice
, &state
)) {
2299 long err
= GetLastError();
2301 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
2302 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2303 // TODO: This may not work as expected on transient errors,
2304 // because smartd interprets -1 as SLEEP mode regardless of errno.
2308 if (ata_debugmode
> 1)
2309 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
2314 /////////////////////////////////////////////////////////////////////////////
2316 // Get default ATA device options
2318 static const char * ata_get_def_options()
2320 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2321 // STORAGE_*, SCSI_MINIPORT_*
2325 // Common routines for devices with HANDLEs
2327 win_smart_device::~win_smart_device() throw()
2329 if (m_fh
!= INVALID_HANDLE_VALUE
)
2330 ::CloseHandle(m_fh
);
2333 bool win_smart_device::is_open() const
2335 return (m_fh
!= INVALID_HANDLE_VALUE
);
2338 bool win_smart_device::close()
2340 if (m_fh
== INVALID_HANDLE_VALUE
)
2342 BOOL rc
= ::CloseHandle(m_fh
);
2343 m_fh
= INVALID_HANDLE_VALUE
;
2349 win_ata_device::win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
2350 : smart_device(intf
, dev_name
, "ata", req_type
),
2351 m_usr_options(false),
2354 m_id_is_cached(false),
2361 win_ata_device::~win_ata_device() throw()
2368 bool win_ata_device::open()
2370 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
2371 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2372 char drive
[2+1] = "", options
[8+1] = ""; int n1
= -1, n2
= -1;
2373 if ( sscanf(name
, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive
, &n1
, options
, &n2
) >= 1
2374 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2375 return open(sdxy_to_phydrive(drive
), -1, options
, -1);
2377 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2378 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
2380 if ( sscanf(name
, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
2381 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2382 return open(sdxy_to_phydrive(drive
), -1, options
, port
);
2384 // pd<m>,N => Physical drive <m>, RAID port N
2385 int phydrive
= -1; port
= ~0; n1
= -1; n2
= -1;
2386 if ( sscanf(name
, "pd%d%n,%u%n", &phydrive
, &n1
, &port
, &n2
) >= 1
2387 && phydrive
>= 0 && ((n1
== len
&& (int)port
< 0) || (n2
== len
&& port
< 32))) {
2388 return open(phydrive
, -1, "", (int)port
);
2390 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2391 int logdrive
= drive_letter(name
);
2392 if (logdrive
>= 0) {
2393 return open(-1, logdrive
, "", -1);
2396 return set_err(EINVAL
);
2400 bool win_ata_device::open(int phydrive
, int logdrive
, const char * options
, int port
)
2404 if (0 <= phydrive
&& phydrive
<= 255)
2405 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive
= phydrive
));
2406 else if (0 <= logdrive
&& logdrive
<= 'Z'-'A')
2407 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\%c:", 'A'+logdrive
);
2409 return set_err(ENOENT
);
2412 HANDLE h
= INVALID_HANDLE_VALUE
;
2413 if (!(*options
&& !options
[strspn(options
, "fp")])) {
2414 // Open with admin rights
2416 h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
2417 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2418 NULL
, OPEN_EXISTING
, 0, 0);
2420 if (h
== INVALID_HANDLE_VALUE
) {
2421 // Open without admin rights
2423 h
= CreateFileA(devpath
, 0,
2424 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2425 NULL
, OPEN_EXISTING
, 0, 0);
2427 if (h
== INVALID_HANDLE_VALUE
) {
2428 long err
= GetLastError();
2429 if (err
== ERROR_FILE_NOT_FOUND
)
2430 set_err(ENOENT
, "%s: not found", devpath
);
2431 else if (err
== ERROR_ACCESS_DENIED
)
2432 set_err(EACCES
, "%s: access denied", devpath
);
2434 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
2439 // Warn once if admin rights are missing
2441 static bool noadmin_warning
= false;
2442 if (!noadmin_warning
) {
2443 pout("Warning: Limited functionality due to missing admin rights\n");
2444 noadmin_warning
= true;
2448 if (ata_debugmode
> 1)
2449 pout("%s: successfully opened%s\n", devpath
, (!m_admin
? " (without admin rights)" :""));
2451 m_usr_options
= false;
2453 // Save user options
2454 m_options
= options
; m_usr_options
= true;
2457 // RAID: SMART_* and SCSI_MINIPORT
2460 // Set default options according to Windows version
2461 static const char * def_options
= ata_get_def_options();
2462 m_options
= def_options
;
2465 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2470 // 3ware RAID: Get port map
2471 GETVERSIONINPARAMS_EX vers_ex
;
2472 int devmap
= smart_get_version(h
, &vers_ex
);
2474 // 3ware RAID if vendor id present
2475 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2477 unsigned long portmap
= 0;
2478 if (port
>= 0 && devmap
>= 0) {
2479 // 3ware RAID: check vendor id
2481 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2482 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2483 vers_ex
.wIdentifier
);
2487 portmap
= vers_ex
.dwDeviceMapEx
;
2490 pout("%s: ATA driver has no SMART support\n", devpath
);
2491 if (!is_permissive()) {
2493 return set_err(ENOSYS
);
2497 m_smartver_state
= 1;
2500 // 3ware RAID: update devicemap first
2502 if (!update_3ware_devicemap_ioctl(h
)) {
2503 if ( smart_get_version(h
, &vers_ex
) >= 0
2504 && vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
2505 portmap
= vers_ex
.dwDeviceMapEx
;
2507 // Check port existence
2508 if (!(portmap
& (1L << port
))) {
2509 if (!is_permissive()) {
2511 return set_err(ENOENT
, "%s: Port %d is empty or does not exist", devpath
, port
);
2520 /////////////////////////////////////////////////////////////////////////////
2522 // Interface to ATA devices
2523 bool win_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2525 // No multi-sector support for now, see above
2526 // warning about IOCTL_ATA_PASS_THROUGH
2527 if (!ata_cmd_is_supported(in
,
2528 ata_device::supports_data_out
|
2529 ata_device::supports_output_regs
|
2530 ata_device::supports_48bit
)
2534 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2535 if ( m_is_3ware
&& m_port
< 0
2536 && in
.in_regs
.command
== ATA_SMART_CMD
2537 && in
.in_regs
.features
== ATA_SMART_DISABLE
)
2538 return set_err(ENOSYS
, "SMART DISABLE requires 3ware port number");
2540 // Determine ioctl functions valid for this ATA cmd
2541 const char * valid_options
= 0;
2543 switch (in
.in_regs
.command
) {
2544 case ATA_IDENTIFY_DEVICE
:
2545 case ATA_IDENTIFY_PACKET_DEVICE
:
2546 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2547 // and SCSI_MINIPORT_* if requested by user
2548 valid_options
= (m_usr_options
? "saimf" : "saif");
2551 case ATA_CHECK_POWER_MODE
:
2552 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2553 valid_options
= "pai3";
2557 switch (in
.in_regs
.features
) {
2558 case ATA_SMART_READ_VALUES
:
2559 case ATA_SMART_READ_THRESHOLDS
:
2560 case ATA_SMART_AUTOSAVE
:
2561 case ATA_SMART_ENABLE
:
2562 case ATA_SMART_DISABLE
:
2563 case ATA_SMART_AUTO_OFFLINE
:
2564 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2565 // and SCSI_MINIPORT_* if requested by user
2566 valid_options
= (m_usr_options
? "saimf" : "saif");
2569 case ATA_SMART_IMMEDIATE_OFFLINE
:
2570 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2571 valid_options
= (m_usr_options
|| in
.in_regs
.lba_low
!= 127/*ABORT*/ ?
2575 case ATA_SMART_READ_LOG_SECTOR
:
2576 // SMART_RCV_DRIVE_DATA does not support READ_LOG
2577 // Try SCSI_MINIPORT also to skip buggy class driver
2578 // SMART functions do not support multi sector I/O.
2580 valid_options
= (m_usr_options
? "saim3" : "aim3");
2582 valid_options
= "a";
2585 case ATA_SMART_WRITE_LOG_SECTOR
:
2586 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2587 // but SCSI_MINIPORT_* only if requested by user and single sector.
2588 valid_options
= (in
.size
== 512 && m_usr_options
? "am" : "a");
2591 case ATA_SMART_STATUS
:
2592 valid_options
= (m_usr_options
? "saimf" : "saif");
2596 // Unknown SMART command, handle below
2602 // Other ATA command, handle below
2606 if (!valid_options
) {
2607 // No special ATA command found above, select a generic pass through ioctl.
2608 if (!( in
.direction
== ata_cmd_in::no_data
2609 || (in
.direction
== ata_cmd_in::data_in
&& in
.size
== 512))
2610 || in
.in_regs
.is_48bit_cmd() )
2611 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2612 valid_options
= "a";
2614 // ATA/IDE_PASS_THROUGH
2615 valid_options
= "ai";
2619 // Restrict to IOCTL_STORAGE_*
2620 if (strchr(valid_options
, 'f'))
2621 valid_options
= "f";
2622 else if (strchr(valid_options
, 'p'))
2623 valid_options
= "p";
2625 return set_err(ENOSYS
, "Function requires admin rights");
2629 IDEREGS regs
, prev_regs
;
2631 const ata_in_regs
& lo
= in
.in_regs
;
2632 regs
.bFeaturesReg
= lo
.features
;
2633 regs
.bSectorCountReg
= lo
.sector_count
;
2634 regs
.bSectorNumberReg
= lo
.lba_low
;
2635 regs
.bCylLowReg
= lo
.lba_mid
;
2636 regs
.bCylHighReg
= lo
.lba_high
;
2637 regs
.bDriveHeadReg
= lo
.device
;
2638 regs
.bCommandReg
= lo
.command
;
2641 if (in
.in_regs
.is_48bit_cmd()) {
2642 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2643 prev_regs
.bFeaturesReg
= hi
.features
;
2644 prev_regs
.bSectorCountReg
= hi
.sector_count
;
2645 prev_regs
.bSectorNumberReg
= hi
.lba_low
;
2646 prev_regs
.bCylLowReg
= hi
.lba_mid
;
2647 prev_regs
.bCylHighReg
= hi
.lba_high
;
2648 prev_regs
.bDriveHeadReg
= hi
.device
;
2649 prev_regs
.bCommandReg
= hi
.command
;
2650 prev_regs
.bReserved
= 0;
2653 // Set data direction
2656 switch (in
.direction
) {
2657 case ata_cmd_in::no_data
:
2659 case ata_cmd_in::data_in
:
2660 datasize
= (int)in
.size
;
2661 data
= (char *)in
.buffer
;
2663 case ata_cmd_in::data_out
:
2664 datasize
= -(int)in
.size
;
2665 data
= (char *)in
.buffer
;
2668 return set_err(EINVAL
, "win_ata_device::ata_pass_through: invalid direction=%d",
2673 // Try all valid ioctls in the order specified in m_options
2674 bool powered_up
= false;
2675 bool out_regs_set
= false;
2676 bool id_is_cached
= false;
2677 const char * options
= m_options
.c_str();
2679 for (int i
= 0; ; i
++) {
2680 char opt
= options
[i
];
2683 if (in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& powered_up
) {
2684 // Power up reported by GetDevicePowerState() and no ioctl available
2685 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2686 regs
.bSectorCountReg
= 0xff;
2687 out_regs_set
= true;
2691 return set_err(ENOSYS
);
2693 if (!strchr(valid_options
, opt
))
2694 // Invalid for this command
2698 assert( datasize
== 0 || datasize
== 512
2699 || (datasize
== -512 && strchr("am", opt
))
2700 || (datasize
> 512 && opt
== 'a'));
2705 // call SMART_GET_VERSION once for each drive
2706 if (m_smartver_state
> 1) {
2707 rc
= -1; errno
= ENOSYS
;
2710 if (!m_smartver_state
) {
2711 assert(m_port
== -1);
2712 GETVERSIONINPARAMS_EX vers_ex
;
2713 if (smart_get_version(get_fh(), &vers_ex
) < 0) {
2714 if (!failuretest_permissive
) {
2715 m_smartver_state
= 2;
2716 rc
= -1; errno
= ENOSYS
;
2719 failuretest_permissive
--;
2722 // 3ware RAID if vendor id present
2723 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2726 m_smartver_state
= 1;
2728 rc
= smart_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2729 out_regs_set
= (in
.in_regs
.features
== ATA_SMART_STATUS
);
2730 id_is_cached
= (m_port
< 0); // Not cached by 3ware driver
2733 rc
= ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s
, data
, datasize
);
2734 id_is_cached
= (m_port
< 0);
2737 rc
= ata_pass_through_ioctl(get_fh(), ®s
,
2738 (in
.in_regs
.is_48bit_cmd() ? &prev_regs
: 0),
2740 out_regs_set
= true;
2743 rc
= ide_pass_through_ioctl(get_fh(), ®s
, data
, datasize
);
2744 out_regs_set
= true;
2747 if (in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
) {
2748 rc
= get_identify_from_device_property(get_fh(), (ata_identify_device
*)data
);
2749 if (rc
== 0 && m_phydrive
>= 0)
2750 get_serial_from_wmi(m_phydrive
, (ata_identify_device
*)data
);
2751 id_is_cached
= true;
2753 else if (in
.in_regs
.command
== ATA_SMART_CMD
) switch (in
.in_regs
.features
) {
2754 case ATA_SMART_READ_VALUES
:
2755 rc
= storage_predict_failure_ioctl(get_fh(), data
);
2759 case ATA_SMART_ENABLE
:
2762 case ATA_SMART_STATUS
:
2763 rc
= storage_predict_failure_ioctl(get_fh());
2765 // Good SMART status
2766 out
.out_regs
.lba_high
= 0xc2; out
.out_regs
.lba_mid
= 0x4f;
2770 out
.out_regs
.lba_high
= 0x2c; out
.out_regs
.lba_mid
= 0xf4;
2775 errno
= ENOSYS
; rc
= -1;
2778 errno
= ENOSYS
; rc
= -1;
2782 rc
= ata_via_3ware_miniport_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2783 out_regs_set
= true;
2786 assert(in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& in
.size
== 0);
2787 rc
= get_device_power_state(get_fh());
2789 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2790 // spin up the drive => simulate ATA result STANDBY.
2791 regs
.bSectorCountReg
= 0x00;
2792 out_regs_set
= true;
2795 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2796 // only if it is selected by the device driver => try a passthrough ioctl to get the
2797 // actual mode, if none available simulate ACTIVE/IDLE.
2799 rc
= -1; errno
= ENOSYS
;
2805 // Working ioctl found
2808 if (errno
!= ENOSYS
)
2809 // Abort on I/O error
2810 return set_err(errno
);
2812 out_regs_set
= false;
2813 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2816 // Return IDEREGS if set
2818 ata_out_regs
& lo
= out
.out_regs
;
2819 lo
.error
= regs
.bFeaturesReg
;
2820 lo
.sector_count
= regs
.bSectorCountReg
;
2821 lo
.lba_low
= regs
.bSectorNumberReg
;
2822 lo
.lba_mid
= regs
.bCylLowReg
;
2823 lo
.lba_high
= regs
.bCylHighReg
;
2824 lo
.device
= regs
.bDriveHeadReg
;
2825 lo
.status
= regs
.bCommandReg
;
2826 if (in
.in_regs
.is_48bit_cmd()) {
2827 ata_out_regs
& hi
= out
.out_regs
.prev
;
2828 hi
.sector_count
= prev_regs
.bSectorCountReg
;
2829 hi
.lba_low
= prev_regs
.bSectorNumberReg
;
2830 hi
.lba_mid
= prev_regs
.bCylLowReg
;
2831 hi
.lba_high
= prev_regs
.bCylHighReg
;
2835 if ( in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
2836 || in
.in_regs
.command
== ATA_IDENTIFY_PACKET_DEVICE
)
2837 // Update ata_identify_is_cached() result according to ioctl used.
2838 m_id_is_cached
= id_is_cached
;
2843 // Return true if OS caches the ATA identify sector
2844 bool win_ata_device::ata_identify_is_cached() const
2846 return m_id_is_cached
;
2850 //////////////////////////////////////////////////////////////////////
2853 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
)
2855 // Get driver info to check CSMI support
2856 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf
;
2857 memset(&driver_info_buf
, 0, sizeof(driver_info_buf
));
2858 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO
, &driver_info_buf
.IoctlHeader
, sizeof(driver_info_buf
)))
2861 if (scsi_debugmode
> 1) {
2862 const CSMI_SAS_DRIVER_INFO
& driver_info
= driver_info_buf
.Information
;
2863 pout("CSMI_SAS_DRIVER_INFO:\n");
2864 pout(" Name: \"%.81s\"\n", driver_info
.szName
);
2865 pout(" Description: \"%.81s\"\n", driver_info
.szDescription
);
2866 pout(" Revision: %d.%d\n", driver_info
.usMajorRevision
, driver_info
.usMinorRevision
);
2870 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf
;
2871 memset(&phy_info_buf
, 0, sizeof(phy_info_buf
));
2872 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO
, &phy_info_buf
.IoctlHeader
, sizeof(phy_info_buf
)))
2875 phy_info
= phy_info_buf
.Information
;
2876 if (phy_info
.bNumberOfPhys
> sizeof(phy_info
.Phy
)/sizeof(phy_info
.Phy
[0]))
2877 return set_err(EIO
, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info
.bNumberOfPhys
);
2879 if (scsi_debugmode
> 1) {
2880 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info
.bNumberOfPhys
);
2881 for (int i
= 0; i
< phy_info
.bNumberOfPhys
; i
++) {
2882 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
2883 const CSMI_SAS_IDENTIFY
& id
= pe
.Identify
, & at
= pe
.Attached
;
2884 pout("Phy[%d] Port: 0x%02x\n", i
, pe
.bPortIdentifier
);
2885 pout(" Type: 0x%02x, 0x%02x\n", id
.bDeviceType
, at
.bDeviceType
);
2886 pout(" InitProto: 0x%02x, 0x%02x\n", id
.bInitiatorPortProtocol
, at
.bInitiatorPortProtocol
);
2887 pout(" TargetProto: 0x%02x, 0x%02x\n", id
.bTargetPortProtocol
, at
.bTargetPortProtocol
);
2888 pout(" PhyIdent: 0x%02x, 0x%02x\n", id
.bPhyIdentifier
, at
.bPhyIdentifier
);
2889 const unsigned char * b
= id
.bSASAddress
;
2890 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2891 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2893 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2894 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2901 bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO
& phy_info
, unsigned phy_no
)
2903 // Check Phy presence
2904 if (phy_no
>= phy_info
.bNumberOfPhys
)
2905 return set_err(ENOENT
, "Port %u does not exist (#ports: %d)", phy_no
,
2906 phy_info
.bNumberOfPhys
);
2908 const CSMI_SAS_PHY_ENTITY
& phy_ent
= phy_info
.Phy
[phy_no
];
2909 if (phy_ent
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2910 return set_err(ENOENT
, "No device on port %u", phy_no
);
2912 switch (phy_ent
.Attached
.bTargetPortProtocol
) {
2913 case CSMI_SAS_PROTOCOL_SATA
:
2914 case CSMI_SAS_PROTOCOL_STP
:
2917 return set_err(ENOENT
, "No SATA device on port %u (protocol: %u)",
2918 phy_no
, phy_ent
.Attached
.bTargetPortProtocol
);
2924 bool csmi_device::select_phy(unsigned phy_no
)
2926 CSMI_SAS_PHY_INFO phy_info
;
2927 if (!get_phy_info(phy_info
))
2931 if (!check_phy(phy_info
, phy_no
))
2934 m_phy_ent
= phy_info
.Phy
[phy_no
];
2939 bool csmi_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2941 if (!ata_cmd_is_supported(in
,
2942 ata_device::supports_data_out
|
2943 ata_device::supports_output_regs
|
2944 ata_device::supports_multi_sector
|
2945 ata_device::supports_48bit
,
2950 // Create buffer with appropriate size
2951 raw_buffer
pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER
) + in
.size
);
2952 CSMI_SAS_STP_PASSTHRU_BUFFER
* pthru_buf
= (CSMI_SAS_STP_PASSTHRU_BUFFER
*)pthru_raw_buf
.data();
2954 // Set addresses from Phy info
2955 CSMI_SAS_STP_PASSTHRU
& pthru
= pthru_buf
->Parameters
;
2956 const CSMI_SAS_PHY_ENTITY
& phy_ent
= get_phy_ent();
2957 pthru
.bPhyIdentifier
= phy_ent
.Identify
.bPhyIdentifier
;
2958 pthru
.bPortIdentifier
= phy_ent
.bPortIdentifier
;
2959 memcpy(pthru
.bDestinationSASAddress
, phy_ent
.Attached
.bSASAddress
,
2960 sizeof(pthru
.bDestinationSASAddress
));
2961 pthru
.bConnectionRate
= CSMI_SAS_LINK_RATE_NEGOTIATED
;
2963 // Set transfer mode
2964 switch (in
.direction
) {
2965 case ata_cmd_in::no_data
:
2966 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_UNSPECIFIED
;
2968 case ata_cmd_in::data_in
:
2969 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_READ
;
2970 pthru
.uDataLength
= in
.size
;
2972 case ata_cmd_in::data_out
:
2973 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_WRITE
;
2974 pthru
.uDataLength
= in
.size
;
2975 memcpy(pthru_buf
->bDataBuffer
, in
.buffer
, in
.size
);
2978 return set_err(EINVAL
, "csmi_ata_device::ata_pass_through: invalid direction=%d",
2982 // Set host-to-device FIS
2984 unsigned char * fis
= pthru
.bCommandFIS
;
2985 const ata_in_regs
& lo
= in
.in_regs
;
2986 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2987 fis
[ 0] = 0x27; // Type: host-to-device FIS
2988 fis
[ 1] = 0x80; // Bit7: Update command register
2989 fis
[ 2] = lo
.command
;
2990 fis
[ 3] = lo
.features
;
2991 fis
[ 4] = lo
.lba_low
;
2992 fis
[ 5] = lo
.lba_mid
;
2993 fis
[ 6] = lo
.lba_high
;
2994 fis
[ 7] = lo
.device
;
2995 fis
[ 8] = hi
.lba_low
;
2996 fis
[ 9] = hi
.lba_mid
;
2997 fis
[10] = hi
.lba_high
;
2998 fis
[11] = hi
.features
;
2999 fis
[12] = lo
.sector_count
;
3000 fis
[13] = hi
.sector_count
;
3004 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU
, &pthru_buf
->IoctlHeader
, pthru_raw_buf
.size())) {
3008 // Get device-to-host FIS
3010 const unsigned char * fis
= pthru_buf
->Status
.bStatusFIS
;
3011 ata_out_regs
& lo
= out
.out_regs
;
3012 lo
.status
= fis
[ 2];
3014 lo
.lba_low
= fis
[ 4];
3015 lo
.lba_mid
= fis
[ 5];
3016 lo
.lba_high
= fis
[ 6];
3017 lo
.device
= fis
[ 7];
3018 lo
.sector_count
= fis
[12];
3019 if (in
.in_regs
.is_48bit_cmd()) {
3020 ata_out_regs
& hi
= out
.out_regs
.prev
;
3021 hi
.lba_low
= fis
[ 8];
3022 hi
.lba_mid
= fis
[ 9];
3023 hi
.lba_high
= fis
[10];
3024 hi
.sector_count
= fis
[13];
3029 if (in
.direction
== ata_cmd_in::data_in
)
3030 // TODO: Check ptru_buf->Status.uDataBytes
3031 memcpy(in
.buffer
, pthru_buf
->bDataBuffer
, in
.size
);
3037 //////////////////////////////////////////////////////////////////////
3040 win_csmi_device::win_csmi_device(smart_interface
* intf
, const char * dev_name
,
3041 const char * req_type
)
3042 : smart_device(intf
, dev_name
, "ata", req_type
),
3043 m_fh(INVALID_HANDLE_VALUE
), m_phy_no(0)
3047 win_csmi_device::~win_csmi_device() throw()
3049 if (m_fh
!= INVALID_HANDLE_VALUE
)
3053 bool win_csmi_device::is_open() const
3055 return (m_fh
!= INVALID_HANDLE_VALUE
);
3058 bool win_csmi_device::close()
3060 if (m_fh
== INVALID_HANDLE_VALUE
)
3062 BOOL rc
= CloseHandle(m_fh
);
3063 m_fh
= INVALID_HANDLE_VALUE
;
3068 bool win_csmi_device::open_scsi()
3071 unsigned contr_no
= ~0, phy_no
= ~0; int nc
= -1;
3072 const char * name
= skipdev(get_dev_name());
3073 if (!( sscanf(name
, "csmi%u,%u%n", &contr_no
, &phy_no
, &nc
) >= 0
3074 && nc
== (int)strlen(name
) && contr_no
<= 9 && phy_no
< 32) )
3075 return set_err(EINVAL
);
3077 // Open controller handle
3079 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\Scsi%u:", contr_no
);
3081 HANDLE h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
3082 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3083 (SECURITY_ATTRIBUTES
*)0, OPEN_EXISTING
, 0, 0);
3085 if (h
== INVALID_HANDLE_VALUE
) {
3086 long err
= GetLastError();
3087 if (err
== ERROR_FILE_NOT_FOUND
)
3088 set_err(ENOENT
, "%s: not found", devpath
);
3089 else if (err
== ERROR_ACCESS_DENIED
)
3090 set_err(EACCES
, "%s: access denied", devpath
);
3092 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
3096 if (scsi_debugmode
> 1)
3097 pout(" %s: successfully opened\n", devpath
);
3105 bool win_csmi_device::open()
3110 // Get Phy info for this drive
3111 if (!select_phy(m_phy_no
)) {
3120 bool win_csmi_device::csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
3121 unsigned csmi_bufsiz
)
3123 // Determine signature
3126 case CC_CSMI_SAS_GET_DRIVER_INFO
:
3127 sig
= CSMI_ALL_SIGNATURE
; break;
3128 case CC_CSMI_SAS_GET_PHY_INFO
:
3129 case CC_CSMI_SAS_STP_PASSTHRU
:
3130 sig
= CSMI_SAS_SIGNATURE
; break;
3132 return set_err(ENOSYS
, "Unknown CSMI code=%u", code
);
3136 csmi_buffer
->HeaderLength
= sizeof(IOCTL_HEADER
);
3137 strncpy((char *)csmi_buffer
->Signature
, sig
, sizeof(csmi_buffer
->Signature
));
3138 csmi_buffer
->Timeout
= CSMI_SAS_TIMEOUT
;
3139 csmi_buffer
->ControlCode
= code
;
3140 csmi_buffer
->ReturnCode
= 0;
3141 csmi_buffer
->Length
= csmi_bufsiz
- sizeof(IOCTL_HEADER
);
3145 if (!DeviceIoControl(m_fh
, IOCTL_SCSI_MINIPORT
,
3146 csmi_buffer
, csmi_bufsiz
, csmi_buffer
, csmi_bufsiz
, &num_out
, (OVERLAPPED
*)0)) {
3147 long err
= GetLastError();
3149 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code
, err
);
3150 if ( err
== ERROR_INVALID_FUNCTION
3151 || err
== ERROR_NOT_SUPPORTED
3152 || err
== ERROR_DEV_NOT_EXIST
)
3153 return set_err(ENOSYS
, "CSMI is not supported (Error=%ld)", err
);
3155 return set_err(EIO
, "CSMI(%u) failed with Error=%ld", code
, err
);
3159 if (csmi_buffer
->ReturnCode
) {
3160 if (scsi_debugmode
) {
3161 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3162 code
, (unsigned)csmi_buffer
->ReturnCode
);
3164 return set_err(EIO
, "CSMI(%u) failed with ReturnCode=%u", code
, (unsigned)csmi_buffer
->ReturnCode
);
3167 if (scsi_debugmode
> 1)
3168 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code
, (unsigned)num_out
);
3174 /////////////////////////////////////////////////////////////////////////////
3175 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3176 // Only supported in NT and later
3177 /////////////////////////////////////////////////////////////////////////////
3179 win_scsi_device::win_scsi_device(smart_interface
* intf
,
3180 const char * dev_name
, const char * req_type
)
3181 : smart_device(intf
, dev_name
, "scsi", req_type
)
3185 bool win_scsi_device::open()
3187 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
3188 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3189 char drive
[2+1] = ""; int sub_addr
= -1; int n1
= -1; int n2
= -1;
3190 if ( sscanf(name
, "sd%2[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
3191 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
3192 return open(sdxy_to_phydrive(drive
), -1, -1, sub_addr
);
3194 // pd<m>,N => Physical drive <m>, RAID port N
3195 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
3196 if ( sscanf(name
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
3197 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
3198 return open(pd_num
, -1, -1, sub_addr
);
3200 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3201 int logdrive
= drive_letter(name
);
3202 if (logdrive
>= 0) {
3203 return open(-1, logdrive
, -1, -1);
3205 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3206 int tape_num
= -1; n1
= -1;
3207 if (sscanf(name
, "st%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3208 return open(-1, -1, tape_num
, -1);
3210 tape_num
= -1; n1
= -1;
3211 if (sscanf(name
, "nst%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3212 return open(-1, -1, tape_num
, -1);
3214 // tape<m> => tape drive <m>
3215 tape_num
= -1; n1
= -1;
3216 if (sscanf(name
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3217 return open(-1, -1, tape_num
, -1);
3220 return set_err(EINVAL
);
3223 bool win_scsi_device::open(int pd_num
, int ld_num
, int tape_num
, int /*sub_addr*/)
3226 b
[sizeof(b
) - 1] = '\0';
3228 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
3229 else if (ld_num
>= 0)
3230 snprintf(b
, sizeof(b
) - 1, "\\\\.\\%c:", 'A' + ld_num
);
3231 else if (tape_num
>= 0)
3232 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
3239 HANDLE h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
3240 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
3241 OPEN_EXISTING
, 0, 0);
3242 if (h
== INVALID_HANDLE_VALUE
) {
3243 set_err(ENODEV
, "%s: Open failed, Error=%u", b
, (unsigned)GetLastError());
3252 SCSI_PASS_THROUGH_DIRECT spt
;
3254 UCHAR ucSenseBuf
[64];
3255 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
3258 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3259 // Used if DataTransferLength not supported by *_DIRECT.
3260 static long scsi_pass_through_indirect(HANDLE h
,
3261 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
* sbd
)
3263 struct SCSI_PASS_THROUGH_WITH_BUFFERS
{
3264 SCSI_PASS_THROUGH spt
;
3266 UCHAR ucSenseBuf
[sizeof(sbd
->ucSenseBuf
)];
3267 UCHAR ucDataBuf
[512];
3270 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
3271 memset(&sb
, 0, sizeof(sb
));
3273 // DATA_OUT not implemented yet
3274 if (!( sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
3275 && sbd
->spt
.DataTransferLength
<= sizeof(sb
.ucDataBuf
)))
3276 return ERROR_INVALID_PARAMETER
;
3278 sb
.spt
.Length
= sizeof(sb
.spt
);
3279 sb
.spt
.CdbLength
= sbd
->spt
.CdbLength
;
3280 memcpy(sb
.spt
.Cdb
, sbd
->spt
.Cdb
, sizeof(sb
.spt
.Cdb
));
3281 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3282 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
3283 sb
.spt
.DataIn
= sbd
->spt
.DataIn
;
3284 sb
.spt
.DataTransferLength
= sbd
->spt
.DataTransferLength
;
3285 sb
.spt
.DataBufferOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
3286 sb
.spt
.TimeOutValue
= sbd
->spt
.TimeOutValue
;
3289 if (!DeviceIoControl(h
, IOCTL_SCSI_PASS_THROUGH
,
3290 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3291 return GetLastError();
3293 sbd
->spt
.ScsiStatus
= sb
.spt
.ScsiStatus
;
3294 if (sb
.spt
.ScsiStatus
& SCSI_STATUS_CHECK_CONDITION
)
3295 memcpy(sbd
->ucSenseBuf
, sb
.ucSenseBuf
, sizeof(sbd
->ucSenseBuf
));
3297 sbd
->spt
.DataTransferLength
= sb
.spt
.DataTransferLength
;
3298 if (sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
&& sb
.spt
.DataTransferLength
> 0)
3299 memcpy(sbd
->spt
.DataBuffer
, sb
.ucDataBuf
, sb
.spt
.DataTransferLength
);
3304 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3305 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io
* iop
)
3307 int report
= scsi_debugmode
; // TODO
3311 const unsigned char * ucp
= iop
->cmnd
;
3314 const int sz
= (int)sizeof(buff
);
3316 np
= scsi_get_opcode_name(ucp
[0]);
3317 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3318 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3319 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3321 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3322 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3324 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3325 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3326 (trunc
? " [only first 256 bytes shown]" : ""));
3327 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3330 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3334 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3335 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3336 set_err(EINVAL
, "cmnd_len too large");
3340 memset(&sb
, 0, sizeof(sb
));
3341 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3342 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3343 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3344 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3345 sb
.spt
.SenseInfoOffset
=
3346 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3347 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3350 switch (iop
->dxfer_dir
) {
3352 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3354 case DXFER_FROM_DEVICE
:
3355 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3356 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3357 sb
.spt
.DataBuffer
= iop
->dxferp
;
3358 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3359 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3360 if (sb
.spt
.DataTransferLength
== 1)
3363 case DXFER_TO_DEVICE
:
3364 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3365 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3366 sb
.spt
.DataBuffer
= iop
->dxferp
;
3369 set_err(EINVAL
, "bad dxfer_dir");
3376 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3377 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3378 err
= GetLastError();
3381 err
= scsi_pass_through_indirect(get_fh(), &sb
);
3384 return set_err((err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
),
3385 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3386 (direct
? "_DIRECT" : ""), err
);
3388 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3389 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3390 int slen
= sb
.ucSenseBuf
[7] + 8;
3392 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3393 slen
= sizeof(sb
.ucSenseBuf
);
3394 if (slen
> (int)iop
->max_sense_len
)
3395 slen
= iop
->max_sense_len
;
3396 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3397 iop
->resp_sense_len
= slen
;
3400 pout(" >>> Sense buffer, len=%d:\n", slen
);
3401 dStrHex(iop
->sensep
, slen
, 1);
3403 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3404 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3405 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3406 iop
->sensep
[2], iop
->sensep
[3]);
3408 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3409 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3410 iop
->sensep
[12], iop
->sensep
[13]);
3413 iop
->resp_sense_len
= 0;
3415 if ((iop
->dxfer_len
> 0) && (sb
.spt
.DataTransferLength
> 0))
3416 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3420 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3421 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3422 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
3423 (trunc
? " [only first 256 bytes shown]" : ""));
3424 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3429 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3430 static long scsi_pass_through_direct(HANDLE fd
, UCHAR targetid
, struct scsi_cmnd_io
* iop
)
3432 int report
= scsi_debugmode
; // TODO
3436 const unsigned char * ucp
= iop
->cmnd
;
3439 const int sz
= (int)sizeof(buff
);
3441 np
= scsi_get_opcode_name(ucp
[0]);
3442 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3443 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3444 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3446 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3447 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3449 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3450 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3451 (trunc
? " [only first 256 bytes shown]" : ""));
3452 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3455 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3459 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3460 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3464 memset(&sb
, 0, sizeof(sb
));
3465 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3466 //sb.spt.PathId = 0;
3467 sb
.spt
.TargetId
= targetid
;
3469 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3470 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3471 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3472 sb
.spt
.SenseInfoOffset
=
3473 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3474 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3477 switch (iop
->dxfer_dir
) {
3479 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3481 case DXFER_FROM_DEVICE
:
3482 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3483 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3484 sb
.spt
.DataBuffer
= iop
->dxferp
;
3485 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3486 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3487 if (sb
.spt
.DataTransferLength
== 1)
3490 case DXFER_TO_DEVICE
:
3491 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3492 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3493 sb
.spt
.DataBuffer
= iop
->dxferp
;
3502 if (!DeviceIoControl(fd
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3503 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3504 err
= GetLastError();
3507 err
= scsi_pass_through_indirect(fd
, &sb
);
3514 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3515 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3516 int slen
= sb
.ucSenseBuf
[7] + 8;
3518 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3519 slen
= sizeof(sb
.ucSenseBuf
);
3520 if (slen
> (int)iop
->max_sense_len
)
3521 slen
= iop
->max_sense_len
;
3522 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3523 iop
->resp_sense_len
= slen
;
3526 pout(" >>> Sense buffer, len=%d:\n", slen
);
3527 dStrHex(iop
->sensep
, slen
, 1);
3529 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3530 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3531 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3532 iop
->sensep
[2], iop
->sensep
[3]);
3534 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3535 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3536 iop
->sensep
[12], iop
->sensep
[13]);
3539 iop
->resp_sense_len
= 0;
3541 if ((iop
->dxfer_len
> 0) && (sb
.spt
.DataTransferLength
> 0))
3542 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3546 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3547 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3548 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
3549 (trunc
? " [only first 256 bytes shown]" : ""));
3550 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3556 // Areca RAID Controller(SAS Device)
3557 win_areca_scsi_device::win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3558 : smart_device(intf
, dev_name
, "areca", "areca")
3560 set_fh(INVALID_HANDLE_VALUE
);
3561 set_disknum(disknum
);
3563 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3566 bool win_areca_scsi_device::open()
3574 hFh
= CreateFile( get_dev_name(),
3575 GENERIC_READ
|GENERIC_WRITE
,
3576 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3581 if(hFh
== INVALID_HANDLE_VALUE
)
3590 smart_device
* win_areca_scsi_device::autodetect_open()
3595 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3597 int ioctlreturn
= 0;
3599 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3600 if ( ioctlreturn
|| iop
->scsi_status
)
3602 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3603 if ( ioctlreturn
|| iop
->scsi_status
)
3613 bool win_areca_scsi_device::arcmsr_lock()
3615 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3619 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3620 return set_err(EINVAL
, "unable to parse device name");
3622 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3623 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3624 if ( m_mutex
== NULL
)
3626 return set_err(EIO
, "CreateMutex failed");
3629 // atomic access to driver
3630 WaitForSingleObject(m_mutex
, INFINITE
);
3636 bool win_areca_scsi_device::arcmsr_unlock()
3638 if( m_mutex
!= NULL
)
3640 ReleaseMutex(m_mutex
);
3641 CloseHandle(m_mutex
);
3648 // Areca RAID Controller(SATA Disk)
3649 win_areca_ata_device::win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3650 : smart_device(intf
, dev_name
, "areca", "areca")
3652 set_fh(INVALID_HANDLE_VALUE
);
3653 set_disknum(disknum
);
3655 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3658 bool win_areca_ata_device::open()
3666 hFh
= CreateFile( get_dev_name(),
3667 GENERIC_READ
|GENERIC_WRITE
,
3668 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3673 if(hFh
== INVALID_HANDLE_VALUE
)
3682 smart_device
* win_areca_ata_device::autodetect_open()
3686 // autodetect device type
3687 is_ata
= arcmsr_get_dev_type();
3701 smart_device_auto_ptr
newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
3704 newdev
->open(); // TODO: Can possibly pass open fd
3706 return newdev
.release();
3709 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3711 int ioctlreturn
= 0;
3713 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3714 if ( ioctlreturn
|| iop
->scsi_status
)
3716 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3717 if ( ioctlreturn
|| iop
->scsi_status
)
3727 bool win_areca_ata_device::arcmsr_lock()
3729 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3733 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3734 return set_err(EINVAL
, "unable to parse device name");
3736 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3737 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3738 if ( m_mutex
== NULL
)
3740 return set_err(EIO
, "CreateMutex failed");
3743 // atomic access to driver
3744 WaitForSingleObject(m_mutex
, INFINITE
);
3750 bool win_areca_ata_device::arcmsr_unlock()
3752 if( m_mutex
!= NULL
)
3754 ReleaseMutex(m_mutex
);
3755 CloseHandle(m_mutex
);
3762 //////////////////////////////////////////////////////////////////////////////////////////////////
3767 /////////////////////////////////////////////////////////////////////////////
3769 // Initialize platform interface and register with smi()
3770 void smart_interface::init()
3773 // Remove "." from DLL search path if supported
3774 // to prevent DLL preloading attacks
3775 BOOL (WINAPI
* SetDllDirectoryA_p
)(LPCSTR
) = (BOOL (WINAPI
*)(LPCSTR
))
3776 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
3777 if (SetDllDirectoryA_p
)
3778 SetDllDirectoryA_p("");
3781 static os_win32::win_smart_interface the_win_interface
;
3782 smart_interface::set(&the_win_interface
);
3788 // Get exe directory
3789 // (prototype in utiliy.h)
3790 std::string
get_exe_dir()
3792 char path
[MAX_PATH
];
3793 // Get path of this exe
3794 if (!GetModuleFileNameA(GetModuleHandleA(0), path
, sizeof(path
)))
3795 throw std::runtime_error("GetModuleFileName() failed");
3796 // Replace backslash by slash
3798 for (int i
= 0; path
[i
]; i
++)
3799 if (path
[i
] == '\\') {
3800 path
[i
] = '/'; sl
= i
;