Diff for /embedaddon/smartmontools/os_win32.cpp between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2012/02/21 16:32:16 version 1.1.1.4, 2013/10/14 07:54:03
Line 3 Line 3
  *   *
  * Home page of code is: http://smartmontools.sourceforge.net   * Home page of code is: http://smartmontools.sourceforge.net
  *   *
 * Copyright (C) 2004-11 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2012    Hank Wu <hank@areca.com.tw>
  *   *
  * This program is free software; you can redistribute it and/or modify   * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
Line 27 Line 28
   
 #include "dev_interface.h"  #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"  #include "dev_ata_cmd_set.h"
   #include "dev_areca.h"
   
 #include "os_win32/wmiquery.h"  #include "os_win32/wmiquery.h"
   
Line 47 Line 49
 #include <windows.h>  #include <windows.h>
   
 #if HAVE_NTDDDISK_H  #if HAVE_NTDDDISK_H
// i686-w64-mingw32, x86_64-w64-mingw32// i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32
 // (Missing: FILE_DEVICE_SCSI)  // (Missing: FILE_DEVICE_SCSI)
 #include <devioctl.h>  #include <devioctl.h>
 #include <ntdddisk.h>  #include <ntdddisk.h>
 #include <ntddscsi.h>  #include <ntddscsi.h>
 #include <ntddstor.h>  #include <ntddstor.h>
 #elif HAVE_DDK_NTDDDISK_H  #elif HAVE_DDK_NTDDDISK_H
// i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc// older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc
 // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)  // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI)
 #include <ddk/ntdddisk.h>  #include <ddk/ntdddisk.h>
 #include <ddk/ntddscsi.h>  #include <ddk/ntddscsi.h>
Line 66 Line 68
 #include <winioctl.h>  #include <winioctl.h>
 #endif  #endif
   
   #ifndef _WIN32
   // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
   #define _WIN32
   #endif
   
 // CSMI support  // CSMI support
 #include "csmisas.h"  #include "csmisas.h"
   
#ifdef __CYGWIN__// Silence -Wunused-local-typedefs warning from g++ >= 4.8
#include <cygwin/version.h> // CYGWIN_VERSION_DLL_MAJOR#if __GNUC__ >= 4
 #define ATTR_UNUSED __attribute__((unused))
 #else
 #define ATTR_UNUSED /**/
 #endif  #endif
   
 // Macro to check constants at compile time using a dummy typedef  // Macro to check constants at compile time using a dummy typedef
 #define ASSERT_CONST(c, n) \  #define ASSERT_CONST(c, n) \
  typedef char assert_const_##c[((c) == (n)) ? 1 : -1]  typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED
 #define ASSERT_SIZEOF(t, n) \  #define ASSERT_SIZEOF(t, n) \
  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
   
 #ifndef _WIN64  #ifndef _WIN64
 #define SELECT_WIN_32_64(x32, x64) (x32)  #define SELECT_WIN_32_64(x32, x64) (x32)
Line 87 Line 97
   
 const char * os_win32_cpp_cvsid = "$Id$";  const char * os_win32_cpp_cvsid = "$Id$";
   
 // Disable Win9x/ME specific code if no longer supported by compiler.  
 #ifdef _WIN64  
   #undef WIN9X_SUPPORT  
 #elif !defined(WIN9X_SUPPORT)  
   #if defined(CYGWIN_VERSION_DLL_MAJOR) && (CYGWIN_VERSION_DLL_MAJOR >= 1007)  
     // Win9x/ME support was dropped in Cygwin 1.7  
   #elif defined(_MSC_VER) && (_MSC_VER >= 1500)  
     // Win9x/ME support was dropped in MSVC9 (cl.exe 15.0)  
   #else  
     #define WIN9X_SUPPORT 1  
   #endif  
 #endif  
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 // Windows I/O-controls, some declarations are missing in the include files  // Windows I/O-controls, some declarations are missing in the include files
   
Line 319  namespace os_win32 { // no need to publish anything, n Line 316  namespace os_win32 { // no need to publish anything, n
 #pragma warning(disable:4250)  #pragma warning(disable:4250)
 #endif  #endif
   
 // Running on Win9x/ME ?  
 #if WIN9X_SUPPORT  
 // Set true in win9x_smart_interface ctor.  
 static bool win9x = false;  
 #else  
 // Never true (const allows compiler to remove dead code).  
 const  bool win9x = false;  
 #endif  
   
   
 class win_smart_device  class win_smart_device
 : virtual public /*implements*/ smart_device  : virtual public /*implements*/ smart_device
 {  {
Line 381  class win_ata_device (private) Line 368  class win_ata_device (private)
   std::string m_options;    std::string m_options;
   bool m_usr_options; // options set by user?    bool m_usr_options; // options set by user?
   bool m_admin; // open with admin access?    bool m_admin; // open with admin access?
     int m_phydrive; // PhysicalDriveN or -1
   bool m_id_is_cached; // ata_identify_is_cached() return value.    bool m_id_is_cached; // ata_identify_is_cached() return value.
  bool m_is_3ware; // AMCC/3ware controller detected?  bool m_is_3ware; // LSI/3ware controller detected?
  int m_drive, m_port;  int m_port; // LSI/3ware port
   int m_smartver_state;    int m_smartver_state;
 };  };
   
Line 408  class win_scsi_device (private) Line 396  class win_scsi_device (private)
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
   
 #if WIN9X_SUPPORT  
   
 class win_aspi_device  
 : public /*implements*/ scsi_device  
 {  
 public:  
   win_aspi_device(smart_interface * intf, const char * dev_name, const char * req_type);  
   
   virtual bool is_open() const;  
   
   virtual bool open();  
   
   virtual bool close();  
   
   virtual bool scsi_pass_through(scsi_cmnd_io * iop);  
   
 private:  
   int m_adapter;  
   unsigned char m_id;  
 };  
   
 #endif // WIN9X_SUPPORT  
   
   
 //////////////////////////////////////////////////////////////////////  
   
 class csmi_device  class csmi_device
 : virtual public /*extends*/ smart_device  : virtual public /*extends*/ smart_device
 {  {
Line 531  class win_tw_cli_device (private) Line 493  class win_tw_cli_device (private)
 };  };
   
   
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Platform specific interfaces/// Areca RAID support
   
// Common to all windows flavors///////////////////////////////////////////////////////////////////
class win_smart_interface// SATA(ATA) device behind Areca RAID Controller
: public /*implements part of*/ smart_interfaceclass win_areca_ata_device
 : public /*implements*/ areca_ata_device,
   public /*extends*/ win_smart_device
 {  {
 public:  public:
  virtual std::string get_os_version_str();  win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
   virtual bool open();
   virtual smart_device * autodetect_open();
   virtual bool arcmsr_lock();
   virtual bool arcmsr_unlock();
   virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
   
  virtual std::string get_app_examples(const char * appname);private:
  HANDLE m_mutex;
//virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, 
//  const char * pattern = 0); 
 
protected: 
  virtual ata_device * get_ata_device(const char * name, const char * type); 
 
//virtual scsi_device * get_scsi_device(const char * name, const char * type); 
 
  virtual smart_device * autodetect_smart_device(const char * name); 
 };  };
   
#if WIN9X_SUPPORT///////////////////////////////////////////////////////////////////
// SAS(SCSI) device behind Areca RAID Controller
// Win9x/ME reduced functionalityclass win_areca_scsi_device
class win9x_smart_interfacepublic /*implements*/ areca_scsi_device,
public /*extends*/ win_smart_interface  public /*extends*/ win_smart_device
 {  {
 public:  public:
  win9x_smart_interface()  win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
    { win9x = true; }  virtual bool open();
   virtual smart_device * autodetect_open();
   virtual bool arcmsr_lock();
   virtual bool arcmsr_unlock();
   virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
   
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,  
     const char * pattern = 0);  
   
 protected:  
   virtual scsi_device * get_scsi_device(const char * name, const char * type);  
   
 private:  private:
  bool ata_scan(smart_device_list & devlist);  HANDLE m_mutex;
 
  bool scsi_scan(smart_device_list & devlist); 
 };  };
   
 #endif // WIN9X_SUPPORT  
   
// WinNT,2000,XP,...//////////////////////////////////////////////////////////////////////
class winnt_smart_interface// Platform specific interface
: public /*extends*/ win_smart_interface
 class win_smart_interface
 : public /*implements part of*/ smart_interface
 {  {
 public:  public:
     virtual std::string get_os_version_str();
   
     virtual std::string get_app_examples(const char * appname);
   
   #ifndef __CYGWIN__
     virtual int64_t get_timer_usec();
   #endif
   
     virtual bool disable_system_auto_standby(bool disable);
   
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,    virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
     const char * pattern = 0);      const char * pattern = 0);
   
 protected:  protected:
     virtual ata_device * get_ata_device(const char * name, const char * type);
   
   virtual scsi_device * get_scsi_device(const char * name, const char * type);    virtual scsi_device * get_scsi_device(const char * name, const char * type);
   
   virtual smart_device * autodetect_smart_device(const char * name);    virtual smart_device * autodetect_smart_device(const char * name);
   
     virtual smart_device * get_custom_smart_device(const char * name, const char * type);
   
     virtual std::string get_valid_custom_dev_types_str();
 };  };
   
   
Line 631  std::string win_smart_interface::get_os_version_str() Line 604  std::string win_smart_interface::get_os_version_str()
       return vstr;        return vstr;
   }    }
   
  if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff)  const char * w = 0;
    return vstr;  if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
   
  const char * w;    if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
  switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) {      // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
    case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0:      // actual OS version, see:
      w = (vi.szCSDVersion[1] == 'B' ||      // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
           vi.szCSDVersion[1] == 'C'     ? "95-osr2" : "95");    break;
    case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10:      ULONGLONG major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
      w = (vi.szCSDVersion[1] == 'A'     ? "98se"    : "98");    break;      for (unsigned major = vi.dwMajorVersion; major <= 9; major++) {
    case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me";     break;        OSVERSIONINFOEXA vi2; memset(&vi2, 0, sizeof(vi2));
  //case VER_PLATFORM_WIN32_NT     <<16|0x0300|51: w = "nt3.51"; break;        vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
    case VER_PLATFORM_WIN32_NT     <<16|0x0400| 0: w = "nt4";    break;        if (!VerifyVersionInfo(&vi2, VER_MAJORVERSION, major_equal))
    case VER_PLATFORM_WIN32_NT     <<16|0x0500| 0: w = "2000";   break;          continue;
    case VER_PLATFORM_WIN32_NT     <<16|0x0500| 1:        if (vi.dwMajorVersion < major) {
      w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ?   "xp"          vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
                                                   :   "xp-mc"); break;        }
    case VER_PLATFORM_WIN32_NT     <<16|0x0500| 2:
      w = (!GetSystemMetrics(89/*SM_SERVERR2*/)    ?   "2003"        ULONGLONG minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
                                                   :   "2003r2"); break;        for (unsigned minor = vi.dwMinorVersion; minor <= 9; minor++) {
    case VER_PLATFORM_WIN32_NT     <<16|0x0600| 0:          memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
      w = (vi.wProductType == VER_NT_WORKSTATION   ?   "vista"          vi2.dwMinorVersion = minor;
                                                   :   "2008" );  break;          if (!VerifyVersionInfo(&vi2, VER_MINORVERSION, minor_equal))
    case VER_PLATFORM_WIN32_NT     <<16|0x0600| 1:            continue;
      w = (vi.wProductType == VER_NT_WORKSTATION   ?   "win7"          vi.dwMinorVersion = minor;
                                                   :   "2008r2"); break;          break;
    default: w = 0; break;        }
 
         break;
       }
     }
 
     if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
       bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
       switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
         case 0x50: w =       "2000";              break;
         case 0x51: w =       "xp";                break;
         case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
                            ? "2003"  : "2003r2"); break;
         case 0x60: w = (ws ? "vista" : "2008"  ); break;
         case 0x61: w = (ws ? "win7"  : "2008r2"); break;
         case 0x62: w = (ws ? "win8"  : "2012"  ); break;
         case 0x63: w = (ws ? "win8.1": "2012r2"); break;
       }
     }
   }    }
   
   const char * w64 = "";    const char * w64 = "";
