]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - os_win32.cpp
Imported Upstream version 6.1+svn3812
[mirror_smartmontools-debian.git] / os_win32.cpp
index ace6d32efeb08ff0cfa43b7b50969e8a18ab5c30..6c5fc5178d795eb36b9d62b43db198f7898ca3b6 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2004-12 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
@@ -28,6 +28,7 @@
 
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
+#include "dev_areca.h"
 
 #include "os_win32/wmiquery.h"
 
 #include <windows.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)
 #include <devioctl.h>
 #include <ntdddisk.h>
 #include <ntddscsi.h>
 #include <ntddstor.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)
 #include <ddk/ntdddisk.h>
 #include <ddk/ntddscsi.h>
 #include <winioctl.h>
 #endif
 
+#ifndef _WIN32
+// csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin
+#define _WIN32
+#endif
+
 // CSMI support
 #include "csmisas.h"
 
-#ifdef __CYGWIN__
-#include <cygwin/version.h> // CYGWIN_VERSION_DLL_MAJOR
+// Silence -Wunused-local-typedefs warning from g++ >= 4.8
+#if __GNUC__ >= 4
+#define ATTR_UNUSED __attribute__((unused))
+#else
+#define ATTR_UNUSED /**/
 #endif
 
 // Macro to check constants at compile time using a dummy typedef
 #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) \
-  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]
+  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
 
 #ifndef _WIN64
 #define SELECT_WIN_32_64(x32, x64) (x32)
 #define SELECT_WIN_32_64(x32, x64) (x64)
 #endif
 
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3558 2012-06-05 16:42:05Z chrfranke $";
-
-// 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
+const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3804 2013-03-27 20:39:41Z chrfranke $";
 
 /////////////////////////////////////////////////////////////////////////////
 // Windows I/O-controls, some declarations are missing in the include files
@@ -320,16 +316,6 @@ namespace os_win32 { // no need to publish anything, name provided for Doxygen
 #pragma warning(disable:4250)
 #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
 : virtual public /*implements*/ smart_device
 {
@@ -382,9 +368,10 @@ private:
   std::string m_options;
   bool m_usr_options; // options set by user?
   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_is_3ware; // AMCC/3ware controller detected?
-  int m_drive, m_port;
+  bool m_is_3ware; // LSI/3ware controller detected?
+  int m_port; // LSI/3ware port
   int m_smartver_state;
 };
 
@@ -409,32 +396,6 @@ 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
 : virtual public /*extends*/ smart_device
 {
@@ -535,58 +496,46 @@ private:
 /////////////////////////////////////////////////////////////////////////////
 /// Areca RAID support
 
-/* ARECA IO CONTROL CODE*/
-#define ARCMSR_IOCTL_READ_RQBUFFER           0x90002004
-#define ARCMSR_IOCTL_WRITE_WQBUFFER          0x90002008
-#define ARCMSR_IOCTL_CLEAR_RQBUFFER          0x9000200C
-#define ARCMSR_IOCTL_CLEAR_WQBUFFER          0x90002010
-#define ARCMSR_IOCTL_RETURN_CODE_3F          0x90002018
-#define ARECA_SIG_STR              "ARCMSR"
-
-
-// The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver
-typedef struct _SRB_IO_CONTROL
-{
-  unsigned int HeaderLength;
-  unsigned char Signature[8];
-  unsigned int Timeout;
-  unsigned int ControlCode;
-  unsigned int ReturnCode;
-  unsigned int Length;
-} sSRB_IO_CONTROL;
-
-typedef struct _SRB_BUFFER
-{
-  sSRB_IO_CONTROL srbioctl;
-  unsigned char   ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware
-} sSRB_BUFFER;
-
-class win_areca_device
-: public /*implements*/ ata_device,
+///////////////////////////////////////////////////////////////////
+// SATA(ATA) device behind Areca RAID Controller
+class win_areca_ata_device
+: public /*implements*/ areca_ata_device,
   public /*extends*/ win_smart_device
 {
 public:
-  win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum = 1);
-
-  static int arcmsr_command_handler(HANDLE fh, unsigned long arcmsr_cmd, unsigned char *data, int data_len);
-
-protected:
+  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 bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
+private:
+  HANDLE m_mutex;
+};
 
-  bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
+///////////////////////////////////////////////////////////////////
+// SAS(SCSI) device behind Areca RAID Controller
+class win_areca_scsi_device
+: public /*implements*/ areca_scsi_device,
+  public /*extends*/ win_smart_device
+{
+public:
+  win_areca_scsi_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);
 
 private:
-  int m_disknum; ///< Disk number.
-  int m_encnum;  ///< Enclosure number.
+  HANDLE m_mutex;
 };
 
 
 //////////////////////////////////////////////////////////////////////
-// Platform specific interfaces
+// Platform specific interface
 
-// Common to all windows flavors
 class win_smart_interface
 : public /*implements part of*/ smart_interface
 {
@@ -599,52 +548,14 @@ public:
   virtual int64_t get_timer_usec();
 #endif
 
-//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
-
-// Win9x/ME reduced functionality
-class win9x_smart_interface
-: public /*extends*/ win_smart_interface
-{
-public:
-  win9x_smart_interface()
-    { win9x = true; }
-
-  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:
-  bool ata_scan(smart_device_list & devlist);
-
-  bool scsi_scan(smart_device_list & devlist);
-};
-
-#endif // WIN9X_SUPPORT
-
-// WinNT,2000,XP,...
-class winnt_smart_interface
-: public /*extends*/ win_smart_interface
-{
-public:
   virtual bool disable_system_auto_standby(bool disable);
 
   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);
@@ -721,7 +632,7 @@ std::string win_smart_interface::get_os_version_str()
                                                    :   "2008r2"); break;
     case VER_PLATFORM_WIN32_NT     <<16|0x0600| 2:
       w = (vi.wProductType == VER_NT_WORKSTATION   ?   "win8"
-                                                   :   "win8s"); break;
+                                                   :   "2012"); break;
     default: w = 0; break;
   }
 
@@ -732,9 +643,9 @@ std::string win_smart_interface::get_os_version_str()
 #endif
 
   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.dwMajorVersion, vi.dwMinorVersion, w64);
