]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - scsiata.cpp
Closes #831504
[mirror_smartmontools-debian.git] / scsiata.cpp
index fbe603b356ed563a60d538d12f69c7d69bbd617e..26a9290c4d0a32e718ed34a8eecc73cb0440b948 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * scsiata.cpp
  *
- * Home page of code is: http://smartmontools.sourceforge.net
+ * Home page of code is: http://www.smartmontools.org
  *
- * Copyright (C) 2006-12 Douglas Gilbert <dgilbert@interlog.com>
- * Copyright (C) 2009-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2006-15 Douglas Gilbert <dgilbert@interlog.com>
+ * Copyright (C) 2009-16 Christian Franke
  *
  * 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
@@ -62,7 +62,7 @@
 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
 #include "dev_tunnelled.h" // tunnelled_device<>
 
-const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 4041 2015-03-14 00:50:20Z dpgilbert $";
+const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 4276 2016-04-02 19:13:39Z chrfranke $";
 
 /* This is a slightly stretched SCSI sense "descriptor" format header.
    The addition is to allow the 0x70 and 0x71 response codes. The idea
@@ -394,6 +394,16 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         }
         scsi_do_sense_disect(&io_hdr, &sinfo);
         int status = scsiSimpleSenseFilter(&sinfo);
+
+        // Workaround for bogus sense_key in sense data with SAT ATA Return Descriptor
+        if (   status && ck_cond && ardp && ard_len > 13
+            && (ardp[13] & 0xc1) == 0x40 /* !BSY && DRDY && !ERR */) {
+            if (scsi_debugmode > 0)
+                pout("ATA status (0x%02x) indicates success, ignoring SCSI sense_key\n",
+                     ardp[13]);
+            status = 0;
+        }
+
         if (0 != status) {  /* other than no_sense and recovered_error */
             if (scsi_debugmode > 0) {
                 pout("sat_device::ata_pass_through: scsi error: %s\n",
@@ -433,7 +443,8 @@ bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
                 }
             } else if ((! sense_descriptor) &&
                        (0 == ssh.asc) &&
-                       (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) {
+                       (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq) &&
+                       (0 != io_hdr.sensep[4] /* Some ATA STATUS bit must be set */)) {
                 /* in SAT-2 and later, ATA registers may be passed back via
                  * fixed format sense data [ref: sat3r07 section 12.2.2.7] */
                 ata_out_regs & lo = out.out_regs;
@@ -1475,6 +1486,13 @@ using namespace sat;
 
 ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev)
 {
+  if (!scsidev)
+    throw std::logic_error("smart_interface: get_sat_device() called with scsidev=0");
+
+  // Take temporary ownership of 'scsidev' to delete it on error
+  scsi_device_auto_ptr scsidev_holder(scsidev);
+  ata_device * satdev = 0;
+
   if (!strncmp(type, "sat", 3)) {
     const char * t = type + 3;
     bool enable_auto = false;
@@ -1488,7 +1506,7 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
       set_err(EINVAL, "Option '-d sat[,auto][,N]' requires N to be 0, 12 or 16");
       return 0;
     }
-    return new sat_device(this, scsidev, type, ptlen, enable_auto);
+    satdev = new sat_device(this, scsidev, type, ptlen, enable_auto);
   }
 
   else if (!strncmp(type, "usbcypress", 10)) {
@@ -1499,7 +1517,7 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
                       "an hexadecimal number between 0x0 and 0xff");
       return 0;
     }
-    return new usbcypress_device(this, scsidev, type, signature);
+    satdev = new usbcypress_device(this, scsidev, type, signature);
   }
 
   else if (!strncmp(type, "usbjmicron", 10)) {
@@ -1520,21 +1538,25 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
       set_err(EINVAL, "Option '-d usbjmicron[,p][,x],<n>' requires <n> to be 0 or 1");
       return 0;
     }
-    return new usbjmicron_device(this, scsidev, type, prolific, ata_48bit_support, port);
+    satdev = new usbjmicron_device(this, scsidev, type, prolific, ata_48bit_support, port);
   }
 
   else if (!strcmp(type, "usbprolific")) {
-    return new usbprolific_device(this, scsidev, type);
+    satdev = new usbprolific_device(this, scsidev, type);
   }
 
   else if (!strcmp(type, "usbsunplus")) {
-    return new usbsunplus_device(this, scsidev, type);
+    satdev = new usbsunplus_device(this, scsidev, type);
   }
 
   else {
     set_err(EINVAL, "Unknown USB device type '%s'", type);
     return 0;
   }
+
+  // 'scsidev' is now owned by 'satdev'
+  scsidev_holder.release();
+  return satdev;
 }
 
 // Try to detect a SAT device behind a SCSI interface.