blob: 60682231adf9d30d1acfac51e989f05cc172c61f [file] [log] [blame]
Eric Andersen3443bd72003-07-22 07:30:36 +00001/* vi: set sw=4 ts=4: */
2/*
3 * hdparm implementation for busybox
4 *
Glenn L McGrath5be6a202003-11-28 22:55:03 +00005 * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
Glenn L McGrath07085852003-10-09 07:28:22 +00006 * Hacked by Tito <farmatito@tiscali.it> for size optimization.
Eric Andersen3443bd72003-07-22 07:30:36 +00007 *
Mike Frysingerf284c762006-04-16 20:38:26 +00008 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen3443bd72003-07-22 07:30:36 +00009 *
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 */
Denys Vlasenko860d2bb2009-07-10 18:37:06 +020014#include "libbb.h"
15/* must be _after_ libbb.h: */
Eric Andersen3443bd72003-07-22 07:30:36 +000016#include <linux/hdreg.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +020017#include <sys/mount.h>
Eric Andersen3443bd72003-07-22 07:30:36 +000018
Eric Andersen3443bd72003-07-22 07:30:36 +000019/* device types */
20/* ------------ */
21#define NO_DEV 0xffff
22#define ATA_DEV 0x0000
23#define ATAPI_DEV 0x0001
24
25/* word definitions */
26/* ---------------- */
27#define GEN_CONFIG 0 /* general configuration */
28#define LCYLS 1 /* number of logical cylinders */
29#define CONFIG 2 /* specific configuration */
30#define LHEADS 3 /* number of logical heads */
31#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
32#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
33#define LSECTS 6 /* number of logical sectors/track */
34#define START_SERIAL 10 /* ASCII serial number */
35#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
36#define BUF_TYPE 20 /* buffer type (ATA-1) */
37#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
38#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
39#define START_FW_REV 23 /* ASCII firmware revision */
40#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000041#define START_MODEL 27 /* ASCII model number */
42#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000043#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +000044#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
45#define CAPAB_0 49 /* capabilities */
46#define CAPAB_1 50
47#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
48#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
49#define WHATS_VALID 53 /* what fields are valid */
50#define LCYLS_CUR 54 /* current logical cylinders */
51#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000052#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +000053#define CAPACITY_LSB 57 /* current capacity in sectors */
54#define CAPACITY_MSB 58
55#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
56#define LBA_SECTS_LSB 60 /* LBA: total number of user */
57#define LBA_SECTS_MSB 61 /* addressable sectors */
58#define SINGLE_DMA 62 /* singleword DMA modes */
59#define MULTI_DMA 63 /* multiword DMA modes */
60#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
61 /* multiword DMA xfer cycle time: */
62#define DMA_TIME_MIN 65 /* - minimum */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +000063#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
Eric Andersen3443bd72003-07-22 07:30:36 +000064 /* minimum PIO xfer cycle time: */
65#define PIO_NO_FLOW 67 /* - without flow control */
66#define PIO_FLOW 68 /* - with IORDY flow control */
67#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
68#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
69#define CDR_MAJOR 73 /* CD ROM: major version number */
70#define CDR_MINOR 74 /* CD ROM: minor version number */
71#define QUEUE_DEPTH 75 /* queue depth */
72#define MAJOR 80 /* major version number */
73#define MINOR 81 /* minor version number */
74#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
75#define CMDS_SUPP_1 83
76#define CMDS_SUPP_2 84
77#define CMDS_EN_0 85 /* command/feature set(s) enabled */
78#define CMDS_EN_1 86
79#define CMDS_EN_2 87
80#define ULTRA_DMA 88 /* ultra DMA modes */
81 /* time to complete security erase */
82#define ERASE_TIME 89 /* - ordinary */
83#define ENH_ERASE_TIME 90 /* - enhanced */
84#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +000085 in low byte, 0x40 in high byte. */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +000086#define PSWD_CODE 92 /* master password revision code */
Eric Andersen3443bd72003-07-22 07:30:36 +000087#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000088#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +000089#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
90#define LBA_MID 101 /* bits are used, but addr 103 */
91#define LBA_48_MSB 102 /* has been reserved for LBA in */
92#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000093#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +000094#define SECU_STATUS 128 /* security status */
95#define CFA_PWR_MODE 160 /* CFA power mode 1 */
96#define START_MEDIA 176 /* media serial number */
97#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
98#define START_MANUF 196 /* media manufacturer I.D. */
99#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
100#define INTEGRITY 255 /* integrity word */
101
102/* bit definitions within the words */
103/* -------------------------------- */
104
105/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
106#define VALID 0xc000
107#define VALID_VAL 0x4000
108/* many words are considered invalid if they are either all-0 or all-1 */
109#define NOVAL_0 0x0000
110#define NOVAL_1 0xffff
111
112/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000113#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000114#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
115#define MEDIA_REMOVABLE 0x0080
116#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
117#define INCOMPLETE 0x0004
118#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
119#define DRQ_RESPONSE_TIME 0x0060
120#define DRQ_3MS_VAL 0x0000
121#define DRQ_INTR_VAL 0x0020
122#define DRQ_50US_VAL 0x0040
123#define PKT_SIZE_SUPPORTED 0x0003
124#define PKT_SIZE_12_VAL 0x0000
125#define PKT_SIZE_16_VAL 0x0001
126#define EQPT_TYPE 0x1f00
127#define SHIFT_EQPT 8
128
129#define CDROM 0x0005
130
Eric Andersen3443bd72003-07-22 07:30:36 +0000131/* word 1: number of logical cylinders */
132#define LCYLS_MAX 0x3fff /* maximum allowable value */
133
Eric Andersenaff114c2004-04-14 17:51:38 +0000134/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000135 * (a) require SET FEATURES to spin-up
136 * (b) require spin-up to fully reply to IDENTIFY DEVICE
137 */
138#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
139#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000140#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000141#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
142
143/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
144#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
145#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
146
147/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000148#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000149#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
150#define IORDY_OFF 0x0400 /* 1=may be disabled */
151#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
152#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
153#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
154#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
155#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
156#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
157
158/* word 50: capabilities 1 */
159#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
160
161/* words 51 & 52: PIO & DMA cycle times */
162#define MODE 0xff00 /* the mode is in the MSBs */
163
164/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000165#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000166#define OK_W64_70 0x0002 /* see above for word descriptions */
167#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
168
169/*word 63,88: dma_mode, ultra_dma_mode*/
170#define MODE_MAX 7 /* bit definitions force udma <=7 (when
171 * udma >=8 comes out it'll have to be
172 * defined in a new dma_mode word!) */
173
174/* word 64: PIO transfer modes */
175#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
176#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
177
178/* word 75: queue_depth */
179#define DEPTH_BITS 0x001f /* bits used for queue depth */
180
181/* words 80-81: version numbers */
182/* NOVAL_0 or NOVAL_1 means device does not report version */
183
184/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000185#define MINOR_MAX 0x22
Eric Andersen3443bd72003-07-22 07:30:36 +0000186/* words 82-84: cmds/feats supported */
187#define CMDS_W82 0x77ff /* word 82: defined command locations*/
188#define CMDS_W83 0x3fff /* word 83: defined command locations*/
189#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000190#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000191#define NUM_CMD_FEAT_STR 48
192
Eric Andersen3443bd72003-07-22 07:30:36 +0000193/* words 85-87: cmds/feats enabled */
194/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000195 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000196 */
197
198/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000199#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000200
201/* word 92: master password revision */
202/* NOVAL_0 or NOVAL_1 means no support for master password revision */
203
204/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000205#define CBLID 0x2000 /* CBLID status */
206#define RST0 0x0001 /* 1=reset to device #0 */
207#define DEV_DET 0x0006 /* how device num determined */
208#define JUMPER_VAL 0x0002 /* device num determined by jumper */
209#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000210
211/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000212#define RM_STAT_BITS 0x0003
213#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000214
Eric Andersen3443bd72003-07-22 07:30:36 +0000215/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000216#define SECU_ENABLED 0x0002
217#define SECU_LEVEL 0x0010
218#define NUM_SECU_STR 6
Eric Andersen3443bd72003-07-22 07:30:36 +0000219
220/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000221#define VALID_W160 0x8000 /* 1=word valid */
222#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
223#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
224#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000225
226/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000227#define SIG 0x00ff /* signature location */
228#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000229
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000230#define TIMING_BUF_MB 1
231#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000232
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000233#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000234
Denis Vlasenko892536f2007-09-27 10:23:34 +0000235
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200236#define IS_GET 1
237#define IS_SET 2
238
239
Denis Vlasenko892536f2007-09-27 10:23:34 +0000240enum { fd = 3 };
241
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000242
243struct globals {
244 smallint get_identity, get_geom;
245 smallint do_flush;
246 smallint do_ctimings, do_timings;
247 smallint reread_partn;
248 smallint set_piomode, noisy_piomode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200249 smallint getset_readahead;
250 smallint getset_readonly;
251 smallint getset_unmask;
252 smallint getset_mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000253#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200254 smallint getset_dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000255#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200256 smallint getset_nowerr;
257 smallint getset_keep;
258 smallint getset_io32bit;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000259 int piomode;
260 unsigned long Xreadahead;
261 unsigned long readonly;
262 unsigned long unmask;
263 unsigned long mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000264#ifdef HDIO_SET_QDMA
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000265 unsigned long dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000266#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000267 unsigned long nowerr;
268 unsigned long keep;
269 unsigned long io32bit;
270#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
271 unsigned long dma;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200272 smallint getset_dma;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000273#endif
274#ifdef HDIO_DRIVE_CMD
275 smallint set_xfermode, get_xfermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200276 smallint getset_dkeep;
277 smallint getset_standby;
278 smallint getset_lookahead;
279 smallint getset_prefetch;
280 smallint getset_defects;
281 smallint getset_wcache;
282 smallint getset_doorlock;
283 smallint set_seagate;
284 smallint set_standbynow;
285 smallint set_sleepnow;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000286 smallint get_powermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200287 smallint getset_apmmode;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000288 int xfermode_requested;
289 unsigned long dkeep;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000290 unsigned long standby_requested; /* 0..255 */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000291 unsigned long lookahead;
292 unsigned long prefetch;
293 unsigned long defects;
294 unsigned long wcache;
295 unsigned long doorlock;
296 unsigned long apmmode;
297#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000298 IF_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200299 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint getset_busstate;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000300 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
301 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
302 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
303 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
304 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
305 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
306 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000307#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
308 unsigned long hwif_data;
309 unsigned long hwif_ctrl;
310 unsigned long hwif_irq;
311#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000312#ifdef DO_FLUSHCACHE
313 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
314#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000315};
316#define G (*(struct globals*)&bb_common_bufsiz1)
317struct BUG_G_too_big {
318 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
319};
320#define get_identity (G.get_identity )
321#define get_geom (G.get_geom )
322#define do_flush (G.do_flush )
323#define do_ctimings (G.do_ctimings )
324#define do_timings (G.do_timings )
325#define reread_partn (G.reread_partn )
326#define set_piomode (G.set_piomode )
327#define noisy_piomode (G.noisy_piomode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200328#define getset_readahead (G.getset_readahead )
329#define getset_readonly (G.getset_readonly )
330#define getset_unmask (G.getset_unmask )
331#define getset_mult (G.getset_mult )
332#define getset_dma_q (G.getset_dma_q )
333#define getset_nowerr (G.getset_nowerr )
334#define getset_keep (G.getset_keep )
335#define getset_io32bit (G.getset_io32bit )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000336#define piomode (G.piomode )
337#define Xreadahead (G.Xreadahead )
338#define readonly (G.readonly )
339#define unmask (G.unmask )
340#define mult (G.mult )
341#define dma_q (G.dma_q )
342#define nowerr (G.nowerr )
343#define keep (G.keep )
344#define io32bit (G.io32bit )
345#define dma (G.dma )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200346#define getset_dma (G.getset_dma )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000347#define set_xfermode (G.set_xfermode )
348#define get_xfermode (G.get_xfermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200349#define getset_dkeep (G.getset_dkeep )
350#define getset_standby (G.getset_standby )
351#define getset_lookahead (G.getset_lookahead )
352#define getset_prefetch (G.getset_prefetch )
353#define getset_defects (G.getset_defects )
354#define getset_wcache (G.getset_wcache )
355#define getset_doorlock (G.getset_doorlock )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000356#define set_seagate (G.set_seagate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000357#define set_standbynow (G.set_standbynow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000358#define set_sleepnow (G.set_sleepnow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000359#define get_powermode (G.get_powermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200360#define getset_apmmode (G.getset_apmmode )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000361#define xfermode_requested (G.xfermode_requested )
362#define dkeep (G.dkeep )
363#define standby_requested (G.standby_requested )
364#define lookahead (G.lookahead )
365#define prefetch (G.prefetch )
366#define defects (G.defects )
367#define wcache (G.wcache )
368#define doorlock (G.doorlock )
369#define apmmode (G.apmmode )
370#define get_IDentity (G.get_IDentity )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200371#define getset_busstate (G.getset_busstate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000372#define perform_reset (G.perform_reset )
373#define perform_tristate (G.perform_tristate )
374#define unregister_hwif (G.unregister_hwif )
375#define scan_hwif (G.scan_hwif )
376#define busstate (G.busstate )
377#define tristate (G.tristate )
378#define hwif (G.hwif )
379#define hwif_data (G.hwif_data )
380#define hwif_ctrl (G.hwif_ctrl )
381#define hwif_irq (G.hwif_irq )
382
383
Glenn L McGrath07085852003-10-09 07:28:22 +0000384/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000385#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000386static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000387{
388 if (!ioctl(fd, cmd, args))
389 return 0;
390 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000391 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000392}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000393#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000394#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000395static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000396{
397 if (!ioctl(fd, cmd, args))
398 return 0;
399 args[0] = alt;
400 return bb_ioctl_or_warn(fd, cmd, args);
401}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000402#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000403#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000404
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000405static void on_off(int value)
406{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000407 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000408}
Glenn L McGrath07085852003-10-09 07:28:22 +0000409
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000410static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000411{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000412 if (get_arg) {
Rob Landleyadde7982006-05-16 15:32:30 +0000413 printf(" setting %s to %ld", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000414 on_off(arg);
415 }
416}
417
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000418static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000419{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000420 printf(" %s\t= %2ld", str, argp);
421 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000422}
Eric Andersen416c2422003-12-12 00:08:57 +0000423
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000424#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000425static void print_ascii(const char *p, int length)
426{
427#if BB_BIG_ENDIAN
428#define LE_ONLY(x)
429 enum { ofs = 0 };
430#else
431#define LE_ONLY(x) x
432 /* every 16bit word is big-endian (i.e. inverted) */
433 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
434 int ofs = 1;
435#endif
436
437 length *= 2;
438 /* find first non-space & print it */
439 while (length && p[ofs] != ' ') {
440 p++;
441 LE_ONLY(ofs = -ofs;)
442 length--;
443 }
444 while (length && p[ofs]) {
445 bb_putchar(p[ofs]);
446 p++;
447 LE_ONLY(ofs = -ofs;)
448 length--;
449 }
450 bb_putchar('\n');
451#undef LE_ONLY
452}
Glenn L McGrath07085852003-10-09 07:28:22 +0000453
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000454static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000455{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000456 if (val[i]) {
457 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000458 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000459 }
460}
Glenn L McGrath07085852003-10-09 07:28:22 +0000461
Glenn L McGrath07085852003-10-09 07:28:22 +0000462static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
463{
Eric Andersen3443bd72003-07-22 07:30:36 +0000464 uint16_t ii;
465 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000466
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000467 for (ii = 0; ii <= MODE_MAX; ii++) {
468 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000469 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000470 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000471 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000472 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000473 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000474 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000475
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000476 mode_sup >>= 1;
477 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000478 }
479 return err_dma;
480}
Glenn L McGrath07085852003-10-09 07:28:22 +0000481
Denis Vlasenko91303402007-10-30 19:36:54 +0000482static const char pkt_str[] ALIGN1 =
483 "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
484 "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
485 "Printer" "\0" /* word 0, bits 12-8 = 02 */
486 "Processor" "\0" /* word 0, bits 12-8 = 03 */
487 "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
488 "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
489 "Scanner" "\0" /* word 0, bits 12-8 = 06 */
490 "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
491 "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
492 "Communications device" "\0" /* word 0, bits 12-8 = 09 */
493 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
494 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
495 "Array controller" "\0" /* word 0, bits 12-8 = 0c */
496 "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
497 "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
498 "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
499;
500
501static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
502 "reserved" "\0" /* bit 0 */
503 "hard sectored" "\0" /* bit 1 */
504 "soft sectored" "\0" /* bit 2 */
505 "not MFM encoded " "\0" /* bit 3 */
506 "head switch time > 15us" "\0" /* bit 4 */
507 "spindle motor control option" "\0" /* bit 5 */
508 "fixed drive" "\0" /* bit 6 */
509 "removable drive" "\0" /* bit 7 */
510 "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
511 "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
512 "disk xfer rate > 5Mbs" "\0" /* bit 10 */
513 "rotational speed tol." "\0" /* bit 11 */
514 "data strobe offset option" "\0" /* bit 12 */
515 "track offset option" "\0" /* bit 13 */
516 "format speed tolerance gap reqd" "\0" /* bit 14 */
517 "ATAPI" /* bit 14 */
518;
519
520static const char minor_str[] ALIGN1 =
521 /* word 81 value: */
522 "Unspecified" "\0" /* 0x0000 */
523 "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
524 "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
525 "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
526 "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
527 "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
528 "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
529 "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
530 "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
531 "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
532 "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
533 "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
534 "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
535 "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
536 "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
537 "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
538 "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
539 "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
540 "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
541 "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
542 "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
543 "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
544 "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
545 "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
546 "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
547 "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
548 "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
549 "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
550 "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
551 "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
552 "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
553 "reserved" "\0" /* 0x001f */
554 "reserved" "\0" /* 0x0020 */
555 "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
556 "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
557 "reserved" /* 0x0023-0xfffe */
558;
559static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
560 /* word 81 value: */
561 0, /* 0x0000 WARNING: actual_ver[] array */
562 1, /* 0x0001 WARNING: corresponds */
563 1, /* 0x0002 WARNING: *exactly* */
564 1, /* 0x0003 WARNING: to the ATA/ */
565 2, /* 0x0004 WARNING: ATAPI version */
566 2, /* 0x0005 WARNING: listed in */
567 3, /* 0x0006 WARNING: the */
568 2, /* 0x0007 WARNING: minor_str */
569 3, /* 0x0008 WARNING: array */
570 2, /* 0x0009 WARNING: above. */
571 3, /* 0x000a WARNING: */
572 3, /* 0x000b WARNING: If you change */
573 3, /* 0x000c WARNING: that one, */
574 4, /* 0x000d WARNING: change this one */
575 4, /* 0x000e WARNING: too!!! */
576 4, /* 0x000f */
577 4, /* 0x0010 */
578 4, /* 0x0011 */
579 4, /* 0x0012 */
580 5, /* 0x0013 */
581 4, /* 0x0014 */
582 5, /* 0x0015 */
583 5, /* 0x0016 */
584 4, /* 0x0017 */
585 6, /* 0x0018 */
586 6, /* 0x0019 */
587 7, /* 0x001a */
588 6, /* 0x001b */
589 6, /* 0x001c */
590 7, /* 0x001d */
591 7, /* 0x001e */
592 0, /* 0x001f */
593 0, /* 0x0020 */
594 7, /* 0x0021 */
595 6, /* 0x0022 */
596 0 /* 0x0023-0xfffe */
597};
598
599static const char cmd_feat_str[] ALIGN1 =
600 "" "\0" /* word 82 bit 15: obsolete */
601 "NOP cmd" "\0" /* word 82 bit 14 */
602 "READ BUFFER cmd" "\0" /* word 82 bit 13 */
603 "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
604 "" "\0" /* word 82 bit 11: obsolete */
605 "Host Protected Area feature set" "\0" /* word 82 bit 10 */
606 "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
607 "SERVICE interrupt" "\0" /* word 82 bit 8 */
608 "Release interrupt" "\0" /* word 82 bit 7 */
609 "Look-ahead" "\0" /* word 82 bit 6 */
610 "Write cache" "\0" /* word 82 bit 5 */
611 "PACKET command feature set" "\0" /* word 82 bit 4 */
612 "Power Management feature set" "\0" /* word 82 bit 3 */
613 "Removable Media feature set" "\0" /* word 82 bit 2 */
614 "Security Mode feature set" "\0" /* word 82 bit 1 */
615 "SMART feature set" "\0" /* word 82 bit 0 */
616 /* -------------- */
617 "" "\0" /* word 83 bit 15: !valid bit */
618 "" "\0" /* word 83 bit 14: valid bit */
619 "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
620 "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
621 "Device Configuration Overlay feature set " "\0"
622 "48-bit Address feature set " "\0" /* word 83 bit 10 */
623 "" "\0"
624 "SET MAX security extension" "\0" /* word 83 bit 8 */
625 "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
626 "SET FEATURES subcommand required to spinup after power up" "\0"
627 "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
628 "Removable Media Status Notification feature set" "\0"
629 "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
630 "CFA feature set" "\0" /* word 83 bit 2 */
631 "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
632 "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
633 /* -------------- */
634 "" "\0" /* word 84 bit 15: !valid bit */
635 "" "\0" /* word 84 bit 14: valid bit */
636 "" "\0" /* word 84 bit 13: reserved */
637 "" "\0" /* word 84 bit 12: reserved */
638 "" "\0" /* word 84 bit 11: reserved */
639 "" "\0" /* word 84 bit 10: reserved */
640 "" "\0" /* word 84 bit 9: reserved */
641 "" "\0" /* word 84 bit 8: reserved */
642 "" "\0" /* word 84 bit 7: reserved */
643 "" "\0" /* word 84 bit 6: reserved */
644 "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
645 "" "\0" /* word 84 bit 4: reserved */
646 "Media Card Pass Through Command feature set " "\0"
647 "Media serial number " "\0" /* word 84 bit 2 */
648 "SMART self-test " "\0" /* word 84 bit 1 */
649 "SMART error logging " /* word 84 bit 0 */
650;
651
652static const char secu_str[] ALIGN1 =
653 "supported" "\0" /* word 128, bit 0 */
654 "enabled" "\0" /* word 128, bit 1 */
655 "locked" "\0" /* word 128, bit 2 */
656 "frozen" "\0" /* word 128, bit 3 */
657 "expired: security count" "\0" /* word 128, bit 4 */
658 "supported: enhanced erase" /* word 128, bit 5 */
659;
660
661// Parse 512 byte disk identification block and print much crap.
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000662static void identify(uint16_t *val) NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000663static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000664{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000665 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000666 uint16_t like_std = 1, std = 0, min_std = 0xffff;
667 uint16_t dev = NO_DEV, eqpt = NO_DEV;
668 uint8_t have_mode = 0, err_dma = 0;
669 uint8_t chksum = 0;
670 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000671 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000672 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000673#if BB_BIG_ENDIAN
674 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000675
Denis Vlasenko4daad902007-09-27 10:20:47 +0000676 // Adjust for endianness
677 swab(val, buf, sizeof(buf));
678 val = buf;
679#endif
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200680 /* check if we recognize the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000681 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000682 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000683 dev = ATA_DEV;
684 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000685 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000686 dev = ATA_DEV;
687 like_std = 4;
688 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000689 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000690 dev = ATAPI_DEV;
691 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000692 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +0000693 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000694 } else
Denis Vlasenko91303402007-10-30 19:36:54 +0000695 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000696 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000697
Rob Landleyadde7982006-05-16 15:32:30 +0000698 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000699 /* Info from the specific configuration word says whether or not the
700 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000701 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000702 * standards. Since the values allowed for this word are extremely
703 * specific, it should be safe to check it now, even though we don't
704 * know yet what standard this device is using.
705 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000706 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
707 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
708 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000709 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000710 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Rob Landleyadde7982006-05-16 15:32:30 +0000711 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000712 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Rob Landleyadde7982006-05-16 15:32:30 +0000713 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000714 }
715
716 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000717 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
718 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
719 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
720 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
721 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000722
723 /* major & minor standards version number (Note: these words were not
724 * defined until ATA-3 & the CDROM std uses different words.) */
725 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000726 if (eqpt != CDROM) {
727 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000728 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000729 std = actual_ver[val[MINOR]];
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000730 if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
Glenn L McGrath07085852003-10-09 07:28:22 +0000731
Eric Andersen3443bd72003-07-22 07:30:36 +0000732 }
733 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000734 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000735 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000736 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000737 printf("\n\tSupported: ");
738 jj = val[MAJOR] << 1;
739 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000740 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
741 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000742 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000743 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000744 like_std = ii;
745 kk = like_std >4 ? like_std-4: 0;
746 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000747 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000748 }
749 jj <<= 1;
750 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000751 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000752 }
753 /* Figure out what standard the device is using if it hasn't told
754 * us. If we know the std, check if the device is using any of
755 * the words from the next level up. It happens.
756 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000757 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000758
Rob Landleya3e4f382006-04-29 16:06:31 +0000759 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000760 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
761 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
762 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000763 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
764 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000765 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000766 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000767 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000768 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
769 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
770 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
771 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000772 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000773 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000774 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
775 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
776 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
777 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
778 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000779 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
780 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000781 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000782 } else if (((std == 2) || (!std && (like_std < 3)))
783 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
784 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000785 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000786 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000787 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
788 (val[WHATS_VALID] & OK_W64_70)) )
789 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000790 like_std = 2;
791 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000792
Rob Landleya3e4f382006-04-29 16:06:31 +0000793 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000794 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000795 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000796 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000797 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000798 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000799 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000800 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000801 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000802 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000803 kk = 1;
804 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
805 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000806 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000807 kk = 1;
808 printf("\n\tSupported: CD-ROM ATAPI");
809 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000810 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000811 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000812 jj >>= 1;
813 }
814 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000815 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000816 /* the cdrom stuff is more like ATA-2 than anything else, so: */
817 like_std = 2;
818 }
819
Rob Landleya3e4f382006-04-29 16:06:31 +0000820 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000821 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000822
823 printf("Configuration:\n");
824 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000825 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000826 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000827 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000828 if (jj & 0x0001)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000829 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +0000830 jj >>=1;
831 }
832 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000833 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000834 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
835 strng = "3ms";
836 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
837 strng = "<=10ms with INTRQ";
838 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
839 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000840 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000841 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000842 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
843
844 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
845 strng = "12 bytes";
846 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
847 strng = "16 bytes";
848 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000849 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000850 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000851 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000852 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000853 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200854 mm = 0;
855 bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000856 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000857 printf("\tCHS addressing not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000858 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000859 jj = val[WHATS_VALID] & OK_W54_58;
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200860 printf("\tLogical\t\tmax\tcurrent\n"
861 "\tcylinders\t%u\t%u\n"
862 "\theads\t\t%u\t%u\n"
863 "\tsectors/track\t%u\t%u\n"
864 "\t--\n",
865 val[LCYLS],
866 jj ? val[LCYLS_CUR] : 0,
867 val[LHEADS],
868 jj ? val[LHEADS_CUR] : 0,
869 val[LSECTS],
870 jj ? val[LSECTS_CUR] : 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000871
Rob Landleyadde7982006-05-16 15:32:30 +0000872 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200873 printf("\tbytes/track: %u\tbytes/sector: %u\n",
874 val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000875
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000876 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000877 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000878 if (like_std < 3) {
879 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000880 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
881 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000882 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +0000883 mm = oo;
884 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000885 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +0000886 }
Eric Andersen3443bd72003-07-22 07:30:36 +0000887 }
888 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000889 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000890 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
891 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
892 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000893 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
894 (uint64_t)val[LBA_48_MSB] << 32 |
895 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000896 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000897 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +0000898 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000899
900 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +0000901 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000902 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
903 bbbig = (bbbig << 9) / 1000000;
904 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +0000905
Rob Landleyadde7982006-05-16 15:32:30 +0000906 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +0000907 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000908 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000909 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000910 }
911
912 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +0000913 printf("Capabilities:\n\t");
914
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000915 if (dev == ATAPI_DEV) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200916 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP))
917 printf("Cmd queuing, ");
918 if (val[CAPAB_0] & OVLP_SUP)
919 printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +0000920 }
Rob Landleyadde7982006-05-16 15:32:30 +0000921 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +0000922
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000923 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000924 printf("IORDY%s(can%s be disabled)\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200925 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
926 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000927 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000928 printf("no IORDY\n");
929
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000930 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000931 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200932 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
933 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000934 }
Rob Landleyadde7982006-05-16 15:32:30 +0000935
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000936 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000937 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +0000938 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000939 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000940 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000941 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000942 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000943 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +0000944 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000945
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000946 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000947 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000948 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000949 else {
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200950 printf("\tStandby timer values: spec'd by %s",
951 (val[CAPAB_0] & STD_STBY) ? "standard" : "vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +0000952 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200953 printf(", %s device specific minimum\n",
954 (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +0000955 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000956 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000957 }
958 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000959 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Eric Andersen3443bd72003-07-22 07:30:36 +0000960 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000961 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000962 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +0000963 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
964 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
965 else
966 printf("?\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000967 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000968 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000969 /* We print out elsewhere whether the APM feature is enabled or
970 not. If it's not enabled, let's not repeat the info; just print
971 nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +0000972 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000973 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000974 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +0000975 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +0000976 }
977 else
Eric Andersen3443bd72003-07-22 07:30:36 +0000978 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000979 }
Rob Landleyadde7982006-05-16 15:32:30 +0000980 if (like_std > 5 && val[ACOUSTIC]) {
981 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200982 (val[ACOUSTIC] >> 8) & 0x00ff,
983 val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +0000984 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000985 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000986 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +0000987 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
988 printf("\tATA sw reset required\n");
Glenn L McGrath07085852003-10-09 07:28:22 +0000989
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000990 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000991 printf("\tOverlap support:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200992 if (val[PKT_REL])
993 printf(" %uus to release bus.", val[PKT_REL]);
994 if (val[SVC_NBSY])
995 printf(" %uus to clear BSY after SERVICE cmd.",
996 val[SVC_NBSY]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000997 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000998 }
999 }
1000
1001 /* DMA stuff. Check that only one DMA mode is selected. */
1002 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001003 if (!(val[CAPAB_0] & DMA_SUP))
Eric Andersen3443bd72003-07-22 07:30:36 +00001004 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001005 else {
Rob Landleyadde7982006-05-16 15:32:30 +00001006 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001007 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001008 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001009 jj = val[SINGLE_DMA];
1010 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001011 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001012 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001013 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001014 jj = val[MULTI_DMA];
1015 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001016 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001017 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001018 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001019 jj = val[ULTRA_DMA];
1020 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001021 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001022 }
Rob Landleyadde7982006-05-16 15:32:30 +00001023 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001024 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001025
Rob Landleyadde7982006-05-16 15:32:30 +00001026 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
1027 printf("\t\tInterleaved DMA support\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001028
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001029 if ((val[WHATS_VALID] & OK_W64_70)
1030 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1031 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001032 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001033 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]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001035 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001036 }
1037 }
1038
1039 /* Programmed IO stuff */
1040 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001041 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +00001042 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001043 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001044 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001045 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001046 if (jj & 0x0001) printf("pio%d ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +00001047 jj >>=1;
1048 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001049 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001050 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001051 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001052 printf("pio%d ", ii);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001053 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001054 } else
Denis Vlasenko91303402007-10-30 19:36:54 +00001055 puts("unknown");
Glenn L McGrath07085852003-10-09 07:28:22 +00001056
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001057 if (val[WHATS_VALID] & OK_W64_70) {
1058 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001059 printf("\t\tCycle time:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001060 if (val[PIO_NO_FLOW])
1061 printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1062 if (val[PIO_FLOW])
1063 printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001064 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001065 }
1066 }
1067
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001068 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001069 printf("Commands/features:\n"
1070 "\tEnabled\tSupported:\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001071 jj = val[CMDS_SUPP_0];
1072 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001073 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001074 const char *feat_str = nth_string(cmd_feat_str, ii);
Denis Vlasenko91303402007-10-30 19:36:54 +00001075 if ((jj & 0x8000) && (*feat_str != '\0')) {
1076 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
Eric Andersen3443bd72003-07-22 07:30:36 +00001077 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001078 jj <<= 1;
1079 kk <<= 1;
1080 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001081 jj = val[CMDS_SUPP_0+1+(ii/16)];
1082 kk = val[CMDS_EN_0+1+(ii/16)];
1083 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001084 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001085 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +00001086 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001087 }
1088 }
1089 }
Rob Landleyadde7982006-05-16 15:32:30 +00001090 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001091 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001092 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
Glenn L McGrath07085852003-10-09 07:28:22 +00001093
Eric Andersen3443bd72003-07-22 07:30:36 +00001094 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001095 if ((eqpt != CDROM) && (like_std > 3)
1096 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1097 ) {
Rob Landleyade7f952006-05-25 18:53:06 +00001098 printf("Security:\n");
Rob Landleyadde7982006-05-16 15:32:30 +00001099 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001100 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001101 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001102 if (jj) {
1103 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001104 printf("\t%s\t%s\n",
1105 (!(jj & 0x0001)) ? "not" : "",
1106 nth_string(secu_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +00001107 jj >>=1;
1108 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001109 if (val[SECU_STATUS] & SECU_ENABLED) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001110 printf("\tSecurity level %s\n",
1111 (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001112 }
1113 }
1114 jj = val[ERASE_TIME] & ERASE_BITS;
1115 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001116 if (jj || kk) {
Denis Vlasenko7d60fc12008-06-05 06:51:06 +00001117 bb_putchar('\t');
Rob Landleyade7f952006-05-25 18:53:06 +00001118 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1119 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001120 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001121 }
1122 }
1123
1124 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001125 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001126 if ((jj & VALID) == VALID_VAL) {
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001127 oo = (jj & RST0);
1128 if (!oo)
Rob Landleyadde7982006-05-16 15:32:30 +00001129 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001130 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001131 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001132 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001133 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001134 else
Rob Landleyadde7982006-05-16 15:32:30 +00001135 strng = "";
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001136 printf("HW reset results:\n"
1137 "\tCBLID- %s Vih\n"
1138 "\tDevice num = %i%s\n",
1139 (val[HWRST_RSLT] & CBLID) ? "above" : "below",
1140 !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001141 }
1142
1143 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001144 if ((like_std > 4) && (eqpt != CDROM)) {
1145 if (val[CFA_PWR_MODE] & VALID_W160) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001146 printf("CFA power mode 1:\n"
1147 "\t%s%s\n",
1148 (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
1149 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001150 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001151 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001152 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001153 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001154 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001155 }
1156 }
1157
Rob Landleyadde7982006-05-16 15:32:30 +00001158 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001159}
1160#endif
1161
Eric Andersen3443bd72003-07-22 07:30:36 +00001162// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1163// then the HDIO_GET_IDENTITY only returned 142 bytes.
1164// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1165// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1166// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1167// (which they should, but they should just return -EINVAL).
1168//
1169// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1170// On a really old system, it will not, and we will be confused.
1171// Too bad, really.
1172
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001173#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko91303402007-10-30 19:36:54 +00001174static const char cfg_str[] ALIGN1 =
Denis Vlasenko6b404432008-01-07 16:13:14 +00001175 """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
1176 "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
1177 "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1178 "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
Denis Vlasenko91303402007-10-30 19:36:54 +00001179;
Eric Andersen3443bd72003-07-22 07:30:36 +00001180
Denis Vlasenko91303402007-10-30 19:36:54 +00001181static const char BuffType[] ALIGN1 =
1182 "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
1183;
Eric Andersen3443bd72003-07-22 07:30:36 +00001184
Rob Landleya3e4f382006-04-29 16:06:31 +00001185static void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001186{
1187 int i;
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00001188 const unsigned short *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001189
Glenn L McGrath07085852003-10-09 07:28:22 +00001190 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1191 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001192 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001193 if (id->config & (1<<i))
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001194 printf(" %s", nth_string(cfg_str, i));
Rob Landleyadde7982006-05-16 15:32:30 +00001195 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001196 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001197 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
1198 id->cyls, id->heads, id->sectors, id->track_bytes,
1199 id->sector_bytes, id->ecc_bytes,
1200 id->buf_type,
1201 nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
1202 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001203 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001204 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001205 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001206 printf("?%u?", id->multsect);
1207 else if (id->multsect)
1208 printf("%u", id->multsect);
1209 else
1210 printf("off");
1211 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001212 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001213
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001214 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001215 printf(" (maybe):");
1216
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001217 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001218 id->cur_sectors,
1219 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001220 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1221 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001222 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001223
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001224 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001225 printf(", LBAsects=%u", id->lba_capacity);
1226
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001227 printf("\n IORDY=%s",
1228 (id->capability & 8)
1229 ? ((id->capability & 4) ? "on/off" : "yes")
1230 : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001231
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001232 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001233 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001234
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001235 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001236 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1237
1238 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001239 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001240 printf("pio0 ");
1241 if (id->tPIO >= 1) printf("pio1 ");
1242 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001243 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001244 if (id->field_valid & 2) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001245 static const masks_labels_t pio_modes = {
1246 .masks = { 1, 2, ~3 },
1247 .labels = "pio3 \0""pio4 \0""pio? \0",
1248 };
1249 print_flags(&pio_modes, id->eide_pio_modes);
Rob Landleyade7f952006-05-25 18:53:06 +00001250 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001251 if (id->capability & 1) {
1252 if (id->dma_1word | id->dma_mword) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001253 static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
Rob Landleyade7f952006-05-25 18:53:06 +00001254 printf("\n DMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001255 print_flags_separated(dma_wmode_masks,
1256 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
1257 id->dma_1word, NULL);
1258 print_flags_separated(dma_wmode_masks,
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001259 "*\0""mdma0 \0""*\0""mdma1 \0""*\0""mdma2 \0""*\0""mdma? \0",
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001260 id->dma_mword, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001261 }
1262 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001263 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001264 static const masks_labels_t ultra_modes1 = {
1265 .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
1266 .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
1267 };
Denis Vlasenko7049ff82008-06-25 09:53:17 +00001268
Rob Landleyade7f952006-05-25 18:53:06 +00001269 printf("\n UDMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001270 print_flags(&ultra_modes1, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001271#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001272 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001273#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001274 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001275#endif /* __NEW_HD_DRIVE_ID */
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001276 static const masks_labels_t ultra_modes2 = {
1277 .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
1278 0x2000, 0x0020, 0x4000, 0x0040,
1279 0x8000, 0x0080 },
1280 .labels = "*\0""udma3 \0""*\0""udma4 \0"
1281 "*\0""udma5 \0""*\0""udma6 \0"
1282 "*\0""udma7 \0"
1283 };
1284 print_flags(&ultra_modes2, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001285 }
1286 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001287 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001288 if (id_regs[83] & 8) {
1289 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001290 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001291 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001292 printf(": unknown setting");
1293 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001294 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001295 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001296 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001297 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001298#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001299 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1300 || (id->major_rev_num && id->minor_rev_num <= 31)
1301 ) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001302 printf("\n Drive conforms to: %s: ",
1303 (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
1304 if (id->major_rev_num != 0x0000 /* NOVAL_0 */
1305 && id->major_rev_num != 0xFFFF /* NOVAL_1 */
1306 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001307 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001308 if (id->major_rev_num & (1<<i))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001309 printf(" ATA/ATAPI-%u", i);
Rob Landleyadde7982006-05-16 15:32:30 +00001310 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001311 }
1312 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001313#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001314 printf("\n\n * current active mode\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001315}
1316#endif
1317
Denis Vlasenko892536f2007-09-27 10:23:34 +00001318static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001319{
Rob Landleya3e4f382006-04-29 16:06:31 +00001320 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001321 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001322#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001323 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001324 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1325 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1326 bb_perror_msg("HDIO_DRIVE_CMD");
1327 else
1328 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1329 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001330#endif
1331}
1332
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001333static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001334{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001335 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001336}
1337
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001338static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001339{
Rob Landleyadde7982006-05-16 15:32:30 +00001340 int i;
1341
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001342 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001343 /* access all sectors of buf to ensure the read fully completed */
1344 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1345 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001346}
1347
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001348static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001349{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001350 union {
1351 unsigned long long blksize64;
1352 unsigned blksize32;
1353 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001354
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001355 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1356 u.blksize64 /= (1024 * 1024);
1357 } else {
1358 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1359 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001360 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001361 if (u.blksize64 > UINT_MAX)
1362 return UINT_MAX;
1363 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001364}
Eric Andersen50af12d2003-08-06 08:47:59 +00001365
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001366static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001367{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001368 unsigned sec = elapsed_us / 1000000;
1369 unsigned hs = (elapsed_us % 1000000) / 10000;
1370
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001371 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001372 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001373 /* "| 1" prevents div-by-0 */
1374 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001375 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001376 // = kb / elapsed_sec
1377 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001378}
1379
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001380static void do_time(int cache /*,int fd*/)
1381/* cache=1: time cache: repeatedly read N MB at offset 0
1382 * cache=0: time device: linear read, starting at offset 0
1383 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001384{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001385 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001386 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001387 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001388 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001389 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001390
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001391 if (mlock(buf, TIMING_BUF_BYTES))
1392 bb_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001393
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001394 /* Clear out the device request queues & give them time to complete.
1395 * NB: *small* delay. User is expected to have a clue and to not run
1396 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001397 sync();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001398 sleep(1);
1399 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001400 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001401 read_big_block(buf);
1402 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001403 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001404 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001405 }
1406 fflush(stdout);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001407
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001408 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001409 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001410 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001411 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001412 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001413 max_iterations = UINT_MAX;
1414 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001415 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001416 /* Don't want to read past the end! */
1417 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1418 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001419 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001420 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001421 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001422 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001423 read_big_block(buf);
1424 elapsed = (unsigned)monotonic_us() - start;
1425 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001426 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001427 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001428 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1429 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001430 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001431 * from elapsed */
1432 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001433 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001434 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001435 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001436 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001437 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001438 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001439 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001440 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001441 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001442 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001443 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001444 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001445}
1446
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001447#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001448static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001449{
Rob Landleyadde7982006-05-16 15:32:30 +00001450 if (value == BUSSTATE_ON)
1451 on_off(1);
1452 else if (value == BUSSTATE_OFF)
1453 on_off(0);
1454 else if (value == BUSSTATE_TRISTATE)
1455 printf(" (tristate)\n");
1456 else
1457 printf(" (unknown: %d)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001458}
1459#endif
1460
1461#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001462static void interpret_standby(uint8_t standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001463{
Rob Landley403777f2006-08-03 20:22:37 +00001464 printf(" (");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001465 if (standby == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001466 printf("off");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001467 } else if (standby <= 240 || standby == 252 || standby == 255) {
1468 /* standby is in 5 sec units */
Denys Vlasenko2b132e52009-05-20 23:21:42 +02001469 unsigned t = standby * 5;
1470 printf("%u minutes %u seconds", t / 60, t % 60);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001471 } else if (standby <= 251) {
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001472 unsigned t = (standby - 240); /* t is in 30 min units */;
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001473 printf("%u.%c hours", t / 2, (t & 1) ? '5' : '0');
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001474 }
1475 if (standby == 253)
1476 printf("vendor-specific");
1477 if (standby == 254)
1478 printf("reserved");
Eric Andersen3443bd72003-07-22 07:30:36 +00001479 printf(")\n");
1480}
1481
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001482static const uint8_t xfermode_val[] ALIGN1 = {
1483 8, 9, 10, 11, 12, 13, 14, 15,
1484 16, 17, 18, 19, 20, 21, 22, 23,
1485 32, 33, 34, 35, 36, 37, 38, 39,
1486 64, 65, 66, 67, 68, 69, 70, 71
1487};
1488/* NB: we save size by _not_ storing terninating NUL! */
1489static const char xfermode_name[][5] ALIGN1 = {
1490 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1491 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1492 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1493 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001494};
1495
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001496static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001497{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001498 int val;
1499 unsigned i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001500
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001501 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1502 if (!strncmp(name, xfermode_name[i], 5))
1503 if (strlen(name) <= 5)
1504 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001505 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001506 /* Negative numbers are invalid and are caught later */
1507 val = bb_strtoi(name, NULL, 10);
1508 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001509 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001510 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001511}
1512
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001513static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001514{
1515 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001516 if (xfermode == 0)
1517 printf("default PIO mode");
1518 else if (xfermode == 1)
1519 printf("default PIO mode, disable IORDY");
1520 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001521 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001522 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001523 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001524 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001525 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001526 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001527 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001528 else
Denis Vlasenko91303402007-10-30 19:36:54 +00001529 printf("unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +00001530 printf(")\n");
1531}
1532#endif /* HDIO_DRIVE_CMD */
1533
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001534static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001535{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001536 if (flag)
Rob Landleyadde7982006-05-16 15:32:30 +00001537 printf(" setting %s to %ld\n", s, value);
1538}
1539
Rob Landleya3e4f382006-04-29 16:06:31 +00001540static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001541{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001542 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001543 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001544#ifndef HDIO_DRIVE_CMD
1545 int force_operation = 0;
1546#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001547 /* Please restore args[n] to these values after each ioctl
1548 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001549 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001550 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001551
Denis Vlasenko892536f2007-09-27 10:23:34 +00001552 /*fd = xopen(devname, O_RDONLY | O_NONBLOCK);*/
1553 xmove_fd(xopen(devname, O_RDONLY | O_NONBLOCK), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001554 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001555
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001556 if (getset_readahead == IS_SET) {
1557 print_flag(getset_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001558 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001559 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001560#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1561 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001562 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001563 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001564 }
1565#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001566#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001567 if (scan_hwif == IS_SET) {
Rob Landley20deab02006-05-07 23:34:15 +00001568 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001569 args[0] = hwif_data;
1570 args[1] = hwif_ctrl;
1571 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001572 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001573 args[0] = WIN_SETFEATURES;
1574 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001575 }
1576#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001577 if (set_piomode) {
1578 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001579 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001580 if (piomode == 255)
Glenn L McGrath07085852003-10-09 07:28:22 +00001581 printf("auto-tune PIO mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001582 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001583 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001584 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001585 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001586 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001587 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001588 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001589 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001590 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001591 if (getset_io32bit == IS_SET) {
1592 print_flag(getset_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001593 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001594 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001595 if (getset_mult == IS_SET) {
1596 print_flag(getset_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001597#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001598 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001599#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001600 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001601#endif
1602 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001603 if (getset_readonly == IS_SET) {
1604 print_flag_on_off(getset_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001605 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001606 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001607 if (getset_unmask == IS_SET) {
1608 print_flag_on_off(getset_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001609 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001610 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001611#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001612 if (getset_dma == IS_SET) {
1613 print_flag_on_off(getset_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001614 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001615 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001616#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001617#ifdef HDIO_SET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001618 if (getset_dma_q == IS_SET) {
1619 print_flag_on_off(getset_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001620 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001621 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001622#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001623 if (getset_nowerr == IS_SET) {
1624 print_flag_on_off(getset_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001625 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001626 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001627 if (getset_keep == IS_SET) {
1628 print_flag_on_off(getset_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001629 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001630 }
1631#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001632 if (getset_doorlock == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001633 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001634 args[2] = 0;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001635 print_flag_on_off(getset_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001636 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001637 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001638 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001639 if (getset_dkeep == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001640 /* lock/unlock the drive's "feature" settings */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001641 print_flag_on_off(getset_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001642 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001643 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001644 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001645 if (getset_defects == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001646 args[2] = defects ? 0x04 : 0x84;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001647 print_flag(getset_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001648 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001649 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001650 if (getset_prefetch == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001651 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001652 args[2] = 0xab;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001653 print_flag(getset_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001654 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001655 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001656 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001657 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001658 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001659 args[2] = 3;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001660 print_flag(1, "xfermode", xfermode_requested);
1661 interpret_xfermode(xfermode_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001662 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001663 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001664 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001665 if (getset_lookahead == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001666 args[2] = lookahead ? 0xaa : 0x55;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001667 print_flag_on_off(getset_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001668 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001669 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001670 if (getset_apmmode == IS_SET) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001671 /* feature register */
1672 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */;
Rob Landleyadde7982006-05-16 15:32:30 +00001673 args[1] = apmmode; /* sector count register 1-255 */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001674 printf(" setting APM level to %s 0x%02lX (%ld)\n",
1675 (apmmode == 255) ? "disabled" : "",
1676 apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001677 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001678 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001679 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001680 if (getset_wcache == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001681#ifdef DO_FLUSHCACHE
1682#ifndef WIN_FLUSHCACHE
1683#define WIN_FLUSHCACHE 0xe7
1684#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001685#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001686 args[2] = wcache ? 0x02 : 0x82;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001687 print_flag_on_off(getset_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001688#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001689 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001690 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001691#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001692 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001693#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001694 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001695 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001696#endif /* DO_FLUSHCACHE */
1697 }
Rob Landley39cf6452006-05-05 16:52:28 +00001698
1699 /* In code below, we do not preserve args[0], but the rest
1700 is preserved, including args[2] */
1701 args[2] = 0;
1702
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001703 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001704#ifndef WIN_STANDBYNOW1
1705#define WIN_STANDBYNOW1 0xE0
1706#endif
1707#ifndef WIN_STANDBYNOW2
1708#define WIN_STANDBYNOW2 0x94
1709#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001710 printf(" issuing standby command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001711 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001712 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001713 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001714 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001715#ifndef WIN_SLEEPNOW1
1716#define WIN_SLEEPNOW1 0xE6
1717#endif
1718#ifndef WIN_SLEEPNOW2
1719#define WIN_SLEEPNOW2 0x99
1720#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001721 printf(" issuing sleep command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001722 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001723 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001724 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001725 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001726 args[0] = 0xfb;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001727 printf(" disabling Seagate auto powersaving mode\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001728 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001729 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001730 if (getset_standby == IS_SET) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001731 args[0] = WIN_SETIDLE1;
1732 args[1] = standby_requested;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001733 print_flag(1, "standby", standby_requested);
1734 interpret_standby(standby_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001735 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001736 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001737 }
1738#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001739 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001740 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001741 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001742 if (-1 == read(fd, buf, sizeof(buf)))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001743 bb_perror_msg("read of 512 bytes failed");
Eric Andersen3443bd72003-07-22 07:30:36 +00001744 }
1745#endif /* HDIO_DRIVE_CMD */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001746 if (getset_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001747 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001748 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001749 /* To be coherent with ioctl_or_warn. */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001750 if (getset_mult && ENABLE_IOCTL_HEX2STR_ERROR)
Eric Andersen06d4ec22004-03-19 10:53:52 +00001751 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001752 else
1753 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001754 } else if (getset_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001755 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001756 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001757 }
1758 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001759 if (getset_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001760 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001761 printf(" IO_support\t=%3ld (", parm);
1762 if (parm == 0)
1763 printf("default 16-bit)\n");
1764 else if (parm == 2)
1765 printf("16-bit)\n");
1766 else if (parm == 1)
1767 printf("32-bit)\n");
1768 else if (parm == 3)
1769 printf("32-bit w/sync)\n");
1770 else if (parm == 8)
1771 printf("Request-Queue-Bypass)\n");
1772 else
1773 printf("\?\?\?)\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001774 }
1775 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001776 if (getset_unmask) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001777 if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001778 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001779 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001780#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001781 if (getset_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001782 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001783 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001784 if (parm == 8)
1785 printf(" (DMA-Assisted-PIO)\n");
1786 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001787 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001788 }
1789 }
1790#endif
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001791#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001792 if (getset_dma_q) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001793 if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001794 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001795 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001796#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001797 if (getset_keep) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001798 if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001799 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001800 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001801 if (getset_nowerr) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001802 if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001803 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001804 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001805 if (getset_readonly) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001806 if (!ioctl_or_warn(fd, BLKROGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001807 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001808 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001809 if (getset_readahead) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001810 if (!ioctl_or_warn(fd, BLKRAGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001811 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001812 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001813 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001814 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001815 struct hd_geometry g;
1816
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001817 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001818 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001819 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001820 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001821 }
1822#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001823 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001824#ifndef WIN_CHECKPOWERMODE1
1825#define WIN_CHECKPOWERMODE1 0xE5
1826#endif
1827#ifndef WIN_CHECKPOWERMODE2
1828#define WIN_CHECKPOWERMODE2 0x98
1829#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001830 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001831
Rob Landleye5b281f2006-04-29 15:49:18 +00001832 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001833 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001834 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001835 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001836 else
1837 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001838 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001839 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001840 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001841
Eric Andersen3443bd72003-07-22 07:30:36 +00001842 printf(" drive state is: %s\n", state);
1843 }
1844#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001845#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1846 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001847 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001848 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001849#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1850#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1851 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001852 args[0] = 0;
1853 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001854 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001855 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001856#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1857#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1858 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001859 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001860
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001861 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1862 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001863 id.multsect = multcount;
1864 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001865 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001866 id.multsect_valid &= ~1;
1867 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001868 } else if (errno == -ENOMSG)
Eric Andersen3443bd72003-07-22 07:30:36 +00001869 printf(" no identification info available\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001870 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001871 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001872 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001873 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001874 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001875
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001876 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001877 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001878
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001879 memset(args1, 0, sizeof(args1));
1880 args1[0] = WIN_IDENTIFY;
1881 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001882 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001883 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00001884 }
1885#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001886#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001887 if (getset_busstate == IS_SET) {
1888 print_flag(1, "bus state", busstate);
1889 bus_state_value(busstate);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001890 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001891 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001892 if (getset_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001893 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001894 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001895 bus_state_value(parm);
1896 }
1897 }
1898#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00001899 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001900 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00001901
Eric Andersen3443bd72003-07-22 07:30:36 +00001902 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001903 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00001904 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001905 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001906 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001907 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00001908 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00001909}
1910
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001911#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00001912static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00001913{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001914 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00001915 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001916 if (c >= 'a' && c <= 'f')
1917 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00001918 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1919}
1920
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001921static void identify_from_stdin(void) NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00001922static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001923{
Rob Landley0753f4a2006-06-07 00:27:25 +00001924 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001925 unsigned char buf[1280];
1926 unsigned char *b = (unsigned char *)buf;
1927 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001928
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001929 xread(STDIN_FILENO, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00001930
Rob Landley0753f4a2006-06-07 00:27:25 +00001931 // Convert the newline-separated hex data into an identify block.
1932
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001933 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00001934 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001935 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001936 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00001937 }
Rob Landley0753f4a2006-06-07 00:27:25 +00001938
1939 // Parse the data.
1940
Rob Landley6389ff12006-05-01 19:28:53 +00001941 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001942}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001943#else
1944void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00001945#endif
1946
Rob Landley20deab02006-05-07 23:34:15 +00001947/* busybox specific stuff */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001948static int parse_opts(unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00001949{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001950 if (optarg) {
Denis Vlasenko13858992006-10-08 12:49:22 +00001951 *value = xatol_range(optarg, min, max);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001952 return IS_SET;
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001953 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001954 return IS_GET;
1955}
1956static int parse_opts_0_max(unsigned long *value, int max)
1957{
1958 return parse_opts(value, 0, max);
1959}
1960static int parse_opts_0_1(unsigned long *value)
1961{
1962 return parse_opts(value, 0, 1);
1963}
1964static int parse_opts_0_INTMAX(unsigned long *value)
1965{
1966 return parse_opts(value, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00001967}
1968
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001969static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00001970{
1971 if (flag) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001972 *get = IS_GET;
Rob Landley20deab02006-05-07 23:34:15 +00001973 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001974 *value = translate_xfermode(optarg);
1975 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00001976 }
1977 }
1978}
1979
Rob Landley06208412006-05-31 22:52:57 +00001980/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001981static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00001982 "gfu::n::p:r::m::c::k::a::B:tT"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001983 IF_FEATURE_HDPARM_GET_IDENTITY("iI")
1984 IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
Rob Landley20deab02006-05-07 23:34:15 +00001985#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001986 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00001987#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001988 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
Rob Landley20deab02006-05-07 23:34:15 +00001989#ifdef HDIO_GET_QDMA
1990#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001991 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00001992#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001993 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00001994#endif
1995#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001996 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
1997 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
1998 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
Rob Landley20deab02006-05-07 23:34:15 +00001999/*-------------------------------------*/
2000
2001/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002002int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00002003int hdparm_main(int argc, char **argv)
2004{
2005 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00002006 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00002007
Rob Landley06208412006-05-31 22:52:57 +00002008 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00002009 flagcount++;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002010 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
2011 IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00002012 get_geom |= (c == 'g');
2013 do_flush |= (c == 'f');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002014 if (c == 'u') getset_unmask = parse_opts_0_1(&unmask);
2015 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
2016 if (c == 'd') getset_dma = parse_opts_0_max(&dma, 9);
2017 )
2018 if (c == 'n') getset_nowerr = parse_opts_0_1(&nowerr);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002019 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002020 if (c == 'r') getset_readonly = parse_opts_0_1(&readonly);
2021 if (c == 'm') getset_mult = parse_opts_0_INTMAX(&mult /*32*/);
2022 if (c == 'c') getset_io32bit = parse_opts_0_INTMAX(&io32bit /*8*/);
2023 if (c == 'k') getset_keep = parse_opts_0_1(&keep);
2024 if (c == 'a') getset_readahead = parse_opts_0_INTMAX(&Xreadahead);
2025 if (c == 'B') getset_apmmode = parse_opts(&apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002026 do_flush |= do_timings |= (c == 't');
2027 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002028#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002029 if (c == 'S') getset_standby = parse_opts_0_max(&standby_requested, 255);
2030 if (c == 'D') getset_defects = parse_opts_0_INTMAX(&defects);
2031 if (c == 'P') getset_prefetch = parse_opts_0_INTMAX(&prefetch);
Rob Landleyade7f952006-05-25 18:53:06 +00002032 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002033 if (c == 'K') getset_dkeep = parse_opts_0_1(&prefetch);
2034 if (c == 'A') getset_lookahead = parse_opts_0_1(&lookahead);
2035 if (c == 'L') getset_doorlock = parse_opts_0_1(&doorlock);
2036 if (c == 'W') getset_wcache = parse_opts_0_1(&wcache);
Rob Landleyade7f952006-05-25 18:53:06 +00002037 get_powermode |= (c == 'C');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002038 set_standbynow |= (c == 'y');
2039 set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002040 reread_partn |= (c == 'z');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002041 set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002042#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002043 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') unregister_hwif = parse_opts_0_INTMAX(&hwif));
Rob Landley20deab02006-05-07 23:34:15 +00002044#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002045 if (c == 'Q') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002046 getset_dma_q = parse_opts_0_INTMAX(&dma_q);
Rob Landley19802562006-05-08 15:35:46 +00002047 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002048#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002049 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002050 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') perform_tristate = parse_opts_0_1(&tristate));
2051 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') getset_busstate = parse_opts_0_max(&busstate, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002052#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2053 if (c == 'R') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002054 scan_hwif = parse_opts_0_INTMAX(&hwif_data);
Denis Vlasenko13858992006-10-08 12:49:22 +00002055 hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
2056 hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002057 /* Move past the 2 additional arguments */
2058 argv += 2;
2059 argc -= 2;
2060 }
2061#endif
2062 }
Rob Landleyade7f952006-05-25 18:53:06 +00002063 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002064 if (!flagcount) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002065 getset_mult = getset_io32bit = getset_unmask = getset_keep = getset_readonly = getset_readahead = get_geom = IS_GET;
2066 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(getset_dma = IS_GET);
Rob Landleyade7f952006-05-25 18:53:06 +00002067 }
Rob Landley20deab02006-05-07 23:34:15 +00002068 argv += optind;
2069
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002070 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002071 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2072 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002073 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002074 }
2075
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002076 do {
2077 process_dev(*argv++);
2078 } while (*argv);
2079
2080 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002081}