4 * Home page of code is: http://smartmontools.sourceforge.net
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 4098 2015-05-30 16:37:37Z chrfranke $";
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 OSVERSIONINFOEXA vi
; memset(&vi
, 0, sizeof(vi
));
647 vi
.dwOSVersionInfoSize
= sizeof(vi
);
648 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
)) {
649 memset(&vi
, 0, sizeof(vi
));
650 vi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
651 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
))
656 if (vi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
658 if (vi
.dwMajorVersion
> 6 || (vi
.dwMajorVersion
== 6 && vi
.dwMinorVersion
>= 2)) {
659 // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
660 // actual OS version, see:
661 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
663 ULONGLONG major_equal
= VerSetConditionMask(0, VER_MAJORVERSION
, VER_EQUAL
);
664 for (unsigned major
= vi
.dwMajorVersion
; major
<= 9; major
++) {
665 OSVERSIONINFOEXA vi2
; memset(&vi2
, 0, sizeof(vi2
));
666 vi2
.dwOSVersionInfoSize
= sizeof(vi2
); vi2
.dwMajorVersion
= major
;
667 if (!VerifyVersionInfo(&vi2
, VER_MAJORVERSION
, major_equal
))
669 if (vi
.dwMajorVersion
< major
) {
670 vi
.dwMajorVersion
= major
; vi
.dwMinorVersion
= 0;
673 ULONGLONG minor_equal
= VerSetConditionMask(0, VER_MINORVERSION
, VER_EQUAL
);
674 for (unsigned minor
= vi
.dwMinorVersion
; minor
<= 9; minor
++) {
675 memset(&vi2
, 0, sizeof(vi2
)); vi2
.dwOSVersionInfoSize
= sizeof(vi2
);
676 vi2
.dwMinorVersion
= minor
;
677 if (!VerifyVersionInfo(&vi2
, VER_MINORVERSION
, minor_equal
))
679 vi
.dwMinorVersion
= minor
;
687 if (vi
.dwMajorVersion
<= 0xf && vi
.dwMinorVersion
<= 0xf) {
688 bool ws
= (vi
.wProductType
<= VER_NT_WORKSTATION
);
689 switch (vi
.dwMajorVersion
<< 4 | vi
.dwMinorVersion
) {
690 case 0x50: w
= "2000"; break;
691 case 0x51: w
= "xp"; break;
692 case 0x52: w
= (!GetSystemMetrics(89/*SM_SERVERR2*/)
693 ? "2003" : "2003r2"); break;
694 case 0x60: w
= (ws
? "vista" : "2008" ); break;
695 case 0x61: w
= (ws
? "win7" : "2008r2"); break;
696 case 0x62: w
= (ws
? "win8" : "2012" ); break;
697 case 0x63: w
= (ws
? "win8.1": "2012r2"); break;
698 case 0x64: w
= (ws
? "win10" : "w10srv"); break;
703 const char * w64
= "";
710 snprintf(vptr
, vlen
, "-%s%u.%u%s",
711 (vi
.dwPlatformId
==VER_PLATFORM_WIN32_NT
? "nt" : "??"),
712 (unsigned)vi
.dwMajorVersion
, (unsigned)vi
.dwMinorVersion
, w64
);
713 else if (vi
.wServicePackMinor
)
714 snprintf(vptr
, vlen
, "-%s%s-sp%u.%u", w
, w64
, vi
.wServicePackMajor
, vi
.wServicePackMinor
);
715 else if (vi
.wServicePackMajor
)
716 snprintf(vptr
, vlen
, "-%s%s-sp%u", w
, w64
, vi
.wServicePackMajor
);
718 snprintf(vptr
, vlen
, "-%s%s", w
, w64
);
723 // MSVCRT only provides ftime() which uses GetSystemTime()
724 // This provides only ~15ms resolution by default.
725 // Use QueryPerformanceCounter instead (~300ns).
726 // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
727 int64_t win_smart_interface::get_timer_usec()
729 static int64_t freq
= 0;
733 freq
= (QueryPerformanceFrequency(&t
) ? t
.QuadPart
: -1);
735 return smart_interface::get_timer_usec();
737 if (!QueryPerformanceCounter(&t
))
739 if (!(0 <= t
.QuadPart
&& t
.QuadPart
<= (int64_t)(~(uint64_t)0 >> 1)/1000000))
742 return (t
.QuadPart
* 1000000LL) / freq
;
747 // Return value for device detection functions
748 enum win_dev_type
{ DEV_UNKNOWN
= 0, DEV_ATA
, DEV_SCSI
, DEV_SAT
, DEV_USB
};
750 static win_dev_type
get_phy_drive_type(int drive
);
751 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
);
752 static win_dev_type
get_log_drive_type(int drive
);
753 static bool get_usb_id(int drive
, unsigned short & vendor_id
,
754 unsigned short & product_id
);
756 static const char * ata_get_def_options(void);
759 static int is_permissive()
761 if (!failuretest_permissive
) {
762 pout("To continue, add one or more '-T permissive' options.\n");
765 failuretest_permissive
--;
769 // return number for drive letter, -1 on error
770 // "[A-Za-z]:([/\\][.]?)?" => 0-25
771 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files
772 static int drive_letter(const char * s
)
774 return ( (('A' <= s
[0] && s
[0] <= 'Z') || ('a' <= s
[0] && s
[0] <= 'z'))
776 && (!s
[2] || ( strchr("/\\\"", s
[2])
777 && (!s
[3] || (s
[3] == '.' && !s
[4]))) ) ?
778 (s
[0] & 0x1f) - 1 : -1);
781 // Skip trailing "/dev/", do not allow "/dev/X:"
782 static const char * skipdev(const char * s
)
784 return (!strncmp(s
, "/dev/", 5) && drive_letter(s
+5) < 0 ? s
+5 : s
);
787 ata_device
* win_smart_interface::get_ata_device(const char * name
, const char * type
)
789 const char * testname
= skipdev(name
);
790 if (!strncmp(testname
, "csmi", 4))
791 return new win_csmi_device(this, name
, type
);
792 if (!strncmp(testname
, "tw_cli", 6))
793 return new win_tw_cli_device(this, name
, type
);
794 return new win_ata_device(this, name
, type
);
797 scsi_device
* win_smart_interface::get_scsi_device(const char * name
, const char * type
)
799 return new win_scsi_device(this, name
, type
);
802 static int sdxy_to_phydrive(const char (& xy
)[2+1])
804 int phydrive
= xy
[0] - 'a';
806 phydrive
= (phydrive
+ 1) * ('z' - 'a' + 1) + (xy
[1] - 'a');
810 static win_dev_type
get_dev_type(const char * name
, int & phydrive
)
813 name
= skipdev(name
);
814 if (!strncmp(name
, "st", 2))
816 if (!strncmp(name
, "nst", 3))
818 if (!strncmp(name
, "tape", 4))
821 int logdrive
= drive_letter(name
);
823 win_dev_type type
= get_log_drive_type(logdrive
);
824 return (type
!= DEV_UNKNOWN
? type
: DEV_SCSI
);
827 char drive
[2+1] = "";
828 if (sscanf(name
, "sd%2[a-z]", drive
) == 1) {
829 phydrive
= sdxy_to_phydrive(drive
);
830 return get_phy_drive_type(phydrive
);
834 if (sscanf(name
, "pd%d", &phydrive
) == 1 && phydrive
>= 0)
835 return get_phy_drive_type(phydrive
);
839 smart_device
* win_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
842 int disknum
= -1, n1
= -1, n2
= -1;
846 if (sscanf(type
, "areca,%n%d/%d%n", &n1
, &disknum
, &encnum
, &n2
) >= 1 || n1
== 6) {
847 if (!(1 <= disknum
&& disknum
<= 128)) {
848 set_err(EINVAL
, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum
);
851 if (!(1 <= encnum
&& encnum
<= 8)) {
852 set_err(EINVAL
, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum
);
856 name
= skipdev(name
);
857 #define ARECA_MAX_CTLR_NUM 16
860 if (sscanf(name
, "arcmsr%d%n", &ctlrindex
, &n1
) >= 1 && n1
== (int)strlen(name
)) {
862 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
863 2. map arcmsrX into "\\\\.\\scsiX"
865 for (int idx
= 0; idx
< ARECA_MAX_CTLR_NUM
; idx
++) {
866 memset(devpath
, 0, sizeof(devpath
));
867 snprintf(devpath
, sizeof(devpath
), "\\\\.\\scsi%d:", idx
);
868 win_areca_ata_device
*arcdev
= new win_areca_ata_device(this, devpath
, disknum
, encnum
);
869 if(arcdev
->arcmsr_probe()) {
870 if(ctlrindex
-- == 0) {
876 set_err(ENOENT
, "No Areca controller found");
879 set_err(EINVAL
, "Option -d areca,N/E requires device name /dev/arcmsrX");
884 unsigned ctrnum
, lun
, target
;
887 if ( sscanf(type
, "aacraid,%u,%u,%u%n", &ctrnum
, &lun
, &target
, &n1
) >= 3
888 && n1
== (int)strlen(type
)) {
889 #define aacraid_MAX_CTLR_NUM 16
890 if (ctrnum
>= aacraid_MAX_CTLR_NUM
) {
891 set_err(EINVAL
, "aacraid: invalid host number %u", ctrnum
);
896 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[AACRAID_MAX_CTLR_NUM]:" and
897 2. map ARCX into "\\\\.\\scsiX"
899 memset(devpath
, 0, sizeof(devpath
));
900 unsigned ctlrindex
= 0;
901 for (int portNum
= 0; portNum
< aacraid_MAX_CTLR_NUM
; portNum
++){
903 snprintf(subKey
, sizeof(subKey
), "HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port %d", portNum
);
905 long regStatus
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hScsiKey
);
906 if (regStatus
== ERROR_SUCCESS
){
908 DWORD driverNameSize
= sizeof(driverName
);
910 regStatus
= RegQueryValueExA(hScsiKey
, "Driver", NULL
, ®Type
, (LPBYTE
) driverName
, &driverNameSize
);
911 if (regStatus
== ERROR_SUCCESS
){
912 if (regType
== REG_SZ
){
913 if (stricmp(driverName
, "arcsas") == 0){
914 if(ctrnum
== ctlrindex
){
915 snprintf(devpath
, sizeof(devpath
), "\\\\.\\Scsi%d:", portNum
);
916 return get_sat_device("sat,auto",
917 new win_aacraid_device(this, devpath
, ctrnum
, target
, lun
));
923 RegCloseKey(hScsiKey
);
927 set_err(EINVAL
, "aacraid: host %u not found", ctrnum
);
934 std::string
win_smart_interface::get_valid_custom_dev_types_str()
936 return "aacraid,H,L,ID, areca,N[/E]";
940 smart_device
* win_smart_interface::autodetect_smart_device(const char * name
)
942 const char * testname
= skipdev(name
);
943 if (str_starts_with(testname
, "hd"))
944 return new win_ata_device(this, name
, "");
946 if (str_starts_with(testname
, "tw_cli"))
947 return new win_tw_cli_device(this, name
, "");
949 if (str_starts_with(testname
, "csmi"))
950 return new win_csmi_device(this, name
, "");
953 win_dev_type type
= get_dev_type(name
, phydrive
);
956 return new win_ata_device(this, name
, "");
958 if (type
== DEV_SCSI
)
959 return new win_scsi_device(this, name
, "");
962 return get_sat_device("sat", new win_scsi_device(this, name
, ""));
964 if (type
== DEV_USB
) {
966 unsigned short vendor_id
= 0, product_id
= 0;
967 if (!(phydrive
>= 0 && get_usb_id(phydrive
, vendor_id
, product_id
))) {
968 set_err(EINVAL
, "Unable to read USB device ID");
971 // Get type name for this ID
972 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
975 // Return SAT/USB device for this type
976 return get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
985 bool win_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
986 const char * type
, const char * pattern
/* = 0*/)
989 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
993 // Check for "[*,]pd" type
995 char type2
[16+1] = "";
998 if (!strcmp(type
, "pd")) {
1002 else if (sscanf(type
, "%16[^,],pd%n", type2
, &nc
) == 1 &&
1003 nc
== (int)strlen(type
)) {
1010 bool ata
, scsi
, sat
, usb
, csmi
;
1012 ata
= scsi
= usb
= sat
= csmi
= true;
1015 ata
= scsi
= usb
= sat
= csmi
= false;
1016 if (!strcmp(type
, "ata"))
1018 else if (!strcmp(type
, "scsi"))
1020 else if (!strcmp(type
, "sat"))
1022 else if (!strcmp(type
, "usb"))
1024 else if (!strcmp(type
, "csmi"))
1028 "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], sat[,pd], usb[,pd], csmi, pd",
1036 if (ata
|| scsi
|| sat
|| usb
) {
1037 // Scan up to 128 drives and 2 3ware controllers
1038 const int max_raid
= 2;
1039 bool raid_seen
[max_raid
] = {false, false};
1041 for (int i
= 0; i
< 128; i
++) {
1043 snprintf(name
, sizeof(name
), "/dev/pd%d", i
);
1044 else if (i
+ 'a' <= 'z')
1045 snprintf(name
, sizeof(name
), "/dev/sd%c", i
+ 'a');
1047 snprintf(name
, sizeof(name
), "/dev/sd%c%c",
1048 i
/ ('z'-'a'+1) - 1 + 'a',
1049 i
% ('z'-'a'+1) + 'a');
1051 GETVERSIONINPARAMS_EX vers_ex
;
1053 switch (get_phy_drive_type(i
, (ata
? &vers_ex
: 0))) {
1055 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
1059 // Interpret RAID drive map if present
1060 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
) {
1061 // Skip if too many controllers or logical drive from this controller already seen
1062 if (!(vers_ex
.wControllerId
< max_raid
&& !raid_seen
[vers_ex
.wControllerId
]))
1064 raid_seen
[vers_ex
.wControllerId
] = true;
1065 // Add physical drives
1066 int len
= strlen(name
);
1067 for (int pi
= 0; pi
< 32; pi
++) {
1068 if (vers_ex
.dwDeviceMapEx
& (1L << pi
)) {
1069 snprintf(name
+len
, sizeof(name
)-1-len
, ",%u", pi
);
1070 devlist
.push_back( new win_ata_device(this, name
, "ata") );
1075 devlist
.push_back( new win_ata_device(this, name
, "ata") );
1080 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
1083 devlist
.push_back( new win_scsi_device(this, name
, "scsi") );
1087 // STORAGE_QUERY_PROPERTY returned VendorId "ATA "
1090 devlist
.push_back( get_sat_device("sat", new win_scsi_device(this, name
, "")) );
1094 // STORAGE_QUERY_PROPERTY returned USB
1098 // TODO: Use common function for this and autodetect_smart_device()
1099 // Get USB bridge ID
1100 unsigned short vendor_id
= 0, product_id
= 0;
1101 if (!get_usb_id(i
, vendor_id
, product_id
))
1103 // Get type name for this ID
1104 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
);
1107 // Return SAT/USB device for this type
1108 ata_device
* dev
= get_sat_device(usbtype
, new win_scsi_device(this, name
, ""));
1111 devlist
.push_back(dev
);
1123 // Scan CSMI devices
1124 for (int i
= 0; i
<= 9; i
++) {
1125 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,0", i
);
1126 win_csmi_device
test_dev(this, name
, "");
1127 if (!test_dev
.open_scsi())
1130 unsigned ports_used
= test_dev
.get_ports_used();
1134 for (int pi
= 0; pi
< 32; pi
++) {
1135 if (!(ports_used
& (1 << pi
)))
1137 snprintf(name
, sizeof(name
)-1, "/dev/csmi%d,%d", i
, pi
);
1138 devlist
.push_back( new win_csmi_device(this, name
, "ata") );
1146 // get examples for smartctl
1147 std::string
win_smart_interface::get_app_examples(const char * appname
)
1149 if (strcmp(appname
, "smartctl"))
1151 return "=================================================== SMARTCTL EXAMPLES =====\n\n"
1152 " smartctl -a /dev/sda (Prints all SMART information)\n\n"
1153 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
1154 " (Enables SMART on first disk)\n\n"
1155 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n"
1156 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
1157 " (Prints Self-Test & Attribute errors)\n"
1158 " smartctl -a /dev/sda\n"
1159 " (Prints all information for disk on PhysicalDrive 0)\n"
1160 " smartctl -a /dev/pd3\n"
1161 " (Prints all information for disk on PhysicalDrive 3)\n"
1162 " smartctl -a /dev/tape1\n"
1163 " (Prints all information for SCSI tape on Tape 1)\n"
1164 " smartctl -A /dev/hdb,3\n"
1165 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
1166 " smartctl -A /dev/tw_cli/c0/p1\n"
1167 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
1168 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
1169 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
1170 " on 1st Areca RAID controller)\n"
1172 " ATA SMART access methods and ordering may be specified by modifiers\n"
1173 " following the device name: /dev/hdX:[saicm], where\n"
1174 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n"
1175 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
1176 " 'm': IOCTL_SCSI_MINIPORT_*.\n"
1178 " The default on this system is /dev/sdX:%s\n", ata_get_def_options()
1183 bool win_smart_interface::disable_system_auto_standby(bool disable
)
1186 SYSTEM_POWER_STATUS ps
;
1187 if (!GetSystemPowerStatus(&ps
))
1188 return set_err(ENOSYS
, "Unknown power status");
1189 if (ps
.ACLineStatus
!= 1) {
1190 SetThreadExecutionState(ES_CONTINUOUS
);
1191 if (ps
.ACLineStatus
== 0)
1192 set_err(EIO
, "AC offline");
1194 set_err(EIO
, "Unknown AC line status");
1199 if (!SetThreadExecutionState(ES_CONTINUOUS
| (disable
? ES_SYSTEM_REQUIRED
: 0)))
1200 return set_err(ENOSYS
);
1205 /////////////////////////////////////////////////////////////////////////////
1207 /////////////////////////////////////////////////////////////////////////////
1209 #define SMART_CYL_LOW 0x4F
1210 #define SMART_CYL_HI 0xC2
1212 static void print_ide_regs(const IDEREGS
* r
, int out
)
1214 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
1215 (out
?"STS":"CMD"), r
->bCommandReg
, (out
?"ERR":" FR"), r
->bFeaturesReg
,
1216 r
->bSectorCountReg
, r
->bSectorNumberReg
, r
->bCylLowReg
, r
->bCylHighReg
, r
->bDriveHeadReg
);
1219 static void print_ide_regs_io(const IDEREGS
* ri
, const IDEREGS
* ro
)
1221 pout(" Input : "); print_ide_regs(ri
, 0);
1223 pout(" Output: "); print_ide_regs(ro
, 1);
1227 /////////////////////////////////////////////////////////////////////////////
1229 // call SMART_GET_VERSION, return device map or -1 on error
1231 static int smart_get_version(HANDLE hdevice
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
1233 GETVERSIONINPARAMS vers
; memset(&vers
, 0, sizeof(vers
));
1234 const GETVERSIONINPARAMS_EX
& vers_ex
= (const GETVERSIONINPARAMS_EX
&)vers
;
1237 if (!DeviceIoControl(hdevice
, SMART_GET_VERSION
,
1238 NULL
, 0, &vers
, sizeof(vers
), &num_out
, NULL
)) {
1240 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
1244 assert(num_out
== sizeof(GETVERSIONINPARAMS
));
1246 if (ata_debugmode
> 1) {
1247 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n"
1248 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
1249 (unsigned)num_out
, vers
.bVersion
, vers
.bRevision
,
1250 (unsigned)vers
.fCapabilities
, vers
.bIDEDeviceMap
);
1251 if (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
1252 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
1253 vers_ex
.wIdentifier
, vers_ex
.wControllerId
, (unsigned)vers_ex
.dwDeviceMapEx
);
1257 *ata_version_ex
= vers_ex
;
1259 // TODO: Check vers.fCapabilities here?
1260 return vers
.bIDEDeviceMap
;
1264 // call SMART_* ioctl
1266 static int smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
, int port
)
1268 SENDCMDINPARAMS inpar
;
1269 SENDCMDINPARAMS_EX
& inpar_ex
= (SENDCMDINPARAMS_EX
&)inpar
;
1271 unsigned char outbuf
[sizeof(SENDCMDOUTPARAMS
)-1 + 512];
1272 const SENDCMDOUTPARAMS
* outpar
;
1273 DWORD code
, num_out
;
1274 unsigned int size_out
;
1277 memset(&inpar
, 0, sizeof(inpar
));
1278 inpar
.irDriveRegs
= *regs
;
1280 // Older drivers may require bits 5 and 7 set
1281 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
1282 inpar
.irDriveRegs
.bDriveHeadReg
|= 0xa0;
1284 // Drive number 0-3 was required on Win9x/ME only
1285 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
1286 //inpar.bDriveNumber = drive;
1290 inpar_ex
.wIdentifier
= SMART_VENDOR_3WARE
;
1291 inpar_ex
.bPortNumber
= port
;
1294 if (datasize
== 512) {
1295 code
= SMART_RCV_DRIVE_DATA
; name
= "SMART_RCV_DRIVE_DATA";
1296 inpar
.cBufferSize
= size_out
= 512;
1298 else if (datasize
== 0) {
1299 code
= SMART_SEND_DRIVE_COMMAND
; name
= "SMART_SEND_DRIVE_COMMAND";
1300 if (regs
->bFeaturesReg
== ATA_SMART_STATUS
)
1301 size_out
= sizeof(IDEREGS
); // ioctl returns new IDEREGS as data
1302 // Note: cBufferSize must be 0 on Win9x
1311 memset(&outbuf
, 0, sizeof(outbuf
));
1313 if (!DeviceIoControl(hdevice
, code
, &inpar
, sizeof(SENDCMDINPARAMS
)-1,
1314 outbuf
, sizeof(SENDCMDOUTPARAMS
)-1 + size_out
, &num_out
, NULL
)) {
1315 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
1316 long err
= GetLastError();
1317 if (ata_debugmode
&& (err
!= ERROR_INVALID_PARAMETER
|| ata_debugmode
> 1)) {
1318 pout(" %s failed, Error=%ld\n", name
, err
);
1319 print_ide_regs_io(regs
, NULL
);
1321 errno
= ( err
== ERROR_INVALID_FUNCTION
/*9x*/
1322 || err
== ERROR_INVALID_PARAMETER
/*NT/2K/XP*/
1323 || err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1326 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs
1328 outpar
= (const SENDCMDOUTPARAMS
*)outbuf
;
1330 if (outpar
->DriverStatus
.bDriverError
) {
1331 if (ata_debugmode
) {
1332 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1333 outpar
->DriverStatus
.bDriverError
, outpar
->DriverStatus
.bIDEError
);
1334 print_ide_regs_io(regs
, NULL
);
1336 errno
= (!outpar
->DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1340 if (ata_debugmode
> 1) {
1341 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name
,
1342 (unsigned)num_out
, (unsigned)outpar
->cBufferSize
);
1343 print_ide_regs_io(regs
, (regs
->bFeaturesReg
== ATA_SMART_STATUS
?
1344 (const IDEREGS
*)(outpar
->bBuffer
) : NULL
));
1348 memcpy(data
, outpar
->bBuffer
, 512);
1349 else if (regs
->bFeaturesReg
== ATA_SMART_STATUS
) {
1350 if (nonempty(outpar
->bBuffer
, sizeof(IDEREGS
)))
1351 memcpy(regs
, outpar
->bBuffer
, sizeof(IDEREGS
));
1352 else { // Workaround for driver not returning regs
1354 pout(" WARNING: driver does not return ATA registers in output buffer!\n");
1355 *regs
= inpar
.irDriveRegs
;
1363 /////////////////////////////////////////////////////////////////////////////
1364 // IDE PASS THROUGH (2000, XP, undocumented)
1366 // Based on WinATA.cpp, 2002 c't/Matthias Withopf
1367 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip
1369 static int ide_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, unsigned datasize
)
1371 if (datasize
> 512) {
1375 unsigned int size
= sizeof(ATA_PASS_THROUGH
)-1 + datasize
;
1376 ATA_PASS_THROUGH
* buf
= (ATA_PASS_THROUGH
*)VirtualAlloc(NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
1378 const unsigned char magic
= 0xcf;
1385 buf
->IdeReg
= *regs
;
1386 buf
->DataBufferSize
= datasize
;
1388 buf
->DataBuffer
[0] = magic
;
1390 if (!DeviceIoControl(hdevice
, IOCTL_IDE_PASS_THROUGH
,
1391 buf
, size
, buf
, size
, &num_out
, NULL
)) {
1392 long err
= GetLastError();
1393 if (ata_debugmode
) {
1394 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err
);
1395 print_ide_regs_io(regs
, NULL
);
1397 VirtualFree(buf
, 0, MEM_RELEASE
);
1398 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1403 if (buf
->IdeReg
.bCommandReg
/*Status*/ & 0x01) {
1404 if (ata_debugmode
) {
1405 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n");
1406 print_ide_regs_io(regs
, &buf
->IdeReg
);
1408 VirtualFree(buf
, 0, MEM_RELEASE
);
1413 // Check and copy data
1415 if ( num_out
!= size
1416 || (buf
->DataBuffer
[0] == magic
&& !nonempty(buf
->DataBuffer
+1, datasize
-1))) {
1417 if (ata_debugmode
) {
1418 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
1419 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1420 print_ide_regs_io(regs
, &buf
->IdeReg
);
1422 VirtualFree(buf
, 0, MEM_RELEASE
);
1426 memcpy(data
, buf
->DataBuffer
, datasize
);
1429 if (ata_debugmode
> 1) {
1430 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
1431 (unsigned)num_out
, (unsigned)buf
->DataBufferSize
);
1432 print_ide_regs_io(regs
, &buf
->IdeReg
);
1434 *regs
= buf
->IdeReg
;
1436 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero
1437 VirtualFree(buf
, 0, MEM_RELEASE
);
1442 /////////////////////////////////////////////////////////////////////////////
1443 // ATA PASS THROUGH (Win2003, XP SP2)
1446 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data
1447 // transfer per command. Therefore, multi-sector transfers are only supported
1448 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS
1449 // or READ/WRITE LOG EXT work only with single sector transfers.
1450 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE.
1452 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da
1454 static int ata_pass_through_ioctl(HANDLE hdevice
, IDEREGS
* regs
, IDEREGS
* prev_regs
, char * data
, int datasize
)
1456 const int max_sectors
= 32; // TODO: Allocate dynamic buffer
1459 ATA_PASS_THROUGH_EX apt
;
1461 UCHAR ucDataBuf
[max_sectors
* 512];
1462 } ATA_PASS_THROUGH_EX_WITH_BUFFERS
;
1464 const unsigned char magic
= 0xcf;
1466 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab
; memset(&ab
, 0, sizeof(ab
));
1467 ab
.apt
.Length
= sizeof(ATA_PASS_THROUGH_EX
);
1468 //ab.apt.PathId = 0;
1469 //ab.apt.TargetId = 0;
1471 ab
.apt
.TimeOutValue
= 10;
1472 unsigned size
= offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS
, ucDataBuf
);
1473 ab
.apt
.DataBufferOffset
= size
;
1476 if (datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1480 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_IN
;
1481 ab
.apt
.DataTransferLength
= datasize
;
1483 ab
.ucDataBuf
[0] = magic
;
1485 else if (datasize
< 0) {
1486 if (-datasize
> (int)sizeof(ab
.ucDataBuf
)) {
1490 ab
.apt
.AtaFlags
= ATA_FLAGS_DATA_OUT
;
1491 ab
.apt
.DataTransferLength
= -datasize
;
1493 memcpy(ab
.ucDataBuf
, data
, -datasize
);
1496 assert(ab
.apt
.AtaFlags
== 0);
1497 assert(ab
.apt
.DataTransferLength
== 0);
1500 assert(sizeof(ab
.apt
.CurrentTaskFile
) == sizeof(IDEREGS
));
1501 IDEREGS
* ctfregs
= (IDEREGS
*)ab
.apt
.CurrentTaskFile
;
1502 IDEREGS
* ptfregs
= (IDEREGS
*)ab
.apt
.PreviousTaskFile
;
1506 *ptfregs
= *prev_regs
;
1507 ab
.apt
.AtaFlags
|= ATA_FLAGS_48BIT_COMMAND
;
1511 if (!DeviceIoControl(hdevice
, IOCTL_ATA_PASS_THROUGH
,
1512 &ab
, size
, &ab
, size
, &num_out
, NULL
)) {
1513 long err
= GetLastError();
1514 if (ata_debugmode
) {
1515 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err
);
1516 print_ide_regs_io(regs
, NULL
);
1518 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1523 if (ctfregs
->bCommandReg
/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) {
1524 if (ata_debugmode
) {
1525 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n");
1526 print_ide_regs_io(regs
, ctfregs
);
1532 // Check and copy data
1534 if ( num_out
!= size
1535 || (ab
.ucDataBuf
[0] == magic
&& !nonempty(ab
.ucDataBuf
+1, datasize
-1))) {
1536 if (ata_debugmode
) {
1537 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out
);
1538 print_ide_regs_io(regs
, ctfregs
);
1543 memcpy(data
, ab
.ucDataBuf
, datasize
);
1546 if (ata_debugmode
> 1) {
1547 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out
);
1548 print_ide_regs_io(regs
, ctfregs
);
1552 *prev_regs
= *ptfregs
;
1558 /////////////////////////////////////////////////////////////////////////////
1559 // SMART IOCTL via SCSI MINIPORT ioctl
1561 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
1562 // miniport driver (via SCSI port driver scsiport.sys).
1563 // It can be used to skip the missing or broken handling of some SMART
1564 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys)
1566 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
)
1569 DWORD code
= 0; const char * name
= 0;
1570 if (regs
->bCommandReg
== ATA_IDENTIFY_DEVICE
) {
1571 code
= IOCTL_SCSI_MINIPORT_IDENTIFY
; name
= "IDENTIFY";
1573 else if (regs
->bCommandReg
== ATA_SMART_CMD
) switch (regs
->bFeaturesReg
) {
1574 case ATA_SMART_READ_VALUES
:
1575 code
= IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
; name
= "READ_SMART_ATTRIBS"; break;
1576 case ATA_SMART_READ_THRESHOLDS
:
1577 code
= IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
; name
= "READ_SMART_THRESHOLDS"; break;
1578 case ATA_SMART_ENABLE
:
1579 code
= IOCTL_SCSI_MINIPORT_ENABLE_SMART
; name
= "ENABLE_SMART"; break;
1580 case ATA_SMART_DISABLE
:
1581 code
= IOCTL_SCSI_MINIPORT_DISABLE_SMART
; name
= "DISABLE_SMART"; break;
1582 case ATA_SMART_STATUS
:
1583 code
= IOCTL_SCSI_MINIPORT_RETURN_STATUS
; name
= "RETURN_STATUS"; break;
1584 case ATA_SMART_AUTOSAVE
:
1585 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
; name
= "ENABLE_DISABLE_AUTOSAVE"; break;
1586 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools
1587 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break;
1588 case ATA_SMART_IMMEDIATE_OFFLINE
:
1589 code
= IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
; name
= "EXECUTE_OFFLINE_DIAGS"; break;
1590 case ATA_SMART_AUTO_OFFLINE
:
1591 code
= IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE
; name
= "ENABLE_DISABLE_AUTO_OFFLINE"; break;
1592 case ATA_SMART_READ_LOG_SECTOR
:
1593 code
= IOCTL_SCSI_MINIPORT_READ_SMART_LOG
; name
= "READ_SMART_LOG"; break;
1594 case ATA_SMART_WRITE_LOG_SECTOR
:
1595 code
= IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
; name
= "WRITE_SMART_LOG"; break;
1604 SRB_IO_CONTROL srbc
;
1607 SENDCMDOUTPARAMS out
;
1611 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(SENDCMDINPARAMS
)-1+512);
1612 memset(&sb
, 0, sizeof(sb
));
1616 if (datasize
> (int)sizeof(sb
.space
)+1) {
1622 else if (datasize
< 0) {
1623 if (-datasize
> (int)sizeof(sb
.space
)+1) {
1628 memcpy(sb
.params
.in
.bBuffer
, data
, size
);
1630 else if (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1631 size
= sizeof(IDEREGS
);
1634 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1635 memcpy(sb
.srbc
.Signature
, "SCSIDISK", 8); // atapi.sys
1636 sb
.srbc
.Timeout
= 60; // seconds
1637 sb
.srbc
.ControlCode
= code
;
1638 //sb.srbc.ReturnCode = 0;
1639 sb
.srbc
.Length
= sizeof(SENDCMDINPARAMS
)-1 + size
;
1640 sb
.params
.in
.irDriveRegs
= *regs
;
1641 sb
.params
.in
.cBufferSize
= size
;
1643 // Call miniport ioctl
1644 size
+= sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
)-1;
1646 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1647 &sb
, size
, &sb
, size
, &num_out
, NULL
)) {
1648 long err
= GetLastError();
1649 if (ata_debugmode
) {
1650 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name
, err
);
1651 print_ide_regs_io(regs
, NULL
);
1653 errno
= (err
== ERROR_INVALID_FUNCTION
|| err
== ERROR_NOT_SUPPORTED
? ENOSYS
: EIO
);
1658 if (sb
.srbc
.ReturnCode
) {
1659 if (ata_debugmode
) {
1660 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name
, (unsigned)sb
.srbc
.ReturnCode
);
1661 print_ide_regs_io(regs
, NULL
);
1667 if (sb
.params
.out
.DriverStatus
.bDriverError
) {
1668 if (ata_debugmode
) {
1669 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name
,
1670 sb
.params
.out
.DriverStatus
.bDriverError
, sb
.params
.out
.DriverStatus
.bIDEError
);
1671 print_ide_regs_io(regs
, NULL
);
1673 errno
= (!sb
.params
.out
.DriverStatus
.bIDEError
? ENOSYS
: EIO
);
1677 if (ata_debugmode
> 1) {
1678 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name
,
1679 (unsigned)num_out
, (unsigned)sb
.params
.out
.cBufferSize
);
1680 print_ide_regs_io(regs
, (code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
?
1681 (const IDEREGS
*)(sb
.params
.out
.bBuffer
) : 0));
1685 memcpy(data
, sb
.params
.out
.bBuffer
, datasize
);
1686 else if (datasize
== 0 && code
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
1687 memcpy(regs
, sb
.params
.out
.bBuffer
, sizeof(IDEREGS
));
1693 /////////////////////////////////////////////////////////////////////////////
1695 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl
1697 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
, IDEREGS
* regs
, char * data
, int datasize
, int port
)
1700 SRB_IO_CONTROL srbc
;
1704 ASSERT_SIZEOF(sb
, sizeof(SRB_IO_CONTROL
)+sizeof(IDEREGS
)+512);
1706 if (!(0 <= datasize
&& datasize
<= (int)sizeof(sb
.buffer
) && port
>= 0)) {
1710 memset(&sb
, 0, sizeof(sb
));
1711 strncpy((char *)sb
.srbc
.Signature
, "<3ware>", sizeof(sb
.srbc
.Signature
));
1712 sb
.srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1713 sb
.srbc
.Timeout
= 60; // seconds
1714 sb
.srbc
.ControlCode
= 0xA0000000;
1715 sb
.srbc
.ReturnCode
= 0;
1716 sb
.srbc
.Length
= sizeof(IDEREGS
) + (datasize
> 0 ? datasize
: 1);
1718 sb
.regs
.bReserved
= port
;
1721 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1722 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, NULL
)) {
1723 long err
= GetLastError();
1724 if (ata_debugmode
) {
1725 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1726 print_ide_regs_io(regs
, NULL
);
1728 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1732 if (sb
.srbc
.ReturnCode
) {
1733 if (ata_debugmode
) {
1734 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb
.srbc
.ReturnCode
);
1735 print_ide_regs_io(regs
, NULL
);
1743 memcpy(data
, sb
.buffer
, datasize
);
1745 if (ata_debugmode
> 1) {
1746 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out
);
1747 print_ide_regs_io(regs
, &sb
.regs
);
1755 /////////////////////////////////////////////////////////////////////////////
1757 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION.
1758 // 3DM/CLI "Rescan Controller" function does not to always update it.
1760 static int update_3ware_devicemap_ioctl(HANDLE hdevice
)
1762 SRB_IO_CONTROL srbc
;
1763 memset(&srbc
, 0, sizeof(srbc
));
1764 strncpy((char *)srbc
.Signature
, "<3ware>", sizeof(srbc
.Signature
));
1765 srbc
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
1766 srbc
.Timeout
= 60; // seconds
1767 srbc
.ControlCode
= 0xCC010014;
1768 srbc
.ReturnCode
= 0;
1772 if (!DeviceIoControl(hdevice
, IOCTL_SCSI_MINIPORT
,
1773 &srbc
, sizeof(srbc
), &srbc
, sizeof(srbc
), &num_out
, NULL
)) {
1774 long err
= GetLastError();
1776 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err
);
1777 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
1780 if (srbc
.ReturnCode
) {
1782 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc
.ReturnCode
);
1786 if (ata_debugmode
> 1)
1787 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n");
1793 /////////////////////////////////////////////////////////////////////////////
1795 // Routines for pseudo device /dev/tw_cli/*
1796 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window
1799 // Get clipboard data
1801 static int get_clipboard(char * data
, int datasize
)
1803 if (!OpenClipboard(NULL
))
1805 HANDLE h
= GetClipboardData(CF_TEXT
);
1810 const void * p
= GlobalLock(h
);
1811 int n
= GlobalSize(h
);
1821 // Run a command, write stdout to dataout
1822 // TODO: Combine with daemon_win32.cpp:daemon_spawn()
1824 static int run_cmd(const char * cmd
, char * dataout
, int outsize
)
1826 // Create stdout pipe
1827 SECURITY_ATTRIBUTES sa
= {sizeof(sa
), 0, TRUE
};
1828 HANDLE pipe_out_w
, h
;
1829 if (!CreatePipe(&h
, &pipe_out_w
, &sa
/*inherit*/, outsize
))
1831 HANDLE self
= GetCurrentProcess();
1833 if (!DuplicateHandle(self
, h
, self
, &pipe_out_r
,
1834 GENERIC_READ
, FALSE
/*!inherit*/, DUPLICATE_CLOSE_SOURCE
)) {
1835 CloseHandle(pipe_out_w
);
1839 if (!DuplicateHandle(self
, pipe_out_w
, self
, &pipe_err_w
,
1840 0, TRUE
/*inherit*/, DUPLICATE_SAME_ACCESS
)) {
1841 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1846 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
1847 si
.hStdInput
= INVALID_HANDLE_VALUE
;
1848 si
.hStdOutput
= pipe_out_w
; si
.hStdError
= pipe_err_w
;
1849 si
.dwFlags
= STARTF_USESTDHANDLES
;
1850 PROCESS_INFORMATION pi
;
1852 NULL
, const_cast<char *>(cmd
),
1853 NULL
, NULL
, TRUE
/*inherit*/,
1854 CREATE_NO_WINDOW
/*do not create a new console window*/,
1855 NULL
, NULL
, &si
, &pi
)) {
1856 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
1859 CloseHandle(pi
.hThread
);
1860 CloseHandle(pipe_err_w
); CloseHandle(pipe_out_w
);
1862 // Copy stdout to output buffer
1864 while (i
< outsize
) {
1866 if (!ReadFile(pipe_out_r
, dataout
+i
, outsize
-i
, &num_read
, NULL
) || num_read
== 0)
1870 CloseHandle(pipe_out_r
);
1872 WaitForSingleObject(pi
.hProcess
, INFINITE
);
1873 CloseHandle(pi
.hProcess
);
1878 static const char * findstr(const char * str
, const char * sub
)
1880 const char * s
= strstr(str
, sub
);
1881 return (s
? s
+strlen(sub
) : "");
1885 static void copy_swapped(unsigned char * dest
, const char * src
, int destsize
)
1887 int srclen
= strcspn(src
, "\r\n");
1889 for (i
= 0; i
< destsize
-1 && i
< srclen
-1; i
+=2) {
1890 dest
[i
] = src
[i
+1]; dest
[i
+1] = src
[i
];
1892 if (i
< destsize
-1 && i
< srclen
)
1897 // TODO: This is OS independent
1899 win_tw_cli_device::win_tw_cli_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
1900 : smart_device(intf
, dev_name
, "tw_cli", req_type
),
1901 m_ident_valid(false), m_smart_valid(false)
1903 memset(&m_ident_buf
, 0, sizeof(m_ident_buf
));
1904 memset(&m_smart_buf
, 0, sizeof(m_smart_buf
));
1908 bool win_tw_cli_device::is_open() const
1910 return (m_ident_valid
|| m_smart_valid
);
1914 bool win_tw_cli_device::open()
1916 m_ident_valid
= m_smart_valid
= false;
1917 const char * name
= skipdev(get_dev_name());
1918 // Read tw_cli or 3DM browser output into buffer
1920 int size
= -1, n1
= -1, n2
= -1;
1921 if (!strcmp(name
, "tw_cli/clip")) { // read clipboard
1922 size
= get_clipboard(buffer
, sizeof(buffer
));
1924 else if (!strcmp(name
, "tw_cli/stdin")) { // read stdin
1925 size
= fread(buffer
, 1, sizeof(buffer
), stdin
);
1927 else if (sscanf(name
, "tw_cli/%nc%*u/p%*u%n", &n1
, &n2
) >= 0 && n2
== (int)strlen(name
)) {
1928 // tw_cli/cx/py => read output from "tw_cli /cx/py show all"
1930 snprintf(cmd
, sizeof(cmd
), "tw_cli /%s show all", name
+n1
);
1931 if (ata_debugmode
> 1)
1932 pout("%s: Run: \"%s\"\n", name
, cmd
);
1933 size
= run_cmd(cmd
, buffer
, sizeof(buffer
));
1936 return set_err(EINVAL
);
1939 if (ata_debugmode
> 1)
1940 pout("%s: Read %d bytes\n", name
, size
);
1942 return set_err(ENOENT
);
1943 if (size
>= (int)sizeof(buffer
))
1944 return set_err(EIO
);
1947 if (ata_debugmode
> 1)
1948 pout("[\n%.100s%s\n]\n", buffer
, (size
>100?"...":""));
1950 // Fake identify sector
1951 ASSERT_SIZEOF(ata_identify_device
, 512);
1952 ata_identify_device
* id
= &m_ident_buf
;
1953 memset(id
, 0, sizeof(*id
));
1954 copy_swapped(id
->model
, findstr(buffer
, " Model = " ), sizeof(id
->model
));
1955 copy_swapped(id
->fw_rev
, findstr(buffer
, " Firmware Version = "), sizeof(id
->fw_rev
));
1956 copy_swapped(id
->serial_no
, findstr(buffer
, " Serial = " ), sizeof(id
->serial_no
));
1957 unsigned long nblocks
= 0; // "Capacity = N.N GB (N Blocks)"
1958 sscanf(findstr(buffer
, "Capacity = "), "%*[^(\r\n](%lu", &nblocks
);
1960 id
->words047_079
[49-47] = 0x0200; // size valid
1961 id
->words047_079
[60-47] = (unsigned short)(nblocks
); // secs_16
1962 id
->words047_079
[61-47] = (unsigned short)(nblocks
>>16); // secs_32
1964 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
1965 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
1967 // Parse smart data hex dump
1968 const char * s
= findstr(buffer
, "Drive Smart Data:");
1970 s
= findstr(buffer
, "Drive SMART Data:"); // tw_cli from 9.5.x
1972 s
= findstr(buffer
, "S.M.A.R.T. (Controller"); // from 3DM browser window
1974 const char * s1
= findstr(s
, "<td class"); // html version
1977 s
+= strcspn(s
, "\r\n");
1980 s
= buffer
; // try raw hex dump without header
1982 unsigned char * sd
= (unsigned char *)&m_smart_buf
;
1985 unsigned x
= ~0; int n
= -1;
1986 if (!(sscanf(s
, "%x %n", &x
, &n
) == 1 && !(x
& ~0xff)))
1988 sd
[i
] = (unsigned char)x
;
1989 if (!(++i
< 512 && n
> 0))
1992 if (*s
== '<') // "<br>"
1993 s
+= strcspn(s
, "\r\n");
1996 if (!id
->model
[1]) {
1997 // No useful data found
1998 char * err
= strstr(buffer
, "Error:");
2000 err
= strstr(buffer
, "error :");
2001 if (err
&& (err
= strchr(err
, ':'))) {
2002 // Show tw_cli error message
2004 err
[strcspn(err
, "\r\n")] = 0;
2005 return set_err(EIO
, "%s", err
);
2007 return set_err(EIO
);
2012 m_ident_valid
= true;
2013 m_smart_valid
= !!sd
;
2018 bool win_tw_cli_device::close()
2020 m_ident_valid
= m_smart_valid
= false;
2025 int win_tw_cli_device::ata_command_interface(smart_command_set command
, int /*select*/, char * data
)
2031 memcpy(data
, &m_ident_buf
, 512);
2036 memcpy(data
, &m_smart_buf
, 512);
2040 case STATUS_CHECK
: // Fake "good" SMART status
2045 // Arrive here for all unsupported commands
2051 /////////////////////////////////////////////////////////////////////////////
2052 // IOCTL_STORAGE_QUERY_PROPERTY
2054 union STORAGE_DEVICE_DESCRIPTOR_DATA
{
2055 STORAGE_DEVICE_DESCRIPTOR desc
;
2059 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device.
2060 // (This works without admin rights)
2062 static int storage_query_property_ioctl(HANDLE hdevice
, STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2064 STORAGE_PROPERTY_QUERY query
= {StorageDeviceProperty
, PropertyStandardQuery
, {0} };
2065 memset(data
, 0, sizeof(*data
));
2068 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_QUERY_PROPERTY
,
2069 &query
, sizeof(query
), data
, sizeof(*data
), &num_out
, NULL
)) {
2070 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2071 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
2076 if (ata_debugmode
> 1 || scsi_debugmode
> 1) {
2077 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n"
2079 " Product: \"%s\"\n"
2080 " Revision: \"%s\"\n"
2082 " BusType: 0x%02x\n",
2083 (data
->desc
.VendorIdOffset
? data
->raw
+data
->desc
.VendorIdOffset
: "(null)"),
2084 (data
->desc
.ProductIdOffset
? data
->raw
+data
->desc
.ProductIdOffset
: "(null)"),
2085 (data
->desc
.ProductRevisionOffset
? data
->raw
+data
->desc
.ProductRevisionOffset
: "(null)"),
2086 (data
->desc
.RemovableMedia
? "Yes":"No"), data
->desc
.BusType
2093 /////////////////////////////////////////////////////////////////////////////
2094 // IOCTL_STORAGE_PREDICT_FAILURE
2096 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value
2097 // or -1 on error, opionally return VendorSpecific data.
2098 // (This works without admin rights)
2100 static int storage_predict_failure_ioctl(HANDLE hdevice
, char * data
= 0)
2102 STORAGE_PREDICT_FAILURE pred
;
2103 memset(&pred
, 0, sizeof(pred
));
2106 if (!DeviceIoControl(hdevice
, IOCTL_STORAGE_PREDICT_FAILURE
,
2107 0, 0, &pred
, sizeof(pred
), &num_out
, NULL
)) {
2108 if (ata_debugmode
> 1)
2109 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
2114 if (ata_debugmode
> 1) {
2115 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
2116 " PredictFailure: 0x%08x\n"
2117 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
2118 (unsigned)pred
.PredictFailure
,
2119 pred
.VendorSpecific
[0], pred
.VendorSpecific
[1], pred
.VendorSpecific
[2],
2120 pred
.VendorSpecific
[sizeof(pred
.VendorSpecific
)-1]
2124 memcpy(data
, pred
.VendorSpecific
, sizeof(pred
.VendorSpecific
));
2125 return (!pred
.PredictFailure
? 0 : 1);
2129 /////////////////////////////////////////////////////////////////////////////
2131 // Return true if ATA drive behind a SAT layer
2132 static bool is_sat(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2134 if (!data
->desc
.VendorIdOffset
)
2136 if (strcmp(data
->raw
+ data
->desc
.VendorIdOffset
, "ATA "))
2141 // Return true if Intel ICHxR RAID volume
2142 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA
* data
)
2144 if (!(data
->desc
.VendorIdOffset
&& data
->desc
.ProductIdOffset
))
2146 const char * vendor
= data
->raw
+ data
->desc
.VendorIdOffset
;
2147 if (!(!strnicmp(vendor
, "Intel", 5) && strspn(vendor
+5, " ") == strlen(vendor
+5)))
2149 if (strnicmp(data
->raw
+ data
->desc
.ProductIdOffset
, "Raid ", 5))
2154 // get DEV_* for open handle
2155 static win_dev_type
get_controller_type(HANDLE hdevice
, bool admin
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2157 // Get BusType from device descriptor
2158 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2159 if (storage_query_property_ioctl(hdevice
, &data
))
2162 // Newer BusType* values are missing in older includes
2163 switch ((int)data
.desc
.BusType
) {
2165 case 0x0b: // BusTypeSata
2166 // Certain Intel AHCI drivers (C600+/C220+) have broken
2167 // IOCTL_ATA_PASS_THROUGH support and a working SAT layer
2172 memset(ata_version_ex
, 0, sizeof(*ata_version_ex
));
2180 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_*
2181 if (is_intel_raid_volume(&data
))
2183 // LSI/3ware RAID volume: supports SMART_*
2184 if (admin
&& smart_get_version(hdevice
, ata_version_ex
) >= 0)
2189 case 0x09: // BusTypeiScsi
2190 case 0x0a: // BusTypeSas
2205 // get DEV_* for device path
2206 static win_dev_type
get_controller_type(const char * path
, GETVERSIONINPARAMS_EX
* ata_version_ex
= 0)
2209 HANDLE h
= CreateFileA(path
, GENERIC_READ
|GENERIC_WRITE
,
2210 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2211 if (h
== INVALID_HANDLE_VALUE
) {
2213 h
= CreateFileA(path
, 0,
2214 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2215 if (h
== INVALID_HANDLE_VALUE
)
2218 if (ata_debugmode
> 1 || scsi_debugmode
> 1)
2219 pout(" %s: successfully opened%s\n", path
, (!admin
? " (without admin rights)" :""));
2220 win_dev_type type
= get_controller_type(h
, admin
, ata_version_ex
);
2225 // get DEV_* for physical drive number
2226 static win_dev_type
get_phy_drive_type(int drive
, GETVERSIONINPARAMS_EX
* ata_version_ex
)
2229 snprintf(path
, sizeof(path
)-1, "\\\\.\\PhysicalDrive%d", drive
);
2230 return get_controller_type(path
, ata_version_ex
);
2233 static win_dev_type
get_phy_drive_type(int drive
)
2235 return get_phy_drive_type(drive
, 0);
2238 // get DEV_* for logical drive number
2239 static win_dev_type
get_log_drive_type(int drive
)
2242 snprintf(path
, sizeof(path
)-1, "\\\\.\\%c:", 'A'+drive
);
2243 return get_controller_type(path
);
2246 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR
2247 static int get_identify_from_device_property(HANDLE hdevice
, ata_identify_device
* id
)
2249 STORAGE_DEVICE_DESCRIPTOR_DATA data
;
2250 if (storage_query_property_ioctl(hdevice
, &data
))
2253 memset(id
, 0, sizeof(*id
));
2255 // Some drivers split ATA model string into VendorId and ProductId,
2256 // others return it as ProductId only.
2257 char model
[sizeof(id
->model
) + 1] = "";
2260 if (data
.desc
.VendorIdOffset
) {
2261 for ( ;i
< sizeof(model
)-1 && data
.raw
[data
.desc
.VendorIdOffset
+i
]; i
++)
2262 model
[i
] = data
.raw
[data
.desc
.VendorIdOffset
+i
];
2265 if (data
.desc
.ProductIdOffset
) {
2266 while (i
> 1 && model
[i
-2] == ' ') // Keep last blank from VendorId
2268 // Ignore VendorId "ATA"
2269 if (i
<= 4 && !strncmp(model
, "ATA", 3) && (i
== 3 || model
[3] == ' '))
2271 for (unsigned j
= 0; i
< sizeof(model
)-1 && data
.raw
[data
.desc
.ProductIdOffset
+j
]; i
++, j
++)
2272 model
[i
] = data
.raw
[data
.desc
.ProductIdOffset
+j
];
2275 while (i
> 0 && model
[i
-1] == ' ')
2278 copy_swapped(id
->model
, model
, sizeof(id
->model
));
2280 if (data
.desc
.ProductRevisionOffset
)
2281 copy_swapped(id
->fw_rev
, data
.raw
+data
.desc
.ProductRevisionOffset
, sizeof(id
->fw_rev
));
2283 id
->command_set_1
= 0x0001; id
->command_set_2
= 0x4000; // SMART supported, words 82,83 valid
2284 id
->cfs_enable_1
= 0x0001; id
->csf_default
= 0x4000; // SMART enabled, words 85,87 valid
2288 // Get Serial Number in IDENTIFY from WMI
2289 static bool get_serial_from_wmi(int drive
, ata_identify_device
* id
)
2291 bool debug
= (ata_debugmode
> 1);
2294 if (!ws
.connect()) {
2296 pout("WMI connect failed\n");
2301 if (!ws
.query1(wo
, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
2302 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2305 std::string serial
= wo
.get_str("SerialNumber");
2307 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive
, wo
.get_str("Model").c_str(), serial
.c_str());
2309 copy_swapped(id
->serial_no
, serial
.c_str(), sizeof(id
->serial_no
));
2314 /////////////////////////////////////////////////////////////////////////////
2315 // USB ID detection using WMI
2317 // Get USB ID for a physical drive number
2318 static bool get_usb_id(int drive
, unsigned short & vendor_id
, unsigned short & product_id
)
2320 bool debug
= (scsi_debugmode
> 1);
2323 if (!ws
.connect()) {
2325 pout("WMI connect failed\n");
2331 if (!ws
.query1(wo
, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive
))
2334 std::string name
= wo
.get_str("Model");
2336 pout("PhysicalDrive%d, \"%s\":\n", drive
, name
.c_str());
2338 // Get USB_CONTROLLER -> DEVICE associations
2340 if (!ws
.query(we
, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice"))
2343 unsigned short usb_venid
= 0, prev_usb_venid
= 0;
2344 unsigned short usb_proid
= 0, prev_usb_proid
= 0;
2345 std::string prev_usb_ant
;
2346 std::string prev_ant
, ant
, dep
;
2348 const regular_expression
regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED
);
2350 while (we
.next(wo
)) {
2352 // Find next 'USB_CONTROLLER, DEVICE' pair
2353 ant
= wo
.get_str("Antecedent");
2354 dep
= wo
.get_str("Dependent");
2356 if (debug
&& ant
!= prev_ant
)
2357 pout(" %s:\n", ant
.c_str());
2360 regmatch_t match
[2];
2361 if (!(regex
.execute(dep
.c_str(), 2, match
) && match
[1].rm_so
>= 0)) {
2363 pout(" | (\"%s\")\n", dep
.c_str());
2367 std::string
devid(dep
.c_str()+match
[1].rm_so
, match
[1].rm_eo
-match
[1].rm_so
);
2369 if (str_starts_with(devid
, "USB\\\\VID_")) {
2370 // USB bridge entry, save CONTROLLER, ID
2372 if (!(sscanf(devid
.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n",
2373 &prev_usb_venid
, &prev_usb_proid
, &nc
) == 2 && nc
== 9+4+5+4)) {
2374 prev_usb_venid
= prev_usb_proid
= 0;
2378 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid
.c_str(), prev_usb_venid
, prev_usb_proid
);
2381 else if (str_starts_with(devid
, "USBSTOR\\\\")) {
2382 // USBSTOR device found
2384 pout(" +--> \"%s\"\n", devid
.c_str());
2388 if (!ws
.query1(wo2
, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid
.c_str()))
2390 std::string name2
= wo2
.get_str("Name");
2392 // Continue if not name of physical disk drive
2393 if (name2
!= name
) {
2395 pout(" +---> (\"%s\")\n", name2
.c_str());
2399 // Fail if previous USB bridge is associated to other controller or ID is unknown
2400 if (!(ant
== prev_usb_ant
&& prev_usb_venid
)) {
2402 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2
.c_str());
2406 // Handle multiple devices with same name
2408 // Fail if multiple devices with same name have different USB bridge types
2409 if (!(usb_venid
== prev_usb_venid
&& usb_proid
== prev_usb_proid
)) {
2411 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2
.c_str());
2417 usb_venid
= prev_usb_venid
;
2418 usb_proid
= prev_usb_proid
;
2420 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2
.c_str(), usb_venid
, usb_proid
);
2422 // Continue to check for duplicate names ...
2426 pout(" | \"%s\"\n", devid
.c_str());
2433 vendor_id
= usb_venid
;
2434 product_id
= usb_proid
;
2440 /////////////////////////////////////////////////////////////////////////////
2442 // Call GetDevicePowerState()
2443 // returns: 1=active, 0=standby, -1=error
2444 // (This would also work for SCSI drives)
2446 static int get_device_power_state(HANDLE hdevice
)
2449 if (!GetDevicePowerState(hdevice
, &state
)) {
2450 long err
= GetLastError();
2452 pout(" GetDevicePowerState() failed, Error=%ld\n", err
);
2453 errno
= (err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
);
2454 // TODO: This may not work as expected on transient errors,
2455 // because smartd interprets -1 as SLEEP mode regardless of errno.
2459 if (ata_debugmode
> 1)
2460 pout(" GetDevicePowerState() succeeded, state=%d\n", state
);
2465 /////////////////////////////////////////////////////////////////////////////
2467 // Get default ATA device options
2469 static const char * ata_get_def_options()
2471 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
2472 // STORAGE_*, SCSI_MINIPORT_*
2476 // Common routines for devices with HANDLEs
2478 win_smart_device::~win_smart_device() throw()
2480 if (m_fh
!= INVALID_HANDLE_VALUE
)
2481 ::CloseHandle(m_fh
);
2484 bool win_smart_device::is_open() const
2486 return (m_fh
!= INVALID_HANDLE_VALUE
);
2489 bool win_smart_device::close()
2491 if (m_fh
== INVALID_HANDLE_VALUE
)
2493 BOOL rc
= ::CloseHandle(m_fh
);
2494 m_fh
= INVALID_HANDLE_VALUE
;
2500 win_ata_device::win_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
2501 : smart_device(intf
, dev_name
, "ata", req_type
),
2502 m_usr_options(false),
2505 m_id_is_cached(false),
2512 win_ata_device::~win_ata_device() throw()
2519 bool win_ata_device::open()
2521 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
2522 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
2523 char drive
[2+1] = "", options
[8+1] = ""; int n1
= -1, n2
= -1;
2524 if ( sscanf(name
, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive
, &n1
, options
, &n2
) >= 1
2525 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2526 return open(sdxy_to_phydrive(drive
), -1, options
, -1);
2528 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
2529 drive
[0] = 0; options
[0] = 0; n1
= -1; n2
= -1;
2531 if ( sscanf(name
, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive
, &port
, &n1
, options
, &n2
) >= 2
2532 && port
< 32 && ((n1
== len
&& !options
[0]) || n2
== len
) ) {
2533 return open(sdxy_to_phydrive(drive
), -1, options
, port
);
2535 // pd<m>,N => Physical drive <m>, RAID port N
2536 int phydrive
= -1; port
= ~0; n1
= -1; n2
= -1;
2537 if ( sscanf(name
, "pd%d%n,%u%n", &phydrive
, &n1
, &port
, &n2
) >= 1
2538 && phydrive
>= 0 && ((n1
== len
&& (int)port
< 0) || (n2
== len
&& port
< 32))) {
2539 return open(phydrive
, -1, "", (int)port
);
2541 // [a-zA-Z]: => Physical drive behind logical drive 0-25
2542 int logdrive
= drive_letter(name
);
2543 if (logdrive
>= 0) {
2544 return open(-1, logdrive
, "", -1);
2547 return set_err(EINVAL
);
2551 bool win_ata_device::open(int phydrive
, int logdrive
, const char * options
, int port
)
2555 if (0 <= phydrive
&& phydrive
<= 255)
2556 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive
= phydrive
));
2557 else if (0 <= logdrive
&& logdrive
<= 'Z'-'A')
2558 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\%c:", 'A'+logdrive
);
2560 return set_err(ENOENT
);
2563 HANDLE h
= INVALID_HANDLE_VALUE
;
2564 if (!(*options
&& !options
[strspn(options
, "fp")])) {
2565 // Open with admin rights
2567 h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
2568 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2569 NULL
, OPEN_EXISTING
, 0, 0);
2571 if (h
== INVALID_HANDLE_VALUE
) {
2572 // Open without admin rights
2574 h
= CreateFileA(devpath
, 0,
2575 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
2576 NULL
, OPEN_EXISTING
, 0, 0);
2578 if (h
== INVALID_HANDLE_VALUE
) {
2579 long err
= GetLastError();
2580 if (err
== ERROR_FILE_NOT_FOUND
)
2581 set_err(ENOENT
, "%s: not found", devpath
);
2582 else if (err
== ERROR_ACCESS_DENIED
)
2583 set_err(EACCES
, "%s: access denied", devpath
);
2585 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
2590 // Warn once if admin rights are missing
2592 static bool noadmin_warning
= false;
2593 if (!noadmin_warning
) {
2594 pout("Warning: Limited functionality due to missing admin rights\n");
2595 noadmin_warning
= true;
2599 if (ata_debugmode
> 1)
2600 pout("%s: successfully opened%s\n", devpath
, (!m_admin
? " (without admin rights)" :""));
2602 m_usr_options
= false;
2604 // Save user options
2605 m_options
= options
; m_usr_options
= true;
2608 // RAID: SMART_* and SCSI_MINIPORT
2611 // Set default options according to Windows version
2612 static const char * def_options
= ata_get_def_options();
2613 m_options
= def_options
;
2616 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
2621 // 3ware RAID: Get port map
2622 GETVERSIONINPARAMS_EX vers_ex
;
2623 int devmap
= smart_get_version(h
, &vers_ex
);
2625 // 3ware RAID if vendor id present
2626 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2628 unsigned long portmap
= 0;
2629 if (port
>= 0 && devmap
>= 0) {
2630 // 3ware RAID: check vendor id
2632 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n"
2633 "This is no 3ware 9000 controller or driver has no SMART support.\n",
2634 vers_ex
.wIdentifier
);
2638 portmap
= vers_ex
.dwDeviceMapEx
;
2641 pout("%s: ATA driver has no SMART support\n", devpath
);
2642 if (!is_permissive()) {
2644 return set_err(ENOSYS
);
2648 m_smartver_state
= 1;
2651 // 3ware RAID: update devicemap first
2653 if (!update_3ware_devicemap_ioctl(h
)) {
2654 if ( smart_get_version(h
, &vers_ex
) >= 0
2655 && vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
)
2656 portmap
= vers_ex
.dwDeviceMapEx
;
2658 // Check port existence
2659 if (!(portmap
& (1L << port
))) {
2660 if (!is_permissive()) {
2662 return set_err(ENOENT
, "%s: Port %d is empty or does not exist", devpath
, port
);
2671 /////////////////////////////////////////////////////////////////////////////
2673 // Interface to ATA devices
2674 bool win_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
2676 // No multi-sector support for now, see above
2677 // warning about IOCTL_ATA_PASS_THROUGH
2678 if (!ata_cmd_is_supported(in
,
2679 ata_device::supports_data_out
|
2680 ata_device::supports_output_regs
|
2681 ata_device::supports_48bit
)
2685 // 3ware RAID: SMART DISABLE without port number disables SMART functions
2686 if ( m_is_3ware
&& m_port
< 0
2687 && in
.in_regs
.command
== ATA_SMART_CMD
2688 && in
.in_regs
.features
== ATA_SMART_DISABLE
)
2689 return set_err(ENOSYS
, "SMART DISABLE requires 3ware port number");
2691 // Determine ioctl functions valid for this ATA cmd
2692 const char * valid_options
= 0;
2694 switch (in
.in_regs
.command
) {
2695 case ATA_IDENTIFY_DEVICE
:
2696 case ATA_IDENTIFY_PACKET_DEVICE
:
2697 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2698 // and SCSI_MINIPORT_* if requested by user
2699 valid_options
= (m_usr_options
? "saimf" : "saif");
2702 case ATA_CHECK_POWER_MODE
:
2703 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk
2704 valid_options
= "pai3";
2708 switch (in
.in_regs
.features
) {
2709 case ATA_SMART_READ_VALUES
:
2710 case ATA_SMART_READ_THRESHOLDS
:
2711 case ATA_SMART_AUTOSAVE
:
2712 case ATA_SMART_ENABLE
:
2713 case ATA_SMART_DISABLE
:
2714 case ATA_SMART_AUTO_OFFLINE
:
2715 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
2716 // and SCSI_MINIPORT_* if requested by user
2717 valid_options
= (m_usr_options
? "saimf" : "saif");
2720 case ATA_SMART_IMMEDIATE_OFFLINE
:
2721 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
2722 valid_options
= (m_usr_options
|| in
.in_regs
.lba_low
!= 127/*ABORT*/ ?
2726 case ATA_SMART_READ_LOG_SECTOR
:
2727 // SMART_RCV_DRIVE_DATA does not support READ_LOG
2728 // Try SCSI_MINIPORT also to skip buggy class driver
2729 // SMART functions do not support multi sector I/O.
2731 valid_options
= (m_usr_options
? "saim3" : "aim3");
2733 valid_options
= "a";
2736 case ATA_SMART_WRITE_LOG_SECTOR
:
2737 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT
2738 // but SCSI_MINIPORT_* only if requested by user and single sector.
2739 valid_options
= (in
.size
== 512 && m_usr_options
? "am" : "a");
2742 case ATA_SMART_STATUS
:
2743 valid_options
= (m_usr_options
? "saimf" : "saif");
2747 // Unknown SMART command, handle below
2753 // Other ATA command, handle below
2757 if (!valid_options
) {
2758 // No special ATA command found above, select a generic pass through ioctl.
2759 if (!( in
.direction
== ata_cmd_in::no_data
2760 || (in
.direction
== ata_cmd_in::data_in
&& in
.size
== 512))
2761 || in
.in_regs
.is_48bit_cmd() )
2762 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
2763 valid_options
= "a";
2765 // ATA/IDE_PASS_THROUGH
2766 valid_options
= "ai";
2770 // Restrict to IOCTL_STORAGE_*
2771 if (strchr(valid_options
, 'f'))
2772 valid_options
= "f";
2773 else if (strchr(valid_options
, 'p'))
2774 valid_options
= "p";
2776 return set_err(ENOSYS
, "Function requires admin rights");
2780 IDEREGS regs
, prev_regs
;
2782 const ata_in_regs
& lo
= in
.in_regs
;
2783 regs
.bFeaturesReg
= lo
.features
;
2784 regs
.bSectorCountReg
= lo
.sector_count
;
2785 regs
.bSectorNumberReg
= lo
.lba_low
;
2786 regs
.bCylLowReg
= lo
.lba_mid
;
2787 regs
.bCylHighReg
= lo
.lba_high
;
2788 regs
.bDriveHeadReg
= lo
.device
;
2789 regs
.bCommandReg
= lo
.command
;
2792 if (in
.in_regs
.is_48bit_cmd()) {
2793 const ata_in_regs
& hi
= in
.in_regs
.prev
;
2794 prev_regs
.bFeaturesReg
= hi
.features
;
2795 prev_regs
.bSectorCountReg
= hi
.sector_count
;
2796 prev_regs
.bSectorNumberReg
= hi
.lba_low
;
2797 prev_regs
.bCylLowReg
= hi
.lba_mid
;
2798 prev_regs
.bCylHighReg
= hi
.lba_high
;
2799 prev_regs
.bDriveHeadReg
= hi
.device
;
2800 prev_regs
.bCommandReg
= hi
.command
;
2801 prev_regs
.bReserved
= 0;
2804 // Set data direction
2807 switch (in
.direction
) {
2808 case ata_cmd_in::no_data
:
2810 case ata_cmd_in::data_in
:
2811 datasize
= (int)in
.size
;
2812 data
= (char *)in
.buffer
;
2814 case ata_cmd_in::data_out
:
2815 datasize
= -(int)in
.size
;
2816 data
= (char *)in
.buffer
;
2819 return set_err(EINVAL
, "win_ata_device::ata_pass_through: invalid direction=%d",
2824 // Try all valid ioctls in the order specified in m_options
2825 bool powered_up
= false;
2826 bool out_regs_set
= false;
2827 bool id_is_cached
= false;
2828 const char * options
= m_options
.c_str();
2830 for (int i
= 0; ; i
++) {
2831 char opt
= options
[i
];
2834 if (in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& powered_up
) {
2835 // Power up reported by GetDevicePowerState() and no ioctl available
2836 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE.
2837 regs
.bSectorCountReg
= 0xff;
2838 out_regs_set
= true;
2842 return set_err(ENOSYS
);
2844 if (!strchr(valid_options
, opt
))
2845 // Invalid for this command
2849 assert( datasize
== 0 || datasize
== 512
2850 || (datasize
== -512 && strchr("am", opt
))
2851 || (datasize
> 512 && opt
== 'a'));
2856 // call SMART_GET_VERSION once for each drive
2857 if (m_smartver_state
> 1) {
2858 rc
= -1; errno
= ENOSYS
;
2861 if (!m_smartver_state
) {
2862 assert(m_port
== -1);
2863 GETVERSIONINPARAMS_EX vers_ex
;
2864 if (smart_get_version(get_fh(), &vers_ex
) < 0) {
2865 if (!failuretest_permissive
) {
2866 m_smartver_state
= 2;
2867 rc
= -1; errno
= ENOSYS
;
2870 failuretest_permissive
--;
2873 // 3ware RAID if vendor id present
2874 m_is_3ware
= (vers_ex
.wIdentifier
== SMART_VENDOR_3WARE
);
2877 m_smartver_state
= 1;
2879 rc
= smart_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2880 out_regs_set
= (in
.in_regs
.features
== ATA_SMART_STATUS
);
2881 id_is_cached
= (m_port
< 0); // Not cached by 3ware driver
2884 rc
= ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s
, data
, datasize
);
2885 id_is_cached
= (m_port
< 0);
2888 rc
= ata_pass_through_ioctl(get_fh(), ®s
,
2889 (in
.in_regs
.is_48bit_cmd() ? &prev_regs
: 0),
2891 out_regs_set
= true;
2894 rc
= ide_pass_through_ioctl(get_fh(), ®s
, data
, datasize
);
2895 out_regs_set
= true;
2898 if (in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
) {
2899 rc
= get_identify_from_device_property(get_fh(), (ata_identify_device
*)data
);
2900 if (rc
== 0 && m_phydrive
>= 0)
2901 get_serial_from_wmi(m_phydrive
, (ata_identify_device
*)data
);
2902 id_is_cached
= true;
2904 else if (in
.in_regs
.command
== ATA_SMART_CMD
) switch (in
.in_regs
.features
) {
2905 case ATA_SMART_READ_VALUES
:
2906 rc
= storage_predict_failure_ioctl(get_fh(), data
);
2910 case ATA_SMART_ENABLE
:
2913 case ATA_SMART_STATUS
:
2914 rc
= storage_predict_failure_ioctl(get_fh());
2916 // Good SMART status
2917 out
.out_regs
.lba_high
= 0xc2; out
.out_regs
.lba_mid
= 0x4f;
2921 out
.out_regs
.lba_high
= 0x2c; out
.out_regs
.lba_mid
= 0xf4;
2926 errno
= ENOSYS
; rc
= -1;
2929 errno
= ENOSYS
; rc
= -1;
2933 rc
= ata_via_3ware_miniport_ioctl(get_fh(), ®s
, data
, datasize
, m_port
);
2934 out_regs_set
= true;
2937 assert(in
.in_regs
.command
== ATA_CHECK_POWER_MODE
&& in
.size
== 0);
2938 rc
= get_device_power_state(get_fh());
2940 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would
2941 // spin up the drive => simulate ATA result STANDBY.
2942 regs
.bSectorCountReg
= 0x00;
2943 out_regs_set
= true;
2946 // Power up reported by GetDevicePowerState(), but this reflects the actual mode
2947 // only if it is selected by the device driver => try a passthrough ioctl to get the
2948 // actual mode, if none available simulate ACTIVE/IDLE.
2950 rc
= -1; errno
= ENOSYS
;
2956 // Working ioctl found
2959 if (errno
!= ENOSYS
)
2960 // Abort on I/O error
2961 return set_err(errno
);
2963 out_regs_set
= false;
2964 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case
2967 // Return IDEREGS if set
2969 ata_out_regs
& lo
= out
.out_regs
;
2970 lo
.error
= regs
.bFeaturesReg
;
2971 lo
.sector_count
= regs
.bSectorCountReg
;
2972 lo
.lba_low
= regs
.bSectorNumberReg
;
2973 lo
.lba_mid
= regs
.bCylLowReg
;
2974 lo
.lba_high
= regs
.bCylHighReg
;
2975 lo
.device
= regs
.bDriveHeadReg
;
2976 lo
.status
= regs
.bCommandReg
;
2977 if (in
.in_regs
.is_48bit_cmd()) {
2978 ata_out_regs
& hi
= out
.out_regs
.prev
;
2979 hi
.sector_count
= prev_regs
.bSectorCountReg
;
2980 hi
.lba_low
= prev_regs
.bSectorNumberReg
;
2981 hi
.lba_mid
= prev_regs
.bCylLowReg
;
2982 hi
.lba_high
= prev_regs
.bCylHighReg
;
2986 if ( in
.in_regs
.command
== ATA_IDENTIFY_DEVICE
2987 || in
.in_regs
.command
== ATA_IDENTIFY_PACKET_DEVICE
)
2988 // Update ata_identify_is_cached() result according to ioctl used.
2989 m_id_is_cached
= id_is_cached
;
2994 // Return true if OS caches the ATA identify sector
2995 bool win_ata_device::ata_identify_is_cached() const
2997 return m_id_is_cached
;
3001 //////////////////////////////////////////////////////////////////////
3004 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO
& phy_info
)
3006 // Get driver info to check CSMI support
3007 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf
;
3008 memset(&driver_info_buf
, 0, sizeof(driver_info_buf
));
3009 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO
, &driver_info_buf
.IoctlHeader
, sizeof(driver_info_buf
)))
3012 if (scsi_debugmode
> 1) {
3013 const CSMI_SAS_DRIVER_INFO
& driver_info
= driver_info_buf
.Information
;
3014 pout("CSMI_SAS_DRIVER_INFO:\n");
3015 pout(" Name: \"%.81s\"\n", driver_info
.szName
);
3016 pout(" Description: \"%.81s\"\n", driver_info
.szDescription
);
3017 pout(" Revision: %d.%d\n", driver_info
.usMajorRevision
, driver_info
.usMinorRevision
);
3021 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf
;
3022 memset(&phy_info_buf
, 0, sizeof(phy_info_buf
));
3023 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO
, &phy_info_buf
.IoctlHeader
, sizeof(phy_info_buf
)))
3026 phy_info
= phy_info_buf
.Information
;
3028 const int max_number_of_phys
= sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]);
3029 if (phy_info
.bNumberOfPhys
> max_number_of_phys
)
3030 return set_err(EIO
, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info
.bNumberOfPhys
);
3032 if (scsi_debugmode
> 1) {
3033 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info
.bNumberOfPhys
);
3034 for (int i
= 0; i
< max_number_of_phys
; i
++) {
3035 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3036 const CSMI_SAS_IDENTIFY
& id
= pe
.Identify
, & at
= pe
.Attached
;
3037 if (id
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3040 pout("Phy[%d] Port: 0x%02x\n", i
, pe
.bPortIdentifier
);
3041 pout(" Type: 0x%02x, 0x%02x\n", id
.bDeviceType
, at
.bDeviceType
);
3042 pout(" InitProto: 0x%02x, 0x%02x\n", id
.bInitiatorPortProtocol
, at
.bInitiatorPortProtocol
);
3043 pout(" TargetProto: 0x%02x, 0x%02x\n", id
.bTargetPortProtocol
, at
.bTargetPortProtocol
);
3044 pout(" PhyIdent: 0x%02x, 0x%02x\n", id
.bPhyIdentifier
, at
.bPhyIdentifier
);
3045 const unsigned char * b
= id
.bSASAddress
;
3046 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ",
3047 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
3049 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n",
3050 b
[0], b
[1], b
[2], b
[3], b
[4], b
[5], b
[6], b
[7]);
3057 unsigned csmi_device::get_ports_used()
3059 CSMI_SAS_PHY_INFO phy_info
;
3060 if (!get_phy_info(phy_info
))
3063 unsigned ports_used
= 0;
3064 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
3065 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3066 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3068 if (pe
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3070 switch (pe
.Attached
.bTargetPortProtocol
) {
3071 case CSMI_SAS_PROTOCOL_SATA
:
3072 case CSMI_SAS_PROTOCOL_STP
:
3078 if (pe
.bPortIdentifier
== 0xff)
3079 // Older (<= 9.*) Intel RST driver
3080 ports_used
|= (1 << i
);
3082 ports_used
|= (1 << pe
.bPortIdentifier
);
3089 bool csmi_device::select_port(int port
)
3091 CSMI_SAS_PHY_INFO phy_info
;
3092 if (!get_phy_info(phy_info
))
3096 int max_port
= -1, port_index
= -1;
3097 for (unsigned i
= 0; i
< sizeof(phy_info
.Phy
) / sizeof(phy_info
.Phy
[0]); i
++) {
3098 const CSMI_SAS_PHY_ENTITY
& pe
= phy_info
.Phy
[i
];
3099 if (pe
.Identify
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3102 if (pe
.bPortIdentifier
== 0xff) {
3103 // Older (<= 9.*) Intel RST driver
3104 max_port
= phy_info
.bNumberOfPhys
- 1;
3105 if (i
>= phy_info
.bNumberOfPhys
)
3111 if (pe
.bPortIdentifier
> max_port
)
3112 max_port
= pe
.bPortIdentifier
;
3113 if (pe
.bPortIdentifier
!= port
)
3121 if (port_index
< 0) {
3122 if (port
<= max_port
)
3123 return set_err(ENOENT
, "Port %d is disabled", port
);
3125 return set_err(ENOENT
, "Port %d does not exist (#ports: %d)", port
,
3129 const CSMI_SAS_PHY_ENTITY
& phy_ent
= phy_info
.Phy
[port_index
];
3130 if (phy_ent
.Attached
.bDeviceType
== CSMI_SAS_NO_DEVICE_ATTACHED
)
3131 return set_err(ENOENT
, "No device on port %d", port
);
3133 switch (phy_ent
.Attached
.bTargetPortProtocol
) {
3134 case CSMI_SAS_PROTOCOL_SATA
:
3135 case CSMI_SAS_PROTOCOL_STP
:
3138 return set_err(ENOENT
, "No SATA device on port %d (protocol: %d)",
3139 port
, phy_ent
.Attached
.bTargetPortProtocol
);
3142 m_phy_ent
= phy_ent
;
3147 bool csmi_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
3149 if (!ata_cmd_is_supported(in
,
3150 ata_device::supports_data_out
|
3151 ata_device::supports_output_regs
|
3152 ata_device::supports_multi_sector
|
3153 ata_device::supports_48bit
,
3158 // Create buffer with appropriate size
3159 raw_buffer
pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER
) + in
.size
);
3160 CSMI_SAS_STP_PASSTHRU_BUFFER
* pthru_buf
= (CSMI_SAS_STP_PASSTHRU_BUFFER
*)pthru_raw_buf
.data();
3162 // Set addresses from Phy info
3163 CSMI_SAS_STP_PASSTHRU
& pthru
= pthru_buf
->Parameters
;
3164 const CSMI_SAS_PHY_ENTITY
& phy_ent
= get_phy_ent();
3165 pthru
.bPhyIdentifier
= phy_ent
.Identify
.bPhyIdentifier
;
3166 pthru
.bPortIdentifier
= phy_ent
.bPortIdentifier
;
3167 memcpy(pthru
.bDestinationSASAddress
, phy_ent
.Attached
.bSASAddress
,
3168 sizeof(pthru
.bDestinationSASAddress
));
3169 pthru
.bConnectionRate
= CSMI_SAS_LINK_RATE_NEGOTIATED
;
3171 // Set transfer mode
3172 switch (in
.direction
) {
3173 case ata_cmd_in::no_data
:
3174 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_UNSPECIFIED
;
3176 case ata_cmd_in::data_in
:
3177 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_READ
;
3178 pthru
.uDataLength
= in
.size
;
3180 case ata_cmd_in::data_out
:
3181 pthru
.uFlags
= CSMI_SAS_STP_PIO
| CSMI_SAS_STP_WRITE
;
3182 pthru
.uDataLength
= in
.size
;
3183 memcpy(pthru_buf
->bDataBuffer
, in
.buffer
, in
.size
);
3186 return set_err(EINVAL
, "csmi_ata_device::ata_pass_through: invalid direction=%d",
3190 // Set host-to-device FIS
3192 unsigned char * fis
= pthru
.bCommandFIS
;
3193 const ata_in_regs
& lo
= in
.in_regs
;
3194 const ata_in_regs
& hi
= in
.in_regs
.prev
;
3195 fis
[ 0] = 0x27; // Type: host-to-device FIS
3196 fis
[ 1] = 0x80; // Bit7: Update command register
3197 fis
[ 2] = lo
.command
;
3198 fis
[ 3] = lo
.features
;
3199 fis
[ 4] = lo
.lba_low
;
3200 fis
[ 5] = lo
.lba_mid
;
3201 fis
[ 6] = lo
.lba_high
;
3202 fis
[ 7] = lo
.device
;
3203 fis
[ 8] = hi
.lba_low
;
3204 fis
[ 9] = hi
.lba_mid
;
3205 fis
[10] = hi
.lba_high
;
3206 fis
[11] = hi
.features
;
3207 fis
[12] = lo
.sector_count
;
3208 fis
[13] = hi
.sector_count
;
3212 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU
, &pthru_buf
->IoctlHeader
, pthru_raw_buf
.size())) {
3216 // Get device-to-host FIS
3218 const unsigned char * fis
= pthru_buf
->Status
.bStatusFIS
;
3219 ata_out_regs
& lo
= out
.out_regs
;
3220 lo
.status
= fis
[ 2];
3222 lo
.lba_low
= fis
[ 4];
3223 lo
.lba_mid
= fis
[ 5];
3224 lo
.lba_high
= fis
[ 6];
3225 lo
.device
= fis
[ 7];
3226 lo
.sector_count
= fis
[12];
3227 if (in
.in_regs
.is_48bit_cmd()) {
3228 ata_out_regs
& hi
= out
.out_regs
.prev
;
3229 hi
.lba_low
= fis
[ 8];
3230 hi
.lba_mid
= fis
[ 9];
3231 hi
.lba_high
= fis
[10];
3232 hi
.sector_count
= fis
[13];
3237 if (in
.direction
== ata_cmd_in::data_in
)
3238 // TODO: Check ptru_buf->Status.uDataBytes
3239 memcpy(in
.buffer
, pthru_buf
->bDataBuffer
, in
.size
);
3245 //////////////////////////////////////////////////////////////////////
3248 win_csmi_device::win_csmi_device(smart_interface
* intf
, const char * dev_name
,
3249 const char * req_type
)
3250 : smart_device(intf
, dev_name
, "ata", req_type
),
3251 m_fh(INVALID_HANDLE_VALUE
), m_port(-1)
3255 win_csmi_device::~win_csmi_device() throw()
3257 if (m_fh
!= INVALID_HANDLE_VALUE
)
3261 bool win_csmi_device::is_open() const
3263 return (m_fh
!= INVALID_HANDLE_VALUE
);
3266 bool win_csmi_device::close()
3268 if (m_fh
== INVALID_HANDLE_VALUE
)
3270 BOOL rc
= CloseHandle(m_fh
);
3271 m_fh
= INVALID_HANDLE_VALUE
;
3276 bool win_csmi_device::open_scsi()
3279 unsigned contr_no
= ~0, port
= ~0; int nc
= -1;
3280 const char * name
= skipdev(get_dev_name());
3281 if (!( sscanf(name
, "csmi%u,%u%n", &contr_no
, &port
, &nc
) >= 0
3282 && nc
== (int)strlen(name
) && contr_no
<= 9 && port
< 32) )
3283 return set_err(EINVAL
);
3285 // Open controller handle
3287 snprintf(devpath
, sizeof(devpath
)-1, "\\\\.\\Scsi%u:", contr_no
);
3289 HANDLE h
= CreateFileA(devpath
, GENERIC_READ
|GENERIC_WRITE
,
3290 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3291 (SECURITY_ATTRIBUTES
*)0, OPEN_EXISTING
, 0, 0);
3293 if (h
== INVALID_HANDLE_VALUE
) {
3294 long err
= GetLastError();
3295 if (err
== ERROR_FILE_NOT_FOUND
)
3296 set_err(ENOENT
, "%s: not found", devpath
);
3297 else if (err
== ERROR_ACCESS_DENIED
)
3298 set_err(EACCES
, "%s: access denied", devpath
);
3300 set_err(EIO
, "%s: Error=%ld", devpath
, err
);
3304 if (scsi_debugmode
> 1)
3305 pout(" %s: successfully opened\n", devpath
);
3313 bool win_csmi_device::open()
3318 // Get Phy info for this drive
3319 if (!select_port(m_port
)) {
3328 bool win_csmi_device::csmi_ioctl(unsigned code
, IOCTL_HEADER
* csmi_buffer
,
3329 unsigned csmi_bufsiz
)
3331 // Determine signature
3334 case CC_CSMI_SAS_GET_DRIVER_INFO
:
3335 sig
= CSMI_ALL_SIGNATURE
; break;
3336 case CC_CSMI_SAS_GET_PHY_INFO
:
3337 case CC_CSMI_SAS_STP_PASSTHRU
:
3338 sig
= CSMI_SAS_SIGNATURE
; break;
3340 return set_err(ENOSYS
, "Unknown CSMI code=%u", code
);
3344 csmi_buffer
->HeaderLength
= sizeof(IOCTL_HEADER
);
3345 strncpy((char *)csmi_buffer
->Signature
, sig
, sizeof(csmi_buffer
->Signature
));
3346 csmi_buffer
->Timeout
= CSMI_SAS_TIMEOUT
;
3347 csmi_buffer
->ControlCode
= code
;
3348 csmi_buffer
->ReturnCode
= 0;
3349 csmi_buffer
->Length
= csmi_bufsiz
- sizeof(IOCTL_HEADER
);
3353 if (!DeviceIoControl(m_fh
, IOCTL_SCSI_MINIPORT
,
3354 csmi_buffer
, csmi_bufsiz
, csmi_buffer
, csmi_bufsiz
, &num_out
, (OVERLAPPED
*)0)) {
3355 long err
= GetLastError();
3357 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code
, err
);
3358 if ( err
== ERROR_INVALID_FUNCTION
3359 || err
== ERROR_NOT_SUPPORTED
3360 || err
== ERROR_DEV_NOT_EXIST
)
3361 return set_err(ENOSYS
, "CSMI is not supported (Error=%ld)", err
);
3363 return set_err(EIO
, "CSMI(%u) failed with Error=%ld", code
, err
);
3367 if (csmi_buffer
->ReturnCode
) {
3368 if (scsi_debugmode
) {
3369 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
3370 code
, (unsigned)csmi_buffer
->ReturnCode
);
3372 return set_err(EIO
, "CSMI(%u) failed with ReturnCode=%u", code
, (unsigned)csmi_buffer
->ReturnCode
);
3375 if (scsi_debugmode
> 1)
3376 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code
, (unsigned)num_out
);
3382 /////////////////////////////////////////////////////////////////////////////
3383 // SPT Interface (for SCSI devices and ATA devices behind SATLs)
3384 // Only supported in NT and later
3385 /////////////////////////////////////////////////////////////////////////////
3387 win_scsi_device::win_scsi_device(smart_interface
* intf
,
3388 const char * dev_name
, const char * req_type
)
3389 : smart_device(intf
, dev_name
, "scsi", req_type
)
3393 bool win_scsi_device::open()
3395 const char * name
= skipdev(get_dev_name()); int len
= strlen(name
);
3396 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
3397 char drive
[2+1] = ""; int sub_addr
= -1; int n1
= -1; int n2
= -1;
3398 if ( sscanf(name
, "sd%2[a-z]%n,%d%n", drive
, &n1
, &sub_addr
, &n2
) >= 1
3399 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0)) ) {
3400 return open(sdxy_to_phydrive(drive
), -1, -1, sub_addr
);
3402 // pd<m>,N => Physical drive <m>, RAID port N
3403 int pd_num
= -1; sub_addr
= -1; n1
= -1; n2
= -1;
3404 if ( sscanf(name
, "pd%d%n,%d%n", &pd_num
, &n1
, &sub_addr
, &n2
) >= 1
3405 && pd_num
>= 0 && ((n1
== len
&& sub_addr
== -1) || (n2
== len
&& sub_addr
>= 0))) {
3406 return open(pd_num
, -1, -1, sub_addr
);
3408 // [a-zA-Z]: => Physical drive behind logical drive 0-25
3409 int logdrive
= drive_letter(name
);
3410 if (logdrive
>= 0) {
3411 return open(-1, logdrive
, -1, -1);
3413 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation)
3414 int tape_num
= -1; n1
= -1;
3415 if (sscanf(name
, "st%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3416 return open(-1, -1, tape_num
, -1);
3418 tape_num
= -1; n1
= -1;
3419 if (sscanf(name
, "nst%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3420 return open(-1, -1, tape_num
, -1);
3422 // tape<m> => tape drive <m>
3423 tape_num
= -1; n1
= -1;
3424 if (sscanf(name
, "tape%d%n", &tape_num
, &n1
) == 1 && tape_num
>= 0 && n1
== len
) {
3425 return open(-1, -1, tape_num
, -1);
3428 return set_err(EINVAL
);
3431 bool win_scsi_device::open(int pd_num
, int ld_num
, int tape_num
, int /*sub_addr*/)
3434 b
[sizeof(b
) - 1] = '\0';
3436 snprintf(b
, sizeof(b
) - 1, "\\\\.\\PhysicalDrive%d", pd_num
);
3437 else if (ld_num
>= 0)
3438 snprintf(b
, sizeof(b
) - 1, "\\\\.\\%c:", 'A' + ld_num
);
3439 else if (tape_num
>= 0)
3440 snprintf(b
, sizeof(b
) - 1, "\\\\.\\TAPE%d", tape_num
);
3447 HANDLE h
= CreateFileA(b
, GENERIC_READ
|GENERIC_WRITE
,
3448 FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
3449 OPEN_EXISTING
, 0, 0);
3450 if (h
== INVALID_HANDLE_VALUE
) {
3451 set_err(ENODEV
, "%s: Open failed, Error=%u", b
, (unsigned)GetLastError());
3460 SCSI_PASS_THROUGH_DIRECT spt
;
3462 UCHAR ucSenseBuf
[64];
3463 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
;
3466 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT.
3467 // Used if DataTransferLength not supported by *_DIRECT.
3468 static long scsi_pass_through_indirect(HANDLE h
,
3469 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
* sbd
)
3471 struct SCSI_PASS_THROUGH_WITH_BUFFERS
{
3472 SCSI_PASS_THROUGH spt
;
3474 UCHAR ucSenseBuf
[sizeof(sbd
->ucSenseBuf
)];
3475 UCHAR ucDataBuf
[512];
3478 SCSI_PASS_THROUGH_WITH_BUFFERS sb
;
3479 memset(&sb
, 0, sizeof(sb
));
3481 // DATA_OUT not implemented yet
3482 if (!( sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
3483 && sbd
->spt
.DataTransferLength
<= sizeof(sb
.ucDataBuf
)))
3484 return ERROR_INVALID_PARAMETER
;
3486 sb
.spt
.Length
= sizeof(sb
.spt
);
3487 sb
.spt
.CdbLength
= sbd
->spt
.CdbLength
;
3488 memcpy(sb
.spt
.Cdb
, sbd
->spt
.Cdb
, sizeof(sb
.spt
.Cdb
));
3489 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3490 sb
.spt
.SenseInfoOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucSenseBuf
);
3491 sb
.spt
.DataIn
= sbd
->spt
.DataIn
;
3492 sb
.spt
.DataTransferLength
= sbd
->spt
.DataTransferLength
;
3493 sb
.spt
.DataBufferOffset
= offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
3494 sb
.spt
.TimeOutValue
= sbd
->spt
.TimeOutValue
;
3497 if (!DeviceIoControl(h
, IOCTL_SCSI_PASS_THROUGH
,
3498 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3499 return GetLastError();
3501 sbd
->spt
.ScsiStatus
= sb
.spt
.ScsiStatus
;
3502 if (sb
.spt
.ScsiStatus
& SCSI_STATUS_CHECK_CONDITION
)
3503 memcpy(sbd
->ucSenseBuf
, sb
.ucSenseBuf
, sizeof(sbd
->ucSenseBuf
));
3505 sbd
->spt
.DataTransferLength
= sb
.spt
.DataTransferLength
;
3506 if (sbd
->spt
.DataIn
== SCSI_IOCTL_DATA_IN
&& sb
.spt
.DataTransferLength
> 0)
3507 memcpy(sbd
->spt
.DataBuffer
, sb
.ucDataBuf
, sb
.spt
.DataTransferLength
);
3512 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3513 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io
* iop
)
3515 int report
= scsi_debugmode
; // TODO
3519 const unsigned char * ucp
= iop
->cmnd
;
3522 const int sz
= (int)sizeof(buff
);
3524 np
= scsi_get_opcode_name(ucp
[0]);
3525 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3526 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3527 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3529 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3530 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3532 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3533 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3534 (trunc
? " [only first 256 bytes shown]" : ""));
3535 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3538 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3542 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3543 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3544 set_err(EINVAL
, "cmnd_len too large");
3548 memset(&sb
, 0, sizeof(sb
));
3549 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3550 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3551 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3552 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3553 sb
.spt
.SenseInfoOffset
=
3554 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3555 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3558 switch (iop
->dxfer_dir
) {
3560 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3562 case DXFER_FROM_DEVICE
:
3563 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3564 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3565 sb
.spt
.DataBuffer
= iop
->dxferp
;
3566 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3567 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3568 if (sb
.spt
.DataTransferLength
== 1)
3571 case DXFER_TO_DEVICE
:
3572 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3573 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3574 sb
.spt
.DataBuffer
= iop
->dxferp
;
3577 set_err(EINVAL
, "bad dxfer_dir");
3584 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3585 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3586 err
= GetLastError();
3589 err
= scsi_pass_through_indirect(get_fh(), &sb
);
3592 return set_err((err
== ERROR_INVALID_FUNCTION
? ENOSYS
: EIO
),
3593 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld",
3594 (direct
? "_DIRECT" : ""), err
);
3596 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3597 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3598 int slen
= sb
.ucSenseBuf
[7] + 8;
3600 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3601 slen
= sizeof(sb
.ucSenseBuf
);
3602 if (slen
> (int)iop
->max_sense_len
)
3603 slen
= iop
->max_sense_len
;
3604 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3605 iop
->resp_sense_len
= slen
;
3608 pout(" >>> Sense buffer, len=%d:\n", slen
);
3609 dStrHex(iop
->sensep
, slen
, 1);
3611 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3612 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3613 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3614 iop
->sensep
[2], iop
->sensep
[3]);
3616 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3617 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3618 iop
->sensep
[12], iop
->sensep
[13]);
3621 iop
->resp_sense_len
= 0;
3623 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3624 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3628 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3629 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3630 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3631 (trunc
? " [only first 256 bytes shown]" : ""));
3632 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3637 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c
3638 static long scsi_pass_through_direct(HANDLE fd
, UCHAR targetid
, struct scsi_cmnd_io
* iop
)
3640 int report
= scsi_debugmode
; // TODO
3644 const unsigned char * ucp
= iop
->cmnd
;
3647 const int sz
= (int)sizeof(buff
);
3649 np
= scsi_get_opcode_name(ucp
[0]);
3650 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
3651 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
3652 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
3654 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
3655 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3657 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
3658 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
3659 (trunc
? " [only first 256 bytes shown]" : ""));
3660 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3663 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
3667 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb
;
3668 if (iop
->cmnd_len
> (int)sizeof(sb
.spt
.Cdb
)) {
3672 memset(&sb
, 0, sizeof(sb
));
3673 sb
.spt
.Length
= sizeof(SCSI_PASS_THROUGH_DIRECT
);
3674 //sb.spt.PathId = 0;
3675 sb
.spt
.TargetId
= targetid
;
3677 sb
.spt
.CdbLength
= iop
->cmnd_len
;
3678 memcpy(sb
.spt
.Cdb
, iop
->cmnd
, iop
->cmnd_len
);
3679 sb
.spt
.SenseInfoLength
= sizeof(sb
.ucSenseBuf
);
3680 sb
.spt
.SenseInfoOffset
=
3681 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
, ucSenseBuf
);
3682 sb
.spt
.TimeOutValue
= (iop
->timeout
? iop
->timeout
: 60);
3685 switch (iop
->dxfer_dir
) {
3687 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_UNSPECIFIED
;
3689 case DXFER_FROM_DEVICE
:
3690 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_IN
;
3691 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3692 sb
.spt
.DataBuffer
= iop
->dxferp
;
3693 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
3694 // transfers (needed for SMART STATUS check of JMicron USB bridges)
3695 if (sb
.spt
.DataTransferLength
== 1)
3698 case DXFER_TO_DEVICE
:
3699 sb
.spt
.DataIn
= SCSI_IOCTL_DATA_OUT
;
3700 sb
.spt
.DataTransferLength
= iop
->dxfer_len
;
3701 sb
.spt
.DataBuffer
= iop
->dxferp
;
3710 if (!DeviceIoControl(fd
, IOCTL_SCSI_PASS_THROUGH_DIRECT
,
3711 &sb
, sizeof(sb
), &sb
, sizeof(sb
), &num_out
, 0))
3712 err
= GetLastError();
3715 err
= scsi_pass_through_indirect(fd
, &sb
);
3722 iop
->scsi_status
= sb
.spt
.ScsiStatus
;
3723 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
3724 int slen
= sb
.ucSenseBuf
[7] + 8;
3726 if (slen
> (int)sizeof(sb
.ucSenseBuf
))
3727 slen
= sizeof(sb
.ucSenseBuf
);
3728 if (slen
> (int)iop
->max_sense_len
)
3729 slen
= iop
->max_sense_len
;
3730 memcpy(iop
->sensep
, sb
.ucSenseBuf
, slen
);
3731 iop
->resp_sense_len
= slen
;
3734 pout(" >>> Sense buffer, len=%d:\n", slen
);
3735 dStrHex(iop
->sensep
, slen
, 1);
3737 if ((iop
->sensep
[0] & 0x7f) > 0x71)
3738 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
3739 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
3740 iop
->sensep
[2], iop
->sensep
[3]);
3742 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
3743 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
3744 iop
->sensep
[12], iop
->sensep
[13]);
3747 iop
->resp_sense_len
= 0;
3749 if (iop
->dxfer_len
> sb
.spt
.DataTransferLength
)
3750 iop
->resid
= iop
->dxfer_len
- sb
.spt
.DataTransferLength
;
3754 if ((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)) {
3755 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
3756 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
3757 (trunc
? " [only first 256 bytes shown]" : ""));
3758 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
3764 // Areca RAID Controller(SAS Device)
3765 win_areca_scsi_device::win_areca_scsi_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3766 : smart_device(intf
, dev_name
, "areca", "areca")
3768 set_fh(INVALID_HANDLE_VALUE
);
3769 set_disknum(disknum
);
3771 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3774 bool win_areca_scsi_device::open()
3782 hFh
= CreateFile( get_dev_name(),
3783 GENERIC_READ
|GENERIC_WRITE
,
3784 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3789 if(hFh
== INVALID_HANDLE_VALUE
)
3798 smart_device
* win_areca_scsi_device::autodetect_open()
3803 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3805 int ioctlreturn
= 0;
3807 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3808 if ( ioctlreturn
|| iop
->scsi_status
)
3810 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3811 if ( ioctlreturn
|| iop
->scsi_status
)
3821 bool win_areca_scsi_device::arcmsr_lock()
3823 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3827 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3828 return set_err(EINVAL
, "unable to parse device name");
3830 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3831 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3832 if ( m_mutex
== NULL
)
3834 return set_err(EIO
, "CreateMutex failed");
3837 // atomic access to driver
3838 WaitForSingleObject(m_mutex
, INFINITE
);
3844 bool win_areca_scsi_device::arcmsr_unlock()
3846 if( m_mutex
!= NULL
)
3848 ReleaseMutex(m_mutex
);
3849 CloseHandle(m_mutex
);
3856 // Areca RAID Controller(SATA Disk)
3857 win_areca_ata_device::win_areca_ata_device(smart_interface
* intf
, const char * dev_name
, int disknum
, int encnum
)
3858 : smart_device(intf
, dev_name
, "areca", "areca")
3860 set_fh(INVALID_HANDLE_VALUE
);
3861 set_disknum(disknum
);
3863 set_info().info_name
= strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name
, disknum
, encnum
);
3866 bool win_areca_ata_device::open()
3874 hFh
= CreateFile( get_dev_name(),
3875 GENERIC_READ
|GENERIC_WRITE
,
3876 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3881 if(hFh
== INVALID_HANDLE_VALUE
)
3890 smart_device
* win_areca_ata_device::autodetect_open()
3894 // autodetect device type
3895 is_ata
= arcmsr_get_dev_type();
3909 smart_device_auto_ptr
newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
3912 newdev
->open(); // TODO: Can possibly pass open fd
3914 return newdev
.release();
3917 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io
* iop
)
3919 int ioctlreturn
= 0;
3921 ioctlreturn
= scsi_pass_through_direct(get_fh(), 16, iop
);
3922 if ( ioctlreturn
|| iop
->scsi_status
)
3924 ioctlreturn
= scsi_pass_through_direct(get_fh(), 127, iop
);
3925 if ( ioctlreturn
|| iop
->scsi_status
)
3935 bool win_areca_ata_device::arcmsr_lock()
3937 #define SYNCOBJNAME "Global\\SynIoctlMutex"
3941 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum
) < 1)
3942 return set_err(EINVAL
, "unable to parse device name");
3944 snprintf(mutexstr
, sizeof(mutexstr
), "%s%d", SYNCOBJNAME
, ctlrnum
);
3945 m_mutex
= CreateMutex(NULL
, FALSE
, mutexstr
);
3946 if ( m_mutex
== NULL
)
3948 return set_err(EIO
, "CreateMutex failed");
3951 // atomic access to driver
3952 WaitForSingleObject(m_mutex
, INFINITE
);
3958 bool win_areca_ata_device::arcmsr_unlock()
3960 if( m_mutex
!= NULL
)
3962 ReleaseMutex(m_mutex
);
3963 CloseHandle(m_mutex
);
3970 win_aacraid_device::win_aacraid_device(smart_interface
* intf
,
3971 const char *dev_name
, unsigned ctrnum
, unsigned target
, unsigned lun
)
3972 : smart_device(intf
, dev_name
, "aacraid", "aacraid"),
3973 m_ctrnum(ctrnum
), m_lun(lun
), m_target(target
)
3975 set_info().info_name
= strprintf("%s [aacraid_disk_%02d_%02d_%d]", dev_name
, m_ctrnum
, m_lun
, m_target
);
3976 set_info().dev_type
= strprintf("aacraid,%d,%d,%d", m_ctrnum
, m_lun
, m_target
);
3979 win_aacraid_device::~win_aacraid_device() throw()
3983 bool win_aacraid_device::open()
3988 HANDLE hFh
= CreateFile( get_dev_name(),
3989 GENERIC_READ
|GENERIC_WRITE
,
3990 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
3995 if (hFh
== INVALID_HANDLE_VALUE
)
3996 return set_err(ENODEV
, "Open failed, Error=%u", (unsigned)GetLastError());
4002 bool win_aacraid_device::scsi_pass_through(struct scsi_cmnd_io
*iop
)
4004 int report
= scsi_debugmode
;
4008 const unsigned char * ucp
= iop
->cmnd
;
4011 const int sz
= (int)sizeof(buff
);
4012 np
= scsi_get_opcode_name(ucp
[0]);
4013 j
= snprintf(buff
, sz
, " [%s: ", np
? np
: "<unknown opcode>");
4014 for (k
= 0; k
< (int)iop
->cmnd_len
; ++k
)
4015 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "%02x ", ucp
[k
]);
4017 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
4018 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
4020 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n Outgoing "
4021 "data, len=%d%s:\n", (int)iop
->dxfer_len
,
4022 (trunc
? " [only first 256 bytes shown]" : ""));
4023 dStrHex((const char *)iop
->dxferp
,
4024 (trunc
? 256 : (int)iop
->dxfer_len
) , 1);
4027 j
+= snprintf(&buff
[j
], (sz
> j
? (sz
- j
) : 0), "]\n");
4028 pout("buff %s\n",buff
);
4031 char ioBuffer
[1000];
4032 SRB_IO_CONTROL
* pSrbIO
= (SRB_IO_CONTROL
*) ioBuffer
;
4033 SCSI_REQUEST_BLOCK
* pScsiIO
= (SCSI_REQUEST_BLOCK
*) (ioBuffer
+ sizeof(SRB_IO_CONTROL
));
4034 DWORD scsiRequestBlockSize
= sizeof(SCSI_REQUEST_BLOCK
);
4035 char *pRequestSenseIO
= (char *) (ioBuffer
+ sizeof(SRB_IO_CONTROL
) + scsiRequestBlockSize
);
4036 DWORD dataOffset
= (sizeof(SRB_IO_CONTROL
) + scsiRequestBlockSize
+ 7) & 0xfffffff8;
4037 char *pDataIO
= (char *) (ioBuffer
+ dataOffset
);
4038 memset(pScsiIO
, 0, scsiRequestBlockSize
);
4039 pScsiIO
->Length
= (USHORT
) scsiRequestBlockSize
;
4040 pScsiIO
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4041 pScsiIO
->PathId
= 0;
4042 pScsiIO
->TargetId
= m_target
;
4043 pScsiIO
->Lun
= m_lun
;
4044 pScsiIO
->CdbLength
= (int)iop
->cmnd_len
;
4045 switch(iop
->dxfer_dir
){
4047 pScsiIO
->SrbFlags
= SRB_NoDataXfer
;
4049 case DXFER_FROM_DEVICE
:
4050 pScsiIO
->SrbFlags
|= SRB_DataIn
;
4052 case DXFER_TO_DEVICE
:
4053 pScsiIO
->SrbFlags
|= SRB_DataOut
;
4056 pout("aacraid: bad dxfer_dir\n");
4057 return set_err(EINVAL
, "aacraid: bad dxfer_dir\n");
4059 pScsiIO
->DataTransferLength
= (ULONG
)iop
->dxfer_len
;
4060 pScsiIO
->TimeOutValue
= iop
->timeout
;
4061 UCHAR
*pCdb
= (UCHAR
*) pScsiIO
->Cdb
;
4062 memcpy(pCdb
, iop
->cmnd
, 16);
4063 if (iop
->max_sense_len
){
4064 memset(pRequestSenseIO
, 0, iop
->max_sense_len
);
4066 if (pScsiIO
->SrbFlags
& SRB_FLAGS_DATA_OUT
){
4067 memcpy(pDataIO
, iop
->dxferp
, iop
->dxfer_len
);
4069 else if (pScsiIO
->SrbFlags
& SRB_FLAGS_DATA_IN
){
4070 memset(pDataIO
, 0, iop
->dxfer_len
);
4073 DWORD bytesReturned
= 0;
4074 memset(pSrbIO
, 0, sizeof(SRB_IO_CONTROL
));
4075 pSrbIO
->HeaderLength
= sizeof(SRB_IO_CONTROL
);
4076 memcpy(pSrbIO
->Signature
, "AACAPI", 7);
4077 pSrbIO
->ControlCode
= ARCIOCTL_SEND_RAW_SRB
;
4078 pSrbIO
->Length
= (dataOffset
+ iop
->dxfer_len
- sizeof(SRB_IO_CONTROL
) + 7) & 0xfffffff8;
4079 pSrbIO
->Timeout
= 3*60;
4081 if (!DeviceIoControl(
4083 IOCTL_SCSI_MINIPORT
,
4085 sizeof(SRB_IO_CONTROL
) + pSrbIO
->Length
,
4087 sizeof(SRB_IO_CONTROL
) + pSrbIO
->Length
,
4091 return set_err(EIO
, "ARCIOCTL_SEND_RAW_SRB failed, Error=%u", (unsigned)GetLastError());
4094 iop
->scsi_status
= pScsiIO
->ScsiStatus
;
4095 if (SCSI_STATUS_CHECK_CONDITION
& iop
->scsi_status
) {
4096 int slen
= sizeof(pRequestSenseIO
) + 8;
4097 if (slen
> (int)sizeof(pRequestSenseIO
))
4098 slen
= sizeof(pRequestSenseIO
);
4099 if (slen
> (int)iop
->max_sense_len
)
4100 slen
= (int)iop
->max_sense_len
;
4101 memcpy(iop
->sensep
, pRequestSenseIO
, slen
);
4102 iop
->resp_sense_len
= slen
;
4105 pout(" >>> Sense buffer, len=%d:\n", slen
);
4106 dStrHex(iop
->sensep
, slen
, 1);
4108 if ((iop
->sensep
[0] & 0x7f) > 0x71)
4109 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
4110 iop
->scsi_status
, iop
->sensep
[1] & 0xf,
4111 iop
->sensep
[2], iop
->sensep
[3]);
4113 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n",
4114 iop
->scsi_status
, iop
->sensep
[2] & 0xf,
4115 iop
->sensep
[12], iop
->sensep
[13]);
4119 iop
->resp_sense_len
= 0;
4122 if (iop
->dxfer_dir
== DXFER_FROM_DEVICE
){
4123 memcpy(iop
->dxferp
,pDataIO
, iop
->dxfer_len
);
4125 if((iop
->dxfer_dir
== DXFER_FROM_DEVICE
) && (report
> 1)){
4126 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
4127 pout(" Incoming data, len=%d, resid=%d%s:\n", (int)iop
->dxfer_len
, iop
->resid
,
4128 (trunc
? " [only first 256 bytes shown]" : ""));
4129 dStrHex((CHAR
*)pDataIO
, (trunc
? 256 : (int)(iop
->dxfer_len
)) , 1);
4134 //////////////////////////////////////////////////////////////////////////////////////////////////
4139 /////////////////////////////////////////////////////////////////////////////
4141 // Initialize platform interface and register with smi()
4142 void smart_interface::init()
4145 // Remove "." from DLL search path if supported
4146 // to prevent DLL preloading attacks
4147 BOOL (WINAPI
* SetDllDirectoryA_p
)(LPCSTR
) = (BOOL (WINAPI
*)(LPCSTR
))
4148 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA");
4149 if (SetDllDirectoryA_p
)
4150 SetDllDirectoryA_p("");
4153 static os_win32::win_smart_interface the_win_interface
;
4154 smart_interface::set(&the_win_interface
);
4160 // Get exe directory
4161 // (prototype in utiliy.h)
4162 std::string
get_exe_dir()
4164 char path
[MAX_PATH
];
4165 // Get path of this exe
4166 if (!GetModuleFileNameA(GetModuleHandleA(0), path
, sizeof(path
)))
4167 throw std::runtime_error("GetModuleFileName() failed");
4168 // Replace backslash by slash
4170 for (int i
= 0; path
[i
]; i
++)
4171 if (path
[i
] == '\\') {
4172 path
[i
] = '/'; sl
= i
;