4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2004-15 Christian Franke
8 * Original AACRaid code:
9 * Copyright (C) 2015 Nidhi Malhotra <nidhi.malhotra@pmcs.com>
11 * Original Areca code:
12 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
19 * You should have received a copy of the GNU General Public License
20 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
26 #define _WIN32_WINNT WINVER
32 #include "smartctl.h" // TODO: Do not use smartctl only variables here
34 #include "dev_interface.h"
35 #include "dev_ata_cmd_set.h"
36 #include "dev_areca.h"
38 #include "os_win32/wmiquery.h"
46 #define assert(x) /* */
49 #include <stddef.h> // offsetof()
50 #include <io.h> // access()
52 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h>
53 #define WIN32_LEAN_AND_MEAN
57 // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32
58 // (Missing: FILE_DEVICE_SCSI)
63 #elif HAVE_DDK_NTDDDISK_H
64 // older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
65 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
66 #include <ddk/ntdddisk.h>
67 #include <ddk/ntddscsi.h>
68 #include <ddk/ntddstor.h>
70 // MSVC10, older MinGW
71 // (Missing: IOCTL_SCSI_MINIPORT_*)
77 // csmisas.h and aacraid.h require _WIN32 but w32api-headers no longer define it on Cygwin
78 // (aacraid.h also checks for _WIN64 which is also set on Cygwin x64)
88 // Silence -Wunused-local-typedefs warning from g++ >= 4.8
90 #define ATTR_UNUSED __attribute__((unused))
92 #define ATTR_UNUSED /**/
95 // Macro to check constants at compile time using a dummy typedef
96 #define ASSERT_CONST(c, n) \
97 typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED
98 #define ASSERT_SIZEOF(t, n) \
99 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
102 #define SELECT_WIN_32_64(x32, x64) (x32)
104 #define SELECT_WIN_32_64(x32, x64) (x64)
107 // Cygwin does no longer provide strn?icmp() compatibility macros
108 // MSVCRT does not provide strn?casecmp()
109 #if defined(__CYGWIN__) && !defined(stricmp)
110 #define stricmp strcasecmp
111 #define strnicmp strncasecmp
114 const char * os_win32_cpp_cvsid
= "$Id: os_win32.cpp 4156 2015-10-18 12:20:40Z samm2 $";
116 /////////////////////////////////////////////////////////////////////////////
117 // Windows I/O-controls, some declarations are missing in the include files
121 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
123 ASSERT_CONST(SMART_GET_VERSION
, 0x074080);
124 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND
, 0x07c084);
125 ASSERT_CONST(SMART_RCV_DRIVE_DATA
, 0x07c088);
126 ASSERT_SIZEOF(GETVERSIONINPARAMS
, 24);
127 ASSERT_SIZEOF(SENDCMDINPARAMS
, 32+1);
128 ASSERT_SIZEOF(SENDCMDOUTPARAMS
, 16+1);
131 // IDE PASS THROUGH (2000, XP, undocumented)
133 #ifndef IOCTL_IDE_PASS_THROUGH
135 #define IOCTL_IDE_PASS_THROUGH \
136 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
138 #endif // IOCTL_IDE_PASS_THROUGH
144 ULONG DataBufferSize
;
150 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH
, 0x04d028);
151 ASSERT_SIZEOF(ATA_PASS_THROUGH
, 12+1);
154 // ATA PASS THROUGH (Win2003, XP SP2)
156 #ifndef IOCTL_ATA_PASS_THROUGH
158 #define IOCTL_ATA_PASS_THROUGH \
159 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
161 typedef struct _ATA_PASS_THROUGH_EX
{
167 UCHAR ReservedAsUchar
;
168 ULONG DataTransferLength
;
170 ULONG ReservedAsUlong
;
171 ULONG_PTR DataBufferOffset
;
172 UCHAR PreviousTaskFile
[8];
173 UCHAR CurrentTaskFile
[8];
174 } ATA_PASS_THROUGH_EX
;
176 #define ATA_FLAGS_DRDY_REQUIRED 0x01
177 #define ATA_FLAGS_DATA_IN 0x02
178 #define ATA_FLAGS_DATA_OUT 0x04
179 #define ATA_FLAGS_48BIT_COMMAND 0x08
180 #define ATA_FLAGS_USE_DMA 0x10
181 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista
183 #endif // IOCTL_ATA_PASS_THROUGH
185 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH
, 0x04d02c);
186 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX
, SELECT_WIN_32_64(40, 48));
189 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
191 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH
, 0x04d004);
192 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT
, 0x04d014);
193 ASSERT_SIZEOF(SCSI_PASS_THROUGH
, SELECT_WIN_32_64(44, 56));
194 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT
, SELECT_WIN_32_64(44, 56));
197 // SMART IOCTL via SCSI MINIPORT ioctl
199 #ifndef FILE_DEVICE_SCSI
200 #define FILE_DEVICE_SCSI 0x001b
203 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION
205 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)
206 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
207 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)
208 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)
209 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)
210 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)
211 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)
212 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
213 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)
214 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)
215 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
216 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)
217 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)
219 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
221 ASSERT_CONST(IOCTL_SCSI_MINIPORT
, 0x04d008);
222 ASSERT_SIZEOF(SRB_IO_CONTROL
, 28);
225 // IOCTL_STORAGE_QUERY_PROPERTY
227 #ifndef IOCTL_STORAGE_QUERY_PROPERTY
229 #define IOCTL_STORAGE_QUERY_PROPERTY \
230 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
232 typedef struct _STORAGE_DEVICE_DESCRIPTOR
{
236 UCHAR DeviceTypeModifier
;
237 BOOLEAN RemovableMedia
;
238 BOOLEAN CommandQueueing
;
239 ULONG VendorIdOffset
;
240 ULONG ProductIdOffset
;
241 ULONG ProductRevisionOffset
;
242 ULONG SerialNumberOffset
;
243 STORAGE_BUS_TYPE BusType
;
244 ULONG RawPropertiesLength
;
245 UCHAR RawDeviceProperties
[1];
246 } STORAGE_DEVICE_DESCRIPTOR
;
248 typedef enum _STORAGE_QUERY_TYPE
{
249 PropertyStandardQuery
= 0,
252 PropertyQueryMaxDefined
253 } STORAGE_QUERY_TYPE
;
255 typedef enum _STORAGE_PROPERTY_ID
{
256 StorageDeviceProperty
= 0,
257 StorageAdapterProperty
,
258 StorageDeviceIdProperty
,
259 StorageDeviceUniqueIdProperty
,
260 StorageDeviceWriteCacheProperty
,
261 StorageMiniportProperty
,
262 StorageAccessAlignmentProperty
263 } STORAGE_PROPERTY_ID
;
265 typedef struct _STORAGE_PROPERTY_QUERY
{
266 STORAGE_PROPERTY_ID PropertyId
;
267 STORAGE_QUERY_TYPE QueryType
;
268 UCHAR AdditionalParameters
[1];
269 } STORAGE_PROPERTY_QUERY
;
271 #endif // IOCTL_STORAGE_QUERY_PROPERTY
273 ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY
, 0x002d1400);
274 ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR
, 36+1+3);
275 ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY
, 8+1+3);
278 // IOCTL_STORAGE_PREDICT_FAILURE
280 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE
, 0x002d1100);
281 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE
, 4+512);
284 // 3ware specific versions of SMART ioctl structs
286 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters
290 typedef struct _GETVERSIONINPARAMS_EX
{
296 DWORD dwDeviceMapEx
; // 3ware specific: RAID drive bit map
297 WORD wIdentifier
; // Vendor specific identifier
298 WORD wControllerId
; // 3ware specific: Controller ID (0,1,...)
300 } GETVERSIONINPARAMS_EX
;
302 typedef struct _SENDCMDINPARAMS_EX
{
306 BYTE bPortNumber
; // 3ware specific: port number
307 WORD wIdentifier
; // Vendor specific identifier
310 } SENDCMDINPARAMS_EX
;
314 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX
, sizeof(GETVERSIONINPARAMS
));
315 ASSERT_SIZEOF(SENDCMDINPARAMS_EX
, sizeof(SENDCMDINPARAMS
));
320 ASSERT_SIZEOF(IOCTL_HEADER
, sizeof(SRB_IO_CONTROL
));
321 ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER
, 204);
322 ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER
, 2080);
323 ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER
, 168);
327 ASSERT_SIZEOF(SCSI_REQUEST_BLOCK
, SELECT_WIN_32_64(64, 88));
331 /////////////////////////////////////////////////////////////////////////////
333 namespace os_win32
{ // no need to publish anything, name provided for Doxygen
336 #pragma warning(disable:4250)
339 class win_smart_device
340 : virtual public /*implements*/ smart_device
344 : smart_device(never_called
),
345 m_fh(INVALID_HANDLE_VALUE
)
348 virtual ~win_smart_device() throw();
350 virtual bool is_open() const;
352 virtual bool close();
355 /// Set handle for open() in derived classes.
356 void set_fh(HANDLE fh
)
359 /// Return handle for derived classes.
360 HANDLE
get_fh() const
364 HANDLE m_fh
; ///< File handle
368 /////////////////////////////////////////////////////////////////////////////
371 : public /*implements*/ ata_device
,
372 public /*extends*/ win_smart_device
375 win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
377 virtual ~win_ata_device() throw();
381 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
383 virtual bool ata_identify_is_cached() const;
386 bool open(int phydrive
, int logdrive
, const char * options
, int port
);
388 std::string m_options
;
389 bool m_usr_options
; // options set by user?
390 bool m_admin
; // open with admin access?
391 int m_phydrive
; // PhysicalDriveN or -1
392 bool m_id_is_cached
; // ata_identify_is_cached() return value.
393 bool m_is_3ware
; // LSI/3ware controller detected?
394 int m_port
; // LSI/3ware port
395 int m_smartver_state
;
399 /////////////////////////////////////////////////////////////////////////////
401 class win_scsi_device
402 : public /*implements*/ scsi_device
,
403 virtual public /*extends*/ win_smart_device
406 win_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
410 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
413 bool open(int pd_num
, int ld_num
, int tape_num
, int sub_addr
);
417 /////////////////////////////////////////////////////////////////////////////
420 : virtual public /*extends*/ smart_device
423 /// Get bitmask of used ports
424 unsigned get_ports_used();
428 : smart_device(never_called
)
429 { memset(&m_phy_ent
, 0, sizeof(m_phy_ent
)); }
432 bool get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
);
434 /// Select physical drive
435 bool select_port(int port
);
437 /// Get info for selected physical drive
438 const CSMI_SAS_PHY_ENTITY
& get_phy_ent() const
439 { return m_phy_ent
; }
441 /// Call platform-specific CSMI ioctl
442 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
443 unsigned csmi_bufsiz
) = 0;
446 CSMI_SAS_PHY_ENTITY m_phy_ent
; ///< CSMI info for this phy
450 class csmi_ata_device
451 : virtual public /*extends*/ csmi_device
,
452 virtual public /*implements*/ ata_device
455 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
459 : smart_device(never_called
) { }
463 //////////////////////////////////////////////////////////////////////
465 class win_csmi_device
466 : public /*implements*/ csmi_ata_device
469 win_csmi_device(smart_interface
* intf
, const char * dev_name
,
470 const char * req_type
);
472 virtual ~win_csmi_device() throw();
476 virtual bool close();
478 virtual bool is_open() const;
483 virtual bool csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
484 unsigned csmi_bufsiz
);
487 HANDLE m_fh
; ///< Controller device handle
488 int m_port
; ///< Port number
492 //////////////////////////////////////////////////////////////////////
494 class win_tw_cli_device
495 : public /*implements*/ ata_device_with_command_set
498 win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
500 virtual bool is_open() const;
504 virtual bool close();
507 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
510 bool m_ident_valid
, m_smart_valid
;
511 ata_identify_device m_ident_buf
;
512 ata_smart_values m_smart_buf
;
515 /////////////////////////////////////////////////////////////////////////////
516 //// PMC aacraid Support
518 class win_aacraid_device
519 :public /*implements*/ scsi_device
,
520 public /*extends*/ win_smart_device
523 win_aacraid_device(smart_interface
*intf
, const char *dev_name
,unsigned int ctrnum
, unsigned int target
, unsigned int lun
);
525 virtual ~win_aacraid_device() throw();
529 virtual bool scsi_pass_through(struct scsi_cmnd_io
*iop
);
535 //Channel(Lun) of the device
544 /////////////////////////////////////////////////////////////////////////////
545 /// Areca RAID support
547 ///////////////////////////////////////////////////////////////////
548 // SATA(ATA) device behind Areca RAID Controller
549 class win_areca_ata_device
550 : public /*implements*/ areca_ata_device
,
551 public /*extends*/ win_smart_device
554 win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
556 virtual smart_device
* autodetect_open();
557 virtual bool arcmsr_lock();
558 virtual bool arcmsr_unlock();
559 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
565 ///////////////////////////////////////////////////////////////////
566 // SAS(SCSI) device behind Areca RAID Controller
567 class win_areca_scsi_device
568 : public /*implements*/ areca_scsi_device
,
569 public /*extends*/ win_smart_device
572 win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
= 1);
574 virtual smart_device
* autodetect_open();
575 virtual bool arcmsr_lock();
576 virtual bool arcmsr_unlock();
577 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
);
584 //////////////////////////////////////////////////////////////////////
585 // Platform specific interface
587 class win_smart_interface
588 : public /*implements part of*/ smart_interface
591 virtual std::string
get_os_version_str();
593 virtual std::string
get_app_examples(const char * appname
);
596 virtual int64_t get_timer_usec();
599 virtual bool disable_system_auto_standby(bool disable
);
601 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
602 const char * pattern
= 0);
605 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
607 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
609 virtual smart_device
* autodetect_smart_device(const char * name
);
611 virtual smart_device
* get_custom_smart_device(const char * name
, const char * type
);
613 virtual std::string
get_valid_custom_dev_types_str();
617 //////////////////////////////////////////////////////////////////////
620 // Running on 64-bit Windows as 32-bit app ?
621 static bool is_wow64()
623 BOOL (WINAPI
* IsWow64Process_p
)(HANDLE
, PBOOL
) =
624 (BOOL (WINAPI
*)(HANDLE
, PBOOL
))
625 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
626 if (!IsWow64Process_p
)
629 if (!IsWow64Process_p(GetCurrentProcess(), &w64
))
635 // Return info string about build host and OS version
636 std::string
win_smart_interface::get_os_version_str()
638 char vstr
[sizeof(SMARTMONTOOLS_BUILD_HOST
)-1+sizeof("-2003r2(64)-sp2.1")+13]
639 = SMARTMONTOOLS_BUILD_HOST
;
642 char * const vptr
= vstr
+sizeof(SMARTMONTOOLS_BUILD_HOST
)-1;
643 const int vlen
= sizeof(vstr
)-sizeof(SMARTMONTOOLS_BUILD_HOST
);
644 assert(vptr
== vstr
+strlen(vstr
) && vptr
+vlen
+1 == vstr
+sizeof(vstr
));
646 // Starting with Windows 8.1, GetVersionEx() does no longer report the
647 // actual OS version, see:
648 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
650 // RtlGetVersion() is not affected
651 LONG
/*NTSTATUS*/ (WINAPI
/*NTAPI*/ * RtlGetVersion_p
)(LPOSVERSIONINFOEXW
) =
652 (LONG (WINAPI
*)(LPOSVERSIONINFOEXW
))
653 GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
655 OSVERSIONINFOEXW vi
; memset(&vi
, 0, sizeof(vi
));
656 vi
.dwOSVersionInfoSize
= sizeof(vi
);
657 if (!RtlGetVersion_p
|| RtlGetVersion_p(&vi
)) {
658 if (!GetVersionExW((OSVERSIONINFOW
*)&vi
))
663 if ( vi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
664 && vi
.dwMajorVersion
<= 0xf && vi
.dwMinorVersion
<= 0xf) {
665 bool ws
= (vi
.wProductType
<= VER_NT_WORKSTATION
);
666 switch (vi
.dwMajorVersion
<< 4 | vi
.dwMinorVersion
) {
667 case 0x50: w
= "2000"; break;
668 case 0x51: w
= "xp"; break;
669 case 0x52: w
= (!GetSystemMetrics(89/*SM_SERVERR2*/)
670 ? "2003" : "2003r2"); break;
671 case 0x60: w
= (ws
? "vista" : "2008" ); break;
672 case 0x61: w
= (ws
? "win7" : "2008r2"); break;
673 case 0x62: w
= (ws
? "win8" : "2012" ); break;
674 case 0x63: w
= (ws
? "win8.1": "2012r2"); break;
675 case 0x64: w
= (ws
? "w10tp" : "w10tps"); break; // 6.4 = Win 10 Technical Preview
676 case 0xa0: w
= (ws
? "win10" : "w10srv"); break; // 10.0 = Win 10 Final
680 const char * w64
= "";
687 snprintf(vptr
, vlen
, "-%s%u.%u%s",
688 (vi
.dwPlatformId
==VER_PLATFORM_WIN32_NT
? "nt" : "??"),
689 (unsigned)vi
.dwMajorVersion
, (unsigned)vi
.dwMinorVersion
, w64
);
690 else if (vi
.wServicePackMinor
)
691 snprintf(vptr
, vlen
, "-%s%s-sp%u.%u", w
, w64
, vi
.wServicePackMajor
, vi
.wServicePackMinor
);
692 else if (vi
.wServicePackMajor
)
693 snprintf(vptr
, vlen
, "-%s%s-sp%u", w
, w64
, vi
.wServicePackMajor
);
695 snprintf(vptr
, vlen
, "-%s%s", w
, w64
);
700 // MSVCRT only provides ftime() which uses GetSystemTime()
701 // This provides only ~15ms resolution by default.
702 // Use QueryPerformanceCounter instead (~300ns).
703 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
704 int64_t win_smart_interface::get_timer_usec()
706 static int64_t freq
= 0;
710 freq
= (QueryPerformanceFrequency(&t
) ? t
.QuadPart
: -1);
712 return smart_interface::get_timer_usec();
714 if (!QueryPerformanceCounter(&t
))
716 if (!(0 <= t
.QuadPart
&& t
.QuadPart
<= (int64_t)(~(uint64_t)0 >> 1)/1000000))
719 return (t
.QuadPart
* 1000000LL) / freq
;
724 // Return value for device detection functions
725 enum win_dev_type
{ DEV_UNKNOWN
= 0, DEV_ATA
, DEV_SCSI
, DEV_SAT
, DEV_USB
};
727 static win_dev_type
get_phy_drive_type(int drive
);
728 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
);
729 static win_dev_type
get_log_drive_type(int drive
);
730 static bool get_usb_id(int phydrive
, int logdrive
,
731 unsigned short & vendor_id
,
732 unsigned short & product_id
);
734 static const char * ata_get_def_options(void);
737 static int is_permissive()
739 if (!failuretest_permissive
) {
740 pout("To continue, add one or more '-T permissive' options.\n");
743 failuretest_permissive
--;
747 // return number for drive letter, -1 on error
748 // "[A-Za-z]:([/\\][.]?)?" => 0-25
749 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
750 static int drive_letter(const char * s
)
752 return ( (('A' <= s
[0] && s
[0] <= 'Z') || ('a' <= s
[0] && s
[0] <= 'z'))
754 && (!s
[2] || ( strchr("/\\\"", s
[2])
755 && (!s
[3] || (s
[3] == '.' && !s
[4]))) ) ?
756 (s
[0] & 0x1f) - 1 : -1);
759 // Skip trailing "/dev/", do not allow "/dev/X:"
760 static const char * skipdev(const char * s
)
762 return (!strncmp(s
, "/dev/", 5) && drive_letter(s
+5) < 0 ? s
+5 : s
);
765 ata_device
* win_smart_interface::get_ata_device(const char * name
, const char * type
)
767 const char * testname
= skipdev(name
);
768 if (!strncmp(testname
, "csmi", 4))
769 return new win_csmi_device(this, name
, type
);
770 if (!strncmp(testname
, "tw_cli", 6))
771 return new win_tw_cli_device(this, name
, type
);
772 return new win_ata_device(this, name
, type
);
775 scsi_device
* win_smart_interface::get_scsi_device(const char * name
, const char * type
)
777 return new win_scsi_device(this, name
, type
);
780 static int sdxy_to_phydrive(const char (& xy
)[2+1])
782 int phydrive
= xy
[0] - 'a';
784 phydrive
= (phydrive
+ 1) * ('z' - 'a' + 1) + (xy
[1] - 'a');
788 static win_dev_type
get_dev_type(const char * name
, int & phydrive
, int & logdrive
)
790 phydrive
= logdrive
= -1;
792 name
= skipdev(name
);
793 if (!strncmp(name
, "st", 2))
795 if (!strncmp(name
, "nst", 3))
797 if (!strncmp(name
, "tape", 4))
800 logdrive
= drive_letter(name
);
802 win_dev_type type
= get_log_drive_type(logdrive
);
803 return (type
!= DEV_UNKNOWN
? type
: DEV_SCSI
);
806 char drive
[2+1] = "";
807 if (sscanf(name
, "sd%2[a-z]", drive
) == 1) {
808 phydrive
= sdxy_to_phydrive(drive
);
809 return get_phy_drive_type(phydrive
);
812 if (sscanf(name
, "pd%d", &phydrive
) == 1 && phydrive
>= 0)
813 return get_phy_drive_type(phydrive
);
818 smart_device
* win_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
821 int disknum
= -1, n1
= -1, n2
= -1;
825 if (sscanf(type
, "areca,%n%d/%d%n", &n1
, &disknum
, &encnum
, &n2
) >= 1 || n1
== 6) {
826 if (!(1 <= disknum
&& disknum
<= 128)) {
827 set_err(EINVAL
, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum
);
830 if (!(1 <= encnum
&& encnum
<= 8)) {
831 set_err(EINVAL
, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum
);
835 name
= skipdev(name
);
836 #define ARECA_MAX_CTLR_NUM 16
839 if (sscanf(name
, "arcmsr%d%n", &ctlrindex
, &n1
) >= 1 && n1
== (int)strlen(name
)) {
841 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
842 2. map arcmsrX into "\\\\.\\scsiX"
844 for (int idx
= 0; idx
< ARECA_MAX_CTLR_NUM
; idx
++) {
845 memset(devpath
, 0, sizeof(devpath
));
846 snprintf(devpath
, sizeof(devpath
), "\\\\.\\scsi%d:", idx
);
847 win_areca_ata_device
*arcdev
= new win_areca_ata_device(this, devpath
, disknum
, encnum
);
848 if(arcdev
->arcmsr_probe()) {
849 if(ctlrindex
-- == 0) {
855 set_err(ENOENT
, "No Areca controller found");
858 set_err(EINVAL
, "Option -d areca,N/E requires device name /dev/arcmsrX");
863 unsigned ctrnum
, lun
, target
;
866 if ( sscanf(type
, "aacraid,%u,%u,%u%n", &ctrnum
, &lun
, &target
, &n1
) >= 3
867 && n1
== (int)strlen(type
)) {
868 #define aacraid_MAX_CTLR_NUM 16
869 if (ctrnum
>= aacraid_MAX_CTLR_NUM
) {
870 set_err(EINVAL
, "aacraid: invalid host number %u", ctrnum
);
875 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[AACRAID_MAX_CTLR_NUM]:" and
876 2. map ARCX into "\\\\.\\scsiX"
878 memset(devpath
, 0, sizeof(devpath
));
879 unsigned ctlrindex
= 0;
880 for (int portNum
= 0; portNum
< aacraid_MAX_CTLR_NUM
; portNum
++){
882 snprintf(subKey
, sizeof(subKey
), "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum
);
884 long regStatus
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hScsiKey
);
885 if (regStatus
== ERROR_SUCCESS
){
887 DWORD driverNameSize
= sizeof(driverName
);
889 regStatus
= RegQueryValueExA(hScsiKey
, "Driver", NULL
, ®Type
, (LPBYTE
) driverName
, &driverNameSize
);
890 if (regStatus
== ERROR_SUCCESS
){
891 if (regType
== REG_SZ
){
892 if (stricmp(driverName
, "arcsas") == 0){
893 if(ctrnum
== ctlrindex
){
894 snprintf(devpath
, sizeof(devpath
), "\\\\.\\Scsi%d:", portNum
);
895 return get_sat_device("sat,auto",
896 new win_aacraid_device(this, devpath
, ctrnum
, target
, lun
));
902 RegCloseKey(hScsiKey
);
906 set_err(EINVAL
, "aacraid: host %u not found", ctrnum
);
913 std::string
win_smart_interface::get_valid_custom_dev_types_str()
915 return "aacraid,H,L,ID, areca,N[/E]";
919 smart_device
* win_smart_interface::autodetect_smart_device(const char * name
)
921 const char * testname
= skipdev(name
);
922 if (str_starts_with(testname
, "hd"))
923 return new win_ata_device(this, name
, "");
925 if (str_starts_with(testname
, "tw_cli"))
926 return new win_tw_cli_device(this, name
, "");
928 if (str_starts_with(testname
, "csmi"))
929 return new win_csmi_device(this, name
, "");
931 int phydrive
= -1, logdrive
= -1;
932 win_dev_type type
= get_dev_type(name
, phydrive
, logdrive
);
935 return new win_ata_device(this, name
, "");
937 if (type
== DEV_SCSI
)
938 return new win_scsi_device(this, name
, "");
941 return get_sat_device("sat", new win_scsi_device(this, name
, ""));
943 if (type
== DEV_USB
) {
945 unsigned short vendor_id
= 0, product_id
= 0;
946 if (!get_usb_id(phydrive
, logdrive
, vendor_id
, product_id
)) {
947 set_err(EINVAL
, "Unable to read USB device ID");
950 // Get type name for this ID
951 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
954 // Return SAT/USB device for this type
955 return get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
964 bool win_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
965 const char * type
, const char * pattern
/* = 0*/)
968 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
972 // Check for "[*,]pd" type
974 char type2
[16+1] = "";
977 if (!strcmp(type
, "pd")) {
981 else if (sscanf(type
, "%16[^,],pd%n", type2
, &nc
) == 1 &&
982 nc
== (int)strlen(type
)) {
989 bool ata
, scsi
, sat
, usb
, csmi
;
991 ata
= scsi
= usb
= sat
= csmi
= true;
994 ata
= scsi
= usb
= sat
= csmi
= false;
995 if (!strcmp(type
, "ata"))
997 else if (!strcmp(type
, "scsi"))
999 else if (!strcmp(type
, "sat"))
1001 else if (!strcmp(type
, "usb"))
1003 else if (!strcmp(type
, "csmi"))
1007 "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], sat[,pd], usb[,pd], csmi, pd",
1015 if (ata
|| scsi
|| sat
|| usb
) {
1016 // Scan up to 128 drives and 2 3ware controllers
1017 const int max_raid
= 2;
1018 bool raid_seen
[max_raid
] = {false, false};
1020 for (int i
= 0; i
< 128; i
++) {
1022 snprintf(name
, sizeof(name
), "/dev/pd%d", i
);
1023 else if (i
+ 'a' <= 'z')
1024 snprintf(name
, sizeof(name
), "/dev/sd%c", i
+ 'a');
1026 snprintf(name
, sizeof(name
), "/dev/sd%c%c",
1027 i
/ ('z'-'a'+1) - 1 + 'a',
1028 i
% ('z'-'a'+1) + 'a');
1030 GETVERSIONINPARAMS_EX vers_ex
;
1032 switch (get_phy_drive_type(i
, (ata
? &vers_ex
: 0))) {
1034 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
1038 // Interpret RAID drive map if present
1039 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
) {
1040 // Skip if too many controllers or logical drive from this controller already seen
1041 if (!(vers_ex
.wControllerId
< max_raid
&& !raid_seen
[vers_ex
.wControllerId
]))
1043 raid_seen
[vers_ex
.wControllerId
] = true;
1044 // Add physical drives
1045 int len
= strlen(name
);
1046 for (unsigned int pi
= 0; pi
< 32; pi
++) {
1047 if (vers_ex
.dwDeviceMapEx
& (1L << pi
)) {
1048 snprintf(name
+len
, sizeof(name
)-1-len
, ",%u", pi
);
1049 devlist
.push_back( new win_ata_device(this, name
, "ata") );
1054 devlist
.push_back( new win_ata_device(this, name
, "ata") );
1059 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
1062 devlist
.push_back( new win_scsi_device(this, name
, "scsi") );
1066 // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
1069 devlist
.push_back( get_sat_device("sat", new win_scsi_device(this, name
, "")) );
1073 // STORAGE_QUERY_PROPERTY returned USB
1077 // TODO: Use common function for this and autodetect_smart_device()
1078 // Get USB bridge ID
1079 unsigned short vendor_id
= 0, product_id
= 0;
1080 if (!get_usb_id(i
, -1, vendor_id
, product_id
))
1082 // Get type name for this ID
1083 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
1086 // Return SAT/USB device for this type
1087 ata_device
* dev
= get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
1090 devlist
.push_back(dev
);
1102 // Scan CSMI devices
1103 for (int i
= 0; i
<= 9; i
++) {
1104 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,0", i
);
1105 win_csmi_device
test_dev(this, name
, "");
1106 if (!test_dev
.open_scsi())
1109 unsigned ports_used
= test_dev
.get_ports_used();
1113 for (int pi
= 0; pi
< 32; pi
++) {
1114 if (!(ports_used
& (1 << pi
)))
1116 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,%d", i
, pi
);
1117 devlist
.push_back( new win_csmi_device(this, name
, "ata") );
1125 // get examples for smartctl
1126 std::string
win_smart_interface::get_app_examples(const char * appname
)
1128 if (strcmp(appname
, "smartctl"))
1130 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1131 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1132 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1133 " (Enables SMART on first disk)\n\n"
1134 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1135 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1136 " (Prints Self-Test & Attribute errors)\n"
1137 " smartctl -a /dev/sda\n"
1138 " (Prints all information for disk on PhysicalDrive 0)\n"
1139 " smartctl -a /dev/pd3\n"
1140 " (Prints all information for disk on PhysicalDrive 3)\n"
1141 " smartctl -a /dev/tape1\n"
1142 " (Prints all information for SCSI tape on Tape 1)\n"
1143 " smartctl -A /dev/hdb,3\n"
1144 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1145 " smartctl -A /dev/tw_cli/c0/p1\n"
1146 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1147 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1148 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1149 " on 1st Areca RAID controller)\n"
1151 " ATA SMART access methods and ordering may be specified by modifiers\n"
1152 " following the device name: /dev/hdX:[saicm], where\n"
1153 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1154 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1155 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1157 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1162 bool win_smart_interface::disable_system_auto_standby(bool disable
)
1165 SYSTEM_POWER_STATUS ps
;
1166 if (!GetSystemPowerStatus(&ps
))
1167 return set_err(ENOSYS
, "Unknown power status");
1168 if (ps
.ACLineStatus
!= 1) {
1169 SetThreadExecutionState(ES_CONTINUOUS
);
1170 if (ps
.ACLineStatus
== 0)
1171 set_err(EIO
, "AC offline");
1173 set_err(EIO
, "Unknown AC line status");
1178 if (!SetThreadExecutionState(ES_CONTINUOUS
| (disable
? ES_SYSTEM_REQUIRED
: 0)))
1179 return set_err(ENOSYS
);
1184 /////////////////////////////////////////////////////////////////////////////
1186 /////////////////////////////////////////////////////////////////////////////
1188 #define SMART_CYL_LOW 0x4F
1189 #define SMART_CYL_HI 0xC2
1191 static void print_ide_regs(const IDEREGS
* r
, int out
)
1193 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1194 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
1195 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
1198 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
1200 pout(" Input : "); print_ide_regs(ri
, 0);
1202 pout(" Output: "); print_ide_regs(ro
, 1);
1206 /////////////////////////////////////////////////////////////////////////////
1208 // call SMART_GET_VERSION, return device map or -1 on error
1210 static int smart_get_version(HANDLE hdevice
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
1212 GETVERSIONINPARAMS vers
; memset(&vers
, 0, sizeof(vers
));
1213 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1216 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
1217 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1219 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1223 assert(num_out
== sizeof(GETVERSIONINPARAMS
));
1225 if (ata_debugmode
> 1) {
1226 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1227 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1228 (unsigned)num_out
, vers
.bVersion
, vers
.bRevision
,
1229 (unsigned)vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1230 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1231 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1232 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, (unsigned)vers_ex
.dwDeviceMapEx
);
1236 *ata_version_ex
= vers_ex
;
1238 // TODO: Check vers.fCapabilities here?
1239 return vers
.bIDEDeviceMap
;
1243 // call SMART_* ioctl
1245 static int smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
1247 SENDCMDINPARAMS inpar
;
1248 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
1250 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
1251 const SENDCMDOUTPARAMS
* outpar
;
1252 DWORD code
, num_out
;
1253 unsigned int size_out
;
1256 memset(&inpar
, 0, sizeof(inpar
));
1257 inpar
.irDriveRegs
= *regs
;
1259 // Older drivers may require bits 5 and 7 set
1260 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1261 inpar
.irDriveRegs
.bDriveHeadReg
|= 0xa0;
1263 // Drive number 0-3 was required on Win9x/ME only
1264 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1265 //inpar.bDriveNumber = drive;
1269 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
1270 inpar_ex
.bPortNumber
= port
;
1273 if (datasize
== 512) {
1274 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
1275 inpar
.cBufferSize
= size_out
= 512;
1277 else if (datasize
== 0) {
1278 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
1279 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
1280 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
1281 // Note: cBufferSize must be 0 on Win9x
1290 memset(&outbuf
, 0, sizeof(outbuf
));
1292 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
1293 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
1294 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1295 long err
= GetLastError();
1296 if (ata_debugmode
&& (err
!= ERROR_INVALID_PARAMETER
|| ata_debugmode
> 1)) {
1297 pout(" %s failed, Error=%ld\n", name
, err
);
1298 print_ide_regs_io(regs
, NULL
);
1300 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
1301 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/
1302 || err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1305 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1307 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
1309 if (outpar
->DriverStatus
.bDriverError
) {
1310 if (ata_debugmode
) {
1311 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1312 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
1313 print_ide_regs_io(regs
, NULL
);
1315 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1319 if (ata_debugmode
> 1) {
1320 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name
,
1321 (unsigned)num_out
, (unsigned)outpar
->cBufferSize
);
1322 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
1323 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
1327 memcpy(data
, outpar
->bBuffer
, 512);
1328 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
1329 if (nonempty(outpar
->bBuffer
, sizeof(IDEREGS
)))
1330 memcpy(regs
, outpar
->bBuffer
, sizeof(IDEREGS
));
1331 else { // Workaround for driver not returning regs
1333 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1334 *regs
= inpar
.irDriveRegs
;
1342 /////////////////////////////////////////////////////////////////////////////
1343 // IDE PASS THROUGH (2000, XP, undocumented)
1345 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1346 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1348 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
1350 if (datasize
> 512) {
1354 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
1355 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1357 const unsigned char magic
= 0xcf;
1364 buf
->IdeReg
= *regs
;
1365 buf
->DataBufferSize
= datasize
;
1367 buf
->DataBuffer
[0] = magic
;
1369 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
1370 buf
, size
, buf
, size
, &num_out
, NULL
)) {
1371 long err
= GetLastError();
1372 if (ata_debugmode
) {
1373 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
1374 print_ide_regs_io(regs
, NULL
);
1376 VirtualFree(buf
, 0, MEM_RELEASE
);
1377 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1382 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
1383 if (ata_debugmode
) {
1384 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1385 print_ide_regs_io(regs
, &buf
->IdeReg
);
1387 VirtualFree(buf
, 0, MEM_RELEASE
);
1392 // Check and copy data
1394 if ( num_out
!= size
1395 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
1396 if (ata_debugmode
) {
1397 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1398 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1399 print_ide_regs_io(regs
, &buf
->IdeReg
);
1401 VirtualFree(buf
, 0, MEM_RELEASE
);
1405 memcpy(data
, buf
->DataBuffer
, datasize
);
1408 if (ata_debugmode
> 1) {
1409 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1410 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1411 print_ide_regs_io(regs
, &buf
->IdeReg
);
1413 *regs
= buf
->IdeReg
;
1415 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1416 VirtualFree(buf
, 0, MEM_RELEASE
);
1421 /////////////////////////////////////////////////////////////////////////////
1422 // ATA PASS THROUGH (Win2003, XP SP2)
1425 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1426 // transfer per command. Therefore, multi-sector transfers are only supported
1427 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1428 // or READ/WRITE LOG EXT work only with single sector transfers.
1429 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1431 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1433 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, IDEREGS
* prev_regs
, char * data
, int datasize
)
1435 const int max_sectors
= 32; // TODO: Allocate dynamic buffer
1438 ATA_PASS_THROUGH_EX apt
;
1440 UCHAR ucDataBuf
[max_sectors
* 512];
1441 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
1443 const unsigned char magic
= 0xcf;
1445 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
1446 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
1447 //ab.apt.PathId = 0;
1448 //ab.apt.TargetId = 0;
1450 ab
.apt
.TimeOutValue
= 10;
1451 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
1452 ab
.apt
.DataBufferOffset
= size
;
1455 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1459 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
1460 ab
.apt
.DataTransferLength
= datasize
;
1462 ab
.ucDataBuf
[0] = magic
;
1464 else if (datasize
< 0) {
1465 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1469 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
1470 ab
.apt
.DataTransferLength
= -datasize
;
1472 memcpy(ab
.ucDataBuf
, data
, -datasize
);
1475 assert(ab
.apt
.AtaFlags
== 0);
1476 assert(ab
.apt
.DataTransferLength
== 0);
1479 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
1480 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
1481 IDEREGS
* ptfregs
= (IDEREGS
*)ab
.apt
.PreviousTaskFile
;
1485 *ptfregs
= *prev_regs
;
1486 ab
.apt
.AtaFlags
|= ATA_FLAGS_48BIT_COMMAND
;
1490 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
1491 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
1492 long err
= GetLastError();
1493 if (ata_debugmode
) {
1494 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
1495 print_ide_regs_io(regs
, NULL
);
1497 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1502 if (ctfregs
->bCommandReg
/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1503 if (ata_debugmode
) {
1504 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1505 print_ide_regs_io(regs
, ctfregs
);
1511 // Check and copy data
1513 if ( num_out
!= size
1514 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
1515 if (ata_debugmode
) {
1516 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out
);
1517 print_ide_regs_io(regs
, ctfregs
);
1522 memcpy(data
, ab
.ucDataBuf
, datasize
);
1525 if (ata_debugmode
> 1) {
1526 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out
);
1527 print_ide_regs_io(regs
, ctfregs
);
1531 *prev_regs
= *ptfregs
;
1537 /////////////////////////////////////////////////////////////////////////////
1538 // SMART IOCTL via SCSI MINIPORT ioctl
1540 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1541 // miniport driver (via SCSI port driver scsiport.sys).
1542 // It can be used to skip the missing or broken handling of some SMART
1543 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1545 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
1548 DWORD code
= 0; const char * name
= 0;
1549 if (regs
->bCommandReg
== ATA_IDENTIFY_DEVICE
) {
1550 code
= IOCTL_SCSI_MINIPORT_IDENTIFY
; name
= "IDENTIFY";
1552 else if (regs
->bCommandReg
== ATA_SMART_CMD
) switch (regs
->bFeaturesReg
) {
1553 case ATA_SMART_READ_VALUES
:
1554 code
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
; name
= "READ_SMART_ATTRIBS"; break;
1555 case ATA_SMART_READ_THRESHOLDS
:
1556 code
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
; name
= "READ_SMART_THRESHOLDS"; break;
1557 case ATA_SMART_ENABLE
:
1558 code
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
; name
= "ENABLE_SMART"; break;
1559 case ATA_SMART_DISABLE
:
1560 code
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
; name
= "DISABLE_SMART"; break;
1561 case ATA_SMART_STATUS
:
1562 code
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
; name
= "RETURN_STATUS"; break;
1563 case ATA_SMART_AUTOSAVE
:
1564 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
; name
= "ENABLE_DISABLE_AUTOSAVE"; break;
1565 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1566 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1567 case ATA_SMART_IMMEDIATE_OFFLINE
:
1568 code
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
; name
= "EXECUTE_OFFLINE_DIAGS"; break;
1569 case ATA_SMART_AUTO_OFFLINE
:
1570 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
; name
= "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1571 case ATA_SMART_READ_LOG_SECTOR
:
1572 code
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
; name
= "READ_SMART_LOG"; break;
1573 case ATA_SMART_WRITE_LOG_SECTOR
:
1574 code
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
; name
= "WRITE_SMART_LOG"; break;
1583 SRB_IO_CONTROL srbc
;
1586 SENDCMDOUTPARAMS out
;
1590 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(SENDCMDINPARAMS
)-1+512);
1591 memset(&sb
, 0, sizeof(sb
));
1595 if (datasize
> (int)sizeof(sb
.space
)+1) {
1601 else if (datasize
< 0) {
1602 if (-datasize
> (int)sizeof(sb
.space
)+1) {
1607 memcpy(sb
.params
.in
.bBuffer
, data
, size
);
1609 else if (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1610 size
= sizeof(IDEREGS
);
1613 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1614 memcpy(sb
.srbc
.Signature
, "SCSIDISK", 8); // atapi.sys
1615 sb
.srbc
.Timeout
= 60; // seconds
1616 sb
.srbc
.ControlCode
= code
;
1617 //sb.srbc.ReturnCode = 0;
1618 sb
.srbc
.Length
= sizeof(SENDCMDINPARAMS
)-1 + size
;
1619 sb
.params
.in
.irDriveRegs
= *regs
;
1620 sb
.params
.in
.cBufferSize
= size
;
1622 // Call miniport ioctl
1623 size
+= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)-1;
1625 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1626 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
1627 long err
= GetLastError();
1628 if (ata_debugmode
) {
1629 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name
, err
);
1630 print_ide_regs_io(regs
, NULL
);
1632 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1637 if (sb
.srbc
.ReturnCode
) {
1638 if (ata_debugmode
) {
1639 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name
, (unsigned)sb
.srbc
.ReturnCode
);
1640 print_ide_regs_io(regs
, NULL
);
1646 if (sb
.params
.out
.DriverStatus
.bDriverError
) {
1647 if (ata_debugmode
) {
1648 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1649 sb
.params
.out
.DriverStatus
.bDriverError
, sb
.params
.out
.DriverStatus
.bIDEError
);
1650 print_ide_regs_io(regs
, NULL
);
1652 errno
= (!sb
.params
.out
.DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1656 if (ata_debugmode
> 1) {
1657 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name
,
1658 (unsigned)num_out
, (unsigned)sb
.params
.out
.cBufferSize
);
1659 print_ide_regs_io(regs
, (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
?
1660 (const IDEREGS
*)(sb
.params
.out
.bBuffer
) : 0));
1664 memcpy(data
, sb
.params
.out
.bBuffer
, datasize
);
1665 else if (datasize
== 0 && code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1666 memcpy(regs
, sb
.params
.out
.bBuffer
, sizeof(IDEREGS
));
1672 /////////////////////////////////////////////////////////////////////////////
1674 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1676 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1679 SRB_IO_CONTROL srbc
;
1683 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1685 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1689 memset(&sb
, 0, sizeof(sb
));
1690 strncpy((char *)sb
.srbc
.Signature
, "<3ware>", sizeof(sb
.srbc
.Signature
));
1691 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1692 sb
.srbc
.Timeout
= 60; // seconds
1693 sb
.srbc
.ControlCode
= 0xA0000000;
1694 sb
.srbc
.ReturnCode
= 0;
1695 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1697 sb
.regs
.bReserved
= port
;
1700 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1701 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1702 long err
= GetLastError();
1703 if (ata_debugmode
) {
1704 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1705 print_ide_regs_io(regs
, NULL
);
1707 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1711 if (sb
.srbc
.ReturnCode
) {
1712 if (ata_debugmode
) {
1713 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb
.srbc
.ReturnCode
);
1714 print_ide_regs_io(regs
, NULL
);
1722 memcpy(data
, sb
.buffer
, datasize
);
1724 if (ata_debugmode
> 1) {
1725 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out
);
1726 print_ide_regs_io(regs
, &sb
.regs
);
1734 /////////////////////////////////////////////////////////////////////////////
1736 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1737 // 3DM/CLI "Rescan Controller" function does not to always update it.
1739 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1741 SRB_IO_CONTROL srbc
;
1742 memset(&srbc
, 0, sizeof(srbc
));
1743 strncpy((char *)srbc
.Signature
, "<3ware>", sizeof(srbc
.Signature
));
1744 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1745 srbc
.Timeout
= 60; // seconds
1746 srbc
.ControlCode
= 0xCC010014;
1747 srbc
.ReturnCode
= 0;
1751 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1752 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1753 long err
= GetLastError();
1755 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1756 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1759 if (srbc
.ReturnCode
) {
1761 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc
.ReturnCode
);
1765 if (ata_debugmode
> 1)
1766 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1772 /////////////////////////////////////////////////////////////////////////////
1774 // Routines for pseudo device /dev/tw_cli/*
1775 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1778 // Get clipboard data
1780 static int get_clipboard(char * data
, int datasize
)
1782 if (!OpenClipboard(NULL
))
1784 HANDLE h
= GetClipboardData(CF_TEXT
);
1789 const void * p
= GlobalLock(h
);
1790 int n
= GlobalSize(h
);
1800 // Run a command, write stdout to dataout
1801 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1803 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1805 // Create stdout pipe
1806 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1807 HANDLE pipe_out_w
, h
;
1808 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1810 HANDLE self
= GetCurrentProcess();
1812 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1813 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1814 CloseHandle(pipe_out_w
);
1818 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1819 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1820 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1825 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1826 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1827 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1828 si
.dwFlags
= STARTF_USESTDHANDLES
;
1829 PROCESS_INFORMATION pi
;
1831 NULL
, const_cast<char *>(cmd
),
1832 NULL
, NULL
, TRUE
/*inherit*/,
1833 CREATE_NO_WINDOW
/*do not create a new console window*/,
1834 NULL
, NULL
, &si
, &pi
)) {
1835 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1838 CloseHandle(pi
.hThread
);
1839 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1841 // Copy stdout to output buffer
1843 while (i
< outsize
) {
1845 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1849 CloseHandle(pipe_out_r
);
1851 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1852 CloseHandle(pi
.hProcess
);
1857 static const char * findstr(const char * str
, const char * sub
)
1859 const char * s
= strstr(str
, sub
);
1860 return (s
? s
+strlen(sub
) : "");
1864 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1866 int srclen
= strcspn(src
, "\r\n");
1868 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1869 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1871 if (i
< destsize
-1 && i
< srclen
)
1876 // TODO: This is OS independent
1878 win_tw_cli_device::win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
1879 : smart_device(intf
, dev_name
, "tw_cli", req_type
),
1880 m_ident_valid(false), m_smart_valid(false)
1882 memset(&m_ident_buf
, 0, sizeof(m_ident_buf
));
1883 memset(&m_smart_buf
, 0, sizeof(m_smart_buf
));
1887 bool win_tw_cli_device::is_open() const
1889 return (m_ident_valid
|| m_smart_valid
);
1893 bool win_tw_cli_device::open()
1895 m_ident_valid
= m_smart_valid
= false;
1896 const char * name
= skipdev(get_dev_name());
1897 // Read tw_cli or 3DM browser output into buffer
1899 int size
= -1, n1
= -1, n2
= -1;
1900 if (!strcmp(name
, "tw_cli/clip")) { // read clipboard
1901 size
= get_clipboard(buffer
, sizeof(buffer
));
1903 else if (!strcmp(name
, "tw_cli/stdin")) { // read stdin
1904 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1906 else if (sscanf(name
, "tw_cli/%nc%*u/p%*u%n", &n1
, &n2
) >= 0 && n2
== (int)strlen(name
)) {
1907 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1909 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
+n1
);
1910 if (ata_debugmode
> 1)
1911 pout("%s: Run: \"%s\"\n", name
, cmd
);
1912 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1915 return set_err(EINVAL
);
1918 if (ata_debugmode
> 1)
1919 pout("%s: Read %d bytes\n", name
, size
);
1921 return set_err(ENOENT
);
1922 if (size
>= (int)sizeof(buffer
))
1923 return set_err(EIO
);
1926 if (ata_debugmode
> 1)
1927 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1929 // Fake identify sector
1930 ASSERT_SIZEOF(ata_identify_device
, 512);
1931 ata_identify_device
* id
= &m_ident_buf
;
1932 memset(id
, 0, sizeof(*id
));
1933 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1934 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1935 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1936 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1937 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1939 id
->words047_079
[49-47] = 0x0200; // size valid
1940 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1941 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1943 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1944 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1946 // Parse smart data hex dump
1947 const char * s
= findstr(buffer
, "Drive Smart Data:");
1949 s
= findstr(buffer
, "Drive SMART Data:"); // tw_cli from 9.5.x
1951 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1953 const char * s1
= findstr(s
, "<td class"); // html version
1956 s
+= strcspn(s
, "\r\n");
1959 s
= buffer
; // try raw hex dump without header
1961 unsigned char * sd
= (unsigned char *)&m_smart_buf
;
1964 unsigned x
= ~0; int n
= -1;
1965 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1967 sd
[i
] = (unsigned char)x
;
1968 if (!(++i
< 512 && n
> 0))
1971 if (*s
== '<') // "<br>"
1972 s
+= strcspn(s
, "\r\n");
1975 if (!id
->model
[1]) {
1976 // No useful data found
1977 char * err
= strstr(buffer
, "Error:");
1979 err
= strstr(buffer
, "error :");
1980 if (err
&& (err
= strchr(err
, ':'))) {
1981 // Show tw_cli error message
1983 err
[strcspn(err
, "\r\n")] = 0;
1984 return set_err(EIO
, "%s", err
);
1986 return set_err(EIO
);
1991 m_ident_valid
= true;
1992 m_smart_valid
= !!sd
;
1997 bool win_tw_cli_device::close()
1999 m_ident_valid
= m_smart_valid
= false;
2004 int win_tw_cli_device::ata_command_interface(smart_command_set command
, int /*select*/, char * data
)
2010 memcpy(data
, &m_ident_buf
, 512);
2015 memcpy(data
, &m_smart_buf
, 512);
2019 case STATUS_CHECK
: // Fake "good" SMART status
2024 // Arrive here for all unsupported commands
2030 /////////////////////////////////////////////////////////////////////////////
2031 // IOCTL_STORAGE_QUERY_PROPERTY
2033 union STORAGE_DEVICE_DESCRIPTOR_DATA
{
2034 STORAGE_DEVICE_DESCRIPTOR desc
;
2038 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
2039 // (This works without admin rights)
2041 static int storage_query_property_ioctl(HANDLE hdevice
, STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2043 STORAGE_PROPERTY_QUERY query
= {StorageDeviceProperty
, PropertyStandardQuery
, {0} };
2044 memset(data
, 0, sizeof(*data
));
2047 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_QUERY_PROPERTY
,
2048 &query
, sizeof(query
), data
, sizeof(*data
), &num_out
, NULL
)) {
2049 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2050 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
2055 if (ata_debugmode
> 1 || scsi_debugmode
> 1) {
2056 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
2058 " Product: \"%s\"\n"
2059 " Revision: \"%s\"\n"
2061 " BusType: 0x%02x\n",
2062 (data
->desc
.VendorIdOffset
? data
->raw
+data
->desc
.VendorIdOffset
: "(null)"),
2063 (data
->desc
.ProductIdOffset
? data
->raw
+data
->desc
.ProductIdOffset
: "(null)"),
2064 (data
->desc
.ProductRevisionOffset
? data
->raw
+data
->desc
.ProductRevisionOffset
: "(null)"),
2065 (data
->desc
.RemovableMedia
? "Yes":"No"), data
->desc
.BusType
2072 /////////////////////////////////////////////////////////////////////////////
2073 // IOCTL_STORAGE_PREDICT_FAILURE
2075 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
2076 // or -1 on error, opionally return VendorSpecific data.
2077 // (This works without admin rights)
2079 static int storage_predict_failure_ioctl(HANDLE hdevice
, char * data
= 0)
2081 STORAGE_PREDICT_FAILURE pred
;
2082 memset(&pred
, 0, sizeof(pred
));
2085 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_PREDICT_FAILURE
,
2086 0, 0, &pred
, sizeof(pred
), &num_out
, NULL
)) {
2087 if (ata_debugmode
> 1)
2088 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
2093 if (ata_debugmode
> 1) {
2094 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2095 " PredictFailure: 0x%08x\n"
2096 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2097 (unsigned)pred
.PredictFailure
,
2098 pred
.VendorSpecific
[0], pred
.VendorSpecific
[1], pred
.VendorSpecific
[2],
2099 pred
.VendorSpecific
[sizeof(pred
.VendorSpecific
)-1]
2103 memcpy(data
, pred
.VendorSpecific
, sizeof(pred
.VendorSpecific
));
2104 return (!pred
.PredictFailure
? 0 : 1);
2108 /////////////////////////////////////////////////////////////////////////////
2110 // Return true if ATA drive behind a SAT layer
2111 static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2113 if (!data
->desc
.VendorIdOffset
)
2115 if (strcmp(data
->raw
+ data
->desc
.VendorIdOffset
, "ATA "))
2120 // Return true if Intel ICHxR RAID volume
2121 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2123 if (!(data
->desc
.VendorIdOffset
&& data
->desc
.ProductIdOffset
))
2125 const char * vendor
= data
->raw
+ data
->desc
.VendorIdOffset
;
2126 if (!(!strnicmp(vendor
, "Intel", 5) && strspn(vendor
+5, " ") == strlen(vendor
+5)))
2128 if (strnicmp(data
->raw
+ data
->desc
.ProductIdOffset
, "Raid ", 5))
2133 // get DEV_* for open handle
2134 static win_dev_type
get_controller_type(HANDLE hdevice
, bool admin
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2136 // Get BusType from device descriptor
2137 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2138 if (storage_query_property_ioctl(hdevice
, &data
))
2141 // Newer BusType* values are missing in older includes
2142 switch ((int)data
.desc
.BusType
) {
2144 case 0x0b: // BusTypeSata
2145 // Certain Intel AHCI drivers (C600+/C220+) have broken
2146 // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
2151 memset(ata_version_ex
, 0, sizeof(*ata_version_ex
));
2159 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2160 if (is_intel_raid_volume(&data
))
2162 // LSI/3ware RAID volume: supports SMART_*
2163 if (admin
&& smart_get_version(hdevice
, ata_version_ex
) >= 0)
2168 case 0x09: // BusTypeiScsi
2169 case 0x0a: // BusTypeSas
2184 // get DEV_* for device path
2185 static win_dev_type
get_controller_type(const char * path
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
2188 HANDLE h
= CreateFileA(path
, GENERIC_READ
|GENERIC_WRITE
,
2189 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2190 if (h
== INVALID_HANDLE_VALUE
) {
2192 h
= CreateFileA(path
, 0,
2193 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2194 if (h
== INVALID_HANDLE_VALUE
)
2197 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2198 pout(" %s: successfully opened%s\n", path
, (!admin
? " (without admin rights)" :""));
2199 win_dev_type type
= get_controller_type(h
, admin
, ata_version_ex
);
2204 // get DEV_* for physical drive number
2205 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2208 snprintf(path
, sizeof(path
)-1, "\\\\.\\PhysicalDrive%d", drive
);
2209 return get_controller_type(path
, ata_version_ex
);
2212 static win_dev_type
get_phy_drive_type(int drive
)
2214 return get_phy_drive_type(drive
, 0);
2217 // get DEV_* for logical drive number
2218 static win_dev_type
get_log_drive_type(int drive
)
2221 snprintf(path
, sizeof(path
)-1, "\\\\.\\%c:", 'A'+drive
);
2222 return get_controller_type(path
);
2225 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2226 static int get_identify_from_device_property(HANDLE hdevice
, ata_identify_device
* id
)
2228 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2229 if (storage_query_property_ioctl(hdevice
, &data
))
2232 memset(id
, 0, sizeof(*id
));
2234 // Some drivers split ATA model string into VendorId and ProductId,
2235 // others return it as ProductId only.
2236 char model
[sizeof(id
->model
) + 1] = "";
2239 if (data
.desc
.VendorIdOffset
) {
2240 for ( ;i
< sizeof(model
)-1 && data
.raw
[data
.desc
.VendorIdOffset
+i
]; i
++)
2241 model
[i
] = data
.raw
[data
.desc
.VendorIdOffset
+i
];
2244 if (data
.desc
.ProductIdOffset
) {
2245 while (i
> 1 && model
[i
-2] == ' ') // Keep last blank from VendorId
2247 // Ignore VendorId "ATA"
2248 if (i
<= 4 && !strncmp(model
, "ATA", 3) && (i
== 3 || model
[3] == ' '))
2250 for (unsigned j
= 0; i
< sizeof(model
)-1 && data
.raw
[data
.desc
.ProductIdOffset
+j
]; i
++, j
++)
2251 model
[i
] = data
.raw
[data
.desc
.ProductIdOffset
+j
];
2254 while (i
> 0 && model
[i
-1] == ' ')
2257 copy_swapped(id
->model
, model
, sizeof(id
->model
));
2259 if (data
.desc
.ProductRevisionOffset
)
2260 copy_swapped(id
->fw_rev
, data
.raw
+data
.desc
.ProductRevisionOffset
, sizeof(id
->fw_rev
));
2262 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
2263 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
2267 // Get Serial Number in IDENTIFY from WMI
2268 static bool get_serial_from_wmi(int drive
, ata_identify_device
* id
)
2270 bool debug
= (ata_debugmode
> 1);
2273 if (!ws
.connect()) {
2275 pout("WMI connect failed\n");
2280 if (!ws
.query1(wo
, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2281 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2284 std::string serial
= wo
.get_str("SerialNumber");
2286 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive
, wo
.get_str("Model").c_str(), serial
.c_str());
2288 copy_swapped(id
->serial_no
, serial
.c_str(), sizeof(id
->serial_no
));
2293 /////////////////////////////////////////////////////////////////////////////
2294 // USB ID detection using WMI
2296 // Get USB ID for a physical or logical drive number
2297 static bool get_usb_id(int phydrive
, int logdrive
,
2298 unsigned short & vendor_id
,
2299 unsigned short & product_id
)
2301 bool debug
= (scsi_debugmode
> 1);
2304 if (!ws
.connect()) {
2306 pout("WMI connect failed\n");
2314 if (0 <= logdrive
&& logdrive
<= 'Z'-'A') {
2315 // Drive letter -> Partition info
2316 if (!ws
.query1(wo
, "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"%c:\"} WHERE ResultClass = Win32_DiskPartition",
2320 std::string partid
= wo
.get_str("DeviceID");
2322 pout("%c: --> \"%s\" -->\n", 'A'+logdrive
, partid
.c_str());
2324 // Partition ID -> Physical drive info
2325 if (!ws
.query1(wo
, "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE ResultClass = Win32_DiskDrive",
2329 name
= wo
.get_str("Model");
2331 pout("%s --> \"%s\":\n", wo
.get_str("DeviceID").c_str(), name
.c_str());
2334 else if (phydrive
>= 0) {
2335 // Physical drive number -> Physical drive info
2336 if (!ws
.query1(wo
, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", phydrive
))
2339 name
= wo
.get_str("Model");
2341 pout("\\.\\\\PHYSICALDRIVE%d --> \"%s\":\n", phydrive
, name
.c_str());
2347 // Get USB_CONTROLLER -> DEVICE associations
2349 if (!ws
.query(we
, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2352 unsigned short usb_venid
= 0, prev_usb_venid
= 0;
2353 unsigned short usb_proid
= 0, prev_usb_proid
= 0;
2354 std::string prev_usb_ant
;
2355 std::string prev_ant
, ant
, dep
;
2357 const regular_expression
regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED
);
2359 while (we
.next(wo
)) {
2361 // Find next 'USB_CONTROLLER, DEVICE' pair
2362 ant
= wo
.get_str("Antecedent");
2363 dep
= wo
.get_str("Dependent");
2365 if (debug
&& ant
!= prev_ant
)
2366 pout(" %s:\n", ant
.c_str());
2369 regmatch_t match
[2];
2370 if (!(regex
.execute(dep
.c_str(), 2, match
) && match
[1].rm_so
>= 0)) {
2372 pout(" | (\"%s\")\n", dep
.c_str());
2376 std::string
devid(dep
.c_str()+match
[1].rm_so
, match
[1].rm_eo
-match
[1].rm_so
);
2378 if (str_starts_with(devid
, "USB\\\\VID_")) {
2379 // USB bridge entry, save CONTROLLER, ID
2381 if (!(sscanf(devid
.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2382 &prev_usb_venid
, &prev_usb_proid
, &nc
) == 2 && nc
== 9+4+5+4)) {
2383 prev_usb_venid
= prev_usb_proid
= 0;
2387 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid
.c_str(), prev_usb_venid
, prev_usb_proid
);
2389 else if (str_starts_with(devid
, "USBSTOR\\\\") || str_starts_with(devid
, "SCSI\\\\")) {
2390 // USBSTORage or SCSI device found
2392 pout(" +--> \"%s\"\n", devid
.c_str());
2396 if (!ws
.query1(wo2
, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid
.c_str()))
2398 std::string name2
= wo2
.get_str("Name");
2400 // Continue if not name of physical disk drive
2401 if (name2
!= name
) {
2403 pout(" +---> (\"%s\")\n", name2
.c_str());
2407 // Fail if previous USB bridge is associated to other controller or ID is unknown
2408 if (!(ant
== prev_usb_ant
&& prev_usb_venid
)) {
2410 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2
.c_str());
2414 // Handle multiple devices with same name
2416 // Fail if multiple devices with same name have different USB bridge types
2417 if (!(usb_venid
== prev_usb_venid
&& usb_proid
== prev_usb_proid
)) {
2419 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2
.c_str());
2425 usb_venid
= prev_usb_venid
;
2426 usb_proid
= prev_usb_proid
;
2428 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2
.c_str(), usb_venid
, usb_proid
);
2430 // Continue to check for duplicate names ...
2434 pout(" | \"%s\"\n", devid
.c_str());
2441 vendor_id
= usb_venid
;
2442 product_id
= usb_proid
;
2448 /////////////////////////////////////////////////////////////////////////////
2450 // Call GetDevicePowerState()
2451 // returns: 1=active, 0=standby, -1=error
2452 // (This would also work for SCSI drives)
2454 static int get_device_power_state(HANDLE hdevice
)
2457 if (!GetDevicePowerState(hdevice
, &state
)) {
2458 long err
= GetLastError();
2460 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
2461 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2462 // TODO: This may not work as expected on transient errors,
2463 // because smartd interprets -1 as SLEEP mode regardless of errno.
2467 if (ata_debugmode
> 1)
2468 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
2473 /////////////////////////////////////////////////////////////////////////////
2475 // Get default ATA device options
2477 static const char * ata_get_def_options()
2479 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2480 // STORAGE_*, SCSI_MINIPORT_*
2484 // Common routines for devices with HANDLEs
2486 win_smart_device::~win_smart_device() throw()
2488 if (m_fh
!= INVALID_HANDLE_VALUE
)
2489 ::CloseHandle(m_fh
);
2492 bool win_smart_device::is_open() const
2494 return (m_fh
!= INVALID_HANDLE_VALUE
);
2497 bool win_smart_device::close()
2499 if (m_fh
== INVALID_HANDLE_VALUE
)
2501 BOOL rc
= ::CloseHandle(m_fh
);
2502 m_fh
= INVALID_HANDLE_VALUE
;
2508 win_ata_device::win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
2509 : smart_device(intf
, dev_name
, "ata", req_type
),
2510 m_usr_options(false),
2513 m_id_is_cached(false),
2520 win_ata_device::~win_ata_device() throw()
2527 bool win_ata_device::open()
2529 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
2530 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2531 char drive
[2+1] = "", options
[8+1] = ""; int n1
= -1, n2
= -1;
2532 if ( sscanf(name
, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive
, &n1
, options
, &n2
) >= 1
2533 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2534 return open(sdxy_to_phydrive(drive
), -1, options
, -1);
2536 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2537 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
2539 if ( sscanf(name
, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
2540 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2541 return open(sdxy_to_phydrive(drive
), -1, options
, port
);
2543 // pd<m>,N => Physical drive <m>, RAID port N
2544 int phydrive
= -1; port
= ~0; n1
= -1; n2
= -1;
2545 if ( sscanf(name
, "pd%d%n,%u%n", &phydrive
, &n1
, &port
, &n2
) >= 1
2546 && phydrive
>= 0 && ((n1
== len
&& (int)port
< 0) || (n2
== len
&& port
< 32))) {
2547 return open(phydrive
, -1, "", (int)port
);
2549 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2550 int logdrive
= drive_letter(name
);
2551 if (logdrive
>= 0) {
2552 return open(-1, logdrive
, "", -1);
2555 return set_err(EINVAL
);
2559 bool win_ata_device::open(int phydrive
, int logdrive
, const char * options
, int port
)
2563 if (0 <= phydrive
&& phydrive
<= 255)
2564 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive
= phydrive
));
2565 else if (0 <= logdrive
&& logdrive
<= 'Z'-'A')
2566 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\%c:", 'A'+logdrive
);
2568 return set_err(ENOENT
);
2571 HANDLE h
= INVALID_HANDLE_VALUE
;
2572 if (!(*options
&& !options
[strspn(options
, "fp")])) {
2573 // Open with admin rights
2575 h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
2576 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2577 NULL
, OPEN_EXISTING
, 0, 0);
2579 if (h
== INVALID_HANDLE_VALUE
) {
2580 // Open without admin rights
2582 h
= CreateFileA(devpath
, 0,
2583 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2584 NULL
, OPEN_EXISTING
, 0, 0);
2586 if (h
== INVALID_HANDLE_VALUE
) {
2587 long err
= GetLastError();
2588 if (err
== ERROR_FILE_NOT_FOUND
)
2589 set_err(ENOENT
, "%s: not found", devpath
);
2590 else if (err
== ERROR_ACCESS_DENIED
)
2591 set_err(EACCES
, "%s: access denied", devpath
);
2593 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
2598 // Warn once if admin rights are missing
2600 static bool noadmin_warning
= false;
2601 if (!noadmin_warning
) {
2602 pout("Warning: Limited functionality due to missing admin rights\n");
2603 noadmin_warning
= true;
2607 if (ata_debugmode
> 1)
2608 pout("%s: successfully opened%s\n", devpath
, (!m_admin
? " (without admin rights)" :""));
2610 m_usr_options
= false;
2612 // Save user options
2613 m_options
= options
; m_usr_options
= true;
2616 // RAID: SMART_* and SCSI_MINIPORT
2619 // Set default options according to Windows version
2620 static const char * def_options
= ata_get_def_options();
2621 m_options
= def_options
;
2624 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2629 // 3ware RAID: Get port map
2630 GETVERSIONINPARAMS_EX vers_ex
;
2631 int devmap
= smart_get_version(h
, &vers_ex
);
2633 // 3ware RAID if vendor id present
2634 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2636 unsigned long portmap
= 0;
2637 if (port
>= 0 && devmap
>= 0) {
2638 // 3ware RAID: check vendor id
2640 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2641 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2642 vers_ex
.wIdentifier
);
2646 portmap
= vers_ex
.dwDeviceMapEx
;
2649 pout("%s: ATA driver has no SMART support\n", devpath
);
2650 if (!is_permissive()) {
2652 return set_err(ENOSYS
);
2655 m_smartver_state
= 1;
2658 // 3ware RAID: update devicemap first
2660 if (!update_3ware_devicemap_ioctl(h
)) {
2661 if ( smart_get_version(h
, &vers_ex
) >= 0
2662 && vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
2663 portmap
= vers_ex
.dwDeviceMapEx
;
2665 // Check port existence
2666 if (!(portmap
& (1L << port
))) {
2667 if (!is_permissive()) {
2669 return set_err(ENOENT
, "%s: Port %d is empty or does not exist", devpath
, port
);
2678 /////////////////////////////////////////////////////////////////////////////
2680 // Interface to ATA devices
2681 bool win_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2683 // No multi-sector support for now, see above
2684 // warning about IOCTL_ATA_PASS_THROUGH
2685 if (!ata_cmd_is_supported(in
,
2686 ata_device::supports_data_out
|
2687 ata_device::supports_output_regs
|
2688 ata_device::supports_48bit
)
2692 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2693 if ( m_is_3ware
&& m_port
< 0
2694 && in
.in_regs
.command
== ATA_SMART_CMD
2695 && in
.in_regs
.features
== ATA_SMART_DISABLE
)
2696 return set_err(ENOSYS
, "SMART DISABLE requires 3ware port number");
2698 // Determine ioctl functions valid for this ATA cmd
2699 const char * valid_options
= 0;
2701 switch (in
.in_regs
.command
) {
2702 case ATA_IDENTIFY_DEVICE
:
2703 case ATA_IDENTIFY_PACKET_DEVICE
:
2704 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2705 // and SCSI_MINIPORT_* if requested by user
2706 valid_options
= (m_usr_options
? "saimf" : "saif");
2709 case ATA_CHECK_POWER_MODE
:
2710 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2711 valid_options
= "pai3";
2715 switch (in
.in_regs
.features
) {
2716 case ATA_SMART_READ_VALUES
:
2717 case ATA_SMART_READ_THRESHOLDS
:
2718 case ATA_SMART_AUTOSAVE
:
2719 case ATA_SMART_ENABLE
:
2720 case ATA_SMART_DISABLE
:
2721 case ATA_SMART_AUTO_OFFLINE
:
2722 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2723 // and SCSI_MINIPORT_* if requested by user
2724 valid_options
= (m_usr_options
? "saimf" : "saif");
2727 case ATA_SMART_IMMEDIATE_OFFLINE
:
2728 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2729 valid_options
= (m_usr_options
|| in
.in_regs
.lba_low
!= 127/*ABORT*/ ?
2733 case ATA_SMART_READ_LOG_SECTOR
:
2734 // SMART_RCV_DRIVE_DATA does not support READ_LOG
2735 // Try SCSI_MINIPORT also to skip buggy class driver
2736 // SMART functions do not support multi sector I/O.
2738 valid_options
= (m_usr_options
? "saim3" : "aim3");
2740 valid_options
= "a";
2743 case ATA_SMART_WRITE_LOG_SECTOR
:
2744 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2745 // but SCSI_MINIPORT_* only if requested by user and single sector.
2746 valid_options
= (in
.size
== 512 && m_usr_options
? "am" : "a");
2749 case ATA_SMART_STATUS
:
2750 valid_options
= (m_usr_options
? "saimf" : "saif");
2754 // Unknown SMART command, handle below
2760 // Other ATA command, handle below
2764 if (!valid_options
) {
2765 // No special ATA command found above, select a generic pass through ioctl.
2766 if (!( in
.direction
== ata_cmd_in::no_data
2767 || (in
.direction
== ata_cmd_in::data_in
&& in
.size
== 512))
2768 || in
.in_regs
.is_48bit_cmd() )
2769 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2770 valid_options
= "a";
2772 // ATA/IDE_PASS_THROUGH
2773 valid_options
= "ai";
2777 // Restrict to IOCTL_STORAGE_*
2778 if (strchr(valid_options
, 'f'))
2779 valid_options
= "f";
2780 else if (strchr(valid_options
, 'p'))
2781 valid_options
= "p";
2783 return set_err(ENOSYS
, "Function requires admin rights");
2787 IDEREGS regs
, prev_regs
;
2789 const ata_in_regs
& lo
= in
.in_regs
;
2790 regs
.bFeaturesReg
= lo
.features
;
2791 regs
.bSectorCountReg
= lo
.sector_count
;
2792 regs
.bSectorNumberReg
= lo
.lba_low
;
2793 regs
.bCylLowReg
= lo
.lba_mid
;
2794 regs
.bCylHighReg
= lo
.lba_high
;
2795 regs
.bDriveHeadReg
= lo
.device
;
2796 regs
.bCommandReg
= lo
.command
;
2799 if (in
.in_regs
.is_48bit_cmd()) {
2800 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2801 prev_regs
.bFeaturesReg
= hi
.features
;
2802 prev_regs
.bSectorCountReg
= hi
.sector_count
;
2803 prev_regs
.bSectorNumberReg
= hi
.lba_low
;
2804 prev_regs
.bCylLowReg
= hi
.lba_mid
;
2805 prev_regs
.bCylHighReg
= hi
.lba_high
;
2806 prev_regs
.bDriveHeadReg
= hi
.device
;
2807 prev_regs
.bCommandReg
= hi
.command
;
2808 prev_regs
.bReserved
= 0;
2811 // Set data direction
2814 switch (in
.direction
) {
2815 case ata_cmd_in::no_data
:
2817 case ata_cmd_in::data_in
:
2818 datasize
= (int)in
.size
;
2819 data
= (char *)in
.buffer
;
2821 case ata_cmd_in::data_out
:
2822 datasize
= -(int)in
.size
;
2823 data
= (char *)in
.buffer
;
2826 return set_err(EINVAL
, "win_ata_device::ata_pass_through: invalid direction=%d",
2831 // Try all valid ioctls in the order specified in m_options
2832 bool powered_up
= false;
2833 bool out_regs_set
= false;
2834 bool id_is_cached
= false;
2835 const char * options
= m_options
.c_str();
2837 for (int i
= 0; ; i
++) {
2838 char opt
= options
[i
];
2841 if (in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& powered_up
) {
2842 // Power up reported by GetDevicePowerState() and no ioctl available
2843 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2844 regs
.bSectorCountReg
= 0xff;
2845 out_regs_set
= true;
2849 return set_err(ENOSYS
);
2851 if (!strchr(valid_options
, opt
))
2852 // Invalid for this command
2856 assert( datasize
== 0 || datasize
== 512
2857 || (datasize
== -512 && strchr("am", opt
))
2858 || (datasize
> 512 && opt
== 'a'));
2863 // call SMART_GET_VERSION once for each drive
2864 if (m_smartver_state
> 1) {
2865 rc
= -1; errno
= ENOSYS
;
2868 if (!m_smartver_state
) {
2869 assert(m_port
== -1);
2870 GETVERSIONINPARAMS_EX vers_ex
;
2871 if (smart_get_version(get_fh(), &vers_ex
) < 0) {
2872 if (!failuretest_permissive
) {
2873 m_smartver_state
= 2;
2874 rc
= -1; errno
= ENOSYS
;
2877 failuretest_permissive
--;
2880 // 3ware RAID if vendor id present
2881 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2884 m_smartver_state
= 1;
2886 rc
= smart_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2887 out_regs_set
= (in
.in_regs
.features
== ATA_SMART_STATUS
);
2888 id_is_cached
= (m_port
< 0); // Not cached by 3ware driver
2891 rc
= ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s
, data
, datasize
);
2892 id_is_cached
= (m_port
< 0);
2895 rc
= ata_pass_through_ioctl(get_fh(), ®s
,
2896 (in
.in_regs
.is_48bit_cmd() ? &prev_regs
: 0),
2898 out_regs_set
= true;
2901 rc
= ide_pass_through_ioctl(get_fh(), ®s
, data
, datasize
);
2902 out_regs_set
= true;
2905 if (in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
) {
2906 ata_identify_device
* id
= reinterpret_cast<ata_identify_device
*>(data
);
2907 rc
= get_identify_from_device_property(get_fh(), id
);
2908 if (rc
== 0 && m_phydrive
>= 0)
2909 get_serial_from_wmi(m_phydrive
, id
);
2910 id_is_cached
= true;
2912 else if (in
.in_regs
.command
== ATA_SMART_CMD
) switch (in
.in_regs
.features
) {
2913 case ATA_SMART_READ_VALUES
:
2914 rc
= storage_predict_failure_ioctl(get_fh(), data
);
2918 case ATA_SMART_ENABLE
:
2921 case ATA_SMART_STATUS
:
2922 rc
= storage_predict_failure_ioctl(get_fh());
2924 // Good SMART status
2925 out
.out_regs
.lba_high
= 0xc2; out
.out_regs
.lba_mid
= 0x4f;
2929 out
.out_regs
.lba_high
= 0x2c; out
.out_regs
.lba_mid
= 0xf4;
2934 errno
= ENOSYS
; rc
= -1;
2937 errno
= ENOSYS
; rc
= -1;
2941 rc
= ata_via_3ware_miniport_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2942 out_regs_set
= true;
2945 assert(in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& in
.size
== 0);
2946 rc
= get_device_power_state(get_fh());
2948 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2949 // spin up the drive => simulate ATA result STANDBY.
2950 regs
.bSectorCountReg
= 0x00;
2951 out_regs_set
= true;
2954 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2955 // only if it is selected by the device driver => try a passthrough ioctl to get the
2956 // actual mode, if none available simulate ACTIVE/IDLE.
2958 rc
= -1; errno
= ENOSYS
;
2964 // Working ioctl found
2967 if (errno
!= ENOSYS
)
2968 // Abort on I/O error
2969 return set_err(errno
);
2971 out_regs_set
= false;
2972 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2975 // Return IDEREGS if set
2977 ata_out_regs
& lo
= out
.out_regs
;
2978 lo
.error
= regs
.bFeaturesReg
;
2979 lo
.sector_count
= regs
.bSectorCountReg
;
2980 lo
.lba_low
= regs
.bSectorNumberReg
;
2981 lo
.lba_mid
= regs
.bCylLowReg
;
2982 lo
.lba_high
= regs
.bCylHighReg
;
2983 lo
.device
= regs
.bDriveHeadReg
;
2984 lo
.status
= regs
.bCommandReg
;
2985 if (in
.in_regs
.is_48bit_cmd()) {
2986 ata_out_regs
& hi
= out
.out_regs
.prev
;
2987 hi
.sector_count
= prev_regs
.bSectorCountReg
;
2988 hi
.lba_low
= prev_regs
.bSectorNumberReg
;
2989 hi
.lba_mid
= prev_regs
.bCylLowReg
;
2990 hi
.lba_high
= prev_regs
.bCylHighReg
;
2994 if ( in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
2995 || in
.in_regs
.command
== ATA_IDENTIFY_PACKET_DEVICE
)
2996 // Update ata_identify_is_cached() result according to ioctl used.
2997 m_id_is_cached
= id_is_cached
;
3002 // Return true if OS caches the ATA identify sector
3003 bool win_ata_device::ata_identify_is_cached() const
3005 return m_id_is_cached
;
3009 //////////////////////////////////////////////////////////////////////
3012 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
)
3014 // Get driver info to check CSMI support
3015 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf
;
3016 memset(&driver_info_buf
, 0, sizeof(driver_info_buf
));
3017 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO
, &driver_info_buf
.IoctlHeader
, sizeof(driver_info_buf
)))
3020 if (scsi_debugmode
> 1) {
3021 const CSMI_SAS_DRIVER_INFO
& driver_info
= driver_info_buf
.Information
;
3022 pout("CSMI_SAS_DRIVER_INFO:\n");
3023 pout(" Name: \"%.81s\"\n", driver_info
.szName
);
3024 pout(" Description: \"%.81s\"\n", driver_info
.szDescription
);
3025 pout(" Revision: %d.%d\n", driver_info
.usMajorRevision
, driver_info
.usMinorRevision
);
3029 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf
;
3030 memset(&phy_info_buf
, 0, sizeof(phy_info_buf
));
3031 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO
, &phy_info_buf
.IoctlHeader
, sizeof(phy_info_buf
)))
3034 phy_info
= phy_info_buf
.Information
;
3036 const int max_number_of_phys
= sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]);
3037 if (phy_info
.bNumberOfPhys
> max_number_of_phys
)
3038 return set_err(EIO
, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info
.bNumberOfPhys
);
3040 if (scsi_debugmode
> 1) {
3041 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info
.bNumberOfPhys
);
3042 for (int i
= 0; i
< max_number_of_phys
; i
++) {
3043 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3044 const CSMI_SAS_IDENTIFY
& id
= pe
.Identify
, & at
= pe
.Attached
;
3045 if (id
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3048 pout("Phy[%d] Port: 0x%02x\n", i
, pe
.bPortIdentifier
);
3049 pout(" Type: 0x%02x, 0x%02x\n", id
.bDeviceType
, at
.bDeviceType
);
3050 pout(" InitProto: 0x%02x, 0x%02x\n", id
.bInitiatorPortProtocol
, at
.bInitiatorPortProtocol
);
3051 pout(" TargetProto: 0x%02x, 0x%02x\n", id
.bTargetPortProtocol
, at
.bTargetPortProtocol
);
3052 pout(" PhyIdent: 0x%02x, 0x%02x\n", id
.bPhyIdentifier
, at
.bPhyIdentifier
);
3053 const unsigned char * b
= id
.bSASAddress
;
3054 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
3055 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
3057 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
3058 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
3065 unsigned csmi_device::get_ports_used()
3067 CSMI_SAS_PHY_INFO phy_info
;
3068 if (!get_phy_info(phy_info
))
3071 unsigned ports_used
= 0;
3072 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
3073 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3074 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3076 if (pe
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3078 switch (pe
.Attached
.bTargetPortProtocol
) {
3079 case CSMI_SAS_PROTOCOL_SATA
:
3080 case CSMI_SAS_PROTOCOL_STP
:
3086 if (pe
.bPortIdentifier
== 0xff)
3087 // Older (<= 9.*) Intel RST driver
3088 ports_used
|= (1 << i
);
3090 ports_used
|= (1 << pe
.bPortIdentifier
);
3097 bool csmi_device::select_port(int port
)
3099 CSMI_SAS_PHY_INFO phy_info
;
3100 if (!get_phy_info(phy_info
))
3104 int max_port
= -1, port_index
= -1;
3105 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
3106 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3107 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3110 if (pe
.bPortIdentifier
== 0xff) {
3111 // Older (<= 9.*) Intel RST driver
3112 max_port
= phy_info
.bNumberOfPhys
- 1;
3113 if (i
>= phy_info
.bNumberOfPhys
)
3119 if (pe
.bPortIdentifier
> max_port
)
3120 max_port
= pe
.bPortIdentifier
;
3121 if (pe
.bPortIdentifier
!= port
)
3129 if (port_index
< 0) {
3130 if (port
<= max_port
)
3131 return set_err(ENOENT
, "Port %d is disabled", port
);
3133 return set_err(ENOENT
, "Port %d does not exist (#ports: %d)", port
,
3137 const CSMI_SAS_PHY_ENTITY
& phy_ent
= phy_info
.Phy
[port_index
];
3138 if (phy_ent
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3139 return set_err(ENOENT
, "No device on port %d", port
);
3141 switch (phy_ent
.Attached
.bTargetPortProtocol
) {
3142 case CSMI_SAS_PROTOCOL_SATA
:
3143 case CSMI_SAS_PROTOCOL_STP
:
3146 return set_err(ENOENT
, "No SATA device on port %d (protocol: %d)",
3147 port
, phy_ent
.Attached
.bTargetPortProtocol
);
3150 m_phy_ent
= phy_ent
;
3155 bool csmi_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
3157 if (!ata_cmd_is_supported(in
,
3158 ata_device::supports_data_out
|
3159 ata_device::supports_output_regs
|
3160 ata_device::supports_multi_sector
|
3161 ata_device::supports_48bit
,
3166 // Create buffer with appropriate size
3167 raw_buffer
pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER
) + in
.size
);
3168 CSMI_SAS_STP_PASSTHRU_BUFFER
* pthru_buf
= (CSMI_SAS_STP_PASSTHRU_BUFFER
*)pthru_raw_buf
.data();
3170 // Set addresses from Phy info
3171 CSMI_SAS_STP_PASSTHRU
& pthru
= pthru_buf
->Parameters
;
3172 const CSMI_SAS_PHY_ENTITY
& phy_ent
= get_phy_ent();
3173 pthru
.bPhyIdentifier
= phy_ent
.Identify
.bPhyIdentifier
;
3174 pthru
.bPortIdentifier
= phy_ent
.bPortIdentifier
;
3175 memcpy(pthru
.bDestinationSASAddress
, phy_ent
.Attached
.bSASAddress
,
3176 sizeof(pthru
.bDestinationSASAddress
));
3177 pthru
.bConnectionRate
= CSMI_SAS_LINK_RATE_NEGOTIATED
;
3179 // Set transfer mode
3180 switch (in
.direction
) {
3181 case ata_cmd_in::no_data
:
3182 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_UNSPECIFIED
;
3184 case ata_cmd_in::data_in
:
3185 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_READ
;
3186 pthru
.uDataLength
= in
.size
;
3188 case ata_cmd_in::data_out
:
3189 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_WRITE
;
3190 pthru
.uDataLength
= in
.size
;
3191 memcpy(pthru_buf
->bDataBuffer
, in
.buffer
, in
.size
);
3194 return set_err(EINVAL
, "csmi_ata_device::ata_pass_through: invalid direction=%d",
3198 // Set host-to-device FIS
3200 unsigned char * fis
= pthru
.bCommandFIS
;
3201 const ata_in_regs
& lo
= in
.in_regs
;
3202 const ata_in_regs
& hi
= in
.in_regs
.prev
;
3203 fis
[ 0] = 0x27; // Type: host-to-device FIS
3204 fis
[ 1] = 0x80; // Bit7: Update command register
3205 fis
[ 2] = lo
.command
;
3206 fis
[ 3] = lo
.features
;
3207 fis
[ 4] = lo
.lba_low
;
3208 fis
[ 5] = lo
.lba_mid
;
3209 fis
[ 6] = lo
.lba_high
;
3210 fis
[ 7] = lo
.device
;
3211 fis
[ 8] = hi
.lba_low
;
3212 fis
[ 9] = hi
.lba_mid
;
3213 fis
[10] = hi
.lba_high
;
3214 fis
[11] = hi
.features
;
3215 fis
[12] = lo
.sector_count
;
3216 fis
[13] = hi
.sector_count
;
3220 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU
, &pthru_buf
->IoctlHeader
, pthru_raw_buf
.size())) {
3224 // Get device-to-host FIS
3226 const unsigned char * fis
= pthru_buf
->Status
.bStatusFIS
;
3227 ata_out_regs
& lo
= out
.out_regs
;
3228 lo
.status
= fis
[ 2];
3230 lo
.lba_low
= fis
[ 4];
3231 lo
.lba_mid
= fis
[ 5];
3232 lo
.lba_high
= fis
[ 6];
3233 lo
.device
= fis
[ 7];
3234 lo
.sector_count
= fis
[12];
3235 if (in
.in_regs
.is_48bit_cmd()) {
3236 ata_out_regs
& hi
= out
.out_regs
.prev
;
3237 hi
.lba_low
= fis
[ 8];
3238 hi
.lba_mid
= fis
[ 9];
3239 hi
.lba_high
= fis
[10];
3240 hi
.sector_count
= fis
[13];
3245 if (in
.direction
== ata_cmd_in::data_in
)
3246 // TODO: Check ptru_buf->Status.uDataBytes
3247 memcpy(in
.buffer
, pthru_buf
->bDataBuffer
, in
.size
);
3253 //////////////////////////////////////////////////////////////////////
3256 win_csmi_device::win_csmi_device(smart_interface
* intf
, const char * dev_name
,
3257 const char * req_type
)
3258 : smart_device(intf
, dev_name
, "ata", req_type
),
3259 m_fh(INVALID_HANDLE_VALUE
), m_port(-1)
3263 win_csmi_device::~win_csmi_device() throw()
3265 if (m_fh
!= INVALID_HANDLE_VALUE
)
3269 bool win_csmi_device::is_open() const
3271 return (m_fh
!= INVALID_HANDLE_VALUE
);
3274 bool win_csmi_device::close()
3276 if (m_fh
== INVALID_HANDLE_VALUE
)
3278 BOOL rc
= CloseHandle(m_fh
);
3279 m_fh
= INVALID_HANDLE_VALUE
;
3284 bool win_csmi_device::open_scsi()
3287 unsigned contr_no
= ~0, port
= ~0; int nc
= -1;
3288 const char * name
= skipdev(get_dev_name());
3289 if (!( sscanf(name
, "csmi%u,%u%n", &contr_no
, &port
, &nc
) >= 0
3290 && nc
== (int)strlen(name
) && contr_no
<= 9 && port
< 32) )
3291 return set_err(EINVAL
);
3293 // Open controller handle
3295 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\Scsi%u:", contr_no
);
3297 HANDLE h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
3298 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3299 (SECURITY_ATTRIBUTES
*)0, OPEN_EXISTING
, 0, 0);
3301 if (h
== INVALID_HANDLE_VALUE
) {
3302 long err
= GetLastError();
3303 if (err
== ERROR_FILE_NOT_FOUND
)
3304 set_err(ENOENT
, "%s: not found", devpath
);
3305 else if (err
== ERROR_ACCESS_DENIED
)
3306 set_err(EACCES
, "%s: access denied", devpath
);
3308 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
3312 if (scsi_debugmode
> 1)
3313 pout(" %s: successfully opened\n", devpath
);
3321 bool win_csmi_device::open()
3326 // Get Phy info for this drive
3327 if (!select_port(m_port
)) {
3336 bool win_csmi_device::csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
3337 unsigned csmi_bufsiz
)
3339 // Determine signature
3342 case CC_CSMI_SAS_GET_DRIVER_INFO
:
3343 sig
= CSMI_ALL_SIGNATURE
; break;
3344 case CC_CSMI_SAS_GET_PHY_INFO
:
3345 case CC_CSMI_SAS_STP_PASSTHRU
:
3346 sig
= CSMI_SAS_SIGNATURE
; break;
3348 return set_err(ENOSYS
, "Unknown CSMI code=%u", code
);
3352 csmi_buffer
->HeaderLength
= sizeof(IOCTL_HEADER
);
3353 strncpy((char *)csmi_buffer
->Signature
, sig
, sizeof(csmi_buffer
->Signature
));
3354 csmi_buffer
->Timeout
= CSMI_SAS_TIMEOUT
;
3355 csmi_buffer
->ControlCode
= code
;
3356 csmi_buffer
->ReturnCode
= 0;
3357 csmi_buffer
->Length
= csmi_bufsiz
- sizeof(IOCTL_HEADER
);
3361 if (!DeviceIoControl(m_fh
, IOCTL_SCSI_MINIPORT
,
3362 csmi_buffer
, csmi_bufsiz
, csmi_buffer
, csmi_bufsiz
, &num_out
, (OVERLAPPED
*)0)) {
3363 long err
= GetLastError();
3365 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code
, err
);
3366 if ( err
== ERROR_INVALID_FUNCTION
3367 || err
== ERROR_NOT_SUPPORTED
3368 || err
== ERROR_DEV_NOT_EXIST
)
3369 return set_err(ENOSYS
, "CSMI is not supported (Error=%ld)", err
);
3371 return set_err(EIO
, "CSMI(%u) failed with Error=%ld", code
, err
);
3375 if (csmi_buffer
->ReturnCode
) {
3376 if (scsi_debugmode
) {
3377 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3378 code
, (unsigned)csmi_buffer
->ReturnCode
);
3380 return set_err(EIO
, "CSMI(%u) failed with ReturnCode=%u", code
, (unsigned)csmi_buffer
->ReturnCode
);
3383 if (scsi_debugmode
> 1)
3384 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code
, (unsigned)num_out
);
3390 /////////////////////////////////////////////////////////////////////////////
3391 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3392 // Only supported in NT and later
3393 /////////////////////////////////////////////////////////////////////////////
3395 win_scsi_device::win_scsi_device(smart_interface
* intf
,
3396 const char * dev_name
, const char * req_type
)
3397 : smart_device(intf
, dev_name
, "scsi", req_type
)
3401 bool win_scsi_device::open()
3403 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
3404 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3405 char drive
[2+1] = ""; int sub_addr
= -1; int n1
= -1; int n2
= -1;
3406 if ( sscanf(name
, "sd%2[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
3407 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
3408 return open(sdxy_to_phydrive(drive
), -1, -1, sub_addr
);
3410 // pd<m>,N => Physical drive <m>, RAID port N
3411 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
3412 if ( sscanf(name
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
3413 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
3414 return open(pd_num
, -1, -1, sub_addr
);
3416 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3417 int logdrive
= drive_letter(name
);
3418 if (logdrive
>= 0) {
3419 return open(-1, logdrive
, -1, -1);
3421 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3422 int tape_num
= -1; n1
= -1;
3423 if (sscanf(name
, "st%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3424 return open(-1, -1, tape_num
, -1);
3426 tape_num
= -1; n1
= -1;
3427 if (sscanf(name
, "nst%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3428 return open(-1, -1, tape_num
, -1);
3430 // tape<m> => tape drive <m>
3431 tape_num
= -1; n1
= -1;
3432 if (sscanf(name
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3433 return open(-1, -1, tape_num
, -1);
3436 return set_err(EINVAL
);
3439 bool win_scsi_device::open(int pd_num
, int ld_num
, int tape_num
, int /*sub_addr*/)
3442 b
[sizeof(b
) - 1] = '\0';
3444 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
3445 else if (ld_num
>= 0)
3446 snprintf(b
, sizeof(b
) - 1, "\\\\.\\%c:", 'A' + ld_num
);
3447 else if (tape_num
>= 0)
3448 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
3455 HANDLE h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
3456 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
3457 OPEN_EXISTING
, 0, 0);
3458 if (h
== INVALID_HANDLE_VALUE
) {
3459 set_err(ENODEV
, "%s: Open failed, Error=%u", b
, (unsigned)GetLastError());
3468 SCSI_PASS_THROUGH_DIRECT spt
;
3470 UCHAR ucSenseBuf
[64];
3471 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
3474 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3475 // Used if DataTransferLength not supported by *_DIRECT.
3476 static long scsi_pass_through_indirect(HANDLE h
,
3477 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
* sbd
)
3479 struct SCSI_PASS_THROUGH_WITH_BUFFERS
{
3480 SCSI_PASS_THROUGH spt
;
3482 UCHAR ucSenseBuf
[sizeof(sbd
->ucSenseBuf
)];
3483 UCHAR ucDataBuf
[512];
3486 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
3487 memset(&sb
, 0, sizeof(sb
));
3489 // DATA_OUT not implemented yet
3490 if (!( sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
3491 && sbd
->spt
.DataTransferLength
<= sizeof(sb
.ucDataBuf
)))
3492 return ERROR_INVALID_PARAMETER
;
3494 sb
.spt
.Length
= sizeof(sb
.spt
);
3495 sb
.spt
.CdbLength
= sbd
->spt
.CdbLength
;
3496 memcpy(sb
.spt
.Cdb
, sbd
->spt
.Cdb
, sizeof(sb
.spt
.Cdb
));
3497 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3498 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
3499 sb
.spt
.DataIn
= sbd
->spt
.DataIn
;
3500 sb
.spt
.DataTransferLength
= sbd
->spt
.DataTransferLength
;
3501 sb
.spt
.DataBufferOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
3502 sb
.spt
.TimeOutValue
= sbd
->spt
.TimeOutValue
;
3505 if (!DeviceIoControl(h
, IOCTL_SCSI_PASS_THROUGH
,
3506 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3507 return GetLastError();
3509 sbd
->spt
.ScsiStatus
= sb
.spt
.ScsiStatus
;
3510 if (sb
.spt
.ScsiStatus
& SCSI_STATUS_CHECK_CONDITION
)
3511 memcpy(sbd
->ucSenseBuf
, sb
.ucSenseBuf
, sizeof(sbd
->ucSenseBuf
));
3513 sbd
->spt
.DataTransferLength
= sb
.spt
.DataTransferLength
;
3514 if (sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
&& sb
.spt
.DataTransferLength
> 0)
3515 memcpy(sbd
->spt
.DataBuffer
, sb
.ucDataBuf
, sb
.spt
.DataTransferLength
);
3520 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3521 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io
* iop
)
3523 int report
= scsi_debugmode
; // TODO
3527 const unsigned char * ucp
= iop
->cmnd
;
3530 const int sz
= (int)sizeof(buff
);
3532 np
= scsi_get_opcode_name(ucp
[0]);
3533 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3534 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3535 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3537 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3538 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3540 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3541 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3542 (trunc
? " [only first 256 bytes shown]" : ""));
3543 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3546 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3550 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3551 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3552 set_err(EINVAL
, "cmnd_len too large");
3556 memset(&sb
, 0, sizeof(sb
));
3557 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3558 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3559 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3560 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3561 sb
.spt
.SenseInfoOffset
=
3562 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3563 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3566 switch (iop
->dxfer_dir
) {
3568 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3570 case DXFER_FROM_DEVICE
:
3571 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3572 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3573 sb
.spt
.DataBuffer
= iop
->dxferp
;
3574 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3575 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3576 if (sb
.spt
.DataTransferLength
== 1)
3579 case DXFER_TO_DEVICE
:
3580 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3581 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3582 sb
.spt
.DataBuffer
= iop
->dxferp
;
3585 set_err(EINVAL
, "bad dxfer_dir");
3592 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3593 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3594 err
= GetLastError();
3597 err
= scsi_pass_through_indirect(get_fh(), &sb
);
3600 return set_err((err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
),
3601 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3602 (direct
? "_DIRECT" : ""), err
);
3604 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3605 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3606 int slen
= sb
.ucSenseBuf
[7] + 8;
3608 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3609 slen
= sizeof(sb
.ucSenseBuf
);
3610 if (slen
> (int)iop
->max_sense_len
)
3611 slen
= iop
->max_sense_len
;
3612 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3613 iop
->resp_sense_len
= slen
;
3616 pout(" >>> Sense buffer, len=%d:\n", slen
);
3617 dStrHex(iop
->sensep
, slen
, 1);
3619 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3620 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3621 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3622 iop
->sensep
[2], iop
->sensep
[3]);
3624 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3625 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3626 iop
->sensep
[12], iop
->sensep
[13]);
3629 iop
->resp_sense_len
= 0;
3631 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3632 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3636 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3637 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3638 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3639 (trunc
? " [only first 256 bytes shown]" : ""));
3640 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3645 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3646 static long scsi_pass_through_direct(HANDLE fd
, UCHAR targetid
, struct scsi_cmnd_io
* iop
)
3648 int report
= scsi_debugmode
; // TODO
3652 const unsigned char * ucp
= iop
->cmnd
;
3655 const int sz
= (int)sizeof(buff
);
3657 np
= scsi_get_opcode_name(ucp
[0]);
3658 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3659 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3660 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3662 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3663 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3665 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3666 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3667 (trunc
? " [only first 256 bytes shown]" : ""));
3668 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3671 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3675 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3676 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3680 memset(&sb
, 0, sizeof(sb
));
3681 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3682 //sb.spt.PathId = 0;
3683 sb
.spt
.TargetId
= targetid
;
3685 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3686 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3687 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3688 sb
.spt
.SenseInfoOffset
=
3689 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3690 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3693 switch (iop
->dxfer_dir
) {
3695 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3697 case DXFER_FROM_DEVICE
:
3698 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3699 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3700 sb
.spt
.DataBuffer
= iop
->dxferp
;
3701 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3702 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3703 if (sb
.spt
.DataTransferLength
== 1)
3706 case DXFER_TO_DEVICE
:
3707 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3708 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3709 sb
.spt
.DataBuffer
= iop
->dxferp
;
3718 if (!DeviceIoControl(fd
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3719 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3720 err
= GetLastError();
3723 err
= scsi_pass_through_indirect(fd
, &sb
);
3730 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3731 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3732 int slen
= sb
.ucSenseBuf
[7] + 8;
3734 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3735 slen
= sizeof(sb
.ucSenseBuf
);
3736 if (slen
> (int)iop
->max_sense_len
)
3737 slen
= iop
->max_sense_len
;
3738 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3739 iop
->resp_sense_len
= slen
;
3742 pout(" >>> Sense buffer, len=%d:\n", slen
);
3743 dStrHex(iop
->sensep
, slen
, 1);
3745 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3746 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3747 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3748 iop
->sensep
[2], iop
->sensep
[3]);
3750 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3751 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3752 iop
->sensep
[12], iop
->sensep
[13]);
3755 iop
->resp_sense_len
= 0;
3757 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3758 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3762 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3763 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3764 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3765 (trunc
? " [only first 256 bytes shown]" : ""));
3766 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3772 // Areca RAID Controller(SAS Device)
3773 win_areca_scsi_device::win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3774 : smart_device(intf
, dev_name
, "areca", "areca")
3776 set_fh(INVALID_HANDLE_VALUE
);
3777 set_disknum(disknum
);
3779 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3782 bool win_areca_scsi_device::open()
3790 hFh
= CreateFile( get_dev_name(),
3791 GENERIC_READ
|GENERIC_WRITE
,
3792 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3797 if(hFh
== INVALID_HANDLE_VALUE
)
3806 smart_device
* win_areca_scsi_device::autodetect_open()
3811 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3813 int ioctlreturn
= 0;
3815 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3816 if ( ioctlreturn
|| iop
->scsi_status
)
3818 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3819 if ( ioctlreturn
|| iop
->scsi_status
)
3829 bool win_areca_scsi_device::arcmsr_lock()
3831 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3835 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3836 return set_err(EINVAL
, "unable to parse device name");
3838 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3839 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3840 if ( m_mutex
== NULL
)
3842 return set_err(EIO
, "CreateMutex failed");
3845 // atomic access to driver
3846 WaitForSingleObject(m_mutex
, INFINITE
);
3852 bool win_areca_scsi_device::arcmsr_unlock()
3854 if( m_mutex
!= NULL
)
3856 ReleaseMutex(m_mutex
);
3857 CloseHandle(m_mutex
);
3864 // Areca RAID Controller(SATA Disk)
3865 win_areca_ata_device::win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3866 : smart_device(intf
, dev_name
, "areca", "areca")
3868 set_fh(INVALID_HANDLE_VALUE
);
3869 set_disknum(disknum
);
3871 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3874 bool win_areca_ata_device::open()
3882 hFh
= CreateFile( get_dev_name(),
3883 GENERIC_READ
|GENERIC_WRITE
,
3884 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3889 if(hFh
== INVALID_HANDLE_VALUE
)
3898 smart_device
* win_areca_ata_device::autodetect_open()
3900 // autodetect device type
3901 int is_ata
= arcmsr_get_dev_type();
3915 smart_device_auto_ptr
newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
3918 newdev
->open(); // TODO: Can possibly pass open fd
3920 return newdev
.release();
3923 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3925 int ioctlreturn
= 0;
3927 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3928 if ( ioctlreturn
|| iop
->scsi_status
)
3930 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3931 if ( ioctlreturn
|| iop
->scsi_status
)
3941 bool win_areca_ata_device::arcmsr_lock()
3943 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3947 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3948 return set_err(EINVAL
, "unable to parse device name");
3950 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3951 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3952 if ( m_mutex
== NULL
)
3954 return set_err(EIO
, "CreateMutex failed");
3957 // atomic access to driver
3958 WaitForSingleObject(m_mutex
, INFINITE
);
3964 bool win_areca_ata_device::arcmsr_unlock()
3966 if( m_mutex
!= NULL
)
3968 ReleaseMutex(m_mutex
);
3969 CloseHandle(m_mutex
);
3976 win_aacraid_device::win_aacraid_device(smart_interface
* intf
,
3977 const char *dev_name
, unsigned ctrnum
, unsigned target
, unsigned lun
)
3978 : smart_device(intf
, dev_name
, "aacraid", "aacraid"),
3979 m_ctrnum(ctrnum
), m_lun(lun
), m_target(target
)
3981 set_info().info_name
= strprintf("%s [aacraid_disk_%02d_%02d_%d]", dev_name
, m_ctrnum
, m_lun
, m_target
);
3982 set_info().dev_type
= strprintf("aacraid,%d,%d,%d", m_ctrnum
, m_lun
, m_target
);
3985 win_aacraid_device::~win_aacraid_device() throw()
3989 bool win_aacraid_device::open()
3994 HANDLE hFh
= CreateFile( get_dev_name(),
3995 GENERIC_READ
|GENERIC_WRITE
,
3996 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
4001 if (hFh
== INVALID_HANDLE_VALUE
)
4002 return set_err(ENODEV
, "Open failed, Error=%u", (unsigned)GetLastError());
4008 bool win_aacraid_device::scsi_pass_through(struct scsi_cmnd_io
*iop
)
4010 int report
= scsi_debugmode
;
4014 const unsigned char * ucp
= iop
->cmnd
;
4017 const int sz
= (int)sizeof(buff
);
4018 np
= scsi_get_opcode_name(ucp
[0]);
4019 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
4020 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
4021 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
4023 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
4024 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
4026 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
4027 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
4028 (trunc
? " [only first 256 bytes shown]" : ""));
4029 dStrHex((const char *)iop
->dxferp
,
4030 (trunc
? 256 : (int)iop
->dxfer_len
) , 1);
4033 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
4034 pout("buff %s\n",buff
);
4037 char ioBuffer
[1000];
4038 SRB_IO_CONTROL
* pSrbIO
= (SRB_IO_CONTROL
*) ioBuffer
;
4039 SCSI_REQUEST_BLOCK
* pScsiIO
= (SCSI_REQUEST_BLOCK
*) (ioBuffer
+ sizeof(SRB_IO_CONTROL
));
4040 DWORD scsiRequestBlockSize
= sizeof(SCSI_REQUEST_BLOCK
);
4041 char *pRequestSenseIO
= (char *) (ioBuffer
+ sizeof(SRB_IO_CONTROL
) + scsiRequestBlockSize
);
4042 DWORD dataOffset
= (sizeof(SRB_IO_CONTROL
) + scsiRequestBlockSize
+ 7) & 0xfffffff8;
4043 char *pDataIO
= (char *) (ioBuffer
+ dataOffset
);
4044 memset(pScsiIO
, 0, scsiRequestBlockSize
);
4045 pScsiIO
->Length
= (USHORT
) scsiRequestBlockSize
;
4046 pScsiIO
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4047 pScsiIO
->PathId
= 0;
4048 pScsiIO
->TargetId
= m_target
;
4049 pScsiIO
->Lun
= m_lun
;
4050 pScsiIO
->CdbLength
= (int)iop
->cmnd_len
;
4051 switch(iop
->dxfer_dir
){
4053 pScsiIO
->SrbFlags
= SRB_NoDataXfer
;
4055 case DXFER_FROM_DEVICE
:
4056 pScsiIO
->SrbFlags
|= SRB_DataIn
;
4058 case DXFER_TO_DEVICE
:
4059 pScsiIO
->SrbFlags
|= SRB_DataOut
;
4062 pout("aacraid: bad dxfer_dir\n");
4063 return set_err(EINVAL
, "aacraid: bad dxfer_dir\n");
4065 pScsiIO
->DataTransferLength
= (ULONG
)iop
->dxfer_len
;
4066 pScsiIO
->TimeOutValue
= iop
->timeout
;
4067 UCHAR
*pCdb
= (UCHAR
*) pScsiIO
->Cdb
;
4068 memcpy(pCdb
, iop
->cmnd
, 16);
4069 if (iop
->max_sense_len
){
4070 memset(pRequestSenseIO
, 0, iop
->max_sense_len
);
4072 if (pScsiIO
->SrbFlags
& SRB_FLAGS_DATA_OUT
){
4073 memcpy(pDataIO
, iop
->dxferp
, iop
->dxfer_len
);
4075 else if (pScsiIO
->SrbFlags
& SRB_FLAGS_DATA_IN
){
4076 memset(pDataIO
, 0, iop
->dxfer_len
);
4079 DWORD bytesReturned
= 0;
4080 memset(pSrbIO
, 0, sizeof(SRB_IO_CONTROL
));
4081 pSrbIO
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
4082 memcpy(pSrbIO
->Signature
, "AACAPI", 7);
4083 pSrbIO
->ControlCode
= ARCIOCTL_SEND_RAW_SRB
;
4084 pSrbIO
->Length
= (dataOffset
+ iop
->dxfer_len
- sizeof(SRB_IO_CONTROL
) + 7) & 0xfffffff8;
4085 pSrbIO
->Timeout
= 3*60;
4087 if (!DeviceIoControl(
4089 IOCTL_SCSI_MINIPORT
,
4091 sizeof(SRB_IO_CONTROL
) + pSrbIO
->Length
,
4093 sizeof(SRB_IO_CONTROL
) + pSrbIO
->Length
,
4097 return set_err(EIO
, "ARCIOCTL_SEND_RAW_SRB failed, Error=%u", (unsigned)GetLastError());
4100 iop
->scsi_status
= pScsiIO
->ScsiStatus
;
4101 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
4102 int slen
= sizeof(pRequestSenseIO
) + 8;
4103 if (slen
> (int)sizeof(pRequestSenseIO
))
4104 slen
= sizeof(pRequestSenseIO
);
4105 if (slen
> (int)iop
->max_sense_len
)
4106 slen
= (int)iop
->max_sense_len
;
4107 memcpy(iop
->sensep
, pRequestSenseIO
, slen
);
4108 iop
->resp_sense_len
= slen
;
4111 pout(" >>> Sense buffer, len=%d:\n", slen
);
4112 dStrHex(iop
->sensep
, slen
, 1);
4114 if ((iop
->sensep
[0] & 0x7f) > 0x71)
4115 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
4116 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
4117 iop
->sensep
[2], iop
->sensep
[3]);
4119 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
4120 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
4121 iop
->sensep
[12], iop
->sensep
[13]);
4125 iop
->resp_sense_len
= 0;
4128 if (iop
->dxfer_dir
== DXFER_FROM_DEVICE
){
4129 memcpy(iop
->dxferp
,pDataIO
, iop
->dxfer_len
);
4131 if((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)){
4132 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
4133 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
4134 (trunc
? " [only first 256 bytes shown]" : ""));
4135 dStrHex((CHAR
*)pDataIO
, (trunc
? 256 : (int)(iop
->dxfer_len
)) , 1);
4140 //////////////////////////////////////////////////////////////////////////////////////////////////
4145 /////////////////////////////////////////////////////////////////////////////
4147 // Initialize platform interface and register with smi()
4148 void smart_interface::init()
4151 // Remove "." from DLL search path if supported
4152 // to prevent DLL preloading attacks
4153 BOOL (WINAPI
* SetDllDirectoryA_p
)(LPCSTR
) = (BOOL (WINAPI
*)(LPCSTR
))
4154 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
4155 if (SetDllDirectoryA_p
)
4156 SetDllDirectoryA_p("");
4159 static os_win32::win_smart_interface the_win_interface
;
4160 smart_interface::set(&the_win_interface
);
4166 // Get exe directory
4167 // (prototype in utiliy.h)
4168 std::string
get_exe_dir()
4170 char path
[MAX_PATH
];
4171 // Get path of this exe
4172 if (!GetModuleFileNameA(GetModuleHandleA(0), path
, sizeof(path
)))
4173 throw std::runtime_error("GetModuleFileName() failed");
4174 // Replace backslash by slash
4176 for (int i
= 0; path
[i
]; i
++)
4177 if (path
[i
] == '\\') {
4178 path
[i
] = '/'; sl
= i
;