~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to commands/hdparm.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* hdparm.c - command to get/set ATA disk parameters.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2009  Free Software Foundation, Inc.
5
 
 *
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.
10
 
 *
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.
15
 
 *
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/>.
18
 
 */
19
 
 
20
 
#include <grub/ata.h>
21
 
#include <grub/disk.h>
22
 
#include <grub/dl.h>
23
 
#include <grub/misc.h>
24
 
#include <grub/mm.h>
25
 
#include <grub/lib/hexdump.h>
26
 
#include <grub/extcmd.h>
27
 
#include <grub/i18n.h>
28
 
 
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)."),
32
 
                              0, ARG_TYPE_INT},
33
 
  {"power",           'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE},
34
 
  {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
35
 
                              0, ARG_TYPE_NONE},
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)."),
39
 
                              0, ARG_TYPE_INT},
40
 
  {"standby-timeout", 'S', 0, N_("Set standby timeout\n"
41
 
                              "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
42
 
                              0, ARG_TYPE_INT},
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."),
46
 
                              0, ARG_TYPE_NONE},
47
 
  {"dumpid",          'I', 0, N_("Dump contents of ATA IDENTIFY sector."),
48
 
                               0, ARG_TYPE_NONE},
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},
51
 
  {0, 0, 0, 0, 0, 0}
52
 
};
53
 
 
54
 
enum grub_ata_smart_commands
55
 
  {
56
 
    GRUB_ATA_FEAT_SMART_ENABLE  = 0xd8,
57
 
    GRUB_ATA_FEAT_SMART_DISABLE = 0xd9,
58
 
    GRUB_ATA_FEAT_SMART_STATUS  = 0xda,
59
 
  };
60
 
 
61
 
static int quiet = 0;
62
 
 
63
 
static grub_err_t
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)
67
 
{
68
 
  struct grub_disk_ata_pass_through_parms apt;
69
 
  grub_memset (&apt, 0, sizeof (apt));
70
 
 
71
 
  apt.taskfile[GRUB_ATA_REG_CMD] = cmd;
72
 
  apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
73
 
  apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
74
 
  apt.buffer = buffer;
75
 
  apt.size = size;
76
 
 
77
 
  if (grub_disk_ata_pass_through (disk, &apt))
78
 
    return grub_errno;
79
 
 
80
 
  return GRUB_ERR_NONE;
81
 
}
82
 
 
83
 
static int
84
 
grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
85
 
{
86
 
  struct grub_disk_ata_pass_through_parms apt;
87
 
  grub_memset (&apt, 0, sizeof (apt));
88
 
 
89
 
  apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
90
 
 
91
 
  if (grub_disk_ata_pass_through (disk, &apt))
92
 
    return -1;
93
 
 
94
 
  return apt.taskfile[GRUB_ATA_REG_SECTORS];
95
 
}
96
 
 
97
 
static int
98
 
grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
99
 
{
100
 
  struct grub_disk_ata_pass_through_parms apt;
101
 
  grub_memset (&apt, 0, sizeof (apt));
102
 
 
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;
107
 
 
108
 
  if (grub_disk_ata_pass_through (disk, &apt))
109
 
    return -1;
110
 
 
111
 
  if (features == GRUB_ATA_FEAT_SMART_STATUS)
112
 
    {
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.  */
119
 
      else
120
 
        return -1;
121
 
    }
122
 
  return 0;
123
 
}
124
 
 
125
 
static grub_err_t
126
 
grub_hdparm_simple_cmd (const char * msg,
127
 
                        grub_disk_t disk, grub_uint8_t cmd)
128
 
{
129
 
  if (! quiet && msg)
130
 
    grub_printf ("%s", msg);
131
 
 
132
 
  grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0);
133
 
 
134
 
  if (! quiet && msg)
135
 
    grub_printf ("%s\n", ! err ? "" : ": not supported");
136
 
  return err;
137
 
}
138
 
 
139
 
