blob: 9738620fd86cb80b5971bec9d4d686613a70de6a [file] [log] [blame]
Eric Andersen3443bd72003-07-22 07:30:36 +00001/* vi: set sw=4 ts=4: */
2/*
3 * hdparm implementation for busybox
4 *
Glenn L McGrath5be6a202003-11-28 22:55:03 +00005 * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
Glenn L McGrath07085852003-10-09 07:28:22 +00006 * Hacked by Tito <farmatito@tiscali.it> for size optimization.
Eric Andersen3443bd72003-07-22 07:30:36 +00007 *
Mike Frysingerf284c762006-04-16 20:38:26 +00008 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen3443bd72003-07-22 07:30:36 +00009 *
10 * This program is based on the source code of hdparm: see below...
11 * hdparm.c - Command line interface to get/set hard disk parameters
12 * - by Mark Lord (C) 1994-2002 -- freely distributable
13 */
Denys Vlasenko860d2bb2009-07-10 18:37:06 +020014#include "libbb.h"
15/* must be _after_ libbb.h: */
Eric Andersen3443bd72003-07-22 07:30:36 +000016#include <linux/hdreg.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +020017#include <sys/mount.h>
Denys Vlasenkoaf3fd142009-09-22 23:16:39 +020018#if !defined(BLKGETSIZE64)
19# define BLKGETSIZE64 _IOR(0x12,114,size_t)
20#endif
Eric Andersen3443bd72003-07-22 07:30:36 +000021
Eric Andersen3443bd72003-07-22 07:30:36 +000022/* device types */
23/* ------------ */
24#define NO_DEV 0xffff
25#define ATA_DEV 0x0000
26#define ATAPI_DEV 0x0001
27
28/* word definitions */
29/* ---------------- */
30#define GEN_CONFIG 0 /* general configuration */
31#define LCYLS 1 /* number of logical cylinders */
32#define CONFIG 2 /* specific configuration */
33#define LHEADS 3 /* number of logical heads */
34#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
35#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
36#define LSECTS 6 /* number of logical sectors/track */
37#define START_SERIAL 10 /* ASCII serial number */
38#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
39#define BUF_TYPE 20 /* buffer type (ATA-1) */
40#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
41#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
42#define START_FW_REV 23 /* ASCII firmware revision */
43#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000044#define START_MODEL 27 /* ASCII model number */
45#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000046#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +000047#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
48#define CAPAB_0 49 /* capabilities */
49#define CAPAB_1 50
50#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
51#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
52#define WHATS_VALID 53 /* what fields are valid */
53#define LCYLS_CUR 54 /* current logical cylinders */
54#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000055#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +000056#define CAPACITY_LSB 57 /* current capacity in sectors */
57#define CAPACITY_MSB 58
58#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
59#define LBA_SECTS_LSB 60 /* LBA: total number of user */
60#define LBA_SECTS_MSB 61 /* addressable sectors */
61#define SINGLE_DMA 62 /* singleword DMA modes */
62#define MULTI_DMA 63 /* multiword DMA modes */
63#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
64 /* multiword DMA xfer cycle time: */
65#define DMA_TIME_MIN 65 /* - minimum */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +000066#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
Eric Andersen3443bd72003-07-22 07:30:36 +000067 /* minimum PIO xfer cycle time: */
68#define PIO_NO_FLOW 67 /* - without flow control */
69#define PIO_FLOW 68 /* - with IORDY flow control */
70#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
71#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
72#define CDR_MAJOR 73 /* CD ROM: major version number */
73#define CDR_MINOR 74 /* CD ROM: minor version number */
74#define QUEUE_DEPTH 75 /* queue depth */
75#define MAJOR 80 /* major version number */
76#define MINOR 81 /* minor version number */
77#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
78#define CMDS_SUPP_1 83
79#define CMDS_SUPP_2 84
80#define CMDS_EN_0 85 /* command/feature set(s) enabled */
81#define CMDS_EN_1 86
82#define CMDS_EN_2 87
83#define ULTRA_DMA 88 /* ultra DMA modes */
84 /* time to complete security erase */
85#define ERASE_TIME 89 /* - ordinary */
86#define ENH_ERASE_TIME 90 /* - enhanced */
87#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +000088 in low byte, 0x40 in high byte. */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +000089#define PSWD_CODE 92 /* master password revision code */
Eric Andersen3443bd72003-07-22 07:30:36 +000090#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000091#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +000092#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
93#define LBA_MID 101 /* bits are used, but addr 103 */
94#define LBA_48_MSB 102 /* has been reserved for LBA in */
95#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000096#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +000097#define SECU_STATUS 128 /* security status */
98#define CFA_PWR_MODE 160 /* CFA power mode 1 */
99#define START_MEDIA 176 /* media serial number */
100#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
101#define START_MANUF 196 /* media manufacturer I.D. */
102#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
103#define INTEGRITY 255 /* integrity word */
104
105/* bit definitions within the words */
106/* -------------------------------- */
107
108/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
109#define VALID 0xc000
110#define VALID_VAL 0x4000
111/* many words are considered invalid if they are either all-0 or all-1 */
112#define NOVAL_0 0x0000
113#define NOVAL_1 0xffff
114
115/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000116#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000117#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
118#define MEDIA_REMOVABLE 0x0080
119#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
120#define INCOMPLETE 0x0004
121#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
122#define DRQ_RESPONSE_TIME 0x0060
123#define DRQ_3MS_VAL 0x0000
124#define DRQ_INTR_VAL 0x0020
125#define DRQ_50US_VAL 0x0040
126#define PKT_SIZE_SUPPORTED 0x0003
127#define PKT_SIZE_12_VAL 0x0000
128#define PKT_SIZE_16_VAL 0x0001
129#define EQPT_TYPE 0x1f00
130#define SHIFT_EQPT 8
131
132#define CDROM 0x0005
133
Eric Andersen3443bd72003-07-22 07:30:36 +0000134/* word 1: number of logical cylinders */
135#define LCYLS_MAX 0x3fff /* maximum allowable value */
136
Eric Andersenaff114c2004-04-14 17:51:38 +0000137/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000138 * (a) require SET FEATURES to spin-up
139 * (b) require spin-up to fully reply to IDENTIFY DEVICE
140 */
141#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
142#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000143#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000144#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
145
146/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
147#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
148#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
149
150/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000151#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000152#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
153#define IORDY_OFF 0x0400 /* 1=may be disabled */
154#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
155#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
156#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
157#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
158#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
159#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
160
161/* word 50: capabilities 1 */
162#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
163
164/* words 51 & 52: PIO & DMA cycle times */
165#define MODE 0xff00 /* the mode is in the MSBs */
166
167/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000168#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000169#define OK_W64_70 0x0002 /* see above for word descriptions */
170#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
171
172/*word 63,88: dma_mode, ultra_dma_mode*/
173#define MODE_MAX 7 /* bit definitions force udma <=7 (when
174 * udma >=8 comes out it'll have to be
175 * defined in a new dma_mode word!) */
176
177/* word 64: PIO transfer modes */
178#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
179#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
180
181/* word 75: queue_depth */
182#define DEPTH_BITS 0x001f /* bits used for queue depth */
183
184/* words 80-81: version numbers */
185/* NOVAL_0 or NOVAL_1 means device does not report version */
186
187/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000188#define MINOR_MAX 0x22
Eric Andersen3443bd72003-07-22 07:30:36 +0000189/* words 82-84: cmds/feats supported */
190#define CMDS_W82 0x77ff /* word 82: defined command locations*/
191#define CMDS_W83 0x3fff /* word 83: defined command locations*/
192#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000193#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000194#define NUM_CMD_FEAT_STR 48
195
Eric Andersen3443bd72003-07-22 07:30:36 +0000196/* words 85-87: cmds/feats enabled */
197/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000198 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000199 */
200
201/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000202#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000203
204/* word 92: master password revision */
205/* NOVAL_0 or NOVAL_1 means no support for master password revision */
206
207/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000208#define CBLID 0x2000 /* CBLID status */
209#define RST0 0x0001 /* 1=reset to device #0 */
210#define DEV_DET 0x0006 /* how device num determined */
211#define JUMPER_VAL 0x0002 /* device num determined by jumper */
212#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000213
214/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000215#define RM_STAT_BITS 0x0003
216#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000217
Eric Andersen3443bd72003-07-22 07:30:36 +0000218/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000219#define SECU_ENABLED 0x0002
220#define SECU_LEVEL 0x0010
221#define NUM_SECU_STR 6
Eric Andersen3443bd72003-07-22 07:30:36 +0000222
223/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000224#define VALID_W160 0x8000 /* 1=word valid */
225#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
226#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
227#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000228
229/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000230#define SIG 0x00ff /* signature location */
231#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000232
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000233#define TIMING_BUF_MB 1
234#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000235
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000236#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000237
Denis Vlasenko892536f2007-09-27 10:23:34 +0000238
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200239#define IS_GET 1
240#define IS_SET 2
241
242
Denis Vlasenko892536f2007-09-27 10:23:34 +0000243enum { fd = 3 };
244
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000245
246struct globals {
247 smallint get_identity, get_geom;
248 smallint do_flush;
249 smallint do_ctimings, do_timings;
250 smallint reread_partn;
251 smallint set_piomode, noisy_piomode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200252 smallint getset_readahead;
253 smallint getset_readonly;
254 smallint getset_unmask;
255 smallint getset_mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000256#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200257 smallint getset_dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000258#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200259 smallint getset_nowerr;
260 smallint getset_keep;
261 smallint getset_io32bit;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000262 int piomode;
263 unsigned long Xreadahead;
264 unsigned long readonly;
265 unsigned long unmask;
266 unsigned long mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000267#ifdef HDIO_SET_QDMA
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000268 unsigned long dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000269#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000270 unsigned long nowerr;
271 unsigned long keep;
272 unsigned long io32bit;
273#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
274 unsigned long dma;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200275 smallint getset_dma;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000276#endif
277#ifdef HDIO_DRIVE_CMD
278 smallint set_xfermode, get_xfermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200279 smallint getset_dkeep;
280 smallint getset_standby;
281 smallint getset_lookahead;
282 smallint getset_prefetch;
283 smallint getset_defects;
284 smallint getset_wcache;
285 smallint getset_doorlock;
286 smallint set_seagate;
287 smallint set_standbynow;
288 smallint set_sleepnow;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000289 smallint get_powermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200290 smallint getset_apmmode;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000291 int xfermode_requested;
292 unsigned long dkeep;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000293 unsigned long standby_requested; /* 0..255 */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000294 unsigned long lookahead;
295 unsigned long prefetch;
296 unsigned long defects;
297 unsigned long wcache;
298 unsigned long doorlock;
299 unsigned long apmmode;
300#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000301 IF_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200302 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint getset_busstate;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000303 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
304 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
305 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
306 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
307 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
308 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
309 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000310#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
311 unsigned long hwif_data;
312 unsigned long hwif_ctrl;
313 unsigned long hwif_irq;
314#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000315#ifdef DO_FLUSHCACHE
316 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
317#endif
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100318} FIX_ALIASING;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000319#define G (*(struct globals*)&bb_common_bufsiz1)
320struct BUG_G_too_big {
321 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
322};
323#define get_identity (G.get_identity )
324#define get_geom (G.get_geom )
325#define do_flush (G.do_flush )
326#define do_ctimings (G.do_ctimings )
327#define do_timings (G.do_timings )
328#define reread_partn (G.reread_partn )
329#define set_piomode (G.set_piomode )
330#define noisy_piomode (G.noisy_piomode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200331#define getset_readahead (G.getset_readahead )
332#define getset_readonly (G.getset_readonly )
333#define getset_unmask (G.getset_unmask )
334#define getset_mult (G.getset_mult )
335#define getset_dma_q (G.getset_dma_q )
336#define getset_nowerr (G.getset_nowerr )
337#define getset_keep (G.getset_keep )
338#define getset_io32bit (G.getset_io32bit )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000339#define piomode (G.piomode )
340#define Xreadahead (G.Xreadahead )
341#define readonly (G.readonly )
342#define unmask (G.unmask )
343#define mult (G.mult )
344#define dma_q (G.dma_q )
345#define nowerr (G.nowerr )
346#define keep (G.keep )
347#define io32bit (G.io32bit )
348#define dma (G.dma )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200349#define getset_dma (G.getset_dma )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000350#define set_xfermode (G.set_xfermode )
351#define get_xfermode (G.get_xfermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200352#define getset_dkeep (G.getset_dkeep )
353#define getset_standby (G.getset_standby )
354#define getset_lookahead (G.getset_lookahead )
355#define getset_prefetch (G.getset_prefetch )
356#define getset_defects (G.getset_defects )
357#define getset_wcache (G.getset_wcache )
358#define getset_doorlock (G.getset_doorlock )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000359#define set_seagate (G.set_seagate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000360#define set_standbynow (G.set_standbynow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000361#define set_sleepnow (G.set_sleepnow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000362#define get_powermode (G.get_powermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200363#define getset_apmmode (G.getset_apmmode )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000364#define xfermode_requested (G.xfermode_requested )
365#define dkeep (G.dkeep )
366#define standby_requested (G.standby_requested )
367#define lookahead (G.lookahead )
368#define prefetch (G.prefetch )
369#define defects (G.defects )
370#define wcache (G.wcache )
371#define doorlock (G.doorlock )
372#define apmmode (G.apmmode )
373#define get_IDentity (G.get_IDentity )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200374#define getset_busstate (G.getset_busstate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000375#define perform_reset (G.perform_reset )
376#define perform_tristate (G.perform_tristate )
377#define unregister_hwif (G.unregister_hwif )
378#define scan_hwif (G.scan_hwif )
379#define busstate (G.busstate )
380#define tristate (G.tristate )
381#define hwif (G.hwif )
382#define hwif_data (G.hwif_data )
383#define hwif_ctrl (G.hwif_ctrl )
384#define hwif_irq (G.hwif_irq )
385
386
Glenn L McGrath07085852003-10-09 07:28:22 +0000387/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000388#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000389static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000390{
391 if (!ioctl(fd, cmd, args))
392 return 0;
393 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000394 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000395}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000396#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000397#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000398static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000399{
400 if (!ioctl(fd, cmd, args))
401 return 0;
402 args[0] = alt;
403 return bb_ioctl_or_warn(fd, cmd, args);
404}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000405#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000406#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000407
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000408static void on_off(int value)
409{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000410 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000411}
Glenn L McGrath07085852003-10-09 07:28:22 +0000412
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000413static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000414{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000415 if (get_arg) {
Rob Landleyadde7982006-05-16 15:32:30 +0000416 printf(" setting %s to %ld", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000417 on_off(arg);
418 }
419}
420
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000421static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000422{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000423 printf(" %s\t= %2ld", str, argp);
424 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000425}
Eric Andersen416c2422003-12-12 00:08:57 +0000426
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000427#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000428static void print_ascii(const char *p, int length)
429{
430#if BB_BIG_ENDIAN
431#define LE_ONLY(x)
432 enum { ofs = 0 };
433#else
434#define LE_ONLY(x) x
435 /* every 16bit word is big-endian (i.e. inverted) */
436 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
437 int ofs = 1;
438#endif
439
440 length *= 2;
441 /* find first non-space & print it */
442 while (length && p[ofs] != ' ') {
443 p++;
444 LE_ONLY(ofs = -ofs;)
445 length--;
446 }
447 while (length && p[ofs]) {
448 bb_putchar(p[ofs]);
449 p++;
450 LE_ONLY(ofs = -ofs;)
451 length--;
452 }
453 bb_putchar('\n');
454#undef LE_ONLY
455}
Glenn L McGrath07085852003-10-09 07:28:22 +0000456
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000457static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000458{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000459 if (val[i]) {
460 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000461 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000462 }
463}
Glenn L McGrath07085852003-10-09 07:28:22 +0000464
Glenn L McGrath07085852003-10-09 07:28:22 +0000465static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
466{
Eric Andersen3443bd72003-07-22 07:30:36 +0000467 uint16_t ii;
468 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000469
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000470 for (ii = 0; ii <= MODE_MAX; ii++) {
471 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000472 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000473 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000474 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000475 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000476 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000477 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000478
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000479 mode_sup >>= 1;
480 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000481 }
482 return err_dma;
483}
Glenn L McGrath07085852003-10-09 07:28:22 +0000484
Denis Vlasenko91303402007-10-30 19:36:54 +0000485static const char pkt_str[] ALIGN1 =
486 "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
487 "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
488 "Printer" "\0" /* word 0, bits 12-8 = 02 */
489 "Processor" "\0" /* word 0, bits 12-8 = 03 */
490 "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
491 "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
492 "Scanner" "\0" /* word 0, bits 12-8 = 06 */
493 "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
494 "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
495 "Communications device" "\0" /* word 0, bits 12-8 = 09 */
496 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
497 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
498 "Array controller" "\0" /* word 0, bits 12-8 = 0c */
499 "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
500 "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
501 "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
502;
503
504static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
505 "reserved" "\0" /* bit 0 */
506 "hard sectored" "\0" /* bit 1 */
507 "soft sectored" "\0" /* bit 2 */
508 "not MFM encoded " "\0" /* bit 3 */
509 "head switch time > 15us" "\0" /* bit 4 */
510 "spindle motor control option" "\0" /* bit 5 */
511 "fixed drive" "\0" /* bit 6 */
512 "removable drive" "\0" /* bit 7 */
513 "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
514 "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
515 "disk xfer rate > 5Mbs" "\0" /* bit 10 */
516 "rotational speed tol." "\0" /* bit 11 */
517 "data strobe offset option" "\0" /* bit 12 */
518 "track offset option" "\0" /* bit 13 */
519 "format speed tolerance gap reqd" "\0" /* bit 14 */
520 "ATAPI" /* bit 14 */
521;
522
523static const char minor_str[] ALIGN1 =
524 /* word 81 value: */
525 "Unspecified" "\0" /* 0x0000 */
526 "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
527 "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
528 "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
529 "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
530 "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
531 "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
532 "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
533 "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
534 "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
535 "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
536 "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
537 "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
538 "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
539 "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
540 "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
541 "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
542 "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
543 "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
544 "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
545 "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
546 "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
547 "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
548 "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
549 "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
550 "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
551 "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
552 "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
553 "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
554 "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
555 "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
556 "reserved" "\0" /* 0x001f */
557 "reserved" "\0" /* 0x0020 */
558 "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
559 "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
560 "reserved" /* 0x0023-0xfffe */
561;
562static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
563 /* word 81 value: */
564 0, /* 0x0000 WARNING: actual_ver[] array */
565 1, /* 0x0001 WARNING: corresponds */
566 1, /* 0x0002 WARNING: *exactly* */
567 1, /* 0x0003 WARNING: to the ATA/ */
568 2, /* 0x0004 WARNING: ATAPI version */
569 2, /* 0x0005 WARNING: listed in */
570 3, /* 0x0006 WARNING: the */
571 2, /* 0x0007 WARNING: minor_str */
572 3, /* 0x0008 WARNING: array */
573 2, /* 0x0009 WARNING: above. */
574 3, /* 0x000a WARNING: */
575 3, /* 0x000b WARNING: If you change */
576 3, /* 0x000c WARNING: that one, */
577 4, /* 0x000d WARNING: change this one */
578 4, /* 0x000e WARNING: too!!! */
579 4, /* 0x000f */
580 4, /* 0x0010 */
581 4, /* 0x0011 */
582 4, /* 0x0012 */
583 5, /* 0x0013 */
584 4, /* 0x0014 */
585 5, /* 0x0015 */
586 5, /* 0x0016 */
587 4, /* 0x0017 */
588 6, /* 0x0018 */
589 6, /* 0x0019 */
590 7, /* 0x001a */
591 6, /* 0x001b */
592 6, /* 0x001c */
593 7, /* 0x001d */
594 7, /* 0x001e */
595 0, /* 0x001f */
596 0, /* 0x0020 */
597 7, /* 0x0021 */
598 6, /* 0x0022 */
599 0 /* 0x0023-0xfffe */
600};
601
602static const char cmd_feat_str[] ALIGN1 =
603 "" "\0" /* word 82 bit 15: obsolete */
604 "NOP cmd" "\0" /* word 82 bit 14 */
605 "READ BUFFER cmd" "\0" /* word 82 bit 13 */
606 "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
607 "" "\0" /* word 82 bit 11: obsolete */
608 "Host Protected Area feature set" "\0" /* word 82 bit 10 */
609 "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
610 "SERVICE interrupt" "\0" /* word 82 bit 8 */
611 "Release interrupt" "\0" /* word 82 bit 7 */
612 "Look-ahead" "\0" /* word 82 bit 6 */
613 "Write cache" "\0" /* word 82 bit 5 */
614 "PACKET command feature set" "\0" /* word 82 bit 4 */
615 "Power Management feature set" "\0" /* word 82 bit 3 */
616 "Removable Media feature set" "\0" /* word 82 bit 2 */
617 "Security Mode feature set" "\0" /* word 82 bit 1 */
618 "SMART feature set" "\0" /* word 82 bit 0 */
619 /* -------------- */
620 "" "\0" /* word 83 bit 15: !valid bit */
621 "" "\0" /* word 83 bit 14: valid bit */
622 "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
623 "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
624 "Device Configuration Overlay feature set " "\0"
625 "48-bit Address feature set " "\0" /* word 83 bit 10 */
626 "" "\0"
627 "SET MAX security extension" "\0" /* word 83 bit 8 */
628 "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
629 "SET FEATURES subcommand required to spinup after power up" "\0"
630 "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
631 "Removable Media Status Notification feature set" "\0"
632 "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
633 "CFA feature set" "\0" /* word 83 bit 2 */
634 "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
635 "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
636 /* -------------- */
637 "" "\0" /* word 84 bit 15: !valid bit */
638 "" "\0" /* word 84 bit 14: valid bit */
639 "" "\0" /* word 84 bit 13: reserved */
640 "" "\0" /* word 84 bit 12: reserved */
641 "" "\0" /* word 84 bit 11: reserved */
642 "" "\0" /* word 84 bit 10: reserved */
643 "" "\0" /* word 84 bit 9: reserved */
644 "" "\0" /* word 84 bit 8: reserved */
645 "" "\0" /* word 84 bit 7: reserved */
646 "" "\0" /* word 84 bit 6: reserved */
647 "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
648 "" "\0" /* word 84 bit 4: reserved */
649 "Media Card Pass Through Command feature set " "\0"
650 "Media serial number " "\0" /* word 84 bit 2 */
651 "SMART self-test " "\0" /* word 84 bit 1 */
652 "SMART error logging " /* word 84 bit 0 */
653;
654
655static const char secu_str[] ALIGN1 =
656 "supported" "\0" /* word 128, bit 0 */
657 "enabled" "\0" /* word 128, bit 1 */
658 "locked" "\0" /* word 128, bit 2 */
659 "frozen" "\0" /* word 128, bit 3 */
660 "expired: security count" "\0" /* word 128, bit 4 */
661 "supported: enhanced erase" /* word 128, bit 5 */
662;
663
664// Parse 512 byte disk identification block and print much crap.
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000665static void identify(uint16_t *val) NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000666static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000667{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000668 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000669 uint16_t like_std = 1, std = 0, min_std = 0xffff;
670 uint16_t dev = NO_DEV, eqpt = NO_DEV;
671 uint8_t have_mode = 0, err_dma = 0;
672 uint8_t chksum = 0;
673 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000674 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000675 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000676#if BB_BIG_ENDIAN
677 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000678
Denis Vlasenko4daad902007-09-27 10:20:47 +0000679 // Adjust for endianness
680 swab(val, buf, sizeof(buf));
681 val = buf;
682#endif
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200683 /* check if we recognize the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000684 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000685 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000686 dev = ATA_DEV;
687 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000688 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000689 dev = ATA_DEV;
690 like_std = 4;
691 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000692 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000693 dev = ATAPI_DEV;
694 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000695 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +0000696 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000697 } else
Denis Vlasenko91303402007-10-30 19:36:54 +0000698 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000699 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000700
Rob Landleyadde7982006-05-16 15:32:30 +0000701 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000702 /* Info from the specific configuration word says whether or not the
703 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000704 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000705 * standards. Since the values allowed for this word are extremely
706 * specific, it should be safe to check it now, even though we don't
707 * know yet what standard this device is using.
708 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000709 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
710 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
711 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000712 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000713 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Rob Landleyadde7982006-05-16 15:32:30 +0000714 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000715 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Rob Landleyadde7982006-05-16 15:32:30 +0000716 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000717 }
718
719 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000720 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
721 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
722 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
723 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
724 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000725
726 /* major & minor standards version number (Note: these words were not
727 * defined until ATA-3 & the CDROM std uses different words.) */
728 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000729 if (eqpt != CDROM) {
730 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000731 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000732 std = actual_ver[val[MINOR]];
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000733 if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
Glenn L McGrath07085852003-10-09 07:28:22 +0000734
Eric Andersen3443bd72003-07-22 07:30:36 +0000735 }
736 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000737 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000738 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000739 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000740 printf("\n\tSupported: ");
741 jj = val[MAJOR] << 1;
742 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000743 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
744 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000745 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000746 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000747 like_std = ii;
748 kk = like_std >4 ? like_std-4: 0;
749 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000750 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000751 }
752 jj <<= 1;
753 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000754 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000755 }
756 /* Figure out what standard the device is using if it hasn't told
757 * us. If we know the std, check if the device is using any of
758 * the words from the next level up. It happens.
759 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000760 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000761
Rob Landleya3e4f382006-04-29 16:06:31 +0000762 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000763 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
764 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
765 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000766 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
767 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000768 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000769 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000770 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000771 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
772 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
773 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
774 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000775 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000776 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000777 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
778 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
779 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
780 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
781 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000782 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
783 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000784 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000785 } else if (((std == 2) || (!std && (like_std < 3)))
786 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
787 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000788 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000789 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000790 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
791 (val[WHATS_VALID] & OK_W64_70)) )
792 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000793 like_std = 2;
794 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000795
Rob Landleya3e4f382006-04-29 16:06:31 +0000796 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000797 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000798 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000799 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000800 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000801 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000802 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000803 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000804 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000805 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000806 kk = 1;
807 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
808 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000809 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000810 kk = 1;
811 printf("\n\tSupported: CD-ROM ATAPI");
812 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000813 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000814 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000815 jj >>= 1;
816 }
817 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000818 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000819 /* the cdrom stuff is more like ATA-2 than anything else, so: */
820 like_std = 2;
821 }
822
Rob Landleya3e4f382006-04-29 16:06:31 +0000823 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000824 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000825
826 printf("Configuration:\n");
827 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000828 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000829 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000830 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000831 if (jj & 0x0001)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000832 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +0000833 jj >>=1;
834 }
835 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000836 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000837 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
838 strng = "3ms";
839 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
840 strng = "<=10ms with INTRQ";
841 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
842 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000843 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000844 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000845 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
846
847 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
848 strng = "12 bytes";
849 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
850 strng = "16 bytes";
851 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000852 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000853 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000854 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000855 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000856 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200857 mm = 0;
858 bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000859 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000860 printf("\tCHS addressing not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000861 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000862 jj = val[WHATS_VALID] & OK_W54_58;
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200863 printf("\tLogical\t\tmax\tcurrent\n"
864 "\tcylinders\t%u\t%u\n"
865 "\theads\t\t%u\t%u\n"
866 "\tsectors/track\t%u\t%u\n"
867 "\t--\n",
868 val[LCYLS],
869 jj ? val[LCYLS_CUR] : 0,
870 val[LHEADS],
871 jj ? val[LHEADS_CUR] : 0,
872 val[LSECTS],
873 jj ? val[LSECTS_CUR] : 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000874
Rob Landleyadde7982006-05-16 15:32:30 +0000875 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200876 printf("\tbytes/track: %u\tbytes/sector: %u\n",
877 val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000878
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000879 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000880 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000881 if (like_std < 3) {
882 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000883 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
884 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000885 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +0000886 mm = oo;
887 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000888 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +0000889 }
Eric Andersen3443bd72003-07-22 07:30:36 +0000890 }
891 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000892 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000893 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
894 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
895 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000896 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
897 (uint64_t)val[LBA_48_MSB] << 32 |
898 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000899 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000900 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +0000901 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000902
903 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +0000904 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000905 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
906 bbbig = (bbbig << 9) / 1000000;
907 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +0000908
Rob Landleyadde7982006-05-16 15:32:30 +0000909 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +0000910 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000911 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000912 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000913 }
914
915 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +0000916 printf("Capabilities:\n\t");
917
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000918 if (dev == ATAPI_DEV) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200919 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP))
920 printf("Cmd queuing, ");
921 if (val[CAPAB_0] & OVLP_SUP)
922 printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +0000923 }
Rob Landleyadde7982006-05-16 15:32:30 +0000924 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +0000925
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000926 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000927 printf("IORDY%s(can%s be disabled)\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200928 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
929 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000930 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000931 printf("no IORDY\n");
932
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000933 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000934 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200935 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
936 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000937 }
Rob Landleyadde7982006-05-16 15:32:30 +0000938
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000939 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000940 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +0000941 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000942 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000943 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000944 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000945 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000946 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +0000947 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000948
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000949 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000950 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000951 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000952 else {
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200953 printf("\tStandby timer values: spec'd by %s",
954 (val[CAPAB_0] & STD_STBY) ? "standard" : "vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +0000955 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200956 printf(", %s device specific minimum\n",
957 (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +0000958 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000959 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000960 }
961 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000962 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Eric Andersen3443bd72003-07-22 07:30:36 +0000963 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000964 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000965 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +0000966 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
967 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
968 else
969 printf("?\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000970 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000971 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000972 /* We print out elsewhere whether the APM feature is enabled or
973 not. If it's not enabled, let's not repeat the info; just print
974 nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +0000975 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000976 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000977 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +0000978 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +0000979 }
980 else
Eric Andersen3443bd72003-07-22 07:30:36 +0000981 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000982 }
Rob Landleyadde7982006-05-16 15:32:30 +0000983 if (like_std > 5 && val[ACOUSTIC]) {
984 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200985 (val[ACOUSTIC] >> 8) & 0x00ff,
986 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:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200995 if (val[PKT_REL])
996 printf(" %uus to release bus.", val[PKT_REL]);
997 if (val[SVC_NBSY])
998 printf(" %uus to clear BSY after SERVICE cmd.",
999 val[SVC_NBSY]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001000 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001001 }
1002 }
1003
1004 /* DMA stuff. Check that only one DMA mode is selected. */
1005 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001006 if (!(val[CAPAB_0] & DMA_SUP))
Eric Andersen3443bd72003-07-22 07:30:36 +00001007 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001008 else {
Rob Landleyadde7982006-05-16 15:32:30 +00001009 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001010 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001011 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001012 jj = val[SINGLE_DMA];
1013 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001014 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001015 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001016 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001017 jj = val[MULTI_DMA];
1018 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001019 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001020 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001021 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001022 jj = val[ULTRA_DMA];
1023 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001024 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001025 }
Rob Landleyadde7982006-05-16 15:32:30 +00001026 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001027 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001028
Rob Landleyadde7982006-05-16 15:32:30 +00001029 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
1030 printf("\t\tInterleaved DMA support\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001031
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001032 if ((val[WHATS_VALID] & OK_W64_70)
1033 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1034 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001035 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001036 if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
1037 if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001038 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001039 }
1040 }
1041
1042 /* Programmed IO stuff */
1043 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001044 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +00001045 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001046 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001047 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001048 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001049 if (jj & 0x0001) printf("pio%d ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +00001050 jj >>=1;
1051 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001052 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001053 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001054 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001055 printf("pio%d ", ii);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001056 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001057 } else
Denis Vlasenko91303402007-10-30 19:36:54 +00001058 puts("unknown");
Glenn L McGrath07085852003-10-09 07:28:22 +00001059
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001060 if (val[WHATS_VALID] & OK_W64_70) {
1061 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001062 printf("\t\tCycle time:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001063 if (val[PIO_NO_FLOW])
1064 printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1065 if (val[PIO_FLOW])
1066 printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001067 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001068 }
1069 }
1070
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001071 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001072 printf("Commands/features:\n"
1073 "\tEnabled\tSupported:\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001074 jj = val[CMDS_SUPP_0];
1075 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001076 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001077 const char *feat_str = nth_string(cmd_feat_str, ii);
Denis Vlasenko91303402007-10-30 19:36:54 +00001078 if ((jj & 0x8000) && (*feat_str != '\0')) {
1079 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
Eric Andersen3443bd72003-07-22 07:30:36 +00001080 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001081 jj <<= 1;
1082 kk <<= 1;
1083 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001084 jj = val[CMDS_SUPP_0+1+(ii/16)];
1085 kk = val[CMDS_EN_0+1+(ii/16)];
1086 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001087 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001088 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +00001089 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001090 }
1091 }
1092 }
Rob Landleyadde7982006-05-16 15:32:30 +00001093 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001094 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001095 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
Glenn L McGrath07085852003-10-09 07:28:22 +00001096
Eric Andersen3443bd72003-07-22 07:30:36 +00001097 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001098 if ((eqpt != CDROM) && (like_std > 3)
1099 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1100 ) {
Rob Landleyade7f952006-05-25 18:53:06 +00001101 printf("Security:\n");
Rob Landleyadde7982006-05-16 15:32:30 +00001102 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001103 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001104 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001105 if (jj) {
1106 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001107 printf("\t%s\t%s\n",
1108 (!(jj & 0x0001)) ? "not" : "",
1109 nth_string(secu_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +00001110 jj >>=1;
1111 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001112 if (val[SECU_STATUS] & SECU_ENABLED) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001113 printf("\tSecurity level %s\n",
1114 (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001115 }
1116 }
1117 jj = val[ERASE_TIME] & ERASE_BITS;
1118 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001119 if (jj || kk) {
Denis Vlasenko7d60fc12008-06-05 06:51:06 +00001120 bb_putchar('\t');
Rob Landleyade7f952006-05-25 18:53:06 +00001121 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1122 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001123 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001124 }
1125 }
1126
1127 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001128 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001129 if ((jj & VALID) == VALID_VAL) {
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001130 oo = (jj & RST0);
1131 if (!oo)
Rob Landleyadde7982006-05-16 15:32:30 +00001132 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001133 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001134 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001135 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001136 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001137 else
Rob Landleyadde7982006-05-16 15:32:30 +00001138 strng = "";
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001139 printf("HW reset results:\n"
1140 "\tCBLID- %s Vih\n"
1141 "\tDevice num = %i%s\n",
1142 (val[HWRST_RSLT] & CBLID) ? "above" : "below",
1143 !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001144 }
1145
1146 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001147 if ((like_std > 4) && (eqpt != CDROM)) {
1148 if (val[CFA_PWR_MODE] & VALID_W160) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001149 printf("CFA power mode 1:\n"
1150 "\t%s%s\n",
1151 (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
1152 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001153 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001154 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001155 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001156 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001157 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001158 }
1159 }
1160
Rob Landleyadde7982006-05-16 15:32:30 +00001161 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001162}
1163#endif
1164
Eric Andersen3443bd72003-07-22 07:30:36 +00001165// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1166// then the HDIO_GET_IDENTITY only returned 142 bytes.
1167// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1168// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1169// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1170// (which they should, but they should just return -EINVAL).
1171//
1172// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1173// On a really old system, it will not, and we will be confused.
1174// Too bad, really.
1175
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001176#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko91303402007-10-30 19:36:54 +00001177static const char cfg_str[] ALIGN1 =
Denis Vlasenko6b404432008-01-07 16:13:14 +00001178 """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
1179 "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
1180 "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1181 "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
Denis Vlasenko91303402007-10-30 19:36:54 +00001182;
Eric Andersen3443bd72003-07-22 07:30:36 +00001183
Denis Vlasenko91303402007-10-30 19:36:54 +00001184static const char BuffType[] ALIGN1 =
1185 "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
1186;
Eric Andersen3443bd72003-07-22 07:30:36 +00001187
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +02001188static NOINLINE void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001189{
1190 int i;
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00001191 const unsigned short *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001192
Glenn L McGrath07085852003-10-09 07:28:22 +00001193 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1194 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001195 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001196 if (id->config & (1<<i))
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001197 printf(" %s", nth_string(cfg_str, i));
Rob Landleyadde7982006-05-16 15:32:30 +00001198 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001199 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001200 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
1201 id->cyls, id->heads, id->sectors, id->track_bytes,
1202 id->sector_bytes, id->ecc_bytes,
1203 id->buf_type,
1204 nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
1205 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001206 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001207 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001208 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001209 printf("?%u?", id->multsect);
1210 else if (id->multsect)
1211 printf("%u", id->multsect);
1212 else
1213 printf("off");
1214 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001215 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001216
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001217 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001218 printf(" (maybe):");
1219
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001220 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001221 id->cur_sectors,
1222 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001223 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1224 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001225 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001226
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001227 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001228 printf(", LBAsects=%u", id->lba_capacity);
1229
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001230 printf("\n IORDY=%s",
1231 (id->capability & 8)
1232 ? ((id->capability & 4) ? "on/off" : "yes")
1233 : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001234
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001235 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001236 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001237
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001238 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001239 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1240
1241 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001242 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001243 printf("pio0 ");
1244 if (id->tPIO >= 1) printf("pio1 ");
1245 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001246 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001247 if (id->field_valid & 2) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001248 static const masks_labels_t pio_modes = {
1249 .masks = { 1, 2, ~3 },
1250 .labels = "pio3 \0""pio4 \0""pio? \0",
1251 };
1252 print_flags(&pio_modes, id->eide_pio_modes);
Rob Landleyade7f952006-05-25 18:53:06 +00001253 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001254 if (id->capability & 1) {
1255 if (id->dma_1word | id->dma_mword) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001256 static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
Rob Landleyade7f952006-05-25 18:53:06 +00001257 printf("\n DMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001258 print_flags_separated(dma_wmode_masks,
1259 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
1260 id->dma_1word, NULL);
1261 print_flags_separated(dma_wmode_masks,
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001262 "*\0""mdma0 \0""*\0""mdma1 \0""*\0""mdma2 \0""*\0""mdma? \0",
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001263 id->dma_mword, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001264 }
1265 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001266 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001267 static const masks_labels_t ultra_modes1 = {
1268 .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
1269 .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
1270 };
Denis Vlasenko7049ff82008-06-25 09:53:17 +00001271
Rob Landleyade7f952006-05-25 18:53:06 +00001272 printf("\n UDMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001273 print_flags(&ultra_modes1, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001274#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001275 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001276#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001277 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001278#endif /* __NEW_HD_DRIVE_ID */
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001279 static const masks_labels_t ultra_modes2 = {
1280 .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
1281 0x2000, 0x0020, 0x4000, 0x0040,
1282 0x8000, 0x0080 },
1283 .labels = "*\0""udma3 \0""*\0""udma4 \0"
1284 "*\0""udma5 \0""*\0""udma6 \0"
1285 "*\0""udma7 \0"
1286 };
1287 print_flags(&ultra_modes2, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001288 }
1289 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001290 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001291 if (id_regs[83] & 8) {
1292 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001293 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001294 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001295 printf(": unknown setting");
1296 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001297 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001298 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001299 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001300 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001301#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001302 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1303 || (id->major_rev_num && id->minor_rev_num <= 31)
1304 ) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001305 printf("\n Drive conforms to: %s: ",
1306 (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
1307 if (id->major_rev_num != 0x0000 /* NOVAL_0 */
1308 && id->major_rev_num != 0xFFFF /* NOVAL_1 */
1309 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001310 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001311 if (id->major_rev_num & (1<<i))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001312 printf(" ATA/ATAPI-%u", i);
Rob Landleyadde7982006-05-16 15:32:30 +00001313 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001314 }
1315 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001316#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001317 printf("\n\n * current active mode\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001318}
1319#endif
1320
Denis Vlasenko892536f2007-09-27 10:23:34 +00001321static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001322{
Rob Landleya3e4f382006-04-29 16:06:31 +00001323 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001324 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001325#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001326 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001327 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1328 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1329 bb_perror_msg("HDIO_DRIVE_CMD");
1330 else
1331 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1332 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001333#endif
1334}
1335
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001336static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001337{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001338 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001339}
1340
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001341static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001342{
Rob Landleyadde7982006-05-16 15:32:30 +00001343 int i;
1344
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001345 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001346 /* access all sectors of buf to ensure the read fully completed */
1347 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1348 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001349}
1350
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001351static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001352{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001353 union {
1354 unsigned long long blksize64;
1355 unsigned blksize32;
1356 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001357
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001358 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1359 u.blksize64 /= (1024 * 1024);
1360 } else {
1361 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1362 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001363 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001364 if (u.blksize64 > UINT_MAX)
1365 return UINT_MAX;
1366 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001367}
Eric Andersen50af12d2003-08-06 08:47:59 +00001368
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001369static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001370{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001371 unsigned sec = elapsed_us / 1000000;
1372 unsigned hs = (elapsed_us % 1000000) / 10000;
1373
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001374 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001375 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001376 /* "| 1" prevents div-by-0 */
1377 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001378 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001379 // = kb / elapsed_sec
1380 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001381}
1382
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001383static void do_time(int cache /*,int fd*/)
1384/* cache=1: time cache: repeatedly read N MB at offset 0
1385 * cache=0: time device: linear read, starting at offset 0
1386 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001387{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001388 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001389 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001390 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001391 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001392 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001393
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001394 if (mlock(buf, TIMING_BUF_BYTES))
1395 bb_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001396
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001397 /* Clear out the device request queues & give them time to complete.
1398 * NB: *small* delay. User is expected to have a clue and to not run
1399 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001400 sync();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001401 sleep(1);
1402 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001403 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001404 read_big_block(buf);
1405 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001406 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001407 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001408 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +01001409 fflush_all();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001410
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001411 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001412 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001413 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001414 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001415 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001416 max_iterations = UINT_MAX;
1417 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001418 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001419 /* Don't want to read past the end! */
1420 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1421 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001422 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001423 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001424 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001425 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001426 read_big_block(buf);
1427 elapsed = (unsigned)monotonic_us() - start;
1428 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001429 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001430 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001431 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1432 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001433 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001434 * from elapsed */
1435 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001436 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001437 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001438 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001439 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001440 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001441 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001442 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001443 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001444 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001445 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001446 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001447 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001448}
1449
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001450#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001451static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001452{
Rob Landleyadde7982006-05-16 15:32:30 +00001453 if (value == BUSSTATE_ON)
1454 on_off(1);
1455 else if (value == BUSSTATE_OFF)
1456 on_off(0);
1457 else if (value == BUSSTATE_TRISTATE)
1458 printf(" (tristate)\n");
1459 else
1460 printf(" (unknown: %d)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001461}
1462#endif
1463
1464#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001465static void interpret_standby(uint8_t standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001466{
Rob Landley403777f2006-08-03 20:22:37 +00001467 printf(" (");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001468 if (standby == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001469 printf("off");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001470 } else if (standby <= 240 || standby == 252 || standby == 255) {
1471 /* standby is in 5 sec units */
Denys Vlasenko2b132e52009-05-20 23:21:42 +02001472 unsigned t = standby * 5;
1473 printf("%u minutes %u seconds", t / 60, t % 60);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001474 } else if (standby <= 251) {
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001475 unsigned t = (standby - 240); /* t is in 30 min units */;
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001476 printf("%u.%c hours", t / 2, (t & 1) ? '5' : '0');
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001477 }
1478 if (standby == 253)
1479 printf("vendor-specific");
1480 if (standby == 254)
1481 printf("reserved");
Eric Andersen3443bd72003-07-22 07:30:36 +00001482 printf(")\n");
1483}
1484
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001485static const uint8_t xfermode_val[] ALIGN1 = {
1486 8, 9, 10, 11, 12, 13, 14, 15,
1487 16, 17, 18, 19, 20, 21, 22, 23,
1488 32, 33, 34, 35, 36, 37, 38, 39,
1489 64, 65, 66, 67, 68, 69, 70, 71
1490};
1491/* NB: we save size by _not_ storing terninating NUL! */
1492static const char xfermode_name[][5] ALIGN1 = {
1493 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1494 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1495 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1496 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001497};
1498
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001499static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001500{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001501 int val;
1502 unsigned i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001503
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001504 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1505 if (!strncmp(name, xfermode_name[i], 5))
1506 if (strlen(name) <= 5)
1507 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001508 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001509 /* Negative numbers are invalid and are caught later */
1510 val = bb_strtoi(name, NULL, 10);
1511 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001512 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001513 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001514}
1515
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001516static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001517{
1518 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001519 if (xfermode == 0)
1520 printf("default PIO mode");
1521 else if (xfermode == 1)
1522 printf("default PIO mode, disable IORDY");
1523 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001524 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001525 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001526 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001527 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001528 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001529 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001530 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001531 else
Denis Vlasenko91303402007-10-30 19:36:54 +00001532 printf("unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +00001533 printf(")\n");
1534}
1535#endif /* HDIO_DRIVE_CMD */
1536
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001537static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001538{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001539 if (flag)
Rob Landleyadde7982006-05-16 15:32:30 +00001540 printf(" setting %s to %ld\n", s, value);
1541}
1542
Rob Landleya3e4f382006-04-29 16:06:31 +00001543static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001544{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001545 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001546 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001547#ifndef HDIO_DRIVE_CMD
1548 int force_operation = 0;
1549#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001550 /* Please restore args[n] to these values after each ioctl
1551 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001552 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001553 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001554
Bernhard Reutner-Fischera4830872009-10-26 23:27:08 +01001555 /*fd = xopen_nonblocking(devname);*/
1556 xmove_fd(xopen_nonblocking(devname), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001557 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001558
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001559 if (getset_readahead == IS_SET) {
1560 print_flag(getset_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001561 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001562 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001563#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1564 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001565 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001566 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001567 }
1568#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001569#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001570 if (scan_hwif == IS_SET) {
Rob Landley20deab02006-05-07 23:34:15 +00001571 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001572 args[0] = hwif_data;
1573 args[1] = hwif_ctrl;
1574 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001575 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001576 args[0] = WIN_SETFEATURES;
1577 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001578 }
1579#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001580 if (set_piomode) {
1581 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001582 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001583 if (piomode == 255)
Glenn L McGrath07085852003-10-09 07:28:22 +00001584 printf("auto-tune PIO mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001585 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001586 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001587 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001588 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001589 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001590 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001591 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001592 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001593 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001594 if (getset_io32bit == IS_SET) {
1595 print_flag(getset_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001596 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001597 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001598 if (getset_mult == IS_SET) {
1599 print_flag(getset_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001600#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001601 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001602#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001603 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001604#endif
1605 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001606 if (getset_readonly == IS_SET) {
1607 print_flag_on_off(getset_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001608 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001609 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001610 if (getset_unmask == IS_SET) {
1611 print_flag_on_off(getset_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001612 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001613 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001614#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001615 if (getset_dma == IS_SET) {
1616 print_flag_on_off(getset_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001617 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001618 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001619#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001620#ifdef HDIO_SET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001621 if (getset_dma_q == IS_SET) {
1622 print_flag_on_off(getset_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001623 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001624 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001625#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001626 if (getset_nowerr == IS_SET) {
1627 print_flag_on_off(getset_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001628 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001629 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001630 if (getset_keep == IS_SET) {
1631 print_flag_on_off(getset_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001632 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001633 }
1634#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001635 if (getset_doorlock == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001636 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001637 args[2] = 0;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001638 print_flag_on_off(getset_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001639 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001640 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001641 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001642 if (getset_dkeep == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001643 /* lock/unlock the drive's "feature" settings */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001644 print_flag_on_off(getset_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001645 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001646 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001647 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001648 if (getset_defects == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001649 args[2] = defects ? 0x04 : 0x84;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001650 print_flag(getset_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001651 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001652 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001653 if (getset_prefetch == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001654 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001655 args[2] = 0xab;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001656 print_flag(getset_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001657 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001658 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001659 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001660 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001661 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001662 args[2] = 3;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001663 print_flag(1, "xfermode", xfermode_requested);
1664 interpret_xfermode(xfermode_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001665 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001666 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001667 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001668 if (getset_lookahead == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001669 args[2] = lookahead ? 0xaa : 0x55;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001670 print_flag_on_off(getset_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001671 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001672 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001673 if (getset_apmmode == IS_SET) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001674 /* feature register */
1675 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */;
Rob Landleyadde7982006-05-16 15:32:30 +00001676 args[1] = apmmode; /* sector count register 1-255 */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001677 printf(" setting APM level to %s 0x%02lX (%ld)\n",
1678 (apmmode == 255) ? "disabled" : "",
1679 apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001680 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001681 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001682 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001683 if (getset_wcache == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001684#ifdef DO_FLUSHCACHE
1685#ifndef WIN_FLUSHCACHE
1686#define WIN_FLUSHCACHE 0xe7
1687#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001688#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001689 args[2] = wcache ? 0x02 : 0x82;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001690 print_flag_on_off(getset_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001691#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001692 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001693 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001694#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001695 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001696#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001697 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001698 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001699#endif /* DO_FLUSHCACHE */
1700 }
Rob Landley39cf6452006-05-05 16:52:28 +00001701
1702 /* In code below, we do not preserve args[0], but the rest
1703 is preserved, including args[2] */
1704 args[2] = 0;
1705
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001706 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001707#ifndef WIN_STANDBYNOW1
1708#define WIN_STANDBYNOW1 0xE0
1709#endif
1710#ifndef WIN_STANDBYNOW2
1711#define WIN_STANDBYNOW2 0x94
1712#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001713 printf(" issuing standby command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001714 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001715 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001716 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001717 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001718#ifndef WIN_SLEEPNOW1
1719#define WIN_SLEEPNOW1 0xE6
1720#endif
1721#ifndef WIN_SLEEPNOW2
1722#define WIN_SLEEPNOW2 0x99
1723#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001724 printf(" issuing sleep command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001725 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001726 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001727 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001728 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001729 args[0] = 0xfb;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001730 printf(" disabling Seagate auto powersaving mode\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001731 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001732 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001733 if (getset_standby == IS_SET) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001734 args[0] = WIN_SETIDLE1;
1735 args[1] = standby_requested;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001736 print_flag(1, "standby", standby_requested);
1737 interpret_standby(standby_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001738 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001739 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001740 }
1741#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001742 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001743 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001744 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001745 if (-1 == read(fd, buf, sizeof(buf)))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001746 bb_perror_msg("read of 512 bytes failed");
Eric Andersen3443bd72003-07-22 07:30:36 +00001747 }
1748#endif /* HDIO_DRIVE_CMD */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001749 if (getset_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001750 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001751 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001752 /* To be coherent with ioctl_or_warn. */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001753 if (getset_mult && ENABLE_IOCTL_HEX2STR_ERROR)
Eric Andersen06d4ec22004-03-19 10:53:52 +00001754 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001755 else
1756 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001757 } else if (getset_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001758 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001759 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001760 }
1761 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001762 if (getset_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001763 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001764 printf(" IO_support\t=%3ld (", parm);
1765 if (parm == 0)
1766 printf("default 16-bit)\n");
1767 else if (parm == 2)
1768 printf("16-bit)\n");
1769 else if (parm == 1)
1770 printf("32-bit)\n");
1771 else if (parm == 3)
1772 printf("32-bit w/sync)\n");
1773 else if (parm == 8)
1774 printf("Request-Queue-Bypass)\n");
1775 else
1776 printf("\?\?\?)\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001777 }
1778 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001779 if (getset_unmask) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001780 if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001781 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001782 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001783#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001784 if (getset_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001785 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001786 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001787 if (parm == 8)
1788 printf(" (DMA-Assisted-PIO)\n");
1789 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001790 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001791 }
1792 }
1793#endif
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001794#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001795 if (getset_dma_q) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001796 if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001797 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001798 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001799#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001800 if (getset_keep) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001801 if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001802 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001803 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001804 if (getset_nowerr) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001805 if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001806 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001807 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001808 if (getset_readonly) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001809 if (!ioctl_or_warn(fd, BLKROGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001810 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001811 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001812 if (getset_readahead) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001813 if (!ioctl_or_warn(fd, BLKRAGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001814 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001815 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001816 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001817 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001818 struct hd_geometry g;
1819
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001820 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001821 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001822 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001823 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001824 }
1825#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001826 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001827#ifndef WIN_CHECKPOWERMODE1
1828#define WIN_CHECKPOWERMODE1 0xE5
1829#endif
1830#ifndef WIN_CHECKPOWERMODE2
1831#define WIN_CHECKPOWERMODE2 0x98
1832#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001833 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001834
Rob Landleye5b281f2006-04-29 15:49:18 +00001835 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001836 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001837 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001838 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001839 else
1840 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001841 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001842 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001843 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001844
Eric Andersen3443bd72003-07-22 07:30:36 +00001845 printf(" drive state is: %s\n", state);
1846 }
1847#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001848#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1849 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001850 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001851 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001852#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1853#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1854 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001855 args[0] = 0;
1856 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001857 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001858 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001859#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1860#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1861 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001862 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001863
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001864 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1865 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001866 id.multsect = multcount;
1867 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001868 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001869 id.multsect_valid &= ~1;
1870 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001871 } else if (errno == -ENOMSG)
Eric Andersen3443bd72003-07-22 07:30:36 +00001872 printf(" no identification info available\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001873 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001874 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001875 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001876 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001877 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001878
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001879 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001880 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001881
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001882 memset(args1, 0, sizeof(args1));
1883 args1[0] = WIN_IDENTIFY;
1884 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001885 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001886 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00001887 }
1888#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001889#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001890 if (getset_busstate == IS_SET) {
1891 print_flag(1, "bus state", busstate);
1892 bus_state_value(busstate);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001893 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001894 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001895 if (getset_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001896 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001897 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001898 bus_state_value(parm);
1899 }
1900 }
1901#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00001902 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001903 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00001904
Eric Andersen3443bd72003-07-22 07:30:36 +00001905 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001906 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00001907 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001908 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001909 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001910 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00001911 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00001912}
1913
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001914#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00001915static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00001916{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001917 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00001918 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001919 if (c >= 'a' && c <= 'f')
1920 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00001921 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1922}
1923
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001924static void identify_from_stdin(void) NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00001925static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001926{
Rob Landley0753f4a2006-06-07 00:27:25 +00001927 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001928 unsigned char buf[1280];
1929 unsigned char *b = (unsigned char *)buf;
1930 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001931
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001932 xread(STDIN_FILENO, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00001933
Rob Landley0753f4a2006-06-07 00:27:25 +00001934 // Convert the newline-separated hex data into an identify block.
1935
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001936 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00001937 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001938 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001939 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00001940 }
Rob Landley0753f4a2006-06-07 00:27:25 +00001941
1942 // Parse the data.
1943
Rob Landley6389ff12006-05-01 19:28:53 +00001944 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001945}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001946#else
1947void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00001948#endif
1949
Rob Landley20deab02006-05-07 23:34:15 +00001950/* busybox specific stuff */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001951static int parse_opts(unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00001952{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001953 if (optarg) {
Denis Vlasenko13858992006-10-08 12:49:22 +00001954 *value = xatol_range(optarg, min, max);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001955 return IS_SET;
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001956 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001957 return IS_GET;
1958}
1959static int parse_opts_0_max(unsigned long *value, int max)
1960{
1961 return parse_opts(value, 0, max);
1962}
1963static int parse_opts_0_1(unsigned long *value)
1964{
1965 return parse_opts(value, 0, 1);
1966}
1967static int parse_opts_0_INTMAX(unsigned long *value)
1968{
1969 return parse_opts(value, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00001970}
1971
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001972static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00001973{
1974 if (flag) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001975 *get = IS_GET;
Rob Landley20deab02006-05-07 23:34:15 +00001976 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001977 *value = translate_xfermode(optarg);
1978 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00001979 }
1980 }
1981}
1982
Rob Landley06208412006-05-31 22:52:57 +00001983/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001984static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00001985 "gfu::n::p:r::m::c::k::a::B:tT"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001986 IF_FEATURE_HDPARM_GET_IDENTITY("iI")
1987 IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
Rob Landley20deab02006-05-07 23:34:15 +00001988#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001989 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00001990#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001991 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
Rob Landley20deab02006-05-07 23:34:15 +00001992#ifdef HDIO_GET_QDMA
1993#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001994 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00001995#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001996 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00001997#endif
1998#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001999 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
2000 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
2001 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
Rob Landley20deab02006-05-07 23:34:15 +00002002/*-------------------------------------*/
2003
2004/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002005int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00002006int hdparm_main(int argc, char **argv)
2007{
2008 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00002009 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00002010
Rob Landley06208412006-05-31 22:52:57 +00002011 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00002012 flagcount++;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002013 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
2014 IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00002015 get_geom |= (c == 'g');
2016 do_flush |= (c == 'f');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002017 if (c == 'u') getset_unmask = parse_opts_0_1(&unmask);
2018 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
2019 if (c == 'd') getset_dma = parse_opts_0_max(&dma, 9);
2020 )
2021 if (c == 'n') getset_nowerr = parse_opts_0_1(&nowerr);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002022 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002023 if (c == 'r') getset_readonly = parse_opts_0_1(&readonly);
2024 if (c == 'm') getset_mult = parse_opts_0_INTMAX(&mult /*32*/);
2025 if (c == 'c') getset_io32bit = parse_opts_0_INTMAX(&io32bit /*8*/);
2026 if (c == 'k') getset_keep = parse_opts_0_1(&keep);
2027 if (c == 'a') getset_readahead = parse_opts_0_INTMAX(&Xreadahead);
2028 if (c == 'B') getset_apmmode = parse_opts(&apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002029 do_flush |= do_timings |= (c == 't');
2030 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002031#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002032 if (c == 'S') getset_standby = parse_opts_0_max(&standby_requested, 255);
2033 if (c == 'D') getset_defects = parse_opts_0_INTMAX(&defects);
2034 if (c == 'P') getset_prefetch = parse_opts_0_INTMAX(&prefetch);
Rob Landleyade7f952006-05-25 18:53:06 +00002035 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002036 if (c == 'K') getset_dkeep = parse_opts_0_1(&prefetch);
2037 if (c == 'A') getset_lookahead = parse_opts_0_1(&lookahead);
2038 if (c == 'L') getset_doorlock = parse_opts_0_1(&doorlock);
2039 if (c == 'W') getset_wcache = parse_opts_0_1(&wcache);
Rob Landleyade7f952006-05-25 18:53:06 +00002040 get_powermode |= (c == 'C');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002041 set_standbynow |= (c == 'y');
2042 set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002043 reread_partn |= (c == 'z');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002044 set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002045#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002046 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') unregister_hwif = parse_opts_0_INTMAX(&hwif));
Rob Landley20deab02006-05-07 23:34:15 +00002047#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002048 if (c == 'Q') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002049 getset_dma_q = parse_opts_0_INTMAX(&dma_q);
Rob Landley19802562006-05-08 15:35:46 +00002050 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002051#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002052 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002053 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') perform_tristate = parse_opts_0_1(&tristate));
2054 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') getset_busstate = parse_opts_0_max(&busstate, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002055#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2056 if (c == 'R') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002057 scan_hwif = parse_opts_0_INTMAX(&hwif_data);
Denis Vlasenko13858992006-10-08 12:49:22 +00002058 hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
2059 hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002060 /* Move past the 2 additional arguments */
2061 argv += 2;
2062 argc -= 2;
2063 }
2064#endif
2065 }
Rob Landleyade7f952006-05-25 18:53:06 +00002066 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002067 if (!flagcount) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002068 getset_mult = getset_io32bit = getset_unmask = getset_keep = getset_readonly = getset_readahead = get_geom = IS_GET;
2069 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(getset_dma = IS_GET);
Rob Landleyade7f952006-05-25 18:53:06 +00002070 }
Rob Landley20deab02006-05-07 23:34:15 +00002071 argv += optind;
2072
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002073 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002074 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2075 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002076 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002077 }
2078
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002079 do {
2080 process_dev(*argv++);
2081 } while (*argv);
2082
2083 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002084}