+      (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
   else if (vi.wServicePackMinor)
     snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor);
   else if (vi.wServicePackMajor)
@@ -819,25 +730,17 @@ ata_device * win_smart_interface::get_ata_device(const char * name, const char *
   return new win_ata_device(this, name, type);
 }
 
-#ifdef WIN9X_SUPPORT
-
-scsi_device * win9x_smart_interface::get_scsi_device(const char * name, const char * type)
+scsi_device * win_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);
 }
 
-#endif
-
-scsi_device * winnt_smart_interface::get_scsi_device(const char * name, const char * type)
+static int sdxy_to_phydrive(const char (& xy)[2+1])
 {
-  const char * testname = skipdev(name);
-  if (!strncmp(testname, "scsi", 4))
-#if WIN9X_SUPPORT
-    return new win_aspi_device(this, name, type);
-#else
-    return (set_err(EINVAL, "ASPI interface not supported"), (scsi_device *)0);
-#endif
-  return new win_scsi_device(this, name, type);
+  int phydrive = xy[0] - 'a';
+  if (xy[1])
+    phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a');
+  return phydrive;
 }
 
 static win_dev_type get_dev_type(const char * name, int & phydrive)
@@ -857,9 +760,9 @@ static win_dev_type get_dev_type(const char * name, int & phydrive)
     return (type != DEV_UNKNOWN ? type : DEV_SCSI);
   }
 
-  char drive[1+1] = "";
-  if (sscanf(name, "sd%1[a-z]", drive) == 1) {
-    phydrive = drive[0] - 'a';
+  char drive[2+1] = "";
+  if (sscanf(name, "sd%2[a-z]", drive) == 1) {
+    phydrive = sdxy_to_phydrive(drive);
     return get_phy_drive_type(phydrive);
   }
 
@@ -869,27 +772,11 @@ static win_dev_type get_dev_type(const char * name, int & phydrive)
   return DEV_UNKNOWN;
 }
 
-smart_device * win_smart_interface::autodetect_smart_device(const char * name)
-{
-  const char * testname = skipdev(name);
-  if (!strncmp(testname, "hd", 2))
-    return new win_ata_device(this, name, "");
-#if WIN9X_SUPPORT
-  if (!strncmp(testname, "scsi", 4))
-    return new win_aspi_device(this, name, "");
-#endif
-  if (!strncmp(testname, "tw_cli", 6))
-    return new win_tw_cli_device(this, name, "");
-  return 0;
-}
-
-
-smart_device * winnt_smart_interface::get_custom_smart_device(const char * name, const char * type)
+smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type)
 {
   // Areca?
   int disknum = -1, n1 = -1, n2 = -1;
   int encnum = 1;
-  HANDLE fh = INVALID_HANDLE_VALUE;
   char devpath[32];
 
   if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
@@ -911,18 +798,16 @@ smart_device * winnt_smart_interface::get_custom_smart_device(const char * 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++) {
+     for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) {
         memset(devpath, 0, sizeof(devpath));
-        sprintf(devpath, "\\\\.\\scsi%d:", idx);
-        if ( (fh = CreateFile( devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
-                               NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE ) {
-          if (win_areca_device::arcmsr_command_handler(fh, ARCMSR_IOCTL_RETURN_CODE_3F, NULL, 0) == 0) {
-            if (ctlrindex-- == 0) {
-              return new win_areca_device(this, devpath, fh, disknum, encnum);
-            }
+        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;
           }
-          CloseHandle(fh);
         }
+        delete arcdev;
       }
       set_err(ENOENT, "No Areca controller found");
     }
@@ -933,19 +818,22 @@ smart_device * winnt_smart_interface::get_custom_smart_device(const char * name,
   return 0;
 }
 
-std::string winnt_smart_interface::get_valid_custom_dev_types_str()
+std::string win_smart_interface::get_valid_custom_dev_types_str()
 {
   return "areca,N[/E]";
 }
 
 
-smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
+smart_device * win_smart_interface::autodetect_smart_device(const char * name)
 {
-  smart_device * dev = win_smart_interface::autodetect_smart_device(name);
-  if (dev)
-    return dev;
+  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 (!strncmp(skipdev(name), "csmi", 4))
+  if (str_starts_with(testname, "csmi"))
     return new win_csmi_device(this, name, "");
 
   int phydrive = -1;
@@ -975,11 +863,9 @@ smart_device * winnt_smart_interface::autodetect_smart_device(const char * name)
 }
 
 
-#if WIN9X_SUPPORT
-
-// Scan for devices on Win9x/ME
+// Scan for devices
 
-bool win9x_smart_interface::scan_smart_devices(smart_device_list & devlist,
+bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
   const char * type, const char * pattern /* = 0*/)
 {
   if (pattern) {
@@ -987,29 +873,20 @@ bool win9x_smart_interface::scan_smart_devices(smart_device_list & devlist,
     return false;
   }
 
-  if (!type || !strcmp(type, "ata")) {
-    if (!ata_scan(devlist))
-      return false;
-  }
-
-  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;
+  // Check for "[*,]pd" type
+  bool pd = 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;
+    }
   }
 
   // Set valid types
@@ -1028,78 +905,89 @@ bool winnt_smart_interface::scan_smart_devices(smart_device_list & devlist,
     else if (!strcmp(type, "csmi"))
       csmi = true;
     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;
     }
   }
 
-  // Scan up to 10 drives and 2 3ware controllers
-  const int max_raid = 2;
-  bool raid_seen[max_raid] = {false, false};
-
   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))) {
-      case DEV_ATA:
-        // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA
-        if (!ata)
-          continue;
 
-        // Interpret RAID drive map if present
-        if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
-          // Skip if too many controllers or logical drive from this controller already seen
-          if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
+  if (ata || scsi || usb) {
+    // Scan up to 128 drives and 2 3ware controllers
+    const int max_raid = 2;
+    bool raid_seen[max_raid] = {false, false};
+
+    for (int i = 0; i < 128; i++) {
+      if (pd)
+        snprintf(name, sizeof(name), "/dev/pd%d", i);
+      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;
-          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)) {
-              sprintf(name+len, ",%u", pi);
-              devlist.push_back( new win_ata_device(this, name, "ata") );
+
+          // Interpret RAID drive map if present
+          if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) {
+            // Skip if too many controllers or logical drive from this controller already seen
+            if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId]))
+              continue;
+            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 {
-          devlist.push_back( new win_ata_device(this, name, "ata") );
-        }
-        break;
-
-      case DEV_SCSI:
-        // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
-        if (!scsi)
-          continue;
-        devlist.push_back( new win_scsi_device(this, name, "scsi") );
-        break;
+          else {
+            devlist.push_back( new win_ata_device(this, name, "ata") );
+          }
+          break;
 
