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
)
129 grub_printf ("%s", msg
);
131 grub_err_t err
= grub_hdparm_do_ata_cmd (disk
, cmd
, 0, 0, NULL
, 0);
134 grub_printf ("%s\n", ! err
? "" : ": not supported");
139 grub_hdparm_set_val_cmd (const char * msg
, int val
,
140 grub_disk_t disk
, grub_uint8_t cmd
,
141 grub_uint8_t features
, grub_uint8_t sectors
)
143 if (! quiet
&& msg
&& *msg
)
146 grub_printf ("Set %s to %d", msg
, val
);
148 grub_printf ("Disable %s", msg
);
151 grub_err_t err
= grub_hdparm_do_ata_cmd (disk
, cmd
, features
, sectors
,
155 grub_printf ("%s\n", ! err
? "" : ": not supported");
160 le16_to_char (char *dest
, const grub_uint16_t
* src16
, unsigned bytes
)
162 grub_uint16_t
* dest16
= (grub_uint16_t
*) dest
;
164 for (i
= 0; i
< bytes
/ 2; i
++)
165 dest16
[i
] = grub_be_to_cpu16 (src16
[i
]);
170 grub_hdparm_print_identify (const char * idbuf
)
172 const grub_uint16_t
* idw
= (const grub_uint16_t
*) idbuf
;
174 /* Print identity strings. */
176 grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp
, &idw
[27], 40));
177 grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp
, &idw
[23], 8));
178 grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp
, &idw
[10], 20));
180 /* Print AAM, APM and SMART settings. */
181 grub_uint16_t features1
= grub_le_to_cpu16 (idw
[82]);
182 grub_uint16_t features2
= grub_le_to_cpu16 (idw
[83]);
183 grub_uint16_t enabled1
= grub_le_to_cpu16 (idw
[85]);
184 grub_uint16_t enabled2
= grub_le_to_cpu16 (idw
[86]);
186 grub_printf ("Automatic Acoustic Management: ");
187 if (features2
& 0x0200)
189 if (enabled2
& 0x0200)
191 grub_uint16_t aam
= grub_le_to_cpu16 (idw
[94]);
192 grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
193 aam
& 0xff, (aam
>> 8) & 0xff);
196 grub_printf ("disabled\n");
199 grub_printf ("not supported\n");
201 grub_printf ("Advanced Power Management: ");
202 if (features2
& 0x0008)
204 if (enabled2
& 0x0008)
205 grub_printf ("%u (1=low, ..., 254=high)\n",
206 grub_le_to_cpu16 (idw
[91]) & 0xff);
208 grub_printf ("disabled\n");
211 grub_printf ("not supported\n");
213 grub_printf ("SMART Feature Set: ");
214 if (features1
& 0x0001)
215 grub_printf ("%sabled\n", (enabled1
& 0x0001 ? "en" : "dis"));
217 grub_printf ("not supported\n");
219 /* Print security settings. */
220 grub_uint16_t security
= grub_le_to_cpu16 (idw
[128]);
222 grub_printf ("ATA Security: ");
223 if (security
& 0x0001)
224 grub_printf ("%s, %s, %s, %s\n",
225 (security
& 0x0002 ? "ENABLED" : "disabled"),
226 (security
& 0x0004 ? "**LOCKED**" : "not locked"),
227 (security
& 0x0008 ? "frozen" : "NOT FROZEN"),
228 (security
& 0x0010 ? "COUNT EXPIRED" : "count not expired"));
230 grub_printf ("not supported\n");
234 grub_hdparm_print_standby_tout (int timeout
)
238 else if (timeout
<= 252 || timeout
== 255)
240 int h
= 0, m
= 0 , s
= 0;
246 else if (timeout
== 252)
248 else if (timeout
<= 240)
256 m
= (timeout
- 240) * 30;
260 grub_printf ("%02d:%02d:%02d", h
, m
, s
);
263 grub_printf ("invalid or vendor-specific");
266 static int get_int_arg (const struct grub_arg_list
*state
)
268 return (state
->set
? (int)grub_strtoul (state
->arg
, 0, 0) : -1);
272 grub_cmd_hdparm (grub_extcmd_t cmd
, int argc
, char **args
) // state????
274 struct grub_arg_list
*state
= cmd
->state
;
276 /* Check command line. */
278 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "missing device name argument");
280 grub_size_t len
= grub_strlen (args
[0]);
281 if (! (args
[0][0] == '(' && args
[0][len
- 1] == ')'))
282 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "argument is not a device name");
283 args
[0][len
- 1] = 0;
285 if (! grub_disk_ata_pass_through
)
286 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "ATA pass through not available");
289 int apm
= get_int_arg (&state
[i
++]);
290 int power
= state
[i
++].set
;
291 int sec_freeze
= state
[i
++].set
;
292 int health
= state
[i
++].set
;
293 int aam
= get_int_arg (&state
[i
++]);
294 int standby_tout
= get_int_arg (&state
[i
++]);
295 int standby_now
= state
[i
++].set
;
296 int sleep_now
= state
[i
++].set
;
297 int ident
= state
[i
++].set
;
298 int dumpid
= state
[i
++].set
;
299 int enable_smart
= get_int_arg (&state
[i
++]);
300 quiet
= state
[i
++].set
;
303 grub_disk_t disk
= grub_disk_open (&args
[0][1]);
309 grub_disk_close (disk
);
310 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "partition not allowed");
313 /* Change settings. */
315 grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam
? aam
: -1),
316 disk
, GRUB_ATA_CMD_SET_FEATURES
, (aam
? 0x42 : 0xc2), aam
);
319 grub_hdparm_set_val_cmd ("Advanced Power Management",
320 (apm
!= 255 ? apm
: -1), disk
, GRUB_ATA_CMD_SET_FEATURES
,
321 (apm
!= 255 ? 0x05 : 0x85), (apm
!= 255 ? apm
: 0));
323 if (standby_tout
>= 0)
327 grub_printf ("Set standby timeout to %d (", standby_tout
);
328 grub_hdparm_print_standby_tout (standby_tout
);
331 /* The IDLE cmd sets disk to idle mode and configures standby timer. */
332 grub_hdparm_set_val_cmd ("", -1, disk
, GRUB_ATA_CMD_IDLE
, 0, standby_tout
);
335 if (enable_smart
>= 0)
338 grub_printf ("%sable SMART operations", (enable_smart
? "En" : "Dis"));
339 int err
= grub_hdparm_do_smart_cmd (disk
, (enable_smart
?
340 GRUB_ATA_FEAT_SMART_ENABLE
: GRUB_ATA_FEAT_SMART_DISABLE
));
342 grub_printf ("%s\n", err
? ": not supported" : "");
346 grub_hdparm_simple_cmd ("Freeze security settings", disk
,
347 GRUB_ATA_CMD_SECURITY_FREEZE_LOCK
);
349 /* Print/dump IDENTIFY. */
352 char buf
[GRUB_DISK_SECTOR_SIZE
];
353 if (grub_hdparm_do_ata_cmd (disk
, GRUB_ATA_CMD_IDENTIFY_DEVICE
,
354 0, 0, buf
, sizeof (buf
)))
355 grub_printf ("Cannot read ATA IDENTIFY data\n");
359 grub_hdparm_print_identify (buf
);
361 hexdump (0, buf
, sizeof (buf
));
365 /* Check power mode. */
368 grub_printf ("Disk power mode is: ");
369 int mode
= grub_hdparm_do_check_powermode_cmd (disk
);
371 grub_printf ("unknown\n");
373 grub_printf ("%s (0x%02x)\n",
374 (mode
== 0xff ? "active/idle" :
375 mode
== 0x80 ? "idle" :
376 mode
== 0x00 ? "standby" : "unknown"), mode
);
384 grub_printf ("SMART status is: ");
385 int err
= grub_hdparm_do_smart_cmd (disk
, GRUB_ATA_FEAT_SMART_STATUS
);
387 grub_printf ("%s\n", (err
< 0 ? "unknown" :
388 err
== 0 ? "OK" : "*BAD*"));
392 /* Change power mode. */
394 grub_hdparm_simple_cmd ("Set disk to standby mode", disk
,
395 GRUB_ATA_CMD_STANDBY_IMMEDIATE
);
398 grub_hdparm_simple_cmd ("Set disk to sleep mode", disk
,
401 grub_disk_close (disk
);
403 grub_errno
= GRUB_ERR_NONE
;
407 static grub_extcmd_t cmd
;
409 GRUB_MOD_INIT(hdparm
)
411 cmd
= grub_register_extcmd ("hdparm", grub_cmd_hdparm
,
412 GRUB_COMMAND_FLAG_BOTH
,
413 "hdparm [OPTIONS] DISK",
414 "Get/set ATA disk parameters.", options
);
417 GRUB_MOD_FINI(hdparm
)
419 grub_unregister_extcmd (cmd
);