blob: ec5ede691c4f7d3b89c80c790f8694220ddc5517 [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 */
Glenn L McGrath07085852003-10-09 07:28:22 +000014
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000015#include "libbb.h"
Eric Andersen3443bd72003-07-22 07:30:36 +000016#include <linux/hdreg.h>
Eric Andersen3443bd72003-07-22 07:30:36 +000017
Eric Andersen3443bd72003-07-22 07:30:36 +000018/* device types */
19/* ------------ */
20#define NO_DEV 0xffff
21#define ATA_DEV 0x0000
22#define ATAPI_DEV 0x0001
23
24/* word definitions */
25/* ---------------- */
26#define GEN_CONFIG 0 /* general configuration */
27#define LCYLS 1 /* number of logical cylinders */
28#define CONFIG 2 /* specific configuration */
29#define LHEADS 3 /* number of logical heads */
30#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
31#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
32#define LSECTS 6 /* number of logical sectors/track */
33#define START_SERIAL 10 /* ASCII serial number */
34#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
35#define BUF_TYPE 20 /* buffer type (ATA-1) */
36#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
37#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
38#define START_FW_REV 23 /* ASCII firmware revision */
39#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000040#define START_MODEL 27 /* ASCII model number */
41#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000042#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +000043#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
44#define CAPAB_0 49 /* capabilities */
45#define CAPAB_1 50
46#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
47#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
48#define WHATS_VALID 53 /* what fields are valid */
49#define LCYLS_CUR 54 /* current logical cylinders */
50#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000051#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +000052#define CAPACITY_LSB 57 /* current capacity in sectors */
53#define CAPACITY_MSB 58
54#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
55#define LBA_SECTS_LSB 60 /* LBA: total number of user */
56#define LBA_SECTS_MSB 61 /* addressable sectors */
57#define SINGLE_DMA 62 /* singleword DMA modes */
58#define MULTI_DMA 63 /* multiword DMA modes */
59#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
60 /* multiword DMA xfer cycle time: */
61#define DMA_TIME_MIN 65 /* - minimum */
62#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
63 /* minimum PIO xfer cycle time: */
64#define PIO_NO_FLOW 67 /* - without flow control */
65#define PIO_FLOW 68 /* - with IORDY flow control */
66#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
67#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
68#define CDR_MAJOR 73 /* CD ROM: major version number */
69#define CDR_MINOR 74 /* CD ROM: minor version number */
70#define QUEUE_DEPTH 75 /* queue depth */
71#define MAJOR 80 /* major version number */
72#define MINOR 81 /* minor version number */
73#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
74#define CMDS_SUPP_1 83
75#define CMDS_SUPP_2 84
76#define CMDS_EN_0 85 /* command/feature set(s) enabled */
77#define CMDS_EN_1 86
78#define CMDS_EN_2 87
79#define ULTRA_DMA 88 /* ultra DMA modes */
80 /* time to complete security erase */
81#define ERASE_TIME 89 /* - ordinary */
82#define ENH_ERASE_TIME 90 /* - enhanced */
83#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +000084 in low byte, 0x40 in high byte. */
Eric Andersen3443bd72003-07-22 07:30:36 +000085#define PSWD_CODE 92 /* master password revision code */
86#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000087#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +000088#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
89#define LBA_MID 101 /* bits are used, but addr 103 */
90#define LBA_48_MSB 102 /* has been reserved for LBA in */
91#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000092#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +000093#define SECU_STATUS 128 /* security status */
94#define CFA_PWR_MODE 160 /* CFA power mode 1 */
95#define START_MEDIA 176 /* media serial number */
96#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
97#define START_MANUF 196 /* media manufacturer I.D. */
98#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
99#define INTEGRITY 255 /* integrity word */
100
101/* bit definitions within the words */
102/* -------------------------------- */
103
104/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
105#define VALID 0xc000
106#define VALID_VAL 0x4000
107/* many words are considered invalid if they are either all-0 or all-1 */
108#define NOVAL_0 0x0000
109#define NOVAL_1 0xffff
110
111/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000112#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000113#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
114#define MEDIA_REMOVABLE 0x0080
115#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
116#define INCOMPLETE 0x0004
117#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
118#define DRQ_RESPONSE_TIME 0x0060
119#define DRQ_3MS_VAL 0x0000
120#define DRQ_INTR_VAL 0x0020
121#define DRQ_50US_VAL 0x0040
122#define PKT_SIZE_SUPPORTED 0x0003
123#define PKT_SIZE_12_VAL 0x0000
124#define PKT_SIZE_16_VAL 0x0001
125#define EQPT_TYPE 0x1f00
126#define SHIFT_EQPT 8
127
128#define CDROM 0x0005
129
Eric Andersen3443bd72003-07-22 07:30:36 +0000130/* word 1: number of logical cylinders */
131#define LCYLS_MAX 0x3fff /* maximum allowable value */
132
Eric Andersenaff114c2004-04-14 17:51:38 +0000133/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000134 * (a) require SET FEATURES to spin-up
135 * (b) require spin-up to fully reply to IDENTIFY DEVICE
136 */
137#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
138#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000139#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000140#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
141
142/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
143#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
144#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
145
146/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000147#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000148#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
149#define IORDY_OFF 0x0400 /* 1=may be disabled */
150#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
151#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
152#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
153#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
154#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
155#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
156
157/* word 50: capabilities 1 */
158#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
159
160/* words 51 & 52: PIO & DMA cycle times */
161#define MODE 0xff00 /* the mode is in the MSBs */
162
163/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000164#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000165#define OK_W64_70 0x0002 /* see above for word descriptions */
166#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
167
168/*word 63,88: dma_mode, ultra_dma_mode*/
169#define MODE_MAX 7 /* bit definitions force udma <=7 (when
170 * udma >=8 comes out it'll have to be
171 * defined in a new dma_mode word!) */
172
173/* word 64: PIO transfer modes */
174#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
175#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
176
177/* word 75: queue_depth */
178#define DEPTH_BITS 0x001f /* bits used for queue depth */
179
180/* words 80-81: version numbers */
181/* NOVAL_0 or NOVAL_1 means device does not report version */
182
183/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000184#define MINOR_MAX 0x22
Eric Andersen3443bd72003-07-22 07:30:36 +0000185/* words 82-84: cmds/feats supported */
186#define CMDS_W82 0x77ff /* word 82: defined command locations*/
187#define CMDS_W83 0x3fff /* word 83: defined command locations*/
188#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000189#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000190#define NUM_CMD_FEAT_STR 48
191
Eric Andersen3443bd72003-07-22 07:30:36 +0000192/* words 85-87: cmds/feats enabled */
193/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000194 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000195 */
196
197/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000198#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000199
200/* word 92: master password revision */
201/* NOVAL_0 or NOVAL_1 means no support for master password revision */
202
203/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000204#define CBLID 0x2000 /* CBLID status */
205#define RST0 0x0001 /* 1=reset to device #0 */
206#define DEV_DET 0x0006 /* how device num determined */
207#define JUMPER_VAL 0x0002 /* device num determined by jumper */
208#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000209
210/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000211#define RM_STAT_BITS 0x0003
212#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000213
Eric Andersen3443bd72003-07-22 07:30:36 +0000214/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000215#define SECU_ENABLED 0x0002
216#define SECU_LEVEL 0x0010
217#define NUM_SECU_STR 6
Eric Andersen3443bd72003-07-22 07:30:36 +0000218
219/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000220#define VALID_W160 0x8000 /* 1=word valid */
221#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
222#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
223#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000224
225/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000226#define SIG 0x00ff /* signature location */
227#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000228
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000229#define TIMING_BUF_MB 1
230#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000231
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000232#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000233
Denis Vlasenko892536f2007-09-27 10:23:34 +0000234
235enum { fd = 3 };
236
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000237
238struct globals {
239 smallint get_identity, get_geom;
240 smallint do_flush;
241 smallint do_ctimings, do_timings;
242 smallint reread_partn;
243 smallint set_piomode, noisy_piomode;
244 smallint set_readahead, get_readahead;
245 smallint set_readonly, get_readonly;
246 smallint set_unmask, get_unmask;
247 smallint set_mult, get_mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000248#ifdef HDIO_GET_QDMA
249 smallint get_dma_q;
250#ifdef HDIO_SET_QDMA
251 smallint set_dma_q;
252#endif
253#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000254 smallint set_nowerr, get_nowerr;
255 smallint set_keep, get_keep;
256 smallint set_io32bit, get_io32bit;
257 int piomode;
258 unsigned long Xreadahead;
259 unsigned long readonly;
260 unsigned long unmask;
261 unsigned long mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000262#ifdef HDIO_SET_QDMA
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000263 unsigned long dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000264#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000265 unsigned long nowerr;
266 unsigned long keep;
267 unsigned long io32bit;
268#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
269 unsigned long dma;
270 smallint set_dma, get_dma;
271#endif
272#ifdef HDIO_DRIVE_CMD
273 smallint set_xfermode, get_xfermode;
274 smallint set_dkeep, get_dkeep;
275 smallint set_standby, get_standby;
276 smallint set_lookahead, get_lookahead;
277 smallint set_prefetch, get_prefetch;
278 smallint set_defects, get_defects;
279 smallint set_wcache, get_wcache;
280 smallint set_doorlock, get_doorlock;
281 smallint set_seagate, get_seagate;
282 smallint set_standbynow, get_standbynow;
283 smallint set_sleepnow, get_sleepnow;
284 smallint get_powermode;
285 smallint set_apmmode, get_apmmode;
286 int xfermode_requested;
287 unsigned long dkeep;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000288 unsigned long standby_requested; /* 0..255 */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000289 unsigned long lookahead;
290 unsigned long prefetch;
291 unsigned long defects;
292 unsigned long wcache;
293 unsigned long doorlock;
294 unsigned long apmmode;
295#endif
296 USE_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
297 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint set_busstate, get_busstate;)
298 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
299 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
300 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
301 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
302 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
303 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
304 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
305#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
306 unsigned long hwif_data;
307 unsigned long hwif_ctrl;
308 unsigned long hwif_irq;
309#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000310#ifdef DO_FLUSHCACHE
311 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
312#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000313};
314#define G (*(struct globals*)&bb_common_bufsiz1)
315struct BUG_G_too_big {
316 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
317};
318#define get_identity (G.get_identity )
319#define get_geom (G.get_geom )
320#define do_flush (G.do_flush )
321#define do_ctimings (G.do_ctimings )
322#define do_timings (G.do_timings )
323#define reread_partn (G.reread_partn )
324#define set_piomode (G.set_piomode )
325#define noisy_piomode (G.noisy_piomode )
326#define set_readahead (G.set_readahead )
327#define get_readahead (G.get_readahead )
328#define set_readonly (G.set_readonly )
329#define get_readonly (G.get_readonly )
330#define set_unmask (G.set_unmask )
331#define get_unmask (G.get_unmask )
332#define set_mult (G.set_mult )
333#define get_mult (G.get_mult )
334#define set_dma_q (G.set_dma_q )
335#define get_dma_q (G.get_dma_q )
336#define set_nowerr (G.set_nowerr )
337#define get_nowerr (G.get_nowerr )
338#define set_keep (G.set_keep )
339#define get_keep (G.get_keep )
340#define set_io32bit (G.set_io32bit )
341#define get_io32bit (G.get_io32bit )
342#define piomode (G.piomode )
343#define Xreadahead (G.Xreadahead )
344#define readonly (G.readonly )
345#define unmask (G.unmask )
346#define mult (G.mult )
347#define dma_q (G.dma_q )
348#define nowerr (G.nowerr )
349#define keep (G.keep )
350#define io32bit (G.io32bit )
351#define dma (G.dma )
352#define set_dma (G.set_dma )
353#define get_dma (G.get_dma )
354#define set_xfermode (G.set_xfermode )
355#define get_xfermode (G.get_xfermode )
356#define set_dkeep (G.set_dkeep )
357#define get_dkeep (G.get_dkeep )
358#define set_standby (G.set_standby )
359#define get_standby (G.get_standby )
360#define set_lookahead (G.set_lookahead )
361#define get_lookahead (G.get_lookahead )
362#define set_prefetch (G.set_prefetch )
363#define get_prefetch (G.get_prefetch )
364#define set_defects (G.set_defects )
365#define get_defects (G.get_defects )
366#define set_wcache (G.set_wcache )
367#define get_wcache (G.get_wcache )
368#define set_doorlock (G.set_doorlock )
369#define get_doorlock (G.get_doorlock )
370#define set_seagate (G.set_seagate )
371#define get_seagate (G.get_seagate )
372#define set_standbynow (G.set_standbynow )
373#define get_standbynow (G.get_standbynow )
374#define set_sleepnow (G.set_sleepnow )
375#define get_sleepnow (G.get_sleepnow )
376#define get_powermode (G.get_powermode )
377#define set_apmmode (G.set_apmmode )
378#define get_apmmode (G.get_apmmode )
379#define xfermode_requested (G.xfermode_requested )
380#define dkeep (G.dkeep )
381#define standby_requested (G.standby_requested )
382#define lookahead (G.lookahead )
383#define prefetch (G.prefetch )
384#define defects (G.defects )
385#define wcache (G.wcache )
386#define doorlock (G.doorlock )
387#define apmmode (G.apmmode )
388#define get_IDentity (G.get_IDentity )
389#define set_busstate (G.set_busstate )
390#define get_busstate (G.get_busstate )
391#define perform_reset (G.perform_reset )
392#define perform_tristate (G.perform_tristate )
393#define unregister_hwif (G.unregister_hwif )
394#define scan_hwif (G.scan_hwif )
395#define busstate (G.busstate )
396#define tristate (G.tristate )
397#define hwif (G.hwif )
398#define hwif_data (G.hwif_data )
399#define hwif_ctrl (G.hwif_ctrl )
400#define hwif_irq (G.hwif_irq )
401
402
Glenn L McGrath07085852003-10-09 07:28:22 +0000403/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000404#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000405static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000406{
407 if (!ioctl(fd, cmd, args))
408 return 0;
409 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000410 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000411}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000412#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000413#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000414static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000415{
416 if (!ioctl(fd, cmd, args))
417 return 0;
418 args[0] = alt;
419 return bb_ioctl_or_warn(fd, cmd, args);
420}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000421#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000422#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000423
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000424static void on_off(int value)
425{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000426 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000427}
Glenn L McGrath07085852003-10-09 07:28:22 +0000428
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000429static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000430{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000431 if (get_arg) {
Rob Landleyadde7982006-05-16 15:32:30 +0000432 printf(" setting %s to %ld", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000433 on_off(arg);
434 }
435}
436
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000437static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000438{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000439 printf(" %s\t= %2ld", str, argp);
440 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000441}
Eric Andersen416c2422003-12-12 00:08:57 +0000442
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000443#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000444static void print_ascii(const char *p, int length)
445{
446#if BB_BIG_ENDIAN
447#define LE_ONLY(x)
448 enum { ofs = 0 };
449#else
450#define LE_ONLY(x) x
451 /* every 16bit word is big-endian (i.e. inverted) */
452 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
453 int ofs = 1;
454#endif
455
456 length *= 2;
457 /* find first non-space & print it */
458 while (length && p[ofs] != ' ') {
459 p++;
460 LE_ONLY(ofs = -ofs;)
461 length--;
462 }
463 while (length && p[ofs]) {
464 bb_putchar(p[ofs]);
465 p++;
466 LE_ONLY(ofs = -ofs;)
467 length--;
468 }
469 bb_putchar('\n');
470#undef LE_ONLY
471}
Glenn L McGrath07085852003-10-09 07:28:22 +0000472
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000473static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000474{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000475 if (val[i]) {
476 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000477 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000478 }
479}
Glenn L McGrath07085852003-10-09 07:28:22 +0000480
Glenn L McGrath07085852003-10-09 07:28:22 +0000481static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
482{
Eric Andersen3443bd72003-07-22 07:30:36 +0000483 uint16_t ii;
484 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000485
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000486 for (ii = 0; ii <= MODE_MAX; ii++) {
487 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000488 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000489 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000490 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000491 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000492 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000493 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000494
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000495 mode_sup >>= 1;
496 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000497 }
498 return err_dma;
499}
Glenn L McGrath07085852003-10-09 07:28:22 +0000500
Denis Vlasenko91303402007-10-30 19:36:54 +0000501static const char pkt_str[] ALIGN1 =
502 "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
503 "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
504 "Printer" "\0" /* word 0, bits 12-8 = 02 */
505 "Processor" "\0" /* word 0, bits 12-8 = 03 */
506 "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
507 "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
508 "Scanner" "\0" /* word 0, bits 12-8 = 06 */
509 "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
510 "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
511 "Communications device" "\0" /* word 0, bits 12-8 = 09 */
512 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
513 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
514 "Array controller" "\0" /* word 0, bits 12-8 = 0c */
515 "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
516 "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
517 "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
518;
519
520static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
521 "reserved" "\0" /* bit 0 */
522 "hard sectored" "\0" /* bit 1 */
523 "soft sectored" "\0" /* bit 2 */
524 "not MFM encoded " "\0" /* bit 3 */
525 "head switch time > 15us" "\0" /* bit 4 */
526 "spindle motor control option" "\0" /* bit 5 */
527 "fixed drive" "\0" /* bit 6 */
528 "removable drive" "\0" /* bit 7 */
529 "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
530 "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
531 "disk xfer rate > 5Mbs" "\0" /* bit 10 */
532 "rotational speed tol." "\0" /* bit 11 */
533 "data strobe offset option" "\0" /* bit 12 */
534 "track offset option" "\0" /* bit 13 */
535 "format speed tolerance gap reqd" "\0" /* bit 14 */
536 "ATAPI" /* bit 14 */
537;
538
539static const char minor_str[] ALIGN1 =
540 /* word 81 value: */
541 "Unspecified" "\0" /* 0x0000 */
542 "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
543 "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
544 "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
545 "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
546 "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
547 "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
548 "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
549 "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
550 "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
551 "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
552 "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
553 "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
554 "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
555 "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
556 "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
557 "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
558 "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
559 "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
560 "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
561 "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
562 "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
563 "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
564 "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
565 "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
566 "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
567 "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
568 "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
569 "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
570 "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
571 "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
572 "reserved" "\0" /* 0x001f */
573 "reserved" "\0" /* 0x0020 */
574 "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
575 "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
576 "reserved" /* 0x0023-0xfffe */
577;
578static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
579 /* word 81 value: */
580 0, /* 0x0000 WARNING: actual_ver[] array */
581 1, /* 0x0001 WARNING: corresponds */
582 1, /* 0x0002 WARNING: *exactly* */
583 1, /* 0x0003 WARNING: to the ATA/ */
584 2, /* 0x0004 WARNING: ATAPI version */
585 2, /* 0x0005 WARNING: listed in */
586 3, /* 0x0006 WARNING: the */
587 2, /* 0x0007 WARNING: minor_str */
588 3, /* 0x0008 WARNING: array */
589 2, /* 0x0009 WARNING: above. */
590 3, /* 0x000a WARNING: */
591 3, /* 0x000b WARNING: If you change */
592 3, /* 0x000c WARNING: that one, */
593 4, /* 0x000d WARNING: change this one */
594 4, /* 0x000e WARNING: too!!! */
595 4, /* 0x000f */
596 4, /* 0x0010 */
597 4, /* 0x0011 */
598 4, /* 0x0012 */
599 5, /* 0x0013 */
600 4, /* 0x0014 */
601 5, /* 0x0015 */
602 5, /* 0x0016 */
603 4, /* 0x0017 */
604 6, /* 0x0018 */
605 6, /* 0x0019 */
606 7, /* 0x001a */
607 6, /* 0x001b */
608 6, /* 0x001c */
609 7, /* 0x001d */
610 7, /* 0x001e */
611 0, /* 0x001f */
612 0, /* 0x0020 */
613 7, /* 0x0021 */
614 6, /* 0x0022 */
615 0 /* 0x0023-0xfffe */
616};
617
618static const char cmd_feat_str[] ALIGN1 =
619 "" "\0" /* word 82 bit 15: obsolete */
620 "NOP cmd" "\0" /* word 82 bit 14 */
621 "READ BUFFER cmd" "\0" /* word 82 bit 13 */
622 "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
623 "" "\0" /* word 82 bit 11: obsolete */
624 "Host Protected Area feature set" "\0" /* word 82 bit 10 */
625 "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
626 "SERVICE interrupt" "\0" /* word 82 bit 8 */
627 "Release interrupt" "\0" /* word 82 bit 7 */
628 "Look-ahead" "\0" /* word 82 bit 6 */
629 "Write cache" "\0" /* word 82 bit 5 */
630 "PACKET command feature set" "\0" /* word 82 bit 4 */
631 "Power Management feature set" "\0" /* word 82 bit 3 */
632 "Removable Media feature set" "\0" /* word 82 bit 2 */
633 "Security Mode feature set" "\0" /* word 82 bit 1 */
634 "SMART feature set" "\0" /* word 82 bit 0 */
635 /* -------------- */
636 "" "\0" /* word 83 bit 15: !valid bit */
637 "" "\0" /* word 83 bit 14: valid bit */
638 "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
639 "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
640 "Device Configuration Overlay feature set " "\0"
641 "48-bit Address feature set " "\0" /* word 83 bit 10 */
642 "" "\0"
643 "SET MAX security extension" "\0" /* word 83 bit 8 */
644 "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
645 "SET FEATURES subcommand required to spinup after power up" "\0"
646 "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
647 "Removable Media Status Notification feature set" "\0"
648 "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
649 "CFA feature set" "\0" /* word 83 bit 2 */
650 "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
651 "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
652 /* -------------- */
653 "" "\0" /* word 84 bit 15: !valid bit */
654 "" "\0" /* word 84 bit 14: valid bit */
655 "" "\0" /* word 84 bit 13: reserved */
656 "" "\0" /* word 84 bit 12: reserved */
657 "" "\0" /* word 84 bit 11: reserved */
658 "" "\0" /* word 84 bit 10: reserved */
659 "" "\0" /* word 84 bit 9: reserved */
660 "" "\0" /* word 84 bit 8: reserved */
661 "" "\0" /* word 84 bit 7: reserved */
662 "" "\0" /* word 84 bit 6: reserved */
663 "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
664 "" "\0" /* word 84 bit 4: reserved */
665 "Media Card Pass Through Command feature set " "\0"
666 "Media serial number " "\0" /* word 84 bit 2 */
667 "SMART self-test " "\0" /* word 84 bit 1 */
668 "SMART error logging " /* word 84 bit 0 */
669;
670
671static const char secu_str[] ALIGN1 =
672 "supported" "\0" /* word 128, bit 0 */
673 "enabled" "\0" /* word 128, bit 1 */
674 "locked" "\0" /* word 128, bit 2 */
675 "frozen" "\0" /* word 128, bit 3 */
676 "expired: security count" "\0" /* word 128, bit 4 */
677 "supported: enhanced erase" /* word 128, bit 5 */
678;
679
680// Parse 512 byte disk identification block and print much crap.
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000681static void identify(uint16_t *val) ATTRIBUTE_NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000682static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000683{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000684 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000685 uint16_t like_std = 1, std = 0, min_std = 0xffff;
686 uint16_t dev = NO_DEV, eqpt = NO_DEV;
687 uint8_t have_mode = 0, err_dma = 0;
688 uint8_t chksum = 0;
689 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000690 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000691 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000692#if BB_BIG_ENDIAN
693 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000694
Denis Vlasenko4daad902007-09-27 10:20:47 +0000695 // Adjust for endianness
696 swab(val, buf, sizeof(buf));
697 val = buf;
698#endif
Eric Andersen3443bd72003-07-22 07:30:36 +0000699 /* check if we recognise the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000700 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000701 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000702 dev = ATA_DEV;
703 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000704 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000705 dev = ATA_DEV;
706 like_std = 4;
707 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000708 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000709 dev = ATAPI_DEV;
710 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000711 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +0000712 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000713 } else
Denis Vlasenko91303402007-10-30 19:36:54 +0000714 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000715 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000716
Rob Landleyadde7982006-05-16 15:32:30 +0000717 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000718 /* Info from the specific configuration word says whether or not the
719 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000720 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000721 * standards. Since the values allowed for this word are extremely
722 * specific, it should be safe to check it now, even though we don't
723 * know yet what standard this device is using.
724 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000725 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
726 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
727 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000728 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000729 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Rob Landleyadde7982006-05-16 15:32:30 +0000730 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000731 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Rob Landleyadde7982006-05-16 15:32:30 +0000732 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000733 }
734
735 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000736 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
737 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
738 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
739 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
740 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000741
742 /* major & minor standards version number (Note: these words were not
743 * defined until ATA-3 & the CDROM std uses different words.) */
744 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000745 if (eqpt != CDROM) {
746 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000747 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000748 std = actual_ver[val[MINOR]];
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000749 if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
Glenn L McGrath07085852003-10-09 07:28:22 +0000750
Eric Andersen3443bd72003-07-22 07:30:36 +0000751 }
752 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000753 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000754 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000755 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000756 printf("\n\tSupported: ");
757 jj = val[MAJOR] << 1;
758 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000759 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
760 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000761 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000762 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000763 like_std = ii;
764 kk = like_std >4 ? like_std-4: 0;
765 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000766 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000767 }
768 jj <<= 1;
769 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000770 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000771 }
772 /* Figure out what standard the device is using if it hasn't told
773 * us. If we know the std, check if the device is using any of
774 * the words from the next level up. It happens.
775 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000776 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000777
Rob Landleya3e4f382006-04-29 16:06:31 +0000778 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000779 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
780 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
781 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000782 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
783 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000784 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000785 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000786 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000787 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
788 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
789 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
790 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000791 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000792 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000793 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
794 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
795 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
796 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
797 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000798 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
799 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000800 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000801 } else if (((std == 2) || (!std && (like_std < 3)))
802 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
803 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000804 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000805 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000806 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
807 (val[WHATS_VALID] & OK_W64_70)) )
808 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000809 like_std = 2;
810 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000811
Rob Landleya3e4f382006-04-29 16:06:31 +0000812 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000813 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000814 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000815 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000816 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000817 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000818 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000819 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000820 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000821 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000822 kk = 1;
823 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
824 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000825 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000826 kk = 1;
827 printf("\n\tSupported: CD-ROM ATAPI");
828 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000829 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000830 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000831 jj >>= 1;
832 }
833 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000834 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000835 /* the cdrom stuff is more like ATA-2 than anything else, so: */
836 like_std = 2;
837 }
838
Rob Landleya3e4f382006-04-29 16:06:31 +0000839 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000840 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000841
842 printf("Configuration:\n");
843 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000844 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000845 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000846 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000847 if (jj & 0x0001)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000848 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +0000849 jj >>=1;
850 }
851 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000852 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000853 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
854 strng = "3ms";
855 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
856 strng = "<=10ms with INTRQ";
857 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
858 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000859 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000860 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000861 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
862
863 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
864 strng = "12 bytes";
865 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
866 strng = "16 bytes";
867 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000868 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000869 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000870 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000871 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000872 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
873 mm = 0; bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000874 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000875 printf("\tCHS addressing not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000876 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000877 jj = val[WHATS_VALID] & OK_W54_58;
Glenn L McGrath07085852003-10-09 07:28:22 +0000878 printf("\tLogical\t\tmax\tcurrent\n\tcylinders\t%u\t%u\n\theads\t\t%u\t%u\n\tsectors/track\t%u\t%u\n\t--\n",
879 val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
880
Rob Landleyadde7982006-05-16 15:32:30 +0000881 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000882 printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000883
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000884 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000885 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000886 if (like_std < 3) {
887 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000888 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
889 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000890 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +0000891 mm = oo;
892 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000893 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +0000894 }
Eric Andersen3443bd72003-07-22 07:30:36 +0000895 }
896 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000897 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000898 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
899 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
900 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000901 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
902 (uint64_t)val[LBA_48_MSB] << 32 |
903 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000904 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000905 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +0000906 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000907
908 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +0000909 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000910 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
911 bbbig = (bbbig << 9) / 1000000;
912 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +0000913
Rob Landleyadde7982006-05-16 15:32:30 +0000914 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +0000915 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000916 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000917 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000918 }
919
920 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +0000921 printf("Capabilities:\n\t");
922
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000923 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000924 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
925 if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +0000926 }
Rob Landleyadde7982006-05-16 15:32:30 +0000927 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +0000928
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000929 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000930 printf("IORDY%s(can%s be disabled)\n",
931 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
Rob Landleyadde7982006-05-16 15:32:30 +0000932 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000933 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000934 printf("no IORDY\n");
935
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000936 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000937 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000938 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
Rob Landleyadde7982006-05-16 15:32:30 +0000939 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000940 }
Rob Landleyadde7982006-05-16 15:32:30 +0000941
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000942 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000943 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +0000944 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000945 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000946 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000947 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000948 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000949 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +0000950 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000951
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000952 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000953 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000954 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000955 else {
Rob Landleyadde7982006-05-16 15:32:30 +0000956 printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +0000957 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000958 printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +0000959 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000960 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000961 }
962 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000963 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Eric Andersen3443bd72003-07-22 07:30:36 +0000964 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000965 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000966 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +0000967 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
968 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
969 else
970 printf("?\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000971 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000972 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000973 /* We print out elsewhere whether the APM feature is enabled or
974 not. If it's not enabled, let's not repeat the info; just print
975 nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +0000976 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000977 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000978 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +0000979 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +0000980 }
981 else
Eric Andersen3443bd72003-07-22 07:30:36 +0000982 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000983 }
Rob Landleyadde7982006-05-16 15:32:30 +0000984 if (like_std > 5 && val[ACOUSTIC]) {
985 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000986 (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +0000987 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000988 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000989 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +0000990 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
991 printf("\tATA sw reset required\n");
Glenn L McGrath07085852003-10-09 07:28:22 +0000992
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000993 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000994 printf("\tOverlap support:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000995 if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
996 if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
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:");
1060 if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1061 if (val[PIO_FLOW]) printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001062 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001063 }
1064 }
1065
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001066 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001067 printf("Commands/features:\n\tEnabled\tSupported:\n");
1068 jj = val[CMDS_SUPP_0];
1069 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001070 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001071 const char *feat_str = nth_string(cmd_feat_str, ii);
Denis Vlasenko91303402007-10-30 19:36:54 +00001072 if ((jj & 0x8000) && (*feat_str != '\0')) {
1073 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
Eric Andersen3443bd72003-07-22 07:30:36 +00001074 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001075 jj <<= 1;
1076 kk <<= 1;
1077 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001078 jj = val[CMDS_SUPP_0+1+(ii/16)];
1079 kk = val[CMDS_EN_0+1+(ii/16)];
1080 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001081 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001082 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +00001083 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001084 }
1085 }
1086 }
Rob Landleyadde7982006-05-16 15:32:30 +00001087 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001088 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001089 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
Glenn L McGrath07085852003-10-09 07:28:22 +00001090
Eric Andersen3443bd72003-07-22 07:30:36 +00001091 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001092 if ((eqpt != CDROM) && (like_std > 3)
1093 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1094 ) {
Rob Landleyade7f952006-05-25 18:53:06 +00001095 printf("Security:\n");
Rob Landleyadde7982006-05-16 15:32:30 +00001096 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001097 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001098 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001099 if (jj) {
1100 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001101 printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "", nth_string(secu_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +00001102 jj >>=1;
1103 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001104 if (val[SECU_STATUS] & SECU_ENABLED) {
Rob Landleyadde7982006-05-16 15:32:30 +00001105 printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001106 }
1107 }
1108 jj = val[ERASE_TIME] & ERASE_BITS;
1109 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001110 if (jj || kk) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001111 printf("\t");
Rob Landleyade7f952006-05-25 18:53:06 +00001112 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1113 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001114 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001115 }
1116 }
1117
1118 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001119 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001120 if ((jj & VALID) == VALID_VAL) {
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001121 oo = (jj & RST0);
1122 if (!oo)
Rob Landleyadde7982006-05-16 15:32:30 +00001123 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001124 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001125 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001126 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001127 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001128 else
Rob Landleyadde7982006-05-16 15:32:30 +00001129 strng = "";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001130 printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
Rob Landleyadde7982006-05-16 15:32:30 +00001131 (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001132 }
1133
1134 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001135 if ((like_std > 4) && (eqpt != CDROM)) {
1136 if (val[CFA_PWR_MODE] & VALID_W160) {
Rob Landleyadde7982006-05-16 15:32:30 +00001137 printf("CFA power mode 1:\n\t%s%s\n", (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001138 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Glenn L McGrath07085852003-10-09 07:28:22 +00001139
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001140 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001141 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001142 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001143 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001144 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001145 }
1146 }
1147
Rob Landleyadde7982006-05-16 15:32:30 +00001148 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001149}
1150#endif
1151
Eric Andersen3443bd72003-07-22 07:30:36 +00001152// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1153// then the HDIO_GET_IDENTITY only returned 142 bytes.
1154// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1155// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1156// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1157// (which they should, but they should just return -EINVAL).
1158//
1159// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1160// On a really old system, it will not, and we will be confused.
1161// Too bad, really.
1162
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001163#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko91303402007-10-30 19:36:54 +00001164static const char cfg_str[] ALIGN1 =
Denis Vlasenko6b404432008-01-07 16:13:14 +00001165 """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
1166 "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
1167 "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1168 "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
Denis Vlasenko91303402007-10-30 19:36:54 +00001169;
Eric Andersen3443bd72003-07-22 07:30:36 +00001170
Denis Vlasenko91303402007-10-30 19:36:54 +00001171static const char BuffType[] ALIGN1 =
1172 "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
1173;
Eric Andersen3443bd72003-07-22 07:30:36 +00001174
Rob Landleya3e4f382006-04-29 16:06:31 +00001175static void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001176{
1177 int i;
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00001178 const unsigned short *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001179
Glenn L McGrath07085852003-10-09 07:28:22 +00001180 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1181 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001182 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001183 if (id->config & (1<<i))
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001184 printf(" %s", nth_string(cfg_str, i));
Rob Landleyadde7982006-05-16 15:32:30 +00001185 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001186 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Rob Landleyadde7982006-05-16 15:32:30 +00001187 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
Glenn L McGrath07085852003-10-09 07:28:22 +00001188 id->cyls, id->heads, id->sectors, id->track_bytes,
Rob Landleyadde7982006-05-16 15:32:30 +00001189 id->sector_bytes, id->ecc_bytes,
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001190 id->buf_type, nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
Rob Landleyadde7982006-05-16 15:32:30 +00001191 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001192 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001193 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001194 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001195 printf("?%u?", id->multsect);
1196 else if (id->multsect)
1197 printf("%u", id->multsect);
1198 else
1199 printf("off");
1200 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001201 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001202
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001203 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001204 printf(" (maybe):");
1205
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001206 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001207 id->cur_sectors,
1208 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001209 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1210 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001211 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001212
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001213 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001214 printf(", LBAsects=%u", id->lba_capacity);
1215
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001216 printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ? "on/off" : "yes" : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001217
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001218 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001219 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001220
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001221 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001222 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1223
1224 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001225 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001226 printf("pio0 ");
1227 if (id->tPIO >= 1) printf("pio1 ");
1228 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001229 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001230 if (id->field_valid & 2) {
Rob Landleyade7f952006-05-25 18:53:06 +00001231 if (id->eide_pio_modes & 1) printf("pio3 ");
1232 if (id->eide_pio_modes & 2) printf("pio4 ");
1233 if (id->eide_pio_modes &~3) printf("pio? ");
1234 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001235 if (id->capability & 1) {
1236 if (id->dma_1word | id->dma_mword) {
Rob Landleyade7f952006-05-25 18:53:06 +00001237 printf("\n DMA modes: ");
1238 if (id->dma_1word & 0x100) printf("*");
1239 if (id->dma_1word & 1) printf("sdma0 ");
1240 if (id->dma_1word & 0x200) printf("*");
1241 if (id->dma_1word & 2) printf("sdma1 ");
1242 if (id->dma_1word & 0x400) printf("*");
1243 if (id->dma_1word & 4) printf("sdma2 ");
1244 if (id->dma_1word & 0xf800) printf("*");
1245 if (id->dma_1word & 0xf8) printf("sdma? ");
1246 if (id->dma_mword & 0x100) printf("*");
1247 if (id->dma_mword & 1) printf("mdma0 ");
1248 if (id->dma_mword & 0x200) printf("*");
1249 if (id->dma_mword & 2) printf("mdma1 ");
1250 if (id->dma_mword & 0x400) printf("*");
1251 if (id->dma_mword & 4) printf("mdma2 ");
1252 if (id->dma_mword & 0xf800) printf("*");
1253 if (id->dma_mword & 0xf8) printf("mdma? ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001254 }
1255 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001256 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Rob Landleyade7f952006-05-25 18:53:06 +00001257 printf("\n UDMA modes: ");
1258 if (id->dma_ultra & 0x100) printf("*");
1259 if (id->dma_ultra & 0x001) printf("udma0 ");
1260 if (id->dma_ultra & 0x200) printf("*");
1261 if (id->dma_ultra & 0x002) printf("udma1 ");
1262 if (id->dma_ultra & 0x400) printf("*");
1263 if (id->dma_ultra & 0x004) printf("udma2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001264#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001265 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001266#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001267 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001268#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001269 if (id->dma_ultra & 0x0800) printf("*");
1270 if (id->dma_ultra & 0x0008) printf("udma3 ");
1271 if (id->dma_ultra & 0x1000) printf("*");
1272 if (id->dma_ultra & 0x0010) printf("udma4 ");
1273 if (id->dma_ultra & 0x2000) printf("*");
1274 if (id->dma_ultra & 0x0020) printf("udma5 ");
1275 if (id->dma_ultra & 0x4000) printf("*");
1276 if (id->dma_ultra & 0x0040) printf("udma6 ");
1277 if (id->dma_ultra & 0x8000) printf("*");
1278 if (id->dma_ultra & 0x0080) printf("udma7 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001279 }
1280 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001281 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001282 if (id_regs[83] & 8) {
1283 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001284 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001285 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001286 printf(": unknown setting");
1287 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001288 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001289 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001290 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001291 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001292#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001293 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1294 || (id->major_rev_num && id->minor_rev_num <= 31)
1295 ) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001296 printf("\n Drive conforms to: %s: ", (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
Rob Landley026147a2006-04-17 22:29:13 +00001297 if (id->major_rev_num != 0x0000 && /* NOVAL_0 */
1298 id->major_rev_num != 0xFFFF) { /* NOVAL_1 */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001299 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001300 if (id->major_rev_num & (1<<i))
1301 printf(" ATA/ATAPI-%u", i);
1302 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001303 }
1304 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001305#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001306 printf("\n\n * current active mode\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001307}
1308#endif
1309
Denis Vlasenko892536f2007-09-27 10:23:34 +00001310static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001311{
Rob Landleya3e4f382006-04-29 16:06:31 +00001312 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001313 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001314#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001315 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001316 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1317 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1318 bb_perror_msg("HDIO_DRIVE_CMD");
1319 else
1320 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1321 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001322#endif
1323}
1324
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001325static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001326{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001327 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001328}
1329
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001330static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001331{
Rob Landleyadde7982006-05-16 15:32:30 +00001332 int i;
1333
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001334 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001335 /* access all sectors of buf to ensure the read fully completed */
1336 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1337 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001338}
1339
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001340static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001341{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001342 union {
1343 unsigned long long blksize64;
1344 unsigned blksize32;
1345 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001346
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001347 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1348 u.blksize64 /= (1024 * 1024);
1349 } else {
1350 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1351 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001352 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001353 if (u.blksize64 > UINT_MAX)
1354 return UINT_MAX;
1355 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001356}
Eric Andersen50af12d2003-08-06 08:47:59 +00001357
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001358static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001359{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001360 unsigned sec = elapsed_us / 1000000;
1361 unsigned hs = (elapsed_us % 1000000) / 10000;
1362
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001363 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001364 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001365 /* "| 1" prevents div-by-0 */
1366 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001367 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001368 // = kb / elapsed_sec
1369 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001370}
1371
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001372static void do_time(int cache /*,int fd*/)
1373/* cache=1: time cache: repeatedly read N MB at offset 0
1374 * cache=0: time device: linear read, starting at offset 0
1375 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001376{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001377 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001378 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001379 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001380 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001381 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001382
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001383 if (mlock(buf, TIMING_BUF_BYTES))
1384 bb_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001385
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001386 /* Clear out the device request queues & give them time to complete.
1387 * NB: *small* delay. User is expected to have a clue and to not run
1388 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001389 sync();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001390 sleep(1);
1391 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001392 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001393 read_big_block(buf);
1394 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001395 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001396 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001397 }
1398 fflush(stdout);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001399
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001400 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001401 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001402 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001403 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001404 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001405 max_iterations = UINT_MAX;
1406 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001407 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001408 /* Don't want to read past the end! */
1409 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1410 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001411 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001412 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001413 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001414 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001415 read_big_block(buf);
1416 elapsed = (unsigned)monotonic_us() - start;
1417 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001418 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001419 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001420 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1421 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001422 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001423 * from elapsed */
1424 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001425 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001426 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001427 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001428 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001429 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001430 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001431 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001432 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001433 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001434 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001435 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001436 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001437}
1438
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001439#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001440static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001441{
Rob Landleyadde7982006-05-16 15:32:30 +00001442 if (value == BUSSTATE_ON)
1443 on_off(1);
1444 else if (value == BUSSTATE_OFF)
1445 on_off(0);
1446 else if (value == BUSSTATE_TRISTATE)
1447 printf(" (tristate)\n");
1448 else
1449 printf(" (unknown: %d)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001450}
1451#endif
1452
1453#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001454static void interpret_standby(uint8_t standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001455{
Rob Landley403777f2006-08-03 20:22:37 +00001456 printf(" (");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001457 if (standby == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001458 printf("off");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001459 } else if (standby <= 240 || standby == 252 || standby == 255) {
1460 /* standby is in 5 sec units */
1461 printf("%u minutes %u seconds", standby / 12, (standby*5) % 60);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001462 } else if (standby <= 251) {
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001463 unsigned t = (standby - 240); /* t is in 30 min units */;
1464 printf("%u.%c hours", t / 2, (t & 1) ? '0' : '5');
1465 }
1466 if (standby == 253)
1467 printf("vendor-specific");
1468 if (standby == 254)
1469 printf("reserved");
Eric Andersen3443bd72003-07-22 07:30:36 +00001470 printf(")\n");
1471}
1472
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001473static const uint8_t xfermode_val[] ALIGN1 = {
1474 8, 9, 10, 11, 12, 13, 14, 15,
1475 16, 17, 18, 19, 20, 21, 22, 23,
1476 32, 33, 34, 35, 36, 37, 38, 39,
1477 64, 65, 66, 67, 68, 69, 70, 71
1478};
1479/* NB: we save size by _not_ storing terninating NUL! */
1480static const char xfermode_name[][5] ALIGN1 = {
1481 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1482 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1483 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1484 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001485};
1486
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001487static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001488{
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001489 int val, i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001490
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001491 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1492 if (!strncmp(name, xfermode_name[i], 5))
1493 if (strlen(name) <= 5)
1494 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001495 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001496 /* Negative numbers are invalid and are caught later */
1497 val = bb_strtoi(name, NULL, 10);
1498 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001499 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001500 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001501}
1502
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001503static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001504{
1505 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001506 if (xfermode == 0)
1507 printf("default PIO mode");
1508 else if (xfermode == 1)
1509 printf("default PIO mode, disable IORDY");
1510 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001511 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001512 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001513 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001514 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001515 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001516 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001517 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001518 else
Denis Vlasenko91303402007-10-30 19:36:54 +00001519 printf("unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +00001520 printf(")\n");
1521}
1522#endif /* HDIO_DRIVE_CMD */
1523
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001524static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001525{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001526 if (flag)
Rob Landleyadde7982006-05-16 15:32:30 +00001527 printf(" setting %s to %ld\n", s, value);
1528}
1529
Rob Landleya3e4f382006-04-29 16:06:31 +00001530static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001531{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001532 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001533 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001534#ifndef HDIO_DRIVE_CMD
1535 int force_operation = 0;
1536#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001537 /* Please restore args[n] to these values after each ioctl
1538 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001539 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001540 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001541
Denis Vlasenko892536f2007-09-27 10:23:34 +00001542 /*fd = xopen(devname, O_RDONLY | O_NONBLOCK);*/
1543 xmove_fd(xopen(devname, O_RDONLY | O_NONBLOCK), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001544 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001545
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001546 if (set_readahead) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001547 print_flag(get_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001548 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001549 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001550#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1551 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001552 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001553 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001554 }
1555#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001556#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
1557 if (scan_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001558 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001559 args[0] = hwif_data;
1560 args[1] = hwif_ctrl;
1561 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001562 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001563 args[0] = WIN_SETFEATURES;
1564 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001565 }
1566#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001567 if (set_piomode) {
1568 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001569 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001570 if (piomode == 255)
Glenn L McGrath07085852003-10-09 07:28:22 +00001571 printf("auto-tune PIO mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001572 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001573 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001574 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001575 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001576 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001577 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001578 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001579 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001580 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001581 if (set_io32bit) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001582 print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001583 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001584 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001585 if (set_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001586 print_flag(get_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001587#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001588 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001589#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001590 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001591#endif
1592 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001593 if (set_readonly) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001594 print_flag_on_off(get_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001595 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001596 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001597 if (set_unmask) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001598 print_flag_on_off(get_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001599 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001600 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001601#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1602 if (set_dma) {
Rob Landleyadde7982006-05-16 15:32:30 +00001603 print_flag_on_off(get_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001604 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001605 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001606#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001607#ifdef HDIO_SET_QDMA
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001608 if (set_dma_q) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001609 print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001610 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001611 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001612#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001613 if (set_nowerr) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001614 print_flag_on_off(get_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001615 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001616 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001617 if (set_keep) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001618 print_flag_on_off(get_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001619 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001620 }
1621#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001622 if (set_doorlock) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001623 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001624 args[2] = 0;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001625 print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001626 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001627 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001628 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001629 if (set_dkeep) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001630 /* lock/unlock the drive's "feature" settings */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001631 print_flag_on_off(get_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001632 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001633 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001634 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001635 if (set_defects) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001636 args[2] = defects ? 0x04 : 0x84;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001637 print_flag(get_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001638 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001639 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001640 if (set_prefetch) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001641 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001642 args[2] = 0xab;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001643 print_flag(get_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001644 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001645 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001646 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001647 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001648 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001649 args[2] = 3;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001650 if (get_xfermode) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001651 print_flag(1, "xfermode", xfermode_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001652 interpret_xfermode(xfermode_requested);
1653 }
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_lookahead) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001658 args[2] = lookahead ? 0xaa : 0x55;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001659 print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001660 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001661 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001662 if (set_apmmode) {
Rob Landleyadde7982006-05-16 15:32:30 +00001663 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
1664 args[1] = apmmode; /* sector count register 1-255 */
1665 if (get_apmmode)
1666 printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001667 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001668 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001669 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001670 if (set_wcache) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001671#ifdef DO_FLUSHCACHE
1672#ifndef WIN_FLUSHCACHE
1673#define WIN_FLUSHCACHE 0xe7
1674#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001675#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001676 args[2] = wcache ? 0x02 : 0x82;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001677 print_flag_on_off(get_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001678#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001679 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001680 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001681#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001682 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001683#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001684 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001685 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001686#endif /* DO_FLUSHCACHE */
1687 }
Rob Landley39cf6452006-05-05 16:52:28 +00001688
1689 /* In code below, we do not preserve args[0], but the rest
1690 is preserved, including args[2] */
1691 args[2] = 0;
1692
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001693 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001694#ifndef WIN_STANDBYNOW1
1695#define WIN_STANDBYNOW1 0xE0
1696#endif
1697#ifndef WIN_STANDBYNOW2
1698#define WIN_STANDBYNOW2 0x94
1699#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001700 if (get_standbynow) printf(" issuing standby command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001701 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001702 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001703 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001704 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001705#ifndef WIN_SLEEPNOW1
1706#define WIN_SLEEPNOW1 0xE6
1707#endif
1708#ifndef WIN_SLEEPNOW2
1709#define WIN_SLEEPNOW2 0x99
1710#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001711 if (get_sleepnow) printf(" issuing sleep command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001712 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001713 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001714 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001715 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001716 args[0] = 0xfb;
Rob Landleyadde7982006-05-16 15:32:30 +00001717 if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001718 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001719 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001720 if (set_standby) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001721 args[0] = WIN_SETIDLE1;
1722 args[1] = standby_requested;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001723 if (get_standby) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001724 print_flag(1, "standby", standby_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001725 interpret_standby(standby_requested);
1726 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001727 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001728 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001729 }
1730#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001731 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001732 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001733 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001734 if (-1 == read(fd, buf, sizeof(buf)))
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001735 bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf));
Eric Andersen3443bd72003-07-22 07:30:36 +00001736 }
1737#endif /* HDIO_DRIVE_CMD */
1738
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001739 if (get_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001740 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001741 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001742 if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
Eric Andersen06d4ec22004-03-19 10:53:52 +00001743 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001744 else
1745 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001746 } else if (get_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001747 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001748 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001749 }
1750 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001751 if (get_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001752 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001753 printf(" IO_support\t=%3ld (", parm);
1754 if (parm == 0)
1755 printf("default 16-bit)\n");
1756 else if (parm == 2)
1757 printf("16-bit)\n");
1758 else if (parm == 1)
1759 printf("32-bit)\n");
1760 else if (parm == 3)
1761 printf("32-bit w/sync)\n");
1762 else if (parm == 8)
1763 printf("Request-Queue-Bypass)\n");
1764 else
1765 printf("\?\?\?)\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001766 }
1767 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001768 if (get_unmask) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001769 if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001770 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001771 }
1772
Glenn L McGrath07085852003-10-09 07:28:22 +00001773
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001774#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Rob Landleyade7f952006-05-25 18:53:06 +00001775 if (get_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001776 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001777 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001778 if (parm == 8)
1779 printf(" (DMA-Assisted-PIO)\n");
1780 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001781 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001782 }
1783 }
1784#endif
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001785#ifdef HDIO_GET_QDMA
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001786 if (get_dma_q) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001787 if(!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001788 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001789 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001790#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001791 if (get_keep) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001792 if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001793 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001794 }
1795
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001796 if (get_nowerr) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001797 if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001798 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001799 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001800 if (get_readonly) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001801 if(!ioctl_or_warn(fd, BLKROGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001802 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001803 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001804 if (get_readahead) {
Bernhard Reutner-Fischer46904bf2008-01-19 11:27:11 +00001805 if(!ioctl_or_warn(fd, BLKRAGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001806 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001807 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001808 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001809 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001810 struct hd_geometry g;
1811
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001812 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001813 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Rob Landley2584e9b2006-05-03 20:00:00 +00001814 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001815 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001816 }
1817#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001818 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001819#ifndef WIN_CHECKPOWERMODE1
1820#define WIN_CHECKPOWERMODE1 0xE5
1821#endif
1822#ifndef WIN_CHECKPOWERMODE2
1823#define WIN_CHECKPOWERMODE2 0x98
1824#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001825 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001826
Rob Landleye5b281f2006-04-29 15:49:18 +00001827 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001828 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001829 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001830 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001831 else
1832 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001833 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001834 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001835 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001836
Eric Andersen3443bd72003-07-22 07:30:36 +00001837 printf(" drive state is: %s\n", state);
1838 }
1839#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001840#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1841 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001842 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001843 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001844#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1845#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1846 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001847 args[0] = 0;
1848 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001849 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001850 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001851#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1852#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1853 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001854 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001855
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001856 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1857 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001858 id.multsect = multcount;
1859 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001860 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001861 id.multsect_valid &= ~1;
1862 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001863 } else if (errno == -ENOMSG)
Eric Andersen3443bd72003-07-22 07:30:36 +00001864 printf(" no identification info available\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001865 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001866 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001867 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001868 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001869 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001870
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001871 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001872 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001873
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001874 memset(args1, 0, sizeof(args1));
1875 args1[0] = WIN_IDENTIFY;
1876 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001877 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001878 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00001879 }
1880#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001881#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1882 if (set_busstate) {
1883 if (get_busstate) {
Rob Landleyadde7982006-05-16 15:32:30 +00001884 print_flag(1, "bus state", busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001885 bus_state_value(busstate);
1886 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001887 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001888 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001889 if (get_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001890 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001891 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001892 bus_state_value(parm);
1893 }
1894 }
1895#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00001896 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001897 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00001898
Eric Andersen3443bd72003-07-22 07:30:36 +00001899 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001900 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00001901 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001902 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001903 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001904 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00001905 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00001906}
1907
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001908#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00001909static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00001910{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001911 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00001912 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001913 if (c >= 'a' && c <= 'f')
1914 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00001915 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1916}
1917
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001918static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00001919static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001920{
Rob Landley0753f4a2006-06-07 00:27:25 +00001921 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001922 unsigned char buf[1280];
1923 unsigned char *b = (unsigned char *)buf;
1924 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001925
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001926 xread(0, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00001927
Rob Landley0753f4a2006-06-07 00:27:25 +00001928 // Convert the newline-separated hex data into an identify block.
1929
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001930 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00001931 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001932 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001933 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00001934 }
Rob Landley0753f4a2006-06-07 00:27:25 +00001935
1936 // Parse the data.
1937
Rob Landley6389ff12006-05-01 19:28:53 +00001938 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001939}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001940#else
1941void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00001942#endif
1943
Rob Landley20deab02006-05-07 23:34:15 +00001944/* busybox specific stuff */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001945static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00001946{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001947 if (get) {
1948 *get = 1;
1949 }
1950 if (optarg) {
1951 *set = 1;
Denis Vlasenko13858992006-10-08 12:49:22 +00001952 *value = xatol_range(optarg, min, max);
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001953 }
Rob Landley20deab02006-05-07 23:34:15 +00001954}
1955
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001956static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00001957{
1958 if (flag) {
Rob Landleyade7f952006-05-25 18:53:06 +00001959 *get = 1;
Rob Landley20deab02006-05-07 23:34:15 +00001960 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001961 *value = translate_xfermode(optarg);
1962 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00001963 }
1964 }
1965}
1966
Rob Landley06208412006-05-31 22:52:57 +00001967/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001968static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00001969 "gfu::n::p:r::m::c::k::a::B:tT"
Rob Landley06208412006-05-31 22:52:57 +00001970 USE_FEATURE_HDPARM_GET_IDENTITY("iI")
Rob Landley20deab02006-05-07 23:34:15 +00001971 USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
1972#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001973 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00001974#endif
1975 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
1976#ifdef HDIO_GET_QDMA
1977#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001978 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00001979#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001980 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00001981#endif
1982#endif
1983 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
1984 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
1985 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
1986/*-------------------------------------*/
1987
1988/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001989int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00001990int hdparm_main(int argc, char **argv)
1991{
1992 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00001993 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00001994
Rob Landley06208412006-05-31 22:52:57 +00001995 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00001996 flagcount++;
Mike Frysingerea93f8a2006-06-07 14:25:22 +00001997 USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
1998 USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00001999 get_geom |= (c == 'g');
2000 do_flush |= (c == 'f');
Rob Landley19802562006-05-08 15:35:46 +00002001 if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
2002 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
2003 if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002004 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Rob Landley19802562006-05-08 15:35:46 +00002005 if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
2006 if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
2007 if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
2008 if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
2009 if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
2010 if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002011 do_flush |= do_timings |= (c == 't');
2012 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002013#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00002014 if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, 255);
Rob Landley19802562006-05-08 15:35:46 +00002015 if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
2016 if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
Rob Landleyade7f952006-05-25 18:53:06 +00002017 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Rob Landley19802562006-05-08 15:35:46 +00002018 if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
2019 if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
2020 if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
2021 if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
Rob Landleyade7f952006-05-25 18:53:06 +00002022 get_powermode |= (c == 'C');
2023 get_standbynow = set_standbynow |= (c == 'y');
2024 get_sleepnow = set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002025 reread_partn |= (c == 'z');
Rob Landleyade7f952006-05-25 18:53:06 +00002026 get_seagate = set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002027#endif
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002028 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
Rob Landley20deab02006-05-07 23:34:15 +00002029#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002030 if (c == 'Q') {
Rob Landley20deab02006-05-07 23:34:15 +00002031#ifdef HDIO_SET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002032 parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00002033#else
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002034 parse_opts(&get_dma_q, NULL, NULL, 0, 0);
Rob Landley20deab02006-05-07 23:34:15 +00002035#endif
Rob Landley19802562006-05-08 15:35:46 +00002036 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002037#endif
Rob Landleyade7f952006-05-25 18:53:06 +00002038 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002039 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
2040 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002041#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2042 if (c == 'R') {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002043 parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
Denis Vlasenko13858992006-10-08 12:49:22 +00002044 hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
2045 hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002046 /* Move past the 2 additional arguments */
2047 argv += 2;
2048 argc -= 2;
2049 }
2050#endif
2051 }
Rob Landleyade7f952006-05-25 18:53:06 +00002052 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002053 if (!flagcount) {
Rob Landleyade7f952006-05-25 18:53:06 +00002054 get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
2055 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
2056 }
Rob Landley20deab02006-05-07 23:34:15 +00002057 argv += optind;
2058
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002059 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002060 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2061 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002062 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002063 }
2064
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002065 do {
2066 process_dev(*argv++);
2067 } while (*argv);
2068
2069 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002070}