-      case DEV_USB:
-        // STORAGE_QUERY_PROPERTY returned 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;
-          // Get type name for this ID
-          const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
-          if (!usbtype)
+        case DEV_SCSI:
+          // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
+          if (!scsi)
             continue;
-          // Return SAT/USB device for this type
-          ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, ""));
-          if (!dev)
+          devlist.push_back( new win_scsi_device(this, name, "scsi") );
+          break;
+
+        case DEV_USB:
+          // STORAGE_QUERY_PROPERTY returned USB
+          if (!usb)
             continue;
-          devlist.push_back(dev);
-        }
-        break;
+          {
+            // 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;
+            // Get type name for this ID
+            const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
+            if (!usbtype)
+              continue;
+            // 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:
-        // Unknown type
-        break;
+        default:
+          // Unknown type
+          break;
+      }
     }
   }
 
@@ -1132,20 +1020,16 @@ std::string win_smart_interface::get_app_examples(const char * appname)
   if (strcmp(appname, "smartctl"))
     return "";
   return "=================================================== SMARTCTL EXAMPLES =====\n\n"
-         "  smartctl -a /dev/hda                       (Prints all SMART information)\n\n"
-         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n"
+         "  smartctl -a /dev/sda                       (Prints all SMART information)\n\n"
+         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n"
          "                                              (Enables SMART on first disk)\n\n"
-         "  smartctl -t long /dev/hda              (Executes extended disk self-test)\n\n"
-         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n"
+         "  smartctl -t long /dev/sda              (Executes extended disk self-test)\n\n"
+         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\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"
-         "             (Prints all information for SCSI disk on PhysicalDrive 0)\n"
+         "             (Prints all information for disk on PhysicalDrive 0)\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"
          "             (Prints all information for SCSI tape on Tape 1)\n"
          "  smartctl -A /dev/hdb,3\n"
@@ -1159,15 +1043,15 @@ std::string win_smart_interface::get_app_examples(const char * appname)
          "  ATA SMART access methods and ordering may be specified by modifiers\n"
          "  following the device name: /dev/hdX:[saicm], where\n"
          "  's': SMART_* IOCTLs,         'a': IOCTL_ATA_PASS_THROUGH,\n"
-         "  'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n"
-         "  'f': IOCTL_STORAGE_*,        'm': IOCTL_SCSI_MINIPORT_*.\n"
+         "  'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n"
+         "  'm': IOCTL_SCSI_MINIPORT_*.\n"
       + strprintf(
          "  The default on this system is /dev/sdX:%s\n", ata_get_def_options()
         );
 }
 
 
-bool winnt_smart_interface::disable_system_auto_standby(bool disable)
+bool win_smart_interface::disable_system_auto_standby(bool disable)
 {
   if (disable) {
     SYSTEM_POWER_STATUS ps;
@@ -1199,8 +1083,8 @@ bool winnt_smart_interface::disable_system_auto_standby(bool disable)
 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",
-  (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
-  r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
+    (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg,
+    r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);
 }
 
 static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro)
@@ -1224,20 +1108,20 @@ static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version
   if (!DeviceIoControl(hdevice, SMART_GET_VERSION,
     NULL, 0, &vers, sizeof(vers), &num_out, NULL)) {
     if (ata_debugmode)
-      pout("  SMART_GET_VERSION failed, Error=%ld\n", GetLastError());
+      pout("  SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError());
     errno = ENOSYS;
     return -1;
   }
   assert(num_out == sizeof(GETVERSIONINPARAMS));
 
   if (ata_debugmode > 1) {
-    pout("  SMART_GET_VERSION suceeded, bytes returned: %lu\n"
-         "    Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n",
-      num_out, vers.bVersion, vers.bRevision,
-      vers.fCapabilities, vers.bIDEDeviceMap);
+    pout("  SMART_GET_VERSION suceeded, bytes returned: %u\n"
+         "    Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n",
+      (unsigned)num_out, vers.bVersion, vers.bRevision,
+      (unsigned)vers.fCapabilities, vers.bIDEDeviceMap);
     if (vers_ex.wIdentifier == SMART_VENDOR_3WARE)
-      pout("    Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n",
-      vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx);
+      pout("    Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n",
+      vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx);
   }
 
   if (ata_version_ex)
@@ -1250,7 +1134,7 @@ static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version
 
 // 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_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar;
@@ -1263,9 +1147,14 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
 
   memset(&inpar, 0, sizeof(inpar));
   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) {
     // Set RAID port
@@ -1294,7 +1183,7 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
 
   if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1,
     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();
     if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) {
       pout("  %s failed, Error=%ld\n", name, err);
@@ -1320,8 +1209,8 @@ static int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, u
   }
 
   if (ata_debugmode > 1) {
-    pout("  %s suceeded, bytes returned: %lu (buffer %lu)\n", name,
-      num_out, outpar->cBufferSize);
+    pout("  %s suceeded, bytes returned: %u (buffer %u)\n", name,
+      (unsigned)num_out, (unsigned)outpar->cBufferSize);
     print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ?
       (const IDEREGS *)(outpar->bBuffer) : NULL));
   }
@@ -1397,8 +1286,8 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
     if (   num_out != size
         || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) {
       if (ata_debugmode) {
-        pout("  IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n",
-          num_out, buf->DataBufferSize);
+        pout("  IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n",
+          (unsigned)num_out, (unsigned)buf->DataBufferSize);
         print_ide_regs_io(regs, &buf->IdeReg);
       }
       VirtualFree(buf, 0, MEM_RELEASE);
@@ -1409,8 +1298,8 @@ static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, u
   }
 
   if (ata_debugmode > 1) {
-    pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n",
-      num_out, buf->DataBufferSize);
+    pout("  IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n",
+      (unsigned)num_out, (unsigned)buf->DataBufferSize);
     print_ide_regs_io(regs, &buf->IdeReg);
   }
   *regs = buf->IdeReg;
