|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * os_win32.cpp 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> 00007 * Copyright (C) 2012 Hank Wu <hank@areca.com.tw> 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2, or (at your option) 00012 * any later version. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. 00016 * 00017 */ 00018 00019 #include "config.h" 00020 #define WINVER 0x0502 00021 #define _WIN32_WINNT WINVER 00022 00023 #include "int64.h" 00024 #include "atacmds.h" 00025 #include "scsicmds.h" 00026 #include "utility.h" 00027 #include "smartctl.h" // TODO: Do not use smartctl only variables here 00028 00029 #include "dev_interface.h" 00030 #include "dev_ata_cmd_set.h" 00031 #include "dev_areca.h" 00032 00033 #include "os_win32/wmiquery.h" 00034 00035 #include <errno.h> 00036 00037 #ifdef _DEBUG 00038 #include <assert.h> 00039 #else 00040 #undef assert 00041 #define assert(x) /* */ 00042 #endif 00043 00044 #include <stddef.h> // offsetof() 00045 #include <io.h> // access() 00046 00047 // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h> 00048 #define WIN32_LEAN_AND_MEAN 00049 #include <windows.h> 00050 00051 #if HAVE_NTDDDISK_H 00052 // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32 00053 // (Missing: FILE_DEVICE_SCSI) 00054 #include <devioctl.h> 00055 #include <ntdddisk.h> 00056 #include <ntddscsi.h> 00057 #include <ntddstor.h> 00058 #elif HAVE_DDK_NTDDDISK_H 00059 // older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc 00060 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI) 00061 #include <ddk/ntdddisk.h> 00062 #include <ddk/ntddscsi.h> 00063 #include <ddk/ntddstor.h> 00064 #else 00065 // MSVC10, older MinGW 00066 // (Missing: IOCTL_SCSI_MINIPORT_*) 00067 #include <ntddscsi.h> 00068 #include <winioctl.h> 00069 #endif 00070 00071 #ifndef _WIN32 00072 // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin 00073 #define _WIN32 00074 #endif 00075 00076 // CSMI support 00077 #include "csmisas.h" 00078 00079 // Silence -Wunused-local-typedefs warning from g++ >= 4.8 00080 #if __GNUC__ >= 4 00081 #define ATTR_UNUSED __attribute__((unused)) 00082 #else 00083 #define ATTR_UNUSED /**/ 00084 #endif 00085 00086 // Macro to check constants at compile time using a dummy typedef 00087 #define ASSERT_CONST(c, n) \ 00088 typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED 00089 #define ASSERT_SIZEOF(t, n) \ 00090 typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED 00091 00092 #ifndef _WIN64 00093 #define SELECT_WIN_32_64(x32, x64) (x32) 00094 #else 00095 #define SELECT_WIN_32_64(x32, x64) (x64) 00096 #endif 00097 00098 const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3804 2013-03-27 20:39:41Z chrfranke $"; 00099 00100 ///////////////////////////////////////////////////////////////////////////// 00101 // Windows I/O-controls, some declarations are missing in the include files 00102 00103 extern "C" { 00104 00105 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection) 00106 00107 ASSERT_CONST(SMART_GET_VERSION, 0x074080); 00108 ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084); 00109 ASSERT_CONST(SMART_RCV_DRIVE_DATA, 0x07c088); 00110 ASSERT_SIZEOF(GETVERSIONINPARAMS, 24); 00111 ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1); 00112 ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1); 00113 00114 00115 // IDE PASS THROUGH (2000, XP, undocumented) 00116 00117 #ifndef IOCTL_IDE_PASS_THROUGH 00118 00119 #define IOCTL_IDE_PASS_THROUGH \ 00120 CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) 00121 00122 #endif // IOCTL_IDE_PASS_THROUGH 00123 00124 #pragma pack(1) 00125 00126 typedef struct { 00127 IDEREGS IdeReg; 00128 ULONG DataBufferSize; 00129 UCHAR DataBuffer[1]; 00130 } ATA_PASS_THROUGH; 00131 00132 #pragma pack() 00133 00134 ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028); 00135 ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1); 00136 00137 00138 // ATA PASS THROUGH (Win2003, XP SP2) 00139 00140 #ifndef IOCTL_ATA_PASS_THROUGH 00141 00142 #define IOCTL_ATA_PASS_THROUGH \ 00143 CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) 00144 00145 typedef struct _ATA_PASS_THROUGH_EX { 00146 USHORT Length; 00147 USHORT AtaFlags; 00148 UCHAR PathId; 00149 UCHAR TargetId; 00150 UCHAR Lun; 00151 UCHAR ReservedAsUchar; 00152 ULONG DataTransferLength; 00153 ULONG TimeOutValue; 00154 ULONG ReservedAsUlong; 00155 ULONG_PTR DataBufferOffset; 00156 UCHAR PreviousTaskFile[8]; 00157 UCHAR CurrentTaskFile[8]; 00158 } ATA_PASS_THROUGH_EX; 00159 00160 #define ATA_FLAGS_DRDY_REQUIRED 0x01 00161 #define ATA_FLAGS_DATA_IN 0x02 00162 #define ATA_FLAGS_DATA_OUT 0x04 00163 #define ATA_FLAGS_48BIT_COMMAND 0x08 00164 #define ATA_FLAGS_USE_DMA 0x10 00165 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista 00166 00167 #endif // IOCTL_ATA_PASS_THROUGH 00168 00169 ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c); 00170 ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, SELECT_WIN_32_64(40, 48)); 00171 00172 00173 // IOCTL_SCSI_PASS_THROUGH[_DIRECT] 00174 00175 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004); 00176 ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT, 0x04d014); 00177 ASSERT_SIZEOF(SCSI_PASS_THROUGH, SELECT_WIN_32_64(44, 56)); 00178 ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56)); 00179 00180 00181 // SMART IOCTL via SCSI MINIPORT ioctl 00182 00183 #ifndef FILE_DEVICE_SCSI 00184 #define FILE_DEVICE_SCSI 0x001b 00185 #endif 00186 00187 #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION 00188 00189 #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500) 00190 #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) 00191 #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502) 00192 #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503) 00193 #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504) 00194 #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505) 00195 #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506) 00196 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507) 00197 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508) 00198 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509) 00199 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a) 00200 #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b) 00201 #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c) 00202 00203 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION 00204 00205 ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008); 00206 ASSERT_SIZEOF(SRB_IO_CONTROL, 28); 00207 00208 00209 // IOCTL_STORAGE_QUERY_PROPERTY 00210 00211 #ifndef IOCTL_STORAGE_QUERY_PROPERTY 00212 00213 #define IOCTL_STORAGE_QUERY_PROPERTY \ 00214 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) 00215 00216 typedef struct _STORAGE_DEVICE_DESCRIPTOR { 00217 ULONG Version; 00218 ULONG Size; 00219 UCHAR DeviceType; 00220 UCHAR DeviceTypeModifier; 00221 BOOLEAN RemovableMedia; 00222 BOOLEAN CommandQueueing; 00223 ULONG VendorIdOffset; 00224 ULONG ProductIdOffset; 00225 ULONG ProductRevisionOffset; 00226 ULONG SerialNumberOffset; 00227 STORAGE_BUS_TYPE BusType; 00228 ULONG RawPropertiesLength; 00229 UCHAR RawDeviceProperties[1]; 00230 } STORAGE_DEVICE_DESCRIPTOR; 00231 00232 typedef enum _STORAGE_QUERY_TYPE { 00233 PropertyStandardQuery = 0, 00234 PropertyExistsQuery, 00235 PropertyMaskQuery, 00236 PropertyQueryMaxDefined 00237 } STORAGE_QUERY_TYPE; 00238 00239 typedef enum _STORAGE_PROPERTY_ID { 00240 StorageDeviceProperty = 0, 00241 StorageAdapterProperty, 00242 StorageDeviceIdProperty, 00243 StorageDeviceUniqueIdProperty, 00244 StorageDeviceWriteCacheProperty, 00245 StorageMiniportProperty, 00246 StorageAccessAlignmentProperty 00247 } STORAGE_PROPERTY_ID; 00248 00249 typedef struct _STORAGE_PROPERTY_QUERY { 00250 STORAGE_PROPERTY_ID PropertyId; 00251 STORAGE_QUERY_TYPE QueryType; 00252 UCHAR AdditionalParameters[1]; 00253 } STORAGE_PROPERTY_QUERY; 00254 00255 #endif // IOCTL_STORAGE_QUERY_PROPERTY 00256 00257 ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY, 0x002d1400); 00258 ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR, 36+1+3); 00259 ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY, 8+1+3); 00260 00261 00262 // IOCTL_STORAGE_PREDICT_FAILURE 00263 00264 ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100); 00265 ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512); 00266 00267 00268 // 3ware specific versions of SMART ioctl structs 00269 00270 #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters 00271 00272 #pragma pack(1) 00273 00274 typedef struct _GETVERSIONINPARAMS_EX { 00275 BYTE bVersion; 00276 BYTE bRevision; 00277 BYTE bReserved; 00278 BYTE bIDEDeviceMap; 00279 DWORD fCapabilities; 00280 DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map 00281 WORD wIdentifier; // Vendor specific identifier 00282 WORD wControllerId; // 3ware specific: Controller ID (0,1,...) 00283 ULONG dwReserved[2]; 00284 } GETVERSIONINPARAMS_EX; 00285 00286 typedef struct _SENDCMDINPARAMS_EX { 00287 DWORD cBufferSize; 00288 IDEREGS irDriveRegs; 00289 BYTE bDriveNumber; 00290 BYTE bPortNumber; // 3ware specific: port number 00291 WORD wIdentifier; // Vendor specific identifier 00292 DWORD dwReserved[4]; 00293 BYTE bBuffer[1]; 00294 } SENDCMDINPARAMS_EX; 00295 00296 #pragma pack() 00297 00298 ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS)); 00299 ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS)); 00300 00301 00302 // CSMI structs 00303 00304 ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL)); 00305 ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER, 204); 00306 ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080); 00307 ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168); 00308 00309 } // extern "C" 00310 00311 ///////////////////////////////////////////////////////////////////////////// 00312 00313 namespace os_win32 { // no need to publish anything, name provided for Doxygen 00314 00315 #ifdef _MSC_VER 00316 #pragma warning(disable:4250) 00317 #endif 00318 00319 class win_smart_device 00320 : virtual public /*implements*/ smart_device 00321 { 00322 public: 00323 win_smart_device() 00324 : smart_device(never_called), 00325 m_fh(INVALID_HANDLE_VALUE) 00326 { } 00327 00328 virtual ~win_smart_device() throw(); 00329 00330 virtual bool is_open() const; 00331 00332 virtual bool close(); 00333 00334 protected: 00335 /// Set handle for open() in derived classes. 00336 void set_fh(HANDLE fh) 00337 { m_fh = fh; } 00338 00339 /// Return handle for derived classes. 00340 HANDLE get_fh() const 00341 { return m_fh; } 00342 00343 private: 00344 HANDLE m_fh; ///< File handle 00345 }; 00346 00347 00348 ///////////////////////////////////////////////////////////////////////////// 00349 00350 class win_ata_device 00351 : public /*implements*/ ata_device, 00352 public /*extends*/ win_smart_device 00353 { 00354 public: 00355 win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); 00356 00357 virtual ~win_ata_device() throw(); 00358 00359 virtual bool open(); 00360 00361 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 00362 00363 virtual bool ata_identify_is_cached() const; 00364 00365 private: 00366 bool open(int phydrive, int logdrive, const char * options, int port); 00367 00368 std::string m_options; 00369 bool m_usr_options; // options set by user? 00370 bool m_admin; // open with admin access? 00371 int m_phydrive; // PhysicalDriveN or -1 00372 bool m_id_is_cached; // ata_identify_is_cached() return value. 00373 bool m_is_3ware; // LSI/3ware controller detected? 00374 int m_port; // LSI/3ware port 00375 int m_smartver_state; 00376 }; 00377 00378 00379 ///////////////////////////////////////////////////////////////////////////// 00380 00381 class win_scsi_device 00382 : public /*implements*/ scsi_device, 00383 virtual public /*extends*/ win_smart_device 00384 { 00385 public: 00386 win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); 00387 00388 virtual bool open(); 00389 00390 virtual bool scsi_pass_through(scsi_cmnd_io * iop); 00391 00392 private: 00393 bool open(int pd_num, int ld_num, int tape_num, int sub_addr); 00394 }; 00395 00396 00397 ///////////////////////////////////////////////////////////////////////////// 00398 00399 class csmi_device 00400 : virtual public /*extends*/ smart_device 00401 { 00402 public: 00403 /// Get phy info 00404 bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info); 00405 00406 /// Check physical drive existence 00407 bool check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no); 00408 00409 protected: 00410 csmi_device() 00411 : smart_device(never_called) 00412 { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); } 00413 00414 /// Select physical drive 00415 bool select_phy(unsigned phy_no); 00416 00417 /// Get info for selected physical drive 00418 const CSMI_SAS_PHY_ENTITY & get_phy_ent() const 00419 { return m_phy_ent; } 00420 00421 /// Call platform-specific CSMI ioctl 00422 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, 00423 unsigned csmi_bufsiz) = 0; 00424 00425 private: 00426 CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy 00427 }; 00428 00429 00430 class csmi_ata_device 00431 : virtual public /*extends*/ csmi_device, 00432 virtual public /*implements*/ ata_device 00433 { 00434 public: 00435 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 00436 00437 protected: 00438 csmi_ata_device() 00439 : smart_device(never_called) { } 00440 }; 00441 00442 00443 ////////////////////////////////////////////////////////////////////// 00444 00445 class win_csmi_device 00446 : public /*implements*/ csmi_ata_device 00447 { 00448 public: 00449 win_csmi_device(smart_interface * intf, const char * dev_name, 00450 const char * req_type); 00451 00452 virtual ~win_csmi_device() throw(); 00453 00454 virtual bool open(); 00455 00456 virtual bool close(); 00457 00458 virtual bool is_open() const; 00459 00460 bool open_scsi(); 00461 00462 protected: 00463 virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, 00464 unsigned csmi_bufsiz); 00465 00466 private: 00467 HANDLE m_fh; ///< Controller device handle 00468 unsigned m_phy_no; ///< Physical drive number 00469 }; 00470 00471 00472 ////////////////////////////////////////////////////////////////////// 00473 00474 class win_tw_cli_device 00475 : public /*implements*/ ata_device_with_command_set 00476 { 00477 public: 00478 win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type); 00479 00480 virtual bool is_open() const; 00481 00482 virtual bool open(); 00483 00484 virtual bool close(); 00485 00486 protected: 00487 virtual int ata_command_interface(smart_command_set command, int select, char * data); 00488 00489 private: 00490 bool m_ident_valid, m_smart_valid; 00491 ata_identify_device m_ident_buf; 00492 ata_smart_values m_smart_buf; 00493 }; 00494 00495 00496 ///////////////////////////////////////////////////////////////////////////// 00497 /// Areca RAID support 00498 00499 /////////////////////////////////////////////////////////////////// 00500 // SATA(ATA) device behind Areca RAID Controller 00501 class win_areca_ata_device 00502 : public /*implements*/ areca_ata_device, 00503 public /*extends*/ win_smart_device 00504 { 00505 public: 00506 win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); 00507 virtual bool open(); 00508 virtual smart_device * autodetect_open(); 00509 virtual bool arcmsr_lock(); 00510 virtual bool arcmsr_unlock(); 00511 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); 00512 00513 private: 00514 HANDLE m_mutex; 00515 }; 00516 00517 /////////////////////////////////////////////////////////////////// 00518 // SAS(SCSI) device behind Areca RAID Controller 00519 class win_areca_scsi_device 00520 : public /*implements*/ areca_scsi_device, 00521 public /*extends*/ win_smart_device 00522 { 00523 public: 00524 win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); 00525 virtual bool open(); 00526 virtual smart_device * autodetect_open(); 00527 virtual bool arcmsr_lock(); 00528 virtual bool arcmsr_unlock(); 00529 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); 00530 00531 private: 00532 HANDLE m_mutex; 00533 }; 00534 00535 00536 ////////////////////////////////////////////////////////////////////// 00537 // Platform specific interface 00538 00539 class win_smart_interface 00540 : public /*implements part of*/ smart_interface 00541 { 00542 public: 00543 virtual std::string get_os_version_str(); 00544 00545 virtual std::string get_app_examples(const char * appname); 00546 00547 #ifndef __CYGWIN__ 00548 virtual int64_t get_timer_usec(); 00549 #endif 00550 00551 virtual bool disable_system_auto_standby(bool disable); 00552 00553 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, 00554 const char * pattern = 0); 00555 00556 protected: 00557 virtual ata_device * get_ata_device(const char * name, const char * type); 00558 00559 virtual scsi_device * get_scsi_device(const char * name, const char * type); 00560 00561 virtual smart_device * autodetect_smart_device(const char * name); 00562 00563 virtual smart_device * get_custom_smart_device(const char * name, const char * type); 00564 00565 virtual std::string get_valid_custom_dev_types_str(); 00566 }; 00567 00568 00569 ////////////////////////////////////////////////////////////////////// 00570 00571 #ifndef _WIN64 00572 // Running on 64-bit Windows as 32-bit app ? 00573 static bool is_wow64() 00574 { 00575 BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) = 00576 (BOOL (WINAPI *)(HANDLE, PBOOL)) 00577 GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); 00578 if (!IsWow64Process_p) 00579 return false; 00580 BOOL w64 = FALSE; 00581 if (!IsWow64Process_p(GetCurrentProcess(), &w64)) 00582 return false; 00583 return !!w64; 00584 } 00585 #endif // _WIN64 00586 00587 // Return info string about build host and OS version 00588 std::string win_smart_interface::get_os_version_str() 00589 { 00590 char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13] 00591 = SMARTMONTOOLS_BUILD_HOST; 00592 if (vstr[1] < '6') 00593 vstr[1] = '6'; 00594 char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1; 00595 const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST); 00596 assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr)); 00597 00598 OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi)); 00599 vi.dwOSVersionInfoSize = sizeof(vi); 00600 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { 00601 memset(&vi, 0, sizeof(vi)); 00602 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); 00603 if (!GetVersionExA((OSVERSIONINFOA *)&vi)) 00604 return vstr; 00605 } 00606 00607 if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff) 00608 return vstr; 00609 00610 const char * w; 00611 switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) { 00612 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0: 00613 w = (vi.szCSDVersion[1] == 'B' || 00614 vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break; 00615 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10: 00616 w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break; 00617 case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break; 00618 //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break; 00619 case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break; 00620 case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break; 00621 case VER_PLATFORM_WIN32_NT <<16|0x0500| 1: 00622 w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp" 00623 : "xp-mc"); break; 00624 case VER_PLATFORM_WIN32_NT <<16|0x0500| 2: 00625 w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003" 00626 : "2003r2"); break; 00627 case VER_PLATFORM_WIN32_NT <<16|0x0600| 0: 00628 w = (vi.wProductType == VER_NT_WORKSTATION ? "vista" 00629 : "2008" ); break; 00630 case VER_PLATFORM_WIN32_NT <<16|0x0600| 1: 00631 w = (vi.wProductType == VER_NT_WORKSTATION ? "win7" 00632 : "2008r2"); break; 00633 case VER_PLATFORM_WIN32_NT <<16|0x0600| 2: 00634 w = (vi.wProductType == VER_NT_WORKSTATION ? "win8" 00635 : "2012"); break; 00636 default: w = 0; break; 00637 } 00638 00639 const char * w64 = ""; 00640 #ifndef _WIN64 00641 if (is_wow64()) 00642 w64 = "(64)"; 00643 #endif 00644 00645 if (!w) 00646 snprintf(vptr, vlen, "-%s%u.%u%s", 00647 (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"), 00648 (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64); 00649 else if (vi.wServicePackMinor) 00650 snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor); 00651 else if (vi.wServicePackMajor) 00652 snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor); 00653 else 00654 snprintf(vptr, vlen, "-%s%s", w, w64); 00655 return vstr; 00656 } 00657 00658 #ifndef __CYGWIN__ 00659 // MSVCRT only provides ftime() which uses GetSystemTime() 00660 // This provides only ~15ms resolution by default. 00661 // Use QueryPerformanceCounter instead (~300ns). 00662 // (Cygwin provides CLOCK_MONOTONIC which has the same effect) 00663 int64_t win_smart_interface::get_timer_usec() 00664 { 00665 static int64_t freq = 0; 00666 00667 LARGE_INTEGER t; 00668 if (freq == 0) 00669 freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1); 00670 if (freq <= 0) 00671 return smart_interface::get_timer_usec(); 00672 00673 if (!QueryPerformanceCounter(&t)) 00674 return -1; 00675 if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000)) 00676 return -1; 00677 00678 return (t.QuadPart * 1000000LL) / freq; 00679 } 00680 #endif // __CYGWIN__ 00681 00682 00683 // Return value for device detection functions 00684 enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB }; 00685 00686 static win_dev_type get_phy_drive_type(int drive); 00687 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex); 00688 static win_dev_type get_log_drive_type(int drive); 00689 static bool get_usb_id(int drive, unsigned short & vendor_id, 00690 unsigned short & product_id); 00691 00692 static const char * ata_get_def_options(void); 00693 00694 00695 static int is_permissive() 00696 { 00697 if (!failuretest_permissive) { 00698 pout("To continue, add one or more '-T permissive' options.\n"); 00699 return 0; 00700 } 00701 failuretest_permissive--; 00702 return 1; 00703 } 00704 00705 // return number for drive letter, -1 on error 00706 // "[A-Za-z]:([/\\][.]?)?" => 0-25 00707 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files 00708 static int drive_letter(const char * s) 00709 { 00710 return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z')) 00711 && s[1] == ':' 00712 && (!s[2] || ( strchr("/\\\"", s[2]) 00713 && (!s[3] || (s[3] == '.' && !s[4]))) ) ? 00714 (s[0] & 0x1f) - 1 : -1); 00715 } 00716 00717 // Skip trailing "/dev/", do not allow "/dev/X:" 00718 static const char * skipdev(const char * s) 00719 { 00720 return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s); 00721 } 00722 00723 ata_device * win_smart_interface::get_ata_device(const char * name, const char * type) 00724 { 00725 const char * testname = skipdev(name); 00726 if (!strncmp(testname, "csmi", 4)) 00727 return new win_csmi_device(this, name, type); 00728 if (!strncmp(testname, "tw_cli", 6)) 00729 return new win_tw_cli_device(this, name, type); 00730 return new win_ata_device(this, name, type); 00731 } 00732 00733 scsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type) 00734 { 00735 return new win_scsi_device(this, name, type); 00736 } 00737 00738 static int sdxy_to_phydrive(const char (& xy)[2+1]) 00739 { 00740 int phydrive = xy[0] - 'a'; 00741 if (xy[1]) 00742 phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a'); 00743 return phydrive; 00744 } 00745 00746 static win_dev_type get_dev_type(const char * name, int & phydrive) 00747 { 00748 phydrive = -1; 00749 name = skipdev(name); 00750 if (!strncmp(name, "st", 2)) 00751 return DEV_SCSI; 00752 if (!strncmp(name, "nst", 3)) 00753 return DEV_SCSI; 00754 if (!strncmp(name, "tape", 4)) 00755 return DEV_SCSI; 00756 00757 int logdrive = drive_letter(name); 00758 if (logdrive >= 0) { 00759 win_dev_type type = get_log_drive_type(logdrive); 00760 return (type != DEV_UNKNOWN ? type : DEV_SCSI); 00761 } 00762 00763 char drive[2+1] = ""; 00764 if (sscanf(name, "sd%2[a-z]", drive) == 1) { 00765 phydrive = sdxy_to_phydrive(drive); 00766 return get_phy_drive_type(phydrive); 00767 } 00768 00769 phydrive = -1; 00770 if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0) 00771 return get_phy_drive_type(phydrive); 00772 return DEV_UNKNOWN; 00773 } 00774 00775 smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type) 00776 { 00777 // Areca? 00778 int disknum = -1, n1 = -1, n2 = -1; 00779 int encnum = 1; 00780 char devpath[32]; 00781 00782 if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { 00783 if (!(1 <= disknum && disknum <= 128)) { 00784 set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); 00785 return 0; 00786 } 00787 if (!(1 <= encnum && encnum <= 8)) { 00788 set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); 00789 return 0; 00790 } 00791 00792 name = skipdev(name); 00793 #define ARECA_MAX_CTLR_NUM 16 00794 n1 = -1; 00795 int ctlrindex = 0; 00796 if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) { 00797 /* 00798 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and 00799 2. map arcmsrX into "\\\\.\\scsiX" 00800 */ 00801 for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) { 00802 memset(devpath, 0, sizeof(devpath)); 00803 snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx); 00804 win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum); 00805 if(arcdev->arcmsr_probe()) { 00806 if(ctlrindex-- == 0) { 00807 return arcdev; 00808 } 00809 } 00810 delete arcdev; 00811 } 00812 set_err(ENOENT, "No Areca controller found"); 00813 } 00814 else 00815 set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX"); 00816 } 00817 00818 return 0; 00819 } 00820 00821 std::string win_smart_interface::get_valid_custom_dev_types_str() 00822 { 00823 return "areca,N[/E]"; 00824 } 00825 00826 00827 smart_device * win_smart_interface::autodetect_smart_device(const char * name) 00828 { 00829 const char * testname = skipdev(name); 00830 if (str_starts_with(testname, "hd")) 00831 return new win_ata_device(this, name, ""); 00832 00833 if (str_starts_with(testname, "tw_cli")) 00834 return new win_tw_cli_device(this, name, ""); 00835 00836 if (str_starts_with(testname, "csmi")) 00837 return new win_csmi_device(this, name, ""); 00838 00839 int phydrive = -1; 00840 win_dev_type type = get_dev_type(name, phydrive); 00841 00842 if (type == DEV_ATA) 00843 return new win_ata_device(this, name, ""); 00844 if (type == DEV_SCSI) 00845 return new win_scsi_device(this, name, ""); 00846 00847 if (type == DEV_USB) { 00848 // Get USB bridge ID 00849 unsigned short vendor_id = 0, product_id = 0; 00850 if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) { 00851 set_err(EINVAL, "Unable to read USB device ID"); 00852 return 0; 00853 } 00854 // Get type name for this ID 00855 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id); 00856 if (!usbtype) 00857 return 0; 00858 // Return SAT/USB device for this type 00859 return get_sat_device(usbtype, new win_scsi_device(this, name, "")); 00860 } 00861 00862 return 0; 00863 } 00864 00865 00866 // Scan for devices 00867 00868 bool win_smart_interface::scan_smart_devices(smart_device_list & devlist, 00869 const char * type, const char * pattern /* = 0*/) 00870 { 00871 if (pattern) { 00872 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); 00873 return false; 00874 } 00875 00876 // Check for "[*,]pd" type 00877 bool pd = false; 00878 char type2[16+1] = ""; 00879 if (type) { 00880 int nc = -1; 00881 if (!strcmp(type, "pd")) { 00882 pd = true; 00883 type = 0; 00884 } 00885 else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 && 00886 nc == (int)strlen(type)) { 00887 pd = true; 00888 type = type2; 00889 } 00890 } 00891 00892 // Set valid types 00893 bool ata, scsi, usb, csmi; 00894 if (!type) { 00895 ata = scsi = usb = csmi = true; 00896 } 00897 else { 00898 ata = scsi = usb = csmi = false; 00899 if (!strcmp(type, "ata")) 00900 ata = true; 00901 else if (!strcmp(type, "scsi")) 00902 scsi = true; 00903 else if (!strcmp(type, "usb")) 00904 usb = true; 00905 else if (!strcmp(type, "csmi")) 00906 csmi = true; 00907 else { 00908 set_err(EINVAL, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type); 00909 return false; 00910 } 00911 } 00912 00913 char name[20]; 00914 00915 if (ata || scsi || usb) { 00916 // Scan up to 128 drives and 2 3ware controllers 00917 const int max_raid = 2; 00918 bool raid_seen[max_raid] = {false, false}; 00919 00920 for (int i = 0; i < 128; i++) { 00921 if (pd) 00922 snprintf(name, sizeof(name), "/dev/pd%d", i); 00923 else if (i + 'a' <= 'z') 00924 snprintf(name, sizeof(name), "/dev/sd%c", i + 'a'); 00925 else 00926 snprintf(name, sizeof(name), "/dev/sd%c%c", 00927 i / ('z'-'a'+1) - 1 + 'a', 00928 i % ('z'-'a'+1) + 'a'); 00929 00930 GETVERSIONINPARAMS_EX vers_ex; 00931 00932 switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) { 00933 case DEV_ATA: 00934 // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA 00935 if (!ata) 00936 continue; 00937 00938 // Interpret RAID drive map if present 00939 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) { 00940 // Skip if too many controllers or logical drive from this controller already seen 00941 if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId])) 00942 continue; 00943 raid_seen[vers_ex.wControllerId] = true; 00944 // Add physical drives 00945 int len = strlen(name); 00946 for (int pi = 0; pi < 32; pi++) { 00947 if (vers_ex.dwDeviceMapEx & (1L << pi)) { 00948 snprintf(name+len, sizeof(name)-1-len, ",%u", pi); 00949 devlist.push_back( new win_ata_device(this, name, "ata") ); 00950 } 00951 } 00952 } 00953 else { 00954 devlist.push_back( new win_ata_device(this, name, "ata") ); 00955 } 00956 break; 00957 00958 case DEV_SCSI: 00959 // STORAGE_QUERY_PROPERTY returned SCSI/SAS/... 00960 if (!scsi) 00961 continue; 00962 devlist.push_back( new win_scsi_device(this, name, "scsi") ); 00963 break; 00964 00965 case DEV_USB: 00966 // STORAGE_QUERY_PROPERTY returned USB 00967 if (!usb) 00968 continue; 00969 { 00970 // TODO: Use common function for this and autodetect_smart_device() 00971 // Get USB bridge ID 00972 unsigned short vendor_id = 0, product_id = 0; 00973 if (!get_usb_id(i, vendor_id, product_id)) 00974 continue; 00975 // Get type name for this ID 00976 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id); 00977 if (!usbtype) 00978 continue; 00979 // Return SAT/USB device for this type 00980 ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, "")); 00981 if (!dev) 00982 continue; 00983 devlist.push_back(dev); 00984 } 00985 break; 00986 00987 default: 00988 // Unknown type 00989 break; 00990 } 00991 } 00992 } 00993 00994 if (csmi) { 00995 // Scan CSMI devices 00996 for (int i = 0; i <= 9; i++) { 00997 snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i); 00998 win_csmi_device test_dev(this, name, ""); 00999 if (!test_dev.open_scsi()) 01000 continue; 01001 CSMI_SAS_PHY_INFO phy_info; 01002 if (!test_dev.get_phy_info(phy_info)) 01003 continue; 01004 01005 for (int pi = 0; pi < phy_info.bNumberOfPhys; pi++) { 01006 if (!test_dev.check_phy(phy_info, pi)) 01007 continue; 01008 snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi); 01009 devlist.push_back( new win_csmi_device(this, name, "ata") ); 01010 } 01011 } 01012 } 01013 return true; 01014 } 01015 01016 01017 // get examples for smartctl 01018 std::string win_smart_interface::get_app_examples(const char * appname) 01019 { 01020 if (strcmp(appname, "smartctl")) 01021 return ""; 01022 return "=================================================== SMARTCTL EXAMPLES =====\n\n" 01023 " smartctl -a /dev/sda (Prints all SMART information)\n\n" 01024 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n" 01025 " (Enables SMART on first disk)\n\n" 01026 " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n" 01027 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n" 01028 " (Prints Self-Test & Attribute errors)\n" 01029 " smartctl -a /dev/sda\n" 01030 " (Prints all information for disk on PhysicalDrive 0)\n" 01031 " smartctl -a /dev/pd3\n" 01032 " (Prints all information for disk on PhysicalDrive 3)\n" 01033 " smartctl -a /dev/tape1\n" 01034 " (Prints all information for SCSI tape on Tape 1)\n" 01035 " smartctl -A /dev/hdb,3\n" 01036 " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n" 01037 " smartctl -A /dev/tw_cli/c0/p1\n" 01038 " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n" 01039 " smartctl --all --device=areca,3/1 /dev/arcmsr0\n" 01040 " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n" 01041 " on 1st Areca RAID controller)\n" 01042 "\n" 01043 " ATA SMART access methods and ordering may be specified by modifiers\n" 01044 " following the device name: /dev/hdX:[saicm], where\n" 01045 " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n" 01046 " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n" 01047 " 'm': IOCTL_SCSI_MINIPORT_*.\n" 01048 + strprintf( 01049 " The default on this system is /dev/sdX:%s\n", ata_get_def_options() 01050 ); 01051 } 01052 01053 01054 bool win_smart_interface::disable_system_auto_standby(bool disable) 01055 { 01056 if (disable) { 01057 SYSTEM_POWER_STATUS ps; 01058 if (!GetSystemPowerStatus(&ps)) 01059 return set_err(ENOSYS, "Unknown power status"); 01060 if (ps.ACLineStatus != 1) { 01061 SetThreadExecutionState(ES_CONTINUOUS); 01062 if (ps.ACLineStatus == 0) 01063 set_err(EIO, "AC offline"); 01064 else 01065 set_err(EIO, "Unknown AC line status"); 01066 return false; 01067 } 01068 } 01069 01070 if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0))) 01071 return set_err(ENOSYS); 01072 return true; 01073 } 01074 01075 01076 ///////////////////////////////////////////////////////////////////////////// 01077 // ATA Interface 01078 ///////////////////////////////////////////////////////////////////////////// 01079 01080 #define SMART_CYL_LOW 0x4F 01081 #define SMART_CYL_HI 0xC2 01082 01083 static void print_ide_regs(const IDEREGS * r, int out) 01084 { 01085 pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n", 01086 (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg, 01087 r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg); 01088 } 01089 01090 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro) 01091 { 01092 pout(" Input : "); print_ide_regs(ri, 0); 01093 if (ro) { 01094 pout(" Output: "); print_ide_regs(ro, 1); 01095 } 01096 } 01097 01098 ///////////////////////////////////////////////////////////////////////////// 01099 01100 // call SMART_GET_VERSION, return device map or -1 on error 01101 01102 static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0) 01103 { 01104 GETVERSIONINPARAMS vers; memset(&vers, 0, sizeof(vers)); 01105 const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers; 01106 DWORD num_out; 01107 01108 if (!DeviceIoControl(hdevice, SMART_GET_VERSION, 01109 NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { 01110 if (ata_debugmode) 01111 pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError()); 01112 errno = ENOSYS; 01113 return -1; 01114 } 01115 assert(num_out == sizeof(GETVERSIONINPARAMS)); 01116 01117 if (ata_debugmode > 1) { 01118 pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n" 01119 " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n", 01120 (unsigned)num_out, vers.bVersion, vers.bRevision, 01121 (unsigned)vers.fCapabilities, vers.bIDEDeviceMap); 01122 if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) 01123 pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n", 01124 vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx); 01125 } 01126 01127 if (ata_version_ex) 01128 *ata_version_ex = vers_ex; 01129 01130 // TODO: Check vers.fCapabilities here? 01131 return vers.bIDEDeviceMap; 01132 } 01133 01134 01135 // call SMART_* ioctl 01136 01137 static int smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize, int port) 01138 { 01139 SENDCMDINPARAMS inpar; 01140 SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar; 01141 01142 unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512]; 01143 const SENDCMDOUTPARAMS * outpar; 01144 DWORD code, num_out; 01145 unsigned int size_out; 01146 const char * name; 01147 01148 memset(&inpar, 0, sizeof(inpar)); 01149 inpar.irDriveRegs = *regs; 01150 01151 // Older drivers may require bits 5 and 7 set 01152 // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete 01153 inpar.irDriveRegs.bDriveHeadReg |= 0xa0; 01154 01155 // Drive number 0-3 was required on Win9x/ME only 01156 //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4; 01157 //inpar.bDriveNumber = drive; 01158 01159 if (port >= 0) { 01160 // Set RAID port 01161 inpar_ex.wIdentifier = SMART_VENDOR_3WARE; 01162 inpar_ex.bPortNumber = port; 01163 } 01164 01165 if (datasize == 512) { 01166 code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA"; 01167 inpar.cBufferSize = size_out = 512; 01168 } 01169 else if (datasize == 0) { 01170 code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND"; 01171 if (regs->bFeaturesReg == ATA_SMART_STATUS) 01172 size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data 01173 // Note: cBufferSize must be 0 on Win9x 01174 else 01175 size_out = 0; 01176 } 01177 else { 01178 errno = EINVAL; 01179 return -1; 01180 } 01181 01182 memset(&outbuf, 0, sizeof(outbuf)); 01183 01184 if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1, 01185 outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) { 01186 // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through() 01187 long err = GetLastError(); 01188 if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) { 01189 pout(" %s failed, Error=%ld\n", name, err); 01190 print_ide_regs_io(regs, NULL); 01191 } 01192 errno = ( err == ERROR_INVALID_FUNCTION/*9x*/ 01193 || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ 01194 || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); 01195 return -1; 01196 } 01197 // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs 01198 01199 outpar = (const SENDCMDOUTPARAMS *)outbuf; 01200 01201 if (outpar->DriverStatus.bDriverError) { 01202 if (ata_debugmode) { 01203 pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, 01204 outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError); 01205 print_ide_regs_io(regs, NULL); 01206 } 01207 errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO); 01208 return -1; 01209 } 01210 01211 if (ata_debugmode > 1) { 01212 pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name, 01213 (unsigned)num_out, (unsigned)outpar->cBufferSize); 01214 print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ? 01215 (const IDEREGS *)(outpar->bBuffer) : NULL)); 01216 } 01217 01218 if (datasize) 01219 memcpy(data, outpar->bBuffer, 512); 01220 else if (regs->bFeaturesReg == ATA_SMART_STATUS) { 01221 if (nonempty(outpar->bBuffer, sizeof(IDEREGS))) 01222 memcpy(regs, outpar->bBuffer, sizeof(IDEREGS)); 01223 else { // Workaround for driver not returning regs 01224 if (ata_debugmode) 01225 pout(" WARNING: driver does not return ATA registers in output buffer!\n"); 01226 *regs = inpar.irDriveRegs; 01227 } 01228 } 01229 01230 return 0; 01231 } 01232 01233 01234 ///////////////////////////////////////////////////////////////////////////// 01235 // IDE PASS THROUGH (2000, XP, undocumented) 01236 // 01237 // Based on WinATA.cpp, 2002 c't/Matthias Withopf 01238 // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip 01239 01240 static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize) 01241 { 01242 if (datasize > 512) { 01243 errno = EINVAL; 01244 return -1; 01245 } 01246 unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize; 01247 ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); 01248 DWORD num_out; 01249 const unsigned char magic = 0xcf; 01250 01251 if (!buf) { 01252 errno = ENOMEM; 01253 return -1; 01254 } 01255 01256 buf->IdeReg = *regs; 01257 buf->DataBufferSize = datasize; 01258 if (datasize) 01259 buf->DataBuffer[0] = magic; 01260 01261 if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH, 01262 buf, size, buf, size, &num_out, NULL)) { 01263 long err = GetLastError(); 01264 if (ata_debugmode) { 01265 pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err); 01266 print_ide_regs_io(regs, NULL); 01267 } 01268 VirtualFree(buf, 0, MEM_RELEASE); 01269 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); 01270 return -1; 01271 } 01272 01273 // Check ATA status 01274 if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) { 01275 if (ata_debugmode) { 01276 pout(" IOCTL_IDE_PASS_THROUGH command failed:\n"); 01277 print_ide_regs_io(regs, &buf->IdeReg); 01278 } 01279 VirtualFree(buf, 0, MEM_RELEASE); 01280 errno = EIO; 01281 return -1; 01282 } 01283 01284 // Check and copy data 01285 if (datasize) { 01286 if ( num_out != size 01287 || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) { 01288 if (ata_debugmode) { 01289 pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n", 01290 (unsigned)num_out, (unsigned)buf->DataBufferSize); 01291 print_ide_regs_io(regs, &buf->IdeReg); 01292 } 01293 VirtualFree(buf, 0, MEM_RELEASE); 01294 errno = EIO; 01295 return -1; 01296 } 01297 memcpy(data, buf->DataBuffer, datasize); 01298 } 01299 01300 if (ata_debugmode > 1) { 01301 pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n", 01302 (unsigned)num_out, (unsigned)buf->DataBufferSize); 01303 print_ide_regs_io(regs, &buf->IdeReg); 01304 } 01305 *regs = buf->IdeReg; 01306 01307 // Caution: VirtualFree() fails if parameter "dwSize" is nonzero 01308 VirtualFree(buf, 0, MEM_RELEASE); 01309 return 0; 01310 } 01311 01312 01313 ///////////////////////////////////////////////////////////////////////////// 01314 // ATA PASS THROUGH (Win2003, XP SP2) 01315 01316 // Warning: 01317 // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data 01318 // transfer per command. Therefore, multi-sector transfers are only supported 01319 // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS 01320 // or READ/WRITE LOG EXT work only with single sector transfers. 01321 // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE. 01322 // See: 01323 // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da 01324 01325 static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize) 01326 { 01327 const int max_sectors = 32; // TODO: Allocate dynamic buffer 01328 01329 typedef struct { 01330 ATA_PASS_THROUGH_EX apt; 01331 ULONG Filler; 01332 UCHAR ucDataBuf[max_sectors * 512]; 01333 } ATA_PASS_THROUGH_EX_WITH_BUFFERS; 01334 01335 const unsigned char magic = 0xcf; 01336 01337 ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab)); 01338 ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX); 01339 //ab.apt.PathId = 0; 01340 //ab.apt.TargetId = 0; 01341 //ab.apt.Lun = 0; 01342 ab.apt.TimeOutValue = 10; 01343 unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf); 01344 ab.apt.DataBufferOffset = size; 01345 01346 if (datasize > 0) { 01347 if (datasize > (int)sizeof(ab.ucDataBuf)) { 01348 errno = EINVAL; 01349 return -1; 01350 } 01351 ab.apt.AtaFlags = ATA_FLAGS_DATA_IN; 01352 ab.apt.DataTransferLength = datasize; 01353 size += datasize; 01354 ab.ucDataBuf[0] = magic; 01355 } 01356 else if (datasize < 0) { 01357 if (-datasize > (int)sizeof(ab.ucDataBuf)) { 01358 errno = EINVAL; 01359 return -1; 01360 } 01361 ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT; 01362 ab.apt.DataTransferLength = -datasize; 01363 size += -datasize; 01364 memcpy(ab.ucDataBuf, data, -datasize); 01365 } 01366 else { 01367 assert(ab.apt.AtaFlags == 0); 01368 assert(ab.apt.DataTransferLength == 0); 01369 } 01370 01371 assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS)); 01372 IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile; 01373 IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile; 01374 *ctfregs = *regs; 01375 01376 if (prev_regs) { 01377 *ptfregs = *prev_regs; 01378 ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND; 01379 } 01380 01381 DWORD num_out; 01382 if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH, 01383 &ab, size, &ab, size, &num_out, NULL)) { 01384 long err = GetLastError(); 01385 if (ata_debugmode) { 01386 pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err); 01387 print_ide_regs_io(regs, NULL); 01388 } 01389 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); 01390 return -1; 01391 } 01392 01393 // Check ATA status 01394 if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) { 01395 if (ata_debugmode) { 01396 pout(" IOCTL_ATA_PASS_THROUGH command failed:\n"); 01397 print_ide_regs_io(regs, ctfregs); 01398 } 01399 errno = EIO; 01400 return -1; 01401 } 01402 01403 // Check and copy data 01404 if (datasize > 0) { 01405 if ( num_out != size 01406 || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) { 01407 if (ata_debugmode) { 01408 pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out); 01409 print_ide_regs_io(regs, ctfregs); 01410 } 01411 errno = EIO; 01412 return -1; 01413 } 01414 memcpy(data, ab.ucDataBuf, datasize); 01415 } 01416 01417 if (ata_debugmode > 1) { 01418 pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out); 01419 print_ide_regs_io(regs, ctfregs); 01420 } 01421 *regs = *ctfregs; 01422 if (prev_regs) 01423 *prev_regs = *ptfregs; 01424 01425 return 0; 01426 } 01427 01428 01429 ///////////////////////////////////////////////////////////////////////////// 01430 // SMART IOCTL via SCSI MINIPORT ioctl 01431 01432 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI 01433 // miniport driver (via SCSI port driver scsiport.sys). 01434 // It can be used to skip the missing or broken handling of some SMART 01435 // command codes (e.g. READ_LOG) in the disk class driver (disk.sys) 01436 01437 static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize) 01438 { 01439 // Select code 01440 DWORD code = 0; const char * name = 0; 01441 if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) { 01442 code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY"; 01443 } 01444 else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) { 01445 case ATA_SMART_READ_VALUES: 01446 code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break; 01447 case ATA_SMART_READ_THRESHOLDS: 01448 code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break; 01449 case ATA_SMART_ENABLE: 01450 code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break; 01451 case ATA_SMART_DISABLE: 01452 code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break; 01453 case ATA_SMART_STATUS: 01454 code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break; 01455 case ATA_SMART_AUTOSAVE: 01456 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break; 01457 //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools 01458 // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break; 01459 case ATA_SMART_IMMEDIATE_OFFLINE: 01460 code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break; 01461 case ATA_SMART_AUTO_OFFLINE: 01462 code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break; 01463 case ATA_SMART_READ_LOG_SECTOR: 01464 code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break; 01465 case ATA_SMART_WRITE_LOG_SECTOR: 01466 code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break; 01467 } 01468 if (!code) { 01469 errno = ENOSYS; 01470 return -1; 01471 } 01472 01473 // Set SRB 01474 struct { 01475 SRB_IO_CONTROL srbc; 01476 union { 01477 SENDCMDINPARAMS in; 01478 SENDCMDOUTPARAMS out; 01479 } params; 01480 char space[512-1]; 01481 } sb; 01482 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512); 01483 memset(&sb, 0, sizeof(sb)); 01484 01485 unsigned size; 01486 if (datasize > 0) { 01487 if (datasize > (int)sizeof(sb.space)+1) { 01488 errno = EINVAL; 01489 return -1; 01490 } 01491 size = datasize; 01492 } 01493 else if (datasize < 0) { 01494 if (-datasize > (int)sizeof(sb.space)+1) { 01495 errno = EINVAL; 01496 return -1; 01497 } 01498 size = -datasize; 01499 memcpy(sb.params.in.bBuffer, data, size); 01500 } 01501 else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) 01502 size = sizeof(IDEREGS); 01503 else 01504 size = 0; 01505 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); 01506 memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys 01507 sb.srbc.Timeout = 60; // seconds 01508 sb.srbc.ControlCode = code; 01509 //sb.srbc.ReturnCode = 0; 01510 sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size; 01511 sb.params.in.irDriveRegs = *regs; 01512 sb.params.in.cBufferSize = size; 01513 01514 // Call miniport ioctl 01515 size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1; 01516 DWORD num_out; 01517 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, 01518 &sb, size, &sb, size, &num_out, NULL)) { 01519 long err = GetLastError(); 01520 if (ata_debugmode) { 01521 pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err); 01522 print_ide_regs_io(regs, NULL); 01523 } 01524 errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); 01525 return -1; 01526 } 01527 01528 // Check result 01529 if (sb.srbc.ReturnCode) { 01530 if (ata_debugmode) { 01531 pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (unsigned)sb.srbc.ReturnCode); 01532 print_ide_regs_io(regs, NULL); 01533 } 01534 errno = EIO; 01535 return -1; 01536 } 01537 01538 if (sb.params.out.DriverStatus.bDriverError) { 01539 if (ata_debugmode) { 01540 pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, 01541 sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError); 01542 print_ide_regs_io(regs, NULL); 01543 } 01544 errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO); 01545 return -1; 01546 } 01547 01548 if (ata_debugmode > 1) { 01549 pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name, 01550 (unsigned)num_out, (unsigned)sb.params.out.cBufferSize); 01551 print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ? 01552 (const IDEREGS *)(sb.params.out.bBuffer) : 0)); 01553 } 01554 01555 if (datasize > 0) 01556 memcpy(data, sb.params.out.bBuffer, datasize); 01557 else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) 01558 memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS)); 01559 01560 return 0; 01561 } 01562 01563 01564 ///////////////////////////////////////////////////////////////////////////// 01565 01566 // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl 01567 01568 static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port) 01569 { 01570 struct { 01571 SRB_IO_CONTROL srbc; 01572 IDEREGS regs; 01573 UCHAR buffer[512]; 01574 } sb; 01575 ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512); 01576 01577 if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) { 01578 errno = EINVAL; 01579 return -1; 01580 } 01581 memset(&sb, 0, sizeof(sb)); 01582 strncpy((char *)sb.srbc.Signature, "<3ware>", sizeof(sb.srbc.Signature)); 01583 sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); 01584 sb.srbc.Timeout = 60; // seconds 01585 sb.srbc.ControlCode = 0xA0000000; 01586 sb.srbc.ReturnCode = 0; 01587 sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1); 01588 sb.regs = *regs; 01589 sb.regs.bReserved = port; 01590 01591 DWORD num_out; 01592 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, 01593 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) { 01594 long err = GetLastError(); 01595 if (ata_debugmode) { 01596 pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err); 01597 print_ide_regs_io(regs, NULL); 01598 } 01599 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); 01600 return -1; 01601 } 01602 01603 if (sb.srbc.ReturnCode) { 01604 if (ata_debugmode) { 01605 pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb.srbc.ReturnCode); 01606 print_ide_regs_io(regs, NULL); 01607 } 01608 errno = EIO; 01609 return -1; 01610 } 01611 01612 // Copy data 01613 if (datasize > 0) 01614 memcpy(data, sb.buffer, datasize); 01615 01616 if (ata_debugmode > 1) { 01617 pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out); 01618 print_ide_regs_io(regs, &sb.regs); 01619 } 01620 *regs = sb.regs; 01621 01622 return 0; 01623 } 01624 01625 01626 ///////////////////////////////////////////////////////////////////////////// 01627 01628 // 3ware specific call to update the devicemap returned by SMART_GET_VERSION. 01629 // 3DM/CLI "Rescan Controller" function does not to always update it. 01630 01631 static int update_3ware_devicemap_ioctl(HANDLE hdevice) 01632 { 01633 SRB_IO_CONTROL srbc; 01634 memset(&srbc, 0, sizeof(srbc)); 01635 strncpy((char *)srbc.Signature, "<3ware>", sizeof(srbc.Signature)); 01636 srbc.HeaderLength = sizeof(SRB_IO_CONTROL); 01637 srbc.Timeout = 60; // seconds 01638 srbc.ControlCode = 0xCC010014; 01639 srbc.ReturnCode = 0; 01640 srbc.Length = 0; 01641 01642 DWORD num_out; 01643 if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, 01644 &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) { 01645 long err = GetLastError(); 01646 if (ata_debugmode) 01647 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err); 01648 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); 01649 return -1; 01650 } 01651 if (srbc.ReturnCode) { 01652 if (ata_debugmode) 01653 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc.ReturnCode); 01654 errno = EIO; 01655 return -1; 01656 } 01657 if (ata_debugmode > 1) 01658 pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n"); 01659 return 0; 01660 } 01661 01662 01663 01664 ///////////////////////////////////////////////////////////////////////////// 01665 01666 // Routines for pseudo device /dev/tw_cli/* 01667 // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window 01668 01669 01670 // Get clipboard data 01671 01672 static int get_clipboard(char * data, int datasize) 01673 { 01674 if (!OpenClipboard(NULL)) 01675 return -1; 01676 HANDLE h = GetClipboardData(CF_TEXT); 01677 if (!h) { 01678 CloseClipboard(); 01679 return 0; 01680 } 01681 const void * p = GlobalLock(h); 01682 int n = GlobalSize(h); 01683 if (n > datasize) 01684 n = datasize; 01685 memcpy(data, p, n); 01686 GlobalFree(h); 01687 CloseClipboard(); 01688 return n; 01689 } 01690 01691 01692 // Run a command, write stdout to dataout 01693 // TODO: Combine with daemon_win32.cpp:daemon_spawn() 01694 01695 static int run_cmd(const char * cmd, char * dataout, int outsize) 01696 { 01697 // Create stdout pipe 01698 SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE}; 01699 HANDLE pipe_out_w, h; 01700 if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) 01701 return -1; 01702 HANDLE self = GetCurrentProcess(); 01703 HANDLE pipe_out_r; 01704 if (!DuplicateHandle(self, h, self, &pipe_out_r, 01705 GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { 01706 CloseHandle(pipe_out_w); 01707 return -1; 01708 } 01709 HANDLE pipe_err_w; 01710 if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, 01711 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { 01712 CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); 01713 return -1; 01714 } 01715 01716 // Create process 01717 STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); 01718 si.hStdInput = INVALID_HANDLE_VALUE; 01719 si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w; 01720 si.dwFlags = STARTF_USESTDHANDLES; 01721 PROCESS_INFORMATION pi; 01722 if (!CreateProcess( 01723 NULL, const_cast<char *>(cmd), 01724 NULL, NULL, TRUE/*inherit*/, 01725 CREATE_NO_WINDOW/*do not create a new console window*/, 01726 NULL, NULL, &si, &pi)) { 01727 CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); 01728 return -1; 01729 } 01730 CloseHandle(pi.hThread); 01731 CloseHandle(pipe_err_w); CloseHandle(pipe_out_w); 01732 01733 // Copy stdout to output buffer 01734 int i = 0; 01735 while (i < outsize) { 01736 DWORD num_read; 01737 if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0) 01738 break; 01739 i += num_read; 01740 } 01741 CloseHandle(pipe_out_r); 01742 // Wait for process 01743 WaitForSingleObject(pi.hProcess, INFINITE); 01744 CloseHandle(pi.hProcess); 01745 return i; 01746 } 01747 01748 01749 static const char * findstr(const char * str, const char * sub) 01750 { 01751 const char * s = strstr(str, sub); 01752 return (s ? s+strlen(sub) : ""); 01753 } 01754 01755 01756 static void copy_swapped(unsigned char * dest, const char * src, int destsize) 01757 { 01758 int srclen = strcspn(src, "\r\n"); 01759 int i; 01760 for (i = 0; i < destsize-1 && i < srclen-1; i+=2) { 01761 dest[i] = src[i+1]; dest[i+1] = src[i]; 01762 } 01763 if (i < destsize-1 && i < srclen) 01764 dest[i+1] = src[i]; 01765 } 01766 01767 01768 // TODO: This is OS independent 01769 01770 win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type) 01771 : smart_device(intf, dev_name, "tw_cli", req_type), 01772 m_ident_valid(false), m_smart_valid(false) 01773 { 01774 memset(&m_ident_buf, 0, sizeof(m_ident_buf)); 01775 memset(&m_smart_buf, 0, sizeof(m_smart_buf)); 01776 } 01777 01778 01779 bool win_tw_cli_device::is_open() const 01780 { 01781 return (m_ident_valid || m_smart_valid); 01782 } 01783 01784 01785 bool win_tw_cli_device::open() 01786 { 01787 m_ident_valid = m_smart_valid = false; 01788 const char * name = skipdev(get_dev_name()); 01789 // Read tw_cli or 3DM browser output into buffer 01790 char buffer[4096]; 01791 int size = -1, n1 = -1, n2 = -1; 01792 if (!strcmp(name, "tw_cli/clip")) { // read clipboard 01793 size = get_clipboard(buffer, sizeof(buffer)); 01794 } 01795 else if (!strcmp(name, "tw_cli/stdin")) { // read stdin 01796 size = fread(buffer, 1, sizeof(buffer), stdin); 01797 } 01798 else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) { 01799 // tw_cli/cx/py => read output from "tw_cli /cx/py show all" 01800 char cmd[100]; 01801 snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1); 01802 if (ata_debugmode > 1) 01803 pout("%s: Run: \"%s\"\n", name, cmd); 01804 size = run_cmd(cmd, buffer, sizeof(buffer)); 01805 } 01806 else { 01807 return set_err(EINVAL); 01808 } 01809 01810 if (ata_debugmode > 1) 01811 pout("%s: Read %d bytes\n", name, size); 01812 if (size <= 0) 01813 return set_err(ENOENT); 01814 if (size >= (int)sizeof(buffer)) 01815 return set_err(EIO); 01816 01817 buffer[size] = 0; 01818 if (ata_debugmode > 1) 01819 pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":"")); 01820 01821 // Fake identify sector 01822 ASSERT_SIZEOF(ata_identify_device, 512); 01823 ata_identify_device * id = &m_ident_buf; 01824 memset(id, 0, sizeof(*id)); 01825 copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model)); 01826 copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev)); 01827 copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no)); 01828 unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)" 01829 sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks); 01830 if (nblocks) { 01831 id->words047_079[49-47] = 0x0200; // size valid 01832 id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16 01833 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32 01834 } 01835 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid 01836 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid 01837 01838 // Parse smart data hex dump 01839 const char * s = findstr(buffer, "Drive Smart Data:"); 01840 if (!*s) 01841 s = findstr(buffer, "Drive SMART Data:"); // tw_cli from 9.5.x 01842 if (!*s) { 01843 s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window 01844 if (*s) { 01845 const char * s1 = findstr(s, "<td class"); // html version 01846 if (*s1) 01847 s = s1; 01848 s += strcspn(s, "\r\n"); 01849 } 01850 else 01851 s = buffer; // try raw hex dump without header 01852 } 01853 unsigned char * sd = (unsigned char *)&m_smart_buf; 01854 int i = 0; 01855 for (;;) { 01856 unsigned x = ~0; int n = -1; 01857 if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff))) 01858 break; 01859 sd[i] = (unsigned char)x; 01860 if (!(++i < 512 && n > 0)) 01861 break; 01862 s += n; 01863 if (*s == '<') // "<br>" 01864 s += strcspn(s, "\r\n"); 01865 } 01866 if (i < 512) { 01867 if (!id->model[1]) { 01868 // No useful data found 01869 char * err = strstr(buffer, "Error:"); 01870 if (!err) 01871 err = strstr(buffer, "error :"); 01872 if (err && (err = strchr(err, ':'))) { 01873 // Show tw_cli error message 01874 err++; 01875 err[strcspn(err, "\r\n")] = 0; 01876 return set_err(EIO, "%s", err); 01877 } 01878 return set_err(EIO); 01879 } 01880 sd = 0; 01881 } 01882 01883 m_ident_valid = true; 01884 m_smart_valid = !!sd; 01885 return true; 01886 } 01887 01888 01889 bool win_tw_cli_device::close() 01890 { 01891 m_ident_valid = m_smart_valid = false; 01892 return true; 01893 } 01894 01895 01896 int win_tw_cli_device::ata_command_interface(smart_command_set command, int /*select*/, char * data) 01897 { 01898 switch (command) { 01899 case IDENTIFY: 01900 if (!m_ident_valid) 01901 break; 01902 memcpy(data, &m_ident_buf, 512); 01903 return 0; 01904 case READ_VALUES: 01905 if (!m_smart_valid) 01906 break; 01907 memcpy(data, &m_smart_buf, 512); 01908 return 0; 01909 case ENABLE: 01910 case STATUS: 01911 case STATUS_CHECK: // Fake "good" SMART status 01912 return 0; 01913 default: 01914 break; 01915 } 01916 // Arrive here for all unsupported commands 01917 set_err(ENOSYS); 01918 return -1; 01919 } 01920 01921 01922 ///////////////////////////////////////////////////////////////////////////// 01923 // IOCTL_STORAGE_QUERY_PROPERTY 01924 01925 union STORAGE_DEVICE_DESCRIPTOR_DATA { 01926 STORAGE_DEVICE_DESCRIPTOR desc; 01927 char raw[256]; 01928 }; 01929 01930 // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device. 01931 // (This works without admin rights) 01932 01933 static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA * data) 01934 { 01935 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} }; 01936 memset(data, 0, sizeof(*data)); 01937 01938 DWORD num_out; 01939 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, 01940 &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) { 01941 if (ata_debugmode > 1 || scsi_debugmode > 1) 01942 pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError()); 01943 errno = ENOSYS; 01944 return -1; 01945 } 01946 01947 if (ata_debugmode > 1 || scsi_debugmode > 1) { 01948 pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n" 01949 " Vendor: \"%s\"\n" 01950 " Product: \"%s\"\n" 01951 " Revision: \"%s\"\n" 01952 " Removable: %s\n" 01953 " BusType: 0x%02x\n", 01954 (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : "(null)"), 01955 (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : "(null)"), 01956 (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : "(null)"), 01957 (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType 01958 ); 01959 } 01960 return 0; 01961 } 01962 01963 01964 ///////////////////////////////////////////////////////////////////////////// 01965 // IOCTL_STORAGE_PREDICT_FAILURE 01966 01967 // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value 01968 // or -1 on error, opionally return VendorSpecific data. 01969 // (This works without admin rights) 01970 01971 static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0) 01972 { 01973 STORAGE_PREDICT_FAILURE pred; 01974 memset(&pred, 0, sizeof(pred)); 01975 01976 DWORD num_out; 01977 if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE, 01978 0, 0, &pred, sizeof(pred), &num_out, NULL)) { 01979 if (ata_debugmode > 1) 01980 pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError()); 01981 errno = ENOSYS; 01982 return -1; 01983 } 01984 01985 if (ata_debugmode > 1) { 01986 pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n" 01987 " PredictFailure: 0x%08x\n" 01988 " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n", 01989 (unsigned)pred.PredictFailure, 01990 pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2], 01991 pred.VendorSpecific[sizeof(pred.VendorSpecific)-1] 01992 ); 01993 } 01994 if (data) 01995 memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific)); 01996 return (!pred.PredictFailure ? 0 : 1); 01997 } 01998 01999 02000 ///////////////////////////////////////////////////////////////////////////// 02001 02002 // Return true if Intel ICHxR RAID volume 02003 static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA * data) 02004 { 02005 if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset)) 02006 return false; 02007 const char * vendor = data->raw + data->desc.VendorIdOffset; 02008 if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5))) 02009 return false; 02010 if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5)) 02011 return false; 02012 return true; 02013 } 02014 02015 // get DEV_* for open handle 02016 static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex) 02017 { 02018 // Get BusType from device descriptor 02019 STORAGE_DEVICE_DESCRIPTOR_DATA data; 02020 if (storage_query_property_ioctl(hdevice, &data)) 02021 return DEV_UNKNOWN; 02022 02023 // Newer BusType* values are missing in older includes 02024 switch ((int)data.desc.BusType) { 02025 case BusTypeAta: 02026 case 0x0b: // BusTypeSata 02027 if (ata_version_ex) 02028 memset(ata_version_ex, 0, sizeof(*ata_version_ex)); 02029 return DEV_ATA; 02030 02031 case BusTypeScsi: 02032 case BusTypeRAID: 02033 // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_* 02034 if (is_intel_raid_volume(&data)) 02035 return DEV_SCSI; 02036 // LSI/3ware RAID volume: supports SMART_* 02037 if (admin && smart_get_version(hdevice, ata_version_ex) >= 0) 02038 return DEV_ATA; 02039 return DEV_SCSI; 02040 02041 case 0x09: // BusTypeiScsi 02042 case 0x0a: // BusTypeSas 02043 return DEV_SCSI; 02044 02045 case BusTypeUsb: 02046 return DEV_USB; 02047 02048 default: 02049 return DEV_UNKNOWN; 02050 } 02051 /*NOTREACHED*/ 02052 } 02053 02054 // get DEV_* for device path 02055 static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0) 02056 { 02057 bool admin = true; 02058 HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 02059 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 02060 if (h == INVALID_HANDLE_VALUE) { 02061 admin = false; 02062 h = CreateFileA(path, 0, 02063 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 02064 if (h == INVALID_HANDLE_VALUE) 02065 return DEV_UNKNOWN; 02066 } 02067 if (ata_debugmode > 1 || scsi_debugmode > 1) 02068 pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :"")); 02069 win_dev_type type = get_controller_type(h, admin, ata_version_ex); 02070 CloseHandle(h); 02071 return type; 02072 } 02073 02074 // get DEV_* for physical drive number 02075 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex) 02076 { 02077 char path[30]; 02078 snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive); 02079 return get_controller_type(path, ata_version_ex); 02080 } 02081 02082 static win_dev_type get_phy_drive_type(int drive) 02083 { 02084 return get_phy_drive_type(drive, 0); 02085 } 02086 02087 // get DEV_* for logical drive number 02088 static win_dev_type get_log_drive_type(int drive) 02089 { 02090 char path[30]; 02091 snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive); 02092 return get_controller_type(path); 02093 } 02094 02095 // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR 02096 static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id) 02097 { 02098 STORAGE_DEVICE_DESCRIPTOR_DATA data; 02099 if (storage_query_property_ioctl(hdevice, &data)) 02100 return -1; 02101 02102 memset(id, 0, sizeof(*id)); 02103 02104 // Some drivers split ATA model string into VendorId and ProductId, 02105 // others return it as ProductId only. 02106 char model[sizeof(id->model) + 1] = ""; 02107 02108 unsigned i = 0; 02109 if (data.desc.VendorIdOffset) { 02110 for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++) 02111 model[i] = data.raw[data.desc.VendorIdOffset+i]; 02112 } 02113 02114 if (data.desc.ProductIdOffset) { 02115 while (i > 1 && model[i-2] == ' ') // Keep last blank from VendorId 02116 i--; 02117 // Ignore VendorId "ATA" 02118 if (i <= 4 && !strncmp(model, "ATA", 3) && (i == 3 || model[3] == ' ')) 02119 i = 0; 02120 for (unsigned j = 0; i < sizeof(model)-1 && data.raw[data.desc.ProductIdOffset+j]; i++, j++) 02121 model[i] = data.raw[data.desc.ProductIdOffset+j]; 02122 } 02123 02124 while (i > 0 && model[i-1] == ' ') 02125 i--; 02126 model[i] = 0; 02127 copy_swapped(id->model, model, sizeof(id->model)); 02128 02129 if (data.desc.ProductRevisionOffset) 02130 copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev)); 02131 02132 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid 02133 id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid 02134 return 0; 02135 } 02136 02137 // Get Serial Number in IDENTIFY from WMI 02138 static bool get_serial_from_wmi(int drive, ata_identify_device * id) 02139 { 02140 bool debug = (ata_debugmode > 1); 02141 02142 wbem_services ws; 02143 if (!ws.connect()) { 02144 if (debug) 02145 pout("WMI connect failed\n"); 02146 return false; 02147 } 02148 02149 wbem_object wo; 02150 if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE " 02151 "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive)) 02152 return false; 02153 02154 std::string serial = wo.get_str("SerialNumber"); 02155 if (debug) 02156 pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str("Model").c_str(), serial.c_str()); 02157 02158 copy_swapped(id->serial_no, serial.c_str(), sizeof(id->serial_no)); 02159 return true; 02160 } 02161 02162 02163 ///////////////////////////////////////////////////////////////////////////// 02164 // USB ID detection using WMI 02165 02166 // Get USB ID for a physical drive number 02167 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id) 02168 { 02169 bool debug = (scsi_debugmode > 1); 02170 02171 wbem_services ws; 02172 if (!ws.connect()) { 02173 if (debug) 02174 pout("WMI connect failed\n"); 02175 return false; 02176 } 02177 02178 // Get device name 02179 wbem_object wo; 02180 if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive)) 02181 return false; 02182 02183 std::string name = wo.get_str("Model"); 02184 if (debug) 02185 pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str()); 02186 02187 // Get USB_CONTROLLER -> DEVICE associations 02188 wbem_enumerator we; 02189 if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice")) 02190 return false; 02191 02192 unsigned short usb_venid = 0, prev_usb_venid = 0; 02193 unsigned short usb_proid = 0, prev_usb_proid = 0; 02194 std::string prev_usb_ant; 02195 std::string prev_ant, ant, dep; 02196 02197 const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED); 02198 02199 while (we.next(wo)) { 02200 prev_ant = ant; 02201 // Find next 'USB_CONTROLLER, DEVICE' pair 02202 ant = wo.get_str("Antecedent"); 02203 dep = wo.get_str("Dependent"); 02204 02205 if (debug && ant != prev_ant) 02206 pout(" %s:\n", ant.c_str()); 02207 02208 // Extract DeviceID 02209 regmatch_t match[2]; 02210 if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) { 02211 if (debug) 02212 pout(" | (\"%s\")\n", dep.c_str()); 02213 continue; 02214 } 02215 02216 std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so); 02217 02218 if (str_starts_with(devid, "USB\\\\VID_")) { 02219 // USB bridge entry, save CONTROLLER, ID 02220 int nc = -1; 02221 if (!(sscanf(devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n", 02222 &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) { 02223 prev_usb_venid = prev_usb_proid = 0; 02224 } 02225 prev_usb_ant = ant; 02226 if (debug) 02227 pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid); 02228 continue; 02229 } 02230 else if (str_starts_with(devid, "USBSTOR\\\\")) { 02231 // USBSTOR device found 02232 if (debug) 02233 pout(" +--> \"%s\"\n", devid.c_str()); 02234 02235 // Retrieve name 02236 wbem_object wo2; 02237 if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str())) 02238 continue; 02239 std::string name2 = wo2.get_str("Name"); 02240 02241 // Continue if not name of physical disk drive 02242 if (name2 != name) { 02243 if (debug) 02244 pout(" +---> (\"%s\")\n", name2.c_str()); 02245 continue; 02246 } 02247 02248 // Fail if previous USB bridge is associated to other controller or ID is unknown 02249 if (!(ant == prev_usb_ant && prev_usb_venid)) { 02250 if (debug) 02251 pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str()); 02252 return false; 02253 } 02254 02255 // Handle multiple devices with same name 02256 if (usb_venid) { 02257 // Fail if multiple devices with same name have different USB bridge types 02258 if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) { 02259 if (debug) 02260 pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str()); 02261 return false; 02262 } 02263 } 02264 02265 // Found 02266 usb_venid = prev_usb_venid; 02267 usb_proid = prev_usb_proid; 02268 if (debug) 02269 pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid); 02270 02271 // Continue to check for duplicate names ... 02272 } 02273 else { 02274 if (debug) 02275 pout(" | \"%s\"\n", devid.c_str()); 02276 } 02277 } 02278 02279 if (!usb_venid) 02280 return false; 02281 02282 vendor_id = usb_venid; 02283 product_id = usb_proid; 02284 02285 return true; 02286 } 02287 02288 02289 ///////////////////////////////////////////////////////////////////////////// 02290 02291 // Call GetDevicePowerState() 02292 // returns: 1=active, 0=standby, -1=error 02293 // (This would also work for SCSI drives) 02294 02295 static int get_device_power_state(HANDLE hdevice) 02296 { 02297 BOOL state = TRUE; 02298 if (!GetDevicePowerState(hdevice, &state)) { 02299 long err = GetLastError(); 02300 if (ata_debugmode) 02301 pout(" GetDevicePowerState() failed, Error=%ld\n", err); 02302 errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); 02303 // TODO: This may not work as expected on transient errors, 02304 // because smartd interprets -1 as SLEEP mode regardless of errno. 02305 return -1; 02306 } 02307 02308 if (ata_debugmode > 1) 02309 pout(" GetDevicePowerState() succeeded, state=%d\n", state); 02310 return state; 02311 } 02312 02313 02314 ///////////////////////////////////////////////////////////////////////////// 02315 02316 // Get default ATA device options 02317 02318 static const char * ata_get_def_options() 02319 { 02320 return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH, 02321 // STORAGE_*, SCSI_MINIPORT_* 02322 } 02323 02324 02325 // Common routines for devices with HANDLEs 02326 02327 win_smart_device::~win_smart_device() throw() 02328 { 02329 if (m_fh != INVALID_HANDLE_VALUE) 02330 ::CloseHandle(m_fh); 02331 } 02332 02333 bool win_smart_device::is_open() const 02334 { 02335 return (m_fh != INVALID_HANDLE_VALUE); 02336 } 02337 02338 bool win_smart_device::close() 02339 { 02340 if (m_fh == INVALID_HANDLE_VALUE) 02341 return true; 02342 BOOL rc = ::CloseHandle(m_fh); 02343 m_fh = INVALID_HANDLE_VALUE; 02344 return !!rc; 02345 } 02346 02347 // ATA 02348 02349 win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) 02350 : smart_device(intf, dev_name, "ata", req_type), 02351 m_usr_options(false), 02352 m_admin(false), 02353 m_phydrive(-1), 02354 m_id_is_cached(false), 02355 m_is_3ware(false), 02356 m_port(-1), 02357 m_smartver_state(0) 02358 { 02359 } 02360 02361 win_ata_device::~win_ata_device() throw() 02362 { 02363 } 02364 02365 02366 // Open ATA device 02367 02368 bool win_ata_device::open() 02369 { 02370 const char * name = skipdev(get_dev_name()); int len = strlen(name); 02371 // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options 02372 char drive[2+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1; 02373 if ( sscanf(name, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1 02374 && ((n1 == len && !options[0]) || n2 == len) ) { 02375 return open(sdxy_to_phydrive(drive), -1, options, -1); 02376 } 02377 // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options 02378 drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1; 02379 unsigned port = ~0; 02380 if ( sscanf(name, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2 02381 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) { 02382 return open(sdxy_to_phydrive(drive), -1, options, port); 02383 } 02384 // pd<m>,N => Physical drive <m>, RAID port N 02385 int phydrive = -1; port = ~0; n1 = -1; n2 = -1; 02386 if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1 02387 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) { 02388 return open(phydrive, -1, "", (int)port); 02389 } 02390 // [a-zA-Z]: => Physical drive behind logical drive 0-25 02391 int logdrive = drive_letter(name); 02392 if (logdrive >= 0) { 02393 return open(-1, logdrive, "", -1); 02394 } 02395 02396 return set_err(EINVAL); 02397 } 02398 02399 02400 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port) 02401 { 02402 m_phydrive = -1; 02403 char devpath[30]; 02404 if (0 <= phydrive && phydrive <= 255) 02405 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive)); 02406 else if (0 <= logdrive && logdrive <= 'Z'-'A') 02407 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive); 02408 else 02409 return set_err(ENOENT); 02410 02411 // Open device 02412 HANDLE h = INVALID_HANDLE_VALUE; 02413 if (!(*options && !options[strspn(options, "fp")])) { 02414 // Open with admin rights 02415 m_admin = true; 02416 h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE, 02417 FILE_SHARE_READ|FILE_SHARE_WRITE, 02418 NULL, OPEN_EXISTING, 0, 0); 02419 } 02420 if (h == INVALID_HANDLE_VALUE) { 02421 // Open without admin rights 02422 m_admin = false; 02423 h = CreateFileA(devpath, 0, 02424 FILE_SHARE_READ|FILE_SHARE_WRITE, 02425 NULL, OPEN_EXISTING, 0, 0); 02426 } 02427 if (h == INVALID_HANDLE_VALUE) { 02428 long err = GetLastError(); 02429 if (err == ERROR_FILE_NOT_FOUND) 02430 set_err(ENOENT, "%s: not found", devpath); 02431 else if (err == ERROR_ACCESS_DENIED) 02432 set_err(EACCES, "%s: access denied", devpath); 02433 else 02434 set_err(EIO, "%s: Error=%ld", devpath, err); 02435 return false; 02436 } 02437 set_fh(h); 02438 02439 // Warn once if admin rights are missing 02440 if (!m_admin) { 02441 static bool noadmin_warning = false; 02442 if (!noadmin_warning) { 02443 pout("Warning: Limited functionality due to missing admin rights\n"); 02444 noadmin_warning = true; 02445 } 02446 } 02447 02448 if (ata_debugmode > 1) 02449 pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :"")); 02450 02451 m_usr_options = false; 02452 if (*options) { 02453 // Save user options 02454 m_options = options; m_usr_options = true; 02455 } 02456 else if (port >= 0) 02457 // RAID: SMART_* and SCSI_MINIPORT 02458 m_options = "s3"; 02459 else { 02460 // Set default options according to Windows version 02461 static const char * def_options = ata_get_def_options(); 02462 m_options = def_options; 02463 } 02464 02465 // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call 02466 m_port = port; 02467 if (port < 0) 02468 return true; 02469 02470 // 3ware RAID: Get port map 02471 GETVERSIONINPARAMS_EX vers_ex; 02472 int devmap = smart_get_version(h, &vers_ex); 02473 02474 // 3ware RAID if vendor id present 02475 m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE); 02476 02477 unsigned long portmap = 0; 02478 if (port >= 0 && devmap >= 0) { 02479 // 3ware RAID: check vendor id 02480 if (!m_is_3ware) { 02481 pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n" 02482 "This is no 3ware 9000 controller or driver has no SMART support.\n", 02483 vers_ex.wIdentifier); 02484 devmap = -1; 02485 } 02486 else 02487 portmap = vers_ex.dwDeviceMapEx; 02488 } 02489 if (devmap < 0) { 02490 pout("%s: ATA driver has no SMART support\n", devpath); 02491 if (!is_permissive()) { 02492 close(); 02493 return set_err(ENOSYS); 02494 } 02495 devmap = 0x0f; 02496 } 02497 m_smartver_state = 1; 02498 02499 { 02500 // 3ware RAID: update devicemap first 02501 02502 if (!update_3ware_devicemap_ioctl(h)) { 02503 if ( smart_get_version(h, &vers_ex) >= 0 02504 && vers_ex.wIdentifier == SMART_VENDOR_3WARE ) 02505 portmap = vers_ex.dwDeviceMapEx; 02506 } 02507 // Check port existence 02508 if (!(portmap & (1L << port))) { 02509 if (!is_permissive()) { 02510 close(); 02511 return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port); 02512 } 02513 } 02514 } 02515 02516 return true; 02517 } 02518 02519 02520 ///////////////////////////////////////////////////////////////////////////// 02521 02522 // Interface to ATA devices 02523 bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 02524 { 02525 // No multi-sector support for now, see above 02526 // warning about IOCTL_ATA_PASS_THROUGH 02527 if (!ata_cmd_is_supported(in, 02528 ata_device::supports_data_out | 02529 ata_device::supports_output_regs | 02530 ata_device::supports_48bit) 02531 ) 02532 return false; 02533 02534 // 3ware RAID: SMART DISABLE without port number disables SMART functions 02535 if ( m_is_3ware && m_port < 0 02536 && in.in_regs.command == ATA_SMART_CMD 02537 && in.in_regs.features == ATA_SMART_DISABLE) 02538 return set_err(ENOSYS, "SMART DISABLE requires 3ware port number"); 02539 02540 // Determine ioctl functions valid for this ATA cmd 02541 const char * valid_options = 0; 02542 02543 switch (in.in_regs.command) { 02544 case ATA_IDENTIFY_DEVICE: 02545 case ATA_IDENTIFY_PACKET_DEVICE: 02546 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE 02547 // and SCSI_MINIPORT_* if requested by user 02548 valid_options = (m_usr_options ? "saimf" : "saif"); 02549 break; 02550 02551 case ATA_CHECK_POWER_MODE: 02552 // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk 02553 valid_options = "pai3"; 02554 break; 02555 02556 case ATA_SMART_CMD: 02557 switch (in.in_regs.features) { 02558 case ATA_SMART_READ_VALUES: 02559 case ATA_SMART_READ_THRESHOLDS: 02560 case ATA_SMART_AUTOSAVE: 02561 case ATA_SMART_ENABLE: 02562 case ATA_SMART_DISABLE: 02563 case ATA_SMART_AUTO_OFFLINE: 02564 // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE 02565 // and SCSI_MINIPORT_* if requested by user 02566 valid_options = (m_usr_options ? "saimf" : "saif"); 02567 break; 02568 02569 case ATA_SMART_IMMEDIATE_OFFLINE: 02570 // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST 02571 valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ? 02572 "saim3" : "aim3"); 02573 break; 02574 02575 case ATA_SMART_READ_LOG_SECTOR: 02576 // SMART_RCV_DRIVE_DATA does not support READ_LOG 02577 // Try SCSI_MINIPORT also to skip buggy class driver 02578 // SMART functions do not support multi sector I/O. 02579 if (in.size == 512) 02580 valid_options = (m_usr_options ? "saim3" : "aim3"); 02581 else 02582 valid_options = "a"; 02583 break; 02584 02585 case ATA_SMART_WRITE_LOG_SECTOR: 02586 // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT 02587 // but SCSI_MINIPORT_* only if requested by user and single sector. 02588 valid_options = (in.size == 512 && m_usr_options ? "am" : "a"); 02589 break; 02590 02591 case ATA_SMART_STATUS: 02592 valid_options = (m_usr_options ? "saimf" : "saif"); 02593 break; 02594 02595 default: 02596 // Unknown SMART command, handle below 02597 break; 02598 } 02599 break; 02600 02601 default: 02602 // Other ATA command, handle below 02603 break; 02604 } 02605 02606 if (!valid_options) { 02607 // No special ATA command found above, select a generic pass through ioctl. 02608 if (!( in.direction == ata_cmd_in::no_data 02609 || (in.direction == ata_cmd_in::data_in && in.size == 512)) 02610 || in.in_regs.is_48bit_cmd() ) 02611 // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only 02612 valid_options = "a"; 02613 else 02614 // ATA/IDE_PASS_THROUGH 02615 valid_options = "ai"; 02616 } 02617 02618 if (!m_admin) { 02619 // Restrict to IOCTL_STORAGE_* 02620 if (strchr(valid_options, 'f')) 02621 valid_options = "f"; 02622 else if (strchr(valid_options, 'p')) 02623 valid_options = "p"; 02624 else 02625 return set_err(ENOSYS, "Function requires admin rights"); 02626 } 02627 02628 // Set IDEREGS 02629 IDEREGS regs, prev_regs; 02630 { 02631 const ata_in_regs & lo = in.in_regs; 02632 regs.bFeaturesReg = lo.features; 02633 regs.bSectorCountReg = lo.sector_count; 02634 regs.bSectorNumberReg = lo.lba_low; 02635 regs.bCylLowReg = lo.lba_mid; 02636 regs.bCylHighReg = lo.lba_high; 02637 regs.bDriveHeadReg = lo.device; 02638 regs.bCommandReg = lo.command; 02639 regs.bReserved = 0; 02640 } 02641 if (in.in_regs.is_48bit_cmd()) { 02642 const ata_in_regs & hi = in.in_regs.prev; 02643 prev_regs.bFeaturesReg = hi.features; 02644 prev_regs.bSectorCountReg = hi.sector_count; 02645 prev_regs.bSectorNumberReg = hi.lba_low; 02646 prev_regs.bCylLowReg = hi.lba_mid; 02647 prev_regs.bCylHighReg = hi.lba_high; 02648 prev_regs.bDriveHeadReg = hi.device; 02649 prev_regs.bCommandReg = hi.command; 02650 prev_regs.bReserved = 0; 02651 } 02652 02653 // Set data direction 02654 int datasize = 0; 02655 char * data = 0; 02656 switch (in.direction) { 02657 case ata_cmd_in::no_data: 02658 break; 02659 case ata_cmd_in::data_in: 02660 datasize = (int)in.size; 02661 data = (char *)in.buffer; 02662 break; 02663 case ata_cmd_in::data_out: 02664 datasize = -(int)in.size; 02665 data = (char *)in.buffer; 02666 break; 02667 default: 02668 return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d", 02669 (int)in.direction); 02670 } 02671 02672 02673 // Try all valid ioctls in the order specified in m_options 02674 bool powered_up = false; 02675 bool out_regs_set = false; 02676 bool id_is_cached = false; 02677 const char * options = m_options.c_str(); 02678 02679 for (int i = 0; ; i++) { 02680 char opt = options[i]; 02681 02682 if (!opt) { 02683 if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) { 02684 // Power up reported by GetDevicePowerState() and no ioctl available 02685 // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE. 02686 regs.bSectorCountReg = 0xff; 02687 out_regs_set = true; 02688 break; 02689 } 02690 // No IOCTL found 02691 return set_err(ENOSYS); 02692 } 02693 if (!strchr(valid_options, opt)) 02694 // Invalid for this command 02695 continue; 02696 02697 errno = 0; 02698 assert( datasize == 0 || datasize == 512 02699 || (datasize == -512 && strchr("am", opt)) 02700 || (datasize > 512 && opt == 'a')); 02701 int rc; 02702 switch (opt) { 02703 default: assert(0); 02704 case 's': 02705 // call SMART_GET_VERSION once for each drive 02706 if (m_smartver_state > 1) { 02707 rc = -1; errno = ENOSYS; 02708 break; 02709 } 02710 if (!m_smartver_state) { 02711 assert(m_port == -1); 02712 GETVERSIONINPARAMS_EX vers_ex; 02713 if (smart_get_version(get_fh(), &vers_ex) < 0) { 02714 if (!failuretest_permissive) { 02715 m_smartver_state = 2; 02716 rc = -1; errno = ENOSYS; 02717 break; 02718 } 02719 failuretest_permissive--; 02720 } 02721 else { 02722 // 3ware RAID if vendor id present 02723 m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE); 02724 } 02725 02726 m_smartver_state = 1; 02727 } 02728 rc = smart_ioctl(get_fh(), ®s, data, datasize, m_port); 02729 out_regs_set = (in.in_regs.features == ATA_SMART_STATUS); 02730 id_is_cached = (m_port < 0); // Not cached by 3ware driver 02731 break; 02732 case 'm': 02733 rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s, data, datasize); 02734 id_is_cached = (m_port < 0); 02735 break; 02736 case 'a': 02737 rc = ata_pass_through_ioctl(get_fh(), ®s, 02738 (in.in_regs.is_48bit_cmd() ? &prev_regs : 0), 02739 data, datasize); 02740 out_regs_set = true; 02741 break; 02742 case 'i': 02743 rc = ide_pass_through_ioctl(get_fh(), ®s, data, datasize); 02744 out_regs_set = true; 02745 break; 02746 case 'f': 02747 if (in.in_regs.command == ATA_IDENTIFY_DEVICE) { 02748 rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data); 02749 if (rc == 0 && m_phydrive >= 0) 02750 get_serial_from_wmi(m_phydrive, (ata_identify_device *)data); 02751 id_is_cached = true; 02752 } 02753 else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) { 02754 case ATA_SMART_READ_VALUES: 02755 rc = storage_predict_failure_ioctl(get_fh(), data); 02756 if (rc > 0) 02757 rc = 0; 02758 break; 02759 case ATA_SMART_ENABLE: 02760 rc = 0; 02761 break; 02762 case ATA_SMART_STATUS: 02763 rc = storage_predict_failure_ioctl(get_fh()); 02764 if (rc == 0) { 02765 // Good SMART status 02766 out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f; 02767 } 02768 else if (rc > 0) { 02769 // Bad SMART status 02770 out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4; 02771 rc = 0; 02772 } 02773 break; 02774 default: 02775 errno = ENOSYS; rc = -1; 02776 } 02777 else { 02778 errno = ENOSYS; rc = -1; 02779 } 02780 break; 02781 case '3': 02782 rc = ata_via_3ware_miniport_ioctl(get_fh(), ®s, data, datasize, m_port); 02783 out_regs_set = true; 02784 break; 02785 case 'p': 02786 assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0); 02787 rc = get_device_power_state(get_fh()); 02788 if (rc == 0) { 02789 // Power down reported by GetDevicePowerState(), using a passthrough ioctl would 02790 // spin up the drive => simulate ATA result STANDBY. 02791 regs.bSectorCountReg = 0x00; 02792 out_regs_set = true; 02793 } 02794 else if (rc > 0) { 02795 // Power up reported by GetDevicePowerState(), but this reflects the actual mode 02796 // only if it is selected by the device driver => try a passthrough ioctl to get the 02797 // actual mode, if none available simulate ACTIVE/IDLE. 02798 powered_up = true; 02799 rc = -1; errno = ENOSYS; 02800 } 02801 break; 02802 } 02803 02804 if (!rc) 02805 // Working ioctl found 02806 break; 02807 02808 if (errno != ENOSYS) 02809 // Abort on I/O error 02810 return set_err(errno); 02811 02812 out_regs_set = false; 02813 // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case 02814 } 02815 02816 // Return IDEREGS if set 02817 if (out_regs_set) { 02818 ata_out_regs & lo = out.out_regs; 02819 lo.error = regs.bFeaturesReg; 02820 lo.sector_count = regs.bSectorCountReg; 02821 lo.lba_low = regs.bSectorNumberReg; 02822 lo.lba_mid = regs.bCylLowReg; 02823 lo.lba_high = regs.bCylHighReg; 02824 lo.device = regs.bDriveHeadReg; 02825 lo.status = regs.bCommandReg; 02826 if (in.in_regs.is_48bit_cmd()) { 02827 ata_out_regs & hi = out.out_regs.prev; 02828 hi.sector_count = prev_regs.bSectorCountReg; 02829 hi.lba_low = prev_regs.bSectorNumberReg; 02830 hi.lba_mid = prev_regs.bCylLowReg; 02831 hi.lba_high = prev_regs.bCylHighReg; 02832 } 02833 } 02834 02835 if ( in.in_regs.command == ATA_IDENTIFY_DEVICE 02836 || in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) 02837 // Update ata_identify_is_cached() result according to ioctl used. 02838 m_id_is_cached = id_is_cached; 02839 02840 return true; 02841 } 02842 02843 // Return true if OS caches the ATA identify sector 02844 bool win_ata_device::ata_identify_is_cached() const 02845 { 02846 return m_id_is_cached; 02847 } 02848 02849 02850 ////////////////////////////////////////////////////////////////////// 02851 // csmi_ata_device 02852 02853 bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info) 02854 { 02855 // Get driver info to check CSMI support 02856 CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf; 02857 memset(&driver_info_buf, 0, sizeof(driver_info_buf)); 02858 if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf))) 02859 return false; 02860 02861 if (scsi_debugmode > 1) { 02862 const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information; 02863 pout("CSMI_SAS_DRIVER_INFO:\n"); 02864 pout(" Name: \"%.81s\"\n", driver_info.szName); 02865 pout(" Description: \"%.81s\"\n", driver_info.szDescription); 02866 pout(" Revision: %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision); 02867 } 02868 02869 // Get Phy info 02870 CSMI_SAS_PHY_INFO_BUFFER phy_info_buf; 02871 memset(&phy_info_buf, 0, sizeof(phy_info_buf)); 02872 if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf))) 02873 return false; 02874 02875 phy_info = phy_info_buf.Information; 02876 if (phy_info.bNumberOfPhys > sizeof(phy_info.Phy)/sizeof(phy_info.Phy[0])) 02877 return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys); 02878 02879 if (scsi_debugmode > 1) { 02880 pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys); 02881 for (int i = 0; i < phy_info.bNumberOfPhys; i++) { 02882 const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i]; 02883 const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached; 02884 pout("Phy[%d] Port: 0x%02x\n", i, pe.bPortIdentifier); 02885 pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType); 02886 pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol); 02887 pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol); 02888 pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier); 02889 const unsigned char * b = id.bSASAddress; 02890 pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ", 02891 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); 02892 b = at.bSASAddress; 02893 pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n", 02894 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); 02895 } 02896 } 02897 02898 return true; 02899 } 02900 02901 bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no) 02902 { 02903 // Check Phy presence 02904 if (phy_no >= phy_info.bNumberOfPhys) 02905 return set_err(ENOENT, "Port %u does not exist (#ports: %d)", phy_no, 02906 phy_info.bNumberOfPhys); 02907 02908 const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[phy_no]; 02909 if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED) 02910 return set_err(ENOENT, "No device on port %u", phy_no); 02911 02912 switch (phy_ent.Attached.bTargetPortProtocol) { 02913 case CSMI_SAS_PROTOCOL_SATA: 02914 case CSMI_SAS_PROTOCOL_STP: 02915 break; 02916 default: 02917 return set_err(ENOENT, "No SATA device on port %u (protocol: %u)", 02918 phy_no, phy_ent.Attached.bTargetPortProtocol); 02919 } 02920 02921 return true; 02922 } 02923 02924 bool csmi_device::select_phy(unsigned phy_no) 02925 { 02926 CSMI_SAS_PHY_INFO phy_info; 02927 if (!get_phy_info(phy_info)) 02928 return false; 02929 02930 02931 if (!check_phy(phy_info, phy_no)) 02932 return false; 02933 02934 m_phy_ent = phy_info.Phy[phy_no]; 02935 return true; 02936 } 02937 02938 02939 bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 02940 { 02941 if (!ata_cmd_is_supported(in, 02942 ata_device::supports_data_out | 02943 ata_device::supports_output_regs | 02944 ata_device::supports_multi_sector | 02945 ata_device::supports_48bit, 02946 "CMSI") 02947 ) 02948 return false; 02949 02950 // Create buffer with appropriate size 02951 raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size); 02952 CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data(); 02953 02954 // Set addresses from Phy info 02955 CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters; 02956 const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent(); 02957 pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier; 02958 pthru.bPortIdentifier = phy_ent.bPortIdentifier; 02959 memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress, 02960 sizeof(pthru.bDestinationSASAddress)); 02961 pthru.bConnectionRate = CSMI_SAS_LINK_RATE_NEGOTIATED; 02962 02963 // Set transfer mode 02964 switch (in.direction) { 02965 case ata_cmd_in::no_data: 02966 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_UNSPECIFIED; 02967 break; 02968 case ata_cmd_in::data_in: 02969 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_READ; 02970 pthru.uDataLength = in.size; 02971 break; 02972 case ata_cmd_in::data_out: 02973 pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_WRITE; 02974 pthru.uDataLength = in.size; 02975 memcpy(pthru_buf->bDataBuffer, in.buffer, in.size); 02976 break; 02977 default: 02978 return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d", 02979 (int)in.direction); 02980 } 02981 02982 // Set host-to-device FIS 02983 { 02984 unsigned char * fis = pthru.bCommandFIS; 02985 const ata_in_regs & lo = in.in_regs; 02986 const ata_in_regs & hi = in.in_regs.prev; 02987 fis[ 0] = 0x27; // Type: host-to-device FIS 02988 fis[ 1] = 0x80; // Bit7: Update command register 02989 fis[ 2] = lo.command; 02990 fis[ 3] = lo.features; 02991 fis[ 4] = lo.lba_low; 02992 fis[ 5] = lo.lba_mid; 02993 fis[ 6] = lo.lba_high; 02994 fis[ 7] = lo.device; 02995 fis[ 8] = hi.lba_low; 02996 fis[ 9] = hi.lba_mid; 02997 fis[10] = hi.lba_high; 02998 fis[11] = hi.features; 02999 fis[12] = lo.sector_count; 03000 fis[13] = hi.sector_count; 03001 } 03002 03003 // Call ioctl 03004 if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) { 03005 return false; 03006 } 03007 03008 // Get device-to-host FIS 03009 { 03010 const unsigned char * fis = pthru_buf->Status.bStatusFIS; 03011 ata_out_regs & lo = out.out_regs; 03012 lo.status = fis[ 2]; 03013 lo.error = fis[ 3]; 03014 lo.lba_low = fis[ 4]; 03015 lo.lba_mid = fis[ 5]; 03016 lo.lba_high = fis[ 6]; 03017 lo.device = fis[ 7]; 03018 lo.sector_count = fis[12]; 03019 if (in.in_regs.is_48bit_cmd()) { 03020 ata_out_regs & hi = out.out_regs.prev; 03021 hi.lba_low = fis[ 8]; 03022 hi.lba_mid = fis[ 9]; 03023 hi.lba_high = fis[10]; 03024 hi.sector_count = fis[13]; 03025 } 03026 } 03027 03028 // Get data 03029 if (in.direction == ata_cmd_in::data_in) 03030 // TODO: Check ptru_buf->Status.uDataBytes 03031 memcpy(in.buffer, pthru_buf->bDataBuffer, in.size); 03032 03033 return true; 03034 } 03035 03036 03037 ////////////////////////////////////////////////////////////////////// 03038 // win_csmi_device 03039 03040 win_csmi_device::win_csmi_device(smart_interface * intf, const char * dev_name, 03041 const char * req_type) 03042 : smart_device(intf, dev_name, "ata", req_type), 03043 m_fh(INVALID_HANDLE_VALUE), m_phy_no(0) 03044 { 03045 } 03046 03047 win_csmi_device::~win_csmi_device() throw() 03048 { 03049 if (m_fh != INVALID_HANDLE_VALUE) 03050 CloseHandle(m_fh); 03051 } 03052 03053 bool win_csmi_device::is_open() const 03054 { 03055 return (m_fh != INVALID_HANDLE_VALUE); 03056 } 03057 03058 bool win_csmi_device::close() 03059 { 03060 if (m_fh == INVALID_HANDLE_VALUE) 03061 return true; 03062 BOOL rc = CloseHandle(m_fh); 03063 m_fh = INVALID_HANDLE_VALUE; 03064 return !!rc; 03065 } 03066 03067 03068 bool win_csmi_device::open_scsi() 03069 { 03070 // Parse name 03071 unsigned contr_no = ~0, phy_no = ~0; int nc = -1; 03072 const char * name = skipdev(get_dev_name()); 03073 if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &phy_no, &nc) >= 0 03074 && nc == (int)strlen(name) && contr_no <= 9 && phy_no < 32) ) 03075 return set_err(EINVAL); 03076 03077 // Open controller handle 03078 char devpath[30]; 03079 snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no); 03080 03081 HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE, 03082 FILE_SHARE_READ|FILE_SHARE_WRITE, 03083 (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0); 03084 03085 if (h == INVALID_HANDLE_VALUE) { 03086 long err = GetLastError(); 03087 if (err == ERROR_FILE_NOT_FOUND) 03088 set_err(ENOENT, "%s: not found", devpath); 03089 else if (err == ERROR_ACCESS_DENIED) 03090 set_err(EACCES, "%s: access denied", devpath); 03091 else 03092 set_err(EIO, "%s: Error=%ld", devpath, err); 03093 return false; 03094 } 03095 03096 if (scsi_debugmode > 1) 03097 pout(" %s: successfully opened\n", devpath); 03098 03099 m_fh = h; 03100 m_phy_no = phy_no; 03101 return true; 03102 } 03103 03104 03105 bool win_csmi_device::open() 03106 { 03107 if (!open_scsi()) 03108 return false; 03109 03110 // Get Phy info for this drive 03111 if (!select_phy(m_phy_no)) { 03112 close(); 03113 return false; 03114 } 03115 03116 return true; 03117 } 03118 03119 03120 bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, 03121 unsigned csmi_bufsiz) 03122 { 03123 // Determine signature 03124 const char * sig; 03125 switch (code) { 03126 case CC_CSMI_SAS_GET_DRIVER_INFO: 03127 sig = CSMI_ALL_SIGNATURE; break; 03128 case CC_CSMI_SAS_GET_PHY_INFO: 03129 case CC_CSMI_SAS_STP_PASSTHRU: 03130 sig = CSMI_SAS_SIGNATURE; break; 03131 default: 03132 return set_err(ENOSYS, "Unknown CSMI code=%u", code); 03133 } 03134 03135 // Set header 03136 csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER); 03137 strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature)); 03138 csmi_buffer->Timeout = CSMI_SAS_TIMEOUT; 03139 csmi_buffer->ControlCode = code; 03140 csmi_buffer->ReturnCode = 0; 03141 csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER); 03142 03143 // Call function 03144 DWORD num_out = 0; 03145 if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT, 03146 csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) { 03147 long err = GetLastError(); 03148 if (scsi_debugmode) 03149 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err); 03150 if ( err == ERROR_INVALID_FUNCTION 03151 || err == ERROR_NOT_SUPPORTED 03152 || err == ERROR_DEV_NOT_EXIST) 03153 return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err); 03154 else 03155 return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err); 03156 } 03157 03158 // Check result 03159 if (csmi_buffer->ReturnCode) { 03160 if (scsi_debugmode) { 03161 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n", 03162 code, (unsigned)csmi_buffer->ReturnCode); 03163 } 03164 return set_err(EIO, "CSMI(%u) failed with ReturnCode=%u", code, (unsigned)csmi_buffer->ReturnCode); 03165 } 03166 03167 if (scsi_debugmode > 1) 03168 pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out); 03169 03170 return true; 03171 } 03172 03173 03174 ///////////////////////////////////////////////////////////////////////////// 03175 // SPT Interface (for SCSI devices and ATA devices behind SATLs) 03176 // Only supported in NT and later 03177 ///////////////////////////////////////////////////////////////////////////// 03178 03179 win_scsi_device::win_scsi_device(smart_interface * intf, 03180 const char * dev_name, const char * req_type) 03181 : smart_device(intf, dev_name, "scsi", req_type) 03182 { 03183 } 03184 03185 bool win_scsi_device::open() 03186 { 03187 const char * name = skipdev(get_dev_name()); int len = strlen(name); 03188 // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N 03189 char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1; 03190 if ( sscanf(name, "sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1 03191 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) { 03192 return open(sdxy_to_phydrive(drive), -1, -1, sub_addr); 03193 } 03194 // pd<m>,N => Physical drive <m>, RAID port N 03195 int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1; 03196 if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1 03197 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) { 03198 return open(pd_num, -1, -1, sub_addr); 03199 } 03200 // [a-zA-Z]: => Physical drive behind logical drive 0-25 03201 int logdrive = drive_letter(name); 03202 if (logdrive >= 0) { 03203 return open(-1, logdrive, -1, -1); 03204 } 03205 // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation) 03206 int tape_num = -1; n1 = -1; 03207 if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { 03208 return open(-1, -1, tape_num, -1); 03209 } 03210 tape_num = -1; n1 = -1; 03211 if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { 03212 return open(-1, -1, tape_num, -1); 03213 } 03214 // tape<m> => tape drive <m> 03215 tape_num = -1; n1 = -1; 03216 if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { 03217 return open(-1, -1, tape_num, -1); 03218 } 03219 03220 return set_err(EINVAL); 03221 } 03222 03223 bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/) 03224 { 03225 char b[128]; 03226 b[sizeof(b) - 1] = '\0'; 03227 if (pd_num >= 0) 03228 snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num); 03229 else if (ld_num >= 0) 03230 snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num); 03231 else if (tape_num >= 0) 03232 snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num); 03233 else { 03234 set_err(EINVAL); 03235 return false; 03236 } 03237 03238 // Open device 03239 HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE, 03240 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, 03241 OPEN_EXISTING, 0, 0); 03242 if (h == INVALID_HANDLE_VALUE) { 03243 set_err(ENODEV, "%s: Open failed, Error=%u", b, (unsigned)GetLastError()); 03244 return false; 03245 } 03246 set_fh(h); 03247 return true; 03248 } 03249 03250 03251 typedef struct { 03252 SCSI_PASS_THROUGH_DIRECT spt; 03253 ULONG Filler; 03254 UCHAR ucSenseBuf[64]; 03255 } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; 03256 03257 03258 // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT. 03259 // Used if DataTransferLength not supported by *_DIRECT. 03260 static long scsi_pass_through_indirect(HANDLE h, 03261 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * sbd) 03262 { 03263 struct SCSI_PASS_THROUGH_WITH_BUFFERS { 03264 SCSI_PASS_THROUGH spt; 03265 ULONG Filler; 03266 UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)]; 03267 UCHAR ucDataBuf[512]; 03268 }; 03269 03270 SCSI_PASS_THROUGH_WITH_BUFFERS sb; 03271 memset(&sb, 0, sizeof(sb)); 03272 03273 // DATA_OUT not implemented yet 03274 if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN 03275 && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf))) 03276 return ERROR_INVALID_PARAMETER; 03277 03278 sb.spt.Length = sizeof(sb.spt); 03279 sb.spt.CdbLength = sbd->spt.CdbLength; 03280 memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb)); 03281 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); 03282 sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); 03283 sb.spt.DataIn = sbd->spt.DataIn; 03284 sb.spt.DataTransferLength = sbd->spt.DataTransferLength; 03285 sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf); 03286 sb.spt.TimeOutValue = sbd->spt.TimeOutValue; 03287 03288 DWORD num_out; 03289 if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH, 03290 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) 03291 return GetLastError(); 03292 03293 sbd->spt.ScsiStatus = sb.spt.ScsiStatus; 03294 if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION) 03295 memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf)); 03296 03297 sbd->spt.DataTransferLength = sb.spt.DataTransferLength; 03298 if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0) 03299 memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength); 03300 return 0; 03301 } 03302 03303 03304 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c 03305 bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop) 03306 { 03307 int report = scsi_debugmode; // TODO 03308 03309 if (report > 0) { 03310 int k, j; 03311 const unsigned char * ucp = iop->cmnd; 03312 const char * np; 03313 char buff[256]; 03314 const int sz = (int)sizeof(buff); 03315 03316 np = scsi_get_opcode_name(ucp[0]); 03317 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); 03318 for (k = 0; k < (int)iop->cmnd_len; ++k) 03319 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); 03320 if ((report > 1) && 03321 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { 03322 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 03323 03324 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " 03325 "data, len=%d%s:\n", (int)iop->dxfer_len, 03326 (trunc ? " [only first 256 bytes shown]" : "")); 03327 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 03328 } 03329 else 03330 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); 03331 pout("%s", buff); 03332 } 03333 03334 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; 03335 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) { 03336 set_err(EINVAL, "cmnd_len too large"); 03337 return false; 03338 } 03339 03340 memset(&sb, 0, sizeof(sb)); 03341 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); 03342 sb.spt.CdbLength = iop->cmnd_len; 03343 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len); 03344 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); 03345 sb.spt.SenseInfoOffset = 03346 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); 03347 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60); 03348 03349 bool direct = true; 03350 switch (iop->dxfer_dir) { 03351 case DXFER_NONE: 03352 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; 03353 break; 03354 case DXFER_FROM_DEVICE: 03355 sb.spt.DataIn = SCSI_IOCTL_DATA_IN; 03356 sb.spt.DataTransferLength = iop->dxfer_len; 03357 sb.spt.DataBuffer = iop->dxferp; 03358 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte 03359 // transfers (needed for SMART STATUS check of JMicron USB bridges) 03360 if (sb.spt.DataTransferLength == 1) 03361 direct = false; 03362 break; 03363 case DXFER_TO_DEVICE: 03364 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT; 03365 sb.spt.DataTransferLength = iop->dxfer_len; 03366 sb.spt.DataBuffer = iop->dxferp; 03367 break; 03368 default: 03369 set_err(EINVAL, "bad dxfer_dir"); 03370 return false; 03371 } 03372 03373 long err = 0; 03374 if (direct) { 03375 DWORD num_out; 03376 if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT, 03377 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) 03378 err = GetLastError(); 03379 } 03380 else 03381 err = scsi_pass_through_indirect(get_fh(), &sb); 03382 03383 if (err) 03384 return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO), 03385 "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld", 03386 (direct ? "_DIRECT" : ""), err); 03387 03388 iop->scsi_status = sb.spt.ScsiStatus; 03389 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) { 03390 int slen = sb.ucSenseBuf[7] + 8; 03391 03392 if (slen > (int)sizeof(sb.ucSenseBuf)) 03393 slen = sizeof(sb.ucSenseBuf); 03394 if (slen > (int)iop->max_sense_len) 03395 slen = iop->max_sense_len; 03396 memcpy(iop->sensep, sb.ucSenseBuf, slen); 03397 iop->resp_sense_len = slen; 03398 if (report) { 03399 if (report > 1) { 03400 pout(" >>> Sense buffer, len=%d:\n", slen); 03401 dStrHex(iop->sensep, slen , 1); 03402 } 03403 if ((iop->sensep[0] & 0x7f) > 0x71) 03404 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", 03405 iop->scsi_status, iop->sensep[1] & 0xf, 03406 iop->sensep[2], iop->sensep[3]); 03407 else 03408 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", 03409 iop->scsi_status, iop->sensep[2] & 0xf, 03410 iop->sensep[12], iop->sensep[13]); 03411 } 03412 } else 03413 iop->resp_sense_len = 0; 03414 03415 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0)) 03416 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength; 03417 else 03418 iop->resid = 0; 03419 03420 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) { 03421 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 03422 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, 03423 (trunc ? " [only first 256 bytes shown]" : "")); 03424 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 03425 } 03426 return true; 03427 } 03428 03429 // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c 03430 static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop) 03431 { 03432 int report = scsi_debugmode; // TODO 03433 03434 if (report > 0) { 03435 int k, j; 03436 const unsigned char * ucp = iop->cmnd; 03437 const char * np; 03438 char buff[256]; 03439 const int sz = (int)sizeof(buff); 03440 03441 np = scsi_get_opcode_name(ucp[0]); 03442 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); 03443 for (k = 0; k < (int)iop->cmnd_len; ++k) 03444 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); 03445 if ((report > 1) && 03446 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { 03447 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 03448 03449 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " 03450 "data, len=%d%s:\n", (int)iop->dxfer_len, 03451 (trunc ? " [only first 256 bytes shown]" : "")); 03452 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 03453 } 03454 else 03455 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); 03456 pout("%s", buff); 03457 } 03458 03459 SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; 03460 if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) { 03461 return EINVAL; 03462 } 03463 03464 memset(&sb, 0, sizeof(sb)); 03465 sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); 03466 //sb.spt.PathId = 0; 03467 sb.spt.TargetId = targetid; 03468 //sb.spt.Lun = 0; 03469 sb.spt.CdbLength = iop->cmnd_len; 03470 memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len); 03471 sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); 03472 sb.spt.SenseInfoOffset = 03473 offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); 03474 sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60); 03475 03476 bool direct = true; 03477 switch (iop->dxfer_dir) { 03478 case DXFER_NONE: 03479 sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; 03480 break; 03481 case DXFER_FROM_DEVICE: 03482 sb.spt.DataIn = SCSI_IOCTL_DATA_IN; 03483 sb.spt.DataTransferLength = iop->dxfer_len; 03484 sb.spt.DataBuffer = iop->dxferp; 03485 // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte 03486 // transfers (needed for SMART STATUS check of JMicron USB bridges) 03487 if (sb.spt.DataTransferLength == 1) 03488 direct = false; 03489 break; 03490 case DXFER_TO_DEVICE: 03491 sb.spt.DataIn = SCSI_IOCTL_DATA_OUT; 03492 sb.spt.DataTransferLength = iop->dxfer_len; 03493 sb.spt.DataBuffer = iop->dxferp; 03494 break; 03495 default: 03496 return EINVAL; 03497 } 03498 03499 long err = 0; 03500 if (direct) { 03501 DWORD num_out; 03502 if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT, 03503 &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) 03504 err = GetLastError(); 03505 } 03506 else 03507 err = scsi_pass_through_indirect(fd, &sb); 03508 03509 if (err) 03510 { 03511 return err; 03512 } 03513 03514 iop->scsi_status = sb.spt.ScsiStatus; 03515 if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) { 03516 int slen = sb.ucSenseBuf[7] + 8; 03517 03518 if (slen > (int)sizeof(sb.ucSenseBuf)) 03519 slen = sizeof(sb.ucSenseBuf); 03520 if (slen > (int)iop->max_sense_len) 03521 slen = iop->max_sense_len; 03522 memcpy(iop->sensep, sb.ucSenseBuf, slen); 03523 iop->resp_sense_len = slen; 03524 if (report) { 03525 if (report > 1) { 03526 pout(" >>> Sense buffer, len=%d:\n", slen); 03527 dStrHex(iop->sensep, slen , 1); 03528 } 03529 if ((iop->sensep[0] & 0x7f) > 0x71) 03530 pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", 03531 iop->scsi_status, iop->sensep[1] & 0xf, 03532 iop->sensep[2], iop->sensep[3]); 03533 else 03534 pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", 03535 iop->scsi_status, iop->sensep[2] & 0xf, 03536 iop->sensep[12], iop->sensep[13]); 03537 } 03538 } else 03539 iop->resp_sense_len = 0; 03540 03541 if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0)) 03542 iop->resid = iop->dxfer_len - sb.spt.DataTransferLength; 03543 else 03544 iop->resid = 0; 03545 03546 if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) { 03547 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 03548 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, 03549 (trunc ? " [only first 256 bytes shown]" : "")); 03550 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 03551 } 03552 03553 return 0; 03554 } 03555 03556 // Areca RAID Controller(SAS Device) 03557 win_areca_scsi_device::win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) 03558 : smart_device(intf, dev_name, "areca", "areca") 03559 { 03560 set_fh(INVALID_HANDLE_VALUE); 03561 set_disknum(disknum); 03562 set_encnum(encnum); 03563 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); 03564 } 03565 03566 bool win_areca_scsi_device::open() 03567 { 03568 HANDLE hFh; 03569 03570 if( is_open() ) 03571 { 03572 return true; 03573 } 03574 hFh = CreateFile( get_dev_name(), 03575 GENERIC_READ|GENERIC_WRITE, 03576 FILE_SHARE_READ|FILE_SHARE_WRITE, 03577 NULL, 03578 OPEN_EXISTING, 03579 0, 03580 NULL ); 03581 if(hFh == INVALID_HANDLE_VALUE) 03582 { 03583 return false; 03584 } 03585 03586 set_fh(hFh); 03587 return true; 03588 } 03589 03590 smart_device * win_areca_scsi_device::autodetect_open() 03591 { 03592 return this; 03593 } 03594 03595 int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) 03596 { 03597 int ioctlreturn = 0; 03598 03599 ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop); 03600 if ( ioctlreturn || iop->scsi_status ) 03601 { 03602 ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop); 03603 if ( ioctlreturn || iop->scsi_status ) 03604 { 03605 // errors found 03606 return -1; 03607 } 03608 } 03609 03610 return ioctlreturn; 03611 } 03612 03613 bool win_areca_scsi_device::arcmsr_lock() 03614 { 03615 #define SYNCOBJNAME "Global\\SynIoctlMutex" 03616 int ctlrnum = -1; 03617 char mutexstr[64]; 03618 03619 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1) 03620 return set_err(EINVAL, "unable to parse device name"); 03621 03622 snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum); 03623 m_mutex = CreateMutex(NULL, FALSE, mutexstr); 03624 if ( m_mutex == NULL ) 03625 { 03626 return set_err(EIO, "CreateMutex failed"); 03627 } 03628 03629 // atomic access to driver 03630 WaitForSingleObject(m_mutex, INFINITE); 03631 03632 return true; 03633 } 03634 03635 03636 bool win_areca_scsi_device::arcmsr_unlock() 03637 { 03638 if( m_mutex != NULL) 03639 { 03640 ReleaseMutex(m_mutex); 03641 CloseHandle(m_mutex); 03642 } 03643 03644 return true; 03645 } 03646 03647 03648 // Areca RAID Controller(SATA Disk) 03649 win_areca_ata_device::win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) 03650 : smart_device(intf, dev_name, "areca", "areca") 03651 { 03652 set_fh(INVALID_HANDLE_VALUE); 03653 set_disknum(disknum); 03654 set_encnum(encnum); 03655 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); 03656 } 03657 03658 bool win_areca_ata_device::open() 03659 { 03660 HANDLE hFh; 03661 03662 if( is_open() ) 03663 { 03664 return true; 03665 } 03666 hFh = CreateFile( get_dev_name(), 03667 GENERIC_READ|GENERIC_WRITE, 03668 FILE_SHARE_READ|FILE_SHARE_WRITE, 03669 NULL, 03670 OPEN_EXISTING, 03671 0, 03672 NULL ); 03673 if(hFh == INVALID_HANDLE_VALUE) 03674 { 03675 return false; 03676 } 03677 03678 set_fh(hFh); 03679 return true; 03680 } 03681 03682 smart_device * win_areca_ata_device::autodetect_open() 03683 { 03684 int is_ata = 1; 03685 03686 // autodetect device type 03687 is_ata = arcmsr_get_dev_type(); 03688 if(is_ata < 0) 03689 { 03690 set_err(EIO); 03691 return this; 03692 } 03693 03694 if(is_ata == 1) 03695 { 03696 // SATA device 03697 return this; 03698 } 03699 03700 // SAS device 03701 smart_device_auto_ptr newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); 03702 close(); 03703 delete this; 03704 newdev->open(); // TODO: Can possibly pass open fd 03705 03706 return newdev.release(); 03707 } 03708 03709 int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) 03710 { 03711 int ioctlreturn = 0; 03712 03713 ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop); 03714 if ( ioctlreturn || iop->scsi_status ) 03715 { 03716 ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop); 03717 if ( ioctlreturn || iop->scsi_status ) 03718 { 03719 // errors found 03720 return -1; 03721 } 03722 } 03723 03724 return ioctlreturn; 03725 } 03726 03727 bool win_areca_ata_device::arcmsr_lock() 03728 { 03729 #define SYNCOBJNAME "Global\\SynIoctlMutex" 03730 int ctlrnum = -1; 03731 char mutexstr[64]; 03732 03733 if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1) 03734 return set_err(EINVAL, "unable to parse device name"); 03735 03736 snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum); 03737 m_mutex = CreateMutex(NULL, FALSE, mutexstr); 03738 if ( m_mutex == NULL ) 03739 { 03740 return set_err(EIO, "CreateMutex failed"); 03741 } 03742 03743 // atomic access to driver 03744 WaitForSingleObject(m_mutex, INFINITE); 03745 03746 return true; 03747 } 03748 03749 03750 bool win_areca_ata_device::arcmsr_unlock() 03751 { 03752 if( m_mutex != NULL) 03753 { 03754 ReleaseMutex(m_mutex); 03755 CloseHandle(m_mutex); 03756 } 03757 03758 return true; 03759 } 03760 03761 03762 ////////////////////////////////////////////////////////////////////////////////////////////////// 03763 03764 03765 } // namespace 03766 03767 ///////////////////////////////////////////////////////////////////////////// 03768 03769 // Initialize platform interface and register with smi() 03770 void smart_interface::init() 03771 { 03772 { 03773 // Remove "." from DLL search path if supported 03774 // to prevent DLL preloading attacks 03775 BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR)) 03776 GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA"); 03777 if (SetDllDirectoryA_p) 03778 SetDllDirectoryA_p(""); 03779 } 03780 03781 static os_win32::win_smart_interface the_win_interface; 03782 smart_interface::set(&the_win_interface); 03783 } 03784 03785 03786 #ifndef __CYGWIN__ 03787 03788 // Get exe directory 03789 // (prototype in utiliy.h) 03790 std::string get_exe_dir() 03791 { 03792 char path[MAX_PATH]; 03793 // Get path of this exe 03794 if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path))) 03795 throw std::runtime_error("GetModuleFileName() failed"); 03796 // Replace backslash by slash 03797 int sl = -1; 03798 for (int i = 0; path[i]; i++) 03799 if (path[i] == '\\') { 03800 path[i] = '/'; sl = i; 03801 } 03802 // Remove filename 03803 if (sl >= 0) 03804 path[sl] = 0; 03805 return path; 03806 } 03807 03808 #endif
1.7.4