diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 685131491b57eb9ca48e4300eb3288a963663c97..127448b82bfd8ae1a713b98894d37fd1e4b36d29 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.712 2008/08/23 15:38:20 chrfranke Exp $
+$Id: CHANGELOG,v 1.713 2008/08/23 17:07:16 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -39,6 +39,9 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Add 'ata_cmd_is_ok()' parameter check,
+       remove 'ata_pass_through_28/48bit()' functions.
+
   [CF] Add CVS date/time from cvsversion.h to man pages also.
 
   [CF] Add configure option '--with-os-deps='os_module.o ...' to specify
diff --git a/sm5/dev_ata_cmd_set.cpp b/sm5/dev_ata_cmd_set.cpp
index 73bf83daeec22ac0db9b0683da2004a0502a6b08..aa0b4f8fee2b83328498aa08ded49ee326a39f49 100644
--- a/sm5/dev_ata_cmd_set.cpp
+++ b/sm5/dev_ata_cmd_set.cpp
@@ -22,7 +22,7 @@
 
 #include <errno.h>
 
-const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp,v 1.2 2008/08/16 16:49:15 chrfranke Exp $"
+const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp,v 1.3 2008/08/23 17:07:16 chrfranke Exp $"
   DEV_ATA_CMD_SET_H_CVSID;
 
 
@@ -31,10 +31,10 @@ const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp,v 1.2 2008/08
 
 // Adapter routine to implement new ATA pass through with old interface
 