static grub_err_t
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)
143
 
{
144
 
  if (! quiet && msg && *msg)
145
 
    {
146
 
      if (val >= 0)
147
 
        grub_printf ("Set %s to %d", msg, val);
148
 
      else
149
 
        grub_printf ("Disable %s", msg);
150
 
    }
151
 
 
152
 
  grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors,
153
 
                                           NULL, 0);
154
 
 
155
 
  if (! quiet && msg)
156
 
    grub_printf ("%s\n", ! err ? "" : ": not supported");
157
 
  return err;
158
 
}
159
 
 
160
 
static const char *
161
 
le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes)
162
 
{
163
 
  grub_uint16_t * dest16 = (grub_uint16_t *) dest;
164
 
  unsigned i;
165
 
  for (i = 0; i < bytes / 2; i++)
166
 
    dest16[i] = grub_be_to_cpu16 (src16[i]);
167
 
  return dest;
168
 
}
169
 
 
170
 
static void
171
 
grub_hdparm_print_identify (const char * idbuf)
172
 
{
173
 
  const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
174
 
 
175
 
  /* Print identity strings.  */
176
 
  char tmp[40];
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));
180
 
 
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]);
186
 
 
187
 
  grub_printf ("Automatic Acoustic Management: ");
188
 
  if (features2 & 0x0200)
189
 
    {
190
 
      if (enabled2 & 0x0200)
191
 
        {
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);
195
 
        }
196
 
      else
197
 
        grub_printf ("disabled\n");
198
 
    }
199
 
  else
200
 
    grub_printf ("not supported\n");
201
 
 
202
 
  grub_printf ("Advanced Power Management: ");
203
 
  if (features2 & 0x0008)
204
 
    {
205
 
      if (enabled2 & 0x0008)
206
 
        grub_printf ("%u (1=low, ..., 254=high)\n",
207
 
                     grub_le_to_cpu16 (idw[91]) & 0xff);
208
 
      else
209
 
        grub_printf ("disabled\n");
210
 
    }
211
 
  else
212
 
    grub_printf ("not supported\n");
213
 
 
214
 
  grub_printf ("SMART Feature Set: ");
215
 
  if (features1 & 0x0001)
216
 
    grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis"));
217
 
  else
218
 
    grub_printf ("not supported\n");
219
 
 
220
 
  /* Print security settings.  */
221
 
  grub_uint16_t security = grub_le_to_cpu16 (idw[128]);
222
 
 
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"));
230
 
  else
231
 
    grub_printf ("not supported\n");
232
 
}
233
 
 
234
 
static void
235
 
grub_hdparm_print_standby_tout (int timeout)
236
 
{
237
 
  if (timeout == 0)
238
 
    grub_printf ("off");
239
 
  else if (timeout <= 252 || timeout == 255)
240
 
    {
241
 
      int h = 0, m = 0 , s = 0;
242
 
      if (timeout == 255)
243
 
        {
244
 
          m = 21;
245
 
          s = 15;
246
 
        }
247
 
      else if (timeout == 252)
248
 
        m = 21;
249
 
      else if (timeout <= 240)
250
 
        {
251
 
          s = timeout * 5;
252
 
          m = s / 60;
253
 
          s %= 60;
254
 
        }
255
 
      else
256
 
        {
257
 
          m = (timeout - 240) * 30;
258
 
          h  = m / 60;
259
 
          m %= 60;
260
 
        }
261
 
      grub_printf ("%02d:%02d:%02d", h, m, s);
262
 
    }
263
 
  else
264
 
    grub_printf ("invalid or vendor-specific");
265
 
}
266
 
 
267
 
static int get_int_arg (const struct grub_arg_list *state)
268
 
{
269
 
  return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1);
270
 
}
271
 
 
272
 
static grub_err_t
273
 
grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state????
274
 