@@ -1516,7 +1405,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
     if (   num_out != size
         || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) {
       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);
       }
       errno = EIO;
@@ -1526,7 +1415,7 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
   }
 
   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);
   }
   *regs = *ctfregs;
@@ -1537,91 +1426,6 @@ static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev
 }
 
 
-/////////////////////////////////////////////////////////////////////////////
-// 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
 
@@ -1724,7 +1528,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
   // Check result
   if (sb.srbc.ReturnCode) {
     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);
     }
     errno = EIO;
@@ -1742,8 +1546,8 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
   }
 
   if (ata_debugmode > 1) {
-    pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name,
-      num_out, sb.params.out.cBufferSize);
+    pout("  IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name,
+      (unsigned)num_out, (unsigned)sb.params.out.cBufferSize);
     print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ?
                              (const IDEREGS *)(sb.params.out.bBuffer) : 0));
   }
@@ -1775,7 +1579,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
     return -1;
   }
   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.Timeout = 60; // seconds
   sb.srbc.ControlCode = 0xA0000000;
@@ -1798,7 +1602,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
 
   if (sb.srbc.ReturnCode) {
     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);
     }
     errno = EIO;
@@ -1810,7 +1614,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
     memcpy(data, sb.buffer, datasize);
 
   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);
   }
   *regs = sb.regs;
@@ -1828,7 +1632,7 @@ static int update_3ware_devicemap_ioctl(HANDLE hdevice)
 {
   SRB_IO_CONTROL 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.Timeout = 60; // seconds
   srbc.ControlCode = 0xCC010014;
@@ -1846,7 +1650,7 @@ static int update_3ware_devicemap_ioctl(HANDLE hdevice)
   }
   if (srbc.ReturnCode) {
     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;
     return -1;
   }
@@ -2135,7 +1939,7 @@ static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTO
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
     &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) {
     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;
     return -1;
   }
@@ -2173,16 +1977,16 @@ static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0)
   if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE,
     0, 0, &pred, sizeof(pred), &num_out, NULL)) {
     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;
     return -1;
   }
 
   if (ata_debugmode > 1) {
     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",
-         pred.PredictFailure,
+         (unsigned)pred.PredictFailure,
          pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2],
          pred.VendorSpecific[sizeof(pred.VendorSpecific)-1]
     );
@@ -2330,6 +2134,31 @@ static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device
   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;
+  if (!ws.connect()) {
+    if (debug)
+      pout("WMI connect failed\n");
+    return false;
+  }
+
+  wbem_object wo;
+  if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE "
+                     "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
+    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
@@ -2416,7 +2245,7 @@ static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & p
         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 (debug)
           pout("  +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str());
@@ -2459,43 +2288,14 @@ static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & p
 
 /////////////////////////////////////////////////////////////////////////////
 
-// Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)
+// Call GetDevicePowerState()
 // returns: 1=active, 0=standby, -1=error
 // (This would also work for SCSI drives)
 
 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;
-  if (!GetDevicePowerState_p(hdevice, &state)) {
+  if (!GetDevicePowerState(hdevice, &state)) {
     long err = GetLastError();
     if (ata_debugmode)
       pout("  GetDevicePowerState() failed, Error=%ld\n", err);
@@ -2513,68 +2313,12 @@ 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
 
 static const char * ata_get_def_options()
 {
-  DWORD ver = GetVersion();
-  if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME
-    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_*
+  return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH,
+                   // STORAGE_*, SCSI_MINIPORT_*
 }
 
 
@@ -2606,9 +2350,9 @@ win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, co
 : smart_device(intf, dev_name, "ata", req_type),
   m_usr_options(false),
   m_admin(false),
+  m_phydrive(-1),
   m_id_is_cached(false),
   m_is_3ware(false),
-  m_drive(0),
   m_port(-1),
   m_smartver_state(0)
 {
@@ -2624,18 +2368,18 @@ win_ata_device::~win_ata_device() throw()
 bool win_ata_device::open()
 {
   const char * name = skipdev(get_dev_name()); int len = strlen(name);
-  // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options
-  char drive[1+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
-      && ((n1 == len && !options[0]) || n2 == len)                                       ) {
-    return open(drive[0] - 'a', -1, options, -1);
+  // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options
+  char drive[2+1] = "", options[8+1] = ""; int n1 = -1, 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)                                   ) {
+    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;
   unsigned port = ~0;
-  if (   sscanf(name, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2
-      && port < 32 && ((n1 == len && !options[0]) || n2 == len)                                     ) {
-    return open(drive[0] - 'a', -1, options, port);
+  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)                                  ) {
+    return open(sdxy_to_phydrive(drive), -1, options, port);
   }
   // pd<m>,N => Physical drive <m>, RAID port N
   int phydrive = -1; port = ~0; n1 = -1; n2 = -1;
@@ -2655,28 +2399,25 @@ bool win_ata_device::open()
 
 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];
-  if (win9x && 0 <= phydrive && phydrive <= 7)
-    // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details
-    strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE"));
-  else if (!win9x && 0 <= phydrive && phydrive <= 255)
-    snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive);
-  else if (!win9x && 0 <= logdrive && logdrive <= 'Z'-'A')
+  if (0 <= phydrive && phydrive <= 255)
+    snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive));
+  else if (0 <= logdrive && logdrive <= 'Z'-'A')
     snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive);
   else
     return set_err(ENOENT);
 
   // Open device
   HANDLE h = INVALID_HANDLE_VALUE;
-  if (win9x || !(*options && !options[strspn(options, "fp")])) {
+  if (!(*options && !options[strspn(options, "fp")])) {
     // Open with admin rights
     m_admin = true;
     h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,
       NULL, OPEN_EXISTING, 0, 0);
   }
