diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 8195c379fcbcf294478f0b214787116e578530b0..ecf041116c0bda76435fe35ff24a1b0ce135ff5f 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.737 2008/09/27 17:04:36 chrfranke Exp $
+$Id: CHANGELOG,v 1.738 2008/09/29 19:13:49 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -40,6 +40,10 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Add option '-d sat+TYPE' to use SAT with controllers which
+       require option '-d TYPE'. Should work with '-d sat+megaraid,N'.
+       As a side effect, '-d usbcypress+TYPE' is also supported.
+
   [CF] Add parser to read drive database from a file. Add '-B' option
        to smartctl and smartd to specify database file name. File syntax
        is identical to the C/C++ syntax used to inialize the internal
diff --git a/sm5/dev_interface.cpp b/sm5/dev_interface.cpp
index 52a37ff168ded72de4ac2a39618ea2d8c93e1487..d16e8ab0477ec4e2206f7648b52985bfaa510712 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.3 2008/08/23 19:56:18 chrfranke Exp $"
+const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp,v 1.4 2008/09/29 19:13:49 chrfranke Exp $"
   DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -224,18 +224,17 @@ const char * smart_interface::get_os_version_str()
 
 const char * smart_interface::get_valid_dev_types_str()
 {
-  static char buf[80+1];
-  if (buf[0])
-    return buf;
+  static std::string buf;
+  if (!buf.empty())
+    return buf.c_str();
   // default
-  strcpy(buf, "ata, scsi, sat[,N]");
+  buf = "ata, scsi, sat[,N][+TYPE]";
   // append custom
   const char * add = get_valid_custom_dev_types_str();
   if (!add || !*add)
-    return buf;
-  strcat(buf, ", ");
-  strcat(buf, add);
-  return buf;
+    return buf.c_str();
+  buf += ", "; buf += add;
+  return buf.c_str();
 }
 
 const char * smart_interface::get_app_examples(const char * /*appname*/)
@@ -294,9 +293,41 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
     dev = get_ata_device(name, type);
   else if (!strcmp(type, "scsi"))
     dev = get_scsi_device(name, type);
-  else if (   (!strncmp(type, "sat", 3) && (!type[3] || type[3] == ','))
-           || (!strncmp(type, "usb", 3)))
-    dev = get_sat_device(name, type /*, 0*/);
+
+  else if (   (!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3]))
+           || (!strncmp(type, "usb", 3)))) {
+    // Split "sat...+base..." -> ("sat...", "base...")
+    unsigned satlen = strcspn(type, "+");
+    std::string sattype(type, satlen);
+    const char * basetype = (type[satlen] ? type+satlen+1 : "");
+    // Recurse to allocate base device, default is standard SCSI
+    if (!*basetype)
+      basetype = "scsi";
+    dev = get_smart_device(name, basetype);
+    if (!dev) {
+      set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
+      return 0;
+    }
+    // Result must be SCSI
+    if (!dev->is_scsi()) {
+      delete dev;
+      set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
+      return 0;
+    }
+    // Attach SAT tunnel
+    try {
+      ata_device * satdev = get_sat_device(sattype.c_str(), dev->to_scsi());
+      if (!satdev) {
+        delete dev;
+        return 0;
+      }
+      return satdev;
+    }
+    catch (...) {
+      delete dev; throw;
+    }
+  }
+
   else {
     set_err(EINVAL, "Unknown device type '%s'", type);
     return 0;
diff --git a/sm5/dev_interface.h b/sm5/dev_interface.h
index d10fadc8e46be31ce4bb8548a590c7bfe4c593b9..35e7afd80eb69fb4476cbc9e3d0c80bf2306a050 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.6 2008/08/29 20:07:36 chrfranke Exp $\n"
+#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h,v 1.7 2008/09/29 19:13:49 chrfranke Exp $\n"
 
 #include <stdarg.h>
 #include <string>
@@ -674,7 +674,7 @@ protected:
 
   /// Return ATA->SCSI filter for SAT or USB.
   /// Override only if platform needs special handling.
-  virtual ata_device * get_sat_device(const char * name, const char * type, scsi_device * scsidev = 0);
+  virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev);
   //{ implemented in scsiata.cpp }
 
 public:
diff --git a/sm5/scsiata.cpp b/sm5/scsiata.cpp
index bff27d946b622a6caf88d43de2f212b5da049cca..c2590b9af09539e55de5250d52e23ab639903f24 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.18 2008/09/12 19:26:09 chrfranke Exp $"
+const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.19 2008/09/29 19:13:49 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 */
@@ -790,13 +790,8 @@ using namespace sat;
 
 // Return ATA->SCSI filter for SAT or USB.
 
-ata_device * smart_interface::get_sat_device(const char * name, const char * type, scsi_device * scsidev /* = 0*/)
+ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev)
 {
-  if (!scsidev) {
-    scsidev = get_scsi_device(name, "scsi");
-    if (!scsidev)
-      return 0;
-  }
   if (!strncmp(type, "sat", 3)) {
     int ptlen = 0, n1 = -1, n2 = -1;
     if (!(((sscanf(type, "sat%n,%d%n", &n1, &ptlen, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type))