4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-14 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 3923 2014-06-25 17:10:46Z 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
403 /// Get bitmask of used ports
404 unsigned get_ports_used();
408 : smart_device(never_called
)
409 { memset(&m_phy_ent
, 0, sizeof(m_phy_ent
)); }
412 bool get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
);
414 /// Select physical drive
415 bool select_port(int port
);
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 int m_port
; ///< Port 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
))
608 if (vi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
610 if (vi
.dwMajorVersion
> 6 || (vi
.dwMajorVersion
== 6 && vi
.dwMinorVersion
>= 2)) {
611 // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
612 // actual OS version, see:
613 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
615 ULONGLONG major_equal
= VerSetConditionMask(0, VER_MAJORVERSION
, VER_EQUAL
);
616 for (unsigned major
= vi
.dwMajorVersion
; major
<= 9; major
++) {
617 OSVERSIONINFOEXA vi2
; memset(&vi2
, 0, sizeof(vi2
));
618 vi2
.dwOSVersionInfoSize
= sizeof(vi2
); vi2
.dwMajorVersion
= major
;
619 if (!VerifyVersionInfo(&vi2
, VER_MAJORVERSION
, major_equal
))
621 if (vi
.dwMajorVersion
< major
) {
622 vi
.dwMajorVersion
= major
; vi
.dwMinorVersion
= 0;
625 ULONGLONG minor_equal
= VerSetConditionMask(0, VER_MINORVERSION
, VER_EQUAL
);
626 for (unsigned minor
= vi
.dwMinorVersion
; minor
<= 9; minor
++) {
627 memset(&vi2
, 0, sizeof(vi2
)); vi2
.dwOSVersionInfoSize
= sizeof(vi2
);
628 vi2
.dwMinorVersion
= minor
;
629 if (!VerifyVersionInfo(&vi2
, VER_MINORVERSION
, minor_equal
))
631 vi
.dwMinorVersion
= minor
;
639 if (vi
.dwMajorVersion
<= 0xf && vi
.dwMinorVersion
<= 0xf) {
640 bool ws
= (vi
.wProductType
<= VER_NT_WORKSTATION
);
641 switch (vi
.dwMajorVersion
<< 4 | vi
.dwMinorVersion
) {
642 case 0x50: w
= "2000"; break;
643 case 0x51: w
= "xp"; break;
644 case 0x52: w
= (!GetSystemMetrics(89/*SM_SERVERR2*/)
645 ? "2003" : "2003r2"); break;
646 case 0x60: w
= (ws
? "vista" : "2008" ); break;
647 case 0x61: w
= (ws
? "win7" : "2008r2"); break;
648 case 0x62: w
= (ws
? "win8" : "2012" ); break;
649 case 0x63: w
= (ws
? "win8.1": "2012r2"); break;
654 const char * w64
= "";
661 snprintf(vptr
, vlen
, "-%s%u.%u%s",
662 (vi
.dwPlatformId
==VER_PLATFORM_WIN32_NT
? "nt" : "??"),
663 (unsigned)vi
.dwMajorVersion
, (unsigned)vi
.dwMinorVersion
, w64
);
664 else if (vi
.wServicePackMinor
)
665 snprintf(vptr
, vlen
, "-%s%s-sp%u.%u", w
, w64
, vi
.wServicePackMajor
, vi
.wServicePackMinor
);
666 else if (vi
.wServicePackMajor
)
667 snprintf(vptr
, vlen
, "-%s%s-sp%u", w
, w64
, vi
.wServicePackMajor
);
669 snprintf(vptr
, vlen
, "-%s%s", w
, w64
);
674 // MSVCRT only provides ftime() which uses GetSystemTime()
675 // This provides only ~15ms resolution by default.
676 // Use QueryPerformanceCounter instead (~300ns).
677 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
678 int64_t win_smart_interface::get_timer_usec()
680 static int64_t freq
= 0;
684 freq
= (QueryPerformanceFrequency(&t
) ? t
.QuadPart
: -1);
686 return smart_interface::get_timer_usec();
688 if (!QueryPerformanceCounter(&t
))
690 if (!(0 <= t
.QuadPart
&& t
.QuadPart
<= (int64_t)(~(uint64_t)0 >> 1)/1000000))
693 return (t
.QuadPart
* 1000000LL) / freq
;
698 // Return value for device detection functions
699 enum win_dev_type
{ DEV_UNKNOWN
= 0, DEV_ATA
, DEV_SCSI
, DEV_USB
};
701 static win_dev_type
get_phy_drive_type(int drive
);
702 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
);
703 static win_dev_type
get_log_drive_type(int drive
);
704 static bool get_usb_id(int drive
, unsigned short & vendor_id
,
705 unsigned short & product_id
);
707 static const char * ata_get_def_options(void);
710 static int is_permissive()
712 if (!failuretest_permissive
) {
713 pout("To continue, add one or more '-T permissive' options.\n");
716 failuretest_permissive
--;
720 // return number for drive letter, -1 on error
721 // "[A-Za-z]:([/\\][.]?)?" => 0-25
722 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
723 static int drive_letter(const char * s
)
725 return ( (('A' <= s
[0] && s
[0] <= 'Z') || ('a' <= s
[0] && s
[0] <= 'z'))
727 && (!s
[2] || ( strchr("/\\\"", s
[2])
728 && (!s
[3] || (s
[3] == '.' && !s
[4]))) ) ?
729 (s
[0] & 0x1f) - 1 : -1);
732 // Skip trailing "/dev/", do not allow "/dev/X:"
733 static const char * skipdev(const char * s
)
735 return (!strncmp(s
, "/dev/", 5) && drive_letter(s
+5) < 0 ? s
+5 : s
);
738 ata_device
* win_smart_interface::get_ata_device(const char * name
, const char * type
)
740 const char * testname
= skipdev(name
);
741 if (!strncmp(testname
, "csmi", 4))
742 return new win_csmi_device(this, name
, type
);
743 if (!strncmp(testname
, "tw_cli", 6))
744 return new win_tw_cli_device(this, name
, type
);
745 return new win_ata_device(this, name
, type
);
748 scsi_device
* win_smart_interface::get_scsi_device(const char * name
, const char * type
)
750 return new win_scsi_device(this, name
, type
);
753 static int sdxy_to_phydrive(const char (& xy
)[2+1])
755 int phydrive
= xy
[0] - 'a';
757 phydrive
= (phydrive
+ 1) * ('z' - 'a' + 1) + (xy
[1] - 'a');
761 static win_dev_type
get_dev_type(const char * name
, int & phydrive
)
764 name
= skipdev(name
);
765 if (!strncmp(name
, "st", 2))
767 if (!strncmp(name
, "nst", 3))
769 if (!strncmp(name
, "tape", 4))
772 int logdrive
= drive_letter(name
);
774 win_dev_type type
= get_log_drive_type(logdrive
);
775 return (type
!= DEV_UNKNOWN
? type
: DEV_SCSI
);
778 char drive
[2+1] = "";
779 if (sscanf(name
, "sd%2[a-z]", drive
) == 1) {
780 phydrive
= sdxy_to_phydrive(drive
);
781 return get_phy_drive_type(phydrive
);
785 if (sscanf(name
, "pd%d", &phydrive
) == 1 && phydrive
>= 0)
786 return get_phy_drive_type(phydrive
);
790 smart_device
* win_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
793 int disknum
= -1, n1
= -1, n2
= -1;
797 if (sscanf(type
, "areca,%n%d/%d%n", &n1
, &disknum
, &encnum
, &n2
) >= 1 || n1
== 6) {
798 if (!(1 <= disknum
&& disknum
<= 128)) {
799 set_err(EINVAL
, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum
);
802 if (!(1 <= encnum
&& encnum
<= 8)) {
803 set_err(EINVAL
, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum
);
807 name
= skipdev(name
);
808 #define ARECA_MAX_CTLR_NUM 16
811 if (sscanf(name
, "arcmsr%d%n", &ctlrindex
, &n1
) >= 1 && n1
== (int)strlen(name
)) {
813 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
814 2. map arcmsrX into "\\\\.\\scsiX"
816 for (int idx
= 0; idx
< ARECA_MAX_CTLR_NUM
; idx
++) {
817 memset(devpath
, 0, sizeof(devpath
));
818 snprintf(devpath
, sizeof(devpath
), "\\\\.\\scsi%d:", idx
);
819 win_areca_ata_device
*arcdev
= new win_areca_ata_device(this, devpath
, disknum
, encnum
);
820 if(arcdev
->arcmsr_probe()) {
821 if(ctlrindex
-- == 0) {
827 set_err(ENOENT
, "No Areca controller found");
830 set_err(EINVAL
, "Option -d areca,N/E requires device name /dev/arcmsrX");
836 std::string
win_smart_interface::get_valid_custom_dev_types_str()
838 return "areca,N[/E]";
842 smart_device
* win_smart_interface::autodetect_smart_device(const char * name
)
844 const char * testname
= skipdev(name
);
845 if (str_starts_with(testname
, "hd"))
846 return new win_ata_device(this, name
, "");
848 if (str_starts_with(testname
, "tw_cli"))
849 return new win_tw_cli_device(this, name
, "");
851 if (str_starts_with(testname
, "csmi"))
852 return new win_csmi_device(this, name
, "");
855 win_dev_type type
= get_dev_type(name
, phydrive
);
858 return new win_ata_device(this, name
, "");
859 if (type
== DEV_SCSI
)
860 return new win_scsi_device(this, name
, "");
862 if (type
== DEV_USB
) {
864 unsigned short vendor_id
= 0, product_id
= 0;
865 if (!(phydrive
>= 0 && get_usb_id(phydrive
, vendor_id
, product_id
))) {
866 set_err(EINVAL
, "Unable to read USB device ID");
869 // Get type name for this ID
870 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
873 // Return SAT/USB device for this type
874 return get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
883 bool win_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
884 const char * type
, const char * pattern
/* = 0*/)
887 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
891 // Check for "[*,]pd" type
893 char type2
[16+1] = "";
896 if (!strcmp(type
, "pd")) {
900 else if (sscanf(type
, "%16[^,],pd%n", type2
, &nc
) == 1 &&
901 nc
== (int)strlen(type
)) {
908 bool ata
, scsi
, usb
, csmi
;
910 ata
= scsi
= usb
= csmi
= true;
913 ata
= scsi
= usb
= csmi
= false;
914 if (!strcmp(type
, "ata"))
916 else if (!strcmp(type
, "scsi"))
918 else if (!strcmp(type
, "usb"))
920 else if (!strcmp(type
, "csmi"))
923 set_err(EINVAL
, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type
);
930 if (ata
|| scsi
|| usb
) {
931 // Scan up to 128 drives and 2 3ware controllers
932 const int max_raid
= 2;
933 bool raid_seen
[max_raid
] = {false, false};
935 for (int i
= 0; i
< 128; i
++) {
937 snprintf(name
, sizeof(name
), "/dev/pd%d", i
);
938 else if (i
+ 'a' <= 'z')
939 snprintf(name
, sizeof(name
), "/dev/sd%c", i
+ 'a');
941 snprintf(name
, sizeof(name
), "/dev/sd%c%c",
942 i
/ ('z'-'a'+1) - 1 + 'a',
943 i
% ('z'-'a'+1) + 'a');
945 GETVERSIONINPARAMS_EX vers_ex
;
947 switch (get_phy_drive_type(i
, (ata
? &vers_ex
: 0))) {
949 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
953 // Interpret RAID drive map if present
954 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
) {
955 // Skip if too many controllers or logical drive from this controller already seen
956 if (!(vers_ex
.wControllerId
< max_raid
&& !raid_seen
[vers_ex
.wControllerId
]))
958 raid_seen
[vers_ex
.wControllerId
] = true;
959 // Add physical drives
960 int len
= strlen(name
);
961 for (int pi
= 0; pi
< 32; pi
++) {
962 if (vers_ex
.dwDeviceMapEx
& (1L << pi
)) {
963 snprintf(name
+len
, sizeof(name
)-1-len
, ",%u", pi
);
964 devlist
.push_back( new win_ata_device(this, name
, "ata") );
969 devlist
.push_back( new win_ata_device(this, name
, "ata") );
974 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
977 devlist
.push_back( new win_scsi_device(this, name
, "scsi") );
981 // STORAGE_QUERY_PROPERTY returned USB
985 // TODO: Use common function for this and autodetect_smart_device()
987 unsigned short vendor_id
= 0, product_id
= 0;
988 if (!get_usb_id(i
, vendor_id
, product_id
))
990 // Get type name for this ID
991 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
994 // Return SAT/USB device for this type
995 ata_device
* dev
= get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
998 devlist
.push_back(dev
);
1010 // Scan CSMI devices
1011 for (int i
= 0; i
<= 9; i
++) {
1012 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,0", i
);
1013 win_csmi_device
test_dev(this, name
, "");
1014 if (!test_dev
.open_scsi())
1017 unsigned ports_used
= test_dev
.get_ports_used();
1021 for (int pi
= 0; pi
< 32; pi
++) {
1022 if (!(ports_used
& (1 << pi
)))
1024 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,%d", i
, pi
);
1025 devlist
.push_back( new win_csmi_device(this, name
, "ata") );
1033 // get examples for smartctl
1034 std::string
win_smart_interface::get_app_examples(const char * appname
)
1036 if (strcmp(appname
, "smartctl"))
1038 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1039 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1040 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1041 " (Enables SMART on first disk)\n\n"
1042 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1043 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1044 " (Prints Self-Test & Attribute errors)\n"
1045 " smartctl -a /dev/sda\n"
1046 " (Prints all information for disk on PhysicalDrive 0)\n"
1047 " smartctl -a /dev/pd3\n"
1048 " (Prints all information for disk on PhysicalDrive 3)\n"
1049 " smartctl -a /dev/tape1\n"
1050 " (Prints all information for SCSI tape on Tape 1)\n"
1051 " smartctl -A /dev/hdb,3\n"
1052 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1053 " smartctl -A /dev/tw_cli/c0/p1\n"
1054 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1055 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1056 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1057 " on 1st Areca RAID controller)\n"
1059 " ATA SMART access methods and ordering may be specified by modifiers\n"
1060 " following the device name: /dev/hdX:[saicm], where\n"
1061 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1062 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1063 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1065 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1070 bool win_smart_interface::disable_system_auto_standby(bool disable
)
1073 SYSTEM_POWER_STATUS ps
;
1074 if (!GetSystemPowerStatus(&ps
))
1075 return set_err(ENOSYS
, "Unknown power status");
1076 if (ps
.ACLineStatus
!= 1) {
1077 SetThreadExecutionState(ES_CONTINUOUS
);
1078 if (ps
.ACLineStatus
== 0)
1079 set_err(EIO
, "AC offline");
1081 set_err(EIO
, "Unknown AC line status");
1086 if (!SetThreadExecutionState(ES_CONTINUOUS
| (disable
? ES_SYSTEM_REQUIRED
: 0)))
1087 return set_err(ENOSYS
);
1092 /////////////////////////////////////////////////////////////////////////////
1094 /////////////////////////////////////////////////////////////////////////////
1096 #define SMART_CYL_LOW 0x4F
1097 #define SMART_CYL_HI 0xC2
1099 static void print_ide_regs(const IDEREGS
* r
, int out
)
1101 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1102 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
1103 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
1106 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
1108 pout(" Input : "); print_ide_regs(ri
, 0);
1110 pout(" Output: "); print_ide_regs(ro
, 1);
1114 /////////////////////////////////////////////////////////////////////////////
1116 // call SMART_GET_VERSION, return device map or -1 on error
1118 static int smart_get_version(HANDLE hdevice
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
1120 GETVERSIONINPARAMS vers
; memset(&vers
, 0, sizeof(vers
));
1121 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1124 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
1125 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1127 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1131 assert(num_out
== sizeof(GETVERSIONINPARAMS
));
1133 if (ata_debugmode
> 1) {
1134 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1135 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1136 (unsigned)num_out
, vers
.bVersion
, vers
.bRevision
,
1137 (unsigned)vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1138 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1139 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1140 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, (unsigned)vers_ex
.dwDeviceMapEx
);
1144 *ata_version_ex
= vers_ex
;
1146 // TODO: Check vers.fCapabilities here?
1147 return vers
.bIDEDeviceMap
;
1151 // call SMART_* ioctl
1153 static int smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
1155 SENDCMDINPARAMS inpar
;
1156 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
1158 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
1159 const SENDCMDOUTPARAMS
* outpar
;
1160 DWORD code
, num_out
;
1161 unsigned int size_out
;
1164 memset(&inpar
, 0, sizeof(inpar
));
1165 inpar
.irDriveRegs
= *regs
;
1167 // Older drivers may require bits 5 and 7 set
1168 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1169 inpar
.irDriveRegs
.bDriveHeadReg
|= 0xa0;
1171 // Drive number 0-3 was required on Win9x/ME only
1172 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1173 //inpar.bDriveNumber = drive;
1177 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
1178 inpar_ex
.bPortNumber
= port
;
1181 if (datasize
== 512) {
1182 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
1183 inpar
.cBufferSize
= size_out
= 512;
1185 else if (datasize
== 0) {
1186 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
1187 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
1188 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
1189 // Note: cBufferSize must be 0 on Win9x
1198 memset(&outbuf
, 0, sizeof(outbuf
));
1200 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
1201 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
1202 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1203 long err
= GetLastError();
1204 if (ata_debugmode
&& (err
!= ERROR_INVALID_PARAMETER
|| ata_debugmode
> 1)) {
1205 pout(" %s failed, Error=%ld\n", name
, err
);
1206 print_ide_regs_io(regs
, NULL
);
1208 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
1209 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/
1210 || err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1213 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1215 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
1217 if (outpar
->DriverStatus
.bDriverError
) {
1218 if (ata_debugmode
) {
1219 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1220 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
1221 print_ide_regs_io(regs
, NULL
);
1223 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1227 if (ata_debugmode
> 1) {
1228 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name
,
1229 (unsigned)num_out
, (unsigned)outpar
->cBufferSize
);
1230 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
1231 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
1235 memcpy(data
, outpar
->bBuffer
, 512);
1236 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
1237 if (nonempty(outpar
->bBuffer
, sizeof(IDEREGS
)))
1238 memcpy(regs
, outpar
->bBuffer
, sizeof(IDEREGS
));
1239 else { // Workaround for driver not returning regs
1241 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1242 *regs
= inpar
.irDriveRegs
;
1250 /////////////////////////////////////////////////////////////////////////////
1251 // IDE PASS THROUGH (2000, XP, undocumented)
1253 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1254 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1256 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
1258 if (datasize
> 512) {
1262 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
1263 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1265 const unsigned char magic
= 0xcf;
1272 buf
->IdeReg
= *regs
;
1273 buf
->DataBufferSize
= datasize
;
1275 buf
->DataBuffer
[0] = magic
;
1277 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
1278 buf
, size
, buf
, size
, &num_out
, NULL
)) {
1279 long err
= GetLastError();
1280 if (ata_debugmode
) {
1281 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
1282 print_ide_regs_io(regs
, NULL
);
1284 VirtualFree(buf
, 0, MEM_RELEASE
);
1285 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1290 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
1291 if (ata_debugmode
) {
1292 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1293 print_ide_regs_io(regs
, &buf
->IdeReg
);
1295 VirtualFree(buf
, 0, MEM_RELEASE
);
1300 // Check and copy data
1302 if ( num_out
!= size
1303 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
1304 if (ata_debugmode
) {
1305 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1306 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1307 print_ide_regs_io(regs
, &buf
->IdeReg
);
1309 VirtualFree(buf
, 0, MEM_RELEASE
);
1313 memcpy(data
, buf
->DataBuffer
, datasize
);
1316 if (ata_debugmode
> 1) {
1317 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1318 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1319 print_ide_regs_io(regs
, &buf
->IdeReg
);
1321 *regs
= buf
->IdeReg
;
1323 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1324 VirtualFree(buf
, 0, MEM_RELEASE
);
1329 /////////////////////////////////////////////////////////////////////////////
1330 // ATA PASS THROUGH (Win2003, XP SP2)
1333 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1334 // transfer per command. Therefore, multi-sector transfers are only supported
1335 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1336 // or READ/WRITE LOG EXT work only with single sector transfers.
1337 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1339 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1341 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, IDEREGS
* prev_regs
, char * data
, int datasize
)
1343 const int max_sectors
= 32; // TODO: Allocate dynamic buffer
1346 ATA_PASS_THROUGH_EX apt
;
1348 UCHAR ucDataBuf
[max_sectors
* 512];
1349 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
1351 const unsigned char magic
= 0xcf;
1353 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
1354 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
1355 //ab.apt.PathId = 0;
1356 //ab.apt.TargetId = 0;
1358 ab
.apt
.TimeOutValue
= 10;
1359 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
1360 ab
.apt
.DataBufferOffset
= size
;
1363 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1367 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
1368 ab
.apt
.DataTransferLength
= datasize
;
1370 ab
.ucDataBuf
[0] = magic
;
1372 else if (datasize
< 0) {
1373 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1377 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
1378 ab
.apt
.DataTransferLength
= -datasize
;
1380 memcpy(ab
.ucDataBuf
, data
, -datasize
);
1383 assert(ab
.apt
.AtaFlags
== 0);
1384 assert(ab
.apt
.DataTransferLength
== 0);
1387 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
1388 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
1389 IDEREGS
* ptfregs
= (IDEREGS
*)ab
.apt
.PreviousTaskFile
;
1393 *ptfregs
= *prev_regs
;
1394 ab
.apt
.AtaFlags
|= ATA_FLAGS_48BIT_COMMAND
;
1398 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
1399 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
1400 long err
= GetLastError();
1401 if (ata_debugmode
) {
1402 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
1403 print_ide_regs_io(regs
, NULL
);
1405 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1410 if (ctfregs
->bCommandReg
/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1411 if (ata_debugmode
) {
1412 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1413 print_ide_regs_io(regs
, ctfregs
);
1419 // Check and copy data
1421 if ( num_out
!= size
1422 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
1423 if (ata_debugmode
) {
1424 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out
);
1425 print_ide_regs_io(regs
, ctfregs
);
1430 memcpy(data
, ab
.ucDataBuf
, datasize
);
1433 if (ata_debugmode
> 1) {
1434 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out
);
1435 print_ide_regs_io(regs
, ctfregs
);
1439 *prev_regs
= *ptfregs
;
1445 /////////////////////////////////////////////////////////////////////////////
1446 // SMART IOCTL via SCSI MINIPORT ioctl
1448 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1449 // miniport driver (via SCSI port driver scsiport.sys).
1450 // It can be used to skip the missing or broken handling of some SMART
1451 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1453 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
1456 DWORD code
= 0; const char * name
= 0;
1457 if (regs
->bCommandReg
== ATA_IDENTIFY_DEVICE
) {
1458 code
= IOCTL_SCSI_MINIPORT_IDENTIFY
; name
= "IDENTIFY";
1460 else if (regs
->bCommandReg
== ATA_SMART_CMD
) switch (regs
->bFeaturesReg
) {
1461 case ATA_SMART_READ_VALUES
:
1462 code
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
; name
= "READ_SMART_ATTRIBS"; break;
1463 case ATA_SMART_READ_THRESHOLDS
:
1464 code
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
; name
= "READ_SMART_THRESHOLDS"; break;
1465 case ATA_SMART_ENABLE
:
1466 code
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
; name
= "ENABLE_SMART"; break;
1467 case ATA_SMART_DISABLE
:
1468 code
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
; name
= "DISABLE_SMART"; break;
1469 case ATA_SMART_STATUS
:
1470 code
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
; name
= "RETURN_STATUS"; break;
1471 case ATA_SMART_AUTOSAVE
:
1472 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
; name
= "ENABLE_DISABLE_AUTOSAVE"; break;
1473 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1474 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1475 case ATA_SMART_IMMEDIATE_OFFLINE
:
1476 code
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
; name
= "EXECUTE_OFFLINE_DIAGS"; break;
1477 case ATA_SMART_AUTO_OFFLINE
:
1478 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
; name
= "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1479 case ATA_SMART_READ_LOG_SECTOR
:
1480 code
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
; name
= "READ_SMART_LOG"; break;
1481 case ATA_SMART_WRITE_LOG_SECTOR
:
1482 code
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
; name
= "WRITE_SMART_LOG"; break;
1491 SRB_IO_CONTROL srbc
;
1494 SENDCMDOUTPARAMS out
;
1498 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(SENDCMDINPARAMS
)-1+512);
1499 memset(&sb
, 0, sizeof(sb
));
1503 if (datasize
> (int)sizeof(sb
.space
)+1) {
1509 else if (datasize
< 0) {
1510 if (-datasize
> (int)sizeof(sb
.space
)+1) {
1515 memcpy(sb
.params
.in
.bBuffer
, data
, size
);
1517 else if (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1518 size
= sizeof(IDEREGS
);
1521 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1522 memcpy(sb
.srbc
.Signature
, "SCSIDISK", 8); // atapi.sys
1523 sb
.srbc
.Timeout
= 60; // seconds
1524 sb
.srbc
.ControlCode
= code
;
1525 //sb.srbc.ReturnCode = 0;
1526 sb
.srbc
.Length
= sizeof(SENDCMDINPARAMS
)-1 + size
;
1527 sb
.params
.in
.irDriveRegs
= *regs
;
1528 sb
.params
.in
.cBufferSize
= size
;
1530 // Call miniport ioctl
1531 size
+= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)-1;
1533 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1534 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
1535 long err
= GetLastError();
1536 if (ata_debugmode
) {
1537 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name
, err
);
1538 print_ide_regs_io(regs
, NULL
);
1540 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1545 if (sb
.srbc
.ReturnCode
) {
1546 if (ata_debugmode
) {
1547 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name
, (unsigned)sb
.srbc
.ReturnCode
);
1548 print_ide_regs_io(regs
, NULL
);
1554 if (sb
.params
.out
.DriverStatus
.bDriverError
) {
1555 if (ata_debugmode
) {
1556 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1557 sb
.params
.out
.DriverStatus
.bDriverError
, sb
.params
.out
.DriverStatus
.bIDEError
);
1558 print_ide_regs_io(regs
, NULL
);
1560 errno
= (!sb
.params
.out
.DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1564 if (ata_debugmode
> 1) {
1565 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name
,
1566 (unsigned)num_out
, (unsigned)sb
.params
.out
.cBufferSize
);
1567 print_ide_regs_io(regs
, (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
?
1568 (const IDEREGS
*)(sb
.params
.out
.bBuffer
) : 0));
1572 memcpy(data
, sb
.params
.out
.bBuffer
, datasize
);
1573 else if (datasize
== 0 && code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1574 memcpy(regs
, sb
.params
.out
.bBuffer
, sizeof(IDEREGS
));
1580 /////////////////////////////////////////////////////////////////////////////
1582 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1584 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1587 SRB_IO_CONTROL srbc
;
1591 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1593 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1597 memset(&sb
, 0, sizeof(sb
));
1598 strncpy((char *)sb
.srbc
.Signature
, "<3ware>", sizeof(sb
.srbc
.Signature
));
1599 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1600 sb
.srbc
.Timeout
= 60; // seconds
1601 sb
.srbc
.ControlCode
= 0xA0000000;
1602 sb
.srbc
.ReturnCode
= 0;
1603 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1605 sb
.regs
.bReserved
= port
;
1608 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1609 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1610 long err
= GetLastError();
1611 if (ata_debugmode
) {
1612 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1613 print_ide_regs_io(regs
, NULL
);
1615 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1619 if (sb
.srbc
.ReturnCode
) {
1620 if (ata_debugmode
) {
1621 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb
.srbc
.ReturnCode
);
1622 print_ide_regs_io(regs
, NULL
);
1630 memcpy(data
, sb
.buffer
, datasize
);
1632 if (ata_debugmode
> 1) {
1633 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out
);
1634 print_ide_regs_io(regs
, &sb
.regs
);
1642 /////////////////////////////////////////////////////////////////////////////
1644 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1645 // 3DM/CLI "Rescan Controller" function does not to always update it.
1647 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1649 SRB_IO_CONTROL srbc
;
1650 memset(&srbc
, 0, sizeof(srbc
));
1651 strncpy((char *)srbc
.Signature
, "<3ware>", sizeof(srbc
.Signature
));
1652 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1653 srbc
.Timeout
= 60; // seconds
1654 srbc
.ControlCode
= 0xCC010014;
1655 srbc
.ReturnCode
= 0;
1659 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1660 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1661 long err
= GetLastError();
1663 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1664 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1667 if (srbc
.ReturnCode
) {
1669 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc
.ReturnCode
);
1673 if (ata_debugmode
> 1)
1674 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1680 /////////////////////////////////////////////////////////////////////////////
1682 // Routines for pseudo device /dev/tw_cli/*
1683 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1686 // Get clipboard data
1688 static int get_clipboard(char * data
, int datasize
)
1690 if (!OpenClipboard(NULL
))
1692 HANDLE h
= GetClipboardData(CF_TEXT
);
1697 const void * p
= GlobalLock(h
);
1698 int n
= GlobalSize(h
);
1708 // Run a command, write stdout to dataout
1709 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1711 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1713 // Create stdout pipe
1714 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1715 HANDLE pipe_out_w
, h
;
1716 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1718 HANDLE self
= GetCurrentProcess();
1720 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1721 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1722 CloseHandle(pipe_out_w
);
1726 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1727 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1728 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1733 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1734 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1735 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1736 si
.dwFlags
= STARTF_USESTDHANDLES
;
1737 PROCESS_INFORMATION pi
;
1739 NULL
, const_cast<char *>(cmd
),
1740 NULL
, NULL
, TRUE
/*inherit*/,
1741 CREATE_NO_WINDOW
/*do not create a new console window*/,
1742 NULL
, NULL
, &si
, &pi
)) {
1743 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1746 CloseHandle(pi
.hThread
);
1747 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1749 // Copy stdout to output buffer
1751 while (i
< outsize
) {
1753 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1757 CloseHandle(pipe_out_r
);
1759 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1760 CloseHandle(pi
.hProcess
);
1765 static const char * findstr(const char * str
, const char * sub
)
1767 const char * s
= strstr(str
, sub
);
1768 return (s
? s
+strlen(sub
) : "");
1772 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1774 int srclen
= strcspn(src
, "\r\n");
1776 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1777 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1779 if (i
< destsize
-1 && i
< srclen
)
1784 // TODO: This is OS independent
1786 win_tw_cli_device::win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
1787 : smart_device(intf
, dev_name
, "tw_cli", req_type
),
1788 m_ident_valid(false), m_smart_valid(false)
1790 memset(&m_ident_buf
, 0, sizeof(m_ident_buf
));
1791 memset(&m_smart_buf
, 0, sizeof(m_smart_buf
));
1795 bool win_tw_cli_device::is_open() const
1797 return (m_ident_valid
|| m_smart_valid
);
1801 bool win_tw_cli_device::open()
1803 m_ident_valid
= m_smart_valid
= false;
1804 const char * name
= skipdev(get_dev_name());
1805 // Read tw_cli or 3DM browser output into buffer
1807 int size
= -1, n1
= -1, n2
= -1;
1808 if (!strcmp(name
, "tw_cli/clip")) { // read clipboard
1809 size
= get_clipboard(buffer
, sizeof(buffer
));
1811 else if (!strcmp(name
, "tw_cli/stdin")) { // read stdin
1812 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1814 else if (sscanf(name
, "tw_cli/%nc%*u/p%*u%n", &n1
, &n2
) >= 0 && n2
== (int)strlen(name
)) {
1815 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1817 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
+n1
);
1818 if (ata_debugmode
> 1)
1819 pout("%s: Run: \"%s\"\n", name
, cmd
);
1820 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1823 return set_err(EINVAL
);
1826 if (ata_debugmode
> 1)
1827 pout("%s: Read %d bytes\n", name
, size
);
1829 return set_err(ENOENT
);
1830 if (size
>= (int)sizeof(buffer
))
1831 return set_err(EIO
);
1834 if (ata_debugmode
> 1)
1835 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1837 // Fake identify sector
1838 ASSERT_SIZEOF(ata_identify_device
, 512);
1839 ata_identify_device
* id
= &m_ident_buf
;
1840 memset(id
, 0, sizeof(*id
));
1841 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1842 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1843 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1844 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1845 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1847 id
->words047_079
[49-47] = 0x0200; // size valid
1848 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1849 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1851 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1852 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1854 // Parse smart data hex dump
1855 const char * s
= findstr(buffer
, "Drive Smart Data:");
1857 s
= findstr(buffer
, "Drive SMART Data:"); // tw_cli from 9.5.x
1859 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1861 const char * s1
= findstr(s
, "<td class"); // html version
1864 s
+= strcspn(s
, "\r\n");
1867 s
= buffer
; // try raw hex dump without header
1869 unsigned char * sd
= (unsigned char *)&m_smart_buf
;
1872 unsigned x
= ~0; int n
= -1;
1873 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1875 sd
[i
] = (unsigned char)x
;
1876 if (!(++i
< 512 && n
> 0))
1879 if (*s
== '<') // "<br>"
1880 s
+= strcspn(s
, "\r\n");
1883 if (!id
->model
[1]) {
1884 // No useful data found
1885 char * err
= strstr(buffer
, "Error:");
1887 err
= strstr(buffer
, "error :");
1888 if (err
&& (err
= strchr(err
, ':'))) {
1889 // Show tw_cli error message
1891 err
[strcspn(err
, "\r\n")] = 0;
1892 return set_err(EIO
, "%s", err
);
1894 return set_err(EIO
);
1899 m_ident_valid
= true;
1900 m_smart_valid
= !!sd
;
1905 bool win_tw_cli_device::close()
1907 m_ident_valid
= m_smart_valid
= false;
1912 int win_tw_cli_device::ata_command_interface(smart_command_set command
, int /*select*/, char * data
)
1918 memcpy(data
, &m_ident_buf
, 512);
1923 memcpy(data
, &m_smart_buf
, 512);
1927 case STATUS_CHECK
: // Fake "good" SMART status
1932 // Arrive here for all unsupported commands
1938 /////////////////////////////////////////////////////////////////////////////
1939 // IOCTL_STORAGE_QUERY_PROPERTY
1941 union STORAGE_DEVICE_DESCRIPTOR_DATA
{
1942 STORAGE_DEVICE_DESCRIPTOR desc
;
1946 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1947 // (This works without admin rights)
1949 static int storage_query_property_ioctl(HANDLE hdevice
, STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
1951 STORAGE_PROPERTY_QUERY query
= {StorageDeviceProperty
, PropertyStandardQuery
, {0} };
1952 memset(data
, 0, sizeof(*data
));
1955 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_QUERY_PROPERTY
,
1956 &query
, sizeof(query
), data
, sizeof(*data
), &num_out
, NULL
)) {
1957 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
1958 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
1963 if (ata_debugmode
> 1 || scsi_debugmode
> 1) {
1964 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1966 " Product: \"%s\"\n"
1967 " Revision: \"%s\"\n"
1969 " BusType: 0x%02x\n",
1970 (data
->desc
.VendorIdOffset
? data
->raw
+data
->desc
.VendorIdOffset
: "(null)"),
1971 (data
->desc
.ProductIdOffset
? data
->raw
+data
->desc
.ProductIdOffset
: "(null)"),
1972 (data
->desc
.ProductRevisionOffset
? data
->raw
+data
->desc
.ProductRevisionOffset
: "(null)"),
1973 (data
->desc
.RemovableMedia
? "Yes":"No"), data
->desc
.BusType
1980 /////////////////////////////////////////////////////////////////////////////
1981 // IOCTL_STORAGE_PREDICT_FAILURE
1983 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1984 // or -1 on error, opionally return VendorSpecific data.
1985 // (This works without admin rights)
1987 static int storage_predict_failure_ioctl(HANDLE hdevice
, char * data
= 0)
1989 STORAGE_PREDICT_FAILURE pred
;
1990 memset(&pred
, 0, sizeof(pred
));
1993 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_PREDICT_FAILURE
,
1994 0, 0, &pred
, sizeof(pred
), &num_out
, NULL
)) {
1995 if (ata_debugmode
> 1)
1996 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
2001 if (ata_debugmode
> 1) {
2002 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2003 " PredictFailure: 0x%08x\n"
2004 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2005 (unsigned)pred
.PredictFailure
,
2006 pred
.VendorSpecific
[0], pred
.VendorSpecific
[1], pred
.VendorSpecific
[2],
2007 pred
.VendorSpecific
[sizeof(pred
.VendorSpecific
)-1]
2011 memcpy(data
, pred
.VendorSpecific
, sizeof(pred
.VendorSpecific
));
2012 return (!pred
.PredictFailure
? 0 : 1);
2016 /////////////////////////////////////////////////////////////////////////////
2018 // Return true if Intel ICHxR RAID volume
2019 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2021 if (!(data
->desc
.VendorIdOffset
&& data
->desc
.ProductIdOffset
))
2023 const char * vendor
= data
->raw
+ data
->desc
.VendorIdOffset
;
2024 if (!(!strnicmp(vendor
, "Intel", 5) && strspn(vendor
+5, " ") == strlen(vendor
+5)))
2026 if (strnicmp(data
->raw
+ data
->desc
.ProductIdOffset
, "Raid ", 5))
2031 // get DEV_* for open handle
2032 static win_dev_type
get_controller_type(HANDLE hdevice
, bool admin
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2034 // Get BusType from device descriptor
2035 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2036 if (storage_query_property_ioctl(hdevice
, &data
))
2039 // Newer BusType* values are missing in older includes
2040 switch ((int)data
.desc
.BusType
) {
2042 case 0x0b: // BusTypeSata
2044 memset(ata_version_ex
, 0, sizeof(*ata_version_ex
));
2049 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2050 if (is_intel_raid_volume(&data
))
2052 // LSI/3ware RAID volume: supports SMART_*
2053 if (admin
&& smart_get_version(hdevice
, ata_version_ex
) >= 0)
2057 case 0x09: // BusTypeiScsi
2058 case 0x0a: // BusTypeSas
2070 // get DEV_* for device path
2071 static win_dev_type
get_controller_type(const char * path
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
2074 HANDLE h
= CreateFileA(path
, GENERIC_READ
|GENERIC_WRITE
,
2075 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2076 if (h
== INVALID_HANDLE_VALUE
) {
2078 h
= CreateFileA(path
, 0,
2079 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2080 if (h
== INVALID_HANDLE_VALUE
)
2083 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2084 pout(" %s: successfully opened%s\n", path
, (!admin
? " (without admin rights)" :""));
2085 win_dev_type type
= get_controller_type(h
, admin
, ata_version_ex
);
2090 // get DEV_* for physical drive number
2091 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2094 snprintf(path
, sizeof(path
)-1, "\\\\.\\PhysicalDrive%d", drive
);
2095 return get_controller_type(path
, ata_version_ex
);
2098 static win_dev_type
get_phy_drive_type(int drive
)
2100 return get_phy_drive_type(drive
, 0);
2103 // get DEV_* for logical drive number
2104 static win_dev_type
get_log_drive_type(int drive
)
2107 snprintf(path
, sizeof(path
)-1, "\\\\.\\%c:", 'A'+drive
);
2108 return get_controller_type(path
);
2111 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2112 static int get_identify_from_device_property(HANDLE hdevice
, ata_identify_device
* id
)
2114 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2115 if (storage_query_property_ioctl(hdevice
, &data
))
2118 memset(id
, 0, sizeof(*id
));
2120 // Some drivers split ATA model string into VendorId and ProductId,
2121 // others return it as ProductId only.
2122 char model
[sizeof(id
->model
) + 1] = "";
2125 if (data
.desc
.VendorIdOffset
) {
2126 for ( ;i
< sizeof(model
)-1 && data
.raw
[data
.desc
.VendorIdOffset
+i
]; i
++)
2127 model
[i
] = data
.raw
[data
.desc
.VendorIdOffset
+i
];
2130 if (data
.desc
.ProductIdOffset
) {
2131 while (i
> 1 && model
[i
-2] == ' ') // Keep last blank from VendorId
2133 // Ignore VendorId "ATA"
2134 if (i
<= 4 && !strncmp(model
, "ATA", 3) && (i
== 3 || model
[3] == ' '))
2136 for (unsigned j
= 0; i
< sizeof(model
)-1 && data
.raw
[data
.desc
.ProductIdOffset
+j
]; i
++, j
++)
2137 model
[i
] = data
.raw
[data
.desc
.ProductIdOffset
+j
];
2140 while (i
> 0 && model
[i
-1] == ' ')
2143 copy_swapped(id
->model
, model
, sizeof(id
->model
));
2145 if (data
.desc
.ProductRevisionOffset
)
2146 copy_swapped(id
->fw_rev
, data
.raw
+data
.desc
.ProductRevisionOffset
, sizeof(id
->fw_rev
));
2148 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
2149 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
2153 // Get Serial Number in IDENTIFY from WMI
2154 static bool get_serial_from_wmi(int drive
, ata_identify_device
* id
)
2156 bool debug
= (ata_debugmode
> 1);
2159 if (!ws
.connect()) {
2161 pout("WMI connect failed\n");
2166 if (!ws
.query1(wo
, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2167 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2170 std::string serial
= wo
.get_str("SerialNumber");
2172 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive
, wo
.get_str("Model").c_str(), serial
.c_str());
2174 copy_swapped(id
->serial_no
, serial
.c_str(), sizeof(id
->serial_no
));
2179 /////////////////////////////////////////////////////////////////////////////
2180 // USB ID detection using WMI
2182 // Get USB ID for a physical drive number
2183 static bool get_usb_id(int drive
, unsigned short & vendor_id
, unsigned short & product_id
)
2185 bool debug
= (scsi_debugmode
> 1);
2188 if (!ws
.connect()) {
2190 pout("WMI connect failed\n");
2196 if (!ws
.query1(wo
, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2199 std::string name
= wo
.get_str("Model");
2201 pout("PhysicalDrive%d, \"%s\":\n", drive
, name
.c_str());
2203 // Get USB_CONTROLLER -> DEVICE associations
2205 if (!ws
.query(we
, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2208 unsigned short usb_venid
= 0, prev_usb_venid
= 0;
2209 unsigned short usb_proid
= 0, prev_usb_proid
= 0;
2210 std::string prev_usb_ant
;
2211 std::string prev_ant
, ant
, dep
;
2213 const regular_expression
regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED
);
2215 while (we
.next(wo
)) {
2217 // Find next 'USB_CONTROLLER, DEVICE' pair
2218 ant
= wo
.get_str("Antecedent");
2219 dep
= wo
.get_str("Dependent");
2221 if (debug
&& ant
!= prev_ant
)
2222 pout(" %s:\n", ant
.c_str());
2225 regmatch_t match
[2];
2226 if (!(regex
.execute(dep
.c_str(), 2, match
) && match
[1].rm_so
>= 0)) {
2228 pout(" | (\"%s\")\n", dep
.c_str());
2232 std::string
devid(dep
.c_str()+match
[1].rm_so
, match
[1].rm_eo
-match
[1].rm_so
);
2234 if (str_starts_with(devid
, "USB\\\\VID_")) {
2235 // USB bridge entry, save CONTROLLER, ID
2237 if (!(sscanf(devid
.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2238 &prev_usb_venid
, &prev_usb_proid
, &nc
) == 2 && nc
== 9+4+5+4)) {
2239 prev_usb_venid
= prev_usb_proid
= 0;
2243 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid
.c_str(), prev_usb_venid
, prev_usb_proid
);
2246 else if (str_starts_with(devid
, "USBSTOR\\\\")) {
2247 // USBSTOR device found
2249 pout(" +--> \"%s\"\n", devid
.c_str());
2253 if (!ws
.query1(wo2
, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid
.c_str()))
2255 std::string name2
= wo2
.get_str("Name");
2257 // Continue if not name of physical disk drive
2258 if (name2
!= name
) {
2260 pout(" +---> (\"%s\")\n", name2
.c_str());
2264 // Fail if previous USB bridge is associated to other controller or ID is unknown
2265 if (!(ant
== prev_usb_ant
&& prev_usb_venid
)) {
2267 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2
.c_str());
2271 // Handle multiple devices with same name
2273 // Fail if multiple devices with same name have different USB bridge types
2274 if (!(usb_venid
== prev_usb_venid
&& usb_proid
== prev_usb_proid
)) {
2276 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2
.c_str());
2282 usb_venid
= prev_usb_venid
;
2283 usb_proid
= prev_usb_proid
;
2285 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2
.c_str(), usb_venid
, usb_proid
);
2287 // Continue to check for duplicate names ...
2291 pout(" | \"%s\"\n", devid
.c_str());
2298 vendor_id
= usb_venid
;
2299 product_id
= usb_proid
;
2305 /////////////////////////////////////////////////////////////////////////////
2307 // Call GetDevicePowerState()
2308 // returns: 1=active, 0=standby, -1=error
2309 // (This would also work for SCSI drives)
2311 static int get_device_power_state(HANDLE hdevice
)
2314 if (!GetDevicePowerState(hdevice
, &state
)) {
2315 long err
= GetLastError();
2317 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
2318 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2319 // TODO: This may not work as expected on transient errors,
2320 // because smartd interprets -1 as SLEEP mode regardless of errno.
2324 if (ata_debugmode
> 1)
2325 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
2330 /////////////////////////////////////////////////////////////////////////////
2332 // Get default ATA device options
2334 static const char * ata_get_def_options()
2336 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2337 // STORAGE_*, SCSI_MINIPORT_*
2341 // Common routines for devices with HANDLEs
2343 win_smart_device::~win_smart_device() throw()
2345 if (m_fh
!= INVALID_HANDLE_VALUE
)
2346 ::CloseHandle(m_fh
);
2349 bool win_smart_device::is_open() const
2351 return (m_fh
!= INVALID_HANDLE_VALUE
);
2354 bool win_smart_device::close()
2356 if (m_fh
== INVALID_HANDLE_VALUE
)
2358 BOOL rc
= ::CloseHandle(m_fh
);
2359 m_fh
= INVALID_HANDLE_VALUE
;
2365 win_ata_device::win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
2366 : smart_device(intf
, dev_name
, "ata", req_type
),
2367 m_usr_options(false),
2370 m_id_is_cached(false),
2377 win_ata_device::~win_ata_device() throw()
2384 bool win_ata_device::open()
2386 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
2387 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2388 char drive
[2+1] = "", options
[8+1] = ""; int n1
= -1, n2
= -1;
2389 if ( sscanf(name
, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive
, &n1
, options
, &n2
) >= 1
2390 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2391 return open(sdxy_to_phydrive(drive
), -1, options
, -1);
2393 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2394 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
2396 if ( sscanf(name
, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
2397 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2398 return open(sdxy_to_phydrive(drive
), -1, options
, port
);
2400 // pd<m>,N => Physical drive <m>, RAID port N
2401 int phydrive
= -1; port
= ~0; n1
= -1; n2
= -1;
2402 if ( sscanf(name
, "pd%d%n,%u%n", &phydrive
, &n1
, &port
, &n2
) >= 1
2403 && phydrive
>= 0 && ((n1
== len
&& (int)port
< 0) || (n2
== len
&& port
< 32))) {
2404 return open(phydrive
, -1, "", (int)port
);
2406 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2407 int logdrive
= drive_letter(name
);
2408 if (logdrive
>= 0) {
2409 return open(-1, logdrive
, "", -1);
2412 return set_err(EINVAL
);
2416 bool win_ata_device::open(int phydrive
, int logdrive
, const char * options
, int port
)
2420 if (0 <= phydrive
&& phydrive
<= 255)
2421 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive
= phydrive
));
2422 else if (0 <= logdrive
&& logdrive
<= 'Z'-'A')
2423 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\%c:", 'A'+logdrive
);
2425 return set_err(ENOENT
);
2428 HANDLE h
= INVALID_HANDLE_VALUE
;
2429 if (!(*options
&& !options
[strspn(options
, "fp")])) {
2430 // Open with admin rights
2432 h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
2433 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2434 NULL
, OPEN_EXISTING
, 0, 0);
2436 if (h
== INVALID_HANDLE_VALUE
) {
2437 // Open without admin rights
2439 h
= CreateFileA(devpath
, 0,
2440 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2441 NULL
, OPEN_EXISTING
, 0, 0);
2443 if (h
== INVALID_HANDLE_VALUE
) {
2444 long err
= GetLastError();
2445 if (err
== ERROR_FILE_NOT_FOUND
)
2446 set_err(ENOENT
, "%s: not found", devpath
);
2447 else if (err
== ERROR_ACCESS_DENIED
)
2448 set_err(EACCES
, "%s: access denied", devpath
);
2450 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
2455 // Warn once if admin rights are missing
2457 static bool noadmin_warning
= false;
2458 if (!noadmin_warning
) {
2459 pout("Warning: Limited functionality due to missing admin rights\n");
2460 noadmin_warning
= true;
2464 if (ata_debugmode
> 1)
2465 pout("%s: successfully opened%s\n", devpath
, (!m_admin
? " (without admin rights)" :""));
2467 m_usr_options
= false;
2469 // Save user options
2470 m_options
= options
; m_usr_options
= true;
2473 // RAID: SMART_* and SCSI_MINIPORT
2476 // Set default options according to Windows version
2477 static const char * def_options
= ata_get_def_options();
2478 m_options
= def_options
;
2481 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2486 // 3ware RAID: Get port map
2487 GETVERSIONINPARAMS_EX vers_ex
;
2488 int devmap
= smart_get_version(h
, &vers_ex
);
2490 // 3ware RAID if vendor id present
2491 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2493 unsigned long portmap
= 0;
2494 if (port
>= 0 && devmap
>= 0) {
2495 // 3ware RAID: check vendor id
2497 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2498 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2499 vers_ex
.wIdentifier
);
2503 portmap
= vers_ex
.dwDeviceMapEx
;
2506 pout("%s: ATA driver has no SMART support\n", devpath
);
2507 if (!is_permissive()) {
2509 return set_err(ENOSYS
);
2513 m_smartver_state
= 1;
2516 // 3ware RAID: update devicemap first
2518 if (!update_3ware_devicemap_ioctl(h
)) {
2519 if ( smart_get_version(h
, &vers_ex
) >= 0
2520 && vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
2521 portmap
= vers_ex
.dwDeviceMapEx
;
2523 // Check port existence
2524 if (!(portmap
& (1L << port
))) {
2525 if (!is_permissive()) {
2527 return set_err(ENOENT
, "%s: Port %d is empty or does not exist", devpath
, port
);
2536 /////////////////////////////////////////////////////////////////////////////
2538 // Interface to ATA devices
2539 bool win_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2541 // No multi-sector support for now, see above
2542 // warning about IOCTL_ATA_PASS_THROUGH
2543 if (!ata_cmd_is_supported(in
,
2544 ata_device::supports_data_out
|
2545 ata_device::supports_output_regs
|
2546 ata_device::supports_48bit
)
2550 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2551 if ( m_is_3ware
&& m_port
< 0
2552 && in
.in_regs
.command
== ATA_SMART_CMD
2553 && in
.in_regs
.features
== ATA_SMART_DISABLE
)
2554 return set_err(ENOSYS
, "SMART DISABLE requires 3ware port number");
2556 // Determine ioctl functions valid for this ATA cmd
2557 const char * valid_options
= 0;
2559 switch (in
.in_regs
.command
) {
2560 case ATA_IDENTIFY_DEVICE
:
2561 case ATA_IDENTIFY_PACKET_DEVICE
:
2562 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2563 // and SCSI_MINIPORT_* if requested by user
2564 valid_options
= (m_usr_options
? "saimf" : "saif");
2567 case ATA_CHECK_POWER_MODE
:
2568 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2569 valid_options
= "pai3";
2573 switch (in
.in_regs
.features
) {
2574 case ATA_SMART_READ_VALUES
:
2575 case ATA_SMART_READ_THRESHOLDS
:
2576 case ATA_SMART_AUTOSAVE
:
2577 case ATA_SMART_ENABLE
:
2578 case ATA_SMART_DISABLE
:
2579 case ATA_SMART_AUTO_OFFLINE
:
2580 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2581 // and SCSI_MINIPORT_* if requested by user
2582 valid_options
= (m_usr_options
? "saimf" : "saif");
2585 case ATA_SMART_IMMEDIATE_OFFLINE
:
2586 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2587 valid_options
= (m_usr_options
|| in
.in_regs
.lba_low
!= 127/*ABORT*/ ?
2591 case ATA_SMART_READ_LOG_SECTOR
:
2592 // SMART_RCV_DRIVE_DATA does not support READ_LOG
2593 // Try SCSI_MINIPORT also to skip buggy class driver
2594 // SMART functions do not support multi sector I/O.
2596 valid_options
= (m_usr_options
? "saim3" : "aim3");
2598 valid_options
= "a";
2601 case ATA_SMART_WRITE_LOG_SECTOR
:
2602 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2603 // but SCSI_MINIPORT_* only if requested by user and single sector.
2604 valid_options
= (in
.size
== 512 && m_usr_options
? "am" : "a");
2607 case ATA_SMART_STATUS
:
2608 valid_options
= (m_usr_options
? "saimf" : "saif");
2612 // Unknown SMART command, handle below
2618 // Other ATA command, handle below
2622 if (!valid_options
) {
2623 // No special ATA command found above, select a generic pass through ioctl.
2624 if (!( in
.direction
== ata_cmd_in::no_data
2625 || (in
.direction
== ata_cmd_in::data_in
&& in
.size
== 512))
2626 || in
.in_regs
.is_48bit_cmd() )
2627 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2628 valid_options
= "a";
2630 // ATA/IDE_PASS_THROUGH
2631 valid_options
= "ai";
2635 // Restrict to IOCTL_STORAGE_*
2636 if (strchr(valid_options
, 'f'))
2637 valid_options
= "f";
2638 else if (strchr(valid_options
, 'p'))
2639 valid_options
= "p";
2641 return set_err(ENOSYS
, "Function requires admin rights");
2645 IDEREGS regs
, prev_regs
;
2647 const ata_in_regs
& lo
= in
.in_regs
;
2648 regs
.bFeaturesReg
= lo
.features
;
2649 regs
.bSectorCountReg
= lo
.sector_count
;
2650 regs
.bSectorNumberReg
= lo
.lba_low
;
2651 regs
.bCylLowReg
= lo
.lba_mid
;
2652 regs
.bCylHighReg
= lo
.lba_high
;
2653 regs
.bDriveHeadReg
= lo
.device
;
2654 regs
.bCommandReg
= lo
.command
;
2657 if (in
.in_regs
.is_48bit_cmd()) {
2658 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2659 prev_regs
.bFeaturesReg
= hi
.features
;
2660 prev_regs
.bSectorCountReg
= hi
.sector_count
;
2661 prev_regs
.bSectorNumberReg
= hi
.lba_low
;
2662 prev_regs
.bCylLowReg
= hi
.lba_mid
;
2663 prev_regs
.bCylHighReg
= hi
.lba_high
;
2664 prev_regs
.bDriveHeadReg
= hi
.device
;
2665 prev_regs
.bCommandReg
= hi
.command
;
2666 prev_regs
.bReserved
= 0;
2669 // Set data direction
2672 switch (in
.direction
) {
2673 case ata_cmd_in::no_data
:
2675 case ata_cmd_in::data_in
:
2676 datasize
= (int)in
.size
;
2677 data
= (char *)in
.buffer
;
2679 case ata_cmd_in::data_out
:
2680 datasize
= -(int)in
.size
;
2681 data
= (char *)in
.buffer
;
2684 return set_err(EINVAL
, "win_ata_device::ata_pass_through: invalid direction=%d",
2689 // Try all valid ioctls in the order specified in m_options
2690 bool powered_up
= false;
2691 bool out_regs_set
= false;
2692 bool id_is_cached
= false;
2693 const char * options
= m_options
.c_str();
2695 for (int i
= 0; ; i
++) {
2696 char opt
= options
[i
];
2699 if (in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& powered_up
) {
2700 // Power up reported by GetDevicePowerState() and no ioctl available
2701 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2702 regs
.bSectorCountReg
= 0xff;
2703 out_regs_set
= true;
2707 return set_err(ENOSYS
);
2709 if (!strchr(valid_options
, opt
))
2710 // Invalid for this command
2714 assert( datasize
== 0 || datasize
== 512
2715 || (datasize
== -512 && strchr("am", opt
))
2716 || (datasize
> 512 && opt
== 'a'));
2721 // call SMART_GET_VERSION once for each drive
2722 if (m_smartver_state
> 1) {
2723 rc
= -1; errno
= ENOSYS
;
2726 if (!m_smartver_state
) {
2727 assert(m_port
== -1);
2728 GETVERSIONINPARAMS_EX vers_ex
;
2729 if (smart_get_version(get_fh(), &vers_ex
) < 0) {
2730 if (!failuretest_permissive
) {
2731 m_smartver_state
= 2;
2732 rc
= -1; errno
= ENOSYS
;
2735 failuretest_permissive
--;
2738 // 3ware RAID if vendor id present
2739 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2742 m_smartver_state
= 1;
2744 rc
= smart_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2745 out_regs_set
= (in
.in_regs
.features
== ATA_SMART_STATUS
);
2746 id_is_cached
= (m_port
< 0); // Not cached by 3ware driver
2749 rc
= ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s
, data
, datasize
);
2750 id_is_cached
= (m_port
< 0);
2753 rc
= ata_pass_through_ioctl(get_fh(), ®s
,
2754 (in
.in_regs
.is_48bit_cmd() ? &prev_regs
: 0),
2756 out_regs_set
= true;
2759 rc
= ide_pass_through_ioctl(get_fh(), ®s
, data
, datasize
);
2760 out_regs_set
= true;
2763 if (in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
) {
2764 rc
= get_identify_from_device_property(get_fh(), (ata_identify_device
*)data
);
2765 if (rc
== 0 && m_phydrive
>= 0)
2766 get_serial_from_wmi(m_phydrive
, (ata_identify_device
*)data
);
2767 id_is_cached
= true;
2769 else if (in
.in_regs
.command
== ATA_SMART_CMD
) switch (in
.in_regs
.features
) {
2770 case ATA_SMART_READ_VALUES
:
2771 rc
= storage_predict_failure_ioctl(get_fh(), data
);
2775 case ATA_SMART_ENABLE
:
2778 case ATA_SMART_STATUS
:
2779 rc
= storage_predict_failure_ioctl(get_fh());
2781 // Good SMART status
2782 out
.out_regs
.lba_high
= 0xc2; out
.out_regs
.lba_mid
= 0x4f;
2786 out
.out_regs
.lba_high
= 0x2c; out
.out_regs
.lba_mid
= 0xf4;
2791 errno
= ENOSYS
; rc
= -1;
2794 errno
= ENOSYS
; rc
= -1;
2798 rc
= ata_via_3ware_miniport_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2799 out_regs_set
= true;
2802 assert(in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& in
.size
== 0);
2803 rc
= get_device_power_state(get_fh());
2805 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2806 // spin up the drive => simulate ATA result STANDBY.
2807 regs
.bSectorCountReg
= 0x00;
2808 out_regs_set
= true;
2811 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2812 // only if it is selected by the device driver => try a passthrough ioctl to get the
2813 // actual mode, if none available simulate ACTIVE/IDLE.
2815 rc
= -1; errno
= ENOSYS
;
2821 // Working ioctl found
2824 if (errno
!= ENOSYS
)
2825 // Abort on I/O error
2826 return set_err(errno
);
2828 out_regs_set
= false;
2829 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2832 // Return IDEREGS if set
2834 ata_out_regs
& lo
= out
.out_regs
;
2835 lo
.error
= regs
.bFeaturesReg
;
2836 lo
.sector_count
= regs
.bSectorCountReg
;
2837 lo
.lba_low
= regs
.bSectorNumberReg
;
2838 lo
.lba_mid
= regs
.bCylLowReg
;
2839 lo
.lba_high
= regs
.bCylHighReg
;
2840 lo
.device
= regs
.bDriveHeadReg
;
2841 lo
.status
= regs
.bCommandReg
;
2842 if (in
.in_regs
.is_48bit_cmd()) {
2843 ata_out_regs
& hi
= out
.out_regs
.prev
;
2844 hi
.sector_count
= prev_regs
.bSectorCountReg
;
2845 hi
.lba_low
= prev_regs
.bSectorNumberReg
;
2846 hi
.lba_mid
= prev_regs
.bCylLowReg
;
2847 hi
.lba_high
= prev_regs
.bCylHighReg
;
2851 if ( in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
2852 || in
.in_regs
.command
== ATA_IDENTIFY_PACKET_DEVICE
)
2853 // Update ata_identify_is_cached() result according to ioctl used.
2854 m_id_is_cached
= id_is_cached
;
2859 // Return true if OS caches the ATA identify sector
2860 bool win_ata_device::ata_identify_is_cached() const
2862 return m_id_is_cached
;
2866 //////////////////////////////////////////////////////////////////////
2869 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
)
2871 // Get driver info to check CSMI support
2872 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf
;
2873 memset(&driver_info_buf
, 0, sizeof(driver_info_buf
));
2874 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO
, &driver_info_buf
.IoctlHeader
, sizeof(driver_info_buf
)))
2877 if (scsi_debugmode
> 1) {
2878 const CSMI_SAS_DRIVER_INFO
& driver_info
= driver_info_buf
.Information
;
2879 pout("CSMI_SAS_DRIVER_INFO:\n");
2880 pout(" Name: \"%.81s\"\n", driver_info
.szName
);
2881 pout(" Description: \"%.81s\"\n", driver_info
.szDescription
);
2882 pout(" Revision: %d.%d\n", driver_info
.usMajorRevision
, driver_info
.usMinorRevision
);
2886 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf
;
2887 memset(&phy_info_buf
, 0, sizeof(phy_info_buf
));
2888 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO
, &phy_info_buf
.IoctlHeader
, sizeof(phy_info_buf
)))
2891 phy_info
= phy_info_buf
.Information
;
2893 const int max_number_of_phys
= sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]);
2894 if (phy_info
.bNumberOfPhys
> max_number_of_phys
)
2895 return set_err(EIO
, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info
.bNumberOfPhys
);
2897 if (scsi_debugmode
> 1) {
2898 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info
.bNumberOfPhys
);
2899 for (int i
= 0; i
< max_number_of_phys
; i
++) {
2900 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
2901 const CSMI_SAS_IDENTIFY
& id
= pe
.Identify
, & at
= pe
.Attached
;
2902 if (id
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2905 pout("Phy[%d] Port: 0x%02x\n", i
, pe
.bPortIdentifier
);
2906 pout(" Type: 0x%02x, 0x%02x\n", id
.bDeviceType
, at
.bDeviceType
);
2907 pout(" InitProto: 0x%02x, 0x%02x\n", id
.bInitiatorPortProtocol
, at
.bInitiatorPortProtocol
);
2908 pout(" TargetProto: 0x%02x, 0x%02x\n", id
.bTargetPortProtocol
, at
.bTargetPortProtocol
);
2909 pout(" PhyIdent: 0x%02x, 0x%02x\n", id
.bPhyIdentifier
, at
.bPhyIdentifier
);
2910 const unsigned char * b
= id
.bSASAddress
;
2911 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2912 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2914 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2915 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2922 unsigned csmi_device::get_ports_used()
2924 CSMI_SAS_PHY_INFO phy_info
;
2925 if (!get_phy_info(phy_info
))
2928 unsigned ports_used
= 0;
2929 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
2930 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
2931 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2933 if (pe
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2935 switch (pe
.Attached
.bTargetPortProtocol
) {
2936 case CSMI_SAS_PROTOCOL_SATA
:
2937 case CSMI_SAS_PROTOCOL_STP
:
2943 if (pe
.bPortIdentifier
== 0xff)
2944 // Older (<= 9.*) Intel RST driver
2945 ports_used
|= (1 << i
);
2947 ports_used
|= (1 << pe
.bPortIdentifier
);
2954 bool csmi_device::select_port(int port
)
2956 CSMI_SAS_PHY_INFO phy_info
;
2957 if (!get_phy_info(phy_info
))
2961 int max_port
= -1, port_index
= -1;
2962 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
2963 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
2964 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2967 if (pe
.bPortIdentifier
== 0xff) {
2968 // Older (<= 9.*) Intel RST driver
2969 max_port
= phy_info
.bNumberOfPhys
- 1;
2970 if (i
>= phy_info
.bNumberOfPhys
)
2976 if (pe
.bPortIdentifier
> max_port
)
2977 max_port
= pe
.bPortIdentifier
;
2978 if (pe
.bPortIdentifier
!= port
)
2986 if (port_index
< 0) {
2987 if (port
<= max_port
)
2988 return set_err(ENOENT
, "Port %d is disabled", port
);
2990 return set_err(ENOENT
, "Port %d does not exist (#ports: %d)", port
,
2994 const CSMI_SAS_PHY_ENTITY
& phy_ent
= phy_info
.Phy
[port_index
];
2995 if (phy_ent
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2996 return set_err(ENOENT
, "No device on port %d", port
);
2998 switch (phy_ent
.Attached
.bTargetPortProtocol
) {
2999 case CSMI_SAS_PROTOCOL_SATA
:
3000 case CSMI_SAS_PROTOCOL_STP
:
3003 return set_err(ENOENT
, "No SATA device on port %d (protocol: %d)",
3004 port
, phy_ent
.Attached
.bTargetPortProtocol
);
3007 m_phy_ent
= phy_ent
;
3012 bool csmi_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
3014 if (!ata_cmd_is_supported(in
,
3015 ata_device::supports_data_out
|
3016 ata_device::supports_output_regs
|
3017 ata_device::supports_multi_sector
|
3018 ata_device::supports_48bit
,
3023 // Create buffer with appropriate size
3024 raw_buffer
pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER
) + in
.size
);
3025 CSMI_SAS_STP_PASSTHRU_BUFFER
* pthru_buf
= (CSMI_SAS_STP_PASSTHRU_BUFFER
*)pthru_raw_buf
.data();
3027 // Set addresses from Phy info
3028 CSMI_SAS_STP_PASSTHRU
& pthru
= pthru_buf
->Parameters
;
3029 const CSMI_SAS_PHY_ENTITY
& phy_ent
= get_phy_ent();
3030 pthru
.bPhyIdentifier
= phy_ent
.Identify
.bPhyIdentifier
;
3031 pthru
.bPortIdentifier
= phy_ent
.bPortIdentifier
;
3032 memcpy(pthru
.bDestinationSASAddress
, phy_ent
.Attached
.bSASAddress
,
3033 sizeof(pthru
.bDestinationSASAddress
));
3034 pthru
.bConnectionRate
= CSMI_SAS_LINK_RATE_NEGOTIATED
;
3036 // Set transfer mode
3037 switch (in
.direction
) {
3038 case ata_cmd_in::no_data
:
3039 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_UNSPECIFIED
;
3041 case ata_cmd_in::data_in
:
3042 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_READ
;
3043 pthru
.uDataLength
= in
.size
;
3045 case ata_cmd_in::data_out
:
3046 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_WRITE
;
3047 pthru
.uDataLength
= in
.size
;
3048 memcpy(pthru_buf
->bDataBuffer
, in
.buffer
, in
.size
);
3051 return set_err(EINVAL
, "csmi_ata_device::ata_pass_through: invalid direction=%d",
3055 // Set host-to-device FIS
3057 unsigned char * fis
= pthru
.bCommandFIS
;
3058 const ata_in_regs
& lo
= in
.in_regs
;
3059 const ata_in_regs
& hi
= in
.in_regs
.prev
;
3060 fis
[ 0] = 0x27; // Type: host-to-device FIS
3061 fis
[ 1] = 0x80; // Bit7: Update command register
3062 fis
[ 2] = lo
.command
;
3063 fis
[ 3] = lo
.features
;
3064 fis
[ 4] = lo
.lba_low
;
3065 fis
[ 5] = lo
.lba_mid
;
3066 fis
[ 6] = lo
.lba_high
;
3067 fis
[ 7] = lo
.device
;
3068 fis
[ 8] = hi
.lba_low
;
3069 fis
[ 9] = hi
.lba_mid
;
3070 fis
[10] = hi
.lba_high
;
3071 fis
[11] = hi
.features
;
3072 fis
[12] = lo
.sector_count
;
3073 fis
[13] = hi
.sector_count
;
3077 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU
, &pthru_buf
->IoctlHeader
, pthru_raw_buf
.size())) {
3081 // Get device-to-host FIS
3083 const unsigned char * fis
= pthru_buf
->Status
.bStatusFIS
;
3084 ata_out_regs
& lo
= out
.out_regs
;
3085 lo
.status
= fis
[ 2];
3087 lo
.lba_low
= fis
[ 4];
3088 lo
.lba_mid
= fis
[ 5];
3089 lo
.lba_high
= fis
[ 6];
3090 lo
.device
= fis
[ 7];
3091 lo
.sector_count
= fis
[12];
3092 if (in
.in_regs
.is_48bit_cmd()) {
3093 ata_out_regs
& hi
= out
.out_regs
.prev
;
3094 hi
.lba_low
= fis
[ 8];
3095 hi
.lba_mid
= fis
[ 9];
3096 hi
.lba_high
= fis
[10];
3097 hi
.sector_count
= fis
[13];
3102 if (in
.direction
== ata_cmd_in::data_in
)
3103 // TODO: Check ptru_buf->Status.uDataBytes
3104 memcpy(in
.buffer
, pthru_buf
->bDataBuffer
, in
.size
);
3110 //////////////////////////////////////////////////////////////////////
3113 win_csmi_device::win_csmi_device(smart_interface
* intf
, const char * dev_name
,
3114 const char * req_type
)
3115 : smart_device(intf
, dev_name
, "ata", req_type
),
3116 m_fh(INVALID_HANDLE_VALUE
), m_port(-1)
3120 win_csmi_device::~win_csmi_device() throw()
3122 if (m_fh
!= INVALID_HANDLE_VALUE
)
3126 bool win_csmi_device::is_open() const
3128 return (m_fh
!= INVALID_HANDLE_VALUE
);
3131 bool win_csmi_device::close()
3133 if (m_fh
== INVALID_HANDLE_VALUE
)
3135 BOOL rc
= CloseHandle(m_fh
);
3136 m_fh
= INVALID_HANDLE_VALUE
;
3141 bool win_csmi_device::open_scsi()
3144 unsigned contr_no
= ~0, port
= ~0; int nc
= -1;
3145 const char * name
= skipdev(get_dev_name());
3146 if (!( sscanf(name
, "csmi%u,%u%n", &contr_no
, &port
, &nc
) >= 0
3147 && nc
== (int)strlen(name
) && contr_no
<= 9 && port
< 32) )
3148 return set_err(EINVAL
);
3150 // Open controller handle
3152 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\Scsi%u:", contr_no
);
3154 HANDLE h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
3155 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3156 (SECURITY_ATTRIBUTES
*)0, OPEN_EXISTING
, 0, 0);
3158 if (h
== INVALID_HANDLE_VALUE
) {
3159 long err
= GetLastError();
3160 if (err
== ERROR_FILE_NOT_FOUND
)
3161 set_err(ENOENT
, "%s: not found", devpath
);
3162 else if (err
== ERROR_ACCESS_DENIED
)
3163 set_err(EACCES
, "%s: access denied", devpath
);
3165 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
3169 if (scsi_debugmode
> 1)
3170 pout(" %s: successfully opened\n", devpath
);
3178 bool win_csmi_device::open()
3183 // Get Phy info for this drive
3184 if (!select_port(m_port
)) {
3193 bool win_csmi_device::csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
3194 unsigned csmi_bufsiz
)
3196 // Determine signature
3199 case CC_CSMI_SAS_GET_DRIVER_INFO
:
3200 sig
= CSMI_ALL_SIGNATURE
; break;
3201 case CC_CSMI_SAS_GET_PHY_INFO
:
3202 case CC_CSMI_SAS_STP_PASSTHRU
:
3203 sig
= CSMI_SAS_SIGNATURE
; break;
3205 return set_err(ENOSYS
, "Unknown CSMI code=%u", code
);
3209 csmi_buffer
->HeaderLength
= sizeof(IOCTL_HEADER
);
3210 strncpy((char *)csmi_buffer
->Signature
, sig
, sizeof(csmi_buffer
->Signature
));
3211 csmi_buffer
->Timeout
= CSMI_SAS_TIMEOUT
;
3212 csmi_buffer
->ControlCode
= code
;
3213 csmi_buffer
->ReturnCode
= 0;
3214 csmi_buffer
->Length
= csmi_bufsiz
- sizeof(IOCTL_HEADER
);
3218 if (!DeviceIoControl(m_fh
, IOCTL_SCSI_MINIPORT
,
3219 csmi_buffer
, csmi_bufsiz
, csmi_buffer
, csmi_bufsiz
, &num_out
, (OVERLAPPED
*)0)) {
3220 long err
= GetLastError();
3222 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code
, err
);
3223 if ( err
== ERROR_INVALID_FUNCTION
3224 || err
== ERROR_NOT_SUPPORTED
3225 || err
== ERROR_DEV_NOT_EXIST
)
3226 return set_err(ENOSYS
, "CSMI is not supported (Error=%ld)", err
);
3228 return set_err(EIO
, "CSMI(%u) failed with Error=%ld", code
, err
);
3232 if (csmi_buffer
->ReturnCode
) {
3233 if (scsi_debugmode
) {
3234 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3235 code
, (unsigned)csmi_buffer
->ReturnCode
);
3237 return set_err(EIO
, "CSMI(%u) failed with ReturnCode=%u", code
, (unsigned)csmi_buffer
->ReturnCode
);
3240 if (scsi_debugmode
> 1)
3241 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code
, (unsigned)num_out
);
3247 /////////////////////////////////////////////////////////////////////////////
3248 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3249 // Only supported in NT and later
3250 /////////////////////////////////////////////////////////////////////////////
3252 win_scsi_device::win_scsi_device(smart_interface
* intf
,
3253 const char * dev_name
, const char * req_type
)
3254 : smart_device(intf
, dev_name
, "scsi", req_type
)
3258 bool win_scsi_device::open()
3260 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
3261 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3262 char drive
[2+1] = ""; int sub_addr
= -1; int n1
= -1; int n2
= -1;
3263 if ( sscanf(name
, "sd%2[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
3264 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
3265 return open(sdxy_to_phydrive(drive
), -1, -1, sub_addr
);
3267 // pd<m>,N => Physical drive <m>, RAID port N
3268 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
3269 if ( sscanf(name
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
3270 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
3271 return open(pd_num
, -1, -1, sub_addr
);
3273 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3274 int logdrive
= drive_letter(name
);
3275 if (logdrive
>= 0) {
3276 return open(-1, logdrive
, -1, -1);
3278 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3279 int tape_num
= -1; n1
= -1;
3280 if (sscanf(name
, "st%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3281 return open(-1, -1, tape_num
, -1);
3283 tape_num
= -1; n1
= -1;
3284 if (sscanf(name
, "nst%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3285 return open(-1, -1, tape_num
, -1);
3287 // tape<m> => tape drive <m>
3288 tape_num
= -1; n1
= -1;
3289 if (sscanf(name
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3290 return open(-1, -1, tape_num
, -1);
3293 return set_err(EINVAL
);
3296 bool win_scsi_device::open(int pd_num
, int ld_num
, int tape_num
, int /*sub_addr*/)
3299 b
[sizeof(b
) - 1] = '\0';
3301 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
3302 else if (ld_num
>= 0)
3303 snprintf(b
, sizeof(b
) - 1, "\\\\.\\%c:", 'A' + ld_num
);
3304 else if (tape_num
>= 0)
3305 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
3312 HANDLE h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
3313 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
3314 OPEN_EXISTING
, 0, 0);
3315 if (h
== INVALID_HANDLE_VALUE
) {
3316 set_err(ENODEV
, "%s: Open failed, Error=%u", b
, (unsigned)GetLastError());
3325 SCSI_PASS_THROUGH_DIRECT spt
;
3327 UCHAR ucSenseBuf
[64];
3328 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
3331 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3332 // Used if DataTransferLength not supported by *_DIRECT.
3333 static long scsi_pass_through_indirect(HANDLE h
,
3334 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
* sbd
)
3336 struct SCSI_PASS_THROUGH_WITH_BUFFERS
{
3337 SCSI_PASS_THROUGH spt
;
3339 UCHAR ucSenseBuf
[sizeof(sbd
->ucSenseBuf
)];
3340 UCHAR ucDataBuf
[512];
3343 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
3344 memset(&sb
, 0, sizeof(sb
));
3346 // DATA_OUT not implemented yet
3347 if (!( sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
3348 && sbd
->spt
.DataTransferLength
<= sizeof(sb
.ucDataBuf
)))
3349 return ERROR_INVALID_PARAMETER
;
3351 sb
.spt
.Length
= sizeof(sb
.spt
);
3352 sb
.spt
.CdbLength
= sbd
->spt
.CdbLength
;
3353 memcpy(sb
.spt
.Cdb
, sbd
->spt
.Cdb
, sizeof(sb
.spt
.Cdb
));
3354 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3355 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
3356 sb
.spt
.DataIn
= sbd
->spt
.DataIn
;
3357 sb
.spt
.DataTransferLength
= sbd
->spt
.DataTransferLength
;
3358 sb
.spt
.DataBufferOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
3359 sb
.spt
.TimeOutValue
= sbd
->spt
.TimeOutValue
;
3362 if (!DeviceIoControl(h
, IOCTL_SCSI_PASS_THROUGH
,
3363 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3364 return GetLastError();
3366 sbd
->spt
.ScsiStatus
= sb
.spt
.ScsiStatus
;
3367 if (sb
.spt
.ScsiStatus
& SCSI_STATUS_CHECK_CONDITION
)
3368 memcpy(sbd
->ucSenseBuf
, sb
.ucSenseBuf
, sizeof(sbd
->ucSenseBuf
));
3370 sbd
->spt
.DataTransferLength
= sb
.spt
.DataTransferLength
;
3371 if (sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
&& sb
.spt
.DataTransferLength
> 0)
3372 memcpy(sbd
->spt
.DataBuffer
, sb
.ucDataBuf
, sb
.spt
.DataTransferLength
);
3377 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3378 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io
* iop
)
3380 int report
= scsi_debugmode
; // TODO
3384 const unsigned char * ucp
= iop
->cmnd
;
3387 const int sz
= (int)sizeof(buff
);
3389 np
= scsi_get_opcode_name(ucp
[0]);
3390 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3391 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3392 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3394 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3395 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3397 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3398 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3399 (trunc
? " [only first 256 bytes shown]" : ""));
3400 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3403 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3407 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3408 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3409 set_err(EINVAL
, "cmnd_len too large");
3413 memset(&sb
, 0, sizeof(sb
));
3414 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3415 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3416 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3417 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3418 sb
.spt
.SenseInfoOffset
=
3419 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3420 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3423 switch (iop
->dxfer_dir
) {
3425 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3427 case DXFER_FROM_DEVICE
:
3428 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3429 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3430 sb
.spt
.DataBuffer
= iop
->dxferp
;
3431 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3432 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3433 if (sb
.spt
.DataTransferLength
== 1)
3436 case DXFER_TO_DEVICE
:
3437 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3438 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3439 sb
.spt
.DataBuffer
= iop
->dxferp
;
3442 set_err(EINVAL
, "bad dxfer_dir");
3449 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3450 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3451 err
= GetLastError();
3454 err
= scsi_pass_through_indirect(get_fh(), &sb
);
3457 return set_err((err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
),
3458 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3459 (direct
? "_DIRECT" : ""), err
);
3461 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3462 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3463 int slen
= sb
.ucSenseBuf
[7] + 8;
3465 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3466 slen
= sizeof(sb
.ucSenseBuf
);
3467 if (slen
> (int)iop
->max_sense_len
)
3468 slen
= iop
->max_sense_len
;
3469 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3470 iop
->resp_sense_len
= slen
;
3473 pout(" >>> Sense buffer, len=%d:\n", slen
);
3474 dStrHex(iop
->sensep
, slen
, 1);
3476 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3477 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3478 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3479 iop
->sensep
[2], iop
->sensep
[3]);
3481 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3482 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3483 iop
->sensep
[12], iop
->sensep
[13]);
3486 iop
->resp_sense_len
= 0;
3488 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3489 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3493 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3494 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3495 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3496 (trunc
? " [only first 256 bytes shown]" : ""));
3497 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3502 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3503 static long scsi_pass_through_direct(HANDLE fd
, UCHAR targetid
, struct scsi_cmnd_io
* iop
)
3505 int report
= scsi_debugmode
; // TODO
3509 const unsigned char * ucp
= iop
->cmnd
;
3512 const int sz
= (int)sizeof(buff
);
3514 np
= scsi_get_opcode_name(ucp
[0]);
3515 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3516 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3517 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3519 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3520 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3522 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3523 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3524 (trunc
? " [only first 256 bytes shown]" : ""));
3525 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3528 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3532 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3533 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3537 memset(&sb
, 0, sizeof(sb
));
3538 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3539 //sb.spt.PathId = 0;
3540 sb
.spt
.TargetId
= targetid
;
3542 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3543 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3544 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3545 sb
.spt
.SenseInfoOffset
=
3546 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3547 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3550 switch (iop
->dxfer_dir
) {
3552 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3554 case DXFER_FROM_DEVICE
:
3555 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3556 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3557 sb
.spt
.DataBuffer
= iop
->dxferp
;
3558 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3559 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3560 if (sb
.spt
.DataTransferLength
== 1)
3563 case DXFER_TO_DEVICE
:
3564 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3565 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3566 sb
.spt
.DataBuffer
= iop
->dxferp
;
3575 if (!DeviceIoControl(fd
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3576 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3577 err
= GetLastError();
3580 err
= scsi_pass_through_indirect(fd
, &sb
);
3587 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3588 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3589 int slen
= sb
.ucSenseBuf
[7] + 8;
3591 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3592 slen
= sizeof(sb
.ucSenseBuf
);
3593 if (slen
> (int)iop
->max_sense_len
)
3594 slen
= iop
->max_sense_len
;
3595 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3596 iop
->resp_sense_len
= slen
;
3599 pout(" >>> Sense buffer, len=%d:\n", slen
);
3600 dStrHex(iop
->sensep
, slen
, 1);
3602 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3603 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3604 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3605 iop
->sensep
[2], iop
->sensep
[3]);
3607 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3608 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3609 iop
->sensep
[12], iop
->sensep
[13]);
3612 iop
->resp_sense_len
= 0;
3614 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3615 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3619 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3620 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3621 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3622 (trunc
? " [only first 256 bytes shown]" : ""));
3623 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3629 // Areca RAID Controller(SAS Device)
3630 win_areca_scsi_device::win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3631 : smart_device(intf
, dev_name
, "areca", "areca")
3633 set_fh(INVALID_HANDLE_VALUE
);
3634 set_disknum(disknum
);
3636 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3639 bool win_areca_scsi_device::open()
3647 hFh
= CreateFile( get_dev_name(),
3648 GENERIC_READ
|GENERIC_WRITE
,
3649 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3654 if(hFh
== INVALID_HANDLE_VALUE
)
3663 smart_device
* win_areca_scsi_device::autodetect_open()
3668 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3670 int ioctlreturn
= 0;
3672 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3673 if ( ioctlreturn
|| iop
->scsi_status
)
3675 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3676 if ( ioctlreturn
|| iop
->scsi_status
)
3686 bool win_areca_scsi_device::arcmsr_lock()
3688 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3692 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3693 return set_err(EINVAL
, "unable to parse device name");
3695 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3696 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3697 if ( m_mutex
== NULL
)
3699 return set_err(EIO
, "CreateMutex failed");
3702 // atomic access to driver
3703 WaitForSingleObject(m_mutex
, INFINITE
);
3709 bool win_areca_scsi_device::arcmsr_unlock()
3711 if( m_mutex
!= NULL
)
3713 ReleaseMutex(m_mutex
);
3714 CloseHandle(m_mutex
);
3721 // Areca RAID Controller(SATA Disk)
3722 win_areca_ata_device::win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3723 : smart_device(intf
, dev_name
, "areca", "areca")
3725 set_fh(INVALID_HANDLE_VALUE
);
3726 set_disknum(disknum
);
3728 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3731 bool win_areca_ata_device::open()
3739 hFh
= CreateFile( get_dev_name(),
3740 GENERIC_READ
|GENERIC_WRITE
,
3741 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3746 if(hFh
== INVALID_HANDLE_VALUE
)
3755 smart_device
* win_areca_ata_device::autodetect_open()
3759 // autodetect device type
3760 is_ata
= arcmsr_get_dev_type();
3774 smart_device_auto_ptr
newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
3777 newdev
->open(); // TODO: Can possibly pass open fd
3779 return newdev
.release();
3782 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3784 int ioctlreturn
= 0;
3786 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3787 if ( ioctlreturn
|| iop
->scsi_status
)
3789 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3790 if ( ioctlreturn
|| iop
->scsi_status
)
3800 bool win_areca_ata_device::arcmsr_lock()
3802 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3806 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3807 return set_err(EINVAL
, "unable to parse device name");
3809 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3810 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3811 if ( m_mutex
== NULL
)
3813 return set_err(EIO
, "CreateMutex failed");
3816 // atomic access to driver
3817 WaitForSingleObject(m_mutex
, INFINITE
);
3823 bool win_areca_ata_device::arcmsr_unlock()
3825 if( m_mutex
!= NULL
)
3827 ReleaseMutex(m_mutex
);
3828 CloseHandle(m_mutex
);
3835 //////////////////////////////////////////////////////////////////////////////////////////////////
3840 /////////////////////////////////////////////////////////////////////////////
3842 // Initialize platform interface and register with smi()
3843 void smart_interface::init()
3846 // Remove "." from DLL search path if supported
3847 // to prevent DLL preloading attacks
3848 BOOL (WINAPI
* SetDllDirectoryA_p
)(LPCSTR
) = (BOOL (WINAPI
*)(LPCSTR
))
3849 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
3850 if (SetDllDirectoryA_p
)
3851 SetDllDirectoryA_p("");
3854 static os_win32::win_smart_interface the_win_interface
;
3855 smart_interface::set(&the_win_interface
);
3861 // Get exe directory
3862 // (prototype in utiliy.h)
3863 std::string
get_exe_dir()
3865 char path
[MAX_PATH
];
3866 // Get path of this exe
3867 if (!GetModuleFileNameA(GetModuleHandleA(0), path
, sizeof(path
)))
3868 throw std::runtime_error("GetModuleFileName() failed");
3869 // Replace backslash by slash
3871 for (int i
= 0; path
[i
]; i
++)
3872 if (path
[i
] == '\\') {
3873 path
[i
] = '/'; sl
= i
;