-  if (!win9x && h == INVALID_HANDLE_VALUE) {
+  if (h == INVALID_HANDLE_VALUE) {
     // Open without admin rights
     m_admin = false;
     h = CreateFileA(devpath, 0,
@@ -2685,10 +2426,6 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
   }
   if (h == INVALID_HANDLE_VALUE) {
     long err = GetLastError();
-#if WIN9X_SUPPORT
-    if (win9x && phydrive <= 3 && err == ERROR_FILE_NOT_FOUND)
-      smartvsd_error();
-#endif
     if (err == ERROR_FILE_NOT_FOUND)
       set_err(ENOENT, "%s: not found", devpath);
     else if (err == ERROR_ACCESS_DENIED)
@@ -2725,13 +2462,12 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
     m_options = def_options;
   }
 
-  // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
-  m_drive = 0; m_port = port;
-  if (!win9x && port < 0)
+  // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call
+  m_port = port;
+  if (port < 0)
     return true;
 
-  // Win9X/ME: Get drive map
-  // RAID: Get port map
+  // 3ware RAID: Get port map
   GETVERSIONINPARAMS_EX vers_ex;
   int devmap = smart_get_version(h, &vers_ex);
 
@@ -2760,7 +2496,7 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
   }
   m_smartver_state = 1;
 
-  if (port >= 0) {
+  {
     // 3ware RAID: update devicemap first
 
     if (!update_3ware_devicemap_ioctl(h)) {
@@ -2775,75 +2511,23 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
         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;
 }
 
 
-#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
 bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 {
   // No multi-sector support for now, see above
   // warning about IOCTL_ATA_PASS_THROUGH
-  if (!ata_cmd_is_ok(in,
-    true, // data_out_support
-    false, // !multi_sector_support
-    true) // ata_48bit_support
+  if (!ata_cmd_is_supported(in,
+    ata_device::supports_data_out |
+    ata_device::supports_output_regs |
+    ata_device::supports_48bit)
   )
     return false;
 
@@ -2861,7 +2545,7 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
     case ATA_IDENTIFY_PACKET_DEVICE:
       // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
       // and SCSI_MINIPORT_* if requested by user
-      valid_options = (m_usr_options ? "saicmf" : "saicf");
+      valid_options = (m_usr_options ? "saimf" : "saif");
       break;
 
     case ATA_CHECK_POWER_MODE:
@@ -2879,21 +2563,21 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         case ATA_SMART_AUTO_OFFLINE:
           // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE
           // and SCSI_MINIPORT_* if requested by user
-          valid_options = (m_usr_options ? "saicmf" : "saicf");
+          valid_options = (m_usr_options ? "saimf" : "saif");
           break;
 
         case ATA_SMART_IMMEDIATE_OFFLINE:
-          // SMART_SEND_DRIVE_COMMAND supports ABORT_SELF_TEST only on Win9x/ME
-          valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ || win9x ?
-                           "saicm3" : "aicm3");
+          // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST
+          valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ?
+                           "saim3" : "aim3");
           break;
 
         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
           // SMART functions do not support multi sector I/O.
           if (in.size == 512)
-            valid_options = (m_usr_options || win9x ? "saicm3" : "aicm3");
+            valid_options = (m_usr_options ? "saim3" : "aim3");
           else
             valid_options = "a";
           break;
@@ -2905,11 +2589,7 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
           break;
 
         case ATA_SMART_STATUS:
-          // May require lba_mid,lba_high register return
-          if (in.out_needed.is_set())
-            valid_options = (m_usr_options ? "saimf" : "saif");
-          else
-            valid_options = (m_usr_options ? "saicmf" : "saicf");
+          valid_options = (m_usr_options ? "saimf" : "saif");
           break;
 
         default:
@@ -2930,11 +2610,9 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
          ||  in.in_regs.is_48bit_cmd()                               )
       // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only
       valid_options = "a";
-    else if (in.out_needed.is_set())
-      // Need output registers: ATA/IDE_PASS_THROUGH
-      valid_options = "ai";
     else
-      valid_options = "aic";
+      // ATA/IDE_PASS_THROUGH
+      valid_options = "ai";
   }
 
   if (!m_admin) {
@@ -3047,13 +2725,13 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 
           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);
-        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;
       case 'm':
         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;
       case 'a':
         rc = ata_pass_through_ioctl(get_fh(), &regs,
@@ -3065,12 +2743,11 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         rc = ide_pass_through_ioctl(get_fh(), &regs, data, datasize);
         out_regs_set = true;
         break;
-      case 'c':
-        rc = ata_via_scsi_pass_through_ioctl(get_fh(), &regs, data, datasize);
-        break;
       case 'f':
         if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
             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;
         }
         else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
@@ -3261,10 +2938,12 @@ bool csmi_device::select_phy(unsigned phy_no)
 
 bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 {
-  if (!ata_cmd_is_ok(in,
-    true, // data_out_support
-    true, // multi_sector_support
-    true) // ata_48bit_support
+  if (!ata_cmd_is_supported(in,
+    ata_device::supports_data_out |
+    ata_device::supports_output_regs |
+    ata_device::supports_multi_sector |
+    ata_device::supports_48bit,
+    "CMSI")
   )
     return false;
 
@@ -3479,556 +3158,19 @@ bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer,
   // Check result
   if (csmi_buffer->ReturnCode) {
     if (scsi_debugmode) {
-      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%lu\n",
-        code, csmi_buffer->ReturnCode);
+      pout("  IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n",
+        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)
-    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;
 }
 
 
-/////////////////////////////////////////////////////////////////////////////
-// 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("%s", 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)
 // Only supported in NT and later
@@ -4043,11 +3185,11 @@ win_scsi_device::win_scsi_device(smart_interface * intf,
 bool win_scsi_device::open()
 {
   const char * name = skipdev(get_dev_name()); int len = strlen(name);
-  // sd[a-z],N => Physical drive 0-26, RAID port N
-  char drive[1+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
+  // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N
+  char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int 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))  ) {
-    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
   int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1;
@@ -4098,7 +3240,7 @@ bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*
            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
            OPEN_EXISTING, 0, 0);
   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;
   }
   set_fh(h);
@@ -4285,7 +3427,7 @@ bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop)
 }
 
 // Interface to SPT SCSI devices.  See scsicmds.h and os_linux.c
