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>
28 static const struct grub_arg_option options
[] = {
29 {"apm", 'B', 0, "set Advanced Power Management\n"
30 "(1=low, ..., 254=high, 255=off)",
32 {"power", 'C', 0, "check power mode", 0, ARG_TYPE_NONE
},
33 {"security-freeze", 'F', 0, "freeze ATA security settings until reset",
35 {"health", 'H', 0, "check SMART health status", 0, ARG_TYPE_NONE
},
36 {"aam", 'M', 0, "set Automatic Acoustic Management\n"
37 "(0=off, 128=quiet, ..., 254=fast)",
39 {"standby-timeout", 'S', 0, "set standby timeout\n"
40 "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)",
42 {"standby", 'y', 0, "set drive to standby mode", 0, ARG_TYPE_NONE
},
43 {"sleep", 'Y', 0, "set drive to sleep mode", 0, ARG_TYPE_NONE
},
44 {"identify", 'i', 0, "print drive identity and settings",
46 {"dumpid", 'I', 0, "dump contents of ATA IDENTIFY sector",
48 {"smart", -1, 0, "disable/enable SMART (0/1)", 0, ARG_TYPE_INT
},
49 {"quiet", 'q', 0, "do not print messages", 0, ARG_TYPE_NONE
},
53 enum grub_ata_smart_commands
55 GRUB_ATA_FEAT_SMART_ENABLE
= 0xd8,
56 GRUB_ATA_FEAT_SMART_DISABLE
= 0xd9,
57 GRUB_ATA_FEAT_SMART_STATUS
= 0xda,
63 grub_hdparm_do_ata_cmd (grub_disk_t disk
, grub_uint8_t cmd
,
64 grub_uint8_t features
, grub_uint8_t sectors
,
65 void * buffer
, int size
)
67 struct grub_disk_ata_pass_through_parms apt
;
68 grub_memset (&apt
, 0, sizeof (apt
));
70 apt
.taskfile
[GRUB_ATA_REG_CMD
] = cmd
;
71 apt
.taskfile
[GRUB_ATA_REG_FEATURES
] = features
;
72 apt
.taskfile
[GRUB_ATA_REG_SECTORS
] = sectors
;
76 if (grub_disk_ata_pass_through (disk
, &apt
))
83 grub_hdparm_do_check_powermode_cmd (grub_disk_t disk
)
85 struct grub_disk_ata_pass_through_parms apt
;
86 grub_memset (&apt
, 0, sizeof (apt
));
88 apt
.taskfile
[GRUB_ATA_REG_CMD
] = GRUB_ATA_CMD_CHECK_POWER_MODE
;
90 if (grub_disk_ata_pass_through (disk
, &apt
))
93 return apt
.taskfile
[GRUB_ATA_REG_SECTORS
];
97 grub_hdparm_do_smart_cmd (grub_disk_t disk
, grub_uint8_t features
)
99 struct grub_disk_ata_pass_through_parms apt
;
100 grub_memset (&apt
, 0, sizeof (apt
));
102 apt
.taskfile
[GRUB_ATA_REG_CMD
] = GRUB_ATA_CMD_SMART
;
103 apt
.taskfile
[GRUB_ATA_REG_FEATURES
] = features
;
104 apt
.taskfile
[GRUB_ATA_REG_LBAMID
] = 0x4f;
105 apt
.taskfile
[GRUB_ATA_REG_LBAHIGH
] = 0xc2;
107 if (grub_disk_ata_pass_through (disk
, &apt
))
110 if (features
== GRUB_ATA_FEAT_SMART_STATUS
)
112 if ( apt
.taskfile
[GRUB_ATA_REG_LBAMID
] == 0x4f
113 && apt
.taskfile
[GRUB_ATA_REG_LBAHIGH
] == 0xc2)
114 return 0; /* Good SMART status. */
115 else if ( apt
.taskfile
[GRUB_ATA_REG_LBAMID
] == 0xf4
116 && apt
.taskfile
[GRUB_ATA_REG_LBAHIGH
] == 0x2c)
117 return 1; /* Bad SMART status. */
125 grub_hdparm_simple_cmd (const char * msg
,
126 grub_disk_t disk
, grub_uint8_t cmd
)
131 grub_printf ("%s", msg
);
133 err
= grub_hdparm_do_ata_cmd (disk
, cmd
, 0, 0, NULL
, 0);
136 grub_printf ("%s\n", ! err
? "" : ": not supported");
141 grub_hdparm_set_val_cmd (const char * msg
, int val
,
142 grub_disk_t disk
, grub_uint8_t cmd
,
143 grub_uint8_t features
, grub_uint8_t sectors
)
147 if (! quiet
&& msg
&& *msg
)
150 grub_printf ("Set %s to %d", msg
, val
);
152 grub_printf ("Disable %s", msg
);
155 err
= grub_hdparm_do_ata_cmd (disk
, cmd
, features
, sectors
, NULL
, 0);
158 grub_printf ("%s\n", ! err
? "" : ": not supported");
163 le16_to_char (char *dest
, const grub_uint16_t
* src16
, unsigned bytes
)
165 grub_uint16_t
* dest16
= (grub_uint16_t
*) dest
;
167 for (i
= 0; i
< bytes
/ 2; i
++)
168 dest16
[i
] = grub_be_to_cpu16 (src16
[i
]);
173 grub_hdparm_print_identify (const char * idbuf
)
175 const grub_uint16_t
* idw
= (const grub_uint16_t
*) idbuf
;
176 grub_uint16_t features1
;
177 grub_uint16_t features2
;
178 grub_uint16_t enabled1
;
179 grub_uint16_t enabled2
;
180 grub_uint16_t security
;
183 /* Print identity strings. */
184 grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp
, &idw
[27], 40));
185 grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp
, &idw
[23], 8));
186 grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp
, &idw
[10], 20));
188 /* Print AAM, APM and SMART settings. */
189 features1
= grub_le_to_cpu16 (idw
[82]);
190 features2
= grub_le_to_cpu16 (idw
[83]);
191 enabled1
= grub_le_to_cpu16 (idw
[85]);
192 enabled2
= grub_le_to_cpu16 (idw
[86]);
194 grub_printf ("Automatic Acoustic Management: ");
195 if (features2
& 0x0200)
197 if (enabled2
& 0x0200)
199 grub_uint16_t aam
= grub_le_to_cpu16 (idw
[94]);
200 grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
201 aam
& 0xff, (aam
>> 8) & 0xff);
204 grub_printf ("disabled\n");
207 grub_printf ("not supported\n");
209 grub_printf ("Advanced Power Management: ");
210 if (features2
& 0x0008)
212 if (enabled2
& 0x0008)
213 grub_printf ("%u (1=low, ..., 254=high)\n",
214 grub_le_to_cpu16 (idw
[91]) & 0xff);
216 grub_printf ("disabled\n");
219 grub_printf ("not supported\n");
221 grub_printf ("SMART Feature Set: ");
222 if (features1
& 0x0001)
223 grub_printf ("%sabled\n", (enabled1
& 0x0001 ? "en" : "dis"));
225 grub_printf ("not supported\n");
227 /* Print security settings. */
228 security
= grub_le_to_cpu16 (idw
[128]);
230 grub_printf ("ATA Security: ");
231 if (security
& 0x0001)
232 grub_printf ("%s, %s, %s, %s\n",
233 (security
& 0x0002 ? "ENABLED" : "disabled"),
234 (security
& 0x0004 ? "**LOCKED**" : "not locked"),
235 (security
& 0x0008 ? "frozen" : "NOT FROZEN"),
236 (security
& 0x0010 ? "COUNT EXPIRED" : "count not expired"));
238 grub_printf ("not supported\n");
242 grub_hdparm_print_standby_tout (int timeout
)
246 else if (timeout
<= 252 || timeout
== 255)
248 int h
= 0, m
= 0 , s
= 0;
254 else if (timeout
== 252)
256 else if (timeout
<= 240)
264 m
= (timeout
- 240) * 30;
268 grub_printf ("%02d:%02d:%02d", h
, m
, s
);
271 grub_printf ("invalid or vendor-specific");
274 static int get_int_arg (const struct grub_arg_list
*state
)
276 return (state
->set
? (int)grub_strtoul (state
->arg
, 0, 0) : -1);
280 grub_cmd_hdparm (grub_extcmd_t cmd
, int argc
, char **args
) // state????
282 struct grub_arg_list
*state
= cmd
->state
;
299 /* Check command line. */
301 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "missing device name argument");
303 len
= grub_strlen (args
[0]);
304 if (! (args
[0][0] == '(' && args
[0][len
- 1] == ')'))
305 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "argument is not a device name");
306 args
[0][len
- 1] = 0;
308 if (! grub_disk_ata_pass_through
)
309 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "ATA pass through not available");
312 apm
= get_int_arg (&state
[i
++]);
313 power
= state
[i
++].set
;
314 sec_freeze
= state
[i
++].set
;
315 health
= state
[i
++].set
;
316 aam
= get_int_arg (&state
[i
++]);
317 standby_tout
= get_int_arg (&state
[i
++]);
318 standby_now
= state
[i
++].set
;
319 sleep_now
= state
[i
++].set
;
320 ident
= state
[i
++].set
;
321 dumpid
= state
[i
++].set
;
322 enable_smart
= get_int_arg (&state
[i
++]);
323 quiet
= state
[i
++].set
;
326 disk
= grub_disk_open (&args
[0][1]);
332 grub_disk_close (disk
);
333 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "partition not allowed");
336 /* Change settings. */
338 grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam
? aam
: -1),
339 disk
, GRUB_ATA_CMD_SET_FEATURES
, (aam
? 0x42 : 0xc2), aam
);
342 grub_hdparm_set_val_cmd ("Advanced Power Management",
343 (apm
!= 255 ? apm
: -1), disk
, GRUB_ATA_CMD_SET_FEATURES
,
344 (apm
!= 255 ? 0x05 : 0x85), (apm
!= 255 ? apm
: 0));
346 if (standby_tout
>= 0)
350 grub_printf ("Set standby timeout to %d (", standby_tout
);
351 grub_hdparm_print_standby_tout (standby_tout
);
354 /* The IDLE cmd sets disk to idle mode and configures standby timer. */
355 grub_hdparm_set_val_cmd ("", -1, disk
, GRUB_ATA_CMD_IDLE
, 0, standby_tout
);
358 if (enable_smart
>= 0)
363 grub_printf ("%sable SMART operations", (enable_smart
? "En" : "Dis"));
364 err
= grub_hdparm_do_smart_cmd (disk
, (enable_smart
?
365 GRUB_ATA_FEAT_SMART_ENABLE
366 : GRUB_ATA_FEAT_SMART_DISABLE
));
368 grub_printf ("%s\n", err
? ": not supported" : "");
372 grub_hdparm_simple_cmd ("Freeze security settings", disk
,
373 GRUB_ATA_CMD_SECURITY_FREEZE_LOCK
);
375 /* Print/dump IDENTIFY. */
378 char buf
[GRUB_DISK_SECTOR_SIZE
];
379 if (grub_hdparm_do_ata_cmd (disk
, GRUB_ATA_CMD_IDENTIFY_DEVICE
,
380 0, 0, buf
, sizeof (buf
)))
381 grub_printf ("Cannot read ATA IDENTIFY data\n");
385 grub_hdparm_print_identify (buf
);
387 hexdump (0, buf
, sizeof (buf
));
391 /* Check power mode. */
396 grub_printf ("Disk power mode is: ");
397 mode
= grub_hdparm_do_check_powermode_cmd (disk
);
399 grub_printf ("unknown\n");
401 grub_printf ("%s (0x%02x)\n",
402 (mode
== 0xff ? "active/idle" :
403 mode
== 0x80 ? "idle" :
404 mode
== 0x00 ? "standby" : "unknown"), mode
);
413 grub_printf ("SMART status is: ");
414 err
= grub_hdparm_do_smart_cmd (disk
, GRUB_ATA_FEAT_SMART_STATUS
);
416 grub_printf ("%s\n", (err
< 0 ? "unknown" :
417 err
== 0 ? "OK" : "*BAD*"));
421 /* Change power mode. */
423 grub_hdparm_simple_cmd ("Set disk to standby mode", disk
,
424 GRUB_ATA_CMD_STANDBY_IMMEDIATE
);
427 grub_hdparm_simple_cmd ("Set disk to sleep mode", disk
,
430 grub_disk_close (disk
);
432 grub_errno
= GRUB_ERR_NONE
;
436 static grub_extcmd_t cmd
;
438 GRUB_MOD_INIT(hdparm
)
440 cmd
= grub_register_extcmd ("hdparm", grub_cmd_hdparm
,
441 GRUB_COMMAND_FLAG_BOTH
,
442 "hdparm [OPTIONS] DISK",
443 "Get/set ATA disk parameters.", options
);
446 GRUB_MOD_FINI(hdparm
)
448 grub_unregister_extcmd (cmd
);