more of -Wall fixes from Cristian Ionescu-Idbohrn.
[oweals/busybox.git] / miscutils / hdparm.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * hdparm implementation for busybox
4  *
5  * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
6  * Hacked by Tito <farmatito@tiscali.it> for size optimization.
7  *
8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9  *
10  * This program is based on the source code of hdparm: see below...
11  * hdparm.c - Command line interface to get/set hard disk parameters
12  *          - by Mark Lord (C) 1994-2002 -- freely distributable
13  */
14
15 #include "libbb.h"
16 #include <linux/hdreg.h>
17
18 /* device types */
19 /* ------------ */
20 #define NO_DEV                  0xffff
21 #define ATA_DEV                 0x0000
22 #define ATAPI_DEV               0x0001
23
24 /* word definitions */
25 /* ---------------- */
26 #define GEN_CONFIG              0   /* general configuration */
27 #define LCYLS                   1   /* number of logical cylinders */
28 #define CONFIG                  2   /* specific configuration */
29 #define LHEADS                  3   /* number of logical heads */
30 #define TRACK_BYTES             4   /* number of bytes/track (ATA-1) */
31 #define SECT_BYTES              5   /* number of bytes/sector (ATA-1) */
32 #define LSECTS                  6   /* number of logical sectors/track */
33 #define START_SERIAL            10  /* ASCII serial number */
34 #define LENGTH_SERIAL           10  /* 10 words (20 bytes or characters) */
35 #define BUF_TYPE                20  /* buffer type (ATA-1) */
36 #define BUFFER__SIZE            21  /* buffer size (ATA-1) */
37 #define RW_LONG                 22  /* extra bytes in R/W LONG cmd ( < ATA-4)*/
38 #define START_FW_REV            23  /* ASCII firmware revision */
39 #define LENGTH_FW_REV            4  /*  4 words (8 bytes or characters) */
40 #define START_MODEL             27  /* ASCII model number */
41 #define LENGTH_MODEL            20  /* 20 words (40 bytes or characters) */
42 #define SECTOR_XFER_MAX         47  /* r/w multiple: max sectors xfered */
43 #define DWORD_IO                48  /* can do double-word IO (ATA-1 only) */
44 #define CAPAB_0                 49  /* capabilities */
45 #define CAPAB_1                 50
46 #define PIO_MODE                51  /* max PIO mode supported (obsolete)*/
47 #define DMA_MODE                52  /* max Singleword DMA mode supported (obs)*/
48 #define WHATS_VALID             53  /* what fields are valid */
49 #define LCYLS_CUR               54  /* current logical cylinders */
50 #define LHEADS_CUR              55  /* current logical heads */
51 #define LSECTS_CUR              56  /* current logical sectors/track */
52 #define CAPACITY_LSB            57  /* current capacity in sectors */
53 #define CAPACITY_MSB            58
54 #define SECTOR_XFER_CUR         59  /* r/w multiple: current sectors xfered */
55 #define LBA_SECTS_LSB           60  /* LBA: total number of user */
56 #define LBA_SECTS_MSB           61  /*      addressable sectors */
57 #define SINGLE_DMA              62  /* singleword DMA modes */
58 #define MULTI_DMA               63  /* multiword DMA modes */
59 #define ADV_PIO_MODES           64  /* advanced PIO modes supported */
60                                     /* multiword DMA xfer cycle time: */
61 #define DMA_TIME_MIN            65  /*   - minimum */
62 #define DMA_TIME_NORM           66  /*   - manufacturer's recommended   */
63                                     /* minimum PIO xfer cycle time: */
64 #define PIO_NO_FLOW             67  /*   - without flow control */
65 #define PIO_FLOW                68  /*   - with IORDY flow control */
66 #define PKT_REL                 71  /* typical #ns from PKT cmd to bus rel */
67 #define SVC_NBSY                72  /* typical #ns from SERVICE cmd to !BSY */
68 #define CDR_MAJOR               73  /* CD ROM: major version number */
69 #define CDR_MINOR               74  /* CD ROM: minor version number */
70 #define QUEUE_DEPTH             75  /* queue depth */
71 #define MAJOR                   80  /* major version number */
72 #define MINOR                   81  /* minor version number */
73 #define CMDS_SUPP_0             82  /* command/feature set(s) supported */
74 #define CMDS_SUPP_1             83
75 #define CMDS_SUPP_2             84
76 #define CMDS_EN_0               85  /* command/feature set(s) enabled */
77 #define CMDS_EN_1               86
78 #define CMDS_EN_2               87
79 #define ULTRA_DMA               88  /* ultra DMA modes */
80                                     /* time to complete security erase */
81 #define ERASE_TIME              89  /*   - ordinary */
82 #define ENH_ERASE_TIME          90  /*   - enhanced */
83 #define ADV_PWR                 91  /* current advanced power management level
84                                        in low byte, 0x40 in high byte. */
85 #define PSWD_CODE               92  /* master password revision code    */
86 #define HWRST_RSLT              93  /* hardware reset result */
87 #define ACOUSTIC                94  /* acoustic mgmt values ( >= ATA-6) */
88 #define LBA_LSB                 100 /* LBA: maximum.  Currently only 48 */
89 #define LBA_MID                 101 /*      bits are used, but addr 103 */
90 #define LBA_48_MSB              102 /*      has been reserved for LBA in */
91 #define LBA_64_MSB              103 /*      the future. */
92 #define RM_STAT                 127 /* removable media status notification feature set support */
93 #define SECU_STATUS             128 /* security status */
94 #define CFA_PWR_MODE            160 /* CFA power mode 1 */
95 #define START_MEDIA             176 /* media serial number */
96 #define LENGTH_MEDIA            20  /* 20 words (40 bytes or characters)*/
97 #define START_MANUF             196 /* media manufacturer I.D. */
98 #define LENGTH_MANUF            10  /* 10 words (20 bytes or characters) */
99 #define INTEGRITY               255 /* integrity word */
100
101 /* bit definitions within the words */
102 /* -------------------------------- */
103
104 /* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
105 #define VALID                   0xc000
106 #define VALID_VAL               0x4000
107 /* many words are considered invalid if they are either all-0 or all-1 */
108 #define NOVAL_0                 0x0000
109 #define NOVAL_1                 0xffff
110
111 /* word 0: gen_config */
112 #define NOT_ATA                 0x8000
113 #define NOT_ATAPI               0x4000  /* (check only if bit 15 == 1) */
114 #define MEDIA_REMOVABLE         0x0080
115 #define DRIVE_NOT_REMOVABLE     0x0040  /* bit obsoleted in ATA 6 */
116 #define INCOMPLETE              0x0004
117 #define CFA_SUPPORT_VAL         0x848a  /* 848a=CFA feature set support */
118 #define DRQ_RESPONSE_TIME       0x0060
119 #define DRQ_3MS_VAL             0x0000
120 #define DRQ_INTR_VAL            0x0020
121 #define DRQ_50US_VAL            0x0040
122 #define PKT_SIZE_SUPPORTED      0x0003
123 #define PKT_SIZE_12_VAL         0x0000
124 #define PKT_SIZE_16_VAL         0x0001
125 #define EQPT_TYPE               0x1f00
126 #define SHIFT_EQPT              8
127
128 #define CDROM 0x0005
129
130 /* word 1: number of logical cylinders */
131 #define LCYLS_MAX               0x3fff /* maximum allowable value */
132
133 /* word 2: specific configuration
134  * (a) require SET FEATURES to spin-up
135  * (b) require spin-up to fully reply to IDENTIFY DEVICE
136  */
137 #define STBY_NID_VAL            0x37c8  /*     (a) and     (b) */
138 #define STBY_ID_VAL             0x738c  /*     (a) and not (b) */
139 #define PWRD_NID_VAL            0x8c73  /* not (a) and     (b) */
140 #define PWRD_ID_VAL             0xc837  /* not (a) and not (b) */
141
142 /* words 47 & 59: sector_xfer_max & sector_xfer_cur */
143 #define SECTOR_XFER             0x00ff  /* sectors xfered on r/w multiple cmds*/
144 #define MULTIPLE_SETTING_VALID  0x0100  /* 1=multiple sector setting is valid */
145
146 /* word 49: capabilities 0 */
147 #define STD_STBY                0x2000  /* 1=standard values supported (ATA); 0=vendor specific values */
148 #define IORDY_SUP               0x0800  /* 1=support; 0=may be supported */
149 #define IORDY_OFF               0x0400  /* 1=may be disabled */
150 #define LBA_SUP                 0x0200  /* 1=Logical Block Address support */
151 #define DMA_SUP                 0x0100  /* 1=Direct Memory Access support */
152 #define DMA_IL_SUP              0x8000  /* 1=interleaved DMA support (ATAPI) */
153 #define CMD_Q_SUP               0x4000  /* 1=command queuing support (ATAPI) */
154 #define OVLP_SUP                0x2000  /* 1=overlap operation support (ATAPI) */
155 #define SWRST_REQ               0x1000  /* 1=ATA SW reset required (ATAPI, obsolete */
156
157 /* word 50: capabilities 1 */
158 #define MIN_STANDBY_TIMER       0x0001  /* 1=device specific standby timer value minimum */
159
160 /* words 51 & 52: PIO & DMA cycle times */
161 #define MODE                    0xff00  /* the mode is in the MSBs */
162
163 /* word 53: whats_valid */
164 #define OK_W88                  0x0004  /* the ultra_dma info is valid */
165 #define OK_W64_70               0x0002  /* see above for word descriptions */
166 #define OK_W54_58               0x0001  /* current cyl, head, sector, cap. info valid */
167
168 /*word 63,88: dma_mode, ultra_dma_mode*/
169 #define MODE_MAX                7       /* bit definitions force udma <=7 (when
170                                          * udma >=8 comes out it'll have to be
171                                          * defined in a new dma_mode word!) */
172
173 /* word 64: PIO transfer modes */
174 #define PIO_SUP                 0x00ff  /* only bits 0 & 1 are used so far,  */
175 #define PIO_MODE_MAX            8       /* but all 8 bits are defined        */
176
177 /* word 75: queue_depth */
178 #define DEPTH_BITS              0x001f  /* bits used for queue depth */
179
180 /* words 80-81: version numbers */
181 /* NOVAL_0 or  NOVAL_1 means device does not report version */
182
183 /* word 81: minor version number */
184 #define MINOR_MAX               0x22
185 /* words 82-84: cmds/feats supported */
186 #define CMDS_W82                0x77ff  /* word 82: defined command locations*/
187 #define CMDS_W83                0x3fff  /* word 83: defined command locations*/
188 #define CMDS_W84                0x002f  /* word 83: defined command locations*/
189 #define SUPPORT_48_BIT          0x0400
190 #define NUM_CMD_FEAT_STR        48
191
192 /* words 85-87: cmds/feats enabled */
193 /* use cmd_feat_str[] to display what commands and features have
194  * been enabled with words 85-87
195  */
196
197 /* words 89, 90, SECU ERASE TIME */
198 #define ERASE_BITS      0x00ff
199
200 /* word 92: master password revision */
201 /* NOVAL_0 or  NOVAL_1 means no support for master password revision */
202
203 /* word 93: hw reset result */
204 #define CBLID           0x2000  /* CBLID status */
205 #define RST0            0x0001  /* 1=reset to device #0 */
206 #define DEV_DET         0x0006  /* how device num determined */
207 #define JUMPER_VAL      0x0002  /* device num determined by jumper */
208 #define CSEL_VAL        0x0004  /* device num determined by CSEL_VAL */
209
210 /* word 127: removable media status notification feature set support */
211 #define RM_STAT_BITS    0x0003
212 #define RM_STAT_SUP     0x0001
213
214 /* word 128: security */
215 #define SECU_ENABLED    0x0002
216 #define SECU_LEVEL      0x0010
217 #define NUM_SECU_STR    6
218
219 /* word 160: CFA power mode */
220 #define VALID_W160              0x8000  /* 1=word valid */
221 #define PWR_MODE_REQ            0x2000  /* 1=CFA power mode req'd by some cmds*/
222 #define PWR_MODE_OFF            0x1000  /* 1=CFA power moded disabled */
223 #define MAX_AMPS                0x0fff  /* value = max current in ma */
224
225 /* word 255: integrity */
226 #define SIG                     0x00ff  /* signature location */
227 #define SIG_VAL                 0x00a5  /* signature value */
228
229 #define TIMING_BUF_MB           1
230 #define TIMING_BUF_BYTES        (TIMING_BUF_MB * 1024 * 1024)
231
232 #undef DO_FLUSHCACHE            /* under construction: force cache flush on -W0 */
233
234
235 enum { fd = 3 };
236
237
238 struct globals {
239         smallint get_identity, get_geom;
240         smallint do_flush;
241         smallint do_ctimings, do_timings;
242         smallint reread_partn;
243         smallint set_piomode, noisy_piomode;
244         smallint set_readahead, get_readahead;
245         smallint set_readonly, get_readonly;
246         smallint set_unmask, get_unmask;
247         smallint set_mult, get_mult;
248 #ifdef HDIO_GET_QDMA
249         smallint get_dma_q;
250 #ifdef HDIO_SET_QDMA
251         smallint set_dma_q;
252 #endif
253 #endif
254         smallint set_nowerr, get_nowerr;
255         smallint set_keep, get_keep;
256         smallint set_io32bit, get_io32bit;
257         int piomode;
258         unsigned long Xreadahead;
259         unsigned long readonly;
260         unsigned long unmask;
261         unsigned long mult;
262 #ifdef HDIO_SET_QDMA
263         unsigned long dma_q;
264 #endif
265         unsigned long nowerr;
266         unsigned long keep;
267         unsigned long io32bit;
268 #if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
269         unsigned long dma;
270         smallint set_dma, get_dma;
271 #endif
272 #ifdef HDIO_DRIVE_CMD
273         smallint set_xfermode, get_xfermode;
274         smallint set_dkeep, get_dkeep;
275         smallint set_standby, get_standby;
276         smallint set_lookahead, get_lookahead;
277         smallint set_prefetch, get_prefetch;
278         smallint set_defects, get_defects;
279         smallint set_wcache, get_wcache;
280         smallint set_doorlock, get_doorlock;
281         smallint set_seagate, get_seagate;
282         smallint set_standbynow, get_standbynow;
283         smallint set_sleepnow, get_sleepnow;
284         smallint get_powermode;
285         smallint set_apmmode, get_apmmode;
286         int xfermode_requested;
287         unsigned long dkeep;
288         unsigned long standby_requested; /* 0..255 */
289         unsigned long lookahead;
290         unsigned long prefetch;
291         unsigned long defects;
292         unsigned long wcache;
293         unsigned long doorlock;
294         unsigned long apmmode;
295 #endif
296         USE_FEATURE_HDPARM_GET_IDENTITY(        smallint get_IDentity;)
297         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint set_busstate, get_busstate;)
298         USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(    smallint perform_reset;)
299         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint perform_tristate;)
300         USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
301         USE_FEATURE_HDPARM_HDIO_SCAN_HWIF(      smallint scan_hwif;)
302         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long busstate;)
303         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long tristate;)
304         USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
305 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
306         unsigned long hwif_data;
307         unsigned long hwif_ctrl;
308         unsigned long hwif_irq;
309 #endif
310 #ifdef DO_FLUSHCACHE
311         unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
312 #endif
313 };
314 #define G (*(struct globals*)&bb_common_bufsiz1)
315 struct BUG_G_too_big {
316         char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
317 };
318 #define get_identity       (G.get_identity           )
319 #define get_geom           (G.get_geom               )
320 #define do_flush           (G.do_flush               )
321 #define do_ctimings        (G.do_ctimings            )
322 #define do_timings         (G.do_timings             )
323 #define reread_partn       (G.reread_partn           )
324 #define set_piomode        (G.set_piomode            )
325 #define noisy_piomode      (G.noisy_piomode          )
326 #define set_readahead      (G.set_readahead          )
327 #define get_readahead      (G.get_readahead          )
328 #define set_readonly       (G.set_readonly           )
329 #define get_readonly       (G.get_readonly           )
330 #define set_unmask         (G.set_unmask             )
331 #define get_unmask         (G.get_unmask             )
332 #define set_mult           (G.set_mult               )
333 #define get_mult           (G.get_mult               )
334 #define set_dma_q          (G.set_dma_q              )
335 #define get_dma_q          (G.get_dma_q              )
336 #define set_nowerr         (G.set_nowerr             )
337 #define get_nowerr         (G.get_nowerr             )
338 #define set_keep           (G.set_keep               )
339 #define get_keep           (G.get_keep               )
340 #define set_io32bit        (G.set_io32bit            )
341 #define get_io32bit        (G.get_io32bit            )
342 #define piomode            (G.piomode                )
343 #define Xreadahead         (G.Xreadahead             )
344 #define readonly           (G.readonly               )
345 #define unmask             (G.unmask                 )
346 #define mult               (G.mult                   )
347 #define dma_q              (G.dma_q                  )
348 #define nowerr             (G.nowerr                 )
349 #define keep               (G.keep                   )
350 #define io32bit            (G.io32bit                )
351 #define dma                (G.dma                    )
352 #define set_dma            (G.set_dma                )
353 #define get_dma            (G.get_dma                )
354 #define set_xfermode       (G.set_xfermode           )
355 #define get_xfermode       (G.get_xfermode           )
356 #define set_dkeep          (G.set_dkeep              )
357 #define get_dkeep          (G.get_dkeep              )
358 #define set_standby        (G.set_standby            )
359 #define get_standby        (G.get_standby            )
360 #define set_lookahead      (G.set_lookahead          )
361 #define get_lookahead      (G.get_lookahead          )
362 #define set_prefetch       (G.set_prefetch           )
363 #define get_prefetch       (G.get_prefetch           )
364 #define set_defects        (G.set_defects            )
365 #define get_defects        (G.get_defects            )
366 #define set_wcache         (G.set_wcache             )
367 #define get_wcache         (G.get_wcache             )
368 #define set_doorlock       (G.set_doorlock           )
369 #define get_doorlock       (G.get_doorlock           )
370 #define set_seagate        (G.set_seagate            )
371 #define get_seagate        (G.get_seagate            )
372 #define set_standbynow     (G.set_standbynow         )
373 #define get_standbynow     (G.get_standbynow         )
374 #define set_sleepnow       (G.set_sleepnow           )
375 #define get_sleepnow       (G.get_sleepnow           )
376 #define get_powermode      (G.get_powermode          )
377 #define set_apmmode        (G.set_apmmode            )
378 #define get_apmmode        (G.get_apmmode            )
379 #define xfermode_requested (G.xfermode_requested     )
380 #define dkeep              (G.dkeep                  )
381 #define standby_requested  (G.standby_requested      )
382 #define lookahead          (G.lookahead              )
383 #define prefetch           (G.prefetch               )
384 #define defects            (G.defects                )
385 #define wcache             (G.wcache                 )
386 #define doorlock           (G.doorlock               )
387 #define apmmode            (G.apmmode                )
388 #define get_IDentity       (G.get_IDentity           )
389 #define set_busstate       (G.set_busstate           )
390 #define get_busstate       (G.get_busstate           )
391 #define perform_reset      (G.perform_reset          )
392 #define perform_tristate   (G.perform_tristate       )
393 #define unregister_hwif    (G.unregister_hwif        )
394 #define scan_hwif          (G.scan_hwif              )
395 #define busstate           (G.busstate               )
396 #define tristate           (G.tristate               )
397 #define hwif               (G.hwif                   )
398 #define hwif_data          (G.hwif_data              )
399 #define hwif_ctrl          (G.hwif_ctrl              )
400 #define hwif_irq           (G.hwif_irq               )
401
402
403 /* Busybox messages and functions */
404 #if ENABLE_IOCTL_HEX2STR_ERROR
405 static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
406 {
407         if (!ioctl(fd, cmd, args))
408                 return 0;
409         args[0] = alt;
410         return bb_ioctl_or_warn(fd, cmd, args, string);
411 }
412 #define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
413 #else
414 static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
415 {
416         if (!ioctl(fd, cmd, args))
417                 return 0;
418         args[0] = alt;
419         return bb_ioctl_or_warn(fd, cmd, args);
420 }
421 #define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
422 #endif
423
424 static void on_off(int value)
425 {
426         puts(value ? " (on)" : " (off)");
427 }
428
429 static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
430 {
431         if (get_arg) {
432                 printf(" setting %s to %ld", s, arg);
433                 on_off(arg);
434         }
435 }
436
437 static void print_value_on_off(const char *str, unsigned long argp)
438 {
439         printf(" %s\t= %2ld", str, argp);
440         on_off(argp != 0);
441 }
442
443 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
444 static void print_ascii(const char *p, int length)
445 {
446 #if BB_BIG_ENDIAN
447 #define LE_ONLY(x)
448         enum { ofs = 0 };
449 #else
450 #define LE_ONLY(x) x
451         /* every 16bit word is big-endian (i.e. inverted) */
452         /* accessing bytes in 1,0, 3,2, 5,4... sequence */
453         int ofs = 1;
454 #endif
455
456         length *= 2;
457         /* find first non-space & print it */
458         while (length && p[ofs] != ' ') {
459                 p++;
460                 LE_ONLY(ofs = -ofs;)
461                 length--;
462         }
463         while (length && p[ofs]) {
464                 bb_putchar(p[ofs]);
465                 p++;
466                 LE_ONLY(ofs = -ofs;)
467                 length--;
468         }
469         bb_putchar('\n');
470 #undef LE_ONLY
471 }
472
473 static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
474 {
475         if (val[i]) {
476                 printf("\t%-20s", string);
477                 print_ascii((void*)&val[i], n);
478         }
479 }
480
481 static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
482 {
483         uint16_t ii;
484         uint8_t err_dma = 0;
485
486         for (ii = 0; ii <= MODE_MAX; ii++) {
487                 if (mode_sel & 0x0001) {
488                         printf("*%cdma%u ", cc, ii);
489                         if (*have_mode)
490                                 err_dma = 1;
491                         *have_mode = 1;
492                 } else if (mode_sup & 0x0001)
493                         printf("%cdma%u ", cc, ii);
494
495                 mode_sup >>= 1;
496                 mode_sel >>= 1;
497         }
498         return err_dma;
499 }
500
501 static const char pkt_str[] ALIGN1 =
502         "Direct-access device" "\0"             /* word 0, bits 12-8 = 00 */
503         "Sequential-access device" "\0"         /* word 0, bits 12-8 = 01 */
504         "Printer" "\0"                          /* word 0, bits 12-8 = 02 */
505         "Processor" "\0"                        /* word 0, bits 12-8 = 03 */
506         "Write-once device" "\0"                /* word 0, bits 12-8 = 04 */
507         "CD-ROM" "\0"                           /* word 0, bits 12-8 = 05 */
508         "Scanner" "\0"                          /* word 0, bits 12-8 = 06 */
509         "Optical memory" "\0"                   /* word 0, bits 12-8 = 07 */
510         "Medium changer" "\0"                   /* word 0, bits 12-8 = 08 */
511         "Communications device" "\0"            /* word 0, bits 12-8 = 09 */
512         "ACS-IT8 device" "\0"                   /* word 0, bits 12-8 = 0a */
513         "ACS-IT8 device" "\0"                   /* word 0, bits 12-8 = 0b */
514         "Array controller" "\0"                 /* word 0, bits 12-8 = 0c */
515         "Enclosure services" "\0"               /* word 0, bits 12-8 = 0d */
516         "Reduced block command device" "\0"     /* word 0, bits 12-8 = 0e */
517         "Optical card reader/writer" "\0"       /* word 0, bits 12-8 = 0f */
518 ;
519
520 static const char ata1_cfg_str[] ALIGN1 =       /* word 0 in ATA-1 mode */
521         "reserved" "\0"                         /* bit 0 */
522         "hard sectored" "\0"                    /* bit 1 */
523         "soft sectored" "\0"                    /* bit 2 */
524         "not MFM encoded " "\0"                 /* bit 3 */
525         "head switch time > 15us" "\0"          /* bit 4 */
526         "spindle motor control option" "\0"     /* bit 5 */
527         "fixed drive" "\0"                      /* bit 6 */
528         "removable drive" "\0"                  /* bit 7 */
529         "disk xfer rate <= 5Mbs" "\0"           /* bit 8 */
530         "disk xfer rate > 5Mbs, <= 10Mbs" "\0"  /* bit 9 */
531         "disk xfer rate > 5Mbs" "\0"            /* bit 10 */
532         "rotational speed tol." "\0"            /* bit 11 */
533         "data strobe offset option" "\0"        /* bit 12 */
534         "track offset option" "\0"              /* bit 13 */
535         "format speed tolerance gap reqd" "\0"  /* bit 14 */
536         "ATAPI"                                 /* bit 14 */
537 ;
538
539 static const char minor_str[] ALIGN1 =
540         /* word 81 value: */
541         "Unspecified" "\0"                                  /* 0x0000 */
542         "ATA-1 X3T9.2 781D prior to rev.4" "\0"             /* 0x0001 */
543         "ATA-1 published, ANSI X3.221-1994" "\0"            /* 0x0002 */
544         "ATA-1 X3T9.2 781D rev.4" "\0"                      /* 0x0003 */
545         "ATA-2 published, ANSI X3.279-1996" "\0"            /* 0x0004 */
546         "ATA-2 X3T10 948D prior to rev.2k" "\0"             /* 0x0005 */
547         "ATA-3 X3T10 2008D rev.1" "\0"                      /* 0x0006 */
548         "ATA-2 X3T10 948D rev.2k" "\0"                      /* 0x0007 */
549         "ATA-3 X3T10 2008D rev.0" "\0"                      /* 0x0008 */
550         "ATA-2 X3T10 948D rev.3" "\0"                       /* 0x0009 */
551         "ATA-3 published, ANSI X3.298-199x" "\0"            /* 0x000a */
552         "ATA-3 X3T10 2008D rev.6" "\0"                      /* 0x000b */
553         "ATA-3 X3T13 2008D rev.7 and 7a" "\0"               /* 0x000c */
554         "ATA/ATAPI-4 X3T13 1153D rev.6" "\0"                /* 0x000d */
555         "ATA/ATAPI-4 T13 1153D rev.13" "\0"                 /* 0x000e */
556         "ATA/ATAPI-4 X3T13 1153D rev.7" "\0"                /* 0x000f */
557         "ATA/ATAPI-4 T13 1153D rev.18" "\0"                 /* 0x0010 */
558         "ATA/ATAPI-4 T13 1153D rev.15" "\0"                 /* 0x0011 */
559         "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0"  /* 0x0012 */
560         "ATA/ATAPI-5 T13 1321D rev.3" "\0"                  /* 0x0013 */
561         "ATA/ATAPI-4 T13 1153D rev.14" "\0"                 /* 0x0014 */
562         "ATA/ATAPI-5 T13 1321D rev.1" "\0"                  /* 0x0015 */
563         "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0"  /* 0x0016 */
564         "ATA/ATAPI-4 T13 1153D rev.17" "\0"                 /* 0x0017 */
565         "ATA/ATAPI-6 T13 1410D rev.0" "\0"                  /* 0x0018 */
566         "ATA/ATAPI-6 T13 1410D rev.3a" "\0"                 /* 0x0019 */
567         "ATA/ATAPI-7 T13 1532D rev.1" "\0"                  /* 0x001a */
568         "ATA/ATAPI-6 T13 1410D rev.2" "\0"                  /* 0x001b */
569         "ATA/ATAPI-6 T13 1410D rev.1" "\0"                  /* 0x001c */
570         "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0"  /* 0x001d */
571         "ATA/ATAPI-7 T13 1532D rev.0" "\0"                  /* 0x001e */
572         "reserved" "\0"                                     /* 0x001f */
573         "reserved" "\0"                                     /* 0x0020 */
574         "ATA/ATAPI-7 T13 1532D rev.4a" "\0"                 /* 0x0021 */
575         "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0"  /* 0x0022 */
576         "reserved"                                          /* 0x0023-0xfffe */
577 ;
578 static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
579            /* word 81 value: */
580         0, /* 0x0000 WARNING: actual_ver[] array */
581         1, /* 0x0001 WARNING: corresponds        */
582         1, /* 0x0002 WARNING: *exactly*          */
583         1, /* 0x0003 WARNING: to the ATA/        */
584         2, /* 0x0004 WARNING: ATAPI version      */
585         2, /* 0x0005 WARNING: listed in          */
586         3, /* 0x0006 WARNING: the                */
587         2, /* 0x0007 WARNING: minor_str          */
588         3, /* 0x0008 WARNING: array              */
589         2, /* 0x0009 WARNING: above.             */
590         3, /* 0x000a WARNING:                    */
591         3, /* 0x000b WARNING: If you change      */
592         3, /* 0x000c WARNING: that one,          */
593         4, /* 0x000d WARNING: change this one    */
594         4, /* 0x000e WARNING: too!!!             */
595         4, /* 0x000f */
596         4, /* 0x0010 */
597         4, /* 0x0011 */
598         4, /* 0x0012 */
599         5, /* 0x0013 */
600         4, /* 0x0014 */
601         5, /* 0x0015 */
602         5, /* 0x0016 */
603         4, /* 0x0017 */
604         6, /* 0x0018 */
605         6, /* 0x0019 */
606         7, /* 0x001a */
607         6, /* 0x001b */
608         6, /* 0x001c */
609         7, /* 0x001d */
610         7, /* 0x001e */
611         0, /* 0x001f */
612         0, /* 0x0020 */
613         7, /* 0x0021 */
614         6, /* 0x0022 */
615         0  /* 0x0023-0xfffe */
616 };
617
618 static const char cmd_feat_str[] ALIGN1 =
619         "" "\0"                                     /* word 82 bit 15: obsolete  */
620         "NOP cmd" "\0"                              /* word 82 bit 14 */
621         "READ BUFFER cmd" "\0"                      /* word 82 bit 13 */
622         "WRITE BUFFER cmd" "\0"                     /* word 82 bit 12 */
623         "" "\0"                                     /* word 82 bit 11: obsolete  */
624         "Host Protected Area feature set" "\0"      /* word 82 bit 10 */
625         "DEVICE RESET cmd" "\0"                     /* word 82 bit  9 */
626         "SERVICE interrupt" "\0"                    /* word 82 bit  8 */
627         "Release interrupt" "\0"                    /* word 82 bit  7 */
628         "Look-ahead" "\0"                           /* word 82 bit  6 */
629         "Write cache" "\0"                          /* word 82 bit  5 */
630         "PACKET command feature set" "\0"           /* word 82 bit  4 */
631         "Power Management feature set" "\0"         /* word 82 bit  3 */
632         "Removable Media feature set" "\0"          /* word 82 bit  2 */
633         "Security Mode feature set" "\0"            /* word 82 bit  1 */
634         "SMART feature set" "\0"                    /* word 82 bit  0 */
635                                                     /* -------------- */
636         "" "\0"                                     /* word 83 bit 15: !valid bit */
637         "" "\0"                                     /* word 83 bit 14:  valid bit */
638         "FLUSH CACHE EXT cmd" "\0"                  /* word 83 bit 13 */
639         "Mandatory FLUSH CACHE cmd " "\0"           /* word 83 bit 12 */
640         "Device Configuration Overlay feature set " "\0"
641         "48-bit Address feature set " "\0"          /* word 83 bit 10 */
642         "" "\0"
643         "SET MAX security extension" "\0"           /* word 83 bit  8 */
644         "Address Offset Reserved Area Boot" "\0"    /* word 83 bit  7 */
645         "SET FEATURES subcommand required to spinup after power up" "\0"
646         "Power-Up In Standby feature set" "\0"      /* word 83 bit  5 */
647         "Removable Media Status Notification feature set" "\0"
648         "Adv. Power Management feature set" "\0"    /* word 83 bit  3 */
649         "CFA feature set" "\0"                      /* word 83 bit  2 */
650         "READ/WRITE DMA QUEUED" "\0"                /* word 83 bit  1 */
651         "DOWNLOAD MICROCODE cmd" "\0"               /* word 83 bit  0 */
652                                                     /* -------------- */
653         "" "\0"                                     /* word 84 bit 15: !valid bit */
654         "" "\0"                                     /* word 84 bit 14:  valid bit */
655         "" "\0"                                     /* word 84 bit 13:  reserved */
656         "" "\0"                                     /* word 84 bit 12:  reserved */
657         "" "\0"                                     /* word 84 bit 11:  reserved */
658         "" "\0"                                     /* word 84 bit 10:  reserved */
659         "" "\0"                                     /* word 84 bit  9:  reserved */
660         "" "\0"                                     /* word 84 bit  8:  reserved */
661         "" "\0"                                     /* word 84 bit  7:  reserved */
662         "" "\0"                                     /* word 84 bit  6:  reserved */
663         "General Purpose Logging feature set" "\0"  /* word 84 bit  5 */
664         "" "\0"                                     /* word 84 bit  4:  reserved */
665         "Media Card Pass Through Command feature set " "\0"
666         "Media serial number " "\0"                 /* word 84 bit  2 */
667         "SMART self-test " "\0"                     /* word 84 bit  1 */
668         "SMART error logging "                      /* word 84 bit  0 */
669 ;
670
671 static const char secu_str[] ALIGN1 =
672         "supported" "\0"                /* word 128, bit 0 */
673         "enabled" "\0"                  /* word 128, bit 1 */
674         "locked" "\0"                   /* word 128, bit 2 */
675         "frozen" "\0"                   /* word 128, bit 3 */
676         "expired: security count" "\0"  /* word 128, bit 4 */
677         "supported: enhanced erase"     /* word 128, bit 5 */
678 ;
679
680 // Parse 512 byte disk identification block and print much crap.
681 static void identify(uint16_t *val) ATTRIBUTE_NORETURN;
682 static void identify(uint16_t *val)
683 {
684         uint16_t ii, jj, kk;
685         uint16_t like_std = 1, std = 0, min_std = 0xffff;
686         uint16_t dev = NO_DEV, eqpt = NO_DEV;
687         uint8_t  have_mode = 0, err_dma = 0;
688         uint8_t  chksum = 0;
689         uint32_t ll, mm, nn, oo;
690         uint64_t bbbig; /* (:) */
691         const char *strng;
692 #if BB_BIG_ENDIAN
693         uint16_t buf[256];
694
695         // Adjust for endianness
696         swab(val, buf, sizeof(buf));
697         val = buf;
698 #endif
699         /* check if we recognise the device type */
700         bb_putchar('\n');
701         if (!(val[GEN_CONFIG] & NOT_ATA)) {
702                 dev = ATA_DEV;
703                 printf("ATA device, with ");
704         } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
705                 dev = ATA_DEV;
706                 like_std = 4;
707                 printf("CompactFlash ATA device, with ");
708         } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
709                 dev = ATAPI_DEV;
710                 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
711                 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
712                 like_std = 3;
713         } else
714                 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
715                 bb_error_msg_and_die("unknown device type");
716
717         printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
718         /* Info from the specific configuration word says whether or not the
719          * ID command completed correctly.  It is only defined, however in
720          * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
721          * standards.  Since the values allowed for this word are extremely
722          * specific, it should be safe to check it now, even though we don't
723          * know yet what standard this device is using.
724          */
725         if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
726          || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
727         ) {
728                 like_std = 5;
729                 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
730                         printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
731                 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
732                         printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
733         }
734
735         /* output the model and serial numbers and the fw revision */
736         xprint_ascii(val, START_MODEL,  "Model Number:",        LENGTH_MODEL);
737         xprint_ascii(val, START_SERIAL, "Serial Number:",       LENGTH_SERIAL);
738         xprint_ascii(val, START_FW_REV, "Firmware Revision:",   LENGTH_FW_REV);
739         xprint_ascii(val, START_MEDIA,  "Media Serial Num:",    LENGTH_MEDIA);
740         xprint_ascii(val, START_MANUF,  "Media Manufacturer:",  LENGTH_MANUF);
741
742         /* major & minor standards version number (Note: these words were not
743          * defined until ATA-3 & the CDROM std uses different words.) */
744         printf("Standards:");
745         if (eqpt != CDROM) {
746                 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
747                         if (like_std < 3) like_std = 3;
748                         std = actual_ver[val[MINOR]];
749                         if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
750
751                 }
752                 /* looks like when they up-issue the std, they obsolete one;
753                  * thus, only the newest 4 issues need be supported. (That's
754                  * what "kk" and "min_std" are all about.) */
755                 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
756                         printf("\n\tSupported: ");
757                         jj = val[MAJOR] << 1;
758                         kk = like_std >4 ? like_std-4: 0;
759                         for (ii = 14; (ii >0)&&(ii>kk); ii--) {
760                                 if (jj & 0x8000) {
761                                         printf("%u ", ii);
762                                         if (like_std < ii) {
763                                                 like_std = ii;
764                                                 kk = like_std >4 ? like_std-4: 0;
765                                         }
766                                         if (min_std > ii) min_std = ii;
767                                 }
768                                 jj <<= 1;
769                         }
770                         if (like_std < 3) like_std = 3;
771                 }
772                 /* Figure out what standard the device is using if it hasn't told
773                  * us.  If we know the std, check if the device is using any of
774                  * the words from the next level up.  It happens.
775                  */
776                 if (like_std < std) like_std = std;
777
778                 if (((std == 5) || (!std && (like_std < 6))) &&
779                         ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
780                         ((      val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
781                         (((     val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
782                         (       val[CMDS_SUPP_2] & CMDS_W84) ) )
783                 ) {
784                         like_std = 6;
785                 } else if (((std == 4) || (!std && (like_std < 5))) &&
786                         ((((val[INTEGRITY]      & SIG) == SIG_VAL) && !chksum) ||
787                         ((      val[HWRST_RSLT] & VALID) == VALID_VAL) ||
788                         (((     val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
789                         ((      val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
790                 {
791                         like_std = 5;
792                 } else if (((std == 3) || (!std && (like_std < 4))) &&
793                                 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
794                                 (((     val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
795                                 ((      val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
796                                 ((      val[CAPAB_1] & VALID) == VALID_VAL) ||
797                                 ((      val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
798                                 ((      val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
799                 ) {
800                         like_std = 4;
801                 } else if (((std == 2) || (!std && (like_std < 3)))
802                  && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
803                 ) {
804                         like_std = 3;
805                 } else if (((std == 1) || (!std && (like_std < 2))) &&
806                                 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
807                                 (val[WHATS_VALID] & OK_W64_70)) )
808                 {
809                         like_std = 2;
810                 }
811
812                 if (!std)
813                         printf("\n\tLikely used: %u\n", like_std);
814                 else if (like_std > std)
815                         printf("& some of %u\n", like_std);
816                 else
817                         bb_putchar('\n');
818         } else {
819                 /* TBD: do CDROM stuff more thoroughly.  For now... */
820                 kk = 0;
821                 if (val[CDR_MINOR] == 9) {
822                         kk = 1;
823                         printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
824                 }
825                 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
826                         kk = 1;
827                         printf("\n\tSupported: CD-ROM ATAPI");
828                         jj = val[CDR_MAJOR] >> 1;
829                         for (ii = 1; ii < 15; ii++) {
830                                 if (jj & 0x0001) printf("-%u ", ii);
831                                 jj >>= 1;
832                         }
833                 }
834                 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
835                 /* the cdrom stuff is more like ATA-2 than anything else, so: */
836                 like_std = 2;
837         }
838
839         if (min_std == 0xffff)
840                 min_std = like_std > 4 ? like_std - 3 : 1;
841
842         printf("Configuration:\n");
843         /* more info from the general configuration word */
844         if ((eqpt != CDROM) && (like_std == 1)) {
845                 jj = val[GEN_CONFIG] >> 1;
846                 for (ii = 1; ii < 15; ii++) {
847                         if (jj & 0x0001)
848                                 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
849                         jj >>=1;
850                 }
851         }
852         if (dev == ATAPI_DEV) {
853                 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) ==  DRQ_3MS_VAL)
854                         strng = "3ms";
855                 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) ==  DRQ_INTR_VAL)
856                         strng = "<=10ms with INTRQ";
857                 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) ==  DRQ_50US_VAL)
858                         strng ="50us";
859                 else
860                         strng = "unknown";
861                 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
862
863                 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
864                         strng = "12 bytes";
865                 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
866                         strng = "16 bytes";
867                 else
868                         strng = "unknown";
869                 puts(strng);
870         } else {
871                 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
872                 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
873                 mm = 0; bbbig = 0;
874                 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
875                         printf("\tCHS addressing not supported\n");
876                 else {
877                         jj = val[WHATS_VALID] & OK_W54_58;
878                         printf("\tLogical\t\tmax\tcurrent\n\tcylinders\t%u\t%u\n\theads\t\t%u\t%u\n\tsectors/track\t%u\t%u\n\t--\n",
879                                         val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
880
881                         if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
882                                 printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
883
884                         if (jj) {
885                                 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
886                                 if (like_std < 3) {
887                                         /* check Endian of capacity bytes */
888                                         nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
889                                         oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
890                                         if (abs(mm - nn) > abs(oo - nn))
891                                                 mm = oo;
892                                 }
893                                 printf("\tCHS current addressable sectors:%11u\n", mm);
894                         }
895                 }
896                 /* LBA addressing */
897                 printf("\tLBA    user addressable sectors:%11u\n", ll);
898                 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
899                  && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
900                 ) {
901                         bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
902                                 (uint64_t)val[LBA_48_MSB] << 32 |
903                                 (uint64_t)val[LBA_MID] << 16 |
904                                         val[LBA_LSB];
905                         printf("\tLBA48  user addressable sectors:%11"PRIu64"\n", bbbig);
906                 }
907
908                 if (!bbbig)
909                         bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
910                 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
911                 bbbig = (bbbig << 9) / 1000000;
912                 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
913
914                 if (bbbig > 1000)
915                         printf("(%"PRIu64" GB)\n", bbbig/1000);
916                 else
917                         bb_putchar('\n');
918         }
919
920         /* hw support of commands (capabilities) */
921         printf("Capabilities:\n\t");
922
923         if (dev == ATAPI_DEV) {
924                 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
925                 if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
926         }
927         if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
928
929         if (like_std != 1) {
930                 printf("IORDY%s(can%s be disabled)\n",
931                                 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
932                                 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
933         } else
934                 printf("no IORDY\n");
935
936         if ((like_std == 1) && val[BUF_TYPE]) {
937                 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
938                                 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
939                                 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
940         }
941
942         if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
943                 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
944         }
945         if ((min_std < 4) && (val[RW_LONG])) {
946                 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
947         }
948         if ((eqpt != CDROM) && (like_std > 3)) {
949                 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
950         }
951
952         if (dev == ATA_DEV) {
953                 if (like_std == 1)
954                         printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
955                 else {
956                         printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
957                         if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
958                                 printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
959                         else
960                                 bb_putchar('\n');
961                 }
962                 printf("\tR/W multiple sector transfer: ");
963                 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
964                         printf("not supported\n");
965                 else {
966                         printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
967                         if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
968                                 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
969                         else
970                                 printf("?\n");
971                 }
972                 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
973                         /* We print out elsewhere whether the APM feature is enabled or
974                            not.  If it's not enabled, let's not repeat the info; just print
975                            nothing here. */
976                         printf("\tAdvancedPM level: ");
977                         if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
978                                 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
979                                 printf("%u (0x%x)\n", apm_level, apm_level);
980                         }
981                         else
982                                 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
983                 }
984                 if (like_std > 5 && val[ACOUSTIC]) {
985                         printf("\tRecommended acoustic management value: %u, current value: %u\n",
986                                         (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
987                 }
988         } else {
989                  /* ATAPI */
990                 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
991                         printf("\tATA sw reset required\n");
992
993                 if (val[PKT_REL] || val[SVC_NBSY]) {
994                         printf("\tOverlap support:");
995                         if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
996                         if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
997                         bb_putchar('\n');
998                 }
999         }
1000
1001         /* DMA stuff. Check that only one DMA mode is selected. */
1002         printf("\tDMA: ");
1003         if (!(val[CAPAB_0] & DMA_SUP))
1004                 printf("not supported\n");
1005         else {
1006                 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
1007                         printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
1008                 if (val[SINGLE_DMA]) {
1009                         jj = val[SINGLE_DMA];
1010                         kk = val[SINGLE_DMA] >> 8;
1011                         err_dma += mode_loop(jj, kk, 's', &have_mode);
1012                 }
1013                 if (val[MULTI_DMA]) {
1014                         jj = val[MULTI_DMA];
1015                         kk = val[MULTI_DMA] >> 8;
1016                         err_dma += mode_loop(jj, kk, 'm', &have_mode);
1017                 }
1018                 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
1019                         jj = val[ULTRA_DMA];
1020                         kk = val[ULTRA_DMA] >> 8;
1021                         err_dma += mode_loop(jj, kk, 'u', &have_mode);
1022                 }
1023                 if (err_dma || !have_mode) printf("(?)");
1024                 bb_putchar('\n');
1025
1026                 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
1027                         printf("\t\tInterleaved DMA support\n");
1028
1029                 if ((val[WHATS_VALID] & OK_W64_70)
1030                  && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1031                 ) {
1032                         printf("\t\tCycle time:");
1033                         if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
1034                         if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
1035                         bb_putchar('\n');
1036                 }
1037         }
1038
1039         /* Programmed IO stuff */
1040         printf("\tPIO: ");
1041         /* If a drive supports mode n (e.g. 3), it also supports all modes less
1042          * than n (e.g. 3, 2, 1 and 0).  Print all the modes. */
1043         if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
1044                 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
1045                 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
1046                         if (jj & 0x0001) printf("pio%d ", ii);
1047                         jj >>=1;
1048                 }
1049                 bb_putchar('\n');
1050         } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
1051                 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
1052                         printf("pio%d ", ii);
1053                 bb_putchar('\n');
1054         } else
1055                 puts("unknown");
1056
1057         if (val[WHATS_VALID] & OK_W64_70) {
1058                 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
1059                         printf("\t\tCycle time:");
1060                         if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1061                         if (val[PIO_FLOW]) printf("  IORDY flow control=%uns", val[PIO_FLOW]);
1062                         bb_putchar('\n');
1063                 }
1064         }
1065
1066         if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
1067                 printf("Commands/features:\n\tEnabled\tSupported:\n");
1068                 jj = val[CMDS_SUPP_0];
1069                 kk = val[CMDS_EN_0];
1070                 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
1071                         const char *feat_str = nth_string(cmd_feat_str, ii);
1072                         if ((jj & 0x8000) && (*feat_str != '\0')) {
1073                                 printf("\t%s\t%s\n", (kk & 0x8000) ? "   *" : "", feat_str);
1074                         }
1075                         jj <<= 1;
1076                         kk <<= 1;
1077                         if (ii % 16 == 15) {
1078                                 jj = val[CMDS_SUPP_0+1+(ii/16)];
1079                                 kk = val[CMDS_EN_0+1+(ii/16)];
1080                         }
1081                         if (ii == 31) {
1082                                 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
1083                                         ii +=16;
1084                         }
1085                 }
1086         }
1087         /* Removable Media Status Notification feature set */
1088         if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
1089                 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
1090
1091         /* security */
1092         if ((eqpt != CDROM) && (like_std > 3)
1093          && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1094         ) {
1095                 printf("Security:\n");
1096                 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
1097                         printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
1098                 jj = val[SECU_STATUS];
1099                 if (jj) {
1100                         for (ii = 0; ii < NUM_SECU_STR; ii++) {
1101                                 printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "", nth_string(secu_str, ii));
1102                                 jj >>=1;
1103                         }
1104                         if (val[SECU_STATUS] & SECU_ENABLED) {
1105                                 printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
1106                         }
1107                 }
1108                 jj =  val[ERASE_TIME]     & ERASE_BITS;
1109                 kk =  val[ENH_ERASE_TIME] & ERASE_BITS;
1110                 if (jj || kk) {
1111                         printf("\t");
1112                         if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1113                         if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
1114                         bb_putchar('\n');
1115                 }
1116         }
1117
1118         /* reset result */
1119         jj = val[HWRST_RSLT];
1120         if ((jj & VALID) == VALID_VAL) {
1121                 oo = (jj & RST0);
1122                 if (!oo)
1123                         jj >>= 8;
1124                 if ((jj & DEV_DET) == JUMPER_VAL)
1125                         strng = " determined by the jumper";
1126                 else if ((jj & DEV_DET) == CSEL_VAL)
1127                         strng = " determined by CSEL";
1128                 else
1129                         strng = "";
1130                 printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
1131                                 (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
1132         }
1133
1134         /* more stuff from std 5 */
1135         if ((like_std > 4) && (eqpt != CDROM)) {
1136                 if (val[CFA_PWR_MODE] & VALID_W160) {
1137                         printf("CFA power mode 1:\n\t%s%s\n", (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
1138                                         (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
1139
1140                         if (val[CFA_PWR_MODE] & MAX_AMPS)
1141                                 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
1142                 }
1143                 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
1144                         printf("Checksum: %scorrect\n", chksum ? "in" : "");
1145                 }
1146         }
1147
1148         exit(EXIT_SUCCESS);
1149 }
1150 #endif
1151
1152 // Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1153 // then the HDIO_GET_IDENTITY only returned 142 bytes.
1154 // Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1155 // and HDIO_GET_IDENTITY returns 512 bytes.  But the latest
1156 // 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1157 // (which they should, but they should just return -EINVAL).
1158 //
1159 // So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1160 // On a really old system, it will not, and we will be confused.
1161 // Too bad, really.
1162
1163 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1164 static const char cfg_str[] ALIGN1 =
1165         """\0"            "HardSect""\0"   "SoftSect""\0"  "NotMFM""\0"
1166         "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0"     "Removeable""\0"
1167         "DTR<=5Mbs""\0"   "DTR>5Mbs""\0"   "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1168         "dStbOff""\0"     "TrkOff""\0"     "FmtGapReq""\0" "nonMagnetic"
1169 ;
1170
1171 static const char BuffType[] ALIGN1 =
1172         "unknown""\0"     "1Sect""\0"      "DualPort""\0"  "DualPortCache"
1173 ;
1174
1175 static void dump_identity(const struct hd_driveid *id)
1176 {
1177         int i;
1178         const unsigned short *id_regs = (const void*) id;
1179
1180         printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1181                                 id->model, id->fw_rev, id->serial_no);
1182         for (i = 0; i <= 15; i++) {
1183                 if (id->config & (1<<i))
1184                         printf(" %s", nth_string(cfg_str, i));
1185         }
1186         printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
1187                         " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
1188                                 id->cyls, id->heads, id->sectors, id->track_bytes,
1189                                 id->sector_bytes, id->ecc_bytes,
1190                                 id->buf_type, nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
1191                                 id->buf_size/2, id->max_multsect);
1192         if (id->max_multsect) {
1193                 printf(", MultSect=");
1194                 if (!(id->multsect_valid & 1))
1195                         printf("?%u?", id->multsect);
1196                 else if (id->multsect)
1197                         printf("%u", id->multsect);
1198                 else
1199                         printf("off");
1200         }
1201         bb_putchar('\n');
1202
1203         if (!(id->field_valid & 1))
1204                 printf(" (maybe):");
1205
1206         printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
1207                 id->cur_sectors,
1208                 (BB_BIG_ENDIAN) ?
1209                         (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1210                         (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
1211                         ((id->capability&2) == 0) ? "no" : "yes");
1212
1213         if (id->capability & 2)
1214                 printf(", LBAsects=%u", id->lba_capacity);
1215
1216         printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ?  "on/off" : "yes" : "no");
1217
1218         if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
1219                 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
1220
1221         if ((id->capability & 1) && (id->field_valid & 2))
1222                 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1223
1224         printf("\n PIO modes:  ");
1225         if (id->tPIO <= 5) {
1226                 printf("pio0 ");
1227                 if (id->tPIO >= 1) printf("pio1 ");
1228                 if (id->tPIO >= 2) printf("pio2 ");
1229         }
1230         if (id->field_valid & 2) {
1231                 if (id->eide_pio_modes & 1) printf("pio3 ");
1232                 if (id->eide_pio_modes & 2) printf("pio4 ");
1233                 if (id->eide_pio_modes &~3) printf("pio? ");
1234         }
1235         if (id->capability & 1) {
1236                 if (id->dma_1word | id->dma_mword) {
1237                         printf("\n DMA modes:  ");
1238                         if (id->dma_1word & 0x100) printf("*");
1239                         if (id->dma_1word & 1) printf("sdma0 ");
1240                         if (id->dma_1word & 0x200) printf("*");
1241                         if (id->dma_1word & 2) printf("sdma1 ");
1242                         if (id->dma_1word & 0x400) printf("*");
1243                         if (id->dma_1word & 4) printf("sdma2 ");
1244                         if (id->dma_1word & 0xf800) printf("*");
1245                         if (id->dma_1word & 0xf8) printf("sdma? ");
1246                         if (id->dma_mword & 0x100) printf("*");
1247                         if (id->dma_mword & 1) printf("mdma0 ");
1248                         if (id->dma_mword & 0x200) printf("*");
1249                         if (id->dma_mword & 2) printf("mdma1 ");
1250                         if (id->dma_mword & 0x400) printf("*");
1251                         if (id->dma_mword & 4) printf("mdma2 ");
1252                         if (id->dma_mword & 0xf800) printf("*");
1253                         if (id->dma_mword & 0xf8) printf("mdma? ");
1254                 }
1255         }
1256         if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
1257                 printf("\n UDMA modes: ");
1258                 if (id->dma_ultra & 0x100) printf("*");
1259                 if (id->dma_ultra & 0x001) printf("udma0 ");
1260                 if (id->dma_ultra & 0x200) printf("*");
1261                 if (id->dma_ultra & 0x002) printf("udma1 ");
1262                 if (id->dma_ultra & 0x400) printf("*");
1263                 if (id->dma_ultra & 0x004) printf("udma2 ");
1264 #ifdef __NEW_HD_DRIVE_ID
1265                 if (id->hw_config & 0x2000) {
1266 #else /* !__NEW_HD_DRIVE_ID */
1267                 if (id->word93 & 0x2000) {
1268 #endif /* __NEW_HD_DRIVE_ID */
1269                         if (id->dma_ultra & 0x0800) printf("*");
1270                         if (id->dma_ultra & 0x0008) printf("udma3 ");
1271                         if (id->dma_ultra & 0x1000) printf("*");
1272                         if (id->dma_ultra & 0x0010) printf("udma4 ");
1273                         if (id->dma_ultra & 0x2000) printf("*");
1274                         if (id->dma_ultra & 0x0020) printf("udma5 ");
1275                         if (id->dma_ultra & 0x4000) printf("*");
1276                         if (id->dma_ultra & 0x0040) printf("udma6 ");
1277                         if (id->dma_ultra & 0x8000) printf("*");
1278                         if (id->dma_ultra & 0x0080) printf("udma7 ");
1279                 }
1280         }
1281         printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
1282         if (id_regs[83] & 8) {
1283                 if (!(id_regs[86] & 8))
1284                         printf(": disabled (255)");
1285                 else if ((id_regs[91] & 0xFF00) != 0x4000)
1286                         printf(": unknown setting");
1287                 else
1288                         printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
1289         }
1290         if (id_regs[82] & 0x20)
1291                 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
1292 #ifdef __NEW_HD_DRIVE_ID
1293         if ((id->minor_rev_num && id->minor_rev_num <= 31)
1294          || (id->major_rev_num && id->minor_rev_num <= 31)
1295         ) {
1296                 printf("\n Drive conforms to: %s: ", (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
1297                 if (id->major_rev_num != 0x0000 &&  /* NOVAL_0 */
1298                     id->major_rev_num != 0xFFFF) {  /* NOVAL_1 */
1299                         for (i = 0; i <= 15; i++) {
1300                                 if (id->major_rev_num & (1<<i))
1301                                                 printf(" ATA/ATAPI-%u", i);
1302                         }
1303                 }
1304         }
1305 #endif /* __NEW_HD_DRIVE_ID */
1306         printf("\n\n * current active mode\n\n");
1307 }
1308 #endif
1309
1310 static void flush_buffer_cache(/*int fd*/ void)
1311 {
1312         fsync(fd);                              /* flush buffers */
1313         ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
1314 #ifdef HDIO_DRIVE_CMD
1315         sleep(1);
1316         if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) {       /* await completion */
1317                 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1318                         bb_perror_msg("HDIO_DRIVE_CMD");
1319                 else
1320                         bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1321         }
1322 #endif
1323 }
1324
1325 static void seek_to_zero(/*int fd*/ void)
1326 {
1327         xlseek(fd, (off_t) 0, SEEK_SET);
1328 }
1329
1330 static void read_big_block(/*int fd,*/ char *buf)
1331 {
1332         int i;
1333
1334         xread(fd, buf, TIMING_BUF_BYTES);
1335         /* access all sectors of buf to ensure the read fully completed */
1336         for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1337                 buf[i] &= 1;
1338 }
1339
1340 static unsigned dev_size_mb(/*int fd*/ void)
1341 {
1342         union {
1343                 unsigned long long blksize64;
1344                 unsigned blksize32;
1345         } u;
1346
1347         if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1348                 u.blksize64 /= (1024 * 1024);
1349         } else {
1350                 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1351                 u.blksize64 = u.blksize32 / (2 * 1024);
1352         }
1353         if (u.blksize64 > UINT_MAX)
1354                 return UINT_MAX;
1355         return u.blksize64;
1356 }
1357
1358 static void print_timing(unsigned m, unsigned elapsed_us)
1359 {
1360         unsigned sec = elapsed_us / 1000000;
1361         unsigned hs = (elapsed_us % 1000000) / 10000;
1362
1363         printf("%5u MB in %u.%02u seconds = %u kB/s\n",
1364                 m, sec, hs,
1365                 /* "| 1" prevents div-by-0 */
1366                 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
1367                 // ~= (m * 1024) / (elapsed_us / 1000000)
1368                 // = kb / elapsed_sec
1369         );
1370 }
1371
1372 static void do_time(int cache /*,int fd*/)
1373 /* cache=1: time cache: repeatedly read N MB at offset 0
1374  * cache=0: time device: linear read, starting at offset 0
1375  */
1376 {
1377         unsigned max_iterations, iterations;
1378         unsigned start; /* doesn't need to be long long */
1379         unsigned elapsed, elapsed2;
1380         unsigned total_MB;
1381         char *buf = xmalloc(TIMING_BUF_BYTES);
1382
1383         if (mlock(buf, TIMING_BUF_BYTES))
1384                 bb_perror_msg_and_die("mlock");
1385
1386         /* Clear out the device request queues & give them time to complete.
1387          * NB: *small* delay. User is expected to have a clue and to not run
1388          * heavy io in parallel with measurements. */
1389         sync();
1390         sleep(1);
1391         if (cache) { /* Time cache */
1392                 seek_to_zero();
1393                 read_big_block(buf);
1394                 printf("Timing buffer-cache reads: ");
1395         } else { /* Time device */
1396                 printf("Timing buffered disk reads:");
1397         }
1398         fflush(stdout);
1399
1400         /* Now do the timing */
1401         iterations = 0;
1402         /* Max time to run (small for cache, avoids getting
1403          * huge total_MB which can overlow unsigned type) */
1404         elapsed2 = 510000; /* cache */
1405         max_iterations = UINT_MAX;
1406         if (!cache) {
1407                 elapsed2 = 3000000; /* not cache */
1408                 /* Don't want to read past the end! */
1409                 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1410         }
1411         start = monotonic_us();
1412         do {
1413                 if (cache)
1414                         seek_to_zero();
1415                 read_big_block(buf);
1416                 elapsed = (unsigned)monotonic_us() - start;
1417                 ++iterations;
1418         } while (elapsed < elapsed2 && iterations < max_iterations);
1419         total_MB = iterations * TIMING_BUF_MB;
1420         //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1421         if (cache) {
1422                 /* Cache: remove lseek() and monotonic_us() overheads
1423                  * from elapsed */
1424                 start = monotonic_us();
1425                 do {
1426                         seek_to_zero();
1427                         elapsed2 = (unsigned)monotonic_us() - start;
1428                 } while (--iterations);
1429                 //printf(" elapsed2:%u ", elapsed2);
1430                 elapsed -= elapsed2;
1431                 total_MB *= 2; // BUFCACHE_FACTOR (why?)
1432                 flush_buffer_cache();
1433         }
1434         print_timing(total_MB, elapsed);
1435         munlock(buf, TIMING_BUF_BYTES);
1436         free(buf);
1437 }
1438
1439 #if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1440 static void bus_state_value(unsigned value)
1441 {
1442         if (value == BUSSTATE_ON)
1443                 on_off(1);
1444         else if (value == BUSSTATE_OFF)
1445                 on_off(0);
1446         else if (value == BUSSTATE_TRISTATE)
1447                 printf(" (tristate)\n");
1448         else
1449                 printf(" (unknown: %d)\n", value);
1450 }
1451 #endif
1452
1453 #ifdef HDIO_DRIVE_CMD
1454 static void interpret_standby(uint8_t standby)
1455 {
1456         printf(" (");
1457         if (standby == 0) {
1458                 printf("off");
1459         } else if (standby <= 240 || standby == 252 || standby == 255) {
1460                 /* standby is in 5 sec units */
1461                 printf("%u minutes %u seconds", standby / 12, (standby*5) % 60);
1462         } else if (standby <= 251) {
1463                 unsigned t = (standby - 240); /* t is in 30 min units */;
1464                 printf("%u.%c hours", t / 2, (t & 1) ? '0' : '5');
1465         }
1466         if (standby == 253)
1467                 printf("vendor-specific");
1468         if (standby == 254)
1469                 printf("reserved");
1470         printf(")\n");
1471 }
1472
1473 static const uint8_t xfermode_val[] ALIGN1 = {
1474          8,      9,     10,     11,     12,     13,     14,     15,
1475         16,     17,     18,     19,     20,     21,     22,     23,
1476         32,     33,     34,     35,     36,     37,     38,     39,
1477         64,     65,     66,     67,     68,     69,     70,     71
1478 };
1479 /* NB: we save size by _not_ storing terninating NUL! */
1480 static const char xfermode_name[][5] ALIGN1 = {
1481         "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1482         "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1483         "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1484         "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
1485 };
1486
1487 static int translate_xfermode(const char *name)
1488 {
1489         int val;
1490         unsigned i;
1491
1492         for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1493                 if (!strncmp(name, xfermode_name[i], 5))
1494                         if (strlen(name) <= 5)
1495                                 return xfermode_val[i];
1496         }
1497         /* Negative numbers are invalid and are caught later */
1498         val = bb_strtoi(name, NULL, 10);
1499         if (!errno)
1500                 return val;
1501         return -1;
1502 }
1503
1504 static void interpret_xfermode(unsigned xfermode)
1505 {
1506         printf(" (");
1507         if (xfermode == 0)
1508                 printf("default PIO mode");
1509         else if (xfermode == 1)
1510                 printf("default PIO mode, disable IORDY");
1511         else if (xfermode >= 8 && xfermode <= 15)
1512                 printf("PIO flow control mode%u", xfermode - 8);
1513         else if (xfermode >= 16 && xfermode <= 23)
1514                 printf("singleword DMA mode%u", xfermode - 16);
1515         else if (xfermode >= 32 && xfermode <= 39)
1516                 printf("multiword DMA mode%u", xfermode - 32);
1517         else if (xfermode >= 64 && xfermode <= 71)
1518                 printf("UltraDMA mode%u", xfermode - 64);
1519         else
1520                 printf("unknown");
1521         printf(")\n");
1522 }
1523 #endif /* HDIO_DRIVE_CMD */
1524
1525 static void print_flag(int flag, const char *s, unsigned long value)
1526 {
1527         if (flag)
1528                 printf(" setting %s to %ld\n", s, value);
1529 }
1530
1531 static void process_dev(char *devname)
1532 {
1533         /*int fd;*/
1534         long parm, multcount;
1535 #ifndef HDIO_DRIVE_CMD
1536         int force_operation = 0;
1537 #endif
1538         /* Please restore args[n] to these values after each ioctl
1539            except for args[2] */
1540         unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
1541         const char *fmt = " %s\t= %2ld";
1542
1543         /*fd = xopen(devname, O_RDONLY | O_NONBLOCK);*/
1544         xmove_fd(xopen(devname, O_RDONLY | O_NONBLOCK), fd);
1545         printf("\n%s:\n", devname);
1546
1547         if (set_readahead) {
1548                 print_flag(get_readahead, "fs readahead", Xreadahead);
1549                 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
1550         }
1551 #if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1552         if (unregister_hwif) {
1553                 printf(" attempting to unregister hwif#%lu\n", hwif);
1554                 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
1555         }
1556 #endif
1557 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
1558         if (scan_hwif) {
1559                 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
1560                 args[0] = hwif_data;
1561                 args[1] = hwif_ctrl;
1562                 args[2] = hwif_irq;
1563                 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
1564                 args[0] = WIN_SETFEATURES;
1565                 args[1] = 0;
1566         }
1567 #endif
1568         if (set_piomode) {
1569                 if (noisy_piomode) {
1570                         printf(" attempting to ");
1571                         if (piomode == 255)
1572                                 printf("auto-tune PIO mode\n");
1573                         else if (piomode < 100)
1574                                 printf("set PIO mode to %d\n", piomode);
1575                         else if (piomode < 200)
1576                                 printf("set MDMA mode to %d\n", (piomode-100));
1577                         else
1578                                 printf("set UDMA mode to %d\n", (piomode-200));
1579                 }
1580                 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
1581         }
1582         if (set_io32bit) {
1583                 print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
1584                 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
1585         }
1586         if (set_mult) {
1587                 print_flag(get_mult, "multcount", mult);
1588 #ifdef HDIO_DRIVE_CMD
1589                 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
1590 #else
1591                 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
1592 #endif
1593         }
1594         if (set_readonly) {
1595                 print_flag_on_off(get_readonly, "readonly", readonly);
1596                 ioctl_or_warn(fd, BLKROSET, &readonly);
1597         }
1598         if (set_unmask) {
1599                 print_flag_on_off(get_unmask, "unmaskirq", unmask);
1600                 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
1601         }
1602 #if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1603         if (set_dma) {
1604                 print_flag_on_off(get_dma, "using_dma", dma);
1605                 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
1606         }
1607 #endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
1608 #ifdef HDIO_SET_QDMA
1609         if (set_dma_q) {
1610                 print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
1611                 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
1612         }
1613 #endif
1614         if (set_nowerr) {
1615                 print_flag_on_off(get_nowerr, "nowerr", nowerr);
1616                 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
1617         }
1618         if (set_keep) {
1619                 print_flag_on_off(get_keep, "keep_settings", keep);
1620                 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
1621         }
1622 #ifdef HDIO_DRIVE_CMD
1623         if (set_doorlock) {
1624                 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
1625                 args[2] = 0;
1626                 print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
1627                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1628                 args[0] = WIN_SETFEATURES;
1629         }
1630         if (set_dkeep) {
1631                 /* lock/unlock the drive's "feature" settings */
1632                 print_flag_on_off(get_dkeep, "drive keep features", dkeep);
1633                 args[2] = dkeep ? 0x66 : 0xcc;
1634                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1635         }
1636         if (set_defects) {
1637                 args[2] = defects ? 0x04 : 0x84;
1638                 print_flag(get_defects, "drive defect-mgmt", defects);
1639                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1640         }
1641         if (set_prefetch) {
1642                 args[1] = prefetch;
1643                 args[2] = 0xab;
1644                 print_flag(get_prefetch, "drive prefetch", prefetch);
1645                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1646                 args[1] = 0;
1647         }
1648         if (set_xfermode) {
1649                 args[1] = xfermode_requested;
1650                 args[2] = 3;
1651                 if (get_xfermode) {
1652                         print_flag(1, "xfermode", xfermode_requested);
1653                         interpret_xfermode(xfermode_requested);
1654                 }
1655                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1656                 args[1] = 0;
1657         }
1658         if (set_lookahead) {
1659                 args[2] = lookahead ? 0xaa : 0x55;
1660                 print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
1661                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1662         }
1663         if (set_apmmode) {
1664                 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
1665                 args[1] = apmmode; /* sector count register 1-255 */
1666                 if (get_apmmode)
1667                         printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
1668                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1669                 args[1] = 0;
1670         }
1671         if (set_wcache) {
1672 #ifdef DO_FLUSHCACHE
1673 #ifndef WIN_FLUSHCACHE
1674 #define WIN_FLUSHCACHE 0xe7
1675 #endif
1676 #endif /* DO_FLUSHCACHE */
1677                 args[2] = wcache ? 0x02 : 0x82;
1678                 print_flag_on_off(get_wcache, "drive write-caching", wcache);
1679 #ifdef DO_FLUSHCACHE
1680                 if (!wcache)
1681                         ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
1682 #endif /* DO_FLUSHCACHE */
1683                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1684 #ifdef DO_FLUSHCACHE
1685                 if (!wcache)
1686                         ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
1687 #endif /* DO_FLUSHCACHE */
1688         }
1689
1690         /* In code below, we do not preserve args[0], but the rest
1691            is preserved, including args[2] */
1692         args[2] = 0;
1693
1694         if (set_standbynow) {
1695 #ifndef WIN_STANDBYNOW1
1696 #define WIN_STANDBYNOW1 0xE0
1697 #endif
1698 #ifndef WIN_STANDBYNOW2
1699 #define WIN_STANDBYNOW2 0x94
1700 #endif
1701                 if (get_standbynow) printf(" issuing standby command\n");
1702                 args[0] = WIN_STANDBYNOW1;
1703                 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
1704         }
1705         if (set_sleepnow) {
1706 #ifndef WIN_SLEEPNOW1
1707 #define WIN_SLEEPNOW1 0xE6
1708 #endif
1709 #ifndef WIN_SLEEPNOW2
1710 #define WIN_SLEEPNOW2 0x99
1711 #endif
1712                 if (get_sleepnow) printf(" issuing sleep command\n");
1713                 args[0] = WIN_SLEEPNOW1;
1714                 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
1715         }
1716         if (set_seagate) {
1717                 args[0] = 0xfb;
1718                 if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
1719                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1720         }
1721         if (set_standby) {
1722                 args[0] = WIN_SETIDLE1;
1723                 args[1] = standby_requested;
1724                 if (get_standby) {
1725                         print_flag(1, "standby", standby_requested);
1726                         interpret_standby(standby_requested);
1727                 }
1728                 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1729                 args[1] = 0;
1730         }
1731 #else   /* HDIO_DRIVE_CMD */
1732         if (force_operation) {
1733                 char buf[512];
1734                 flush_buffer_cache();
1735                 if (-1 == read(fd, buf, sizeof(buf)))
1736                         bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf));
1737         }
1738 #endif  /* HDIO_DRIVE_CMD */
1739
1740         if (get_mult || get_identity) {
1741                 multcount = -1;
1742                 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
1743                         if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
1744                                 bb_perror_msg("HDIO_GET_MULTCOUNT");
1745                         else
1746                                 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
1747                 } else if (get_mult) {
1748                         printf(fmt, "multcount", multcount);
1749                         on_off(multcount != 0);
1750                 }
1751         }
1752         if (get_io32bit) {
1753                 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
1754                         printf(" IO_support\t=%3ld (", parm);
1755                         if (parm == 0)
1756                                 printf("default 16-bit)\n");
1757                         else if (parm == 2)
1758                                 printf("16-bit)\n");
1759                         else if (parm == 1)
1760                                 printf("32-bit)\n");
1761                         else if (parm == 3)
1762                                 printf("32-bit w/sync)\n");
1763                         else if (parm == 8)
1764                                 printf("Request-Queue-Bypass)\n");
1765                         else
1766                                 printf("\?\?\?)\n");
1767                 }
1768         }
1769         if (get_unmask) {
1770                 if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
1771                         print_value_on_off("unmaskirq", parm);
1772         }
1773
1774
1775 #if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1776         if (get_dma) {
1777                 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
1778                         printf(fmt, "using_dma", parm);
1779                         if (parm == 8)
1780                                 printf(" (DMA-Assisted-PIO)\n");
1781                         else
1782                                 on_off(parm != 0);
1783                 }
1784         }
1785 #endif
1786 #ifdef HDIO_GET_QDMA
1787         if (get_dma_q) {
1788                 if(!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
1789                         print_value_on_off("queue_depth", parm);
1790         }
1791 #endif
1792         if (get_keep) {
1793                 if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
1794                         print_value_on_off("keepsettings", parm);
1795         }
1796
1797         if (get_nowerr) {
1798                 if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
1799                         print_value_on_off("nowerr", parm);
1800         }
1801         if (get_readonly) {
1802                 if(!ioctl_or_warn(fd, BLKROGET, &parm))
1803                         print_value_on_off("readonly", parm);
1804         }
1805         if (get_readahead) {
1806                 if(!ioctl_or_warn(fd, BLKRAGET, &parm))
1807                         print_value_on_off("readahead", parm);
1808         }
1809         if (get_geom) {
1810                 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
1811                         struct hd_geometry g;
1812
1813                         if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
1814                                 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
1815                                                 g.cylinders, g.heads, g.sectors, parm, g.start);
1816                 }
1817         }
1818 #ifdef HDIO_DRIVE_CMD
1819         if (get_powermode) {
1820 #ifndef WIN_CHECKPOWERMODE1
1821 #define WIN_CHECKPOWERMODE1 0xE5
1822 #endif
1823 #ifndef WIN_CHECKPOWERMODE2
1824 #define WIN_CHECKPOWERMODE2 0x98
1825 #endif
1826                 const char *state;
1827
1828                 args[0] = WIN_CHECKPOWERMODE1;
1829                 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
1830                         if (errno != EIO || args[0] != 0 || args[1] != 0)
1831                                 state = "unknown";
1832                         else
1833                                 state = "sleeping";
1834                 } else
1835                         state = (args[2] == 255) ? "active/idle" : "standby";
1836                 args[1] = args[2] = 0;
1837
1838                 printf(" drive state is:  %s\n", state);
1839         }
1840 #endif
1841 #if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1842         if (perform_reset) {
1843                 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
1844         }
1845 #endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1846 #if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1847         if (perform_tristate) {
1848                 args[0] = 0;
1849                 args[1] = tristate;
1850                 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
1851         }
1852 #endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1853 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1854         if (get_identity) {
1855                 struct hd_driveid id;
1856
1857                 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1858                         if (multcount != -1) {
1859                                 id.multsect = multcount;
1860                                 id.multsect_valid |= 1;
1861                         } else
1862                                 id.multsect_valid &= ~1;
1863                         dump_identity(&id);
1864                 } else if (errno == -ENOMSG)
1865                         printf(" no identification info available\n");
1866                 else if (ENABLE_IOCTL_HEX2STR_ERROR)  /* To be coherent with ioctl_or_warn */
1867                         bb_perror_msg("HDIO_GET_IDENTITY");
1868                 else
1869                         bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
1870         }
1871
1872         if (get_IDentity) {
1873                 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
1874
1875                 memset(args1, 0, sizeof(args1));
1876                 args1[0] = WIN_IDENTIFY;
1877                 args1[3] = 1;
1878                 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
1879                         identify((void *)(args1 + 4));
1880         }
1881 #endif
1882 #if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1883         if (set_busstate) {
1884                 if (get_busstate) {
1885                         print_flag(1, "bus state", busstate);
1886                         bus_state_value(busstate);
1887                 }
1888                 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
1889         }
1890         if (get_busstate) {
1891                 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
1892                         printf(fmt, "bus state", parm);
1893                         bus_state_value(parm);
1894                 }
1895         }
1896 #endif
1897         if (reread_partn)
1898                 ioctl_or_warn(fd, BLKRRPART, NULL);
1899
1900         if (do_ctimings)
1901                 do_time(1 /*,fd*/); /* time cache */
1902         if (do_timings)
1903                 do_time(0 /*,fd*/); /* time device */
1904         if (do_flush)
1905                 flush_buffer_cache();
1906         close(fd);
1907 }
1908
1909 #if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1910 static int fromhex(unsigned char c)
1911 {
1912         if (isdigit(c))
1913                 return (c - '0');
1914         if (c >= 'a' && c <= 'f')
1915                 return (c - ('a' - 10));
1916         bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1917 }
1918
1919 static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
1920 static void identify_from_stdin(void)
1921 {
1922         uint16_t sbuf[256];
1923         unsigned char buf[1280];
1924         unsigned char *b = (unsigned char *)buf;
1925         int i;
1926
1927         xread(0, buf, 1280);
1928
1929         // Convert the newline-separated hex data into an identify block.
1930
1931         for (i = 0; i < 256; i++) {
1932                 int j;
1933                 for (j = 0; j < 4; j++)
1934                         sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
1935         }
1936
1937         // Parse the data.
1938
1939         identify(sbuf);
1940 }
1941 #else
1942 void identify_from_stdin(void);
1943 #endif
1944
1945 /* busybox specific stuff */
1946 static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
1947 {
1948         if (get) {
1949                 *get = 1;
1950         }
1951         if (optarg) {
1952                 *set = 1;
1953                 *value = xatol_range(optarg, min, max);
1954         }
1955 }
1956
1957 static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
1958 {
1959         if (flag) {
1960                 *get = 1;
1961                 if (optarg) {
1962                         *value = translate_xfermode(optarg);
1963                         *set = (*value > -1);
1964                 }
1965         }
1966 }
1967
1968 /*------- getopt short options --------*/
1969 static const char hdparm_options[] ALIGN1 =
1970         "gfu::n::p:r::m::c::k::a::B:tT"
1971         USE_FEATURE_HDPARM_GET_IDENTITY("iI")
1972         USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
1973 #ifdef HDIO_DRIVE_CMD
1974         "S:D:P:X:K:A:L:W:CyYzZ"
1975 #endif
1976         USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
1977 #ifdef HDIO_GET_QDMA
1978 #ifdef HDIO_SET_QDMA
1979         "Q:"
1980 #else
1981         "Q"
1982 #endif
1983 #endif
1984         USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
1985         USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
1986         USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
1987 /*-------------------------------------*/
1988
1989 /* our main() routine: */
1990 int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1991 int hdparm_main(int argc, char **argv)
1992 {
1993         int c;
1994         int flagcount = 0;
1995
1996         while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
1997                 flagcount++;
1998                 USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
1999                 USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
2000                 get_geom |= (c == 'g');
2001                 do_flush |= (c == 'f');
2002                 if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
2003                 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
2004                 if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
2005                 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
2006                 if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
2007                 if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
2008                 if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
2009                 if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
2010                 if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
2011                 if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
2012                 do_flush |= do_timings |= (c == 't');
2013                 do_flush |= do_ctimings |= (c == 'T');
2014 #ifdef HDIO_DRIVE_CMD
2015                 if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, 255);
2016                 if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
2017                 if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
2018                 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
2019                 if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
2020                 if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
2021                 if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
2022                 if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
2023                 get_powermode |= (c == 'C');
2024                 get_standbynow = set_standbynow |= (c == 'y');
2025                 get_sleepnow = set_sleepnow |= (c == 'Y');
2026                 reread_partn |= (c == 'z');
2027                 get_seagate = set_seagate |= (c == 'Z');
2028 #endif
2029                 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
2030 #ifdef HDIO_GET_QDMA
2031                 if (c == 'Q') {
2032 #ifdef HDIO_SET_QDMA
2033                         parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
2034 #else
2035                         parse_opts(&get_dma_q, NULL, NULL, 0, 0);
2036 #endif
2037                 }
2038 #endif
2039                 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
2040                 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
2041                 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
2042 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2043                 if (c == 'R') {
2044                         parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
2045                         hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
2046                         hwif_irq  = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
2047                         /* Move past the 2 additional arguments */
2048                         argv += 2;
2049                         argc -= 2;
2050                 }
2051 #endif
2052         }
2053         /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
2054         if (!flagcount) {
2055                 get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
2056                 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
2057         }
2058         argv += optind;
2059
2060         if (!*argv) {
2061                 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2062                         identify_from_stdin(); /* EXIT */
2063                 bb_show_usage();
2064         }
2065
2066         do {
2067                 process_dev(*argv++);
2068         } while (*argv);
2069
2070         return EXIT_SUCCESS;
2071 }