-static long scsi_pass_through_direct(HANDLE fd, struct scsi_cmnd_io * iop)
+static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop)
 {
   int report = scsi_debugmode; // TODO
 
@@ -4322,7 +3464,7 @@ static long scsi_pass_through_direct(HANDLE fd, struct scsi_cmnd_io * iop)
   memset(&sb, 0, sizeof(sb));
   sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
   //sb.spt.PathId = 0;
-  sb.spt.TargetId = 127;
+  sb.spt.TargetId = targetid;
   //sb.spt.Lun = 0;
   sb.spt.CdbLength = iop->cmnd_len;
   memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len);
@@ -4411,229 +3553,109 @@ static long scsi_pass_through_direct(HANDLE fd, struct scsi_cmnd_io * iop)
   return 0;
 }
 
-
-#if 0 // For debugging areca code
-
-static void dumpdata(unsigned char *block, int len)
+// 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")
 {
-  int ln = (len / 16) + 1;   // total line#
-  unsigned char c;
-  int pos = 0;
-
-  printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
-  printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");
-  printf("=====================================================================\n");
-
-  for ( int l = 0; l < ln && len; l++ )
-  {
-    // printf the line# and the HEX data
-    // if a line data length < 16 then append the space to the tail of line to reach 16 chars
-    printf("%02X | ", l);
-    for ( pos = 0; pos < 16 && len; pos++, len-- )
-    {
-      c = block[l*16+pos];
-      printf("%02X ", c);
-    }
-
-    if ( pos < 16 )
-    {
-      for ( int loop = pos; loop < 16; loop++ )
-      {
-        printf("   ");
-      }
-    }
-
-    // print ASCII char
-    for ( int loop = 0; loop < pos; loop++ )
-    {
-      c = block[l*16+loop];
-      if ( c >= 0x20 && c <= 0x7F )
-      {
-        printf("%c", c);
-      }
-      else
-      {
-        printf(".");
-      }
-    }
-    printf("\n");
-  }
-  printf("=====================================================================\n");
+    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);
 }
 
-#endif
-
-// PURPOSE
-//   This is an interface routine meant to isolate the OS dependent
-//   parts of the code, and to provide a debugging interface.  Each
-//   different port and OS needs to provide it's own interface.  This
-//   is the Windows interface to the Areca "arcmsr" driver.  It allows ATA
-//   commands to be passed through the SCSI driver.
-// DETAILED DESCRIPTION OF ARGUMENTS
-//   fd: is the file descriptor provided by open()
-//   disknum is the disk number (0 to 127) in the RAID array
-//   command: defines the different operations.
-//   select: additional input data if needed (which log, which type of
-//           self-test).
-//   data:   location to write output data, if needed (512 bytes).
-//   Note: not all commands use all arguments.
-// RETURN VALUES
-//  -1 if the command failed
-//   0 if the command succeeded,
-//   STATUS_CHECK routine:
-//  -1 if the command failed
-//   0 if the command succeeded and disk SMART status is "OK"
-//   1 if the command succeeded and disk SMART status is "FAILING"
-int win_areca_device::arcmsr_command_handler(HANDLE fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len)
+bool win_areca_scsi_device::open()
 {
-  int ioctlreturn = 0;
-  sSRB_BUFFER sBuf;
-  struct scsi_cmnd_io io_hdr;
-  int dir = DXFER_TO_DEVICE;
-
-  UINT8 cdb[10];
-  UINT8 sense[32];
-
-  unsigned char *areca_return_packet;
-  int total = 0;
-  int expected = -1;
-  unsigned char return_buff[2048];
-  unsigned char *ptr = &return_buff[0];
-  memset(return_buff, 0, sizeof(return_buff));
-
-  memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
-  memset(&io_hdr, 0, sizeof(io_hdr));
-  memset(cdb, 0, sizeof(cdb));
-  memset(sense, 0, sizeof(sense));
-
-
-  sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL);
-  memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
-  sBuf.srbioctl.Timeout = 10000;
-  sBuf.srbioctl.ControlCode = arcmsr_cmd;
+  HANDLE hFh;
 
-  switch ( arcmsr_cmd )
+  if( is_open() )
   {
-  // command for writing data to driver
-  case ARCMSR_IOCTL_WRITE_WQBUFFER:
-    if ( data && data_len )
-    {
-      sBuf.srbioctl.Length = data_len;
-      memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
-    }
-    // commands for clearing related buffer of driver
-  case ARCMSR_IOCTL_CLEAR_RQBUFFER:
-  case ARCMSR_IOCTL_CLEAR_WQBUFFER:
-    cdb[0] = 0x3B; //SCSI_WRITE_BUF command;
-    break;
-  // command for reading data from driver
-  case ARCMSR_IOCTL_READ_RQBUFFER:
-  // command for identifying driver
-  case ARCMSR_IOCTL_RETURN_CODE_3F:
-    cdb[0] = 0x3C; //SCSI_READ_BUF command;
-    dir = DXFER_FROM_DEVICE;
-    break;
-  default:
-    // unknown arcmsr commands
-    return -1;
+    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;
   }
 
-  cdb[1] = 0x01;
-  cdb[2] = 0xf0;
+  set_fh(hFh);
+  return true;
+}
 
-  io_hdr.dxfer_dir = dir;
-  io_hdr.dxfer_len = sizeof(sBuf);
-  io_hdr.dxferp = (unsigned char *)&sBuf;
-  io_hdr.cmnd = cdb;
-  io_hdr.cmnd_len = sizeof(cdb);
-  io_hdr.sensep = sense;
-  io_hdr.max_sense_len = sizeof(sense);
-  io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
+smart_device * win_areca_scsi_device::autodetect_open()
+{
+  return this;
+}
 
-  while ( 1 )
-  {
-    ioctlreturn = scsi_pass_through_direct(fd, &io_hdr);
-    if ( ioctlreturn || io_hdr.scsi_status )
-    {
-      // errors found
-      break;
-    }
+int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
+{
+   int ioctlreturn = 0;
 
-    if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER )
-    {
-      // if succeeded, just returns the length of outgoing data
-      return data_len;
-    }
+   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;
+     }
+   }
 
