4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
21 #define _WIN32_WINNT WINVER
27 #include "smartctl.h" // TODO: Do not use smartctl only variables here
29 #include "dev_interface.h"
30 #include "dev_ata_cmd_set.h"
31 #include "dev_areca.h"
33 #include "os_win32/wmiquery.h"
41 #define assert(x) /* */
44 #include <stddef.h> // offsetof()
45 #include <io.h> // access()
47 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
48 #define WIN32_LEAN_AND_MEAN
52 // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32
53 // (Missing: FILE_DEVICE_SCSI)
58 #elif HAVE_DDK_NTDDDISK_H
59 // older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
60 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
61 #include <ddk/ntdddisk.h>
62 #include <ddk/ntddscsi.h>
63 #include <ddk/ntddstor.h>
65 // MSVC10, older MinGW
66 // (Missing: IOCTL_SCSI_MINIPORT_*)
72 // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
79 // Silence -Wunused-local-typedefs warning from g++ >= 4.8
81 #define ATTR_UNUSED __attribute__((unused))
83 #define ATTR_UNUSED /**/
86 // Macro to check constants at compile time using a dummy typedef
87 #define ASSERT_CONST(c, n) \
88 typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED
89 #define ASSERT_SIZEOF(t, n) \
90 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
93 #define SELECT_WIN_32_64(x32, x64) (x32)
95 #define SELECT_WIN_32_64(x32, x64) (x64)
98 const char * os_win32_cpp_cvsid
= "$Id: os_win32.cpp 3830 2013-07-18 20:59:53Z chrfranke $";
100 /////////////////////////////////////////////////////////////////////////////
101 // Windows I/O-controls, some declarations are missing in the include files
105 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
107 ASSERT_CONST(SMART_GET_VERSION
, 0x074080);
108 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND
, 0x07c084);
109 ASSERT_CONST(SMART_RCV_DRIVE_DATA
, 0x07c088);
110 ASSERT_SIZEOF(GETVERSIONINPARAMS
, 24);
111 ASSERT_SIZEOF(SENDCMDINPARAMS
, 32+1);
112 ASSERT_SIZEOF(SENDCMDOUTPARAMS
, 16+1);
115 // IDE PASS THROUGH (2000, XP, undocumented)
117 #ifndef IOCTL_IDE_PASS_THROUGH
119 #define IOCTL_IDE_PASS_THROUGH \
120 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
122 #endif // IOCTL_IDE_PASS_THROUGH
128 ULONG DataBufferSize
;
134 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH
, 0x04d028);
135 ASSERT_SIZEOF(ATA_PASS_THROUGH
, 12+1);
138 // ATA PASS THROUGH (Win2003, XP SP2)
140 #ifndef IOCTL_ATA_PASS_THROUGH
142 #define IOCTL_ATA_PASS_THROUGH \
143 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
145 typedef struct _ATA_PASS_THROUGH_EX
{
151 UCHAR ReservedAsUchar
;
152 ULONG DataTransferLength
;
154 ULONG ReservedAsUlong
;
155 ULONG_PTR DataBufferOffset
;
156 UCHAR PreviousTaskFile
[8];
157 UCHAR CurrentTaskFile
[8];
158 } ATA_PASS_THROUGH_EX
;
160 #define ATA_FLAGS_DRDY_REQUIRED 0x01
161 #define ATA_FLAGS_DATA_IN 0x02
162 #define ATA_FLAGS_DATA_OUT 0x04
163 #define ATA_FLAGS_48BIT_COMMAND 0x08
164 #define ATA_FLAGS_USE_DMA 0x10
165 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
167 #endif // IOCTL_ATA_PASS_THROUGH
169 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH
, 0x04d02c);
170 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX
, SELECT_WIN_32_64(40, 48));
173 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
175 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH
, 0x04d004);
176 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT
, 0x04d014);
177 ASSERT_SIZEOF(SCSI_PASS_THROUGH
, SELECT_WIN_32_64(44, 56));
178 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT
, SELECT_WIN_32_64(44, 56));
181 // SMART IOCTL via SCSI MINIPORT ioctl
183 #ifndef FILE_DEVICE_SCSI
184 #define FILE_DEVICE_SCSI 0x001b
187 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
189 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
190 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
191 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
192 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
193 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
194 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
195 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
196 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
197 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
198 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
199 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
200 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
201 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
203 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
205 ASSERT_CONST(IOCTL_SCSI_MINIPORT
, 0x04d008);
206 ASSERT_SIZEOF(SRB_IO_CONTROL
, 28);
209 // IOCTL_STORAGE_QUERY_PROPERTY
211 #ifndef IOCTL_STORAGE_QUERY_PROPERTY
213 #define IOCTL_STORAGE_QUERY_PROPERTY \
214 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
216 typedef struct _STORAGE_DEVICE_DESCRIPTOR
{
220 UCHAR DeviceTypeModifier
;
221 BOOLEAN RemovableMedia
;
222 BOOLEAN CommandQueueing
;
223 ULONG VendorIdOffset
;
224 ULONG ProductIdOffset
;
225 ULONG ProductRevisionOffset
;
226 ULONG SerialNumberOffset
;
227 STORAGE_BUS_TYPE BusType
;
228 ULONG RawPropertiesLength
;
229 UCHAR RawDeviceProperties
[1];
230 } STORAGE_DEVICE_DESCRIPTOR
;
232 typedef enum _STORAGE_QUERY_TYPE
{
233 PropertyStandardQuery
= 0,
236 PropertyQueryMaxDefined
237 } STORAGE_QUERY_TYPE
;
239 typedef enum _STORAGE_PROPERTY_ID
{
240 StorageDeviceProperty
= 0,
241 StorageAdapterProperty
,
242 StorageDeviceIdProperty
,
243 StorageDeviceUniqueIdProperty
,
244 StorageDeviceWriteCacheProperty
,
245 StorageMiniportProperty
,
246 StorageAccessAlignmentProperty
247 } STORAGE_PROPERTY_ID
;
249 typedef struct _STORAGE_PROPERTY_QUERY
{
250 STORAGE_PROPERTY_ID PropertyId
;
251 STORAGE_QUERY_TYPE QueryType
;
252 UCHAR AdditionalParameters
[1];
253 } STORAGE_PROPERTY_QUERY
;
255 #endif // IOCTL_STORAGE_QUERY_PROPERTY
257 ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY
, 0x002d1400);
258 ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR
, 36+1+3);
259 ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY
, 8+1+3);
262 // IOCTL_STORAGE_PREDICT_FAILURE
264 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE
, 0x002d1100);
265 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE
, 4+512);
268 // 3ware specific versions of SMART ioctl structs
270 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
274 typedef struct _GETVERSIONINPARAMS_EX
{
280 DWORD dwDeviceMapEx
; // 3ware specific: RAID drive bit map
281 WORD wIdentifier
; // Vendor specific identifier
282 WORD wControllerId
; // 3ware specific: Controller ID (0,1,...)
284 } GETVERSIONINPARAMS_EX
;
286 typedef struct _SENDCMDINPARAMS_EX
{
290 BYTE bPortNumber
; // 3ware specific: port number
291 WORD wIdentifier
; // Vendor specific identifier
294 } SENDCMDINPARAMS_EX
;
298 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX
, sizeof(GETVERSIONINPARAMS
));
299 ASSERT_SIZEOF(SENDCMDINPARAMS_EX
, sizeof(SENDCMDINPARAMS
));
304 ASSERT_SIZEOF(IOCTL_HEADER
, sizeof(SRB_IO_CONTROL
));
305 ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER
, 204);
306 ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER
, 2080);
307 ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER
, 168);
311 /////////////////////////////////////////////////////////////////////////////
313 namespace os_win32
{ // no need to publish anything, name provided for Doxygen
316 #pragma warning(disable:4250)
319 class win_smart_device
320 : virtual public /*implements*/ smart_device
324 : smart_device(never_called
),
325 m_fh(INVALID_HANDLE_VALUE
)
328 virtual ~win_smart_device() throw();
330 virtual bool is_open() const;
332 virtual bool close();
335 /// Set handle for open() in derived classes.
336 void set_fh(HANDLE fh
)
339 /// Return handle for derived classes.
340 HANDLE
get_fh() const
344 HANDLE m_fh
; ///< File handle
348 /////////////////////////////////////////////////////////////////////////////
351 : public /*implements*/ ata_device
,
352 public /*extends*/ win_smart_device
355 win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
357 virtual ~win_ata_device() throw();
361 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
363 virtual bool ata_identify_is_cached() const;
366 bool open(int phydrive
, int logdrive
, const char * options
, int port
);
368 std::string m_options
;
369 bool m_usr_options
; // options set by user?
370 bool m_admin
; // open with admin access?
371 int m_phydrive
; // PhysicalDriveN or -1
372 bool m_id_is_cached
; // ata_identify_is_cached() return value.
373 bool m_is_3ware
; // LSI/3ware controller detected?
374 int m_port
; // LSI/3ware port
375 int m_smartver_state
;
379 /////////////////////////////////////////////////////////////////////////////
381 class win_scsi_device
382 : public /*implements*/ scsi_device
,
383 virtual public /*extends*/ win_smart_device
386 win_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
390 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
393 bool open(int pd_num
, int ld_num
, int tape_num
, int sub_addr
);
397 /////////////////////////////////////////////////////////////////////////////
400 : virtual public /*extends*/ smart_device
404 bool get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
);
406 /// Check physical drive existence
407 bool check_phy(const CSMI_SAS_PHY_INFO
& phy_info
, unsigned phy_no
);
411 : smart_device(never_called
)
412 { memset(&m_phy_ent
, 0, sizeof(m_phy_ent
)); }
414 /// Select physical drive
415 bool select_phy(unsigned phy_no
);
417 /// Get info for selected physical drive
418 const CSMI_SAS_PHY_ENTITY
& get_phy_ent() const
419 { return m_phy_ent
; }
421 /// Call platform-specific CSMI ioctl
422 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
423 unsigned csmi_bufsiz
) = 0;
426 CSMI_SAS_PHY_ENTITY m_phy_ent
; ///< CSMI info for this phy
430 class csmi_ata_device
431 : virtual public /*extends*/ csmi_device
,
432 virtual public /*implements*/ ata_device
435 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
439 : smart_device(never_called
) { }
443 //////////////////////////////////////////////////////////////////////
445 class win_csmi_device
446 : public /*implements*/ csmi_ata_device
449 win_csmi_device(smart_interface
* intf
, const char * dev_name
,
450 const char * req_type
);
452 virtual ~win_csmi_device() throw();
456 virtual bool close();
458 virtual bool is_open() const;
463 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
464 unsigned csmi_bufsiz
);
467 HANDLE m_fh
; ///< Controller device handle
468 unsigned m_phy_no
; ///< Physical drive number
472 //////////////////////////////////////////////////////////////////////
474 class win_tw_cli_device
475 : public /*implements*/ ata_device_with_command_set
478 win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
480 virtual bool is_open() const;
484 virtual bool close();
487 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
490 bool m_ident_valid
, m_smart_valid
;
491 ata_identify_device m_ident_buf
;
492 ata_smart_values m_smart_buf
;
496 /////////////////////////////////////////////////////////////////////////////
497 /// Areca RAID support
499 ///////////////////////////////////////////////////////////////////
500 // SATA(ATA) device behind Areca RAID Controller
501 class win_areca_ata_device
502 : public /*implements*/ areca_ata_device
,
503 public /*extends*/ win_smart_device
506 win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
508 virtual smart_device
* autodetect_open();
509 virtual bool arcmsr_lock();
510 virtual bool arcmsr_unlock();
511 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
517 ///////////////////////////////////////////////////////////////////
518 // SAS(SCSI) device behind Areca RAID Controller
519 class win_areca_scsi_device
520 : public /*implements*/ areca_scsi_device
,
521 public /*extends*/ win_smart_device
524 win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
526 virtual smart_device
* autodetect_open();
527 virtual bool arcmsr_lock();
528 virtual bool arcmsr_unlock();
529 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
536 //////////////////////////////////////////////////////////////////////
537 // Platform specific interface
539 class win_smart_interface
540 : public /*implements part of*/ smart_interface
543 virtual std::string
get_os_version_str();
545 virtual std::string
get_app_examples(const char * appname
);
548 virtual int64_t get_timer_usec();
551 virtual bool disable_system_auto_standby(bool disable
);
553 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
554 const char * pattern
= 0);
557 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
559 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
561 virtual smart_device
* autodetect_smart_device(const char * name
);
563 virtual smart_device
* get_custom_smart_device(const char * name
, const char * type
);
565 virtual std::string
get_valid_custom_dev_types_str();
569 //////////////////////////////////////////////////////////////////////
572 // Running on 64-bit Windows as 32-bit app ?
573 static bool is_wow64()
575 BOOL (WINAPI
* IsWow64Process_p
)(HANDLE
, PBOOL
) =
576 (BOOL (WINAPI
*)(HANDLE
, PBOOL
))
577 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
578 if (!IsWow64Process_p
)
581 if (!IsWow64Process_p(GetCurrentProcess(), &w64
))
587 // Return info string about build host and OS version
588 std::string
win_smart_interface::get_os_version_str()
590 char vstr
[sizeof(SMARTMONTOOLS_BUILD_HOST
)-1+sizeof("-2003r2(64)-sp2.1")+13]
591 = SMARTMONTOOLS_BUILD_HOST
;
594 char * const vptr
= vstr
+sizeof(SMARTMONTOOLS_BUILD_HOST
)-1;
595 const int vlen
= sizeof(vstr
)-sizeof(SMARTMONTOOLS_BUILD_HOST
);
596 assert(vptr
== vstr
+strlen(vstr
) && vptr
+vlen
+1 == vstr
+sizeof(vstr
));
598 OSVERSIONINFOEXA vi
; memset(&vi
, 0, sizeof(vi
));
599 vi
.dwOSVersionInfoSize
= sizeof(vi
);
600 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
)) {
601 memset(&vi
, 0, sizeof(vi
));
602 vi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
603 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
))
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())
1016 CSMI_SAS_PHY_INFO phy_info
;
1017 if (!test_dev
.get_phy_info(phy_info
))
1020 for (int pi
= 0; pi
< phy_info
.bNumberOfPhys
; pi
++) {
1021 if (!test_dev
.check_phy(phy_info
, pi
))
1023 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,%d", i
, pi
);
1024 devlist
.push_back( new win_csmi_device(this, name
, "ata") );
1032 // get examples for smartctl
1033 std::string
win_smart_interface::get_app_examples(const char * appname
)
1035 if (strcmp(appname
, "smartctl"))
1037 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1038 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1039 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1040 " (Enables SMART on first disk)\n\n"
1041 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1042 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1043 " (Prints Self-Test & Attribute errors)\n"
1044 " smartctl -a /dev/sda\n"
1045 " (Prints all information for disk on PhysicalDrive 0)\n"
1046 " smartctl -a /dev/pd3\n"
1047 " (Prints all information for disk on PhysicalDrive 3)\n"
1048 " smartctl -a /dev/tape1\n"
1049 " (Prints all information for SCSI tape on Tape 1)\n"
1050 " smartctl -A /dev/hdb,3\n"
1051 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1052 " smartctl -A /dev/tw_cli/c0/p1\n"
1053 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1054 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1055 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1056 " on 1st Areca RAID controller)\n"
1058 " ATA SMART access methods and ordering may be specified by modifiers\n"
1059 " following the device name: /dev/hdX:[saicm], where\n"
1060 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1061 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1062 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1064 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1069 bool win_smart_interface::disable_system_auto_standby(bool disable
)
1072 SYSTEM_POWER_STATUS ps
;
1073 if (!GetSystemPowerStatus(&ps
))
1074 return set_err(ENOSYS
, "Unknown power status");
1075 if (ps
.ACLineStatus
!= 1) {
1076 SetThreadExecutionState(ES_CONTINUOUS
);
1077 if (ps
.ACLineStatus
== 0)
1078 set_err(EIO
, "AC offline");
1080 set_err(EIO
, "Unknown AC line status");
1085 if (!SetThreadExecutionState(ES_CONTINUOUS
| (disable
? ES_SYSTEM_REQUIRED
: 0)))
1086 return set_err(ENOSYS
);
1091 /////////////////////////////////////////////////////////////////////////////
1093 /////////////////////////////////////////////////////////////////////////////
1095 #define SMART_CYL_LOW 0x4F
1096 #define SMART_CYL_HI 0xC2
1098 static void print_ide_regs(const IDEREGS
* r
, int out
)
1100 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1101 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
1102 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
1105 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
1107 pout(" Input : "); print_ide_regs(ri
, 0);
1109 pout(" Output: "); print_ide_regs(ro
, 1);
1113 /////////////////////////////////////////////////////////////////////////////
1115 // call SMART_GET_VERSION, return device map or -1 on error
1117 static int smart_get_version(HANDLE hdevice
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
1119 GETVERSIONINPARAMS vers
; memset(&vers
, 0, sizeof(vers
));
1120 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1123 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
1124 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1126 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1130 assert(num_out
== sizeof(GETVERSIONINPARAMS
));
1132 if (ata_debugmode
> 1) {
1133 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1134 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1135 (unsigned)num_out
, vers
.bVersion
, vers
.bRevision
,
1136 (unsigned)vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1137 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1138 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1139 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, (unsigned)vers_ex
.dwDeviceMapEx
);
1143 *ata_version_ex
= vers_ex
;
1145 // TODO: Check vers.fCapabilities here?
1146 return vers
.bIDEDeviceMap
;
1150 // call SMART_* ioctl
1152 static int smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
1154 SENDCMDINPARAMS inpar
;
1155 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
1157 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
1158 const SENDCMDOUTPARAMS
* outpar
;
1159 DWORD code
, num_out
;
1160 unsigned int size_out
;
1163 memset(&inpar
, 0, sizeof(inpar
));
1164 inpar
.irDriveRegs
= *regs
;
1166 // Older drivers may require bits 5 and 7 set
1167 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1168 inpar
.irDriveRegs
.bDriveHeadReg
|= 0xa0;
1170 // Drive number 0-3 was required on Win9x/ME only
1171 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1172 //inpar.bDriveNumber = drive;
1176 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
1177 inpar_ex
.bPortNumber
= port
;
1180 if (datasize
== 512) {
1181 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
1182 inpar
.cBufferSize
= size_out
= 512;
1184 else if (datasize
== 0) {
1185 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
1186 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
1187 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
1188 // Note: cBufferSize must be 0 on Win9x
1197 memset(&outbuf
, 0, sizeof(outbuf
));
1199 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
1200 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
1201 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1202 long err
= GetLastError();
1203 if (ata_debugmode
&& (err
!= ERROR_INVALID_PARAMETER
|| ata_debugmode
> 1)) {
1204 pout(" %s failed, Error=%ld\n", name
, err
);
1205 print_ide_regs_io(regs
, NULL
);
1207 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
1208 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/
1209 || err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1212 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1214 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
1216 if (outpar
->DriverStatus
.bDriverError
) {
1217 if (ata_debugmode
) {
1218 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1219 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
1220 print_ide_regs_io(regs
, NULL
);
1222 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1226 if (ata_debugmode
> 1) {
1227 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name
,
1228 (unsigned)num_out
, (unsigned)outpar
->cBufferSize
);
1229 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
1230 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
1234 memcpy(data
, outpar
->bBuffer
, 512);
1235 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
1236 if (nonempty(outpar
->bBuffer
, sizeof(IDEREGS
)))
1237 memcpy(regs
, outpar
->bBuffer
, sizeof(IDEREGS
));
1238 else { // Workaround for driver not returning regs
1240 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1241 *regs
= inpar
.irDriveRegs
;
1249 /////////////////////////////////////////////////////////////////////////////
1250 // IDE PASS THROUGH (2000, XP, undocumented)
1252 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1253 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1255 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
1257 if (datasize
> 512) {
1261 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
1262 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1264 const unsigned char magic
= 0xcf;
1271 buf
->IdeReg
= *regs
;
1272 buf
->DataBufferSize
= datasize
;
1274 buf
->DataBuffer
[0] = magic
;
1276 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
1277 buf
, size
, buf
, size
, &num_out
, NULL
)) {
1278 long err
= GetLastError();
1279 if (ata_debugmode
) {
1280 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
1281 print_ide_regs_io(regs
, NULL
);
1283 VirtualFree(buf
, 0, MEM_RELEASE
);
1284 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1289 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
1290 if (ata_debugmode
) {
1291 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1292 print_ide_regs_io(regs
, &buf
->IdeReg
);
1294 VirtualFree(buf
, 0, MEM_RELEASE
);
1299 // Check and copy data
1301 if ( num_out
!= size
1302 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
1303 if (ata_debugmode
) {
1304 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1305 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1306 print_ide_regs_io(regs
, &buf
->IdeReg
);
1308 VirtualFree(buf
, 0, MEM_RELEASE
);
1312 memcpy(data
, buf
->DataBuffer
, datasize
);
1315 if (ata_debugmode
> 1) {
1316 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1317 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1318 print_ide_regs_io(regs
, &buf
->IdeReg
);
1320 *regs
= buf
->IdeReg
;
1322 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1323 VirtualFree(buf
, 0, MEM_RELEASE
);
1328 /////////////////////////////////////////////////////////////////////////////
1329 // ATA PASS THROUGH (Win2003, XP SP2)
1332 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1333 // transfer per command. Therefore, multi-sector transfers are only supported
1334 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1335 // or READ/WRITE LOG EXT work only with single sector transfers.
1336 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1338 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1340 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, IDEREGS
* prev_regs
, char * data
, int datasize
)
1342 const int max_sectors
= 32; // TODO: Allocate dynamic buffer
1345 ATA_PASS_THROUGH_EX apt
;
1347 UCHAR ucDataBuf
[max_sectors
* 512];
1348 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
1350 const unsigned char magic
= 0xcf;
1352 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
1353 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
1354 //ab.apt.PathId = 0;
1355 //ab.apt.TargetId = 0;
1357 ab
.apt
.TimeOutValue
= 10;
1358 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
1359 ab
.apt
.DataBufferOffset
= size
;
1362 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1366 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
1367 ab
.apt
.DataTransferLength
= datasize
;
1369 ab
.ucDataBuf
[0] = magic
;
1371 else if (datasize
< 0) {
1372 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1376 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
1377 ab
.apt
.DataTransferLength
= -datasize
;
1379 memcpy(ab
.ucDataBuf
, data
, -datasize
);
1382 assert(ab
.apt
.AtaFlags
== 0);
1383 assert(ab
.apt
.DataTransferLength
== 0);
1386 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
1387 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
1388 IDEREGS
* ptfregs
= (IDEREGS
*)ab
.apt
.PreviousTaskFile
;
1392 *ptfregs
= *prev_regs
;
1393 ab
.apt
.AtaFlags
|= ATA_FLAGS_48BIT_COMMAND
;
1397 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
1398 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
1399 long err
= GetLastError();
1400 if (ata_debugmode
) {
1401 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
1402 print_ide_regs_io(regs
, NULL
);
1404 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1409 if (ctfregs
->bCommandReg
/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1410 if (ata_debugmode
) {
1411 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1412 print_ide_regs_io(regs
, ctfregs
);
1418 // Check and copy data
1420 if ( num_out
!= size
1421 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
1422 if (ata_debugmode
) {
1423 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out
);
1424 print_ide_regs_io(regs
, ctfregs
);
1429 memcpy(data
, ab
.ucDataBuf
, datasize
);
1432 if (ata_debugmode
> 1) {
1433 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out
);
1434 print_ide_regs_io(regs
, ctfregs
);
1438 *prev_regs
= *ptfregs
;
1444 /////////////////////////////////////////////////////////////////////////////
1445 // SMART IOCTL via SCSI MINIPORT ioctl
1447 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1448 // miniport driver (via SCSI port driver scsiport.sys).
1449 // It can be used to skip the missing or broken handling of some SMART
1450 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1452 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
1455 DWORD code
= 0; const char * name
= 0;
1456 if (regs
->bCommandReg
== ATA_IDENTIFY_DEVICE
) {
1457 code
= IOCTL_SCSI_MINIPORT_IDENTIFY
; name
= "IDENTIFY";
1459 else if (regs
->bCommandReg
== ATA_SMART_CMD
) switch (regs
->bFeaturesReg
) {
1460 case ATA_SMART_READ_VALUES
:
1461 code
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
; name
= "READ_SMART_ATTRIBS"; break;
1462 case ATA_SMART_READ_THRESHOLDS
:
1463 code
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
; name
= "READ_SMART_THRESHOLDS"; break;
1464 case ATA_SMART_ENABLE
:
1465 code
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
; name
= "ENABLE_SMART"; break;
1466 case ATA_SMART_DISABLE
:
1467 code
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
; name
= "DISABLE_SMART"; break;
1468 case ATA_SMART_STATUS
:
1469 code
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
; name
= "RETURN_STATUS"; break;
1470 case ATA_SMART_AUTOSAVE
:
1471 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
; name
= "ENABLE_DISABLE_AUTOSAVE"; break;
1472 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1473 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1474 case ATA_SMART_IMMEDIATE_OFFLINE
:
1475 code
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
; name
= "EXECUTE_OFFLINE_DIAGS"; break;
1476 case ATA_SMART_AUTO_OFFLINE
:
1477 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
; name
= "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1478 case ATA_SMART_READ_LOG_SECTOR
:
1479 code
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
; name
= "READ_SMART_LOG"; break;
1480 case ATA_SMART_WRITE_LOG_SECTOR
:
1481 code
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
; name
= "WRITE_SMART_LOG"; break;
1490 SRB_IO_CONTROL srbc
;
1493 SENDCMDOUTPARAMS out
;
1497 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(SENDCMDINPARAMS
)-1+512);
1498 memset(&sb
, 0, sizeof(sb
));
1502 if (datasize
> (int)sizeof(sb
.space
)+1) {
1508 else if (datasize
< 0) {
1509 if (-datasize
> (int)sizeof(sb
.space
)+1) {
1514 memcpy(sb
.params
.in
.bBuffer
, data
, size
);
1516 else if (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1517 size
= sizeof(IDEREGS
);
1520 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1521 memcpy(sb
.srbc
.Signature
, "SCSIDISK", 8); // atapi.sys
1522 sb
.srbc
.Timeout
= 60; // seconds
1523 sb
.srbc
.ControlCode
= code
;
1524 //sb.srbc.ReturnCode = 0;
1525 sb
.srbc
.Length
= sizeof(SENDCMDINPARAMS
)-1 + size
;
1526 sb
.params
.in
.irDriveRegs
= *regs
;
1527 sb
.params
.in
.cBufferSize
= size
;
1529 // Call miniport ioctl
1530 size
+= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)-1;
1532 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1533 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
1534 long err
= GetLastError();
1535 if (ata_debugmode
) {
1536 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name
, err
);
1537 print_ide_regs_io(regs
, NULL
);
1539 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1544 if (sb
.srbc
.ReturnCode
) {
1545 if (ata_debugmode
) {
1546 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name
, (unsigned)sb
.srbc
.ReturnCode
);
1547 print_ide_regs_io(regs
, NULL
);
1553 if (sb
.params
.out
.DriverStatus
.bDriverError
) {
1554 if (ata_debugmode
) {
1555 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1556 sb
.params
.out
.DriverStatus
.bDriverError
, sb
.params
.out
.DriverStatus
.bIDEError
);
1557 print_ide_regs_io(regs
, NULL
);
1559 errno
= (!sb
.params
.out
.DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1563 if (ata_debugmode
> 1) {
1564 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name
,
1565 (unsigned)num_out
, (unsigned)sb
.params
.out
.cBufferSize
);
1566 print_ide_regs_io(regs
, (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
?
1567 (const IDEREGS
*)(sb
.params
.out
.bBuffer
) : 0));
1571 memcpy(data
, sb
.params
.out
.bBuffer
, datasize
);
1572 else if (datasize
== 0 && code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1573 memcpy(regs
, sb
.params
.out
.bBuffer
, sizeof(IDEREGS
));
1579 /////////////////////////////////////////////////////////////////////////////
1581 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1583 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1586 SRB_IO_CONTROL srbc
;
1590 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1592 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1596 memset(&sb
, 0, sizeof(sb
));
1597 strncpy((char *)sb
.srbc
.Signature
, "<3ware>", sizeof(sb
.srbc
.Signature
));
1598 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1599 sb
.srbc
.Timeout
= 60; // seconds
1600 sb
.srbc
.ControlCode
= 0xA0000000;
1601 sb
.srbc
.ReturnCode
= 0;
1602 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1604 sb
.regs
.bReserved
= port
;
1607 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1608 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1609 long err
= GetLastError();
1610 if (ata_debugmode
) {
1611 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1612 print_ide_regs_io(regs
, NULL
);
1614 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1618 if (sb
.srbc
.ReturnCode
) {
1619 if (ata_debugmode
) {
1620 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb
.srbc
.ReturnCode
);
1621 print_ide_regs_io(regs
, NULL
);
1629 memcpy(data
, sb
.buffer
, datasize
);
1631 if (ata_debugmode
> 1) {
1632 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out
);
1633 print_ide_regs_io(regs
, &sb
.regs
);
1641 /////////////////////////////////////////////////////////////////////////////
1643 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1644 // 3DM/CLI "Rescan Controller" function does not to always update it.
1646 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1648 SRB_IO_CONTROL srbc
;
1649 memset(&srbc
, 0, sizeof(srbc
));
1650 strncpy((char *)srbc
.Signature
, "<3ware>", sizeof(srbc
.Signature
));
1651 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1652 srbc
.Timeout
= 60; // seconds
1653 srbc
.ControlCode
= 0xCC010014;
1654 srbc
.ReturnCode
= 0;
1658 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1659 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1660 long err
= GetLastError();
1662 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1663 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1666 if (srbc
.ReturnCode
) {
1668 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc
.ReturnCode
);
1672 if (ata_debugmode
> 1)
1673 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1679 /////////////////////////////////////////////////////////////////////////////
1681 // Routines for pseudo device /dev/tw_cli/*
1682 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1685 // Get clipboard data
1687 static int get_clipboard(char * data
, int datasize
)
1689 if (!OpenClipboard(NULL
))
1691 HANDLE h
= GetClipboardData(CF_TEXT
);
1696 const void * p
= GlobalLock(h
);
1697 int n
= GlobalSize(h
);
1707 // Run a command, write stdout to dataout
1708 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1710 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1712 // Create stdout pipe
1713 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1714 HANDLE pipe_out_w
, h
;
1715 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1717 HANDLE self
= GetCurrentProcess();
1719 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1720 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1721 CloseHandle(pipe_out_w
);
1725 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1726 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1727 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1732 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1733 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1734 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1735 si
.dwFlags
= STARTF_USESTDHANDLES
;
1736 PROCESS_INFORMATION pi
;
1738 NULL
, const_cast<char *>(cmd
),
1739 NULL
, NULL
, TRUE
/*inherit*/,
1740 CREATE_NO_WINDOW
/*do not create a new console window*/,
1741 NULL
, NULL
, &si
, &pi
)) {
1742 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1745 CloseHandle(pi
.hThread
);
1746 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1748 // Copy stdout to output buffer
1750 while (i
< outsize
) {
1752 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1756 CloseHandle(pipe_out_r
);
1758 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1759 CloseHandle(pi
.hProcess
);
1764 static const char * findstr(const char * str
, const char * sub
)
1766 const char * s
= strstr(str
, sub
);
1767 return (s
? s
+strlen(sub
) : "");
1771 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1773 int srclen
= strcspn(src
, "\r\n");
1775 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1776 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1778 if (i
< destsize
-1 && i
< srclen
)
1783 // TODO: This is OS independent
1785 win_tw_cli_device::win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
1786 : smart_device(intf
, dev_name
, "tw_cli", req_type
),
1787 m_ident_valid(false), m_smart_valid(false)
1789 memset(&m_ident_buf
, 0, sizeof(m_ident_buf
));
1790 memset(&m_smart_buf
, 0, sizeof(m_smart_buf
));
1794 bool win_tw_cli_device::is_open() const
1796 return (m_ident_valid
|| m_smart_valid
);
1800 bool win_tw_cli_device::open()
1802 m_ident_valid
= m_smart_valid
= false;
1803 const char * name
= skipdev(get_dev_name());
1804 // Read tw_cli or 3DM browser output into buffer
1806 int size
= -1, n1
= -1, n2
= -1;
1807 if (!strcmp(name
, "tw_cli/clip")) { // read clipboard
1808 size
= get_clipboard(buffer
, sizeof(buffer
));
1810 else if (!strcmp(name
, "tw_cli/stdin")) { // read stdin
1811 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1813 else if (sscanf(name
, "tw_cli/%nc%*u/p%*u%n", &n1
, &n2
) >= 0 && n2
== (int)strlen(name
)) {
1814 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1816 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
+n1
);
1817 if (ata_debugmode
> 1)
1818 pout("%s: Run: \"%s\"\n", name
, cmd
);
1819 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1822 return set_err(EINVAL
);
1825 if (ata_debugmode
> 1)
1826 pout("%s: Read %d bytes\n", name
, size
);
1828 return set_err(ENOENT
);
1829 if (size
>= (int)sizeof(buffer
))
1830 return set_err(EIO
);
1833 if (ata_debugmode
> 1)
1834 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1836 // Fake identify sector
1837 ASSERT_SIZEOF(ata_identify_device
, 512);
1838 ata_identify_device
* id
= &m_ident_buf
;
1839 memset(id
, 0, sizeof(*id
));
1840 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1841 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1842 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1843 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1844 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1846 id
->words047_079
[49-47] = 0x0200; // size valid
1847 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1848 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1850 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1851 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1853 // Parse smart data hex dump
1854 const char * s
= findstr(buffer
, "Drive Smart Data:");
1856 s
= findstr(buffer
, "Drive SMART Data:"); // tw_cli from 9.5.x
1858 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1860 const char * s1
= findstr(s
, "<td class"); // html version
1863 s
+= strcspn(s
, "\r\n");
1866 s
= buffer
; // try raw hex dump without header
1868 unsigned char * sd
= (unsigned char *)&m_smart_buf
;
1871 unsigned x
= ~0; int n
= -1;
1872 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1874 sd
[i
] = (unsigned char)x
;
1875 if (!(++i
< 512 && n
> 0))
1878 if (*s
== '<') // "<br>"
1879 s
+= strcspn(s
, "\r\n");
1882 if (!id
->model
[1]) {
1883 // No useful data found
1884 char * err
= strstr(buffer
, "Error:");
1886 err
= strstr(buffer
, "error :");
1887 if (err
&& (err
= strchr(err
, ':'))) {
1888 // Show tw_cli error message
1890 err
[strcspn(err
, "\r\n")] = 0;
1891 return set_err(EIO
, "%s", err
);
1893 return set_err(EIO
);
1898 m_ident_valid
= true;
1899 m_smart_valid
= !!sd
;
1904 bool win_tw_cli_device::close()
1906 m_ident_valid
= m_smart_valid
= false;
1911 int win_tw_cli_device::ata_command_interface(smart_command_set command
, int /*select*/, char * data
)
1917 memcpy(data
, &m_ident_buf
, 512);
1922 memcpy(data
, &m_smart_buf
, 512);
1926 case STATUS_CHECK
: // Fake "good" SMART status
1931 // Arrive here for all unsupported commands
1937 /////////////////////////////////////////////////////////////////////////////
1938 // IOCTL_STORAGE_QUERY_PROPERTY
1940 union STORAGE_DEVICE_DESCRIPTOR_DATA
{
1941 STORAGE_DEVICE_DESCRIPTOR desc
;
1945 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
1946 // (This works without admin rights)
1948 static int storage_query_property_ioctl(HANDLE hdevice
, STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
1950 STORAGE_PROPERTY_QUERY query
= {StorageDeviceProperty
, PropertyStandardQuery
, {0} };
1951 memset(data
, 0, sizeof(*data
));
1954 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_QUERY_PROPERTY
,
1955 &query
, sizeof(query
), data
, sizeof(*data
), &num_out
, NULL
)) {
1956 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
1957 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
1962 if (ata_debugmode
> 1 || scsi_debugmode
> 1) {
1963 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
1965 " Product: \"%s\"\n"
1966 " Revision: \"%s\"\n"
1968 " BusType: 0x%02x\n",
1969 (data
->desc
.VendorIdOffset
? data
->raw
+data
->desc
.VendorIdOffset
: "(null)"),
1970 (data
->desc
.ProductIdOffset
? data
->raw
+data
->desc
.ProductIdOffset
: "(null)"),
1971 (data
->desc
.ProductRevisionOffset
? data
->raw
+data
->desc
.ProductRevisionOffset
: "(null)"),
1972 (data
->desc
.RemovableMedia
? "Yes":"No"), data
->desc
.BusType
1979 /////////////////////////////////////////////////////////////////////////////
1980 // IOCTL_STORAGE_PREDICT_FAILURE
1982 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
1983 // or -1 on error, opionally return VendorSpecific data.
1984 // (This works without admin rights)
1986 static int storage_predict_failure_ioctl(HANDLE hdevice
, char * data
= 0)
1988 STORAGE_PREDICT_FAILURE pred
;
1989 memset(&pred
, 0, sizeof(pred
));
1992 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_PREDICT_FAILURE
,
1993 0, 0, &pred
, sizeof(pred
), &num_out
, NULL
)) {
1994 if (ata_debugmode
> 1)
1995 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
2000 if (ata_debugmode
> 1) {
2001 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2002 " PredictFailure: 0x%08x\n"
2003 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2004 (unsigned)pred
.PredictFailure
,
2005 pred
.VendorSpecific
[0], pred
.VendorSpecific
[1], pred
.VendorSpecific
[2],
2006 pred
.VendorSpecific
[sizeof(pred
.VendorSpecific
)-1]
2010 memcpy(data
, pred
.VendorSpecific
, sizeof(pred
.VendorSpecific
));
2011 return (!pred
.PredictFailure
? 0 : 1);
2015 /////////////////////////////////////////////////////////////////////////////
2017 // Return true if Intel ICHxR RAID volume
2018 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2020 if (!(data
->desc
.VendorIdOffset
&& data
->desc
.ProductIdOffset
))
2022 const char * vendor
= data
->raw
+ data
->desc
.VendorIdOffset
;
2023 if (!(!strnicmp(vendor
, "Intel", 5) && strspn(vendor
+5, " ") == strlen(vendor
+5)))
2025 if (strnicmp(data
->raw
+ data
->desc
.ProductIdOffset
, "Raid ", 5))
2030 // get DEV_* for open handle
2031 static win_dev_type
get_controller_type(HANDLE hdevice
, bool admin
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2033 // Get BusType from device descriptor
2034 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2035 if (storage_query_property_ioctl(hdevice
, &data
))
2038 // Newer BusType* values are missing in older includes
2039 switch ((int)data
.desc
.BusType
) {
2041 case 0x0b: // BusTypeSata
2043 memset(ata_version_ex
, 0, sizeof(*ata_version_ex
));
2048 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2049 if (is_intel_raid_volume(&data
))
2051 // LSI/3ware RAID volume: supports SMART_*
2052 if (admin
&& smart_get_version(hdevice
, ata_version_ex
) >= 0)
2056 case 0x09: // BusTypeiScsi
2057 case 0x0a: // BusTypeSas
2069 // get DEV_* for device path
2070 static win_dev_type
get_controller_type(const char * path
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
2073 HANDLE h
= CreateFileA(path
, GENERIC_READ
|GENERIC_WRITE
,
2074 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2075 if (h
== INVALID_HANDLE_VALUE
) {
2077 h
= CreateFileA(path
, 0,
2078 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2079 if (h
== INVALID_HANDLE_VALUE
)
2082 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2083 pout(" %s: successfully opened%s\n", path
, (!admin
? " (without admin rights)" :""));
2084 win_dev_type type
= get_controller_type(h
, admin
, ata_version_ex
);
2089 // get DEV_* for physical drive number
2090 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2093 snprintf(path
, sizeof(path
)-1, "\\\\.\\PhysicalDrive%d", drive
);
2094 return get_controller_type(path
, ata_version_ex
);
2097 static win_dev_type
get_phy_drive_type(int drive
)
2099 return get_phy_drive_type(drive
, 0);
2102 // get DEV_* for logical drive number
2103 static win_dev_type
get_log_drive_type(int drive
)
2106 snprintf(path
, sizeof(path
)-1, "\\\\.\\%c:", 'A'+drive
);
2107 return get_controller_type(path
);
2110 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2111 static int get_identify_from_device_property(HANDLE hdevice
, ata_identify_device
* id
)
2113 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2114 if (storage_query_property_ioctl(hdevice
, &data
))
2117 memset(id
, 0, sizeof(*id
));
2119 // Some drivers split ATA model string into VendorId and ProductId,
2120 // others return it as ProductId only.
2121 char model
[sizeof(id
->model
) + 1] = "";
2124 if (data
.desc
.VendorIdOffset
) {
2125 for ( ;i
< sizeof(model
)-1 && data
.raw
[data
.desc
.VendorIdOffset
+i
]; i
++)
2126 model
[i
] = data
.raw
[data
.desc
.VendorIdOffset
+i
];
2129 if (data
.desc
.ProductIdOffset
) {
2130 while (i
> 1 && model
[i
-2] == ' ') // Keep last blank from VendorId
2132 // Ignore VendorId "ATA"
2133 if (i
<= 4 && !strncmp(model
, "ATA", 3) && (i
== 3 || model
[3] == ' '))
2135 for (unsigned j
= 0; i
< sizeof(model
)-1 && data
.raw
[data
.desc
.ProductIdOffset
+j
]; i
++, j
++)
2136 model
[i
] = data
.raw
[data
.desc
.ProductIdOffset
+j
];
2139 while (i
> 0 && model
[i
-1] == ' ')
2142 copy_swapped(id
->model
, model
, sizeof(id
->model
));
2144 if (data
.desc
.ProductRevisionOffset
)
2145 copy_swapped(id
->fw_rev
, data
.raw
+data
.desc
.ProductRevisionOffset
, sizeof(id
->fw_rev
));
2147 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
2148 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
2152 // Get Serial Number in IDENTIFY from WMI
2153 static bool get_serial_from_wmi(int drive
, ata_identify_device
* id
)
2155 bool debug
= (ata_debugmode
> 1);
2158 if (!ws
.connect()) {
2160 pout("WMI connect failed\n");
2165 if (!ws
.query1(wo
, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2166 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2169 std::string serial
= wo
.get_str("SerialNumber");
2171 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive
, wo
.get_str("Model").c_str(), serial
.c_str());
2173 copy_swapped(id
->serial_no
, serial
.c_str(), sizeof(id
->serial_no
));
2178 /////////////////////////////////////////////////////////////////////////////
2179 // USB ID detection using WMI
2181 // Get USB ID for a physical drive number
2182 static bool get_usb_id(int drive
, unsigned short & vendor_id
, unsigned short & product_id
)
2184 bool debug
= (scsi_debugmode
> 1);
2187 if (!ws
.connect()) {
2189 pout("WMI connect failed\n");
2195 if (!ws
.query1(wo
, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2198 std::string name
= wo
.get_str("Model");
2200 pout("PhysicalDrive%d, \"%s\":\n", drive
, name
.c_str());
2202 // Get USB_CONTROLLER -> DEVICE associations
2204 if (!ws
.query(we
, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2207 unsigned short usb_venid
= 0, prev_usb_venid
= 0;
2208 unsigned short usb_proid
= 0, prev_usb_proid
= 0;
2209 std::string prev_usb_ant
;
2210 std::string prev_ant
, ant
, dep
;
2212 const regular_expression
regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED
);
2214 while (we
.next(wo
)) {
2216 // Find next 'USB_CONTROLLER, DEVICE' pair
2217 ant
= wo
.get_str("Antecedent");
2218 dep
= wo
.get_str("Dependent");
2220 if (debug
&& ant
!= prev_ant
)
2221 pout(" %s:\n", ant
.c_str());
2224 regmatch_t match
[2];
2225 if (!(regex
.execute(dep
.c_str(), 2, match
) && match
[1].rm_so
>= 0)) {
2227 pout(" | (\"%s\")\n", dep
.c_str());
2231 std::string
devid(dep
.c_str()+match
[1].rm_so
, match
[1].rm_eo
-match
[1].rm_so
);
2233 if (str_starts_with(devid
, "USB\\\\VID_")) {
2234 // USB bridge entry, save CONTROLLER, ID
2236 if (!(sscanf(devid
.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2237 &prev_usb_venid
, &prev_usb_proid
, &nc
) == 2 && nc
== 9+4+5+4)) {
2238 prev_usb_venid
= prev_usb_proid
= 0;
2242 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid
.c_str(), prev_usb_venid
, prev_usb_proid
);
2245 else if (str_starts_with(devid
, "USBSTOR\\\\")) {
2246 // USBSTOR device found
2248 pout(" +--> \"%s\"\n", devid
.c_str());
2252 if (!ws
.query1(wo2
, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid
.c_str()))
2254 std::string name2
= wo2
.get_str("Name");
2256 // Continue if not name of physical disk drive
2257 if (name2
!= name
) {
2259 pout(" +---> (\"%s\")\n", name2
.c_str());
2263 // Fail if previous USB bridge is associated to other controller or ID is unknown
2264 if (!(ant
== prev_usb_ant
&& prev_usb_venid
)) {
2266 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2
.c_str());
2270 // Handle multiple devices with same name
2272 // Fail if multiple devices with same name have different USB bridge types
2273 if (!(usb_venid
== prev_usb_venid
&& usb_proid
== prev_usb_proid
)) {
2275 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2
.c_str());
2281 usb_venid
= prev_usb_venid
;
2282 usb_proid
= prev_usb_proid
;
2284 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2
.c_str(), usb_venid
, usb_proid
);
2286 // Continue to check for duplicate names ...
2290 pout(" | \"%s\"\n", devid
.c_str());
2297 vendor_id
= usb_venid
;
2298 product_id
= usb_proid
;
2304 /////////////////////////////////////////////////////////////////////////////
2306 // Call GetDevicePowerState()
2307 // returns: 1=active, 0=standby, -1=error
2308 // (This would also work for SCSI drives)
2310 static int get_device_power_state(HANDLE hdevice
)
2313 if (!GetDevicePowerState(hdevice
, &state
)) {
2314 long err
= GetLastError();
2316 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
2317 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2318 // TODO: This may not work as expected on transient errors,
2319 // because smartd interprets -1 as SLEEP mode regardless of errno.
2323 if (ata_debugmode
> 1)
2324 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
2329 /////////////////////////////////////////////////////////////////////////////
2331 // Get default ATA device options
2333 static const char * ata_get_def_options()
2335 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2336 // STORAGE_*, SCSI_MINIPORT_*
2340 // Common routines for devices with HANDLEs
2342 win_smart_device::~win_smart_device() throw()
2344 if (m_fh
!= INVALID_HANDLE_VALUE
)
2345 ::CloseHandle(m_fh
);
2348 bool win_smart_device::is_open() const
2350 return (m_fh
!= INVALID_HANDLE_VALUE
);
2353 bool win_smart_device::close()
2355 if (m_fh
== INVALID_HANDLE_VALUE
)
2357 BOOL rc
= ::CloseHandle(m_fh
);
2358 m_fh
= INVALID_HANDLE_VALUE
;
2364 win_ata_device::win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
2365 : smart_device(intf
, dev_name
, "ata", req_type
),
2366 m_usr_options(false),
2369 m_id_is_cached(false),
2376 win_ata_device::~win_ata_device() throw()
2383 bool win_ata_device::open()
2385 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
2386 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2387 char drive
[2+1] = "", options
[8+1] = ""; int n1
= -1, n2
= -1;
2388 if ( sscanf(name
, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive
, &n1
, options
, &n2
) >= 1
2389 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2390 return open(sdxy_to_phydrive(drive
), -1, options
, -1);
2392 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2393 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
2395 if ( sscanf(name
, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
2396 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2397 return open(sdxy_to_phydrive(drive
), -1, options
, port
);
2399 // pd<m>,N => Physical drive <m>, RAID port N
2400 int phydrive
= -1; port
= ~0; n1
= -1; n2
= -1;
2401 if ( sscanf(name
, "pd%d%n,%u%n", &phydrive
, &n1
, &port
, &n2
) >= 1
2402 && phydrive
>= 0 && ((n1
== len
&& (int)port
< 0) || (n2
== len
&& port
< 32))) {
2403 return open(phydrive
, -1, "", (int)port
);
2405 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2406 int logdrive
= drive_letter(name
);
2407 if (logdrive
>= 0) {
2408 return open(-1, logdrive
, "", -1);
2411 return set_err(EINVAL
);
2415 bool win_ata_device::open(int phydrive
, int logdrive
, const char * options
, int port
)
2419 if (0 <= phydrive
&& phydrive
<= 255)
2420 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive
= phydrive
));
2421 else if (0 <= logdrive
&& logdrive
<= 'Z'-'A')
2422 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\%c:", 'A'+logdrive
);
2424 return set_err(ENOENT
);
2427 HANDLE h
= INVALID_HANDLE_VALUE
;
2428 if (!(*options
&& !options
[strspn(options
, "fp")])) {
2429 // Open with admin rights
2431 h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
2432 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2433 NULL
, OPEN_EXISTING
, 0, 0);
2435 if (h
== INVALID_HANDLE_VALUE
) {
2436 // Open without admin rights
2438 h
= CreateFileA(devpath
, 0,
2439 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2440 NULL
, OPEN_EXISTING
, 0, 0);
2442 if (h
== INVALID_HANDLE_VALUE
) {
2443 long err
= GetLastError();
2444 if (err
== ERROR_FILE_NOT_FOUND
)
2445 set_err(ENOENT
, "%s: not found", devpath
);
2446 else if (err
== ERROR_ACCESS_DENIED
)
2447 set_err(EACCES
, "%s: access denied", devpath
);
2449 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
2454 // Warn once if admin rights are missing
2456 static bool noadmin_warning
= false;
2457 if (!noadmin_warning
) {
2458 pout("Warning: Limited functionality due to missing admin rights\n");
2459 noadmin_warning
= true;
2463 if (ata_debugmode
> 1)
2464 pout("%s: successfully opened%s\n", devpath
, (!m_admin
? " (without admin rights)" :""));
2466 m_usr_options
= false;
2468 // Save user options
2469 m_options
= options
; m_usr_options
= true;
2472 // RAID: SMART_* and SCSI_MINIPORT
2475 // Set default options according to Windows version
2476 static const char * def_options
= ata_get_def_options();
2477 m_options
= def_options
;
2480 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2485 // 3ware RAID: Get port map
2486 GETVERSIONINPARAMS_EX vers_ex
;
2487 int devmap
= smart_get_version(h
, &vers_ex
);
2489 // 3ware RAID if vendor id present
2490 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2492 unsigned long portmap
= 0;
2493 if (port
>= 0 && devmap
>= 0) {
2494 // 3ware RAID: check vendor id
2496 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2497 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2498 vers_ex
.wIdentifier
);
2502 portmap
= vers_ex
.dwDeviceMapEx
;
2505 pout("%s: ATA driver has no SMART support\n", devpath
);
2506 if (!is_permissive()) {
2508 return set_err(ENOSYS
);
2512 m_smartver_state
= 1;
2515 // 3ware RAID: update devicemap first
2517 if (!update_3ware_devicemap_ioctl(h
)) {
2518 if ( smart_get_version(h
, &vers_ex
) >= 0
2519 && vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
2520 portmap
= vers_ex
.dwDeviceMapEx
;
2522 // Check port existence
2523 if (!(portmap
& (1L << port
))) {
2524 if (!is_permissive()) {
2526 return set_err(ENOENT
, "%s: Port %d is empty or does not exist", devpath
, port
);
2535 /////////////////////////////////////////////////////////////////////////////
2537 // Interface to ATA devices
2538 bool win_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2540 // No multi-sector support for now, see above
2541 // warning about IOCTL_ATA_PASS_THROUGH
2542 if (!ata_cmd_is_supported(in
,
2543 ata_device::supports_data_out
|
2544 ata_device::supports_output_regs
|
2545 ata_device::supports_48bit
)
2549 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2550 if ( m_is_3ware
&& m_port
< 0
2551 && in
.in_regs
.command
== ATA_SMART_CMD
2552 && in
.in_regs
.features
== ATA_SMART_DISABLE
)
2553 return set_err(ENOSYS
, "SMART DISABLE requires 3ware port number");
2555 // Determine ioctl functions valid for this ATA cmd
2556 const char * valid_options
= 0;
2558 switch (in
.in_regs
.command
) {
2559 case ATA_IDENTIFY_DEVICE
:
2560 case ATA_IDENTIFY_PACKET_DEVICE
:
2561 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2562 // and SCSI_MINIPORT_* if requested by user
2563 valid_options
= (m_usr_options
? "saimf" : "saif");
2566 case ATA_CHECK_POWER_MODE
:
2567 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2568 valid_options
= "pai3";
2572 switch (in
.in_regs
.features
) {
2573 case ATA_SMART_READ_VALUES
:
2574 case ATA_SMART_READ_THRESHOLDS
:
2575 case ATA_SMART_AUTOSAVE
:
2576 case ATA_SMART_ENABLE
:
2577 case ATA_SMART_DISABLE
:
2578 case ATA_SMART_AUTO_OFFLINE
:
2579 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2580 // and SCSI_MINIPORT_* if requested by user
2581 valid_options
= (m_usr_options
? "saimf" : "saif");
2584 case ATA_SMART_IMMEDIATE_OFFLINE
:
2585 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2586 valid_options
= (m_usr_options
|| in
.in_regs
.lba_low
!= 127/*ABORT*/ ?
2590 case ATA_SMART_READ_LOG_SECTOR
:
2591 // SMART_RCV_DRIVE_DATA does not support READ_LOG
2592 // Try SCSI_MINIPORT also to skip buggy class driver
2593 // SMART functions do not support multi sector I/O.
2595 valid_options
= (m_usr_options
? "saim3" : "aim3");
2597 valid_options
= "a";
2600 case ATA_SMART_WRITE_LOG_SECTOR
:
2601 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2602 // but SCSI_MINIPORT_* only if requested by user and single sector.
2603 valid_options
= (in
.size
== 512 && m_usr_options
? "am" : "a");
2606 case ATA_SMART_STATUS
:
2607 valid_options
= (m_usr_options
? "saimf" : "saif");
2611 // Unknown SMART command, handle below
2617 // Other ATA command, handle below
2621 if (!valid_options
) {
2622 // No special ATA command found above, select a generic pass through ioctl.
2623 if (!( in
.direction
== ata_cmd_in::no_data
2624 || (in
.direction
== ata_cmd_in::data_in
&& in
.size
== 512))
2625 || in
.in_regs
.is_48bit_cmd() )
2626 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2627 valid_options
= "a";
2629 // ATA/IDE_PASS_THROUGH
2630 valid_options
= "ai";
2634 // Restrict to IOCTL_STORAGE_*
2635 if (strchr(valid_options
, 'f'))
2636 valid_options
= "f";
2637 else if (strchr(valid_options
, 'p'))
2638 valid_options
= "p";
2640 return set_err(ENOSYS
, "Function requires admin rights");
2644 IDEREGS regs
, prev_regs
;
2646 const ata_in_regs
& lo
= in
.in_regs
;
2647 regs
.bFeaturesReg
= lo
.features
;
2648 regs
.bSectorCountReg
= lo
.sector_count
;
2649 regs
.bSectorNumberReg
= lo
.lba_low
;
2650 regs
.bCylLowReg
= lo
.lba_mid
;
2651 regs
.bCylHighReg
= lo
.lba_high
;
2652 regs
.bDriveHeadReg
= lo
.device
;
2653 regs
.bCommandReg
= lo
.command
;
2656 if (in
.in_regs
.is_48bit_cmd()) {
2657 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2658 prev_regs
.bFeaturesReg
= hi
.features
;
2659 prev_regs
.bSectorCountReg
= hi
.sector_count
;
2660 prev_regs
.bSectorNumberReg
= hi
.lba_low
;
2661 prev_regs
.bCylLowReg
= hi
.lba_mid
;
2662 prev_regs
.bCylHighReg
= hi
.lba_high
;
2663 prev_regs
.bDriveHeadReg
= hi
.device
;
2664 prev_regs
.bCommandReg
= hi
.command
;
2665 prev_regs
.bReserved
= 0;
2668 // Set data direction
2671 switch (in
.direction
) {
2672 case ata_cmd_in::no_data
:
2674 case ata_cmd_in::data_in
:
2675 datasize
= (int)in
.size
;
2676 data
= (char *)in
.buffer
;
2678 case ata_cmd_in::data_out
:
2679 datasize
= -(int)in
.size
;
2680 data
= (char *)in
.buffer
;
2683 return set_err(EINVAL
, "win_ata_device::ata_pass_through: invalid direction=%d",
2688 // Try all valid ioctls in the order specified in m_options
2689 bool powered_up
= false;
2690 bool out_regs_set
= false;
2691 bool id_is_cached
= false;
2692 const char * options
= m_options
.c_str();
2694 for (int i
= 0; ; i
++) {
2695 char opt
= options
[i
];
2698 if (in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& powered_up
) {
2699 // Power up reported by GetDevicePowerState() and no ioctl available
2700 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2701 regs
.bSectorCountReg
= 0xff;
2702 out_regs_set
= true;
2706 return set_err(ENOSYS
);
2708 if (!strchr(valid_options
, opt
))
2709 // Invalid for this command
2713 assert( datasize
== 0 || datasize
== 512
2714 || (datasize
== -512 && strchr("am", opt
))
2715 || (datasize
> 512 && opt
== 'a'));
2720 // call SMART_GET_VERSION once for each drive
2721 if (m_smartver_state
> 1) {
2722 rc
= -1; errno
= ENOSYS
;
2725 if (!m_smartver_state
) {
2726 assert(m_port
== -1);
2727 GETVERSIONINPARAMS_EX vers_ex
;
2728 if (smart_get_version(get_fh(), &vers_ex
) < 0) {
2729 if (!failuretest_permissive
) {
2730 m_smartver_state
= 2;
2731 rc
= -1; errno
= ENOSYS
;
2734 failuretest_permissive
--;
2737 // 3ware RAID if vendor id present
2738 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2741 m_smartver_state
= 1;
2743 rc
= smart_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2744 out_regs_set
= (in
.in_regs
.features
== ATA_SMART_STATUS
);
2745 id_is_cached
= (m_port
< 0); // Not cached by 3ware driver
2748 rc
= ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s
, data
, datasize
);
2749 id_is_cached
= (m_port
< 0);
2752 rc
= ata_pass_through_ioctl(get_fh(), ®s
,
2753 (in
.in_regs
.is_48bit_cmd() ? &prev_regs
: 0),
2755 out_regs_set
= true;
2758 rc
= ide_pass_through_ioctl(get_fh(), ®s
, data
, datasize
);
2759 out_regs_set
= true;
2762 if (in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
) {
2763 rc
= get_identify_from_device_property(get_fh(), (ata_identify_device
*)data
);
2764 if (rc
== 0 && m_phydrive
>= 0)
2765 get_serial_from_wmi(m_phydrive
, (ata_identify_device
*)data
);
2766 id_is_cached
= true;
2768 else if (in
.in_regs
.command
== ATA_SMART_CMD
) switch (in
.in_regs
.features
) {
2769 case ATA_SMART_READ_VALUES
:
2770 rc
= storage_predict_failure_ioctl(get_fh(), data
);
2774 case ATA_SMART_ENABLE
:
2777 case ATA_SMART_STATUS
:
2778 rc
= storage_predict_failure_ioctl(get_fh());
2780 // Good SMART status
2781 out
.out_regs
.lba_high
= 0xc2; out
.out_regs
.lba_mid
= 0x4f;
2785 out
.out_regs
.lba_high
= 0x2c; out
.out_regs
.lba_mid
= 0xf4;
2790 errno
= ENOSYS
; rc
= -1;
2793 errno
= ENOSYS
; rc
= -1;
2797 rc
= ata_via_3ware_miniport_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2798 out_regs_set
= true;
2801 assert(in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& in
.size
== 0);
2802 rc
= get_device_power_state(get_fh());
2804 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2805 // spin up the drive => simulate ATA result STANDBY.
2806 regs
.bSectorCountReg
= 0x00;
2807 out_regs_set
= true;
2810 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2811 // only if it is selected by the device driver => try a passthrough ioctl to get the
2812 // actual mode, if none available simulate ACTIVE/IDLE.
2814 rc
= -1; errno
= ENOSYS
;
2820 // Working ioctl found
2823 if (errno
!= ENOSYS
)
2824 // Abort on I/O error
2825 return set_err(errno
);
2827 out_regs_set
= false;
2828 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2831 // Return IDEREGS if set
2833 ata_out_regs
& lo
= out
.out_regs
;
2834 lo
.error
= regs
.bFeaturesReg
;
2835 lo
.sector_count
= regs
.bSectorCountReg
;
2836 lo
.lba_low
= regs
.bSectorNumberReg
;
2837 lo
.lba_mid
= regs
.bCylLowReg
;
2838 lo
.lba_high
= regs
.bCylHighReg
;
2839 lo
.device
= regs
.bDriveHeadReg
;
2840 lo
.status
= regs
.bCommandReg
;
2841 if (in
.in_regs
.is_48bit_cmd()) {
2842 ata_out_regs
& hi
= out
.out_regs
.prev
;
2843 hi
.sector_count
= prev_regs
.bSectorCountReg
;
2844 hi
.lba_low
= prev_regs
.bSectorNumberReg
;
2845 hi
.lba_mid
= prev_regs
.bCylLowReg
;
2846 hi
.lba_high
= prev_regs
.bCylHighReg
;
2850 if ( in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
2851 || in
.in_regs
.command
== ATA_IDENTIFY_PACKET_DEVICE
)
2852 // Update ata_identify_is_cached() result according to ioctl used.
2853 m_id_is_cached
= id_is_cached
;
2858 // Return true if OS caches the ATA identify sector
2859 bool win_ata_device::ata_identify_is_cached() const
2861 return m_id_is_cached
;
2865 //////////////////////////////////////////////////////////////////////
2868 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
)
2870 // Get driver info to check CSMI support
2871 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf
;
2872 memset(&driver_info_buf
, 0, sizeof(driver_info_buf
));
2873 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO
, &driver_info_buf
.IoctlHeader
, sizeof(driver_info_buf
)))
2876 if (scsi_debugmode
> 1) {
2877 const CSMI_SAS_DRIVER_INFO
& driver_info
= driver_info_buf
.Information
;
2878 pout("CSMI_SAS_DRIVER_INFO:\n");
2879 pout(" Name: \"%.81s\"\n", driver_info
.szName
);
2880 pout(" Description: \"%.81s\"\n", driver_info
.szDescription
);
2881 pout(" Revision: %d.%d\n", driver_info
.usMajorRevision
, driver_info
.usMinorRevision
);
2885 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf
;
2886 memset(&phy_info_buf
, 0, sizeof(phy_info_buf
));
2887 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO
, &phy_info_buf
.IoctlHeader
, sizeof(phy_info_buf
)))
2890 phy_info
= phy_info_buf
.Information
;
2891 if (phy_info
.bNumberOfPhys
> sizeof(phy_info
.Phy
)/sizeof(phy_info
.Phy
[0]))
2892 return set_err(EIO
, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info
.bNumberOfPhys
);
2894 if (scsi_debugmode
> 1) {
2895 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info
.bNumberOfPhys
);
2896 for (int i
= 0; i
< phy_info
.bNumberOfPhys
; i
++) {
2897 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
2898 const CSMI_SAS_IDENTIFY
& id
= pe
.Identify
, & at
= pe
.Attached
;
2899 pout("Phy[%d] Port: 0x%02x\n", i
, pe
.bPortIdentifier
);
2900 pout(" Type: 0x%02x, 0x%02x\n", id
.bDeviceType
, at
.bDeviceType
);
2901 pout(" InitProto: 0x%02x, 0x%02x\n", id
.bInitiatorPortProtocol
, at
.bInitiatorPortProtocol
);
2902 pout(" TargetProto: 0x%02x, 0x%02x\n", id
.bTargetPortProtocol
, at
.bTargetPortProtocol
);
2903 pout(" PhyIdent: 0x%02x, 0x%02x\n", id
.bPhyIdentifier
, at
.bPhyIdentifier
);
2904 const unsigned char * b
= id
.bSASAddress
;
2905 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
2906 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2908 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2909 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
2916 bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO
& phy_info
, unsigned phy_no
)
2918 // Check Phy presence
2919 if (phy_no
>= phy_info
.bNumberOfPhys
)
2920 return set_err(ENOENT
, "Port %u does not exist (#ports: %d)", phy_no
,
2921 phy_info
.bNumberOfPhys
);
2923 const CSMI_SAS_PHY_ENTITY
& phy_ent
= phy_info
.Phy
[phy_no
];
2924 if (phy_ent
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
2925 return set_err(ENOENT
, "No device on port %u", phy_no
);
2927 switch (phy_ent
.Attached
.bTargetPortProtocol
) {
2928 case CSMI_SAS_PROTOCOL_SATA
:
2929 case CSMI_SAS_PROTOCOL_STP
:
2932 return set_err(ENOENT
, "No SATA device on port %u (protocol: %u)",
2933 phy_no
, phy_ent
.Attached
.bTargetPortProtocol
);
2939 bool csmi_device::select_phy(unsigned phy_no
)
2941 CSMI_SAS_PHY_INFO phy_info
;
2942 if (!get_phy_info(phy_info
))
2946 if (!check_phy(phy_info
, phy_no
))
2949 m_phy_ent
= phy_info
.Phy
[phy_no
];
2954 bool csmi_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2956 if (!ata_cmd_is_supported(in
,
2957 ata_device::supports_data_out
|
2958 ata_device::supports_output_regs
|
2959 ata_device::supports_multi_sector
|
2960 ata_device::supports_48bit
,
2965 // Create buffer with appropriate size
2966 raw_buffer
pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER
) + in
.size
);
2967 CSMI_SAS_STP_PASSTHRU_BUFFER
* pthru_buf
= (CSMI_SAS_STP_PASSTHRU_BUFFER
*)pthru_raw_buf
.data();
2969 // Set addresses from Phy info
2970 CSMI_SAS_STP_PASSTHRU
& pthru
= pthru_buf
->Parameters
;
2971 const CSMI_SAS_PHY_ENTITY
& phy_ent
= get_phy_ent();
2972 pthru
.bPhyIdentifier
= phy_ent
.Identify
.bPhyIdentifier
;
2973 pthru
.bPortIdentifier
= phy_ent
.bPortIdentifier
;
2974 memcpy(pthru
.bDestinationSASAddress
, phy_ent
.Attached
.bSASAddress
,
2975 sizeof(pthru
.bDestinationSASAddress
));
2976 pthru
.bConnectionRate
= CSMI_SAS_LINK_RATE_NEGOTIATED
;
2978 // Set transfer mode
2979 switch (in
.direction
) {
2980 case ata_cmd_in::no_data
:
2981 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_UNSPECIFIED
;
2983 case ata_cmd_in::data_in
:
2984 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_READ
;
2985 pthru
.uDataLength
= in
.size
;
2987 case ata_cmd_in::data_out
:
2988 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_WRITE
;
2989 pthru
.uDataLength
= in
.size
;
2990 memcpy(pthru_buf
->bDataBuffer
, in
.buffer
, in
.size
);
2993 return set_err(EINVAL
, "csmi_ata_device::ata_pass_through: invalid direction=%d",
2997 // Set host-to-device FIS
2999 unsigned char * fis
= pthru
.bCommandFIS
;
3000 const ata_in_regs
& lo
= in
.in_regs
;
3001 const ata_in_regs
& hi
= in
.in_regs
.prev
;
3002 fis
[ 0] = 0x27; // Type: host-to-device FIS
3003 fis
[ 1] = 0x80; // Bit7: Update command register
3004 fis
[ 2] = lo
.command
;
3005 fis
[ 3] = lo
.features
;
3006 fis
[ 4] = lo
.lba_low
;
3007 fis
[ 5] = lo
.lba_mid
;
3008 fis
[ 6] = lo
.lba_high
;
3009 fis
[ 7] = lo
.device
;
3010 fis
[ 8] = hi
.lba_low
;
3011 fis
[ 9] = hi
.lba_mid
;
3012 fis
[10] = hi
.lba_high
;
3013 fis
[11] = hi
.features
;
3014 fis
[12] = lo
.sector_count
;
3015 fis
[13] = hi
.sector_count
;
3019 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU
, &pthru_buf
->IoctlHeader
, pthru_raw_buf
.size())) {
3023 // Get device-to-host FIS
3025 const unsigned char * fis
= pthru_buf
->Status
.bStatusFIS
;
3026 ata_out_regs
& lo
= out
.out_regs
;
3027 lo
.status
= fis
[ 2];
3029 lo
.lba_low
= fis
[ 4];
3030 lo
.lba_mid
= fis
[ 5];
3031 lo
.lba_high
= fis
[ 6];
3032 lo
.device
= fis
[ 7];
3033 lo
.sector_count
= fis
[12];
3034 if (in
.in_regs
.is_48bit_cmd()) {
3035 ata_out_regs
& hi
= out
.out_regs
.prev
;
3036 hi
.lba_low
= fis
[ 8];
3037 hi
.lba_mid
= fis
[ 9];
3038 hi
.lba_high
= fis
[10];
3039 hi
.sector_count
= fis
[13];
3044 if (in
.direction
== ata_cmd_in::data_in
)
3045 // TODO: Check ptru_buf->Status.uDataBytes
3046 memcpy(in
.buffer
, pthru_buf
->bDataBuffer
, in
.size
);
3052 //////////////////////////////////////////////////////////////////////
3055 win_csmi_device::win_csmi_device(smart_interface
* intf
, const char * dev_name
,
3056 const char * req_type
)
3057 : smart_device(intf
, dev_name
, "ata", req_type
),
3058 m_fh(INVALID_HANDLE_VALUE
), m_phy_no(0)
3062 win_csmi_device::~win_csmi_device() throw()
3064 if (m_fh
!= INVALID_HANDLE_VALUE
)
3068 bool win_csmi_device::is_open() const
3070 return (m_fh
!= INVALID_HANDLE_VALUE
);
3073 bool win_csmi_device::close()
3075 if (m_fh
== INVALID_HANDLE_VALUE
)
3077 BOOL rc
= CloseHandle(m_fh
);
3078 m_fh
= INVALID_HANDLE_VALUE
;
3083 bool win_csmi_device::open_scsi()
3086 unsigned contr_no
= ~0, phy_no
= ~0; int nc
= -1;
3087 const char * name
= skipdev(get_dev_name());
3088 if (!( sscanf(name
, "csmi%u,%u%n", &contr_no
, &phy_no
, &nc
) >= 0
3089 && nc
== (int)strlen(name
) && contr_no
<= 9 && phy_no
< 32) )
3090 return set_err(EINVAL
);
3092 // Open controller handle
3094 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\Scsi%u:", contr_no
);
3096 HANDLE h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
3097 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3098 (SECURITY_ATTRIBUTES
*)0, OPEN_EXISTING
, 0, 0);
3100 if (h
== INVALID_HANDLE_VALUE
) {
3101 long err
= GetLastError();
3102 if (err
== ERROR_FILE_NOT_FOUND
)
3103 set_err(ENOENT
, "%s: not found", devpath
);
3104 else if (err
== ERROR_ACCESS_DENIED
)
3105 set_err(EACCES
, "%s: access denied", devpath
);
3107 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
3111 if (scsi_debugmode
> 1)
3112 pout(" %s: successfully opened\n", devpath
);
3120 bool win_csmi_device::open()
3125 // Get Phy info for this drive
3126 if (!select_phy(m_phy_no
)) {
3135 bool win_csmi_device::csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
3136 unsigned csmi_bufsiz
)
3138 // Determine signature
3141 case CC_CSMI_SAS_GET_DRIVER_INFO
:
3142 sig
= CSMI_ALL_SIGNATURE
; break;
3143 case CC_CSMI_SAS_GET_PHY_INFO
:
3144 case CC_CSMI_SAS_STP_PASSTHRU
:
3145 sig
= CSMI_SAS_SIGNATURE
; break;
3147 return set_err(ENOSYS
, "Unknown CSMI code=%u", code
);
3151 csmi_buffer
->HeaderLength
= sizeof(IOCTL_HEADER
);
3152 strncpy((char *)csmi_buffer
->Signature
, sig
, sizeof(csmi_buffer
->Signature
));
3153 csmi_buffer
->Timeout
= CSMI_SAS_TIMEOUT
;
3154 csmi_buffer
->ControlCode
= code
;
3155 csmi_buffer
->ReturnCode
= 0;
3156 csmi_buffer
->Length
= csmi_bufsiz
- sizeof(IOCTL_HEADER
);
3160 if (!DeviceIoControl(m_fh
, IOCTL_SCSI_MINIPORT
,
3161 csmi_buffer
, csmi_bufsiz
, csmi_buffer
, csmi_bufsiz
, &num_out
, (OVERLAPPED
*)0)) {
3162 long err
= GetLastError();
3164 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code
, err
);
3165 if ( err
== ERROR_INVALID_FUNCTION
3166 || err
== ERROR_NOT_SUPPORTED
3167 || err
== ERROR_DEV_NOT_EXIST
)
3168 return set_err(ENOSYS
, "CSMI is not supported (Error=%ld)", err
);
3170 return set_err(EIO
, "CSMI(%u) failed with Error=%ld", code
, err
);
3174 if (csmi_buffer
->ReturnCode
) {
3175 if (scsi_debugmode
) {
3176 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3177 code
, (unsigned)csmi_buffer
->ReturnCode
);
3179 return set_err(EIO
, "CSMI(%u) failed with ReturnCode=%u", code
, (unsigned)csmi_buffer
->ReturnCode
);
3182 if (scsi_debugmode
> 1)
3183 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code
, (unsigned)num_out
);
3189 /////////////////////////////////////////////////////////////////////////////
3190 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3191 // Only supported in NT and later
3192 /////////////////////////////////////////////////////////////////////////////
3194 win_scsi_device::win_scsi_device(smart_interface
* intf
,
3195 const char * dev_name
, const char * req_type
)
3196 : smart_device(intf
, dev_name
, "scsi", req_type
)
3200 bool win_scsi_device::open()
3202 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
3203 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3204 char drive
[2+1] = ""; int sub_addr
= -1; int n1
= -1; int n2
= -1;
3205 if ( sscanf(name
, "sd%2[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
3206 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
3207 return open(sdxy_to_phydrive(drive
), -1, -1, sub_addr
);
3209 // pd<m>,N => Physical drive <m>, RAID port N
3210 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
3211 if ( sscanf(name
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
3212 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
3213 return open(pd_num
, -1, -1, sub_addr
);
3215 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3216 int logdrive
= drive_letter(name
);
3217 if (logdrive
>= 0) {
3218 return open(-1, logdrive
, -1, -1);
3220 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3221 int tape_num
= -1; n1
= -1;
3222 if (sscanf(name
, "st%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3223 return open(-1, -1, tape_num
, -1);
3225 tape_num
= -1; n1
= -1;
3226 if (sscanf(name
, "nst%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3227 return open(-1, -1, tape_num
, -1);
3229 // tape<m> => tape drive <m>
3230 tape_num
= -1; n1
= -1;
3231 if (sscanf(name
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3232 return open(-1, -1, tape_num
, -1);
3235 return set_err(EINVAL
);
3238 bool win_scsi_device::open(int pd_num
, int ld_num
, int tape_num
, int /*sub_addr*/)
3241 b
[sizeof(b
) - 1] = '\0';
3243 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
3244 else if (ld_num
>= 0)
3245 snprintf(b
, sizeof(b
) - 1, "\\\\.\\%c:", 'A' + ld_num
);
3246 else if (tape_num
>= 0)
3247 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
3254 HANDLE h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
3255 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
3256 OPEN_EXISTING
, 0, 0);
3257 if (h
== INVALID_HANDLE_VALUE
) {
3258 set_err(ENODEV
, "%s: Open failed, Error=%u", b
, (unsigned)GetLastError());
3267 SCSI_PASS_THROUGH_DIRECT spt
;
3269 UCHAR ucSenseBuf
[64];
3270 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
3273 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3274 // Used if DataTransferLength not supported by *_DIRECT.
3275 static long scsi_pass_through_indirect(HANDLE h
,
3276 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
* sbd
)
3278 struct SCSI_PASS_THROUGH_WITH_BUFFERS
{
3279 SCSI_PASS_THROUGH spt
;
3281 UCHAR ucSenseBuf
[sizeof(sbd
->ucSenseBuf
)];
3282 UCHAR ucDataBuf
[512];
3285 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
3286 memset(&sb
, 0, sizeof(sb
));
3288 // DATA_OUT not implemented yet
3289 if (!( sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
3290 && sbd
->spt
.DataTransferLength
<= sizeof(sb
.ucDataBuf
)))
3291 return ERROR_INVALID_PARAMETER
;
3293 sb
.spt
.Length
= sizeof(sb
.spt
);
3294 sb
.spt
.CdbLength
= sbd
->spt
.CdbLength
;
3295 memcpy(sb
.spt
.Cdb
, sbd
->spt
.Cdb
, sizeof(sb
.spt
.Cdb
));
3296 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3297 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
3298 sb
.spt
.DataIn
= sbd
->spt
.DataIn
;
3299 sb
.spt
.DataTransferLength
= sbd
->spt
.DataTransferLength
;
3300 sb
.spt
.DataBufferOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
3301 sb
.spt
.TimeOutValue
= sbd
->spt
.TimeOutValue
;
3304 if (!DeviceIoControl(h
, IOCTL_SCSI_PASS_THROUGH
,
3305 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3306 return GetLastError();
3308 sbd
->spt
.ScsiStatus
= sb
.spt
.ScsiStatus
;
3309 if (sb
.spt
.ScsiStatus
& SCSI_STATUS_CHECK_CONDITION
)
3310 memcpy(sbd
->ucSenseBuf
, sb
.ucSenseBuf
, sizeof(sbd
->ucSenseBuf
));
3312 sbd
->spt
.DataTransferLength
= sb
.spt
.DataTransferLength
;
3313 if (sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
&& sb
.spt
.DataTransferLength
> 0)
3314 memcpy(sbd
->spt
.DataBuffer
, sb
.ucDataBuf
, sb
.spt
.DataTransferLength
);
3319 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3320 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io
* iop
)
3322 int report
= scsi_debugmode
; // TODO
3326 const unsigned char * ucp
= iop
->cmnd
;
3329 const int sz
= (int)sizeof(buff
);
3331 np
= scsi_get_opcode_name(ucp
[0]);
3332 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3333 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3334 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3336 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3337 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3339 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3340 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3341 (trunc
? " [only first 256 bytes shown]" : ""));
3342 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3345 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3349 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3350 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3351 set_err(EINVAL
, "cmnd_len too large");
3355 memset(&sb
, 0, sizeof(sb
));
3356 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3357 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3358 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3359 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3360 sb
.spt
.SenseInfoOffset
=
3361 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3362 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3365 switch (iop
->dxfer_dir
) {
3367 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3369 case DXFER_FROM_DEVICE
:
3370 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3371 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3372 sb
.spt
.DataBuffer
= iop
->dxferp
;
3373 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3374 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3375 if (sb
.spt
.DataTransferLength
== 1)
3378 case DXFER_TO_DEVICE
:
3379 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3380 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3381 sb
.spt
.DataBuffer
= iop
->dxferp
;
3384 set_err(EINVAL
, "bad dxfer_dir");
3391 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3392 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3393 err
= GetLastError();
3396 err
= scsi_pass_through_indirect(get_fh(), &sb
);
3399 return set_err((err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
),
3400 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3401 (direct
? "_DIRECT" : ""), err
);
3403 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3404 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3405 int slen
= sb
.ucSenseBuf
[7] + 8;
3407 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3408 slen
= sizeof(sb
.ucSenseBuf
);
3409 if (slen
> (int)iop
->max_sense_len
)
3410 slen
= iop
->max_sense_len
;
3411 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3412 iop
->resp_sense_len
= slen
;
3415 pout(" >>> Sense buffer, len=%d:\n", slen
);
3416 dStrHex(iop
->sensep
, slen
, 1);
3418 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3419 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3420 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3421 iop
->sensep
[2], iop
->sensep
[3]);
3423 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3424 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3425 iop
->sensep
[12], iop
->sensep
[13]);
3428 iop
->resp_sense_len
= 0;
3430 if ((iop
->dxfer_len
> 0) && (sb
.spt
.DataTransferLength
> 0))
3431 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3435 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3436 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3437 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
3438 (trunc
? " [only first 256 bytes shown]" : ""));
3439 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3444 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3445 static long scsi_pass_through_direct(HANDLE fd
, UCHAR targetid
, struct scsi_cmnd_io
* iop
)
3447 int report
= scsi_debugmode
; // TODO
3451 const unsigned char * ucp
= iop
->cmnd
;
3454 const int sz
= (int)sizeof(buff
);
3456 np
= scsi_get_opcode_name(ucp
[0]);
3457 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3458 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3459 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3461 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3462 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3464 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3465 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3466 (trunc
? " [only first 256 bytes shown]" : ""));
3467 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3470 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3474 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3475 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3479 memset(&sb
, 0, sizeof(sb
));
3480 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3481 //sb.spt.PathId = 0;
3482 sb
.spt
.TargetId
= targetid
;
3484 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3485 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3486 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3487 sb
.spt
.SenseInfoOffset
=
3488 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3489 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3492 switch (iop
->dxfer_dir
) {
3494 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3496 case DXFER_FROM_DEVICE
:
3497 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3498 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3499 sb
.spt
.DataBuffer
= iop
->dxferp
;
3500 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3501 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3502 if (sb
.spt
.DataTransferLength
== 1)
3505 case DXFER_TO_DEVICE
:
3506 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3507 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3508 sb
.spt
.DataBuffer
= iop
->dxferp
;
3517 if (!DeviceIoControl(fd
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3518 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3519 err
= GetLastError();
3522 err
= scsi_pass_through_indirect(fd
, &sb
);
3529 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3530 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3531 int slen
= sb
.ucSenseBuf
[7] + 8;
3533 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3534 slen
= sizeof(sb
.ucSenseBuf
);
3535 if (slen
> (int)iop
->max_sense_len
)
3536 slen
= iop
->max_sense_len
;
3537 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3538 iop
->resp_sense_len
= slen
;
3541 pout(" >>> Sense buffer, len=%d:\n", slen
);
3542 dStrHex(iop
->sensep
, slen
, 1);
3544 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3545 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3546 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3547 iop
->sensep
[2], iop
->sensep
[3]);
3549 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3550 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3551 iop
->sensep
[12], iop
->sensep
[13]);
3554 iop
->resp_sense_len
= 0;
3556 if ((iop
->dxfer_len
> 0) && (sb
.spt
.DataTransferLength
> 0))
3557 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3561 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3562 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3563 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
3564 (trunc
? " [only first 256 bytes shown]" : ""));
3565 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3571 // Areca RAID Controller(SAS Device)
3572 win_areca_scsi_device::win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3573 : smart_device(intf
, dev_name
, "areca", "areca")
3575 set_fh(INVALID_HANDLE_VALUE
);
3576 set_disknum(disknum
);
3578 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3581 bool win_areca_scsi_device::open()
3589 hFh
= CreateFile( get_dev_name(),
3590 GENERIC_READ
|GENERIC_WRITE
,
3591 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3596 if(hFh
== INVALID_HANDLE_VALUE
)
3605 smart_device
* win_areca_scsi_device::autodetect_open()
3610 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3612 int ioctlreturn
= 0;
3614 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3615 if ( ioctlreturn
|| iop
->scsi_status
)
3617 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3618 if ( ioctlreturn
|| iop
->scsi_status
)
3628 bool win_areca_scsi_device::arcmsr_lock()
3630 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3634 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3635 return set_err(EINVAL
, "unable to parse device name");
3637 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3638 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3639 if ( m_mutex
== NULL
)
3641 return set_err(EIO
, "CreateMutex failed");
3644 // atomic access to driver
3645 WaitForSingleObject(m_mutex
, INFINITE
);
3651 bool win_areca_scsi_device::arcmsr_unlock()
3653 if( m_mutex
!= NULL
)
3655 ReleaseMutex(m_mutex
);
3656 CloseHandle(m_mutex
);
3663 // Areca RAID Controller(SATA Disk)
3664 win_areca_ata_device::win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3665 : smart_device(intf
, dev_name
, "areca", "areca")
3667 set_fh(INVALID_HANDLE_VALUE
);
3668 set_disknum(disknum
);
3670 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3673 bool win_areca_ata_device::open()
3681 hFh
= CreateFile( get_dev_name(),
3682 GENERIC_READ
|GENERIC_WRITE
,
3683 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3688 if(hFh
== INVALID_HANDLE_VALUE
)
3697 smart_device
* win_areca_ata_device::autodetect_open()
3701 // autodetect device type
3702 is_ata
= arcmsr_get_dev_type();
3716 smart_device_auto_ptr
newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
3719 newdev
->open(); // TODO: Can possibly pass open fd
3721 return newdev
.release();
3724 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3726 int ioctlreturn
= 0;
3728 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3729 if ( ioctlreturn
|| iop
->scsi_status
)
3731 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3732 if ( ioctlreturn
|| iop
->scsi_status
)
3742 bool win_areca_ata_device::arcmsr_lock()
3744 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3748 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3749 return set_err(EINVAL
, "unable to parse device name");
3751 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3752 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3753 if ( m_mutex
== NULL
)
3755 return set_err(EIO
, "CreateMutex failed");
3758 // atomic access to driver
3759 WaitForSingleObject(m_mutex
, INFINITE
);
3765 bool win_areca_ata_device::arcmsr_unlock()
3767 if( m_mutex
!= NULL
)
3769 ReleaseMutex(m_mutex
);
3770 CloseHandle(m_mutex
);
3777 //////////////////////////////////////////////////////////////////////////////////////////////////
3782 /////////////////////////////////////////////////////////////////////////////
3784 // Initialize platform interface and register with smi()
3785 void smart_interface::init()
3788 // Remove "." from DLL search path if supported
3789 // to prevent DLL preloading attacks
3790 BOOL (WINAPI
* SetDllDirectoryA_p
)(LPCSTR
) = (BOOL (WINAPI
*)(LPCSTR
))
3791 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
3792 if (SetDllDirectoryA_p
)
3793 SetDllDirectoryA_p("");
3796 static os_win32::win_smart_interface the_win_interface
;
3797 smart_interface::set(&the_win_interface
);
3803 // Get exe directory
3804 // (prototype in utiliy.h)
3805 std::string
get_exe_dir()
3807 char path
[MAX_PATH
];
3808 // Get path of this exe
3809 if (!GetModuleFileNameA(GetModuleHandleA(0), path
, sizeof(path
)))
3810 throw std::runtime_error("GetModuleFileName() failed");
3811 // Replace backslash by slash
3813 for (int i
= 0; path
[i
]; i
++)
3814 if (path
[i
] == '\\') {
3815 path
[i
] = '/'; sl
= i
;