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_t cmd
, int argc
, char **args
) // state????
275 struct grub_arg_list
*state
= cmd
->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
,
413 GRUB_COMMAND_FLAG_BOTH
,
414 N_("[OPTIONS] DISK"),
415 N_("Get/set ATA disk parameters."), options
);
418 GRUB_MOD_FINI(hdparm
)
420 grub_unregister_extcmd (cmd
);