-    if ( sBuf.srbioctl.Length )
-    {
-      //dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
-      memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
-      ptr += sBuf.srbioctl.Length;
-      total += sBuf.srbioctl.Length;
-      // the returned bytes enough to compute payload length ?
-      if ( expected < 0 && total >= 5 )
-      {
-        areca_return_packet = (unsigned char *)&return_buff[0];
-        if ( areca_return_packet[0] == 0x5E &&
-           areca_return_packet[1] == 0x01 &&
-           areca_return_packet[2] == 0x61 )
-        {
-          // valid header, let's compute the returned payload length,
-          // we expected the total length is
-          // payload + 3 bytes header + 2 bytes length + 1 byte checksum
-          expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
-        }
-      }
+   return ioctlreturn;
+}
 
-      if ( total >= 7 && total >= expected )
-      {
-        //printf("total bytes received = %d, expected length = %d\n", total, expected);
+bool win_areca_scsi_device::arcmsr_lock()
+{
+#define    SYNCOBJNAME "Global\\SynIoctlMutex"
+  int ctlrnum = -1;
+  char mutexstr[64];
 
-        // ------ Okay! we received enough --------
-        break;
-      }
-    }
-  }
+  if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
+    return set_err(EINVAL, "unable to parse device name");
 
-  // Deal with the different error cases
-  if ( arcmsr_cmd == ARCMSR_IOCTL_RETURN_CODE_3F )
+  snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
+  m_mutex = CreateMutex(NULL, FALSE, mutexstr);
+  if ( m_mutex == NULL )
   {
-    // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...)
-    return -4;
+    return set_err(EIO, "CreateMutex failed");
   }
 
-  if ( ioctlreturn )
-  {
-    pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
-    return -2;
-  }
+  // atomic access to driver
+  WaitForSingleObject(m_mutex, INFINITE);
+
+  return true;
+}
 
-  if ( io_hdr.scsi_status )
-  {
-    pout("io_hdr.scsi_status with write buffer failed code = %x\n", io_hdr.scsi_status);
-    return -3;
-  }
 
-  if ( data )
+bool win_areca_scsi_device::arcmsr_unlock()
+{
+  if( m_mutex != NULL)
   {
-    memcpy(data, return_buff, total);
+      ReleaseMutex(m_mutex);
+      CloseHandle(m_mutex);
   }
 
-  return total;
+  return true;
 }
 
 
-win_areca_device::win_areca_device(smart_interface * intf, const char * dev_name, HANDLE fh, int disknum, int encnum)
-: smart_device(intf, dev_name, "areca", "areca"),
-  m_disknum(disknum),
-  m_encnum(encnum)
+// 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(fh);
+  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_device::open()
+bool win_areca_ata_device::open()
 {
   HANDLE hFh;
 
@@ -4641,7 +3663,6 @@ bool win_areca_device::open()
   {
     return true;
   }
-
   hFh = CreateFile( get_dev_name(),
                     GENERIC_READ|GENERIC_WRITE,
                     FILE_SHARE_READ|FILE_SHARE_WRITE,
@@ -4658,256 +3679,83 @@ bool win_areca_device::open()
   return true;
 }
 
-// Areca RAID Controller
-bool win_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
+smart_device * win_areca_ata_device::autodetect_open()
 {
-  // ATA input registers
-  typedef struct _ATA_INPUT_REGISTERS
-  {
-    unsigned char features;
-    unsigned char sector_count;
-    unsigned char sector_number;
-    unsigned char cylinder_low;
-    unsigned char cylinder_high;
-    unsigned char device_head;
-    unsigned char command;
-    unsigned char reserved[8];
-    unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
-  } sATA_INPUT_REGISTERS;
-
-  // ATA output registers
-  // Note: The output registers is re-sorted for areca internal use only
-  typedef struct _ATA_OUTPUT_REGISTERS
-  {
-    unsigned char error;
-    unsigned char status;
-    unsigned char sector_count;
-    unsigned char sector_number;
-    unsigned char cylinder_low;
-    unsigned char cylinder_high;
-  } sATA_OUTPUT_REGISTERS;
-
-  // Areca packet format for outgoing:
-  // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
-  // B[3~4] : 2 bytes command length + variant data length, little endian
-  // B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
-  // B[6~last-1] : variant bytes payload data
-  // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
-  //
-  //
-  //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte
-  // +--------------------------------------------------------------------------------+
-  // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
-  // +--------------------------------------------------------------------------------+
-  //
-
-  //Areca packet format for incoming:
-  // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
-  // B[3~4] : 2 bytes payload length, little endian
-  // B[5~last-1] : variant bytes returned payload data
-  // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
-  //
-  //
-  //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte
-  // +-------------------------------------------------------------------+
-  // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
-  // +-------------------------------------------------------------------+
-  unsigned char    areca_packet[640];
-  int areca_packet_len = sizeof(areca_packet);
-  unsigned char cs = 0;
-
-  sATA_INPUT_REGISTERS *ata_cmd;
-
-  // For debugging
-#if 0
-  memset(sInq, 0, sizeof(sInq));
-  scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq));
-  dumpdata((unsigned char *)sInq, sizeof(sInq));
-#endif
-  memset(areca_packet, 0, areca_packet_len);
+  int is_ata = 1;
 
-  // ----- BEGIN TO SETUP HEADERS -------
-  areca_packet[0] = 0x5E;
-  areca_packet[1] = 0x01;
-  areca_packet[2] = 0x61;
-  areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
-  areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
-  areca_packet[5] = 0x1c;  // areca defined code for ATA passthrough command
-
-  // ----- BEGIN TO SETUP PAYLOAD DATA -----
-  memcpy(&areca_packet[7], "SmrT", 4);  // areca defined password
-  ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
-
-  // Set registers
-  {
-    const ata_in_regs & r = in.in_regs;
-    ata_cmd->features      = r.features;
-    ata_cmd->sector_count  = r.sector_count;
-    ata_cmd->sector_number = r.lba_low;
-    ata_cmd->cylinder_low  = r.lba_mid;
-    ata_cmd->cylinder_high = r.lba_high;
-    ata_cmd->device_head   = r.device;
-    ata_cmd->command       = r.command;
-  }
-  bool readdata = false;
-  if (in.direction == ata_cmd_in::data_in) {
-      readdata = true;
-      // the command will read data
-      areca_packet[6] = 0x13;
-  }
-  else if ( in.direction == ata_cmd_in::no_data )
+  // autodetect device type
+  is_ata = arcmsr_get_dev_type();
+  if(is_ata < 0)
   {
-    // the commands will return no data
-    areca_packet[6] = 0x15;
+    set_err(EIO);
+    return this;
   }
