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/scsi.h>
22 #include <grub/disk.h>
24 #include <grub/misc.h>
26 #include <grub/lib/hexdump.h>
27 #include <grub/extcmd.h>
28 #include <grub/i18n.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
32 static const struct grub_arg_option options
[] = {
33 {"apm", 'B', 0, N_("Set Advanced Power Management\n"
34 "(1=low, ..., 254=high, 255=off)."),
36 {"power", 'C', 0, N_("Display power mode."), 0, ARG_TYPE_NONE
},
37 {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
39 {"health", 'H', 0, N_("Display SMART health status."), 0, ARG_TYPE_NONE
},
40 {"aam", 'M', 0, N_("Set Automatic Acoustic Management\n"
41 "(0=off, 128=quiet, ..., 254=fast)."),
43 {"standby-timeout", 'S', 0, N_("Set standby timeout\n"
44 "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
46 {"standby", 'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE
},
47 {"sleep", 'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE
},
48 {"identify", 'i', 0, N_("Print drive identity and settings."),
50 {"dumpid", 'I', 0, N_("Show raw contents of ATA IDENTIFY sector."),
52 {"smart", -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT
},
53 {"quiet", 'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE
},
57 enum grub_ata_smart_commands
59 GRUB_ATA_FEAT_SMART_ENABLE
= 0xd8,
60 GRUB_ATA_FEAT_SMART_DISABLE
= 0xd9,
61 GRUB_ATA_FEAT_SMART_STATUS
= 0xda,
67 grub_hdparm_do_ata_cmd (grub_ata_t ata
, grub_uint8_t cmd
,
68 grub_uint8_t features
, grub_uint8_t sectors
,
69 void * buffer
, int size
)
71 struct grub_disk_ata_pass_through_parms apt
;
72 grub_memset (&apt
, 0, sizeof (apt
));
74 apt
.taskfile
.cmd
= cmd
;
75 apt
.taskfile
.features
= features
;
76 apt
.taskfile
.sectors
= sectors
;
77 apt
.taskfile
.disk
= 0xE0;
82 if (ata
->dev
->readwrite (ata
, &apt
, 0))
89 grub_hdparm_do_check_powermode_cmd (grub_ata_t ata
)
91 struct grub_disk_ata_pass_through_parms apt
;
92 grub_memset (&apt
, 0, sizeof (apt
));
94 apt
.taskfile
.cmd
= GRUB_ATA_CMD_CHECK_POWER_MODE
;
95 apt
.taskfile
.disk
= 0xE0;
97 if (ata
->dev
->readwrite (ata
, &apt
, 0))
100 return apt
.taskfile
.sectors
;
104 grub_hdparm_do_smart_cmd (grub_ata_t ata
, grub_uint8_t features
)
106 struct grub_disk_ata_pass_through_parms apt
;
107 grub_memset (&apt
, 0, sizeof (apt
));
109 apt
.taskfile
.cmd
= GRUB_ATA_CMD_SMART
;
110 apt
.taskfile
.features
= features
;
111 apt
.taskfile
.lba_mid
= 0x4f;
112 apt
.taskfile
.lba_high
= 0xc2;
113 apt
.taskfile
.disk
= 0xE0;
115 if (ata
->dev
->readwrite (ata
, &apt
, 0))
118 if (features
== GRUB_ATA_FEAT_SMART_STATUS
)
120 if ( apt
.taskfile
.lba_mid
== 0x4f
121 && apt
.taskfile
.lba_high
== 0xc2)
122 return 0; /* Good SMART status. */
123 else if ( apt
.taskfile
.lba_mid
== 0xf4
124 && apt
.taskfile
.lba_high
== 0x2c)
125 return 1; /* Bad SMART status. */
133 grub_hdparm_simple_cmd (const char * msg
,
134 grub_ata_t ata
, grub_uint8_t cmd
)
137 grub_printf ("%s", msg
);
139 grub_err_t err
= grub_hdparm_do_ata_cmd (ata
, cmd
, 0, 0, NULL
, 0);
142 grub_printf ("%s\n", ! err
? "" : ": not supported");
147 grub_hdparm_set_val_cmd (const char * msg
, int val
,
148 grub_ata_t ata
, grub_uint8_t cmd
,
149 grub_uint8_t features
, grub_uint8_t sectors
)
151 if (! quiet
&& msg
&& *msg
)
154 grub_printf ("Set %s to %d", msg
, val
);
156 grub_printf ("Disable %s", msg
);
159 grub_err_t err
= grub_hdparm_do_ata_cmd (ata
, cmd
, features
, sectors
,
163 grub_printf ("%s\n", ! err
? "" : ": not supported");
168 le16_to_char (grub_uint16_t
*dest
, const grub_uint16_t
* src16
, unsigned bytes
)
171 for (i
= 0; i
< bytes
/ 2; i
++)
172 dest
[i
] = grub_swap_bytes16 (src16
[i
]);
174 return (char *) dest
;
178 grub_hdparm_print_identify (const grub_uint16_t
* idw
)
180 /* Print identity strings. */
181 grub_uint16_t tmp
[21];
182 grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp
, &idw
[27], 40));
183 grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp
, &idw
[23], 8));
184 grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp
, &idw
[10], 20));
186 /* Print AAM, APM and SMART settings. */
187 grub_uint16_t features1
= grub_le_to_cpu16 (idw
[82]);
188 grub_uint16_t features2
= grub_le_to_cpu16 (idw
[83]);
189 grub_uint16_t enabled1
= grub_le_to_cpu16 (idw
[85]);
190 grub_uint16_t enabled2
= grub_le_to_cpu16 (idw
[86]);
192 grub_printf ("Automatic Acoustic Management: ");
193 if (features2
& 0x0200)
195 if (enabled2
& 0x0200)
197 grub_uint16_t aam
= grub_le_to_cpu16 (idw
[94]);
198 grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
199 aam
& 0xff, (aam
>> 8) & 0xff);
202 grub_printf ("disabled\n");
205 grub_printf ("not supported\n");
207 grub_printf ("Advanced Power Management: ");
208 if (features2
& 0x0008)
210 if (enabled2
& 0x0008)
211 grub_printf ("%u (1=low, ..., 254=high)\n",
212 grub_le_to_cpu16 (idw
[91]) & 0xff);
214 grub_printf ("disabled\n");
217 grub_printf ("not supported\n");
219 grub_printf ("SMART Feature Set: ");
220 if (features1
& 0x0001)
221 grub_printf ("%sabled\n", (enabled1
& 0x0001 ? "en" : "dis"));
223 grub_printf ("not supported\n");
225 /* Print security settings. */
226 grub_uint16_t security
= grub_le_to_cpu16 (idw
[128]);
228 grub_printf ("ATA Security: ");
229 if (security
& 0x0001)
230 grub_printf ("%s, %s, %s, %s\n",
231 (security
& 0x0002 ? "ENABLED" : "disabled"),
232 (security
& 0x0004 ? "**LOCKED**" : "not locked"),
233 (security
& 0x0008 ? "frozen" : "NOT FROZEN"),
234 (security
& 0x0010 ? "COUNT EXPIRED" : "count not expired"));
236 grub_printf ("not supported\n");
240 grub_hdparm_print_standby_tout (int timeout
)
244 else if (timeout
<= 252 || timeout
== 255)
246 int h
= 0, m
= 0 , s
= 0;
252 else if (timeout
== 252)
254 else if (timeout
<= 240)
262 m
= (timeout
- 240) * 30;
266 grub_printf ("%02d:%02d:%02d", h
, m
, s
);
269 grub_printf ("invalid or vendor-specific");
272 static int get_int_arg (const struct grub_arg_list
*state
)
274 return (state
->set
? (int)grub_strtoul (state
->arg
, 0, 0) : -1);
278 grub_cmd_hdparm (grub_extcmd_context_t ctxt
, int argc
, char **args
)
280 struct grub_arg_list
*state
= ctxt
->state
;
281 struct grub_ata
*ata
;
282 const char *diskname
;
284 /* Check command line. */
286 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
288 if (args
[0][0] == '(')
290 grub_size_t len
= grub_strlen (args
[0]);
291 if (args
[0][len
- 1] == ')')
292 args
[0][len
- 1] = 0;
293 diskname
= &args
[0][1];
296 diskname
= &args
[0][0];
299 int apm
= get_int_arg (&state
[i
++]);
300 int power
= state
[i
++].set
;
301 int sec_freeze
= state
[i
++].set
;
302 int health
= state
[i
++].set
;
303 int aam
= get_int_arg (&state
[i
++]);
304 int standby_tout
= get_int_arg (&state
[i
++]);
305 int standby_now
= state
[i
++].set
;
306 int sleep_now
= state
[i
++].set
;
307 int ident
= state
[i
++].set
;
308 int dumpid
= state
[i
++].set
;
309 int enable_smart
= get_int_arg (&state
[i
++]);
310 quiet
= state
[i
++].set
;
313 grub_disk_t disk
= grub_disk_open (diskname
);
317 switch (disk
->dev
->id
)
319 case GRUB_DISK_DEVICE_ATA_ID
:
322 case GRUB_DISK_DEVICE_SCSI_ID
:
323 if (((disk
->id
>> GRUB_SCSI_ID_SUBSYSTEM_SHIFT
) & 0xFF)
324 == GRUB_SCSI_SUBSYSTEM_PATA
325 || (((disk
->id
>> GRUB_SCSI_ID_SUBSYSTEM_SHIFT
) & 0xFF)
326 == GRUB_SCSI_SUBSYSTEM_AHCI
))
328 ata
= ((struct grub_scsi
*) disk
->data
)->data
;
332 grub_disk_close (disk
);
333 return grub_error (GRUB_ERR_IO
, "not an ATA device");
337 /* Change settings. */
339 grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam
? aam
: -1),
340 ata
, GRUB_ATA_CMD_SET_FEATURES
,
341 (aam
? 0x42 : 0xc2), aam
);
344 grub_hdparm_set_val_cmd ("Advanced Power Management",
345 (apm
!= 255 ? apm
: -1), ata
,
346 GRUB_ATA_CMD_SET_FEATURES
,
347 (apm
!= 255 ? 0x05 : 0x85),
348 (apm
!= 255 ? apm
: 0));
350 if (standby_tout
>= 0)
354 grub_printf ("Set standby timeout to %d (", standby_tout
);
355 grub_hdparm_print_standby_tout (standby_tout
);
358 /* The IDLE cmd sets disk to idle mode and configures standby timer. */
359 grub_hdparm_set_val_cmd ("", -1, ata
, GRUB_ATA_CMD_IDLE
, 0, standby_tout
);
362 if (enable_smart
>= 0)
365 grub_printf ("%sable SMART operations", (enable_smart
? "En" : "Dis"));
366 int err
= grub_hdparm_do_smart_cmd (ata
, (enable_smart
?
367 GRUB_ATA_FEAT_SMART_ENABLE
: GRUB_ATA_FEAT_SMART_DISABLE
));
369 grub_printf ("%s\n", err
? ": not supported" : "");
373 grub_hdparm_simple_cmd ("Freeze security settings", ata
,
374 GRUB_ATA_CMD_SECURITY_FREEZE_LOCK
);
376 /* Print/dump IDENTIFY. */
379 grub_uint16_t buf
[GRUB_DISK_SECTOR_SIZE
/ 2];
380 if (grub_hdparm_do_ata_cmd (ata
, GRUB_ATA_CMD_IDENTIFY_DEVICE
,
381 0, 0, buf
, sizeof (buf
)))
382 grub_printf ("Cannot read ATA IDENTIFY data\n");
386 grub_hdparm_print_identify (buf
);
388 hexdump (0, (char *) buf
, sizeof (buf
));
392 /* Check power mode. */
395 grub_printf ("Disk power mode is: ");
396 int mode
= grub_hdparm_do_check_powermode_cmd (ata
);
398 grub_printf ("unknown\n");
400 grub_printf ("%s (0x%02x)\n",
401 (mode
== 0xff ? "active/idle" :
402 mode
== 0x80 ? "idle" :
403 mode
== 0x00 ? "standby" : "unknown"), mode
);
411 grub_printf ("SMART status is: ");
412 int err
= grub_hdparm_do_smart_cmd (ata
, GRUB_ATA_FEAT_SMART_STATUS
);
414 grub_printf ("%s\n", (err
< 0 ? "unknown" :
415 err
== 0 ? "OK" : "*BAD*"));
419 /* Change power mode. */
421 grub_hdparm_simple_cmd ("Set disk to standby mode", ata
,
422 GRUB_ATA_CMD_STANDBY_IMMEDIATE
);
425 grub_hdparm_simple_cmd ("Set disk to sleep mode", ata
,
428 grub_disk_close (disk
);
430 grub_errno
= GRUB_ERR_NONE
;
434 static grub_extcmd_t cmd
;
436 GRUB_MOD_INIT(hdparm
)
438 cmd
= grub_register_extcmd ("hdparm", grub_cmd_hdparm
, 0,
439 N_("[OPTIONS] DISK"),
440 N_("Get/set ATA disk parameters."), options
);
443 GRUB_MOD_FINI(hdparm
)
445 grub_unregister_extcmd (cmd
);