Line 667  std::string win_smart_interface::get_os_version_str() Line 658  std::string win_smart_interface::get_os_version_str()
 #endif  #endif
   
   if (!w)    if (!w)
    snprintf(vptr, vlen, "-%s%lu.%lu%s",    snprintf(vptr, vlen, "-%s%u.%u%s",
      (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"),      (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"),
      vi.dwMajorVersion, vi.dwMinorVersion, w64);      (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
   else if (vi.wServicePackMinor)    else if (vi.wServicePackMinor)
     snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);      snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
   else if (vi.wServicePackMajor)    else if (vi.wServicePackMajor)
Line 679  std::string win_smart_interface::get_os_version_str() Line 670  std::string win_smart_interface::get_os_version_str()
   return vstr;    return vstr;
 }  }
   
   #ifndef __CYGWIN__
   // MSVCRT only provides ftime() which uses GetSystemTime()
   // This provides only ~15ms resolution by default.
   // Use QueryPerformanceCounter instead (~300ns).
   // (Cygwin provides CLOCK_MONOTONIC which has the same effect)
   int64_t win_smart_interface::get_timer_usec()
   {
     static int64_t freq = 0;
   
     LARGE_INTEGER t;
     if (freq == 0)
       freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1);
     if (freq <= 0)
       return smart_interface::get_timer_usec();
   
     if (!QueryPerformanceCounter(&t))
       return -1;
     if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000))
       return -1;
   
     return (t.QuadPart * 1000000LL) / freq;
   }
   #endif // __CYGWIN__
   
   
 // Return value for device detection functions  // Return value for device detection functions
 enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };  enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB };
   
Line 729  ata_device * win_smart_interface::get_ata_device(const Line 745  ata_device * win_smart_interface::get_ata_device(const
   return new win_ata_device(this, name, type);    return new win_ata_device(this, name, type);
 }  }
   
#ifdef WIN9X_SUPPORTscsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type)
 
scsi_device * win9x_smart_interface::get_scsi_device(const char * name, const char * type) 
 {  {
  return new win_aspi_device(this, name, type);  return new win_scsi_device(this, name, type);
 }  }
   
#endifstatic int sdxy_to_phydrive(const char (& xy)[2+1])
 
scsi_device * winnt_smart_interface::get_scsi_device(const char * name, const char * type) 
 {  {
  const char * testname = skipdev(name);  int phydrive = xy[0] - 'a';
  if (!strncmp(testname, "scsi", 4))  if (xy[1])
#if WIN9X_SUPPORT    phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a');
    return new win_aspi_device(this, name, type);  return phydrive;
#else 
    return (set_err(EINVAL, "ASPI interface not supported"), (scsi_device *)0); 
#endif 
  return new win_scsi_device(this, name, type); 
 }  }
   
 static win_dev_type get_dev_type(const char * name, int & phydrive)  static win_dev_type get_dev_type(const char * name, int & phydrive)
Line 767  static win_dev_type get_dev_type(const char * name, in Line 775  static win_dev_type get_dev_type(const char * name, in
     return (type != DEV_UNKNOWN ? type : DEV_SCSI);      return (type != DEV_UNKNOWN ? type : DEV_SCSI);
   }    }
   
  char drive[1+1] = "";  char drive[2+1] = "";
  if (sscanf(name, "sd%1[a-z]", drive) == 1) {  if (sscanf(name, "sd%2[a-z]", drive) == 1) {
    phydrive = drive[0] - 'a';    phydrive = sdxy_to_phydrive(drive);
     return get_phy_drive_type(phydrive);      return get_phy_drive_type(phydrive);
   }    }
   
Line 779  static win_dev_type get_dev_type(const char * name, in Line 787  static win_dev_type get_dev_type(const char * name, in
   return DEV_UNKNOWN;    return DEV_UNKNOWN;
 }  }
   
smart_device * win_smart_interface::autodetect_smart_device(const char * name)smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type)
 {  {
  const char * testname = skipdev(name);  // Areca?
  if (!strncmp(testname, "hd", 2))  int disknum = -1, n1 = -1, n2 = -1;
    return new win_ata_device(this, name, "");  int encnum = 1;
#if WIN9X_SUPPORT  char devpath[32];
  if (!strncmp(testname, "scsi", 4))
    return new win_aspi_device(this, name, "");  if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
#endif    if (!(1 <= disknum && disknum <= 128)) {
  if (!strncmp(testname, "tw_cli", 6))      set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
    return new win_tw_cli_device(this, name, "");      return 0;
     }
     if (!(1 <= encnum && encnum <= 8)) {
       set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
       return 0;
     }
 
     name = skipdev(name);
 #define ARECA_MAX_CTLR_NUM  16
     n1 = -1;
     int ctlrindex = 0;
     if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) {
       /*
        1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and
        2. map arcmsrX into "\\\\.\\scsiX"
       */
      for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
         memset(devpath, 0, sizeof(devpath));
         snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx);
         win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum);
         if(arcdev->arcmsr_probe()) {
           if(ctlrindex-- == 0) {
             return arcdev;
           }
         }
         delete arcdev;
       }
       set_err(ENOENT, "No Areca controller found");
     }
     else
       set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX");
   }
 
   return 0;    return 0;
 }  }
   
smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)std::string win_smart_interface::get_valid_custom_dev_types_str()
 {  {
  smart_device * dev = win_smart_interface::autodetect_smart_device(name);  return "areca,N[/E]";
  if (dev)}
    return dev; 
   
  if (!strncmp(skipdev(name), "csmi", 4))
 smart_device * win_smart_interface::autodetect_smart_device(const char * name)
 {
   const char * testname = skipdev(name);
   if (str_starts_with(testname, "hd"))
     return new win_ata_device(this, name, "");
 
   if (str_starts_with(testname, "tw_cli"))
     return new win_tw_cli_device(this, name, "");
 
   if (str_starts_with(testname, "csmi"))
     return new win_csmi_device(this, name, "");      return new win_csmi_device(this, name, "");
   
   int phydrive = -1;    int phydrive = -1;
Line 829  smart_device * winnt_smart_interface::autodetect_smart Line 878  smart_device * winnt_smart_interface::autodetect_smart
 }  }
   
   
#if WIN9X_SUPPORT// Scan for devices
   
// Scan for devices on Win9x/MEbool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
 
bool win9x_smart_interface::scan_smart_devices(smart_device_list & devlist, 
   const char * type, const char * pattern /* = 0*/)    const char * type, const char * pattern /* = 0*/)
 {  {
   if (pattern) {    if (pattern) {
Line 841  bool win9x_smart_interface::scan_smart_devices(smart_d Line 888  bool win9x_smart_interface::scan_smart_devices(smart_d
     return false;      return false;
   }    }
   
  if (!type || !strcmp(type, "ata")) {  // Check for "[*,]pd" type
    if (!ata_scan(devlist))  bool pd = false;
      return false;  char type2[16+1] = "";
   if (type) {
     int nc = -1;
     if (!strcmp(type, "pd")) {
       pd = true;
       type = 0;
     }
     else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 &&
              nc == (int)strlen(type)) {
       pd = true;
       type = type2;
     }
   }    }
   
   if (!type || !strcmp(type, "scsi")) {  
     if (!scsi_scan(devlist))  
       return false;  
   }  
   return true;  
 }  
   
 #endif  // WIN9X_SUPPORT  
   
   
 // Scan for devices  
   
 bool winnt_smart_interface::scan_smart_devices(smart_device_list & devlist,  
   const char * type, const char * pattern /* = 0*/)  
 {  
   if (pattern) {  
     set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");  
     return false;  
   }  
   
   // Set valid types    // Set valid types
   bool ata, scsi, usb, csmi;    bool ata, scsi, usb, csmi;
   if (!type) {    if (!type) {
Line 882  bool winnt_smart_interface::scan_smart_devices(smart_d Line 920  bool winnt_smart_interface::scan_smart_devices(smart_d
     else if (!strcmp(type, "csmi"))      else if (!strcmp(type, "csmi"))
       csmi = true;        csmi = true;
     else {      else {
      set_err(EINVAL, "Invalid type '%s', valid arguments are: ata, scsi, usb, csmi", type);      set_err(EINVAL, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type);
       return false;        return false;
     }      }
   }    }
   
   // Scan up to 10 drives and 2 3ware controllers  
   const int max_raid = 2;  
   bool raid_seen[max_raid] = {false, false};  
   
   char name[20];    char name[20];
   for (int i = 0; i <= 9; i++) {  
     sprintf(name, "/dev/sd%c", 'a'+i);  
     GETVERSIONINPARAMS_EX vers_ex;  
   
    switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {  if (ata || scsi || usb) {
      case DEV_ATA:    // Scan up to 128 drives and 2 3ware controllers
        // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA    const int max_raid = 2;
        if (!ata)    bool raid_seen[max_raid] = {false, false};
          continue; 
   
        // Interpret RAID drive map if present    for (int i = 0; i < 128; i++) {
        if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {      if (pd)
          // Skip if too many controllers or logical drive from this controller already seen        snprintf(name, sizeof(name), "/dev/pd%d", i);
          if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))      else if (i + 'a' <= 'z')
         snprintf(name, sizeof(name), "/dev/sd%c", i + 'a');
       else
         snprintf(name, sizeof(name), "/dev/sd%c%c",
                  i / ('z'-'a'+1) - 1 + 'a',
                  i % ('z'-'a'+1)     + 'a');
 
       GETVERSIONINPARAMS_EX vers_ex;
 
       switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) {
         case DEV_ATA:
           // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
           if (!ata)
             continue;              continue;
          raid_seen[vers_ex.wControllerId] = true;
          // Add physical drives          // Interpret RAID drive map if present
          int len = strlen(name);          if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
          for (int pi = 0; pi < 32; pi++) {            // Skip if too many controllers or logical drive from this controller already seen
            if (vers_ex.dwDeviceMapEx & (1L << pi)) {            if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
              sprintf(name+len, ",%u", pi);              continue;
              devlist.push_back( new win_ata_device(this, name, "ata") );            raid_seen[vers_ex.wControllerId] = true;
             // Add physical drives
             int len = strlen(name);
             for (int pi = 0; pi < 32; pi++) {
               if (vers_ex.dwDeviceMapEx & (1L << pi)) {
                 snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
                 devlist.push_back( new win_ata_device(this, name, "ata") );
               }
             }              }
           }            }
        }          else {
        else {            devlist.push_back( new win_ata_device(this, name, "ata") );
          devlist.push_back( new win_ata_device(this, name, "ata") );          }
        }          break;
        break; 
   
      case DEV_SCSI:        case DEV_SCSI:
        // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...          // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
        if (!scsi)          if (!scsi)
          continue;            continue;
        devlist.push_back( new win_scsi_device(this, name, "scsi") );          devlist.push_back( new win_scsi_device(this, name, "scsi") );
        break;          break;
   
      case DEV_USB:        case DEV_USB:
        // STORAGE_QUERY_PROPERTY returned USB          // STORAGE_QUERY_PROPERTY returned USB
        if (!usb)          if (!usb)
          continue; 
        { 
          // TODO: Use common function for this and autodetect_smart_device() 
          // Get USB bridge ID 
          unsigned short vendor_id = 0, product_id = 0; 
          if (!get_usb_id(i, vendor_id, product_id)) 
             continue;              continue;
          // Get type name for this ID          {
          const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);            // TODO: Use common function for this and autodetect_smart_device()
          if (!usbtype)            // Get USB bridge ID
            continue;            unsigned short vendor_id = 0, product_id = 0;
          // Return SAT/USB device for this type            if (!get_usb_id(i, vendor_id, product_id))
          ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));              continue;
          if (!dev)            // Get type name for this ID
            continue;            const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
          devlist.push_back(dev);            if (!usbtype)
        }              continue;
        break;            // Return SAT/USB device for this type
             ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
             if (!dev)
               continue;
             devlist.push_back(dev);
           }
           break;
   
      default:        default:
        // Unknown type          // Unknown type
        break;          break;
       }
     }      }
   }    }
   
