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