-bool ata_device_with_command_set::ata_pass_through_28bit(const ata_cmd_in & in, ata_cmd_out & out)
+bool ata_device_with_command_set::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
 {
-  if (!(in.size == 0 || in.size == 512))
-    return set_err(ENOSYS, "Multi sector I/O not implemented");
+  if (!ata_cmd_is_ok(in, true)) // data_out_support
+    return false;
 
   smart_command_set command = (smart_command_set)-1;
   int select = 0;
diff --git a/sm5/dev_ata_cmd_set.h b/sm5/dev_ata_cmd_set.h
index dfe963f4741a04811f573f53e52a3abd48faa3dc..8f73d267c3f09dc6c5a977509fc6684959e4491a 100644
--- a/sm5/dev_ata_cmd_set.h
+++ b/sm5/dev_ata_cmd_set.h
@@ -18,7 +18,7 @@
 #ifndef DEV_ATA_CMD_SET_H
 #define DEV_ATA_CMD_SET_H
 
-#define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h,v 1.1 2008/07/25 21:16:00 chrfranke Exp $\n"
+#define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h,v 1.2 2008/08/23 17:07:16 chrfranke Exp $\n"
 
 #include "atacmds.h" // smart_command_set
 #include "dev_interface.h"
@@ -32,10 +32,10 @@ class ata_device_with_command_set
 : public /*implements*/ ata_device
 {
 protected:
-  /// 28-bit ATA pass through mapped to ata_command_interface().
-  virtual bool ata_pass_through_28bit(const ata_cmd_in & in, ata_cmd_out & out);
+  /// ATA pass through mapped to ata_command_interface().
+  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
 
-  /// Old ATA interface called by ata_pass_through_28bit.
+  /// Old ATA interface called by ata_pass_through()
   virtual int ata_command_interface(smart_command_set command, int select, char * data) = 0;
 
   ata_device_with_command_set()
diff --git a/sm5/dev_interface.cpp b/sm5/dev_interface.cpp
index 7d657d0a0c3c677fa827ce8d75ed1b8b174279b0..65417fb002612c66603079e6ff52f2519810a1ef 100644
--- a/sm5/dev_interface.cpp
+++ b/sm5/dev_interface.cpp
@@ -25,7 +25,7 @@
 
 #include <stdexcept>
 
-const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp,v 1.1 2008/07/25 21:16:00 chrfranke Exp $"
+const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp,v 1.2 2008/08/23 17:07:16 chrfranke Exp $"
   DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -95,23 +95,48 @@ ata_cmd_out::ata_cmd_out()
 {
 }
 
-bool ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
-{
-  if (!in.in_regs.is_48bit_cmd())
-    return ata_pass_through_28bit(in, out);
-  else
-    return ata_pass_through_48bit(in, out);
-}
-
 bool ata_device::ata_pass_through(const ata_cmd_in & in)
 {
   ata_cmd_out dummy;
   return ata_pass_through(in, dummy);
 }
 
-bool ata_device::ata_pass_through_48bit(const ata_cmd_in & /*in*/, ata_cmd_out & /*out*/)
+bool ata_device::ata_cmd_is_ok(const ata_cmd_in & in,
+  bool data_out_support /*= false*/,
+  bool multi_sector_support /*= false*/,
+  bool ata_48bit_support /*= false*/)
 {
-  return set_err(ENOSYS, "48-bit ATA commands not supported");
+  // Check DATA IN/OUT
+  switch (in.direction) {
+    case ata_cmd_in::no_data:  break;
+    case ata_cmd_in::data_in:  break;
+    case ata_cmd_in::data_out: break;
+    default:
+      return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
+  }
+
+  // Check buffer size
+  if (in.direction == ata_cmd_in::no_data) {
+    if (in.size)
+      return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
+  }
+  else {
+    if (!in.buffer)
+      return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
+    unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
+    // TODO: Add check for sector count == 0
+    if (count * 512 != in.size)
+      return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
+  }
+
+  // Check features
+  if (in.direction == ata_cmd_in::data_out && !data_out_support)
+    return set_err(ENOSYS, "DATA OUT ATA commands not supported");
+  if (!(in.size == 0 || in.size == 512) && !multi_sector_support)
+    return set_err(ENOSYS, "Multi-sector ATA commands not supported");
+  if (in.in_regs.is_48bit_cmd() && !ata_48bit_support)
+    return set_err(ENOSYS, "48-bit ATA commands not supported");
+  return true;
 }
 
 bool ata_device::ata_identify_is_cached() const
diff --git a/sm5/dev_interface.h b/sm5/dev_interface.h
index b1485baff3a82dc89125a8d4002e9bb9d691d76d..70cbcd9a109fb09d3a232d3df20f29b3be476a2b 100644
--- a/sm5/dev_interface.h
+++ b/sm5/dev_interface.h
@@ -18,7 +18,7 @@
 #ifndef DEV_INTERFACE_H
 #define DEV_INTERFACE_H
 
-#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h,v 1.3 2008/08/16 16:49:15 chrfranke Exp $\n"
+#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h,v 1.4 2008/08/23 17:07:16 chrfranke Exp $\n"
 
 #include <stdarg.h>
 #include <string>
@@ -404,8 +404,8 @@ class ata_device
 public:
   /// ATA pass through.
   /// Return false on error.
-  /// Default implementation calls ata_pass_through_28bit or _48bit.
-  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
+  /// Must be implemented in derived class.
+  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) = 0;
 
   /// ATA pass through without output registers.
   /// Return false on error.
@@ -417,13 +417,12 @@ public:
   virtual bool ata_identify_is_cached() const;
 
 protected:
-  /// 28-bit ATA pass through.
-  /// Must be implemented in derived class.
-  virtual bool ata_pass_through_28bit(const ata_cmd_in & in, ata_cmd_out & out) = 0;
-
-  /// 48-bit ATA pass through.
-  /// Default implementation returns false and sets errno to ENOSYS.
-  virtual bool ata_pass_through_48bit(const ata_cmd_in & in, ata_cmd_out & out);
+  /// Check command input parameters.
+  /// Calls set_err(...) accordingly.
+  bool ata_cmd_is_ok(const ata_cmd_in & in,
+    bool data_out_support = false,
+    bool multi_sector_support = false,
+    bool ata_48bit_support = false);
 
   /// Default constructor, registers device as ATA.
   ata_device()
diff --git a/sm5/os_win32.cpp b/sm5/os_win32.cpp
index 2e7310614294ca36f5f171510676aabd18046482..7d97b2ff7e511c4c31ea020630bfeab94aac4cee 100644
--- a/sm5/os_win32.cpp
+++ b/sm5/os_win32.cpp
@@ -48,7 +48,7 @@ extern smartmonctrl * con; // con->permissive,reportataioctl
 
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.67 2008/08/20 21:19:08 chrfranke Exp $"
+const char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.68 2008/08/23 17:07:16 chrfranke Exp $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
@@ -106,9 +106,6 @@ public:
 
   virtual bool ata_identify_is_cached() const;
 
-protected:
-  virtual bool ata_pass_through_28bit(const ata_cmd_in & in, ata_cmd_out & out);
-
 private:
   bool open(int phydrive, int logdrive, const char * options, int port);
 
@@ -2327,6 +2324,13 @@ bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
 // Interface to ATA devices
 bool win_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
+  )
+    return false;
+
   // Determine ioctl functions valid for this ATA cmd
   const char * valid_options = 0;
 