Line 986  std::string win_smart_interface::get_app_examples(cons Line 1035  std::string win_smart_interface::get_app_examples(cons
   if (strcmp(appname, "smartctl"))    if (strcmp(appname, "smartctl"))
     return "";      return "";
   return "=================================================== SMARTCTL EXAMPLES =====\n\n"    return "=================================================== SMARTCTL EXAMPLES =====\n\n"
         "  smartctl -a /dev/hda                       (Prints all SMART information)\n\n"         "  smartctl -a /dev/sda                       (Prints all SMART information)\n\n"
         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
          "                                              (Enables SMART on first disk)\n\n"           "                                              (Enables SMART on first disk)\n\n"
         "  smartctl -t long /dev/hda              (Executes extended disk self-test)\n\n"         "  smartctl -t long /dev/sda              (Executes extended disk self-test)\n\n"
         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n"
          "                                      (Prints Self-Test & Attribute errors)\n"           "                                      (Prints Self-Test & Attribute errors)\n"
 #if WIN9X_SUPPORT  
          "  smartctl -a /dev/scsi21\n"  
          "             (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n"  
 #endif  
          "  smartctl -a /dev/sda\n"           "  smartctl -a /dev/sda\n"
         "             (Prints all information for SCSI disk on PhysicalDrive 0)\n"         "             (Prints all information for disk on PhysicalDrive 0)\n"
          "  smartctl -a /dev/pd3\n"           "  smartctl -a /dev/pd3\n"
         "             (Prints all information for SCSI disk on PhysicalDrive 3)\n"         "             (Prints all information for disk on PhysicalDrive 3)\n"
          "  smartctl -a /dev/tape1\n"           "  smartctl -a /dev/tape1\n"
          "             (Prints all information for SCSI tape on Tape 1)\n"           "             (Prints all information for SCSI tape on Tape 1)\n"
          "  smartctl -A /dev/hdb,3\n"           "  smartctl -A /dev/hdb,3\n"
          "                (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"           "                (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n"
          "  smartctl -A /dev/tw_cli/c0/p1\n"           "  smartctl -A /dev/tw_cli/c0/p1\n"
          "            (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"           "            (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n"
            "  smartctl --all --device=areca,3/1 /dev/arcmsr0\n"
            "           (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n"
            "            on 1st Areca RAID controller)\n"
          "\n"           "\n"
          "  ATA SMART access methods and ordering may be specified by modifiers\n"           "  ATA SMART access methods and ordering may be specified by modifiers\n"
          "  following the device name: /dev/hdX:[saicm], where\n"           "  following the device name: /dev/hdX:[saicm], where\n"
          "  's': SMART_* IOCTLs,         'a': IOCTL_ATA_PASS_THROUGH,\n"           "  's': SMART_* IOCTLs,         'a': IOCTL_ATA_PASS_THROUGH,\n"
         "  'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"         "  'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
         "  'f': IOCTL_STORAGE_*,        'm': IOCTL_SCSI_MINIPORT_*.\n"         "  'm': IOCTL_SCSI_MINIPORT_*.\n"
       + strprintf(        + strprintf(
          "  The default on this system is /dev/sdX:%s\n", ata_get_def_options()           "  The default on this system is /dev/sdX:%s\n", ata_get_def_options()
         );          );
 }  }
   
   
   bool win_smart_interface::disable_system_auto_standby(bool disable)
   {
     if (disable) {
       SYSTEM_POWER_STATUS ps;
       if (!GetSystemPowerStatus(&ps))
         return set_err(ENOSYS, "Unknown power status");
       if (ps.ACLineStatus != 1) {
         SetThreadExecutionState(ES_CONTINUOUS);
         if (ps.ACLineStatus == 0)
           set_err(EIO, "AC offline");
         else
           set_err(EIO, "Unknown AC line status");
         return false;
       }
     }
   
     if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0)))
       return set_err(ENOSYS);
     return true;
   }
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 // ATA Interface  // ATA Interface
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
Line 1028  std::string win_smart_interface::get_app_examples(cons Line 1098  std::string win_smart_interface::get_app_examples(cons
 static void print_ide_regs(const IDEREGS * r, int out)  static void print_ide_regs(const IDEREGS * r, int out)
 {  {
   pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",    pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n",
  (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,    (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
  r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);    r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
 }  }
   
 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)  static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
Line 1053  static int smart_get_version(HANDLE hdevice, GETVERSIO Line 1123  static int smart_get_version(HANDLE hdevice, GETVERSIO
   if (!DeviceIoControl(hdevice, SMART_GET_VERSION,    if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
     NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {      NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
     if (ata_debugmode)      if (ata_debugmode)
      pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());      pout("  SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
     errno = ENOSYS;      errno = ENOSYS;
     return -1;      return -1;
   }    }
   assert(num_out == sizeof(GETVERSIONINPARAMS));    assert(num_out == sizeof(GETVERSIONINPARAMS));
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  SMART_GET_VERSION suceeded, bytes returned: %lu\n"    pout("  SMART_GET_VERSION suceeded, bytes returned: %u\n"
         "    Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",         "    Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
      num_out, vers.bVersion, vers.bRevision,      (unsigned)num_out, vers.bVersion, vers.bRevision,
      vers.fCapabilities, vers.bIDEDeviceMap);      (unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
     if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)      if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
      pout("    Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",      pout("    Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
      vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);      vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx);
   }    }
   
   if (ata_version_ex)    if (ata_version_ex)
Line 1079  static int smart_get_version(HANDLE hdevice, GETVERSIO Line 1149  static int smart_get_version(HANDLE hdevice, GETVERSIO
   
 // call SMART_* ioctl  // call SMART_* ioctl
   
static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port)static int smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize, int port)
 {  {
   SENDCMDINPARAMS inpar;    SENDCMDINPARAMS inpar;
   SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;    SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
Line 1092  static int smart_ioctl(HANDLE hdevice, int drive, IDER Line 1162  static int smart_ioctl(HANDLE hdevice, int drive, IDER
   
   memset(&inpar, 0, sizeof(inpar));    memset(&inpar, 0, sizeof(inpar));
   inpar.irDriveRegs = *regs;    inpar.irDriveRegs = *regs;
   // drive is set to 0-3 on Win9x only  
   inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4);  
   inpar.bDriveNumber = drive;  
   
     // Older drivers may require bits 5 and 7 set
     // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete
     inpar.irDriveRegs.bDriveHeadReg |= 0xa0;
   
     // Drive number 0-3 was required on Win9x/ME only
     //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4;
     //inpar.bDriveNumber = drive;
   
   if (port >= 0) {    if (port >= 0) {
     // Set RAID port      // Set RAID port
     inpar_ex.wIdentifier = SMART_VENDOR_3WARE;      inpar_ex.wIdentifier = SMART_VENDOR_3WARE;
Line 1123  static int smart_ioctl(HANDLE hdevice, int drive, IDER Line 1198  static int smart_ioctl(HANDLE hdevice, int drive, IDER
   
   if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,    if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
     outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {      outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) {
    // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface()    // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through()
     long err = GetLastError();      long err = GetLastError();
     if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {      if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
       pout("  %s failed, Error=%ld\n", name, err);        pout("  %s failed, Error=%ld\n", name, err);
Line 1149  static int smart_ioctl(HANDLE hdevice, int drive, IDER Line 1224  static int smart_ioctl(HANDLE hdevice, int drive, IDER
   }    }
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  %s suceeded, bytes returned: %lu (buffer %lu)\n", name,    pout("  %s suceeded, bytes returned: %u (buffer %u)\n", name,
      num_out, outpar->cBufferSize);      (unsigned)num_out, (unsigned)outpar->cBufferSize);
     print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?      print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
       (const IDEREGS *)(outpar->bBuffer) : NULL));        (const IDEREGS *)(outpar->bBuffer) : NULL));
   }    }
Line 1226  static int ide_pass_through_ioctl(HANDLE hdevice, IDER Line 1301  static int ide_pass_through_ioctl(HANDLE hdevice, IDER
     if (   num_out != size      if (   num_out != size
         || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {          || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
       if (ata_debugmode) {        if (ata_debugmode) {
        pout("  IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",        pout("  IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
          num_out, buf->DataBufferSize);          (unsigned)num_out, (unsigned)buf->DataBufferSize);
         print_ide_regs_io(regs, &buf->IdeReg);          print_ide_regs_io(regs, &buf->IdeReg);
       }        }
       VirtualFree(buf, 0, MEM_RELEASE);        VirtualFree(buf, 0, MEM_RELEASE);
Line 1238  static int ide_pass_through_ioctl(HANDLE hdevice, IDER Line 1313  static int ide_pass_through_ioctl(HANDLE hdevice, IDER
   }    }
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",    pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
      num_out, buf->DataBufferSize);      (unsigned)num_out, (unsigned)buf->DataBufferSize);
     print_ide_regs_io(regs, &buf->IdeReg);      print_ide_regs_io(regs, &buf->IdeReg);
   }    }
   *regs = buf->IdeReg;    *regs = buf->IdeReg;
Line 1345  static int ata_pass_through_ioctl(HANDLE hdevice, IDER Line 1420  static int ata_pass_through_ioctl(HANDLE hdevice, IDER
     if (   num_out != size      if (   num_out != size
         || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {          || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
       if (ata_debugmode) {        if (ata_debugmode) {
        pout("  IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out);        pout("  IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out);
         print_ide_regs_io(regs, ctfregs);          print_ide_regs_io(regs, ctfregs);
       }        }
       errno = EIO;        errno = EIO;
Line 1355  static int ata_pass_through_ioctl(HANDLE hdevice, IDER Line 1430  static int ata_pass_through_ioctl(HANDLE hdevice, IDER
   }    }
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);    pout("  IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out);
     print_ide_regs_io(regs, ctfregs);      print_ide_regs_io(regs, ctfregs);
   }    }
   *regs = *ctfregs;    *regs = *ctfregs;
Line 1367  static int ata_pass_through_ioctl(HANDLE hdevice, IDER Line 1442  static int ata_pass_through_ioctl(HANDLE hdevice, IDER
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 // ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)  
   
 // undocumented SCSI opcode to for ATA passthrough  
 #define SCSIOP_ATA_PASSTHROUGH    0xCC  
   
 static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize)  
 {  
   typedef struct {  
     SCSI_PASS_THROUGH spt;  
     ULONG Filler;  
     UCHAR ucSenseBuf[32];  
     UCHAR ucDataBuf[512];  
   } SCSI_PASS_THROUGH_WITH_BUFFERS;  
   
   SCSI_PASS_THROUGH_WITH_BUFFERS sb;  
   IDEREGS * cdbregs;  
   unsigned int size;  
   DWORD num_out;  
   const unsigned char magic = 0xcf;  
   
   memset(&sb, 0, sizeof(sb));  
   sb.spt.Length = sizeof(SCSI_PASS_THROUGH);  
   //sb.spt.PathId = 0;  
   sb.spt.TargetId = 1;  
   //sb.spt.Lun = 0;  
   sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24;  
   sb.spt.TimeOutValue = 10;  
   sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf);  
   size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);  
   sb.spt.DataBufferOffset = size;  
   
   if (datasize) {  
     if (datasize > sizeof(sb.ucDataBuf)) {  
       errno = EINVAL;  
       return -1;  
     }  
     sb.spt.DataIn = SCSI_IOCTL_DATA_IN;  
     sb.spt.DataTransferLength = datasize;  
     size += datasize;  
     sb.ucDataBuf[0] = magic;  
   }  
   else {  
     sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;  
     //sb.spt.DataTransferLength = 0;  
   }  
   
   // Use pseudo SCSI command followed by registers  
   sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH;  
   cdbregs = (IDEREGS *)(sb.spt.Cdb+2);  
   *cdbregs = *regs;  
   
   if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH,  
     &sb, size, &sb, size, &num_out, NULL)) {  
     long err = GetLastError();  
     if (ata_debugmode)  
       pout("  ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err);  
     errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO);  
     return -1;  
   }  
   
   // Cannot check ATA status, because command does not return IDEREGS  
   
   // Check and copy data  
   if (datasize) {  
     if (   num_out != size  
         || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) {  
       if (ata_debugmode) {  
         pout("  ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out);  
         print_ide_regs_io(regs, NULL);  
       }  
       errno = EIO;  
       return -1;  
     }  
     memcpy(data, sb.ucDataBuf, datasize);  
   }  
   
   if (ata_debugmode > 1) {  
     pout("  ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out);  
     print_ide_regs_io(regs, NULL);  
   }  
   return 0;  
 }  
   
   
 /////////////////////////////////////////////////////////////////////////////  
 // SMART IOCTL via SCSI MINIPORT ioctl  // SMART IOCTL via SCSI MINIPORT ioctl
   
 // This function is handled by ATAPI port driver (atapi.sys) or by SCSI  // This function is handled by ATAPI port driver (atapi.sys) or by SCSI
Line 1553  static int ata_via_scsi_miniport_smart_ioctl(HANDLE hd Line 1543  static int ata_via_scsi_miniport_smart_ioctl(HANDLE hd
   // Check result    // Check result
   if (sb.srbc.ReturnCode) {    if (sb.srbc.ReturnCode) {
     if (ata_debugmode) {      if (ata_debugmode) {
      pout("  IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode);      pout("  IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (unsigned)sb.srbc.ReturnCode);
       print_ide_regs_io(regs, NULL);        print_ide_regs_io(regs, NULL);
     }      }
     errno = EIO;      errno = EIO;
Line 1571  static int ata_via_scsi_miniport_smart_ioctl(HANDLE hd Line 1561  static int ata_via_scsi_miniport_smart_ioctl(HANDLE hd
   }    }
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,    pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name,
      num_out, sb.params.out.cBufferSize);      (unsigned)num_out, (unsigned)sb.params.out.cBufferSize);
     print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?      print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
                              (const IDEREGS *)(sb.params.out.bBuffer) : 0));                               (const IDEREGS *)(sb.params.out.bBuffer) : 0));
   }    }
Line 1604  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice Line 1594  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
     return -1;      return -1;
   }    }
   memset(&sb, 0, sizeof(sb));    memset(&sb, 0, sizeof(sb));
  strcpy((char *)sb.srbc.Signature, "<3ware>");  strncpy((char *)sb.srbc.Signature, "<3ware>", sizeof(sb.srbc.Signature));
   sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);    sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
   sb.srbc.Timeout = 60; // seconds    sb.srbc.Timeout = 60; // seconds
   sb.srbc.ControlCode = 0xA0000000;    sb.srbc.ControlCode = 0xA0000000;
