source: MondoRescue/branches/2.2.5/mindi-busybox/miscutils/hdparm.c @ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 13 years ago

Update to busybox 1.7.2

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