Skip to content
Snippets Groups Projects
Commit b69d2483 authored by chrfranke's avatar chrfranke
Browse files

Add option '-d usbsunplus' for drives behind SunplusIT USB bridges.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2769 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent b2ccc5b2
No related branches found
No related tags found
No related merge requests found
CHANGELOG for smartmontools
$Id: CHANGELOG,v 1.790 2009/03/22 17:17:39 chrfranke Exp $
$Id: CHANGELOG,v 1.791 2009/03/23 21:59:31 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 experimental option '-d usbsunplus' for drives behind
SunplusIT USB bridges. Tested on WinXP with SPIF215(?) in
TrekStor DataStation maxi m.u.. Many thanks to SunplusIT
tech support for providing the required information.
[CF] Windows: Provide a non-console version of smartctl.exe
as smartctl-nc.exe. This prevents that a new console is
opened when smartctl is run from a GUI program with
......
......@@ -51,7 +51,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.28 2009/03/17 19:53:14 chrfranke Exp $"
const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.29 2009/03/23 21:59:31 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 */
......@@ -458,6 +458,39 @@ const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep,
}
// Call scsi_pass_through and check sense.
// TODO: Provide as member function of class scsi_device (?)
static bool scsi_pass_through_and_check(scsi_device * scsidev, scsi_cmnd_io * iop,
const char * msg = "")
{
// Provide sense buffer
unsigned char sense[32] = {0, };
iop->sensep = sense;
iop->max_sense_len = sizeof(sense);
iop->timeout = SCSI_TIMEOUT_DEFAULT;
// Run cmd
if (!scsidev->scsi_pass_through(iop)) {
if (con->reportscsiioctl > 0)
pout("%sscsi_pass_through() failed, errno=%d [%s]\n",
msg, scsidev->get_errno(), scsidev->get_errmsg());
return false;
}
// Check sense
scsi_sense_disect sinfo;
scsi_do_sense_disect(iop, &sinfo);
int err = scsiSimpleSenseFilter(&sinfo);
if (err) {
if (con->reportscsiioctl > 0)
pout("%sscsi error: %s\n", msg, scsiErrString(err));
return scsidev->set_err(EIO, "scsi error %s", scsiErrString(err));
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
namespace sat {
......@@ -925,28 +958,10 @@ bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & ou
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
unsigned char sense[32] = {0, };
io_hdr.sensep = sense;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
scsi_device * scsidev = get_tunnel_dev();
if (!scsidev->scsi_pass_through(&io_hdr)) {
if (con->reportscsiioctl > 0)
pout("usbjmicron_device::ata_pass_through: scsi_pass_through() failed, "
"errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbjmicron_device::ata_pass_through: "))
return set_err(scsidev->get_err());
}
scsi_sense_disect sinfo;
scsi_do_sense_disect(&io_hdr, &sinfo);
int err = scsiSimpleSenseFilter(&sinfo);
if (err) {
if (con->reportscsiioctl > 0)
pout("usbjmicron_device::ata_pass_through: scsi error: %s\n",
scsiErrString(err));
return set_err(EIO, "scsi error %s", scsiErrString(err));
}
if (in.out_needed.is_set()) {
if (is_smart_status) {
......@@ -1010,27 +1025,159 @@ bool usbjmicron_device::get_registers(unsigned short addr,
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
unsigned char sense[32] = {0, };
io_hdr.sensep = sense;
io_hdr.max_sense_len = sizeof(sense);
io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
scsi_device * scsidev = get_tunnel_dev();
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbjmicron_device::get_registers: "))
return set_err(scsidev->get_err());
return true;
}
/////////////////////////////////////////////////////////////////////////////
/// SunplusIT USB Bridge support.
class usbsunplus_device
: public tunnelled_device<
/*implements*/ ata_device,
/*by tunnelling through a*/ scsi_device
>
{
public:
usbsunplus_device(smart_interface * intf, scsi_device * scsidev,
const char * req_type);
virtual ~usbsunplus_device() throw();
virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
};
usbsunplus_device::usbsunplus_device(smart_interface * intf, scsi_device * scsidev,
const char * req_type)
: smart_device(intf, scsidev->get_dev_name(), "usbsunplus", req_type),
tunnelled_device<ata_device, scsi_device>(scsidev)
{
set_info().info_name = strprintf("%s [USB Sunplus]", scsidev->get_info_name());
}
usbsunplus_device::~usbsunplus_device() throw()
{
}
bool usbsunplus_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
{
if (!ata_cmd_is_ok(in,
true, // data_out_support
false, // !multi_sector_support
true) // ata_48bit_support
)
return false;
scsi_cmnd_io io_hdr;
unsigned char cdb[12];
if (in.in_regs.is_48bit_cmd()) {
// Set "previous" registers
memset(&io_hdr, 0, sizeof(io_hdr));
io_hdr.dxfer_dir = DXFER_NONE;
cdb[ 0] = 0xf8;
cdb[ 1] = 0x00;
cdb[ 2] = 0x23; // Subcommand: Pass through presetting
cdb[ 3] = 0x00;
cdb[ 4] = 0x00;
cdb[ 5] = in.in_regs.prev.features;
cdb[ 6] = in.in_regs.prev.sector_count;
cdb[ 7] = in.in_regs.prev.lba_low;
cdb[ 8] = in.in_regs.prev.lba_mid;
cdb[ 9] = in.in_regs.prev.lba_high;
cdb[10] = 0x00;
cdb[11] = 0x00;
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
scsi_device * scsidev = get_tunnel_dev();
if (!scsidev->scsi_pass_through(&io_hdr)) {
if (con->reportscsiioctl > 0)
pout("usbjmicron_device::get_registers: scsi_pass_through failed, "
"errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg());
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbsunplus_device::scsi_pass_through (presetting): "))
return set_err(scsidev->get_err());
}
scsi_sense_disect sinfo;
scsi_do_sense_disect(&io_hdr, &sinfo);
int err = scsiSimpleSenseFilter(&sinfo);
if (err) {
if (con->reportscsiioctl > 0)
pout("usbjmicron_device::get_registers: scsi error: %s\n",
scsiErrString(err));
return set_err(EIO, "scsi error %s", scsiErrString(err));
// Run Pass through command
memset(&io_hdr, 0, sizeof(io_hdr));
unsigned char protocol;
switch (in.direction) {
case ata_cmd_in::no_data:
io_hdr.dxfer_dir = DXFER_NONE;
protocol = 0x00;
break;
case ata_cmd_in::data_in:
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
io_hdr.dxfer_len = in.size;
io_hdr.dxferp = (unsigned char *)in.buffer;
memset(in.buffer, 0, in.size);
protocol = 0x10;
break;
case ata_cmd_in::data_out:
io_hdr.dxfer_dir = DXFER_TO_DEVICE;
io_hdr.dxfer_len = in.size;
io_hdr.dxferp = (unsigned char *)in.buffer;
protocol = 0x11;
break;
default:
return set_err(EINVAL);
}
cdb[ 0] = 0xf8;
cdb[ 1] = 0x00;
cdb[ 2] = 0x22; // Subcommand: Pass through
cdb[ 3] = protocol;
cdb[ 4] = (unsigned char)(io_hdr.dxfer_len >> 9);
cdb[ 5] = in.in_regs.features;
cdb[ 6] = in.in_regs.sector_count;
cdb[ 7] = in.in_regs.lba_low;
cdb[ 8] = in.in_regs.lba_mid;
cdb[ 9] = in.in_regs.lba_high;
cdb[10] = in.in_regs.device | 0xa0;
cdb[11] = in.in_regs.command;
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
scsi_device * scsidev = get_tunnel_dev();
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbsunplus_device::scsi_pass_through: "))
// Returns sense key 0x03 (medium error) on ATA command error
return set_err(scsidev->get_err());
if (in.out_needed.is_set()) {
// Read ATA output registers
unsigned char regbuf[8] = {0, };
memset(&io_hdr, 0, sizeof(io_hdr));
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
io_hdr.dxfer_len = sizeof(regbuf);
io_hdr.dxferp = regbuf;
cdb[ 0] = 0xf8;
cdb[ 1] = 0x00;
cdb[ 2] = 0x21; // Subcommand: Get status
memset(cdb+3, 0, sizeof(cdb)-3);
io_hdr.cmnd = cdb;
io_hdr.cmnd_len = sizeof(cdb);
if (!scsi_pass_through_and_check(scsidev, &io_hdr,
"usbsunplus_device::scsi_pass_through (get registers): "))
return set_err(scsidev->get_err());
out.out_regs.error = regbuf[1];
out.out_regs.sector_count = regbuf[2];
out.out_regs.lba_low = regbuf[3];
out.out_regs.lba_mid = regbuf[4];
out.out_regs.lba_high = regbuf[5];
out.out_regs.device = regbuf[6];
out.out_regs.status = regbuf[7];
}
return true;
......@@ -1080,6 +1227,10 @@ ata_device * smart_interface::get_sat_device(const char * type, scsi_device * sc
return new usbjmicron_device(this, scsidev, type, port);
}
else if (!strcmp(type, "usbsunplus")) {
return new usbsunplus_device(this, scsidev, type);
}
else {
set_err(EINVAL, "Unknown USB device type '%s'", type);
return 0;
......@@ -1143,8 +1294,9 @@ struct usb_id_entry {
};
const char d_sat[] = "sat";
const char d_jmicron[] = "usbjmicron";
const char d_cypress[] = "usbcypress";
const char d_jmicron[] = "usbjmicron";
const char d_sunplus[] = "usbsunplus";
const char d_unsup[] = "unsupported";
// Map USB IDs -> '-d type' string
......@@ -1155,7 +1307,7 @@ const usb_id_entry usb_ids[] = {
{ 0x059f, 0x0651, -1, d_unsup }, // LaCie hard disk (FA Porsche design)
{ 0x059f, 0x1018, -1, d_sat }, // LaCie hard disk (Neil Poulton design)
{ 0x0bc2, 0x3001, -1, d_sat }, // Seagate FreeAgent Desk
{ 0x0c0b, 0xb159, 0x0103, d_unsup }, // Dura Micro ?
{ 0x0c0b, 0xb159, 0x0103, d_sunplus }, // Dura Micro (Sunplus USB-bridge)
{ 0x0d49, 0x7310, 0x0125, d_sat }, // Maxtor OneTouch 4
//{ 0x0d49, -1, -1, d_sat }, // Maxtor Basics Desktop
{ 0x1058, 0x1001, 0x0104, d_sat }, // WD Elements Desktop
......
.ig
Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
$Id: smartctl.8.in,v 1.121 2009/03/14 16:14:10 chrfranke Exp $
$Id: smartctl.8.in,v 1.122 2009/03/23 21:59:31 chrfranke Exp $
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 the Free
......@@ -214,8 +214,8 @@ use the exit status of \fBsmartctl\fP (see RETURN VALUES below).
.B \-d TYPE, \-\-device=TYPE
Specifies the type of the device. The valid arguments to this option
are \fIata\fP, \fIscsi\fP, \fIsat\fP, \fImarvell\fP, \fI3ware,N\fP,
\fIareca,N\fP, \fIusbcypress\fP, \fIusbjmicron\fP, \fIcciss,N\fP,
\fIhpt,L/M\fP (or \fIhpt,L/M/N\fP), and \fItest\fP.
\fIareca,N\fP, \fIusbcypress\fP, \fIusbjmicron\fP, \fIusbsunplus\fP,
\fIcciss,N\fP, \fIhpt,L/M\fP (or \fIhpt,L/M/N\fP), and \fItest\fP.
If this option is not used then \fBsmartctl\fP will attempt to guess
the device type from the device name or from controller type info
......@@ -244,6 +244,9 @@ specified by \'\-d usbjmicron,PORT\' where PORT is 0 (master) or 1 (slave).
If no PORT is specified, it is auto-detected. If both ports are connected,
0 takes precedence.
[NEW EXPERIMENTAL SMARTCTL FEATURE] The \'usbsunplus\' device type is for
SATA disks that are behind a SunplusIT USB to SATA bridge.
Under Linux, to look at SATA disks behind Marvell SATA controllers
(using Marvell's \'linuxIAL\' driver rather than libata driver) use \'\-d marvell\'. Such
controllers show up as Marvell Technology Group Ltd. SATA I or II controllers
......@@ -1666,7 +1669,7 @@ these documents may be found in the References section of the
.SH
CVS ID OF THIS PAGE:
$Id: smartctl.8.in,v 1.121 2009/03/14 16:14:10 chrfranke Exp $
$Id: smartctl.8.in,v 1.122 2009/03/23 21:59:31 chrfranke Exp $
.\" Local Variables:
.\" mode: nroff
.\" End:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment