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