Line 1627  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice Line 1617  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
   
   if (sb.srbc.ReturnCode) {    if (sb.srbc.ReturnCode) {
     if (ata_debugmode) {      if (ata_debugmode) {
      pout("  ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", sb.srbc.ReturnCode);      pout("  ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb.srbc.ReturnCode);
       print_ide_regs_io(regs, NULL);        print_ide_regs_io(regs, NULL);
     }      }
     errno = EIO;      errno = EIO;
Line 1639  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice Line 1629  static int ata_via_3ware_miniport_ioctl(HANDLE hdevice
     memcpy(data, sb.buffer, datasize);      memcpy(data, sb.buffer, datasize);
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
    pout("  ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %lu\n", num_out);    pout("  ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out);
     print_ide_regs_io(regs, &sb.regs);      print_ide_regs_io(regs, &sb.regs);
   }    }
   *regs = sb.regs;    *regs = sb.regs;
Line 1657  static int update_3ware_devicemap_ioctl(HANDLE hdevice Line 1647  static int update_3ware_devicemap_ioctl(HANDLE hdevice
 {  {
   SRB_IO_CONTROL srbc;    SRB_IO_CONTROL srbc;
   memset(&srbc, 0, sizeof(srbc));    memset(&srbc, 0, sizeof(srbc));
  strcpy((char *)srbc.Signature, "<3ware>");  strncpy((char *)srbc.Signature, "<3ware>", sizeof(srbc.Signature));
   srbc.HeaderLength = sizeof(SRB_IO_CONTROL);    srbc.HeaderLength = sizeof(SRB_IO_CONTROL);
   srbc.Timeout = 60; // seconds    srbc.Timeout = 60; // seconds
   srbc.ControlCode = 0xCC010014;    srbc.ControlCode = 0xCC010014;
Line 1675  static int update_3ware_devicemap_ioctl(HANDLE hdevice Line 1665  static int update_3ware_devicemap_ioctl(HANDLE hdevice
   }    }
   if (srbc.ReturnCode) {    if (srbc.ReturnCode) {
     if (ata_debugmode)      if (ata_debugmode)
      pout("  UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08lx\n", srbc.ReturnCode);      pout("  UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc.ReturnCode);
     errno = EIO;      errno = EIO;
     return -1;      return -1;
   }    }
Line 1898  bool win_tw_cli_device::open() Line 1888  bool win_tw_cli_device::open()
         // Show tw_cli error message          // Show tw_cli error message
         err++;          err++;
         err[strcspn(err, "\r\n")] = 0;          err[strcspn(err, "\r\n")] = 0;
        return set_err(EIO, err);        return set_err(EIO, "%s", err);
       }        }
       return set_err(EIO);        return set_err(EIO);
     }      }
Line 1964  static int storage_query_property_ioctl(HANDLE hdevice Line 1954  static int storage_query_property_ioctl(HANDLE hdevice
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,    if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
     &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {      &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
     if (ata_debugmode > 1 || scsi_debugmode > 1)      if (ata_debugmode > 1 || scsi_debugmode > 1)
      pout("  IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError());      pout("  IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError());
     errno = ENOSYS;      errno = ENOSYS;
     return -1;      return -1;
   }    }
Line 2002  static int storage_predict_failure_ioctl(HANDLE hdevic Line 1992  static int storage_predict_failure_ioctl(HANDLE hdevic
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,    if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
     0, 0, &pred, sizeof(pred), &num_out, NULL)) {      0, 0, &pred, sizeof(pred), &num_out, NULL)) {
     if (ata_debugmode > 1)      if (ata_debugmode > 1)
      pout("  IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError());      pout("  IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError());
     errno = ENOSYS;      errno = ENOSYS;
     return -1;      return -1;
   }    }
   
   if (ata_debugmode > 1) {    if (ata_debugmode > 1) {
     pout("  IOCTL_STORAGE_PREDICT_FAILURE returns:\n"      pout("  IOCTL_STORAGE_PREDICT_FAILURE returns:\n"
         "    PredictFailure: 0x%08lx\n"         "    PredictFailure: 0x%08x\n"
          "    VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",           "    VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n",
         pred.PredictFailure,         (unsigned)pred.PredictFailure,
          pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],           pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
          pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]           pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
     );      );
Line 2159  static int get_identify_from_device_property(HANDLE hd Line 2149  static int get_identify_from_device_property(HANDLE hd
   return 0;    return 0;
 }  }
   
   // Get Serial Number in IDENTIFY from WMI
   static bool get_serial_from_wmi(int drive, ata_identify_device * id)
   {
     bool debug = (ata_debugmode > 1);
   
/////////////////////////////////////////////////////////////////////////////  wbem_services ws;
// USB ID detection using WMI  if (!ws.connect()) {
     if (debug)
       pout("WMI connect failed\n");
     return false;
   }
   
// Return true if STR starts with PREFIX.  wbem_object wo;
static inline bool str_starts_with(const std::string & str, const char * prefix)  if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
{                     "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
  return !strncmp(str.c_str(), prefix, strlen(prefix));    return false;
 
   std::string serial = wo.get_str("SerialNumber");
   if (debug)
     pout("  WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str("Model").c_str(), serial.c_str());
 
   copy_swapped(id->serial_no, serial.c_str(), sizeof(id->serial_no));
   return true;
 }  }
   
   
   /////////////////////////////////////////////////////////////////////////////
   // USB ID detection using WMI
   
 // Get USB ID for a physical drive number  // Get USB ID for a physical drive number
 static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)  static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
 {  {
Line 2251  static bool get_usb_id(int drive, unsigned short & ven Line 2260  static bool get_usb_id(int drive, unsigned short & ven
         continue;          continue;
       }        }
   
      // Fail if previos USB bridge is associated to other controller or ID is unknown      // Fail if previous USB bridge is associated to other controller or ID is unknown
       if (!(ant == prev_usb_ant && prev_usb_venid)) {        if (!(ant == prev_usb_ant && prev_usb_venid)) {
         if (debug)          if (debug)
           pout("  +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());            pout("  +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
Line 2294  static bool get_usb_id(int drive, unsigned short & ven Line 2303  static bool get_usb_id(int drive, unsigned short & ven
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
   
// Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)// Call GetDevicePowerState()
 // returns: 1=active, 0=standby, -1=error  // returns: 1=active, 0=standby, -1=error
 // (This would also work for SCSI drives)  // (This would also work for SCSI drives)
   
 static int get_device_power_state(HANDLE hdevice)  static int get_device_power_state(HANDLE hdevice)
 {  {
   static bool unsupported = false;  
   if (unsupported) {  
     errno = ENOSYS;  
     return -1;  
   }  
   
 #ifdef __CYGWIN__  
   static DWORD kernel_dll_pid = 0;  
 #endif  
   static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0;  
   
   if (!GetDevicePowerState_p  
 #ifdef __CYGWIN__  
       || kernel_dll_pid != GetCurrentProcessId() // detect fork()  
 #endif  
      ) {  
     if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *))  
           GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDevicePowerState"))) {  
       if (ata_debugmode)  
         pout("  GetDevicePowerState() not found, Error=%ld\n", GetLastError());  
       unsupported = true;  
       errno = ENOSYS;  
       return -1;  
     }  
 #ifdef __CYGWIN__  
     kernel_dll_pid = GetCurrentProcessId();  
 #endif  
   }  
   
   BOOL state = TRUE;    BOOL state = TRUE;
  if (!GetDevicePowerState_p(hdevice, &state)) {  if (!GetDevicePowerState(hdevice, &state)) {
     long err = GetLastError();      long err = GetLastError();
     if (ata_debugmode)      if (ata_debugmode)
       pout("  GetDevicePowerState() failed, Error=%ld\n", err);        pout("  GetDevicePowerState() failed, Error=%ld\n", err);
Line 2348  static int get_device_power_state(HANDLE hdevice) Line 2328  static int get_device_power_state(HANDLE hdevice)
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
   
 #if WIN9X_SUPPORT  
 // Print SMARTVSD error message, return errno  
   
 static int smartvsd_error()  
 {  
   char path[MAX_PATH];  
   unsigned len;  
   if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2))  
     return ENOENT;  
   // SMARTVSD.VXD present?  
   strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD");  
   if (!access(path, 0)) {  
     // Yes, standard IDE driver used?  
     HANDLE h;  
     if (   (h = CreateFileA("\\\\.\\ESDI_506",  
                  GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,  
                  NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE  
         && GetLastError() == ERROR_FILE_NOT_FOUND                             ) {  
       pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n");  
       return ENOENT;  
     }  
     else {  
       if (h != INVALID_HANDLE_VALUE) // should not happen  
         CloseHandle(h);  
       pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n");  
       return ENOSYS;  
     }  
   }  
   else {  
     strcpy(path+len, "\\SMARTVSD.VXD");  
     if (!access(path, 0)) {  
       // Some Windows versions install SMARTVSD.VXD in SYSTEM directory  
       // (http://support.microsoft.com/kb/265854/en-us).  
       path[len] = 0;  
       pout("SMART driver is not properly installed,\n"  
          " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n"  
          " and reboot Windows.\n", path, path);  
     }  
     else {  
       // Some Windows versions do not provide SMARTVSD.VXD  
       // (http://support.microsoft.com/kb/199886/en-us).  
       path[len] = 0;  
       pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path);  
     }  
     return ENOSYS;  
   }  
 }  
   
 #endif // WIN9X_SUPPORT  
   
 // Get default ATA device options  // Get default ATA device options
   
 static const char * ata_get_def_options()  static const char * ata_get_def_options()
 {  {
  DWORD ver = GetVersion();  return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
  if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME                   // STORAGE_*, SCSI_MINIPORT_*
    return "s"; // SMART_* only 
  else if ((ver & 0xff) == 4) // WinNT4 
    return "sc"; // SMART_*, SCSI_PASS_THROUGH 
  else // WinXP, 2003, Vista 
    return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH, 
                     // STORAGE_*, SCSI_MINIPORT_* 
 }  }
   
   
Line 2441  win_ata_device::win_ata_device(smart_interface * intf, Line 2365  win_ata_device::win_ata_device(smart_interface * intf,
 : smart_device(intf, dev_name, "ata", req_type),  : smart_device(intf, dev_name, "ata", req_type),
   m_usr_options(false),    m_usr_options(false),
   m_admin(false),    m_admin(false),
     m_phydrive(-1),
   m_id_is_cached(false),    m_id_is_cached(false),
   m_is_3ware(false),    m_is_3ware(false),
   m_drive(0),  
   m_port(-1),    m_port(-1),
   m_smartver_state(0)    m_smartver_state(0)
 {  {
Line 2459  win_ata_device::~win_ata_device() throw() Line 2383  win_ata_device::~win_ata_device() throw()
 bool win_ata_device::open()  bool win_ata_device::open()
 {  {
   const char * name = skipdev(get_dev_name()); int len = strlen(name);    const char * name = skipdev(get_dev_name()); int len = strlen(name);
  // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options  // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
  char drive[1+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;  char drive[2+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1;
  if (   sscanf(name, "%*[sh]d%1[a-z]%n:%7[saicmfp]%n", drive, &n1, options, &n2) >= 1  if (   sscanf(name, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1
      && ((n1 == len && !options[0]) || n2 == len)                                       ) {      && ((n1 == len && !options[0]) || n2 == len)                                   ) {
    return open(drive[0] - 'a', -1, options, -1);    return open(sdxy_to_phydrive(drive), -1, options, -1);
   }    }
  // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-25, RAID port N, with options  // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options
   drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;    drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1;
   unsigned port = ~0;    unsigned port = ~0;
  if (   sscanf(name, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2  if (   sscanf(name, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2
      && port < 32 && ((n1 == len && !options[0]) || n2 == len)                                     ) {      && port < 32 && ((n1 == len && !options[0]) || n2 == len)                                  ) {
    return open(drive[0] - 'a', -1, options, port);    return open(sdxy_to_phydrive(drive), -1, options, port);
   }    }
   // pd<m>,N => Physical drive <m>, RAID port N    // pd<m>,N => Physical drive <m>, RAID port N
   int phydrive = -1; port = ~0; n1 = -1; n2 = -1;    int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
Line 2490  bool win_ata_device::open() Line 2414  bool win_ata_device::open()
   
 bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)  bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port)
 {  {
  // path depends on Windows Version  m_phydrive = -1;
   char devpath[30];    char devpath[30];
  if (win9x && 0 <= phydrive && phydrive <= 7)  if (0 <= phydrive && phydrive <= 255)
    // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details    snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive));
    strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));  else if (0 <= logdrive && logdrive <= 'Z'-'A')
  else if (!win9x && 0 <= phydrive && phydrive <= 255) 
    snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive); 
  else if (!win9x && 0 <= logdrive && logdrive <= 'Z'-'A') 
     snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);      snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
   else    else
     return set_err(ENOENT);      return set_err(ENOENT);
   
   // Open device    // Open device
   HANDLE h = INVALID_HANDLE_VALUE;    HANDLE h = INVALID_HANDLE_VALUE;
  if (win9x || !(*options && !options[strspn(options, "fp")])) {  if (!(*options && !options[strspn(options, "fp")])) {
     // Open with admin rights      // Open with admin rights
     m_admin = true;      m_admin = true;
     h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,      h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,        FILE_SHARE_READ|FILE_SHARE_WRITE,
       NULL, OPEN_EXISTING, 0, 0);        NULL, OPEN_EXISTING, 0, 0);
   }    }
  if (!win9x && h == INVALID_HANDLE_VALUE) {  if (h == INVALID_HANDLE_VALUE) {
     // Open without admin rights      // Open without admin rights
     m_admin = false;      m_admin = false;
     h = CreateFileA(devpath, 0,      h = CreateFileA(devpath, 0,
Line 2520  bool win_ata_device::open(int phydrive, int logdrive,  Line 2441  bool win_ata_device::open(int phydrive, int logdrive, 
   }    }
   if (h == INVALID_HANDLE_VALUE) {    if (h == INVALID_HANDLE_VALUE) {
     long err = GetLastError();      long err = GetLastError();
 #if WIN9X_SUPPORT  
     if (win9x && phydrive <= 3 && err == ERROR_FILE_NOT_FOUND)  
       smartvsd_error();  
 #endif  
     if (err == ERROR_FILE_NOT_FOUND)      if (err == ERROR_FILE_NOT_FOUND)
       set_err(ENOENT, "%s: not found", devpath);        set_err(ENOENT, "%s: not found", devpath);
     else if (err == ERROR_ACCESS_DENIED)      else if (err == ERROR_ACCESS_DENIED)
Line 2560  bool win_ata_device::open(int phydrive, int logdrive,  Line 2477  bool win_ata_device::open(int phydrive, int logdrive, 
     m_options = def_options;      m_options = def_options;
   }    }
   
  // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call  // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
  m_drive = 0; m_port = port;  m_port = port;
  if (!win9x && port < 0)  if (port < 0)
     return true;      return true;
   
  // Win9X/ME: Get drive map  // 3ware RAID: Get port map
  // RAID: Get port map 
   GETVERSIONINPARAMS_EX vers_ex;    GETVERSIONINPARAMS_EX vers_ex;
   int devmap = smart_get_version(h, &vers_ex);    int devmap = smart_get_version(h, &vers_ex);
   
Line 2595  bool win_ata_device::open(int phydrive, int logdrive,  Line 2511  bool win_ata_device::open(int phydrive, int logdrive, 
   }    }
   m_smartver_state = 1;    m_smartver_state = 1;
   
  if (port >= 0) {  {
     // 3ware RAID: update devicemap first      // 3ware RAID: update devicemap first
   
     if (!update_3ware_devicemap_ioctl(h)) {      if (!update_3ware_devicemap_ioctl(h)) {
Line 2610  bool win_ata_device::open(int phydrive, int logdrive,  Line 2526  bool win_ata_device::open(int phydrive, int logdrive, 
         return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);          return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port);
       }        }
     }      }
     return true;  
   }    }
   
   // Win9x/ME: Check device presence & type  
   if (((devmap >> (phydrive & 0x3)) & 0x11) != 0x01) {  
     unsigned char atapi = (devmap >> (phydrive & 0x3)) & 0x10;  
     // Win9x drive existence check may not work as expected  
     // The atapi.sys driver incorrectly fills in the bIDEDeviceMap with 0x01  
     // (The related KB Article Q196120 is no longer available)  
     if (!is_permissive()) {  
       close();  
       return set_err((atapi ? ENOSYS : ENOENT), "%s: Drive %d %s (IDEDeviceMap=0x%02x)",  
         devpath, phydrive, (atapi?"is an ATAPI device":"does not exist"), devmap);  
     }  
   }  
   // Drive number must be passed to ioctl  
   m_drive = (phydrive & 0x3);  
   return true;    return true;
 }  }
   
   
 #if WIN9X_SUPPORT  
   
 // Scan for ATA drives on Win9x/ME  
   
 bool win9x_smart_interface::ata_scan(smart_device_list & devlist)  
 {  
   // Open device  
   const char devpath[] = "\\\\.\\SMARTVSD";  
   HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,  
     FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);  
   if (h == INVALID_HANDLE_VALUE) {  
     if (ata_debugmode > 1)  
       pout(" %s: Open failed, Error=%ld\n", devpath, GetLastError());  
     return true; // SMARTVSD.VXD missing or no ATA devices  
   }  
   
   // Get drive map  
   int devmap = smart_get_version(h);  
   CloseHandle(h);  
   if (devmap < 0)  
     return true; // Should not happen  
   
   // Check ATA device presence, remove ATAPI devices  
   devmap = (devmap & 0xf) & ~((devmap >> 4) & 0xf);  
   char name[20];  
   for (int i = 0; i < 4; i++) {  
     if (!(devmap & (1 << i)))  
       continue;  
     sprintf(name, "/dev/hd%c", 'a'+i);  
     devlist.push_back( new win_ata_device(this, name, "ata") );  
   }  
   return true;  
 }  
   
 #endif // WIN9X_SUPPORT  
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
   
 // Interface to ATA devices  // Interface to ATA devices
Line 2675  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2539  bool win_ata_device::ata_pass_through(const ata_cmd_in
 {  {
   // No multi-sector support for now, see above    // No multi-sector support for now, see above
   // warning about IOCTL_ATA_PASS_THROUGH    // warning about IOCTL_ATA_PASS_THROUGH
  if (!ata_cmd_is_ok(in,  if (!ata_cmd_is_supported(in,
    true, // data_out_support    ata_device::supports_data_out |
    false, // !multi_sector_support    ata_device::supports_output_regs |
    true) // ata_48bit_support    ata_device::supports_48bit)
   )    )
     return false;      return false;
   
Line 2696  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2560  bool win_ata_device::ata_pass_through(const ata_cmd_in
     case ATA_IDENTIFY_PACKET_DEVICE:      case ATA_IDENTIFY_PACKET_DEVICE:
       // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE        // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
       // and SCSI_MINIPORT_* if requested by user        // and SCSI_MINIPORT_* if requested by user
      valid_options = (m_usr_options ? "saicmf" : "saicf");      valid_options = (m_usr_options ? "saimf" : "saif");
       break;        break;
   
     case ATA_CHECK_POWER_MODE:      case ATA_CHECK_POWER_MODE:
Line 2714  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2578  bool win_ata_device::ata_pass_through(const ata_cmd_in
         case ATA_SMART_AUTO_OFFLINE:          case ATA_SMART_AUTO_OFFLINE:
           // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE            // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
           // and SCSI_MINIPORT_* if requested by user            // and SCSI_MINIPORT_* if requested by user
          valid_options = (m_usr_options ? "saicmf" : "saicf");          valid_options = (m_usr_options ? "saimf" : "saif");
           break;            break;
   
         case ATA_SMART_IMMEDIATE_OFFLINE:          case ATA_SMART_IMMEDIATE_OFFLINE:
          // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME          // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
          valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ || win9x ?          valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ?
                           "saicm3" : "aicm3");                           "saim3" : "aim3");
           break;            break;
   
         case ATA_SMART_READ_LOG_SECTOR:          case ATA_SMART_READ_LOG_SECTOR:
          // SMART_RCV_DRIVE_DATA supports this only on Win9x/ME          // SMART_RCV_DRIVE_DATA does not support READ_LOG
           // Try SCSI_MINIPORT also to skip buggy class driver            // Try SCSI_MINIPORT also to skip buggy class driver
           // SMART functions do not support multi sector I/O.            // SMART functions do not support multi sector I/O.
           if (in.size == 512)            if (in.size == 512)
            valid_options = (m_usr_options || win9x ? "saicm3" : "aicm3");            valid_options = (m_usr_options ? "saim3" : "aim3");
           else            else
             valid_options = "a";              valid_options = "a";
           break;            break;
Line 2740  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2604  bool win_ata_device::ata_pass_through(const ata_cmd_in
           break;            break;
   
         case ATA_SMART_STATUS:          case ATA_SMART_STATUS:
          // May require lba_mid,lba_high register return          valid_options = (m_usr_options ? "saimf" : "saif");
          if (in.out_needed.is_set()) 
            valid_options = (m_usr_options ? "saimf" : "saif"); 
          else 
            valid_options = (m_usr_options ? "saicmf" : "saicf"); 
           break;            break;
   
         default:          default:
Line 2765  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2625  bool win_ata_device::ata_pass_through(const ata_cmd_in
          ||  in.in_regs.is_48bit_cmd()                               )           ||  in.in_regs.is_48bit_cmd()                               )
       // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only        // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
       valid_options = "a";        valid_options = "a";
     else if (in.out_needed.is_set())  
       // Need output registers: ATA/IDE_PASS_THROUGH  
       valid_options = "ai";  
     else      else
      valid_options = "aic";      // ATA/IDE_PASS_THROUGH
       valid_options = "ai";
   }    }
   
   if (!m_admin) {    if (!m_admin) {
Line 2882  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2740  bool win_ata_device::ata_pass_through(const ata_cmd_in
   
           m_smartver_state = 1;            m_smartver_state = 1;
         }          }
        rc = smart_ioctl(get_fh(), m_drive, &regs, data, datasize, m_port);        rc = smart_ioctl(get_fh(), &regs, data, datasize, m_port);
         out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);          out_regs_set = (in.in_regs.features == ATA_SMART_STATUS);
        id_is_cached = (m_port < 0 && !win9x); // Not cached by 3ware or Win9x/ME driver        id_is_cached = (m_port < 0); // Not cached by 3ware driver
         break;          break;
       case 'm':        case 'm':
         rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);          rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), &regs, data, datasize);
        id_is_cached = (m_port < 0 && !win9x);        id_is_cached = (m_port < 0);
         break;          break;
       case 'a':        case 'a':
         rc = ata_pass_through_ioctl(get_fh(), &regs,          rc = ata_pass_through_ioctl(get_fh(), &regs,
Line 2900  bool win_ata_device::ata_pass_through(const ata_cmd_in Line 2758  bool win_ata_device::ata_pass_through(const ata_cmd_in
         rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);          rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
         out_regs_set = true;          out_regs_set = true;
         break;          break;
       case 'c':  
         rc = ata_via_scsi_pass_through_ioctl(get_fh(), &regs, data, datasize);  
         break;  
       case 'f':        case 'f':
         if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {          if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
             rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);              rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
               if (rc == 0 && m_phydrive >= 0)
                 get_serial_from_wmi(m_phydrive, (ata_identify_device *)data);
             id_is_cached = true;              id_is_cached = true;
         }          }
         else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {          else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
Line 3096  bool csmi_device::select_phy(unsigned phy_no) Line 2953  bool csmi_device::select_phy(unsigned phy_no)
   
 bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)  bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 {  {
  if (!ata_cmd_is_ok(in,  if (!ata_cmd_is_supported(in,
    true, // data_out_support    ata_device::supports_data_out |
    true, // multi_sector_support    ata_device::supports_output_regs |
    true) // ata_48bit_support    ata_device::supports_multi_sector |
     ata_device::supports_48bit,
     "CMSI")
   )    )
     return false;      return false;
   
Line 3314  bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_ Line 3173  bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_
   // Check result    // Check result
   if (csmi_buffer->ReturnCode) {    if (csmi_buffer->ReturnCode) {
     if (scsi_debugmode) {      if (scsi_debugmode) {
      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%lu\n",      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
        code, csmi_buffer->ReturnCode);        code, (unsigned)csmi_buffer->ReturnCode);
     }      }
    return set_err(EIO, "CSMI(%u) failed with ReturnCode=%lu", code, csmi_buffer->ReturnCode);    return set_err(EIO, "CSMI(%u) failed with ReturnCode=%u", code, (unsigned)csmi_buffer->ReturnCode);
   }    }
   
   if (scsi_debugmode > 1)    if (scsi_debugmode > 1)
    pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %lu\n", code, num_out);    pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out);
   
   return true;    return true;
 }  }
   
   
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
 // ASPI Interface (for SCSI devices on 9x/ME)  
 /////////////////////////////////////////////////////////////////////////////  
   
 #if WIN9X_SUPPORT  
   
 #pragma pack(1)  
   
 #define ASPI_SENSE_SIZE 18  
   
 // ASPI SCSI Request block header  
   
 typedef struct {  
   unsigned char cmd;             // 00: Command code  
   unsigned char status;          // 01: ASPI status  
   unsigned char adapter;         // 02: Host adapter number  
   unsigned char flags;           // 03: Request flags  
   unsigned char reserved[4];     // 04: 0  
 } ASPI_SRB_HEAD;  
   
 // SRB for host adapter inquiry  
   
 typedef struct {  
   ASPI_SRB_HEAD h;               // 00: Header  
   unsigned char adapters;        // 08: Number of adapters  
   unsigned char target_id;       // 09: Target ID ?  
   char manager_id[16];           // 10: SCSI manager ID  
   char adapter_id[16];           // 26: Host adapter ID  
   unsigned char parameters[16];  // 42: Host adapter unique parmameters  
 } ASPI_SRB_INQUIRY;  
   
 // SRB for get device type  
   
 typedef struct {  
   ASPI_SRB_HEAD h;               // 00: Header  
   unsigned char target_id;       // 08: Target ID  
   unsigned char lun;             // 09: LUN  
   unsigned char devtype;         // 10: Device type  
   unsigned char reserved;        // 11: Reserved  
 } ASPI_SRB_DEVTYPE;  
   
 // SRB for SCSI I/O  
   
 typedef struct {  
   ASPI_SRB_HEAD h;               // 00: Header  
   unsigned char target_id;       // 08: Target ID  
   unsigned char lun;             // 09: LUN  
   unsigned char reserved[2];     // 10: Reserved  
   unsigned long data_size;       // 12: Data alloc. lenght  
   void * data_addr;              // 16: Data buffer pointer  
   unsigned char sense_size;      // 20: Sense alloc. length  
   unsigned char cdb_size;        // 21: CDB length  
   unsigned char host_status;     // 22: Host status  
   unsigned char target_status;   // 23: Target status  
   void * event_handle;           // 24: Event handle  
   unsigned char workspace[20];   // 28: ASPI workspace  
   unsigned char cdb[16+ASPI_SENSE_SIZE];  
 } ASPI_SRB_IO;  
   
 // Macro to retrieve start of sense information  
 #define ASPI_SRB_SENSE(srb,cdbsz) ((srb)->cdb + 16)  
   
 // SRB union  
   
 typedef union {  
   ASPI_SRB_HEAD h;       // Common header  
   ASPI_SRB_INQUIRY q;    // Inquiry  
   ASPI_SRB_DEVTYPE t;    // Device type  
   ASPI_SRB_IO i;         // I/O  
 } ASPI_SRB;  
   
 #pragma pack()  
   
 // ASPI commands  
 #define ASPI_CMD_ADAPTER_INQUIRE        0x00  
 #define ASPI_CMD_GET_DEVICE_TYPE        0x01  
 #define ASPI_CMD_EXECUTE_IO             0x02  
 #define ASPI_CMD_ABORT_IO               0x03  
   
 // Request flags  
 #define ASPI_REQFLAG_DIR_TO_HOST        0x08  
 #define ASPI_REQFLAG_DIR_TO_TARGET      0x10  
 #define ASPI_REQFLAG_DIR_NO_XFER        0x18  
 #define ASPI_REQFLAG_EVENT_NOTIFY       0x40  
   
 // ASPI status  
 #define ASPI_STATUS_IN_PROGRESS         0x00  
 #define ASPI_STATUS_NO_ERROR            0x01  
 #define ASPI_STATUS_ABORTED             0x02  
 #define ASPI_STATUS_ABORT_ERR           0x03  
 #define ASPI_STATUS_ERROR               0x04  
 #define ASPI_STATUS_INVALID_COMMAND     0x80  
 #define ASPI_STATUS_INVALID_ADAPTER     0x81  
 #define ASPI_STATUS_INVALID_TARGET      0x82  
 #define ASPI_STATUS_NO_ADAPTERS         0xE8  
   
 // Adapter (host) status  
 #define ASPI_HSTATUS_NO_ERROR           0x00  
 #define ASPI_HSTATUS_SELECTION_TIMEOUT  0x11  
 #define ASPI_HSTATUS_DATA_OVERRUN       0x12  
 #define ASPI_HSTATUS_BUS_FREE           0x13  
 #define ASPI_HSTATUS_BUS_PHASE_ERROR    0x14  
 #define ASPI_HSTATUS_BAD_SGLIST         0x1A  
   
 // Target status  
 #define ASPI_TSTATUS_NO_ERROR           0x00  
 #define ASPI_TSTATUS_CHECK_CONDITION    0x02  
 #define ASPI_TSTATUS_BUSY               0x08  
 #define ASPI_TSTATUS_RESERV_CONFLICT    0x18  
   
   
 static HINSTANCE h_aspi_dll; // DLL handle  
 static UINT (* aspi_entry)(ASPI_SRB * srb); // ASPI entrypoint  
 static unsigned num_aspi_adapters;  
   
 #ifdef __CYGWIN__  
 // h_aspi_dll+aspi_entry is not inherited by Cygwin's fork()  
 static DWORD aspi_dll_pid; // PID of DLL owner to detect fork()  
 #define aspi_entry_valid() (aspi_entry && (aspi_dll_pid == GetCurrentProcessId()))  
 #else  
 #define aspi_entry_valid() (!!aspi_entry)  
 #endif  
   
   
 static int aspi_call(ASPI_SRB * srb)  
 {  
   int i;  
   aspi_entry(srb);  
   i = 0;  
   while (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {  
     if (++i > 100/*10sek*/) {  
       pout("ASPI Adapter %u: Timed out\n", srb->h.adapter);  
       aspi_entry = 0;  
       h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;  
       errno = EIO;  
       return -1;  
     }  
     if (scsi_debugmode > 1)  
       pout("ASPI Adapter %u: Waiting (%d) ...\n", srb->h.adapter, i);  
     Sleep(100);  
   }  
   return 0;  
 }  
   
   
 // Get ASPI entrypoint from wnaspi32.dll  
   
 static FARPROC aspi_get_address(const char * name, int verbose)  
 {  
   FARPROC addr;  
   assert(h_aspi_dll && h_aspi_dll != INVALID_HANDLE_VALUE);  
   
   if (!(addr = GetProcAddress(h_aspi_dll, name))) {  
     if (verbose)  
       pout("Missing %s() in WNASPI32.DLL\n", name);  
     aspi_entry = 0;  
     FreeLibrary(h_aspi_dll);  
     h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;  
     errno = ENOSYS;  
     return 0;  
   }  
   return addr;  
 }  
   
   
 static int aspi_open_dll(int verbose)  
 {  
   UINT (*aspi_info)(void);  
   UINT info, rc;  
   
   assert(!aspi_entry_valid());  
   
   // Check structure layout  
   assert(sizeof(ASPI_SRB_HEAD) == 8);  
   assert(sizeof(ASPI_SRB_INQUIRY) == 58);  
   assert(sizeof(ASPI_SRB_DEVTYPE) == 12);  
   assert(sizeof(ASPI_SRB_IO) == 64+ASPI_SENSE_SIZE);  
   assert(offsetof(ASPI_SRB,h.cmd) == 0);  
   assert(offsetof(ASPI_SRB,h.flags) == 3);  
   assert(offsetof(ASPI_SRB_IO,lun) == 9);  
   assert(offsetof(ASPI_SRB_IO,data_addr) == 16);  
   assert(offsetof(ASPI_SRB_IO,workspace) == 28);  
   assert(offsetof(ASPI_SRB_IO,cdb) == 48);  
   
   if (h_aspi_dll == INVALID_HANDLE_VALUE) {  
     // do not retry  
     errno = ENOENT;  
     return -1;  
   }  
   
   // Load ASPI DLL  
   if (!(h_aspi_dll = LoadLibraryA("WNASPI32.DLL"))) {  
     if (verbose)  
       pout("Cannot load WNASPI32.DLL, Error=%ld\n", GetLastError());  
     h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;  
     errno = ENOENT;  
     return -1;  
   }  
   if (scsi_debugmode > 1) {  
     // Print full path of WNASPI32.DLL  
     char path[MAX_PATH];  
     if (!GetModuleFileName(h_aspi_dll, path, sizeof(path)))  
       strcpy(path, "*unknown*");  
     pout("Using ASPI interface \"%s\"\n", path);  
   }  
   
   // Get ASPI entrypoints  
   if (!(aspi_info = (UINT (*)(void))aspi_get_address("GetASPI32SupportInfo", verbose)))  
     return -1;  
   if (!(aspi_entry = (UINT (*)(ASPI_SRB *))aspi_get_address("SendASPI32Command", verbose)))  
     return -1;  
   
   // Init ASPI manager and get number of adapters  
   info = (aspi_info)();  
   if (scsi_debugmode > 1)  
     pout("GetASPI32SupportInfo() returns 0x%04x\n", info);  
   rc = (info >> 8) & 0xff;  
   if (rc == ASPI_STATUS_NO_ADAPTERS) {  
     num_aspi_adapters = 0;  
   }  
   else if (rc == ASPI_STATUS_NO_ERROR) {  
     num_aspi_adapters = info & 0xff;  
   }  
   else {  
     if (verbose)  
       pout("Got strange 0x%04x from GetASPI32SupportInfo()\n", info);  
     aspi_entry = 0;  
     FreeLibrary(h_aspi_dll);  
     h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;  
     errno = ENOENT;  
     return -1;  
   }  
   
   if (scsi_debugmode)  
     pout("%u ASPI Adapter%s detected\n",num_aspi_adapters, (num_aspi_adapters!=1?"s":""));  
   
 #ifdef __CYGWIN__  
   // save PID to detect fork() in aspi_entry_valid()  
   aspi_dll_pid = GetCurrentProcessId();  
 #endif  
   assert(aspi_entry_valid());  
   return 0;  
 }  
   
   
 static int aspi_io_call(ASPI_SRB * srb, unsigned timeout)  
 {  
   HANDLE event;  
   // Create event  
   if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) {  
     pout("CreateEvent(): Error=%ld\n", GetLastError()); return -EIO;  
   }  
   srb->i.event_handle = event;  
   srb->h.flags |= ASPI_REQFLAG_EVENT_NOTIFY;  
   // Start ASPI request  
   aspi_entry(srb);  
   if (((volatile ASPI_SRB *)srb)->h.status == ASPI_STATUS_IN_PROGRESS) {  
     // Wait for event  
     DWORD rc = WaitForSingleObject(event, timeout*1000L);  
     if (rc != WAIT_OBJECT_0) {  
       if (rc == WAIT_TIMEOUT) {  
         pout("ASPI Adapter %u, ID %u: Timed out after %u seconds\n",  
           srb->h.adapter, srb->i.target_id, timeout);  
       }  
       else {  
         pout("WaitForSingleObject(%lx) = 0x%lx,%ld, Error=%ld\n",  
           (unsigned long)(ULONG_PTR)event, rc, rc, GetLastError());  
       }  
       // TODO: ASPI_ABORT_IO command  
       aspi_entry = 0;  
       h_aspi_dll = (HINSTANCE)INVALID_HANDLE_VALUE;  
       return -EIO;  
     }  
   }  
   CloseHandle(event);  
   return 0;  
 }  
   
   
 win_aspi_device::win_aspi_device(smart_interface * intf,  
   const char * dev_name, const char * req_type)  
 : smart_device(intf, dev_name, "scsi", req_type),  
   m_adapter(-1), m_id(0)  
 {  
 }  
   
 bool win_aspi_device::is_open() const  
 {  
   return (m_adapter >= 0);  
 }  
   
 bool win_aspi_device::open()  
 {  
   // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0  
   unsigned adapter = ~0, id = ~0; int n1 = -1;  
   const char * name = skipdev(get_dev_name());  
   if (!(sscanf(name,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == (int)strlen(name)  
         && adapter <= 9 && id < 16))  
     return set_err(EINVAL);  
   
   if (!aspi_entry_valid()) {  
     if (aspi_open_dll(1/*verbose*/))  
       return set_err(ENOENT);  
   }  
   
   // Adapter OK?  
   if (adapter >= num_aspi_adapters) {  
     pout("ASPI Adapter %u does not exist (%u Adapter%s detected).\n",  
       adapter, num_aspi_adapters, (num_aspi_adapters!=1?"s":""));  
     if (!is_permissive())  
       return set_err(ENOENT);  
   }  
   
   // Device present ?  
   ASPI_SRB srb;  
   memset(&srb, 0, sizeof(srb));  
   srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;  
   srb.h.adapter = adapter; srb.i.target_id = id;  
   if (aspi_call(&srb))  
     return set_err(EIO);  
   if (srb.h.status != ASPI_STATUS_NO_ERROR) {  
     pout("ASPI Adapter %u, ID %u: No such device (Status=0x%02x)\n", adapter, id, srb.h.status);  
     if (!is_permissive())  
       return set_err(srb.h.status == ASPI_STATUS_INVALID_TARGET ? ENOENT : EIO);  
   }  
   else if (scsi_debugmode)  
     pout("ASPI Adapter %u, ID %u: Device Type=0x%02x\n", adapter, id, srb.t.devtype);  
   
   m_adapter = (int)adapter; m_id = (unsigned char)id;  
   return true;  
 }  
   
   
 bool win_aspi_device::close()  
 {  
   // No FreeLibrary(h_aspi_dll) to prevent problems with ASPI threads  
   return true;  
 }  
   
   
 // Scan for ASPI drives  
   
 bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)  
 {  
   if (!aspi_entry_valid()) {  
     if (aspi_open_dll(scsi_debugmode/*default is quiet*/))  
       return true;  
   }  
   
   for (unsigned ad = 0; ad < num_aspi_adapters; ad++) {  
     ASPI_SRB srb;  
   
     if (ad > 9) {  
       if (scsi_debugmode)  
         pout(" ASPI Adapter %u: Ignored\n", ad);  
       continue;  
     }  
   
     // Get adapter name  
     memset(&srb, 0, sizeof(srb));  
     srb.h.cmd = ASPI_CMD_ADAPTER_INQUIRE;  
     srb.h.adapter = ad;  
     if (aspi_call(&srb))  
       break;  
   
     if (srb.h.status != ASPI_STATUS_NO_ERROR) {  
       if (scsi_debugmode)  
         pout(" ASPI Adapter %u: Status=0x%02x\n", ad, srb.h.status);  
       continue;  
     }  
   
     if (scsi_debugmode) {  
       for (int i = 1; i < 16 && srb.q.adapter_id[i]; i++)  
         if (!(' ' <= srb.q.adapter_id[i] && srb.q.adapter_id[i] <= '~'))  
           srb.q.adapter_id[i] = '?';  
       pout(" ASPI Adapter %u (\"%.16s\"):\n", ad, srb.q.adapter_id);  
     }  
   
     bool ignore = !strnicmp(srb.q.adapter_id, "3ware", 5);  
   
     for (unsigned id = 0; id <= 7; id++) {  
       // Get device type  
       memset(&srb, 0, sizeof(srb));  
       srb.h.cmd = ASPI_CMD_GET_DEVICE_TYPE;  
       srb.h.adapter = ad; srb.i.target_id = id;  
       if (aspi_call(&srb))  
         return 0;  
       if (srb.h.status != ASPI_STATUS_NO_ERROR) {  
         if (scsi_debugmode > 1)  
           pout("  ID %u: No such device (Status=0x%02x)\n", id, srb.h.status);  
         continue;  
       }  
   
       if (!ignore && srb.t.devtype == 0x00/*HDD*/) {  
         if (scsi_debugmode)  
           pout("  ID %u: Device Type=0x%02x\n", id, srb.t.devtype);  
         char name[20];  
         sprintf(name, "/dev/scsi%u%u", ad, id);  
         devlist.push_back( new win_aspi_device(this, name, "scsi") );  
       }  
       else if (scsi_debugmode)  
         pout("  ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);  
     }  
   }  
   return true;  
 }  
   
   
 // Interface to ASPI SCSI devices  
 bool win_aspi_device::scsi_pass_through(scsi_cmnd_io * iop)  
 {  
   int report = scsi_debugmode; // TODO  
   
   if (m_adapter < 0) {  
     set_err(EBADF);  
     return false;  
   }  
   
   if (!aspi_entry_valid()) {  
     set_err(EBADF);  
     return false;  
   }  
   
   if (!(iop->cmnd_len == 6 || iop->cmnd_len == 10 || iop->cmnd_len == 12 || iop->cmnd_len == 16)) {  
     set_err(EINVAL, "bad CDB length");  
     return false;  
   }  
   
   if (report > 0) {  
     // From os_linux.c  
     int k, j;  
     const unsigned char * ucp = iop->cmnd;  
     const char * np;  
     char buff[256];  
     const int sz = (int)sizeof(buff);  
   
     np = scsi_get_opcode_name(ucp[0]);  
     j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");  
     for (k = 0; k < (int)iop->cmnd_len; ++k)  
       j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);  
     if ((report > 1) &&  
       (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {  
       int trunc = (iop->dxfer_len > 256) ? 1 : 0;  
   
       j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n  Outgoing "  
               "data, len=%d%s:\n", (int)iop->dxfer_len,  
               (trunc ? " [only first 256 bytes shown]" : ""));  
       dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);  
     }  
     else  
       j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");  
     pout(buff);  
   }  
   
   ASPI_SRB srb;  
   memset(&srb, 0, sizeof(srb));  
   srb.h.cmd = ASPI_CMD_EXECUTE_IO;  
   srb.h.adapter = m_adapter;  
   srb.i.target_id = m_id;  
   //srb.i.lun = 0;  
   srb.i.sense_size = ASPI_SENSE_SIZE;  
   srb.i.cdb_size = iop->cmnd_len;  
   memcpy(srb.i.cdb, iop->cmnd, iop->cmnd_len);  
   
   switch (iop->dxfer_dir) {  
     case DXFER_NONE:  
       srb.h.flags = ASPI_REQFLAG_DIR_NO_XFER;  
       break;  
     case DXFER_FROM_DEVICE:  
       srb.h.flags = ASPI_REQFLAG_DIR_TO_HOST;  
       srb.i.data_size = iop->dxfer_len;  
       srb.i.data_addr = iop->dxferp;  
       break;  
     case DXFER_TO_DEVICE:  
       srb.h.flags = ASPI_REQFLAG_DIR_TO_TARGET;  
       srb.i.data_size = iop->dxfer_len;  
       srb.i.data_addr = iop->dxferp;  
       break;  
     default:  
       set_err(EINVAL, "bad dxfer_dir");  
       return false;  
   }  
   
   iop->resp_sense_len = 0;  
   iop->scsi_status = 0;  
   iop->resid = 0;  
   
   if (aspi_io_call(&srb, (iop->timeout ? iop->timeout : 60))) {  
     // Timeout  
     set_err(EIO, "ASPI Timeout"); return false;  
   }  
   
   if (srb.h.status != ASPI_STATUS_NO_ERROR) {  
     if (   srb.h.status        == ASPI_STATUS_ERROR  
         && srb.i.host_status   == ASPI_HSTATUS_NO_ERROR  
         && srb.i.target_status == ASPI_TSTATUS_CHECK_CONDITION) {  
       // Sense valid  
       const unsigned char * sense = ASPI_SRB_SENSE(&srb.i, iop->cmnd_len);  
       int len = (ASPI_SENSE_SIZE < iop->max_sense_len ? ASPI_SENSE_SIZE : iop->max_sense_len);  
       iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;  
       if (len > 0 && iop->sensep) {  
         memcpy(iop->sensep, sense, len);  
         iop->resp_sense_len = len;  
         if (report > 1) {  
           pout("  >>> Sense buffer, len=%d:\n", (int)len);  
           dStrHex(iop->sensep, len , 1);  
         }  
       }  
       if (report) {  
         pout("  sense_key=%x asc=%x ascq=%x\n",  
          sense[2] & 0xf, sense[12], sense[13]);  
       }  
       return true;  
     }  
     else {  
       if (report)  
         pout("  ASPI call failed, (0x%02x,0x%02x,0x%02x)\n", srb.h.status, srb.i.host_status, srb.i.target_status);  
       set_err(EIO);  
       return false;  
     }  
   }  
   
   if (report > 0)  
     pout("  OK\n");  
   
   if (iop->dxfer_dir == DXFER_FROM_DEVICE && report > 1) {  
      int trunc = (iop->dxfer_len > 256) ? 1 : 0;  
      pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,  
         (trunc ? " [only first 256 bytes shown]" : ""));  
         dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);  
   }  
   
   return true;  
 }  
   
 #endif // WIN9X_SUPPORT  
   
 /////////////////////////////////////////////////////////////////////////////  
 // SPT Interface (for SCSI devices and ATA devices behind SATLs)  // SPT Interface (for SCSI devices and ATA devices behind SATLs)
 // Only supported in NT and later  // Only supported in NT and later
 /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
Line 3878  win_scsi_device::win_scsi_device(smart_interface * int Line 3200  win_scsi_device::win_scsi_device(smart_interface * int
 bool win_scsi_device::open()  bool win_scsi_device::open()
 {  {
   const char * name = skipdev(get_dev_name()); int len = strlen(name);    const char * name = skipdev(get_dev_name()); int len = strlen(name);
  // sd[a-z],N => Physical drive 0-26, RAID port N  // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
  char drive[1+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;  char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1;
  if (   sscanf(name, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1  if (   sscanf(name, "sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1
       && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))  ) {        && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))  ) {
    return open(drive[0] - 'a', -1, -1, sub_addr);    return open(sdxy_to_phydrive(drive), -1, -1, sub_addr);
   }    }
   // pd<m>,N => Physical drive <m>, RAID port N    // pd<m>,N => Physical drive <m>, RAID port N
   int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;    int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
Line 3933  bool win_scsi_device::open(int pd_num, int ld_num, int Line 3255  bool win_scsi_device::open(int pd_num, int ld_num, int
            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,             FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
            OPEN_EXISTING, 0, 0);             OPEN_EXISTING, 0, 0);
   if (h == INVALID_HANDLE_VALUE) {    if (h == INVALID_HANDLE_VALUE) {
    set_err(ENODEV, "%s: Open failed, Error=%ld", b, GetLastError());    set_err(ENODEV, "%s: Open failed, Error=%u", b, (unsigned)GetLastError());
     return false;      return false;
   }    }
   set_fh(h);    set_fh(h);
Line 4021  bool win_scsi_device::scsi_pass_through(struct scsi_cm Line 3343  bool win_scsi_device::scsi_pass_through(struct scsi_cm
     }      }
     else      else
       j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");        j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
    pout(buff);    pout("%s", buff);
   }    }
   
   SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;    SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
Line 4119  bool win_scsi_device::scsi_pass_through(struct scsi_cm Line 3441  bool win_scsi_device::scsi_pass_through(struct scsi_cm
   return true;    return true;
 }  }
   
   // Interface to SPT SCSI devices.  See scsicmds.h and os_linux.c
   static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop)
   {
     int report = scsi_debugmode; // TODO
   
     if (report > 0) {
       int k, j;
       const unsigned char * ucp = iop->cmnd;
       const char * np;
       char buff[256];
       const int sz = (int)sizeof(buff);
   
       np = scsi_get_opcode_name(ucp[0]);
       j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
       for (k = 0; k < (int)iop->cmnd_len; ++k)
         j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
       if ((report > 1) &&
         (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
         int trunc = (iop->dxfer_len > 256) ? 1 : 0;
   
         j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n  Outgoing "
                 "data, len=%d%s:\n", (int)iop->dxfer_len,
                 (trunc ? " [only first 256 bytes shown]" : ""));
         dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
       }
       else
         j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
       pout("%s", buff);
     }
   
     SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb;
     if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) {
       return EINVAL;
     }
   
     memset(&sb, 0, sizeof(sb));
     sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
     //sb.spt.PathId = 0;
     sb.spt.TargetId = targetid;
     //sb.spt.Lun = 0;
     sb.spt.CdbLength = iop->cmnd_len;
     memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
     sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf);
     sb.spt.SenseInfoOffset =
       offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
     sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60);
   
     bool direct = true;
     switch (iop->dxfer_dir) {
       case DXFER_NONE:
         sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
         break;
       case DXFER_FROM_DEVICE:
         sb.spt.DataIn = SCSI_IOCTL_DATA_IN;
         sb.spt.DataTransferLength = iop->dxfer_len;
         sb.spt.DataBuffer = iop->dxferp;
         // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte
         // transfers (needed for SMART STATUS check of JMicron USB bridges)
         if (sb.spt.DataTransferLength == 1)
           direct = false;
         break;
       case DXFER_TO_DEVICE:
         sb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
         sb.spt.DataTransferLength = iop->dxfer_len;
         sb.spt.DataBuffer = iop->dxferp;
         break;
       default:
         return EINVAL;
     }
   
     long err = 0;
     if (direct) {
       DWORD num_out;
       if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
              &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0))
         err = GetLastError();
     }
     else
       err = scsi_pass_through_indirect(fd, &sb);
   
     if (err)
     {
       return err;
     }
   
     iop->scsi_status = sb.spt.ScsiStatus;
     if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) {
       int slen = sb.ucSenseBuf[7] + 8;
   
       if (slen > (int)sizeof(sb.ucSenseBuf))
         slen = sizeof(sb.ucSenseBuf);
       if (slen > (int)iop->max_sense_len)
         slen = iop->max_sense_len;
       memcpy(iop->sensep, sb.ucSenseBuf, slen);
       iop->resp_sense_len = slen;
       if (report) {
         if (report > 1) {
           pout("  >>> Sense buffer, len=%d:\n", slen);
           dStrHex(iop->sensep, slen , 1);
         }
         if ((iop->sensep[0] & 0x7f) > 0x71)
           pout("  status=%x: [desc] sense_key=%x asc=%x ascq=%x\n",
                iop->scsi_status, iop->sensep[1] & 0xf,
                iop->sensep[2], iop->sensep[3]);
         else
           pout("  status=%x: sense_key=%x asc=%x ascq=%x\n",
                iop->scsi_status, iop->sensep[2] & 0xf,
                iop->sensep[12], iop->sensep[13]);
       }
     } else
       iop->resp_sense_len = 0;
   
     if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0))
       iop->resid = iop->dxfer_len - sb.spt.DataTransferLength;
     else
       iop->resid = 0;
   
     if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) {
        int trunc = (iop->dxfer_len > 256) ? 1 : 0;
        pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
           (trunc ? " [only first 256 bytes shown]" : ""));
           dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
     }
   
     return 0;
   }
   
   // Areca RAID Controller(SAS Device)
   win_areca_scsi_device::win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
   : smart_device(intf, dev_name, "areca", "areca")
   {
       set_fh(INVALID_HANDLE_VALUE);
       set_disknum(disknum);
       set_encnum(encnum);
       set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
   }
   
   bool win_areca_scsi_device::open()
   {
     HANDLE hFh;
   
     if( is_open() )
     {
       return true;
     }
     hFh = CreateFile( get_dev_name(),
                       GENERIC_READ|GENERIC_WRITE,
                       FILE_SHARE_READ|FILE_SHARE_WRITE,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL );
     if(hFh == INVALID_HANDLE_VALUE)
     {
       return false;
     }
   
     set_fh(hFh);
     return true;
   }
   
   smart_device * win_areca_scsi_device::autodetect_open()
   {
     return this;
   }
   
   int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
   {
      int ioctlreturn = 0;
   
      ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
      if ( ioctlreturn || iop->scsi_status )
      {
        ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
        if ( ioctlreturn || iop->scsi_status )
        {
          // errors found
          return -1;
        }
      }
   
      return ioctlreturn;
   }
   
   bool win_areca_scsi_device::arcmsr_lock()
   {
   #define    SYNCOBJNAME "Global\\SynIoctlMutex"
     int ctlrnum = -1;
     char mutexstr[64];
   
     if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
       return set_err(EINVAL, "unable to parse device name");
   
     snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
     m_mutex = CreateMutex(NULL, FALSE, mutexstr);
     if ( m_mutex == NULL )
     {
       return set_err(EIO, "CreateMutex failed");
     }
   
     // atomic access to driver
     WaitForSingleObject(m_mutex, INFINITE);
   
     return true;
   }
   
   
   bool win_areca_scsi_device::arcmsr_unlock()
   {
     if( m_mutex != NULL)
     {
         ReleaseMutex(m_mutex);
         CloseHandle(m_mutex);
     }
   
     return true;
   }
   
   
   // Areca RAID Controller(SATA Disk)
   win_areca_ata_device::win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
   : smart_device(intf, dev_name, "areca", "areca")
   {
     set_fh(INVALID_HANDLE_VALUE);
     set_disknum(disknum);
     set_encnum(encnum);
     set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
   }
   
   bool win_areca_ata_device::open()
   {
     HANDLE hFh;
   
     if( is_open() )
     {
       return true;
     }
     hFh = CreateFile( get_dev_name(),
                       GENERIC_READ|GENERIC_WRITE,
                       FILE_SHARE_READ|FILE_SHARE_WRITE,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL );
     if(hFh == INVALID_HANDLE_VALUE)
     {
       return false;
     }
   
     set_fh(hFh);
     return true;
   }
   
   smart_device * win_areca_ata_device::autodetect_open()
   {
     int is_ata = 1;
   
     // autodetect device type
     is_ata = arcmsr_get_dev_type();
     if(is_ata < 0)
     {
       set_err(EIO);
       return this;
     }
   
     if(is_ata == 1)
     {
       // SATA device
       return this;
     }
   
     // SAS device
     smart_device_auto_ptr newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
     close();
     delete this;
     newdev->open(); // TODO: Can possibly pass open fd
   
     return newdev.release();
   }
   
   int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
   {
      int ioctlreturn = 0;
   
      ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop);
      if ( ioctlreturn || iop->scsi_status )
      {
        ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop);
        if ( ioctlreturn || iop->scsi_status )
        {
          // errors found
          return -1;
        }
      }
   
      return ioctlreturn;
   }
   
   bool win_areca_ata_device::arcmsr_lock()
   {
   #define    SYNCOBJNAME "Global\\SynIoctlMutex"
     int ctlrnum = -1;
     char mutexstr[64];
   
     if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
       return set_err(EINVAL, "unable to parse device name");
   
     snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
     m_mutex = CreateMutex(NULL, FALSE, mutexstr);
     if ( m_mutex == NULL )
     {
       return set_err(EIO, "CreateMutex failed");
     }
   
     // atomic access to driver
     WaitForSingleObject(m_mutex, INFINITE);
   
     return true;
   }
   
   
   bool win_areca_ata_device::arcmsr_unlock()
   {
     if( m_mutex != NULL)
     {
         ReleaseMutex(m_mutex);
         CloseHandle(m_mutex);
     }
   
     return true;
   }
   
   
 //////////////////////////////////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////////////////////////////////
   
   
Line 4139  void smart_interface::init() Line 3793  void smart_interface::init()
       SetDllDirectoryA_p("");        SetDllDirectoryA_p("");
   }    }
   
  // Select interface for Windows flavor  static os_win32::win_smart_interface the_win_interface;
  if (GetVersion() & 0x80000000) {  smart_interface::set(&the_win_interface);
#if WIN9X_SUPPORT 
    static os_win32::win9x_smart_interface the_win9x_interface; 
    smart_interface::set(&the_win9x_interface); 
#else 
    throw std::runtime_error("Win9x/ME not supported"); 
#endif 
  } 
  else { 
    static os_win32::winnt_smart_interface the_winnt_interface; 
    smart_interface::set(&the_winnt_interface); 
  } 
 }  }
   
   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>