From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1LQrTF-0001CH-Fq for mharc-grub-devel@gnu.org; Sat, 24 Jan 2009 17:59:21 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LQrTC-00018e-Nu for grub-devel@gnu.org; Sat, 24 Jan 2009 17:59:18 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LQrTA-00017b-TN for grub-devel@gnu.org; Sat, 24 Jan 2009 17:59:18 -0500 Received: from [199.232.76.173] (port=35324 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LQrTA-00017I-KI for grub-devel@gnu.org; Sat, 24 Jan 2009 17:59:16 -0500 Received: from mailout09.t-online.de ([194.25.134.84]:41930) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LQrT9-0002tj-Ma for grub-devel@gnu.org; Sat, 24 Jan 2009 17:59:16 -0500 Received: from fwd07.aul.t-online.de by mailout09.sul.t-online.de with smtp id 1LQrT5-00044H-02; Sat, 24 Jan 2009 23:59:11 +0100 Received: from [10.3.2.2] (Xdfj1+Z1ohrmMRJaK9XFRCOvCkMdYclUJqVWNhSZPMZL0DdV07MVPhPruiBJqx5Zd2@[217.235.189.209]) by fwd07.aul.t-online.de with esmtp id 1LQrSz-0Fxw480; Sat, 24 Jan 2009 23:59:05 +0100 Message-ID: <497B9D35.5010703@t-online.de> Date: Sat, 24 Jan 2009 23:59:01 +0100 From: Christian Franke User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.16) Gecko/20080702 SeaMonkey/1.1.11 MIME-Version: 1.0 To: grub-devel@gnu.org Content-Type: multipart/mixed; boundary="------------020701060803010104010207" X-ID: Xdfj1+Z1ohrmMRJaK9XFRCOvCkMdYclUJqVWNhSZPMZL0DdV07MVPhPruiBJqx5Zd2 X-TOI-MSGID: ad60a3ad-e080-43d4-a353-19f35eaf1a90 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) Subject: [PATCH] hdparm.mod - get/set ATA disk parameters X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 24 Jan 2009 22:59:19 -0000 This is a multi-part message in MIME format. --------------020701060803010104010207 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit This patch adds a command which allows to change a few (S)ATA drive settings. It relies on a new pass-through function in ata.mod. Command name and option syntax are borrowed from the well-known Linux tool. Examples: - Set AAM of system drive to "fast", other drive to "quiet": hdparm -S 254 (ata0) hdparm -S 128 (ata1) - Change APM level (reportedly useful to avoid clicking noise of some Notebook disks): hdparm -B 254 (ata0) - Set standby timeout to 10min (e.g. if disk is likely not used in the selected boot configuration): hdparm -S 120 (ata0) - Set disk to standby or sleep mode (e.g. before running a long memtest): hdparm -y (ata0) hdparm -Y (ata0) - Freeze security settings (some BIOS don't): hdparm -F (ata0) Thanks for any comment. Christian 2009-01-24 Christian Franke * commands/hdparm.c: New file. Provides `hdparm' command which sends ATA commands via grub_ata_pass_through. * conf/i386-pc.rmk: Add hdparm.mod. * disk/ata.c: Include . (GRUB_CDROM_SECTOR_SIZE): Remove. (GRUB_ATA_*): Move to include/grub/ata.h. (GRUB_ATAPI_*): Likewise. (enum grub_ata_commands): Likewise. (grub_ata_pass_through): New function. (GRUB_MOD_INIT): Set grub_disk_ata_pass_through pointer. (GRUB_MOD_FINI): Reset grub_disk_ata_pass_through pointer. * include/grub/ata.h: New file, contains declarations from ata.c. * include/grub/disk.h (grub_disk_ata_pass_through_parms): New struct. (grub_disk_ata_pass_through): New exported variable. * kern/disk.c (grub_disk_ata_pass_through): New variable. --------------020701060803010104010207 Content-Type: text/x-diff; name="grub2-hdparm-mod.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="grub2-hdparm-mod.patch" diff --git a/commands/hdparm.c b/commands/hdparm.c new file mode 100644 index 0000000..e829ced --- /dev/null +++ b/commands/hdparm.c @@ -0,0 +1,340 @@ +/* hdparm.c - command to get/set ATA disk parameters. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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 Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const struct grub_arg_option options[] = { + {"apm", 'B', 0, "Set Advanced Power Management\n" + "(1=low, ..., 254=high, 255=off)", + 0, ARG_TYPE_INT}, + {"power", 'C', 0, "Check power mode", 0, ARG_TYPE_NONE}, + {"security-freeze", 'F', 0, "Freeze ATA security settings until reset", + 0, ARG_TYPE_NONE}, + {"aam", 'M', 0, "Set Automatic Acoustic Management\n" + "(0=off, 128=quiet, ..., 254=fast)", + 0, ARG_TYPE_INT}, + {"standby-timeout", 'S', 0, "Set standby timeout\n" + "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)", + 0, ARG_TYPE_INT}, + {"standby", 'y', 0, "Set drive to standby mode", 0, ARG_TYPE_NONE}, + {"sleep", 'Y', 0, "Set drive to sleep mode", 0, ARG_TYPE_NONE}, + {"identify", 'i', 0, "Print drive identity and settings", + 0, ARG_TYPE_NONE}, + {"dumpid", 'I', 0, "Dump contents of ATA IDENTIFY sector", + 0, ARG_TYPE_NONE}, + {"quiet", 'q', 0, "Do not print messages", 0, ARG_TYPE_NONE}, + {0, 0, 0, 0, 0, 0} +}; + +static int quiet = 0; + +static grub_err_t +grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd, + grub_uint8_t features, grub_uint8_t sectors, + grub_uint8_t *ret_sectors, + void * buffer, int size) +{ + struct grub_disk_ata_pass_through_parms apt; + grub_memset (&apt, 0, sizeof (apt)); + + apt.taskfile[GRUB_ATA_REG_CMD] = cmd; + apt.taskfile[GRUB_ATA_REG_FEATURES] = features; + apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors; + apt.buffer = buffer; + apt.size = size; + + if (grub_disk_ata_pass_through (disk, &apt)) + return grub_errno; + + if (ret_sectors) + *ret_sectors = apt.taskfile[GRUB_ATA_REG_SECTORS]; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_hdparm_simple_cmd (const char * msg, + grub_disk_t disk, grub_uint8_t cmd) +{ + if (! quiet && msg) + grub_printf ("%s", msg); + + grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, NULL, 0); + + if (! quiet && msg) + grub_printf ("%s\n", ! err ? "" : ": not supported"); + return err; +} + +static grub_err_t +grub_hdparm_set_val_cmd (const char * msg, int val, + grub_disk_t disk, grub_uint8_t cmd, + grub_uint8_t features, grub_uint8_t sectors) +{ + if (! quiet && msg && *msg) + { + if (val >= 0) + grub_printf ("Set %s to %d", msg, val); + else + grub_printf ("Disable %s", msg); + } + + grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors, + NULL, NULL, 0); + + if (! quiet && msg) + grub_printf ("%s\n", ! err ? "" : ": not supported"); + return err; +} + +static const char * +le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes) +{ + grub_uint16_t * dest16 = (grub_uint16_t *) dest; + unsigned i; + for (i = 0; i < bytes / 2; i++) + dest16[i] = grub_be_to_cpu16 (src16[i]); + return dest; +} + +static void +grub_hdparm_print_identify (const char * idbuf) +{ + const grub_uint16_t * idw = (const grub_uint16_t *) idbuf; + + /* Print identity strings. */ + char tmp[40]; + grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40)); + grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8)); + grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20)); + + /* Print AAM and APM settings. */ + grub_uint16_t features = grub_le_to_cpu16 (idw[83]); + grub_uint16_t enabled = grub_le_to_cpu16 (idw[86]); + + grub_printf("Automatic Acoustic Management: "); + if (features & 0x0200) + { + if (enabled & 0x0200) + { + grub_uint16_t aam = grub_le_to_cpu16 (idw[94]); + grub_printf("%u (128=quiet, ..., 254=fast, recommended=%u)\n", + aam & 0xff, (aam >> 8) & 0xff); + } + else + grub_printf("disabled\n"); + } + else + grub_printf("not supported\n"); + + grub_printf("Advanced Power Management: "); + if (features & 0x0008) + { + if (enabled & 0x0008) + grub_printf ("%u (1=low, ..., 254=high)\n", + grub_le_to_cpu16 (idw[91]) & 0xff); + else + grub_printf ("disabled\n"); + } + else + grub_printf ("not supported\n"); + + /* Print security settings. */ + grub_uint16_t security = grub_le_to_cpu16 (idw[128]); + + grub_printf("ATA Security: "); + if (security & 0x0001) + grub_printf ("%s, %s, %s, %s\n", + (security & 0x0002 ? "ENABLED" : "disabled"), + (security & 0x0004 ? "**LOCKED**" : "not locked"), + (security & 0x0008 ? "frozen" : "NOT FROZEN"), + (security & 0x0010 ? "COUNT EXPIRED" : "count not expired")); + else + grub_printf ("no supported\n"); +} + +static void +grub_hdparm_print_standby_tout (int timeout) +{ + if (timeout == 0) + grub_printf ("off"); + else if (timeout <= 252 || timeout == 255) + { + int h = 0, m = 0 , s = 0; + if (timeout == 255) + { + m = 21; + s = 15; + } + else if (timeout == 252) + m = 21; + else if (timeout <= 240) + { + s = timeout * 5; + m = s / 60; + s %= 60; + } + else + { + m = (timeout - 240) * 30; + h = m / 60; + m %= 60; + } + grub_printf("%02d:%02d:%02d", h, m, s); + } + else + grub_printf("invalid or vendor-specific"); +} + +static int get_int_arg (const struct grub_arg_list *state) +{ + return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1); +} + + +static grub_err_t +grub_cmd_hdparm (struct grub_arg_list *state, int argc, char **args) // state???? +{ + /* Check command line. */ + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument"); + + grub_size_t len = grub_strlen (args[0]); + if (! (args[0][0] == '(' && args[0][len - 1] == ')')) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name"); + args[0][len - 1] = 0; + + if (! grub_disk_ata_pass_through) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available"); + + int i = 0; + int apm = get_int_arg (&state[i++]); + int power = state[i++].set; + int sec_freeze = state[i++].set; + int aam = get_int_arg (&state[i++]); + int standby_tout = get_int_arg (&state[i++]); + int standby_now = state[i++].set; + int sleep_now = state[i++].set; + int ident = state[i++].set; + int dumpid = state[i++].set; + quiet = state[i++].set; + + /* Open disk. */ + grub_disk_t disk = grub_disk_open (&args[0][1]); + if (! disk) + return grub_errno; + + if (disk->partition) + { + grub_disk_close (disk); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed"); + } + + /* Change settings. */ + if (aam >= 0) + grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1), + disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam); + + if (apm >= 0) + grub_hdparm_set_val_cmd ("Advanced Power Management", + (apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES, + (apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0)); + + if (standby_tout >= 0) + { + if (! quiet) + { + grub_printf ("Set standby timeout to %d (", standby_tout); + grub_hdparm_print_standby_tout (standby_tout); + grub_printf (")"); + } + /* The IDLE cmd sets disk to idle mode and configures standby timer. */ + grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout); + } + + if (sec_freeze) + grub_hdparm_simple_cmd ("Freeze security settings", disk, + GRUB_ATA_CMD_SECURITY_FREEZE_LOCK); + + /* Print/dump IDENTIFY. */ + if (ident || dumpid) + { + char buf[GRUB_DISK_SECTOR_SIZE]; + if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE, + 0, 0, NULL, buf, sizeof(buf))) + grub_printf("Cannot read ATA IDENTIFY data\n"); + else + { + if (ident) + grub_hdparm_print_identify (buf); + if (dumpid) + hexdump (0, buf, sizeof(buf)); + } + } + + /* Check power mode. */ + if (power) + { + grub_printf("Disk power mode is "); + grub_uint8_t mode = 0; + if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_CHECK_POWER_MODE, + 0, 0, &mode, NULL, 0)) + grub_printf ("unknown\n"); + else + grub_printf ("%s (0x%02x)\n", + (mode == 0xff ? "active/idle" : + mode == 0x80 ? "idle" : + mode == 0x00 ? "standby" : "unknown"), mode); + } + + /* Change power mode. */ + if (standby_now) + grub_hdparm_simple_cmd ("Set disk to standby mode", disk, + GRUB_ATA_CMD_STANDBY_IMMEDIATE); + + if (sleep_now) + grub_hdparm_simple_cmd ("Set disk to sleep mode", disk, + GRUB_ATA_CMD_SLEEP); + + grub_disk_close (disk); + grub_errno = GRUB_ERR_NONE; + return 0; +} + + +GRUB_MOD_INIT(hdparm) +{ + (void) mod; + + grub_register_command ("hdparm", grub_cmd_hdparm, GRUB_COMMAND_FLAG_BOTH, + "hdparm [OPTIONS] DISK", + "Get/set ATA disk parameters.", options); +} + +GRUB_MOD_FINI(hdparm) +{ + grub_unregister_command ("hdparm"); +} diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 0998252..a7d652c 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -164,7 +164,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod \ ata.mod vga.mod memdisk.mod pci.mod lspci.mod \ aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \ - datehook.mod lsmmap.mod + datehook.mod lsmmap.mod hdparm.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -321,5 +321,10 @@ lsmmap_mod_SOURCES = commands/lsmmap.c lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For hdparm.mod. +hdparm_mod_SOURCES = commands/hdparm.c lib/hexdump.c +hdparm_mod_CFLAGS = $(COMMON_CFLAGS) +hdparm_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk diff --git a/disk/.ata.c.swp b/disk/.ata.c.swp new file mode 100644 index 0000000..96cc004 Binary files /dev/null and b/disk/.ata.c.swp differ diff --git a/disk/ata.c b/disk/ata.c index e981fe9..6dd417f 100644 --- a/disk/ata.c +++ b/disk/ata.c @@ -1,7 +1,7 @@ /* ata.c - ATA disk access. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007, 2008 Free Software Foundation, Inc. + * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ * along with GRUB. If not, see . */ +#include #include #include #include @@ -38,54 +39,6 @@ typedef enum static const int grub_ata_ioaddress[] = { 0x1f0, 0x170 }; static const int grub_ata_ioaddress2[] = { 0x3f6, 0x376 }; -#define GRUB_CDROM_SECTOR_SIZE 2048 - -#define GRUB_ATA_REG_DATA 0 -#define GRUB_ATA_REG_ERROR 1 -#define GRUB_ATA_REG_FEATURES 1 -#define GRUB_ATA_REG_SECTORS 2 -#define GRUB_ATAPI_REG_IREASON 2 -#define GRUB_ATA_REG_SECTNUM 3 -#define GRUB_ATA_REG_CYLLSB 4 -#define GRUB_ATA_REG_CYLMSB 5 -#define GRUB_ATA_REG_LBALOW 3 -#define GRUB_ATA_REG_LBAMID 4 -#define GRUB_ATAPI_REG_CNTLOW 4 -#define GRUB_ATA_REG_LBAHIGH 5 -#define GRUB_ATAPI_REG_CNTHIGH 5 -#define GRUB_ATA_REG_DISK 6 -#define GRUB_ATA_REG_CMD 7 -#define GRUB_ATA_REG_STATUS 7 - -#define GRUB_ATA_REG2_CONTROL 0 - -#define GRUB_ATA_STATUS_ERR 0x01 -#define GRUB_ATA_STATUS_INDEX 0x02 -#define GRUB_ATA_STATUS_ECC 0x04 -#define GRUB_ATA_STATUS_DRQ 0x08 -#define GRUB_ATA_STATUS_SEEK 0x10 -#define GRUB_ATA_STATUS_WRERR 0x20 -#define GRUB_ATA_STATUS_READY 0x40 -#define GRUB_ATA_STATUS_BUSY 0x80 - -/* ATAPI interrupt reason values (I/O, D/C bits). */ -#define GRUB_ATAPI_IREASON_MASK 0x3 -#define GRUB_ATAPI_IREASON_DATA_OUT 0x0 -#define GRUB_ATAPI_IREASON_CMD_OUT 0x1 -#define GRUB_ATAPI_IREASON_DATA_IN 0x2 -#define GRUB_ATAPI_IREASON_ERROR 0x3 - -enum grub_ata_commands - { - GRUB_ATA_CMD_READ_SECTORS = 0x20, - GRUB_ATA_CMD_READ_SECTORS_EXT = 0x24, - GRUB_ATA_CMD_WRITE_SECTORS = 0x30, - GRUB_ATA_CMD_WRITE_SECTORS_EXT = 0x34, - GRUB_ATA_CMD_IDENTIFY_DEVICE = 0xEC, - GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE = 0xA1, - GRUB_ATA_CMD_PACKET = 0xA0, - }; - enum grub_ata_timeout_milliseconds { GRUB_ATA_TOUT_STD = 1000, /* 1s standard timeout. */ @@ -962,6 +915,67 @@ static struct grub_scsi_dev grub_atapi_dev = .write = grub_atapi_write }; +/* ATA pass through support, used by hdparm.mod. */ +static grub_err_t +grub_ata_pass_through (grub_disk_t disk, + struct grub_disk_ata_pass_through_parms *parms) +{ + if (disk->dev->id != GRUB_DISK_DEVICE_ATA_ID) + return grub_error (GRUB_ERR_BAD_DEVICE, + "Device not accessed via ata.mod"); + + struct grub_ata_device *dev = (struct grub_ata_device *) disk->data; + + if (! (parms->size == 0 || parms->size == GRUB_DISK_SECTOR_SIZE)) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "ATA multi-sector read and DATA OUT not implemented"); + + grub_dprintf("ata", "ata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x, size=%d\n", + parms->taskfile[GRUB_ATA_REG_CMD], parms->taskfile[GRUB_ATA_REG_FEATURES], + parms->taskfile[GRUB_ATA_REG_SECTORS], parms->size); + + /* Set registers. */ + grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4 + | (parms->taskfile[GRUB_ATA_REG_DISK] & 0xf)); + if (grub_ata_check_ready (dev)) + return grub_errno; + + int i; + for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++) + grub_ata_regset (dev, i, parms->taskfile[i]); + + /* Start command. */ + grub_ata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile[GRUB_ATA_REG_CMD]); + + /* Wait for !BSY. */ + if (grub_ata_wait_not_busy(dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + /* Check status. */ + grub_int8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); + grub_dprintf("ata", "status=%x\n", sts); + + /* Transfer data. */ + if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_DRQ) + { + if (parms->size != GRUB_DISK_SECTOR_SIZE) + return grub_error (GRUB_ERR_READ_ERROR, "DRQ unexpected"); + grub_ata_pio_read (dev, parms->buffer, GRUB_DISK_SECTOR_SIZE); + } + + /* Return registers. */ + for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++) + parms->taskfile[i] = grub_ata_regget (dev, i); + + grub_dprintf("ata", "status=%x, error=%x\n", sts, + parms->taskfile[GRUB_ATA_REG_ERROR]); + + if (parms->taskfile[GRUB_ATA_REG_STATUS] & (GRUB_ATA_STATUS_DRQ|GRUB_ATA_STATUS_ERR)) + return grub_error (GRUB_ERR_READ_ERROR, "ATA passthrough failed"); + + return GRUB_ERR_NONE; +} + GRUB_MOD_INIT(ata) @@ -983,10 +997,16 @@ GRUB_MOD_INIT(ata) /* ATAPI devices are handled by scsi.mod. */ grub_scsi_dev_register (&grub_atapi_dev); + + /* Register ATA pass through function. */ + grub_disk_ata_pass_through = grub_ata_pass_through; } GRUB_MOD_FINI(ata) { + if (grub_disk_ata_pass_through == grub_ata_pass_through) + grub_disk_ata_pass_through = NULL; + grub_scsi_dev_unregister (&grub_atapi_dev); grub_disk_dev_unregister (&grub_atadisk_dev); } diff --git a/include/grub/ata.h b/include/grub/ata.h new file mode 100644 index 0000000..f4c5d5b --- /dev/null +++ b/include/grub/ata.h @@ -0,0 +1,76 @@ +/* ata.h - ATA disk access. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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 Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + + +#ifndef GRUB_ATA_H +#define GRUB_ATA_H + +#define GRUB_ATA_REG_DATA 0 +#define GRUB_ATA_REG_ERROR 1 +#define GRUB_ATA_REG_FEATURES 1 +#define GRUB_ATA_REG_SECTORS 2 +#define GRUB_ATAPI_REG_IREASON 2 +#define GRUB_ATA_REG_SECTNUM 3 +#define GRUB_ATA_REG_CYLLSB 4 +#define GRUB_ATA_REG_CYLMSB 5 +#define GRUB_ATA_REG_LBALOW 3 +#define GRUB_ATA_REG_LBAMID 4 +#define GRUB_ATAPI_REG_CNTLOW 4 +#define GRUB_ATA_REG_LBAHIGH 5 +#define GRUB_ATAPI_REG_CNTHIGH 5 +#define GRUB_ATA_REG_DISK 6 +#define GRUB_ATA_REG_CMD 7 +#define GRUB_ATA_REG_STATUS 7 + +#define GRUB_ATA_REG2_CONTROL 0 + +#define GRUB_ATA_STATUS_ERR 0x01 +#define GRUB_ATA_STATUS_INDEX 0x02 +#define GRUB_ATA_STATUS_ECC 0x04 +#define GRUB_ATA_STATUS_DRQ 0x08 +#define GRUB_ATA_STATUS_SEEK 0x10 +#define GRUB_ATA_STATUS_WRERR 0x20 +#define GRUB_ATA_STATUS_READY 0x40 +#define GRUB_ATA_STATUS_BUSY 0x80 + +/* ATAPI interrupt reason values (I/O, D/C bits). */ +#define GRUB_ATAPI_IREASON_MASK 0x3 +#define GRUB_ATAPI_IREASON_DATA_OUT 0x0 +#define GRUB_ATAPI_IREASON_CMD_OUT 0x1 +#define GRUB_ATAPI_IREASON_DATA_IN 0x2 +#define GRUB_ATAPI_IREASON_ERROR 0x3 + +enum grub_ata_commands +{ + GRUB_ATA_CMD_CHECK_POWER_MODE = 0xe5, + GRUB_ATA_CMD_IDENTIFY_DEVICE = 0xec, + GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE = 0xa1, + GRUB_ATA_CMD_IDLE = 0xe3, + GRUB_ATA_CMD_PACKET = 0xa0, + GRUB_ATA_CMD_READ_SECTORS = 0x20, + GRUB_ATA_CMD_READ_SECTORS_EXT = 0x24, + GRUB_ATA_CMD_SECURITY_FREEZE_LOCK = 0xf5, + GRUB_ATA_CMD_SET_FEATURES = 0xef, + GRUB_ATA_CMD_SLEEP = 0xe6, + GRUB_ATA_CMD_STANDBY_IMMEDIATE = 0xe0, + GRUB_ATA_CMD_WRITE_SECTORS = 0x30, + GRUB_ATA_CMD_WRITE_SECTORS_EXT = 0x34, +}; + +#endif /* ! GRUB_ATA_H */ diff --git a/include/grub/disk.h b/include/grub/disk.h index f2fa421..1e8046a 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -161,6 +161,17 @@ grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk); extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void); extern int EXPORT_VAR(grub_disk_firmware_is_tainted); +/* ATA pass through parameters and function. */ +struct grub_disk_ata_pass_through_parms +{ + grub_uint8_t taskfile[8]; + void * buffer; + int size; +}; + +extern grub_err_t (* EXPORT_VAR(grub_disk_ata_pass_through)) (grub_disk_t, + struct grub_disk_ata_pass_through_parms *); + #ifdef GRUB_UTIL void grub_raid_init (void); void grub_raid_fini (void); diff --git a/kern/disk.c b/kern/disk.c index ed82506..3f7e451 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -46,6 +46,10 @@ static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM]; void (*grub_disk_firmware_fini) (void); int grub_disk_firmware_is_tainted; +grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t, + struct grub_ata_pass_through_cmd *); + + #if 0 static unsigned long grub_disk_cache_hits; static unsigned long grub_disk_cache_misses; --------------020701060803010104010207--