@@ -2633,12 +2637,6 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
   return true;
 }
 
-// Dummy, never called because above implements 28-bit and 48-bit commands.
-bool win_ata_device::ata_pass_through_28bit(const ata_cmd_in & /*in*/, ata_cmd_out & /*out*/)
-{
-  return set_err(ENOSYS);
-}
-
 // Return true if OS caches the ATA identify sector
 bool win_ata_device::ata_identify_is_cached() const
 {
diff --git a/sm5/scsiata.cpp b/sm5/scsiata.cpp
index e16935ecc5a5f18bd1b1a3fa0adb7ebc3d2c2a71..34f74d826fc37d3f2cb17aac019ffc51f1ca14c7 100644
--- a/sm5/scsiata.cpp
+++ b/sm5/scsiata.cpp
@@ -50,7 +50,7 @@
 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
 #include "dev_tunnelled.h" // tunnelled_device<>
 
-const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.15 2008/08/16 16:49:16 chrfranke Exp $"
+const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.16 2008/08/23 17:07:17 chrfranke Exp $"
 CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIATA_H_CVSID UTILITY_H_CVSID;
 
 /* for passing global control variables */
@@ -78,9 +78,7 @@ public:
 
   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
 
-protected:
-  virtual bool ata_pass_through_28bit(const ata_cmd_in & in, ata_cmd_out & out);
-
+private:
   int m_passthrulen;
 };
 
@@ -174,6 +172,13 @@ sat_device::~sat_device() throw()
 
 bool sat_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
+  )
+    return false;
+
     struct scsi_cmnd_io io_hdr;
     struct scsi_sense_disect sinfo;
     struct sg_scsi_sense_hdr ssh;
@@ -226,15 +231,6 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
       extend = 1;
     }
 
-    // Check buffer size
-    if (t_length == 2) {
-      // TODO: Add this as utility member function to ata_in_regs
-      unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
-      // TODO: Add check for sector count == 0
-      if (!(in.buffer && (count * 512 == in.size)))
-        return set_err(EINVAL, "sector_count %u does not match buffer size %u", count, in.size);
-    }
-
     cdb[0] = (SAT_ATA_PASSTHROUGH_12LEN == passthru_size) ?
              SAT_ATA_PASSTHROUGH_12 : SAT_ATA_PASSTHROUGH_16;
 
@@ -379,15 +375,6 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
     return true;
 }
 
-
-// Dummy, never called because above implements 28-bit and 48-bit commands.
-
-bool sat_device::ata_pass_through_28bit(const ata_cmd_in & /*in*/, ata_cmd_out & /*out*/)
-{
-  return set_err(ENOSYS);
-}
-
-
 } // namespace
 
 /////////////////////////////////////////////////////////////////////////////