diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG index 93075cdeb260c83883ff8e96e54ac20dd863887d..009d527d7eb026bebcd9ccf294c84d9cf5081a39 100644 --- a/sm5/CHANGELOG +++ b/sm5/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG,v 1.778 2009/03/03 20:13:08 chrfranke Exp $ +$Id: CHANGELOG,v 1.779 2009/03/03 20:23:55 chrfranke Exp $ The most recent version of this file is: http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup @@ -41,6 +41,10 @@ NOTES FOR FUTURE RELEASES: see TODO file. <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> + [CF] Add new SMART STATUS check command for JMicron USB bridges. + Should support also older chip versions and prevents a race + condition. + [CF] Windows: Fix win_scsi_device::scsi_pass_through() for single byte data transfers. Required for JMicron SMART STATUS check. diff --git a/sm5/scsiata.cpp b/sm5/scsiata.cpp index 691e18d9d58a38b9fef2cce7f076b3ee2d31067a..a2cb2e32c8d4a9bac0933f62c5ccc035062d661b 100644 --- a/sm5/scsiata.cpp +++ b/sm5/scsiata.cpp @@ -3,7 +3,8 @@ * * Home page of code is: http://smartmontools.sourceforge.net * - * Copyright (C) 2006-8 Douglas Gilbert <dougg@torque.net> + * Copyright (C) 2006-9 Douglas Gilbert <dougg@torque.net> + * Copyright (C) 2009 Christian Franke <smartmontools-support@lists.sourceforge.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 @@ -50,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.22 2009/02/27 22:42:52 chrfranke Exp $" +const char *scsiata_c_cvsid="$Id: scsiata.cpp,v 1.23 2009/03/03 20:23:55 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 */ @@ -832,7 +833,7 @@ bool usbjmicron_device::open() // Detect port if not specified if (m_port < 0) { - unsigned char regbuf[2] = {0, 0}; + unsigned char regbuf[1] = {0}; if (!get_registers(0x720f, regbuf, sizeof(regbuf))) { close(); return false; @@ -861,11 +862,16 @@ bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & ou ) return false; + bool is_smart_status = ( in.in_regs.command == ATA_SMART_CMD + && in.in_regs.features == ATA_SMART_STATUS); + + // Support output registers for SMART STATUS + if (in.out_needed.is_set() && !is_smart_status) + return set_err(ENOSYS, "ATA output registers not supported"); + // Support 48-bit commands with zero high bytes - if (in.in_regs.is_48bit_cmd()) { - if (in.in_regs.is_real_48bit_cmd() || in.out_needed.is_set()) - return set_err(ENOSYS, "48-bit ATA commands not fully supported"); - } + if (in.in_regs.is_real_48bit_cmd()) + return set_err(ENOSYS, "48-bit ATA commands not fully supported"); if (m_port < 0) return set_err(EIO, "Unknown JMicron port"); @@ -874,7 +880,14 @@ bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & ou memset(&io_hdr, 0, sizeof(io_hdr)); bool rwbit = true; - switch (in.direction) { + unsigned char smart_status = 0; + + if (is_smart_status && in.out_needed.is_set()) { + io_hdr.dxfer_dir = DXFER_FROM_DEVICE; + io_hdr.dxfer_len = 1; + io_hdr.dxferp = &smart_status; + } + else switch (in.direction) { case ata_cmd_in::no_data: io_hdr.dxfer_dir = DXFER_NONE; break; @@ -926,19 +939,37 @@ bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & ou } if (in.out_needed.is_set()) { - // Read ATA output registers - // NOTE: There is a small race condition here! - unsigned char regbuf[16] = {0, }; - if (!get_registers((m_port == 0 ? 0x8000 : 0x9000), regbuf, sizeof(regbuf))) - return false; + if (is_smart_status) { + switch (smart_status) { + case 0x01: case 0xc2: + out.out_regs.lba_high = 0xc2; + out.out_regs.lba_mid = 0x4f; + break; + case 0x00: case 0x2c: + out.out_regs.lba_high = 0x2c; + out.out_regs.lba_mid = 0xf4; + break; + } + } - out.out_regs.sector_count = regbuf[ 0]; - out.out_regs.lba_mid = regbuf[ 4]; - out.out_regs.lba_low = regbuf[ 6]; - out.out_regs.device = regbuf[ 9]; - out.out_regs.lba_high = regbuf[10]; - out.out_regs.error = regbuf[13]; - out.out_regs.status = regbuf[14]; +#if 0 // Not needed for SMART STATUS, see also notes below + else { + // Read ATA output registers + // NOTE: The register addresses are not valid for some older chip revisions + // NOTE: There is a small race condition here! + unsigned char regbuf[16] = {0, }; + if (!get_registers((m_port == 0 ? 0x8000 : 0x9000), regbuf, sizeof(regbuf))) + return false; + + out.out_regs.sector_count = regbuf[ 0]; + out.out_regs.lba_mid = regbuf[ 4]; + out.out_regs.lba_low = regbuf[ 6]; + out.out_regs.device = regbuf[ 9]; + out.out_regs.lba_high = regbuf[10]; + out.out_regs.error = regbuf[13]; + out.out_regs.status = regbuf[14]; + } +#endif } return true;