/*
* 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
#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
}
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",
}
} 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;
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;
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)) {
"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)) {
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.