1
/* hdparm.c - command to get/set ATA disk parameters. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2009 Free Software Foundation, Inc.
6
* GRUB is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* GRUB is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21
#include <grub/disk.h>
23
#include <grub/misc.h>
25
#include <grub/lib/hexdump.h>
26
#include <grub/extcmd.h>
27
#include <grub/i18n.h>
29
static const struct grub_arg_option options[] = {
30
{"apm", 'B', 0, N_("Set Advanced Power Management\n"
31
"(1=low, ..., 254=high, 255=off)."),
33
{"power", 'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE},
34
{"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
36
{"health", 'H', 0, N_("Check SMART health status."), 0, ARG_TYPE_NONE},
37
{"aam", 'M', 0, N_("Set Automatic Acoustic Management\n"
38
"(0=off, 128=quiet, ..., 254=fast)."),
40
{"standby-timeout", 'S', 0, N_("Set standby timeout\n"
41
"(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
43
{"standby", 'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE},
44
{"sleep", 'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE},
45
{"identify", 'i', 0, N_("Print drive identity and settings."),
47
{"dumpid", 'I', 0, N_("Dump contents of ATA IDENTIFY sector."),
49
{"smart", -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT},
50
{"quiet", 'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE},
54
enum grub_ata_smart_commands
56
GRUB_ATA_FEAT_SMART_ENABLE = 0xd8,
57
GRUB_ATA_FEAT_SMART_DISABLE = 0xd9,
58
GRUB_ATA_FEAT_SMART_STATUS = 0xda,
64
grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd,
65
grub_uint8_t features, grub_uint8_t sectors,
66
void * buffer, int size)
68
struct grub_disk_ata_pass_through_parms apt;
69
grub_memset (&apt, 0, sizeof (apt));
71
apt.taskfile[GRUB_ATA_REG_CMD] = cmd;
72
apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
73
apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
77
if (grub_disk_ata_pass_through (disk, &apt))
84
grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
86
struct grub_disk_ata_pass_through_parms apt;
87
grub_memset (&apt, 0, sizeof (apt));
89
apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
91
if (grub_disk_ata_pass_through (disk, &apt))
94
return apt.taskfile[GRUB_ATA_REG_SECTORS];
98
grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
100
struct grub_disk_ata_pass_through_parms apt;
101
grub_memset (&apt, 0, sizeof (apt));
103
apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_SMART;
104
apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
105
apt.taskfile[GRUB_ATA_REG_LBAMID] = 0x4f;
106
apt.taskfile[GRUB_ATA_REG_LBAHIGH] = 0xc2;
108
if (grub_disk_ata_pass_through (disk, &apt))
111
if (features == GRUB_ATA_FEAT_SMART_STATUS)
113
if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0x4f
114
&& apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2)
115
return 0; /* Good SMART status. */
116
else if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0xf4
117
&& apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c)
118
return 1; /* Bad SMART status. */
126
grub_hdparm_simple_cmd (const char * msg,
127
grub_disk_t disk, grub_uint8_t cmd)
130
grub_printf ("%s", msg);
132
grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0);
135
grub_printf ("%s\n", ! err ? "" : ": not supported");
140
grub_hdparm_set_val_cmd (const char * msg, int val,
141
grub_disk_t disk, grub_uint8_t cmd,
142
grub_uint8_t features, grub_uint8_t sectors)
144
if (! quiet && msg && *msg)
147
grub_printf ("Set %s to %d", msg, val);
149
grub_printf ("Disable %s", msg);
152
grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors,
156
grub_printf ("%s\n", ! err ? "" : ": not supported");
161
le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes)
163
grub_uint16_t * dest16 = (grub_uint16_t *) dest;
165
for (i = 0; i < bytes / 2; i++)
166
dest16[i] = grub_be_to_cpu16 (src16[i]);
171
grub_hdparm_print_identify (const char * idbuf)
173
const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
175
/* Print identity strings. */
177
grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40));
178
grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8));
179
grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20));
181
/* Print AAM, APM and SMART settings. */
182
grub_uint16_t features1 = grub_le_to_cpu16 (idw[82]);
183
grub_uint16_t features2 = grub_le_to_cpu16 (idw[83]);
184
grub_uint16_t enabled1 = grub_le_to_cpu16 (idw[85]);
185
grub_uint16_t enabled2 = grub_le_to_cpu16 (idw[86]);
187
grub_printf ("Automatic Acoustic Management: ");
188
if (features2 & 0x0200)
190
if (enabled2 & 0x0200)
192
grub_uint16_t aam = grub_le_to_cpu16 (idw[94]);
193
grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
194
aam & 0xff, (aam >> 8) & 0xff);
197
grub_printf ("disabled\n");
200
grub_printf ("not supported\n");
202
grub_printf ("Advanced Power Management: ");
203
if (features2 & 0x0008)
205
if (enabled2 & 0x0008)
206
grub_printf ("%u (1=low, ..., 254=high)\n",
207
grub_le_to_cpu16 (idw[91]) & 0xff);
209
grub_printf ("disabled\n");
212
grub_printf ("not supported\n");
214
grub_printf ("SMART Feature Set: ");
215
if (features1 & 0x0001)
216
grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis"));
218
grub_printf ("not supported\n");
220
/* Print security settings. */
221
grub_uint16_t security = grub_le_to_cpu16 (idw[128]);
223
grub_printf ("ATA Security: ");
224
if (security & 0x0001)
225
grub_printf ("%s, %s, %s, %s\n",
226
(security & 0x0002 ? "ENABLED" : "disabled"),
227
(security & 0x0004 ? "**LOCKED**" : "not locked"),
228
(security & 0x0008 ? "frozen" : "NOT FROZEN"),
229
(security & 0x0010 ? "COUNT EXPIRED" : "count not expired"));
231
grub_printf ("not supported\n");
235
grub_hdparm_print_standby_tout (int timeout)
239
else if (timeout <= 252 || timeout == 255)
241
int h = 0, m = 0 , s = 0;
247
else if (timeout == 252)
249
else if (timeout <= 240)
257
m = (timeout - 240) * 30;
261
grub_printf ("%02d:%02d:%02d", h, m, s);
264
grub_printf ("invalid or vendor-specific");
267
static int get_int_arg (const struct grub_arg_list *state)
269
return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1);
273
grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
275
struct grub_arg_list *state = ctxt->state;
277
/* Check command line. */
279
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument");
281
grub_size_t len = grub_strlen (args[0]);
282
if (! (args[0][0] == '(' && args[0][len - 1] == ')'))
283
return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name");
284
args[0][len - 1] = 0;
286
if (! grub_disk_ata_pass_through)
287
return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
290
int apm = get_int_arg (&state[i++]);
291
int power = state[i++].set;
292
int sec_freeze = state[i++].set;
293
int health = state[i++].set;
294
int aam = get_int_arg (&state[i++]);
295
int standby_tout = get_int_arg (&state[i++]);
296
int standby_now = state[i++].set;
297
int sleep_now = state[i++].set;
298
int ident = state[i++].set;
299
int dumpid = state[i++].set;
300
int enable_smart = get_int_arg (&state[i++]);
301
quiet = state[i++].set;
304
grub_disk_t disk = grub_disk_open (&args[0][1]);
310
grub_disk_close (disk);
311
return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed");
314
/* Change settings. */
316
grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
317
disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
320
grub_hdparm_set_val_cmd ("Advanced Power Management",
321
(apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES,
322
(apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0));
324
if (standby_tout >= 0)
328
grub_printf ("Set standby timeout to %d (", standby_tout);
329
grub_hdparm_print_standby_tout (standby_tout);
332
/* The IDLE cmd sets disk to idle mode and configures standby timer. */
333
grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout);
336
if (enable_smart >= 0)
339
grub_printf ("%sable SMART operations", (enable_smart ? "En" : "Dis"));
340
int err = grub_hdparm_do_smart_cmd (disk, (enable_smart ?
341
GRUB_ATA_FEAT_SMART_ENABLE : GRUB_ATA_FEAT_SMART_DISABLE));
343
grub_printf ("%s\n", err ? ": not supported" : "");
347
grub_hdparm_simple_cmd ("Freeze security settings", disk,
348
GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
350
/* Print/dump IDENTIFY. */
353
char buf[GRUB_DISK_SECTOR_SIZE];
354
if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE,
355
0, 0, buf, sizeof (buf)))
356
grub_printf ("Cannot read ATA IDENTIFY data\n");
360
grub_hdparm_print_identify (buf);
362
hexdump (0, buf, sizeof (buf));
366
/* Check power mode. */
369
grub_printf ("Disk power mode is: ");
370
int mode = grub_hdparm_do_check_powermode_cmd (disk);
372
grub_printf ("unknown\n");
374
grub_printf ("%s (0x%02x)\n",
375
(mode == 0xff ? "active/idle" :
376
mode == 0x80 ? "idle" :
377
mode == 0x00 ? "standby" : "unknown"), mode);
385
grub_printf ("SMART status is: ");
386
int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS);
388
grub_printf ("%s\n", (err < 0 ? "unknown" :
389
err == 0 ? "OK" : "*BAD*"));
393
/* Change power mode. */
395
grub_hdparm_simple_cmd ("Set disk to standby mode", disk,
396
GRUB_ATA_CMD_STANDBY_IMMEDIATE);
399
grub_hdparm_simple_cmd ("Set disk to sleep mode", disk,
402
grub_disk_close (disk);
404
grub_errno = GRUB_ERR_NONE;
408
static grub_extcmd_t cmd;
410
GRUB_MOD_INIT(hdparm)
412
cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0,
413
N_("[OPTIONS] DISK"),
414
N_("Get/set ATA disk parameters."), options);
417
GRUB_MOD_FINI(hdparm)
419
grub_unregister_extcmd (cmd);