{
275
 
  struct grub_arg_list *state = cmd->state;
276
 
 
277
 
  /* Check command line.  */
278
 
  if (argc != 1)
279
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument");
280
 
 
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;
285
 
 
286
 
  if (! grub_disk_ata_pass_through)
287
 
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
288
 
 
289
 
  int i = 0;
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;
302
 
 
303
 
  /* Open disk.  */
304
 
  grub_disk_t disk = grub_disk_open (&args[0][1]);
305
 
  if (! disk)
306
 
    return grub_errno;
307
 
 
308
 
  if (disk->partition)
309
 
    {
310
 
      grub_disk_close (disk);
311
 
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed");
312
 
    }
313
 
 
314
 
  /* Change settings.  */
315
 
  if (aam >= 0)
316
 
    grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
317
 
      disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
318
 
 
319
 
  if (apm >= 0)
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));
323
 
 
324
 
  if (standby_tout >= 0)
325
 
    {
326
 
      if (! quiet)
327
 
        {
328
 
          grub_printf ("Set standby timeout to %d (", standby_tout);
329
 
          grub_hdparm_print_standby_tout (standby_tout);
330
 
          grub_printf (")");
331
 
        }
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);
334
 
    }
335
 
 
336
 
  if (enable_smart >= 0)
337
 
    {
338
 
      if (! quiet)
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));
342
 
      if (! quiet)
343
 
        grub_printf ("%s\n", err ? ": not supported" : "");
344
 
    }
345
 
 
346
 
  if (sec_freeze)
347
 
    grub_hdparm_simple_cmd ("Freeze security settings", disk,
348
 
                            GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
349
 
 
350
 
  /* Print/dump IDENTIFY.  */
351
 
  if (ident || dumpid)
352
 
    {
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");
357
 
      else
358
 
        {
359
 
          if (ident)
360
 
            grub_hdparm_print_identify (buf);
361
 
          if (dumpid)
362
 
            hexdump (0, buf, sizeof (buf));
363
 
        }
364
 
    }
365
 
 
366
 
  /* Check power mode.  */
367
 
  if (power)
368
 
    {
369
 
      grub_printf ("Disk power mode is: ");
370
 
      int mode = grub_hdparm_do_check_powermode_cmd (disk);
371
 
      if (mode < 0)
372
 
        grub_printf ("unknown\n");
373
 
      else
374
 
        grub_printf ("%s (0x%02x)\n",
375
 
                     (mode == 0xff ? "active/idle" :
376
 
                      mode == 0x80 ? "idle" :
377
 
                      mode == 0x00 ? "standby" : "unknown"), mode);
378
 
    }
379
 
 
380
 
  /* Check health.  */
381
 
  int status = 0;
382
 
  if (health)
383
 
    {
384
 
      if (! quiet)
385
 
        grub_printf ("SMART status is: ");
386
 
      int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS);
387
 
      if (! quiet)
388
 
        grub_printf ("%s\n", (err  < 0 ? "unknown" :
389
 
                              err == 0 ? "OK" : "*BAD*"));
390
 
      status = (err > 0);
391
 
    }
392
 
 
393
 
  /* Change power mode.  */
394
 
  if (standby_now)
395
 
    grub_hdparm_simple_cmd ("Set disk to standby mode", disk,
396
 
                            GRUB_ATA_CMD_STANDBY_IMMEDIATE);
397
 
 
398
 
  if (sleep_now)
399
 
    grub_hdparm_simple_cmd ("Set disk to sleep mode", disk,
400
 
                            GRUB_ATA_CMD_SLEEP);
401
 
 
402
 
  grub_disk_close (disk);
403
 
 
404
 
  grub_errno = GRUB_ERR_NONE;
405
 
  return status;
406
 
}
407
 
 
408
 
static grub_extcmd_t cmd;
409
 
 
410
 
GRUB_MOD_INIT(hdparm)
411
 
{
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);
416
 
}
417
 
 
418
 
GRUB_MOD_FINI(hdparm)
419
 
{
420
 
  grub_unregister_extcmd (cmd);
421
 
}