From patchwork Mon Feb 7 21:31:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Wheeler X-Patchwork-Id: 82191 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id EE8E2B7123 for ; Tue, 8 Feb 2011 09:47:24 +1100 (EST) Received: from localhost ([127.0.0.1]:56771 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PmZrf-0007jk-Om for incoming@patchwork.ozlabs.org; Mon, 07 Feb 2011 17:47:23 -0500 Received: from [140.186.70.92] (port=41732 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PmYga-0004i7-5b for qemu-devel@nongnu.org; Mon, 07 Feb 2011 16:31:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PmYgX-0002Wz-Gj for qemu-devel@nongnu.org; Mon, 07 Feb 2011 16:31:50 -0500 Received: from hartman.uits.indiana.edu ([129.79.1.194]:48839 helo=internal-relay.indiana.edu) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PmYgX-0002WE-CH for qemu-devel@nongnu.org; Mon, 07 Feb 2011 16:31:49 -0500 Received: from mail-relay.iu.edu (burns.uits.indiana.edu [129.79.1.202]) by internal-relay.indiana.edu (8.14.4/8.14.4/IU Messaging Team) with ESMTP id p17LVjbJ010570 for ; Mon, 7 Feb 2011 16:31:45 -0500 Received: from [129.79.35.119] (nibbler.dlib.indiana.edu [129.79.35.119]) (authenticated bits=0) by mail-relay.iu.edu (8.14.4/8.14.4/IU Messaging Team Submission) with ESMTP id p17LVha3031155 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 7 Feb 2011 16:31:44 -0500 From: Brian Wheeler To: qemu-devel@nongnu.org Date: Mon, 07 Feb 2011 16:31:43 -0500 Message-ID: <1297114303.7349.17.camel@nibbler.dlib.indiana.edu> Mime-Version: 1.0 X-Mailer: Evolution 2.32.1 (2.32.1-1.fc14) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 129.79.1.194 Subject: [Qemu-devel] [PATCH] Fix ATA SMART and CHECK POWER MODE X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch fixes two things: 1) CHECK POWER MODE The error return value wasn't always zero, so it would show up as offline. Error is now explicitly set to zero. 2) SMART The smart values that were returned were invalid and tools like skdump would not recognize that the smart data was actually valid and would dump weird output. The data has been fixed up and raw value support was added. Tools like skdump and palimpsest work as expected. Signed-of-by: Brian Wheeler diff --git a/hw/ide/core.c b/hw/ide/core.c index dd63664..4d4ccfa 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -34,15 +34,37 @@ #include -static const int smart_attributes[][5] = { - /* id, flags, val, wrst, thrsh */ - { 0x01, 0x03, 0x64, 0x64, 0x06}, /* raw read */ - { 0x03, 0x03, 0x64, 0x64, 0x46}, /* spin up */ - { 0x04, 0x02, 0x64, 0x64, 0x14}, /* start stop count */ - { 0x05, 0x03, 0x64, 0x64, 0x36}, /* remapped sectors */ - { 0x00, 0x00, 0x00, 0x00, 0x00} +/* These values were taking from a running system. */ +static const int smart_attributes[][12] = { + /* id, flags, hflags, val, wrst, raw (up to 6 bytes) */ + /* raw read error rate*/ + { 0x01, 0x03, 0x00, 0x74, 0x63, 0x31, 0x6d, 0x3f, 0x0d}, + /* spin up */ + { 0x03, 0x03, 0x00, 0x61, 0x61}, + /* start stop count */ + { 0x04, 0x02, 0x00, 0x64, 0x64, 0x64}, + /* remapped sectors */ + { 0x05, 0x03, 0x00, 0x64, 0x64}, + /* power on hours */ + { 0x09, 0x03, 0x00, 0x61, 0x61, 0x68, 0x0a}, + /* power cycle count */ + { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x32}, + /* airflow-temperature-celsius */ + { 190, 0x03, 0x00, 0x64, 0x64, 0x1f, 0x00, 0x16, 0x22}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; +static const int smart_thresholds[][2] = { + { 0x01, 0x06}, + { 0x03, 0x00}, + { 0x04, 0x14}, + { 0x05, 0x24}, + { 0x09, 0x00}, + { 190, 0x32}, + { 0x00, 0x00} +}; + + /* XXX: DVDs that could fit on a CD will be reported as a CD */ static inline int media_present(IDEState *s) { @@ -1843,6 +1865,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) break; case WIN_CHECKPOWERMODE1: case WIN_CHECKPOWERMODE2: + s->error = 0; s->nsector = 0xff; /* device active or idle */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); @@ -2068,24 +2091,24 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_ATTR_AUTOSAVE: switch (s->sector) { case 0x00: - s->smart_autosave = 0; - break; + s->smart_autosave = 0; + break; case 0xf1: - s->smart_autosave = 1; - break; + s->smart_autosave = 1; + break; default: - goto abort_cmd; + goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; case SMART_STATUS: if (!s->smart_errors) { - s->hcyl = 0xc2; - s->lcyl = 0x4f; + s->hcyl = 0xc2; + s->lcyl = 0x4f; } else { - s->hcyl = 0x2c; - s->lcyl = 0xf4; + s->hcyl = 0x2c; + s->lcyl = 0xf4; } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); @@ -2094,13 +2117,13 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) + if (smart_attributes[n][0] == 0) break; - s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; - s->io_buffer[2+1+(n*12)] = smart_attributes[n][4]; + s->io_buffer[2+0+(n*12)] = smart_thresholds[n][0]; + s->io_buffer[2+1+(n*12)] = smart_thresholds[n][1]; } for (n=0; n<511; n++) /* checksum */ - s->io_buffer[511] += s->io_buffer[n]; + s->io_buffer[511] += s->io_buffer[n]; s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); @@ -2110,21 +2133,22 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) + if (smart_attributes[n][0] == 0) break; - s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; - s->io_buffer[2+1+(n*12)] = smart_attributes[n][1]; - s->io_buffer[2+3+(n*12)] = smart_attributes[n][2]; - s->io_buffer[2+4+(n*12)] = smart_attributes[n][3]; + int i; + for(i = 0; i < 12; i++) { + s->io_buffer[2+i+(n*12)] = smart_attributes[n][i]; + } } + s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00); if (s->smart_selftest_count == 0) { - s->io_buffer[363] = 0; + s->io_buffer[363] = 0; } else { - s->io_buffer[363] = + s->io_buffer[363] = s->smart_selftest_data[3 + - (s->smart_selftest_count - 1) * - 24]; + (s->smart_selftest_count - 1) * + 24]; } s->io_buffer[364] = 0x20; s->io_buffer[365] = 0x01; @@ -2136,9 +2160,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->io_buffer[372] = 0x02; /* minutes for poll short test */ s->io_buffer[373] = 0x36; /* minutes for poll ext test */ s->io_buffer[374] = 0x01; /* minutes for poll conveyance */ - - for (n=0; n<511; n++) - s->io_buffer[511] += s->io_buffer[n]; + for (n=0; n<511; n++) { /* checksum */ + s->io_buffer[511] += s->io_buffer[n]; + } s->io_buffer[511] = 0x100 - s->io_buffer[511]; s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); @@ -2147,32 +2171,31 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_READ_LOG: switch (s->sector) { case 0x01: /* summary smart error log */ - memset(s->io_buffer, 0, 0x200); - s->io_buffer[0] = 0x01; - s->io_buffer[1] = 0x00; /* no error entries */ - s->io_buffer[452] = s->smart_errors & 0xff; - s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; - - for (n=0; n<511; n++) + memset(s->io_buffer, 0, 0x200); + s->io_buffer[0] = 0x01; + s->io_buffer[1] = 0x00; /* no error entries */ + s->io_buffer[452] = s->smart_errors & 0xff; + s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8; + for (n=0; n<511; n++) s->io_buffer[511] += s->io_buffer[n]; - s->io_buffer[511] = 0x100 - s->io_buffer[511]; - break; + s->io_buffer[511] = 0x100 - s->io_buffer[511]; + break; case 0x06: /* smart self test log */ - memset(s->io_buffer, 0, 0x200); - s->io_buffer[0] = 0x01; - if (s->smart_selftest_count == 0) { + memset(s->io_buffer, 0, 0x200); + s->io_buffer[0] = 0x01; + if (s->smart_selftest_count == 0) { s->io_buffer[508] = 0; - } else { + } else { s->io_buffer[508] = s->smart_selftest_count; for (n=2; n<506; n++) - s->io_buffer[n] = s->smart_selftest_data[n]; - } - for (n=0; n<511; n++) + s->io_buffer[n] = s->smart_selftest_data[n]; + } + for (n=0; n<511; n++) s->io_buffer[511] += s->io_buffer[n]; - s->io_buffer[511] = 0x100 - s->io_buffer[511]; - break; + s->io_buffer[511] = 0x100 - s->io_buffer[511]; + break; default: - goto abort_cmd; + goto abort_cmd; } s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);