-  else if (in.direction == ata_cmd_in::data_out)
-  {
-    // the commands will write data
-    memcpy(ata_cmd->data, in.buffer, in.size);
-    areca_packet[6] = 0x14;
-  }
-  else {
-      // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
-      return set_err(ENOSYS);
-  }
-
-  areca_packet[11] = m_disknum - 1;  // disk#
-  areca_packet[19] = m_encnum - 1;   // enc#
 
-  // ----- BEGIN TO SETUP CHECKSUM -----
-  for ( int loop = 3; loop < areca_packet_len - 1; loop++ )
+  if(is_ata == 1)
   {
-    cs += areca_packet[loop];
-  }
-  areca_packet[areca_packet_len-1] = cs;
-
-  // ----- BEGIN TO SEND TO ARECA DRIVER ------
-  int expected = 0;
-  unsigned char return_buff[2048];
-  memset(return_buff, 0, sizeof(return_buff));
-
-  expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0);
-  if (expected==-3) {
-      return set_err(EIO);
+    // SATA device
+    return this;
   }
 
-  expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0);
-  expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len);
-  if ( expected > 0 )
-  {
-    expected = arcmsr_command_handler(get_fh(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff));
-  }
-  if ( expected < 0 )
-  {
-    return set_err(EIO);
-  }
+  // 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
 
-  // ----- VERIFY THE CHECKSUM -----
-  cs = 0;
-  for ( int loop = 3; loop < expected - 1; loop++ )
-  {
-    cs += return_buff[loop];
-  }
+  return newdev.release();
+}
 
-  if ( return_buff[expected - 1] != cs )
-  {
-    return set_err(EIO);
-  }
+int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
+{
+   int ioctlreturn = 0;
 
-  sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
-  if ( ata_out->status )
-  {
-    if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
-     && !nonempty((unsigned char *)in.buffer, in.size))
+   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 )
      {
-        return set_err(ENODEV, "No drive on port %d", m_disknum);
+       // errors found
+       return -1;
      }
-  }
+   }
 
-  // returns with data
-  if (readdata)
-  {
-    memcpy(in.buffer, &return_buff[7], in.size);
-  }
-
-  // Return register values
-  {
-    ata_out_regs & r = out.out_regs;
-    r.error          = ata_out->error;
-    r.sector_count   = ata_out->sector_count;
-    r.lba_low        = ata_out->sector_number;
-    r.lba_mid        = ata_out->cylinder_low;
-    r.lba_high       = ata_out->cylinder_high;
-    r.status         = ata_out->status;
-  }
-  return true;
+   return ioctlreturn;
 }
 
-
-bool win_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
+bool win_areca_ata_device::arcmsr_lock()
 {
 #define    SYNCOBJNAME "Global\\SynIoctlMutex"
   int ctlrnum = -1;
   char mutexstr[64];
-  SECURITY_ATTRIBUTES sa;
-  PSECURITY_DESCRIPTOR pSD;
-  HANDLE hmutex;
-
-  if (!ata_cmd_is_ok(in,
-    true, // data_out_support
-    false, // TODO: multi_sector_support
-    true) // ata_48bit_support
-  )
-    return false;
-
-  // Support 48-bit commands with zero high bytes
-  if (in.in_regs.is_real_48bit_cmd())
-    return set_err(ENOSYS, "48-bit ATA commands not fully supported by Areca");
 
   if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1)
     return set_err(EINVAL, "unable to parse device name");
 
-  memset(mutexstr, 0, sizeof(mutexstr));
-  sprintf(mutexstr, "%s%d",SYNCOBJNAME, ctlrnum);
-  pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
-  if ( !InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) )
+  snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum);
+  m_mutex = CreateMutex(NULL, FALSE, mutexstr);
+  if ( m_mutex == NULL )
   {
-    LocalFree((HLOCAL)pSD);
-    return set_err(EIO, "InitializeSecurityDescriptor failed");
-  }
-
-  if ( !SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE) )
-  {
-    LocalFree((HLOCAL)pSD);
-    return set_err(EIO, "SetSecurityDescriptor failed");
-  }
-
-  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-  sa.lpSecurityDescriptor = pSD;
-  sa.bInheritHandle = TRUE;
-  hmutex = CreateMutex(&sa, FALSE, mutexstr);
-  if ( hmutex == NULL )
-  {
-    LocalFree((HLOCAL)pSD);
     return set_err(EIO, "CreateMutex failed");
   }
 
   // atomic access to driver
-  WaitForSingleObject(hmutex, INFINITE);
-  bool ok = arcmsr_ata_pass_through(in,out);
-  ReleaseMutex(hmutex);
+  WaitForSingleObject(m_mutex, INFINITE);
 
-  if(hmutex)
-  {
-    CloseHandle(hmutex);
-  }
+  return true;
+}
 
-  if ( (HLOCAL)pSD )
+
+bool win_areca_ata_device::arcmsr_unlock()
+{
+  if( m_mutex != NULL)
   {
-    LocalFree((HLOCAL)pSD);
+      ReleaseMutex(m_mutex);
+      CloseHandle(m_mutex);
   }
 
-  return ok;
+  return true;
 }
 
 
@@ -4930,19 +3778,8 @@ void smart_interface::init()
       SetDllDirectoryA_p("");
   }
 
-  // Select interface for Windows flavor
-  if (GetVersion() & 0x80000000) {
-#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);
-  }
+  static os_win32::win_smart_interface the_win_interface;
+  smart_interface::set(&the_win_interface);
 }