diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index d2b97e1b4b63eb070e882435b5f155658a7ff47d..72131f76814555e120120d56c7e6a6d205e5422f 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.805 2009/06/18 17:24:51 chrfranke Exp $
+$Id: CHANGELOG,v 1.806 2009/06/20 17:58:33 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -41,6 +41,11 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Add 'options' parameter to SCSI printing routine. Move global
+       'con->...' smartctl variables to 'options' parameters of
+       printing routines.
+
+       variables used for drive presets by local variables.
   [CF] Windows: Remove outdated entry about undocumented system calls
        from WARNINGS file.
 
diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp
index 78faf9d9abb805fe20177bc53349d3ddf980f335..d2e0a0e9a46c5ba3e66af98fdeb3461c6db91a54 100644
--- a/sm5/ataprint.cpp
+++ b/sm5/ataprint.cpp
@@ -44,7 +44,7 @@
 #include "utility.h"
 #include "knowndrives.h"
 
-const char *ataprint_c_cvsid="$Id: ataprint.cpp,v 1.211 2009/06/13 14:56:20 chrfranke Exp $"
+const char *ataprint_c_cvsid="$Id: ataprint.cpp,v 1.212 2009/06/20 17:58:33 chrfranke Exp $"
 ATACMDNAMES_H_CVSID ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // for passing global control variables
@@ -1713,7 +1713,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   const char * powername = 0; char powerchg = 0;
 
   // If requested, check power mode first
