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