-  if (con->powermode) {
+  if (options.powermode) {
     unsigned char powerlimit = 0xff;
     int powermode = ataCheckPowerMode(device);
     switch (powermode) {
@@ -1734,7 +1734,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         break;
     }
     if (powername) {
-      if (con->powermode >= powerlimit) {
+      if (options.powermode >= powerlimit) {
         pout("Device is in %s mode, exit(%d)\n", powername, FAILPOWER);
         return FAILPOWER;
       }
@@ -1763,7 +1763,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // Print most drive identity information if requested
   bool known = false;
-  if (con->driveinfo){
+  if (options.drive_info) {
     pout("=== START OF INFORMATION SECTION ===\n");
     known = PrintDriveInfo(&drive, options.fix_swapped_id);
   }
@@ -1797,11 +1797,12 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       pout("                  SMART ENABLE appeared to work!  Continuing.\n");
       supported=1;
     }
-    if (!con->driveinfo) pout("\n");
+    if (!options.drive_info)
+      pout("\n");
   }
   
   // Now print remaining drive info: is SMART enabled?    
-  if (con->driveinfo){
+  if (options.drive_info) {
     int ison=ataIsSmartEnabled(&drive),isenabled=ison;
     
     if (ison==-1) {
@@ -1835,13 +1836,13 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
   
   // START OF THE ENABLE/DISABLE SECTION OF THE CODE
-  if (con->smartenable || con->smartdisable || 
-      con->smartautosaveenable || con->smartautosavedisable || 
-      con->smartautoofflineenable || con->smartautoofflinedisable)
+  if (   options.smart_disable           || options.smart_enable
+      || options.smart_auto_save_disable || options.smart_auto_save_enable
+      || options.smart_auto_offl_disable || options.smart_auto_offl_enable)
     pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
   
   // Enable/Disable SMART commands
-  if (con->smartenable){
+  if (options.smart_enable) {
     if (ataEnableSmart(device)) {
       pout("Smartctl: SMART Enable Failed.\n\n");
       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
@@ -1857,7 +1858,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
   
   // Turn off SMART on device
-  if (con->smartdisable){    
+  if (options.smart_disable) {
     if (ataDisableSmart(device)) {
       pout( "Smartctl: SMART Disable Failed.\n\n");
       failuretest(MANDATORY_CMD,returnval|=FAILSMART);
@@ -1872,7 +1873,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 
   // Enable/Disable Auto-save attributes
-  if (con->smartautosaveenable){
+  if (options.smart_auto_save_enable) {
     if (ataEnableAutoSave(device)){
       pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
@@ -1880,7 +1881,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     else
       pout("SMART Attribute Autosave Enabled.\n");
   }
-  if (con->smartautosavedisable){
+
+  if (options.smart_auto_save_disable) {
     if (ataDisableAutoSave(device)){
       pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
@@ -1900,7 +1902,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Enable/Disable Off-line testing
-  if (con->smartautoofflineenable){
+  if (options.smart_auto_offl_enable) {
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -1913,7 +1915,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     else
       pout("SMART Automatic Offline Testing Enabled every four hours.\n");
   }
-  if (con->smartautoofflinedisable){
+
+  if (options.smart_auto_offl_disable) {
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -1933,26 +1936,28 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // all this for a newline!
-  if (con->smartenable || con->smartdisable || 
-      con->smartautosaveenable || con->smartautosavedisable || 
-      con->smartautoofflineenable || con->smartautoofflinedisable)
+  if (   options.smart_disable           || options.smart_enable
+      || options.smart_auto_save_disable || options.smart_auto_save_enable
+      || options.smart_auto_offl_disable || options.smart_auto_offl_enable)
     pout("\n");
 
   // START OF READ-ONLY OPTIONS APART FROM -V and -i
-  if (   con->checksmart || con->generalsmartvalues || con->smartvendorattrib || con->smarterrorlog
-      || con->smartselftestlog || con->selectivetestlog || con->scttempsts || con->scttemphist
-      || options.smart_ext_error_log || options.smart_ext_selftest_log                             )
+  if (   options.smart_check_status  || options.smart_general_values
+      || options.smart_vendor_attrib || options.smart_error_log
+      || options.smart_selftest_log  || options.smart_selective_selftest_log
+      || options.smart_ext_error_log || options.smart_ext_selftest_log
+      || options.sct_temp_sts        || options.sct_temp_hist               )
     pout("=== START OF READ SMART DATA SECTION ===\n");
   
   // Check SMART status (use previously returned value)
-  if (con->checksmart){
+  if (options.smart_check_status) {
     switch (code) {
 
     case 0:
       // The case where the disk health is OK
       pout("SMART overall-health self-assessment test result: PASSED\n");
       if (ataCheckSmart(&smartval, &smartthres,0)){
-        if (con->smartvendorattrib)
+        if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
         else {
           PRINT_ON(con);
@@ -1973,7 +1978,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       PRINT_OFF(con);
       if (ataCheckSmart(&smartval, &smartthres,1)){
         returnval|=FAILATTR;
-        if (con->smartvendorattrib)
+        if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
         else {
           PRINT_ON(con);
@@ -1997,7 +2002,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         PRINT_OFF(con);
         returnval|=FAILATTR;
         returnval|=FAILSTATUS;
-        if (con->smartvendorattrib)
+        if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
         else {
           PRINT_ON(con);
@@ -2008,7 +2013,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       else {
         pout("SMART overall-health self-assessment test result: PASSED\n");
         if (ataCheckSmart(&smartval, &smartthres,0)){
-          if (con->smartvendorattrib)
+          if (options.smart_vendor_attrib)
             pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
           else {
             PRINT_ON(con);
@@ -2028,11 +2033,11 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   } // end of checking SMART Status
   
   // Print general SMART values
-  if (con->generalsmartvalues)
+  if (options.smart_general_values)
     PrintGeneralSmartValues(&smartval, &drive, fix_firmwarebug);
 
   // Print vendor-specific attributes
-  if (con->smartvendorattrib){
+  if (options.smart_vendor_attrib) {
     PRINT_ON(con);
     PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs,
                               (con->printing_switchable ? 2 : 0));
@@ -2163,7 +2168,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Print SMART error log
-  if (con->smarterrorlog){
+  if (options.smart_error_log) {
     if (!isSmartErrorLogCapable(&smartval, &drive)){
       pout("Warning: device does not support Error Logging\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -2198,7 +2203,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Print SMART self-test log
-  if (con->smartselftestlog){
+  if (options.smart_selftest_log) {
     if (!isSmartTestLogCapable(&smartval, &drive)){
       pout("Warning: device does not support Self Test Logging\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -2217,7 +2222,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Print SMART selective self-test log
-  if (con->selectivetestlog){
+  if (options.smart_selective_selftest_log) {
     ata_selective_self_test_log log;
 
     if (!isSupportSelectiveSelfTest(&smartval))
@@ -2237,18 +2242,18 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     }
   }
 
-  // Print SMART SCT status and temperature history table
-  if (con->scttempsts || con->scttemphist || con->scttempint) {
+  // Print SCT status and temperature history table
+  if (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int) {
     for (;;) {
       if (!isSCTCapable(&drive)) {
         pout("Warning: device does not support SCT Commands\n");
         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
         break;
       }
-      if (con->scttempsts || con->scttemphist) {
+      if (options.sct_temp_sts || options.sct_temp_hist) {
         ata_sct_status_response sts;
         ata_sct_temperature_history_table tmh;
-        if (!con->scttemphist) {
+        if (!options.sct_temp_hist) {
           // Read SCT status only
           if (ataReadSCTStatus(device, &sts)) {
             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -2267,25 +2272,26 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
             break;
           }
         }
-        if (con->scttempsts)
+        if (options.sct_temp_sts)
           ataPrintSCTStatus(&sts);
-        if (con->scttemphist)
+        if (options.sct_temp_hist)
           ataPrintSCTTempHist(&tmh);
         pout("\n");
       }
-      if (con->scttempint) {
+      if (options.sct_temp_int) {
         // Set new temperature logging interval
         if (!isSCTFeatureControlCapable(&drive)) {
           pout("Warning: device does not support SCT Feature Control command\n");
           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
           break;
         }
-        if (ataSetSCTTempInterval(device, con->scttempint, !!con->scttempintp)) {
+        if (ataSetSCTTempInterval(device, options.sct_temp_int, options.sct_temp_int_pers)) {
           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
           break;
         }
         pout("Temperature Logging Interval set to %u minute%s (%s)\n",
-          con->scttempint, (con->scttempint==1?"":"s"), (con->scttempintp?"persistent":"volatile"));
+          options.sct_temp_int, (options.sct_temp_int == 1 ? "" : "s"),
+          (options.sct_temp_int_pers ? "persistent" : "volatile"));
       }
       break;
     }
@@ -2302,12 +2308,12 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
-  if (con->testcase==-1)
+  if (options.smart_selftest_type == -1)
     return returnval;
   
   pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
   // if doing a self-test, be sure it's supported by the hardware
-  switch (con->testcase){
+  switch (options.smart_selftest_type) {
   case OFFLINE_FULL_SCAN:
     if (!isSupportExecuteOfflineImmediate(&smartval)){
       pout("Warning: device does not support Execute Offline Immediate function.\n\n");
@@ -2339,14 +2345,14 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     }
     break;
   default:
-    pout("Internal error in smartctl: con->testcase==%d not recognized\n", (int)con->testcase);
+    pout("Internal error in smartctl: smart_test_type==%d not recognized\n", options.smart_selftest_type);
     pout("Please contact smartmontools developers at %s.\n", PACKAGE_BUGREPORT);
     EXIT(returnval|=FAILCMD);
   }
 
   // Now do the test.  Note ataSmartTest prints its own error/success
   // messages
-  if (ataSmartTest(device, con->testcase, &smartval, get_num_sectors(&drive)))
+  if (ataSmartTest(device, options.smart_selftest_type, &smartval, get_num_sectors(&drive)))
     failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   else {  
     // Tell user how long test will take to complete.  This is tricky
@@ -2354,7 +2360,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     // timer is volatile, and needs to be read AFTER the command is
     // given. If this will interrupt the Offline Full Scan, we don't
     // do it, just warn user.
-    if (con->testcase==OFFLINE_FULL_SCAN){
+    if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
       if (isSupportOfflineAbort(&smartval))
 	pout("Note: giving further SMART commands will abort Offline testing\n");
       else if (ataReadSmartValues(device, &smartval)){
@@ -2364,9 +2370,9 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     }
     
     // Now say how long the test will take to complete
-    if ((timewait=TestTime(&smartval,con->testcase))){ 
+    if ((timewait = TestTime(&smartval, options.smart_selftest_type))) {
       time_t t=time(NULL);
-      if (con->testcase==OFFLINE_FULL_SCAN) {
+      if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
 	t+=timewait;
 	pout("Please wait %d seconds for test to complete.\n", (int)timewait);
       } else {
@@ -2375,11 +2381,11 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       }
       pout("Test will complete after %s\n", ctime(&t));
       
-      if (con->testcase!=SHORT_CAPTIVE_SELF_TEST && 
-	  con->testcase!=EXTEND_CAPTIVE_SELF_TEST && 
-	  con->testcase!=CONVEYANCE_CAPTIVE_SELF_TEST && 
-	  con->testcase!=SELECTIVE_CAPTIVE_SELF_TEST)
-	pout("Use smartctl -X to abort test.\n"); 
+      if (   options.smart_selftest_type != SHORT_CAPTIVE_SELF_TEST
+          && options.smart_selftest_type != EXTEND_CAPTIVE_SELF_TEST
+          && options.smart_selftest_type != CONVEYANCE_CAPTIVE_SELF_TEST
+          && options.smart_selftest_type != SELECTIVE_CAPTIVE_SELF_TEST )
+        pout("Use smartctl -X to abort test.\n");
     }
   }
 
diff --git a/sm5/ataprint.h b/sm5/ataprint.h
index e346bcf3eba5c9da8fe7346dc0a5cb81606f8425..d672fadfea56237d3da6479e38c425829841474e 100644
--- a/sm5/ataprint.h
+++ b/sm5/ataprint.h
@@ -26,7 +26,7 @@
 #ifndef ATAPRINT_H_
 #define ATAPRINT_H_
 
-#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.40 2009/04/16 21:24:08 chrfranke Exp $\n"
+#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.41 2009/06/20 17:58:33 chrfranke Exp $\n"
 
 #include <vector>
 
@@ -47,13 +47,32 @@ struct ata_log_request
 // TODO: Move remaining options from con->* to here.
 struct ata_print_options
 {
-  bool sataphy, sataphy_reset;
+  bool drive_info;
+  bool smart_check_status;
+  bool smart_general_values;
+  bool smart_vendor_attrib;
+  bool smart_error_log;
+  bool smart_selftest_log;
+  bool smart_selective_selftest_log;
+
   bool gp_logdir, smart_logdir;
   unsigned smart_ext_error_log;
   unsigned smart_ext_selftest_log;
 
   std::vector<ata_log_request> log_requests;
 
+  bool sct_temp_sts, sct_temp_hist;
+  bool sataphy, sataphy_reset;
+
+  bool smart_disable, smart_enable;
+  bool smart_auto_offl_disable, smart_auto_offl_enable;
+  bool smart_auto_save_disable, smart_auto_save_enable;
+
+  int smart_selftest_type; // OFFLINE_FULL_SCAN, ..., see atacmds.h. -1 for no test
+
+  unsigned sct_temp_int;
+  bool sct_temp_int_pers;
+
   unsigned char fix_firmwarebug; // FIX_*, see atacmds.h
   bool fix_swapped_id; // Fix swapped ID strings returned by some buggy drivers
 
@@ -67,16 +86,31 @@ struct ata_print_options
 
   bool ignore_presets; // Ignore presets from drive database
   bool show_presets; // Show presets and exit
+  unsigned char powermode; // Skip check, if disk in idle or standby mode
 
   ata_print_options()
-    : sataphy(false), sataphy_reset(false),
+    : drive_info(false),
+      smart_check_status(false),
+      smart_general_values(false),
+      smart_vendor_attrib(false),
+      smart_error_log(false),
+      smart_selftest_log(false),
+      smart_selective_selftest_log(false),
       gp_logdir(false), smart_logdir(false),
       smart_ext_error_log(0),
       smart_ext_selftest_log(0),
+      sct_temp_sts(false), sct_temp_hist(false),
+      sataphy(false), sataphy_reset(false),
+      smart_disable(false), smart_enable(false),
+      smart_auto_offl_disable(false), smart_auto_offl_enable(false),
+      smart_auto_save_disable(false), smart_auto_save_enable(false),
+      smart_selftest_type(-1),
+      sct_temp_int(0), sct_temp_int_pers(false),
       fix_firmwarebug(FIX_NOTSPECIFIED),
       fix_swapped_id(false),
       ignore_presets(false),
-      show_presets(false)
+      show_presets(false),
+      powermode(0)
     { memset(attributedefs, 0, sizeof(attributedefs)); }
 };
 
diff --git a/sm5/extern.h b/sm5/extern.h
index 1f9c5217c5f9b8f69e2188989b6d4e758df8c55d..44743deb70f03c95c06bf1b6d3e52d8d357adfb1 100644
--- a/sm5/extern.h
+++ b/sm5/extern.h
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,20 +25,19 @@
 #ifndef EXTERN_H_
 #define EXTERN_H_
 
-#define EXTERN_H_CVSID "$Id: extern.h,v 1.60 2009/04/16 21:24:08 chrfranke Exp $\n"
+#define EXTERN_H_CVSID "$Id: extern.h,v 1.61 2009/06/20 17:58:33 chrfranke Exp $\n"
 
 // Block used for global control/communications.  If you need more
 // global variables, this should be the only place that you need to
 // add them.
 typedef struct smartmonctrl_s {
+  // TODO: Use local struct for selective self test parameters
   // spans for selective self-test
   uint64_t smartselectivespan[5][2];
   // mode for each span, see SEL_* in utility.h
   char smartselectivemode[5];
   // number of spans
   int smartselectivenumspans;
-  int           testcase;
-  unsigned      scttempint;
   // one plus time in minutes to wait after powerup before restarting
   // interrupted offline scan after selective self-test.
   int  pendingtime;
@@ -46,36 +45,7 @@ typedef struct smartmonctrl_s {
   // turn off scan after selective self-test, 2: turn on scan after
   // selective self-test.
   unsigned char scanafterselect;
-  // skip check, if disk in idle or standby mode
-  unsigned char powermode;
-  unsigned char driveinfo;
-  unsigned char checksmart;
-  unsigned char smartvendorattrib;
-  unsigned char generalsmartvalues;
-  unsigned char smartselftestlog;
-  unsigned char selectivetestlog;
-  unsigned char smarterrorlog;
-  unsigned char smartbackgroundlog;
-  unsigned char scttempsts;
-  unsigned char scttemphist;
-  unsigned char scttempintp;
-  unsigned char smartdisable;
-  unsigned char smartenable; 
-  unsigned char smartstatus;
-  unsigned char smartexeoffimmediate;
-  unsigned char smartshortselftest;
-  unsigned char smartextendselftest;
-  unsigned char smartconveyanceselftest;
-  unsigned char smartselectiveselftest;
-  unsigned char smartshortcapselftest;
-  unsigned char smartextendcapselftest;
-  unsigned char smartconveyancecapselftest;
-  unsigned char smartselectivecapselftest;
-  unsigned char smartselftestabort;
-  unsigned char smartautoofflineenable;
-  unsigned char smartautoofflinedisable;
-  unsigned char smartautosaveenable;
-  unsigned char smartautosavedisable;
+
   unsigned char printing_switchable;
   unsigned char dont_print;
   unsigned char dont_print_serial;
diff --git a/sm5/scsiprint.cpp b/sm5/scsiprint.cpp
index 4698a8690cc0bb2fb50597040e81646afa4c1e35..a1df47597fd27a47c28488b551e249ef6069fa4e 100644
--- a/sm5/scsiprint.cpp
+++ b/sm5/scsiprint.cpp
@@ -44,7 +44,7 @@
 
 #define GBUF_SIZE 65535
 
-const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.126 2009/06/03 15:05:23 dpgilbert Exp $"
+const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.127 2009/06/20 17:58:33 chrfranke Exp $"
 CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // control block which points to external global control variables
@@ -142,7 +142,7 @@ static void scsiGetSupportedLogPages(scsi_device * device)
 
 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
    (or at least something to report). */
-static int scsiGetSmartData(scsi_device * device, int attribs)
+static int scsiGetSmartData(scsi_device * device, bool attribs)
 {
     UINT8 asc;
     UINT8 ascq;
@@ -987,7 +987,7 @@ static const char * transport_proto_arr[] = {
 };
 
 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
-static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, int all)
+static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
 {
     char manufacturer[9];
     char product[17];
@@ -1237,14 +1237,14 @@ static void scsiPrintTemp(scsi_device * device)
 }
 
 /* Main entry point used by smartctl command. Return 0 for success */
-int scsiPrintMain(scsi_device * device)
+int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
 {
     int checkedSupportedLogPages = 0;
     UINT8 peripheral_type = 0;
     int returnval = 0;
     int res, durationSec;
 
-    res = scsiGetDriveInfo(device, &peripheral_type, con->driveinfo);
+    res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
     if (res) {
         if (2 == res)
             return 0;
@@ -1252,37 +1252,37 @@ int scsiPrintMain(scsi_device * device)
             failuretest(MANDATORY_CMD, returnval |= FAILID);
     }
 
-    if (con->smartenable) {
+    if (options.smart_enable) {
         if (scsiSmartEnable(device))
             failuretest(MANDATORY_CMD, returnval |= FAILSMART);
     }
 
-    if (con->smartdisable) {
+    if (options.smart_disable) {
         if (scsiSmartDisable(device))
             failuretest(MANDATORY_CMD,returnval |= FAILSMART);
     }
     
-    if (con->smartautosaveenable) {
+    if (options.smart_auto_save_enable) {
       if (scsiSetControlGLTSD(device, 0, modese_len)) {
         pout("Enable autosave (clear GLTSD bit) failed\n");
         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
       }
     }
     
-    if (con->smartautosavedisable) {
+    if (options.smart_auto_save_disable) {
       if (scsiSetControlGLTSD(device, 1, modese_len)) {
         pout("Disable autosave (set GLTSD bit) failed\n");
         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
       }
     }
     
-    if (con->checksmart) {
+    if (options.smart_check_status) {
         scsiGetSupportedLogPages(device);
         checkedSupportedLogPages = 1;
         if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
             (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */
             if (gTapeAlertsLPage) {
-                if (con->driveinfo)
+                if (options.drive_info)
                     pout("TapeAlert Supported\n");
                 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
                     failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
@@ -1290,7 +1290,7 @@ int scsiPrintMain(scsi_device * device)
             else
                 pout("TapeAlert Not Supported\n");
         } else { /* disk, cd/dvd, enclosure, etc */
-            if ((res = scsiGetSmartData(device, con->smartvendorattrib))) {
+            if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
                 if (-2 == res)
                     returnval |= FAILSTATUS;
                 else
@@ -1298,11 +1298,11 @@ int scsiPrintMain(scsi_device * device)
             }
         }
     }   
-    if (con->smartvendorattrib) {
+    if (options.smart_vendor_attrib) {
         if (! checkedSupportedLogPages)
             scsiGetSupportedLogPages(device);
         if (gTempLPage) {
-            if (con->checksmart)
+            if (options.smart_check_status)
                 pout("\n");
             scsiPrintTemp(device);
         }
@@ -1316,7 +1316,7 @@ int scsiPrintMain(scsi_device * device)
                 scsiPrintSeagateFactoryLPage(device);
         }
     }
-    if (con->smarterrorlog) {
+    if (options.smart_error_log) {
         if (! checkedSupportedLogPages)
             scsiGetSupportedLogPages(device);
         scsiPrintErrorCounterLog(device);
@@ -1324,7 +1324,7 @@ int scsiPrintMain(scsi_device * device)
             pout("\n[GLTSD (Global Logging Target Save Disable) set. "
                  "Enable Save with '-S on']\n");
     }
-    if (con->smartselftestlog) {
+    if (options.smart_selftest_log) {
         if (! checkedSupportedLogPages)
             scsiGetSupportedLogPages(device);
         res = 0;
@@ -1337,7 +1337,7 @@ int scsiPrintMain(scsi_device * device)
         if (0 != res)
             failuretest(OPTIONAL_CMD, returnval|=res);
     }
-    if (con->smartbackgroundlog) {
+    if (options.smart_background_log) {
         if (! checkedSupportedLogPages)
             scsiGetSupportedLogPages(device);
         res = 0;
@@ -1350,23 +1350,23 @@ int scsiPrintMain(scsi_device * device)
         if (0 != res)
             failuretest(OPTIONAL_CMD, returnval|=res);
     }
-    if (con->smartexeoffimmediate) {
+    if (options.smart_default_selftest) {
         if (scsiSmartDefaultSelfTest(device))
             return returnval | FAILSMART;
         pout("Default Self Test Successful\n");
     }
-    if (con->smartshortcapselftest) {
+    if (options.smart_short_cap_selftest) {
         if (scsiSmartShortCapSelfTest(device))
             return returnval | FAILSMART;
         pout("Short Foreground Self Test Successful\n");
     }
-    if (con->smartshortselftest ) { 
+    if (options.smart_short_selftest) {
         if (scsiSmartShortSelfTest(device))
             return returnval | FAILSMART;
         pout("Short Background Self Test has begun\n");
         pout("Use smartctl -X to abort test\n");
     }
-    if (con->smartextendselftest) {
+    if (options.smart_extend_selftest) {
         if (scsiSmartExtendSelfTest(device))
             return returnval | FAILSMART;
         pout("Extended Background Self Test has begun\n");
@@ -1381,12 +1381,12 @@ int scsiPrintMain(scsi_device * device)
         }
         pout("Use smartctl -X to abort test\n");        
     }
-    if (con->smartextendcapselftest) {
+    if (options.smart_extend_cap_selftest) {
         if (scsiSmartExtendCapSelfTest(device))
             return returnval | FAILSMART;
         pout("Extended Foreground Self Test Successful\n");
     }
-    if (con->smartselftestabort) {
+    if (options.smart_selftest_abort) {
         if (scsiSmartSelfTestAbort(device))
             return returnval | FAILSMART;
         pout("Self Test returned without error\n");
diff --git a/sm5/scsiprint.h b/sm5/scsiprint.h
index 14dcea912a25fb6807ec60bfce43329a5165cd67..46a227568b5e8984b9118e2799e05a0c1353ae79 100644
--- a/sm5/scsiprint.h
+++ b/sm5/scsiprint.h
@@ -3,11 +3,11 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
  *
  * Additional SCSI work:
- * Copyright (C) 2003-8 Douglas Gilbert <dougg@torque.net>
+ * Copyright (C) 2003-9 Douglas Gilbert <dougg@torque.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,12 +26,46 @@
  */
 
 
-/* scsismart version number */
 #ifndef SCSI_PRINT_H_
 #define SCSI_PRINT_H_
 
-#define SCSIPRINT_H_CVSID "$Id: scsiprint.h,v 1.22 2008/07/25 21:16:00 chrfranke Exp $\n"
+#define SCSIPRINT_H_CVSID "$Id: scsiprint.h,v 1.23 2009/06/20 17:58:33 chrfranke Exp $\n"
 
-int scsiPrintMain(scsi_device * device);
+// Options for scsiPrintMain
+// TODO: Move remaining options from con->* to here.
+struct scsi_print_options
+{
+  bool drive_info;
+  bool smart_check_status;
+  bool smart_vendor_attrib;
+  bool smart_error_log;
+  bool smart_selftest_log;
+  bool smart_background_log;
+
+  bool smart_disable, smart_enable;
+  bool smart_auto_save_disable, smart_auto_save_enable;
+
+  bool smart_default_selftest;
+  bool smart_short_selftest, smart_short_cap_selftest;
+  bool smart_extend_selftest, smart_extend_cap_selftest;
+  bool smart_selftest_abort;
+
+  scsi_print_options()
+    : drive_info(false),
+      smart_check_status(false),
+      smart_vendor_attrib(false),
+      smart_error_log(false),
+      smart_selftest_log(false),
+      smart_background_log(false),
+      smart_disable(false), smart_enable(false),
+      smart_auto_save_disable(false), smart_auto_save_enable(false),
+      smart_default_selftest(false),
+      smart_short_selftest(false), smart_short_cap_selftest(false),
+      smart_extend_selftest(false), smart_extend_cap_selftest(false),
+      smart_selftest_abort(false)
+    { }
+};
+
+int scsiPrintMain(scsi_device * device, const scsi_print_options & options);
 
 #endif
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index ba530dfbab8297b669b742bb2e150a8aa5eea146..81fa8ccbbc993b86ea2c4b5cc40d77fe4ccc73f4 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -63,7 +63,7 @@ extern const char *os_solaris_ata_s_cvsid;
 extern const char *cciss_c_cvsid;
 #endif
 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid;
-const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.197 2009/04/16 21:24:08 chrfranke Exp $"
+const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.198 2009/06/20 17:58:33 chrfranke Exp $"
 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // This is a block containing all the "control variables".  We declare
@@ -266,7 +266,9 @@ enum checksum_err_mode_t {
 static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN;
 
 /*      Takes command options and sets features to be run */    
-const char * ParseOpts (int argc, char** argv, ata_print_options & options)
+const char * parse_options(int argc, char** argv,
+                           ata_print_options & ataopts,
+                           scsi_print_options & scsiopts)
 {
   int optchar;
   int badarg;
@@ -309,12 +311,12 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
 
   memset(extraerror, 0, sizeof(extraerror));
   memset(con,0,sizeof(*con));
-  con->testcase=-1;
   opterr=optopt=0;
   badarg = captive = FALSE;
   
   const char * type = 0; // set to -d optarg
   bool no_defaultdb = false; // set true on '-B FILE'
+  int testcnt = 0; // number of self-tests requested
 
   // This miserable construction is needed to get emacs to do proper indenting. Sorry!
   while (-1 != (optchar = 
@@ -395,86 +397,86 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
       break;
     case 's':
       if (!strcmp(optarg,"on")) {
-        con->smartenable  = TRUE;
-        con->smartdisable = FALSE;
+        ataopts.smart_enable  = scsiopts.smart_enable  = true;
+        ataopts.smart_disable = scsiopts.smart_disable = false;
       } else if (!strcmp(optarg,"off")) {
-        con->smartdisable = TRUE;
-        con->smartenable  = FALSE;
+        ataopts.smart_disable = scsiopts.smart_disable = true;
+        ataopts.smart_enable  = scsiopts.smart_enable  = false;
       } else {
         badarg = TRUE;
       }
       break;
     case 'o':
       if (!strcmp(optarg,"on")) {
-        con->smartautoofflineenable  = TRUE;
-        con->smartautoofflinedisable = FALSE;
+        ataopts.smart_auto_offl_enable  = true;
+        ataopts.smart_auto_offl_disable = false;
       } else if (!strcmp(optarg,"off")) {
-        con->smartautoofflinedisable = TRUE;
-        con->smartautoofflineenable  = FALSE;
+        ataopts.smart_auto_offl_disable = true;
+        ataopts.smart_auto_offl_enable  = false;
       } else {
         badarg = TRUE;
       }
       break;
     case 'S':
       if (!strcmp(optarg,"on")) {
-        con->smartautosaveenable  = TRUE;
-        con->smartautosavedisable = FALSE;
+        ataopts.smart_auto_save_enable  = scsiopts.smart_auto_save_enable  = true;
+        ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = false;
       } else if (!strcmp(optarg,"off")) {
-        con->smartautosavedisable = TRUE;
-        con->smartautosaveenable  = FALSE;
+        ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = true;
+        ataopts.smart_auto_save_enable  = scsiopts.smart_auto_save_enable  = false;
       } else {
         badarg = TRUE;
       }
       break;
     case 'H':
-      con->checksmart = TRUE;           
+      ataopts.smart_check_status = scsiopts.smart_check_status = true;
       break;
     case 'F':
       if (!strcmp(optarg,"none")) {
-        options.fix_firmwarebug = FIX_NONE;
+        ataopts.fix_firmwarebug = FIX_NONE;
       } else if (!strcmp(optarg,"samsung")) {
-        options.fix_firmwarebug = FIX_SAMSUNG;
+        ataopts.fix_firmwarebug = FIX_SAMSUNG;
       } else if (!strcmp(optarg,"samsung2")) {
-        options.fix_firmwarebug = FIX_SAMSUNG2;
+        ataopts.fix_firmwarebug = FIX_SAMSUNG2;
       } else if (!strcmp(optarg,"samsung3")) {
-        options.fix_firmwarebug = FIX_SAMSUNG3;
+        ataopts.fix_firmwarebug = FIX_SAMSUNG3;
       } else if (!strcmp(optarg,"swapid")) {
-        options.fix_swapped_id = true;
+        ataopts.fix_swapped_id = true;
       } else {
         badarg = TRUE;
       }
       break;
     case 'c':
-      con->generalsmartvalues = TRUE;
+      ataopts.smart_general_values = true;
       break;
     case 'A':
-      con->smartvendorattrib = TRUE;
+      ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true;
       break;
     case 'l':
       if (!strcmp(optarg,"error")) {
-        con->smarterrorlog = TRUE;
+        ataopts.smart_error_log = scsiopts.smart_error_log = true;
       } else if (!strcmp(optarg,"selftest")) {
-        con->smartselftestlog = TRUE;
+        ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
       } else if (!strcmp(optarg, "selective")) {
-        con->selectivetestlog = TRUE;
+        ataopts.smart_selective_selftest_log = true;
       } else if (!strcmp(optarg,"directory")) {
-        options.smart_logdir = options.gp_logdir = true; // SMART+GPL
+        ataopts.smart_logdir = ataopts.gp_logdir = true; // SMART+GPL
       } else if (!strcmp(optarg,"directory,s")) {
-        options.smart_logdir = true; // SMART
+        ataopts.smart_logdir = true; // SMART
       } else if (!strcmp(optarg,"directory,g")) {
-        options.gp_logdir = true; // GPL
+        ataopts.gp_logdir = true; // GPL
       } else if (!strcmp(optarg,"sataphy")) {
-        options.sataphy = true;
+        ataopts.sataphy = true;
       } else if (!strcmp(optarg,"sataphy,reset")) {
-        options.sataphy = options.sataphy_reset = true;
+        ataopts.sataphy = ataopts.sataphy_reset = true;
       } else if (!strcmp(optarg,"background")) {
-        con->smartbackgroundlog = TRUE;
+        scsiopts.smart_background_log = true;
       } else if (!strcmp(optarg,"scttemp")) {
-        con->scttempsts = con->scttemphist = TRUE;
+        ataopts.sct_temp_sts = ataopts.sct_temp_hist = true;
       } else if (!strcmp(optarg,"scttempsts")) {
-        con->scttempsts = TRUE;
+        ataopts.sct_temp_sts = true;
       } else if (!strcmp(optarg,"scttemphist")) {
-        con->scttemphist = TRUE;
+        ataopts.sct_temp_hist = true;
 
       } else if (   !strncmp(optarg,"xerror"   , sizeof("xerror"   )-1)
                  || !strncmp(optarg,"xselftest", sizeof("xselftest")-1)) {
@@ -484,9 +486,9 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
         if (!((n1 == len || n2 == len) && val > 0))
           badarg = TRUE;
         else if (optarg[1] == 'e')
-          options.smart_ext_error_log = val;
+          ataopts.smart_ext_error_log = val;
         else
-          options.smart_ext_selftest_log = val;
+          ataopts.smart_ext_selftest_log = val;
 
       } else if (   !strncmp(optarg, "gplog,"   , sizeof("gplog,"   )-1)
                  || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) {
@@ -515,24 +517,24 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
           ata_log_request req;
           req.gpl = gpl; req.logaddr = logaddr; req.page = page;
           req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors);
-          options.log_requests.push_back(req);
+          ataopts.log_requests.push_back(req);
         }
       } else {
         badarg = TRUE;
       }
       break;
     case 'i':
-      con->driveinfo = TRUE;
-      break;            
+      ataopts.drive_info = scsiopts.drive_info = true;
+      break;
     case 'a':
-      con->driveinfo          = TRUE;
-      con->checksmart         = TRUE;
-      con->generalsmartvalues = TRUE;
-      con->smartvendorattrib  = TRUE;
-      con->smarterrorlog      = TRUE;
-      con->smartselftestlog   = TRUE;
-      con->selectivetestlog   = TRUE;
-      /* con->smartbackgroundlog = TRUE; */
+      ataopts.drive_info           = scsiopts.drive_info          = true;
+      ataopts.smart_check_status   = scsiopts.smart_check_status  = true;
+      ataopts.smart_general_values = true;
+      ataopts.smart_vendor_attrib  = scsiopts.smart_vendor_attrib = true;
+      ataopts.smart_error_log      = scsiopts.smart_error_log     = true;
+      ataopts.smart_selftest_log   = scsiopts.smart_selftest_log  = true;
+      ataopts.smart_selective_selftest_log = true;
+      /* scsiopts.smart_background_log = true; */
       break;
     case 'v':
       // parse vendor-specific definitions of attributes
@@ -543,16 +545,16 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
              create_vendor_attribute_arg_list().c_str());
         EXIT(0);
       }
-      if (parse_attribute_def(optarg, options.attributedefs))
+      if (parse_attribute_def(optarg, ataopts.attributedefs))
         badarg = TRUE;
       break;    
     case 'P':
       if (!strcmp(optarg, "use")) {
-        options.ignore_presets = false;
+        ataopts.ignore_presets = false;
       } else if (!strcmp(optarg, "ignore")) {
-        options.ignore_presets = true;
+        ataopts.ignore_presets = true;
       } else if (!strcmp(optarg, "show")) {
-        options.show_presets = true;
+        ataopts.show_presets = true;
       } else if (!strcmp(optarg, "showall")) {
         if (!no_defaultdb && !read_default_drive_databases())
           EXIT(FAILCMD);
@@ -569,17 +571,20 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
       break;
     case 't':
       if (!strcmp(optarg,"offline")) {
-        con->smartexeoffimmediate = TRUE;
-        con->testcase             = OFFLINE_FULL_SCAN;
+        testcnt++;
+        ataopts.smart_selftest_type = OFFLINE_FULL_SCAN;
+        scsiopts.smart_default_selftest = true;
       } else if (!strcmp(optarg,"short")) {
-        con->smartshortselftest = TRUE;
-        con->testcase           = SHORT_SELF_TEST;
+        testcnt++;
+        ataopts.smart_selftest_type = SHORT_SELF_TEST;
+        scsiopts.smart_short_selftest = true;
       } else if (!strcmp(optarg,"long")) {
-        con->smartextendselftest = TRUE;
-        con->testcase            = EXTEND_SELF_TEST;
+        testcnt++;
+        ataopts.smart_selftest_type = EXTEND_SELF_TEST;
+        scsiopts.smart_extend_selftest = true;
       } else if (!strcmp(optarg,"conveyance")) {
-        con->smartconveyanceselftest = TRUE;
-        con->testcase            = CONVEYANCE_SELF_TEST;
+        testcnt++;
+        ataopts.smart_selftest_type = CONVEYANCE_SELF_TEST;
       } else if (!strcmp(optarg,"afterselect,on")) {
 	// scan remainder of disk after doing selected segments
 	con->scanafterselect=2;
@@ -602,6 +607,7 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
 	  con->pendingtime=i+1;
 	}
       } else if (!strncmp(optarg,"select",strlen("select"))) {
+        testcnt++;
         // parse range of LBAs to test
         uint64_t start, stop; int mode;
         if (split_selective_arg(optarg, &start, &stop, &mode)) {
@@ -622,7 +628,7 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
           con->smartselectivespan[con->smartselectivenumspans][1] = stop;
           con->smartselectivemode[con->smartselectivenumspans] = mode;
           con->smartselectivenumspans++;
-          con->testcase            = SELECTIVE_SELF_TEST;
+          ataopts.smart_selftest_type = SELECTIVE_SELF_TEST;
         }
       } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) {
         unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg);
@@ -631,8 +637,8 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
             strcpy(extraerror, "Option -t scttempint,N[,p] must have positive integer N\n");
             badarg = TRUE;
         }
-        con->scttempint = interval;
-        con->scttempintp = (n2 == len);
+        ataopts.sct_temp_int = interval;
+        ataopts.sct_temp_int_pers = (n2 == len);
       } else {
         badarg = TRUE;
       }
@@ -641,19 +647,20 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
       captive = TRUE;
       break;
     case 'X':
-      con->smartselftestabort = TRUE;
-      con->testcase           = ABORT_SELF_TEST;
+      testcnt++;
+      scsiopts.smart_selftest_abort = true;
+      ataopts.smart_selftest_type = ABORT_SELF_TEST;
       break;
     case 'n':
       // skip disk check if in low-power mode
       if (!strcmp(optarg, "never"))
-        con->powermode = 1; // do not skip, but print mode
+        ataopts.powermode = 1; // do not skip, but print mode
       else if (!strcmp(optarg, "sleep"))
-        con->powermode = 2;
+        ataopts.powermode = 2;
       else if (!strcmp(optarg, "standby"))
-        con->powermode = 3;
+        ataopts.powermode = 3;
       else if (!strcmp(optarg, "idle"))
-        con->powermode = 4;
+        ataopts.powermode = 4;
       else
         badarg = TRUE;
       break;
@@ -732,8 +739,7 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
     con->dont_print=TRUE;
 
   // error message if user has asked for more than one test
-  if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+
-         con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){
+  if (testcnt > 1) {
     con->dont_print=FALSE;
     printslogan();
     pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
@@ -755,26 +761,26 @@ const char * ParseOpts (int argc, char** argv, ata_print_options & options)
   }
 
   // If captive option was used, change test type if appropriate.
-  if (captive && con->smartshortselftest) {
-    con->smartshortselftest    = FALSE;
-    con->smartshortcapselftest = TRUE;
-    con->testcase              = SHORT_CAPTIVE_SELF_TEST;
-  } else if (captive && con->smartextendselftest) {
-    con->smartextendselftest    = FALSE;
-    con->smartextendcapselftest = TRUE;
-    con->testcase               = EXTEND_CAPTIVE_SELF_TEST;
-  }
-  else if (captive && con->smartconveyanceselftest) {
-    con->smartconveyanceselftest    = FALSE;
-    con->smartconveyancecapselftest = TRUE;
-    con->testcase                   = CONVEYANCE_CAPTIVE_SELF_TEST;
-  }
-  else if (captive && con->smartselectiveselftest) {
-    con->smartselectiveselftest    = FALSE;
-    con->smartselectivecapselftest = TRUE;
-    con->testcase                  = SELECTIVE_CAPTIVE_SELF_TEST;
-  }
- 
+  if (captive)
+    switch (ataopts.smart_selftest_type) {
+      case SHORT_SELF_TEST:
+        ataopts.smart_selftest_type = SHORT_CAPTIVE_SELF_TEST;
+        scsiopts.smart_short_selftest     = false;
+        scsiopts.smart_short_cap_selftest = true;
+        break;
+      case EXTEND_SELF_TEST:
+        ataopts.smart_selftest_type = EXTEND_CAPTIVE_SELF_TEST;
+        scsiopts.smart_extend_selftest     = false;
+        scsiopts.smart_extend_cap_selftest = true;
+        break;
+      case CONVEYANCE_SELF_TEST:
+        ataopts.smart_selftest_type = CONVEYANCE_CAPTIVE_SELF_TEST;
+        break;
+      case SELECTIVE_SELF_TEST:
+        ataopts.smart_selftest_type = SELECTIVE_CAPTIVE_SELF_TEST;
+        break;
+    }
+
   // From here on, normal operations...
   printslogan();
   
@@ -885,8 +891,9 @@ int main_worker(int argc, char **argv)
     con=&control;
 
     // Parse input arguments
-    ata_print_options options;
-    const char * type = ParseOpts(argc, argv, options);
+    ata_print_options ataopts;
+    scsi_print_options scsiopts;
+    const char * type = parse_options(argc, argv, ataopts, scsiopts);
 
     // '-d test' -> Report result of autodetection
     bool print_type_only = (type && !strcmp(type, "test"));
@@ -947,9 +954,9 @@ int main_worker(int argc, char **argv)
       pout("%s: Device of type '%s' [%s] opened\n",
            dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev));
     else if (dev->is_ata())
-      retval = ataPrintMain(dev->to_ata(), options);
+      retval = ataPrintMain(dev->to_ata(), ataopts);
     else if (dev->is_scsi())
-      retval = scsiPrintMain(dev->to_scsi());
+      retval = scsiPrintMain(dev->to_scsi(), scsiopts);
     else
       // we should never fall into this branch!
       pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name());