blob: 0bbe6ca100d89800f4c2a3107f23241cd9625e03 [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02008 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
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 Vlasenkofb4da162016-11-22 23:14:24 +010014//config:config HDPARM
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020015//config: bool "hdparm (23 kb)"
Denys Vlasenkofb4da162016-11-22 23:14:24 +010016//config: default y
17//config: select PLATFORM_LINUX
18//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020019//config: Get/Set hard drive parameters. Primarily intended for ATA
20//config: drives.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010021//config:
22//config:config FEATURE_HDPARM_GET_IDENTITY
23//config: bool "Support obtaining detailed information directly from drives"
24//config: default y
25//config: depends on HDPARM
26//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020027//config: Enable the -I and -i options to obtain detailed information
28//config: directly from drives about their capabilities and supported ATA
29//config: feature set. If no device name is specified, hdparm will read
30//config: identify data from stdin. Enabling this option will add about 16k...
Denys Vlasenkofb4da162016-11-22 23:14:24 +010031//config:
32//config:config FEATURE_HDPARM_HDIO_SCAN_HWIF
33//config: bool "Register an IDE interface (DANGEROUS)"
34//config: default y
35//config: depends on HDPARM
36//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020037//config: Enable the 'hdparm -R' option to register an IDE interface.
38//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010039//config:
40//config:config FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
41//config: bool "Un-register an IDE interface (DANGEROUS)"
42//config: default y
43//config: depends on HDPARM
44//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020045//config: Enable the 'hdparm -U' option to un-register an IDE interface.
46//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010047//config:
48//config:config FEATURE_HDPARM_HDIO_DRIVE_RESET
49//config: bool "Perform device reset (DANGEROUS)"
50//config: default y
51//config: depends on HDPARM
52//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020053//config: Enable the 'hdparm -w' option to perform a device reset.
54//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010055//config:
56//config:config FEATURE_HDPARM_HDIO_TRISTATE_HWIF
57//config: bool "Tristate device for hotswap (DANGEROUS)"
58//config: default y
59//config: depends on HDPARM
60//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020061//config: Enable the 'hdparm -x' option to tristate device for hotswap,
62//config: and the '-b' option to get/set bus state. This is dangerous
63//config: stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010064//config:
65//config:config FEATURE_HDPARM_HDIO_GETSET_DMA
66//config: bool "Get/set using_dma flag"
67//config: default y
68//config: depends on HDPARM
69//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020070//config: Enable the 'hdparm -d' option to get/set using_dma flag.
Pere Orga5bc8c002011-04-11 03:29:49 +020071
Denys Vlasenkof88e3bf2016-11-22 23:54:17 +010072//applet:IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP))
73
74//kbuild:lib-$(CONFIG_HDPARM) += hdparm.o
75
Pere Orga5bc8c002011-04-11 03:29:49 +020076//usage:#define hdparm_trivial_usage
77//usage: "[OPTIONS] [DEVICE]"
78//usage:#define hdparm_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020079//usage: " -a Get/set fs readahead"
Pere Orga5bc8c002011-04-11 03:29:49 +020080//usage: "\n -A Set drive read-lookahead flag (0/1)"
81//usage: "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)"
82//usage: "\n -B Set Advanced Power Management setting (1-255)"
83//usage: "\n -c Get/set IDE 32-bit IO setting"
84//usage: "\n -C Check IDE power mode status"
85//usage: IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
86//usage: "\n -d Get/set using_dma flag")
87//usage: "\n -D Enable/disable drive defect-mgmt"
88//usage: "\n -f Flush buffer cache for device on exit"
89//usage: "\n -g Display drive geometry"
90//usage: "\n -h Display terse usage information"
91//usage: IF_FEATURE_HDPARM_GET_IDENTITY(
92//usage: "\n -i Display drive identification")
93//usage: IF_FEATURE_HDPARM_GET_IDENTITY(
94//usage: "\n -I Detailed/current information directly from drive")
95//usage: "\n -k Get/set keep_settings_over_reset flag (0/1)"
96//usage: "\n -K Set drive keep_features_over_reset flag (0/1)"
97//usage: "\n -L Set drive doorlock (0/1) (removable harddisks only)"
98//usage: "\n -m Get/set multiple sector count"
99//usage: "\n -n Get/set ignore-write-errors flag (0/1)"
100//usage: "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)"
101//usage: "\n -P Set drive prefetch count"
102/* //usage: "\n -q Change next setting quietly" - not supported ib bbox */
103//usage: "\n -Q Get/set DMA tagged-queuing depth (if supported)"
104//usage: "\n -r Get/set readonly flag (DANGEROUS to set)"
105//usage: IF_FEATURE_HDPARM_HDIO_SCAN_HWIF(
106//usage: "\n -R Register an IDE interface (DANGEROUS)")
107//usage: "\n -S Set standby (spindown) timeout"
108//usage: "\n -t Perform device read timings"
109//usage: "\n -T Perform cache read timings"
110//usage: "\n -u Get/set unmaskirq flag (0/1)"
111//usage: IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(
112//usage: "\n -U Unregister an IDE interface (DANGEROUS)")
113//usage: "\n -v Defaults; same as -mcudkrag for IDE drives"
114//usage: "\n -V Display program version and exit immediately"
115//usage: IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(
116//usage: "\n -w Perform device reset (DANGEROUS)")
117//usage: "\n -W Set drive write-caching flag (0/1) (DANGEROUS)"
118//usage: IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(
119//usage: "\n -x Tristate device for hotswap (0/1) (DANGEROUS)")
120//usage: "\n -X Set IDE xfer mode (DANGEROUS)"
121//usage: "\n -y Put IDE drive in standby mode"
122//usage: "\n -Y Put IDE drive to sleep"
123//usage: "\n -Z Disable Seagate auto-powersaving mode"
124//usage: "\n -z Reread partition table"
125
Denys Vlasenko860d2bb2009-07-10 18:37:06 +0200126#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200127#include "common_bufsiz.h"
Denys Vlasenko860d2bb2009-07-10 18:37:06 +0200128/* must be _after_ libbb.h: */
Eric Andersen3443bd72003-07-22 07:30:36 +0000129#include <linux/hdreg.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200130#include <sys/mount.h>
Denys Vlasenkoaf3fd142009-09-22 23:16:39 +0200131#if !defined(BLKGETSIZE64)
132# define BLKGETSIZE64 _IOR(0x12,114,size_t)
133#endif
Eric Andersen3443bd72003-07-22 07:30:36 +0000134
Eric Andersen3443bd72003-07-22 07:30:36 +0000135/* device types */
136/* ------------ */
137#define NO_DEV 0xffff
138#define ATA_DEV 0x0000
139#define ATAPI_DEV 0x0001
140
141/* word definitions */
142/* ---------------- */
143#define GEN_CONFIG 0 /* general configuration */
144#define LCYLS 1 /* number of logical cylinders */
145#define CONFIG 2 /* specific configuration */
146#define LHEADS 3 /* number of logical heads */
147#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
148#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
149#define LSECTS 6 /* number of logical sectors/track */
150#define START_SERIAL 10 /* ASCII serial number */
151#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
152#define BUF_TYPE 20 /* buffer type (ATA-1) */
153#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
154#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
155#define START_FW_REV 23 /* ASCII firmware revision */
156#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000157#define START_MODEL 27 /* ASCII model number */
158#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000159#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +0000160#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
161#define CAPAB_0 49 /* capabilities */
162#define CAPAB_1 50
163#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
164#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
165#define WHATS_VALID 53 /* what fields are valid */
166#define LCYLS_CUR 54 /* current logical cylinders */
167#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000168#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +0000169#define CAPACITY_LSB 57 /* current capacity in sectors */
170#define CAPACITY_MSB 58
171#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
172#define LBA_SECTS_LSB 60 /* LBA: total number of user */
173#define LBA_SECTS_MSB 61 /* addressable sectors */
174#define SINGLE_DMA 62 /* singleword DMA modes */
175#define MULTI_DMA 63 /* multiword DMA modes */
176#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
177 /* multiword DMA xfer cycle time: */
178#define DMA_TIME_MIN 65 /* - minimum */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +0000179#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
Eric Andersen3443bd72003-07-22 07:30:36 +0000180 /* minimum PIO xfer cycle time: */
181#define PIO_NO_FLOW 67 /* - without flow control */
182#define PIO_FLOW 68 /* - with IORDY flow control */
183#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
184#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
185#define CDR_MAJOR 73 /* CD ROM: major version number */
186#define CDR_MINOR 74 /* CD ROM: minor version number */
187#define QUEUE_DEPTH 75 /* queue depth */
188#define MAJOR 80 /* major version number */
189#define MINOR 81 /* minor version number */
190#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
191#define CMDS_SUPP_1 83
192#define CMDS_SUPP_2 84
193#define CMDS_EN_0 85 /* command/feature set(s) enabled */
194#define CMDS_EN_1 86
195#define CMDS_EN_2 87
196#define ULTRA_DMA 88 /* ultra DMA modes */
197 /* time to complete security erase */
198#define ERASE_TIME 89 /* - ordinary */
199#define ENH_ERASE_TIME 90 /* - enhanced */
200#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +0000201 in low byte, 0x40 in high byte. */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +0000202#define PSWD_CODE 92 /* master password revision code */
Eric Andersen3443bd72003-07-22 07:30:36 +0000203#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000204#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000205#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
206#define LBA_MID 101 /* bits are used, but addr 103 */
207#define LBA_48_MSB 102 /* has been reserved for LBA in */
208#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000209#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +0000210#define SECU_STATUS 128 /* security status */
211#define CFA_PWR_MODE 160 /* CFA power mode 1 */
212#define START_MEDIA 176 /* media serial number */
213#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
214#define START_MANUF 196 /* media manufacturer I.D. */
215#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
216#define INTEGRITY 255 /* integrity word */
217
218/* bit definitions within the words */
219/* -------------------------------- */
220
221/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
222#define VALID 0xc000
223#define VALID_VAL 0x4000
224/* many words are considered invalid if they are either all-0 or all-1 */
225#define NOVAL_0 0x0000
226#define NOVAL_1 0xffff
227
228/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000229#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000230#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
231#define MEDIA_REMOVABLE 0x0080
232#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
233#define INCOMPLETE 0x0004
234#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
235#define DRQ_RESPONSE_TIME 0x0060
236#define DRQ_3MS_VAL 0x0000
237#define DRQ_INTR_VAL 0x0020
238#define DRQ_50US_VAL 0x0040
239#define PKT_SIZE_SUPPORTED 0x0003
240#define PKT_SIZE_12_VAL 0x0000
241#define PKT_SIZE_16_VAL 0x0001
242#define EQPT_TYPE 0x1f00
243#define SHIFT_EQPT 8
244
245#define CDROM 0x0005
246
Eric Andersen3443bd72003-07-22 07:30:36 +0000247/* word 1: number of logical cylinders */
248#define LCYLS_MAX 0x3fff /* maximum allowable value */
249
Eric Andersenaff114c2004-04-14 17:51:38 +0000250/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000251 * (a) require SET FEATURES to spin-up
252 * (b) require spin-up to fully reply to IDENTIFY DEVICE
253 */
254#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
255#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000256#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000257#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
258
259/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
260#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
261#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
262
263/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000264#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000265#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
266#define IORDY_OFF 0x0400 /* 1=may be disabled */
267#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
268#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
269#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
270#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
271#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
272#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
273
274/* word 50: capabilities 1 */
275#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
276
277/* words 51 & 52: PIO & DMA cycle times */
278#define MODE 0xff00 /* the mode is in the MSBs */
279
280/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000281#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000282#define OK_W64_70 0x0002 /* see above for word descriptions */
283#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
284
285/*word 63,88: dma_mode, ultra_dma_mode*/
286#define MODE_MAX 7 /* bit definitions force udma <=7 (when
287 * udma >=8 comes out it'll have to be
288 * defined in a new dma_mode word!) */
289
290/* word 64: PIO transfer modes */
291#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
292#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
293
294/* word 75: queue_depth */
295#define DEPTH_BITS 0x001f /* bits used for queue depth */
296
297/* words 80-81: version numbers */
298/* NOVAL_0 or NOVAL_1 means device does not report version */
299
300/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000301#define MINOR_MAX 0x22
Eric Andersen3443bd72003-07-22 07:30:36 +0000302/* words 82-84: cmds/feats supported */
303#define CMDS_W82 0x77ff /* word 82: defined command locations*/
304#define CMDS_W83 0x3fff /* word 83: defined command locations*/
305#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000306#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000307#define NUM_CMD_FEAT_STR 48
308
Eric Andersen3443bd72003-07-22 07:30:36 +0000309/* words 85-87: cmds/feats enabled */
310/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000311 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000312 */
313
314/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000315#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000316
317/* word 92: master password revision */
318/* NOVAL_0 or NOVAL_1 means no support for master password revision */
319
320/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000321#define CBLID 0x2000 /* CBLID status */
322#define RST0 0x0001 /* 1=reset to device #0 */
323#define DEV_DET 0x0006 /* how device num determined */
324#define JUMPER_VAL 0x0002 /* device num determined by jumper */
325#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000326
327/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000328#define RM_STAT_BITS 0x0003
329#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000330
Eric Andersen3443bd72003-07-22 07:30:36 +0000331/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000332#define SECU_ENABLED 0x0002
333#define SECU_LEVEL 0x0010
334#define NUM_SECU_STR 6
Eric Andersen3443bd72003-07-22 07:30:36 +0000335
336/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000337#define VALID_W160 0x8000 /* 1=word valid */
338#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
339#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
340#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000341
342/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000343#define SIG 0x00ff /* signature location */
344#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000345
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000346#define TIMING_BUF_MB 1
347#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000348
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000349#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000350
Denis Vlasenko892536f2007-09-27 10:23:34 +0000351
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200352#define IS_GET 1
353#define IS_SET 2
354
355
Denis Vlasenko892536f2007-09-27 10:23:34 +0000356enum { fd = 3 };
357
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000358
359struct globals {
360 smallint get_identity, get_geom;
361 smallint do_flush;
362 smallint do_ctimings, do_timings;
363 smallint reread_partn;
364 smallint set_piomode, noisy_piomode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200365 smallint getset_readahead;
366 smallint getset_readonly;
367 smallint getset_unmask;
368 smallint getset_mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000369#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200370 smallint getset_dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000371#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200372 smallint getset_nowerr;
373 smallint getset_keep;
374 smallint getset_io32bit;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000375 int piomode;
376 unsigned long Xreadahead;
377 unsigned long readonly;
378 unsigned long unmask;
379 unsigned long mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000380#ifdef HDIO_SET_QDMA
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000381 unsigned long dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000382#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000383 unsigned long nowerr;
384 unsigned long keep;
385 unsigned long io32bit;
386#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
387 unsigned long dma;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200388 smallint getset_dma;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000389#endif
390#ifdef HDIO_DRIVE_CMD
391 smallint set_xfermode, get_xfermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200392 smallint getset_dkeep;
393 smallint getset_standby;
394 smallint getset_lookahead;
395 smallint getset_prefetch;
396 smallint getset_defects;
397 smallint getset_wcache;
398 smallint getset_doorlock;
399 smallint set_seagate;
400 smallint set_standbynow;
401 smallint set_sleepnow;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000402 smallint get_powermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200403 smallint getset_apmmode;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000404 int xfermode_requested;
405 unsigned long dkeep;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000406 unsigned long standby_requested; /* 0..255 */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000407 unsigned long lookahead;
408 unsigned long prefetch;
409 unsigned long defects;
410 unsigned long wcache;
411 unsigned long doorlock;
412 unsigned long apmmode;
413#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000414 IF_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200415 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint getset_busstate;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000416 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
417 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
418 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
419 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
420 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
421 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
422 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000423#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
424 unsigned long hwif_data;
425 unsigned long hwif_ctrl;
426 unsigned long hwif_irq;
427#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000428#ifdef DO_FLUSHCACHE
429 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
430#endif
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100431} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200432#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000433#define get_identity (G.get_identity )
434#define get_geom (G.get_geom )
435#define do_flush (G.do_flush )
436#define do_ctimings (G.do_ctimings )
437#define do_timings (G.do_timings )
438#define reread_partn (G.reread_partn )
439#define set_piomode (G.set_piomode )
440#define noisy_piomode (G.noisy_piomode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200441#define getset_readahead (G.getset_readahead )
442#define getset_readonly (G.getset_readonly )
443#define getset_unmask (G.getset_unmask )
444#define getset_mult (G.getset_mult )
445#define getset_dma_q (G.getset_dma_q )
446#define getset_nowerr (G.getset_nowerr )
447#define getset_keep (G.getset_keep )
448#define getset_io32bit (G.getset_io32bit )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000449#define piomode (G.piomode )
450#define Xreadahead (G.Xreadahead )
451#define readonly (G.readonly )
452#define unmask (G.unmask )
453#define mult (G.mult )
454#define dma_q (G.dma_q )
455#define nowerr (G.nowerr )
456#define keep (G.keep )
457#define io32bit (G.io32bit )
458#define dma (G.dma )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200459#define getset_dma (G.getset_dma )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000460#define set_xfermode (G.set_xfermode )
461#define get_xfermode (G.get_xfermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200462#define getset_dkeep (G.getset_dkeep )
463#define getset_standby (G.getset_standby )
464#define getset_lookahead (G.getset_lookahead )
465#define getset_prefetch (G.getset_prefetch )
466#define getset_defects (G.getset_defects )
467#define getset_wcache (G.getset_wcache )
468#define getset_doorlock (G.getset_doorlock )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000469#define set_seagate (G.set_seagate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000470#define set_standbynow (G.set_standbynow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000471#define set_sleepnow (G.set_sleepnow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000472#define get_powermode (G.get_powermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200473#define getset_apmmode (G.getset_apmmode )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000474#define xfermode_requested (G.xfermode_requested )
475#define dkeep (G.dkeep )
476#define standby_requested (G.standby_requested )
477#define lookahead (G.lookahead )
478#define prefetch (G.prefetch )
479#define defects (G.defects )
480#define wcache (G.wcache )
481#define doorlock (G.doorlock )
482#define apmmode (G.apmmode )
483#define get_IDentity (G.get_IDentity )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200484#define getset_busstate (G.getset_busstate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000485#define perform_reset (G.perform_reset )
486#define perform_tristate (G.perform_tristate )
487#define unregister_hwif (G.unregister_hwif )
488#define scan_hwif (G.scan_hwif )
489#define busstate (G.busstate )
490#define tristate (G.tristate )
491#define hwif (G.hwif )
492#define hwif_data (G.hwif_data )
493#define hwif_ctrl (G.hwif_ctrl )
494#define hwif_irq (G.hwif_irq )
Denys Vlasenko7b85ec32015-10-13 17:17:34 +0200495#define INIT_G() do { \
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200496 setup_common_bufsiz(); \
Denys Vlasenko7b85ec32015-10-13 17:17:34 +0200497 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
498} while (0)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000499
500
Glenn L McGrath07085852003-10-09 07:28:22 +0000501/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000502#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000503static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000504{
505 if (!ioctl(fd, cmd, args))
506 return 0;
507 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000508 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000509}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000510#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000511#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000512static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000513{
514 if (!ioctl(fd, cmd, args))
515 return 0;
516 args[0] = alt;
517 return bb_ioctl_or_warn(fd, cmd, args);
518}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000519#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000520#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000521
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000522static void on_off(int value)
523{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000524 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000525}
Glenn L McGrath07085852003-10-09 07:28:22 +0000526
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000527static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000528{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000529 if (get_arg) {
Denys Vlasenko327f5502013-11-29 16:45:45 +0100530 printf(" setting %s to %lu", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000531 on_off(arg);
532 }
533}
534
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000535static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000536{
Denys Vlasenko327f5502013-11-29 16:45:45 +0100537 printf(" %s\t= %2lu", str, argp);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000538 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000539}
Eric Andersen416c2422003-12-12 00:08:57 +0000540
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000541#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000542static void print_ascii(const char *p, int length)
543{
544#if BB_BIG_ENDIAN
545#define LE_ONLY(x)
546 enum { ofs = 0 };
547#else
548#define LE_ONLY(x) x
549 /* every 16bit word is big-endian (i.e. inverted) */
550 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
551 int ofs = 1;
552#endif
553
554 length *= 2;
555 /* find first non-space & print it */
556 while (length && p[ofs] != ' ') {
557 p++;
558 LE_ONLY(ofs = -ofs;)
559 length--;
560 }
561 while (length && p[ofs]) {
562 bb_putchar(p[ofs]);
563 p++;
564 LE_ONLY(ofs = -ofs;)
565 length--;
566 }
567 bb_putchar('\n');
568#undef LE_ONLY
569}
Glenn L McGrath07085852003-10-09 07:28:22 +0000570
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000571static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000572{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000573 if (val[i]) {
574 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000575 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000576 }
577}
Glenn L McGrath07085852003-10-09 07:28:22 +0000578
Glenn L McGrath07085852003-10-09 07:28:22 +0000579static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
580{
Eric Andersen3443bd72003-07-22 07:30:36 +0000581 uint16_t ii;
582 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000583
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000584 for (ii = 0; ii <= MODE_MAX; ii++) {
585 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000586 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000587 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000588 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000589 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000590 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000591 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000592
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000593 mode_sup >>= 1;
594 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000595 }
596 return err_dma;
597}
Glenn L McGrath07085852003-10-09 07:28:22 +0000598
Denis Vlasenko91303402007-10-30 19:36:54 +0000599static const char pkt_str[] ALIGN1 =
600 "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
601 "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
602 "Printer" "\0" /* word 0, bits 12-8 = 02 */
603 "Processor" "\0" /* word 0, bits 12-8 = 03 */
604 "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
605 "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
606 "Scanner" "\0" /* word 0, bits 12-8 = 06 */
607 "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
608 "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
609 "Communications device" "\0" /* word 0, bits 12-8 = 09 */
610 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
611 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
612 "Array controller" "\0" /* word 0, bits 12-8 = 0c */
613 "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
614 "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
615 "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
616;
617
618static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
619 "reserved" "\0" /* bit 0 */
620 "hard sectored" "\0" /* bit 1 */
621 "soft sectored" "\0" /* bit 2 */
622 "not MFM encoded " "\0" /* bit 3 */
623 "head switch time > 15us" "\0" /* bit 4 */
624 "spindle motor control option" "\0" /* bit 5 */
625 "fixed drive" "\0" /* bit 6 */
626 "removable drive" "\0" /* bit 7 */
627 "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
628 "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
629 "disk xfer rate > 5Mbs" "\0" /* bit 10 */
630 "rotational speed tol." "\0" /* bit 11 */
631 "data strobe offset option" "\0" /* bit 12 */
632 "track offset option" "\0" /* bit 13 */
633 "format speed tolerance gap reqd" "\0" /* bit 14 */
634 "ATAPI" /* bit 14 */
635;
636
637static const char minor_str[] ALIGN1 =
638 /* word 81 value: */
639 "Unspecified" "\0" /* 0x0000 */
640 "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
641 "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
642 "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
643 "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
644 "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
645 "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
646 "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
647 "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
648 "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
649 "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
650 "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
651 "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
652 "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
653 "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
654 "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
655 "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
656 "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
657 "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
658 "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
659 "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
660 "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
661 "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
662 "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
663 "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
664 "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
665 "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
666 "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
667 "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
668 "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
669 "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
670 "reserved" "\0" /* 0x001f */
671 "reserved" "\0" /* 0x0020 */
672 "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
673 "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
674 "reserved" /* 0x0023-0xfffe */
675;
676static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
677 /* word 81 value: */
678 0, /* 0x0000 WARNING: actual_ver[] array */
679 1, /* 0x0001 WARNING: corresponds */
680 1, /* 0x0002 WARNING: *exactly* */
681 1, /* 0x0003 WARNING: to the ATA/ */
682 2, /* 0x0004 WARNING: ATAPI version */
683 2, /* 0x0005 WARNING: listed in */
684 3, /* 0x0006 WARNING: the */
685 2, /* 0x0007 WARNING: minor_str */
686 3, /* 0x0008 WARNING: array */
687 2, /* 0x0009 WARNING: above. */
688 3, /* 0x000a WARNING: */
689 3, /* 0x000b WARNING: If you change */
690 3, /* 0x000c WARNING: that one, */
691 4, /* 0x000d WARNING: change this one */
692 4, /* 0x000e WARNING: too!!! */
693 4, /* 0x000f */
694 4, /* 0x0010 */
695 4, /* 0x0011 */
696 4, /* 0x0012 */
697 5, /* 0x0013 */
698 4, /* 0x0014 */
699 5, /* 0x0015 */
700 5, /* 0x0016 */
701 4, /* 0x0017 */
702 6, /* 0x0018 */
703 6, /* 0x0019 */
704 7, /* 0x001a */
705 6, /* 0x001b */
706 6, /* 0x001c */
707 7, /* 0x001d */
708 7, /* 0x001e */
709 0, /* 0x001f */
710 0, /* 0x0020 */
711 7, /* 0x0021 */
712 6, /* 0x0022 */
713 0 /* 0x0023-0xfffe */
714};
715
716static const char cmd_feat_str[] ALIGN1 =
717 "" "\0" /* word 82 bit 15: obsolete */
718 "NOP cmd" "\0" /* word 82 bit 14 */
719 "READ BUFFER cmd" "\0" /* word 82 bit 13 */
720 "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
721 "" "\0" /* word 82 bit 11: obsolete */
722 "Host Protected Area feature set" "\0" /* word 82 bit 10 */
723 "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
724 "SERVICE interrupt" "\0" /* word 82 bit 8 */
725 "Release interrupt" "\0" /* word 82 bit 7 */
726 "Look-ahead" "\0" /* word 82 bit 6 */
727 "Write cache" "\0" /* word 82 bit 5 */
728 "PACKET command feature set" "\0" /* word 82 bit 4 */
729 "Power Management feature set" "\0" /* word 82 bit 3 */
730 "Removable Media feature set" "\0" /* word 82 bit 2 */
731 "Security Mode feature set" "\0" /* word 82 bit 1 */
732 "SMART feature set" "\0" /* word 82 bit 0 */
733 /* -------------- */
734 "" "\0" /* word 83 bit 15: !valid bit */
735 "" "\0" /* word 83 bit 14: valid bit */
736 "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
737 "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
738 "Device Configuration Overlay feature set " "\0"
739 "48-bit Address feature set " "\0" /* word 83 bit 10 */
740 "" "\0"
741 "SET MAX security extension" "\0" /* word 83 bit 8 */
742 "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
743 "SET FEATURES subcommand required to spinup after power up" "\0"
744 "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
745 "Removable Media Status Notification feature set" "\0"
746 "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
747 "CFA feature set" "\0" /* word 83 bit 2 */
748 "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
749 "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
750 /* -------------- */
751 "" "\0" /* word 84 bit 15: !valid bit */
752 "" "\0" /* word 84 bit 14: valid bit */
753 "" "\0" /* word 84 bit 13: reserved */
754 "" "\0" /* word 84 bit 12: reserved */
755 "" "\0" /* word 84 bit 11: reserved */
756 "" "\0" /* word 84 bit 10: reserved */
757 "" "\0" /* word 84 bit 9: reserved */
758 "" "\0" /* word 84 bit 8: reserved */
759 "" "\0" /* word 84 bit 7: reserved */
760 "" "\0" /* word 84 bit 6: reserved */
761 "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
762 "" "\0" /* word 84 bit 4: reserved */
763 "Media Card Pass Through Command feature set " "\0"
764 "Media serial number " "\0" /* word 84 bit 2 */
765 "SMART self-test " "\0" /* word 84 bit 1 */
766 "SMART error logging " /* word 84 bit 0 */
767;
768
769static const char secu_str[] ALIGN1 =
770 "supported" "\0" /* word 128, bit 0 */
771 "enabled" "\0" /* word 128, bit 1 */
772 "locked" "\0" /* word 128, bit 2 */
773 "frozen" "\0" /* word 128, bit 3 */
774 "expired: security count" "\0" /* word 128, bit 4 */
775 "supported: enhanced erase" /* word 128, bit 5 */
776;
777
778// Parse 512 byte disk identification block and print much crap.
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000779static void identify(uint16_t *val) NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000780static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000781{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000782 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000783 uint16_t like_std = 1, std = 0, min_std = 0xffff;
784 uint16_t dev = NO_DEV, eqpt = NO_DEV;
785 uint8_t have_mode = 0, err_dma = 0;
786 uint8_t chksum = 0;
787 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000788 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000789 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000790#if BB_BIG_ENDIAN
791 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000792
Denis Vlasenko4daad902007-09-27 10:20:47 +0000793 // Adjust for endianness
794 swab(val, buf, sizeof(buf));
795 val = buf;
796#endif
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200797 /* check if we recognize the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000798 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000799 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000800 dev = ATA_DEV;
801 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000802 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000803 dev = ATA_DEV;
804 like_std = 4;
805 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000806 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000807 dev = ATAPI_DEV;
808 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000809 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +0000810 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000811 } else
Denis Vlasenko91303402007-10-30 19:36:54 +0000812 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000813 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000814
Rob Landleyadde7982006-05-16 15:32:30 +0000815 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000816 /* Info from the specific configuration word says whether or not the
817 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000818 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000819 * standards. Since the values allowed for this word are extremely
820 * specific, it should be safe to check it now, even though we don't
821 * know yet what standard this device is using.
822 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000823 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
824 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
825 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000826 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000827 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200828 puts("powers-up in standby; SET FEATURES subcmd spins-up.");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000829 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200830 puts("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000831 }
832
833 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000834 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
835 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
836 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
837 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
838 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000839
840 /* major & minor standards version number (Note: these words were not
841 * defined until ATA-3 & the CDROM std uses different words.) */
842 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000843 if (eqpt != CDROM) {
844 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000845 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000846 std = actual_ver[val[MINOR]];
Denys Vlasenkof3ea7922010-07-26 01:06:14 +0200847 if (std)
848 printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
Eric Andersen3443bd72003-07-22 07:30:36 +0000849 }
850 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000851 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000852 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000853 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000854 printf("\n\tSupported: ");
855 jj = val[MAJOR] << 1;
856 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000857 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
858 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000859 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000860 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000861 like_std = ii;
862 kk = like_std >4 ? like_std-4: 0;
863 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000864 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000865 }
866 jj <<= 1;
867 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000868 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000869 }
870 /* Figure out what standard the device is using if it hasn't told
871 * us. If we know the std, check if the device is using any of
872 * the words from the next level up. It happens.
873 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000874 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000875
Rob Landleya3e4f382006-04-29 16:06:31 +0000876 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000877 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
878 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
879 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000880 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
881 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000882 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000883 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000884 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000885 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
886 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
887 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
888 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000889 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000890 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000891 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
892 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
893 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
894 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
895 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000896 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
897 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000898 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000899 } else if (((std == 2) || (!std && (like_std < 3)))
900 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
901 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000902 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000903 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000904 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
905 (val[WHATS_VALID] & OK_W64_70)) )
906 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000907 like_std = 2;
908 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000909
Rob Landleya3e4f382006-04-29 16:06:31 +0000910 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000911 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000912 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000913 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000914 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000915 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000916 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000917 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000918 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000919 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000920 kk = 1;
921 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
922 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000923 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000924 kk = 1;
925 printf("\n\tSupported: CD-ROM ATAPI");
926 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000927 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000928 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000929 jj >>= 1;
930 }
931 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000932 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000933 /* the cdrom stuff is more like ATA-2 than anything else, so: */
934 like_std = 2;
935 }
936
Rob Landleya3e4f382006-04-29 16:06:31 +0000937 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000938 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000939
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200940 puts("Configuration:");
Eric Andersen3443bd72003-07-22 07:30:36 +0000941 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000942 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000943 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000944 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000945 if (jj & 0x0001)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000946 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +0000947 jj >>=1;
948 }
949 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000950 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000951 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
952 strng = "3ms";
953 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
954 strng = "<=10ms with INTRQ";
955 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
956 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000957 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000958 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000959 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
960
961 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
962 strng = "12 bytes";
963 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
964 strng = "16 bytes";
965 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000966 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000967 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000968 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000969 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000970 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200971 mm = 0;
972 bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000973 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200974 puts("\tCHS addressing not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000975 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000976 jj = val[WHATS_VALID] & OK_W54_58;
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200977 printf("\tLogical\t\tmax\tcurrent\n"
978 "\tcylinders\t%u\t%u\n"
979 "\theads\t\t%u\t%u\n"
980 "\tsectors/track\t%u\t%u\n"
981 "\t--\n",
982 val[LCYLS],
983 jj ? val[LCYLS_CUR] : 0,
984 val[LHEADS],
985 jj ? val[LHEADS_CUR] : 0,
986 val[LSECTS],
987 jj ? val[LSECTS_CUR] : 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000988
Rob Landleyadde7982006-05-16 15:32:30 +0000989 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200990 printf("\tbytes/track: %u\tbytes/sector: %u\n",
991 val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000992
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000993 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000994 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000995 if (like_std < 3) {
996 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000997 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
998 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000999 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +00001000 mm = oo;
1001 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001002 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +00001003 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001004 }
1005 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001006 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001007 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
1008 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
1009 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001010 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
1011 (uint64_t)val[LBA_48_MSB] << 32 |
1012 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001013 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001014 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +00001015 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001016
1017 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +00001018 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001019 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
1020 bbbig = (bbbig << 9) / 1000000;
1021 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +00001022
Rob Landleyadde7982006-05-16 15:32:30 +00001023 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +00001024 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001025 else
Denis Vlasenko4daad902007-09-27 10:20:47 +00001026 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001027 }
1028
1029 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +00001030 printf("Capabilities:\n\t");
1031
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001032 if (dev == ATAPI_DEV) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001033 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP))
1034 printf("Cmd queuing, ");
1035 if (val[CAPAB_0] & OVLP_SUP)
1036 printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001037 }
Rob Landleyadde7982006-05-16 15:32:30 +00001038 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +00001039
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001040 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001041 printf("IORDY%s(can%s be disabled)\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001042 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
1043 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001044 } else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001045 puts("no IORDY");
Glenn L McGrath07085852003-10-09 07:28:22 +00001046
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001047 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001048 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001049 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
1050 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001051 }
Rob Landleyadde7982006-05-16 15:32:30 +00001052
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001053 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001054 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001055 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001056 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001057 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001058 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001059 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001060 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +00001061 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001062
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001063 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001064 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001065 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001066 else {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001067 printf("\tStandby timer values: spec'd by %s",
1068 (val[CAPAB_0] & STD_STBY) ? "standard" : "vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +00001069 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001070 printf(", %s device specific minimum\n",
1071 (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +00001072 else
Denis Vlasenko4daad902007-09-27 10:20:47 +00001073 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001074 }
1075 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001076 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001077 puts("not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001078 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001079 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +00001080 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
1081 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
1082 else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001083 puts("?");
Eric Andersen3443bd72003-07-22 07:30:36 +00001084 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001085 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001086 /* We print out elsewhere whether the APM feature is enabled or
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001087 * not. If it's not enabled, let's not repeat the info; just print
1088 * nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +00001089 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001090 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001091 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +00001092 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +00001093 }
1094 else
Eric Andersen3443bd72003-07-22 07:30:36 +00001095 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001096 }
Rob Landleyadde7982006-05-16 15:32:30 +00001097 if (like_std > 5 && val[ACOUSTIC]) {
1098 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001099 (val[ACOUSTIC] >> 8) & 0x00ff,
1100 val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +00001101 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001102 } else {
Denys Vlasenko6830ade2013-01-15 13:58:01 +01001103 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +00001104 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001105 puts("\tATA sw reset required");
Glenn L McGrath07085852003-10-09 07:28:22 +00001106
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001107 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001108 printf("\tOverlap support:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001109 if (val[PKT_REL])
1110 printf(" %uus to release bus.", val[PKT_REL]);
1111 if (val[SVC_NBSY])
1112 printf(" %uus to clear BSY after SERVICE cmd.",
1113 val[SVC_NBSY]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001114 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001115 }
1116 }
1117
1118 /* DMA stuff. Check that only one DMA mode is selected. */
1119 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001120 if (!(val[CAPAB_0] & DMA_SUP))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001121 puts("not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001122 else {
Rob Landleyadde7982006-05-16 15:32:30 +00001123 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001124 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001125 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001126 jj = val[SINGLE_DMA];
1127 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001128 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001129 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001130 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001131 jj = val[MULTI_DMA];
1132 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001133 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001134 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001135 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001136 jj = val[ULTRA_DMA];
1137 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001138 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001139 }
Rob Landleyadde7982006-05-16 15:32:30 +00001140 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001141 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001142
Rob Landleyadde7982006-05-16 15:32:30 +00001143 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001144 puts("\t\tInterleaved DMA support");
Eric Andersen3443bd72003-07-22 07:30:36 +00001145
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001146 if ((val[WHATS_VALID] & OK_W64_70)
1147 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1148 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001149 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001150 if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
1151 if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001152 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001153 }
1154 }
1155
1156 /* Programmed IO stuff */
1157 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001158 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +00001159 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001160 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001161 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001162 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001163 if (jj & 0x0001) printf("pio%d ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +00001164 jj >>=1;
1165 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001166 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001167 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001168 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001169 printf("pio%d ", ii);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001170 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001171 } else
Denis Vlasenko91303402007-10-30 19:36:54 +00001172 puts("unknown");
Glenn L McGrath07085852003-10-09 07:28:22 +00001173
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001174 if (val[WHATS_VALID] & OK_W64_70) {
1175 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001176 printf("\t\tCycle time:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001177 if (val[PIO_NO_FLOW])
1178 printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1179 if (val[PIO_FLOW])
1180 printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001181 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001182 }
1183 }
1184
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001185 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001186 puts("Commands/features:\n"
1187 "\tEnabled\tSupported:");
Eric Andersen3443bd72003-07-22 07:30:36 +00001188 jj = val[CMDS_SUPP_0];
1189 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001190 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001191 const char *feat_str = nth_string(cmd_feat_str, ii);
Denis Vlasenko91303402007-10-30 19:36:54 +00001192 if ((jj & 0x8000) && (*feat_str != '\0')) {
1193 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
Eric Andersen3443bd72003-07-22 07:30:36 +00001194 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001195 jj <<= 1;
1196 kk <<= 1;
1197 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001198 jj = val[CMDS_SUPP_0+1+(ii/16)];
1199 kk = val[CMDS_EN_0+1+(ii/16)];
1200 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001201 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001202 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +00001203 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001204 }
1205 }
1206 }
Rob Landleyadde7982006-05-16 15:32:30 +00001207 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001208 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001209 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
Glenn L McGrath07085852003-10-09 07:28:22 +00001210
Eric Andersen3443bd72003-07-22 07:30:36 +00001211 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001212 if ((eqpt != CDROM) && (like_std > 3)
1213 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1214 ) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001215 puts("Security:");
Rob Landleyadde7982006-05-16 15:32:30 +00001216 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001217 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001218 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001219 if (jj) {
1220 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001221 printf("\t%s\t%s\n",
1222 (!(jj & 0x0001)) ? "not" : "",
1223 nth_string(secu_str, ii));
Eric Andersen3443bd72003-07-22 07:30:36 +00001224 jj >>=1;
1225 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001226 if (val[SECU_STATUS] & SECU_ENABLED) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001227 printf("\tSecurity level %s\n",
1228 (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001229 }
1230 }
1231 jj = val[ERASE_TIME] & ERASE_BITS;
1232 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001233 if (jj || kk) {
Denis Vlasenko7d60fc12008-06-05 06:51:06 +00001234 bb_putchar('\t');
Rob Landleyade7f952006-05-25 18:53:06 +00001235 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1236 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001237 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001238 }
1239 }
1240
1241 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001242 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001243 if ((jj & VALID) == VALID_VAL) {
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001244 oo = (jj & RST0);
1245 if (!oo)
Rob Landleyadde7982006-05-16 15:32:30 +00001246 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001247 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001248 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001249 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001250 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001251 else
Rob Landleyadde7982006-05-16 15:32:30 +00001252 strng = "";
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001253 printf("HW reset results:\n"
1254 "\tCBLID- %s Vih\n"
1255 "\tDevice num = %i%s\n",
1256 (val[HWRST_RSLT] & CBLID) ? "above" : "below",
1257 !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001258 }
1259
1260 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001261 if ((like_std > 4) && (eqpt != CDROM)) {
1262 if (val[CFA_PWR_MODE] & VALID_W160) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001263 printf("CFA power mode 1:\n"
1264 "\t%s%s\n",
1265 (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
1266 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001267 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001268 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001269 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001270 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001271 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001272 }
1273 }
1274
Rob Landleyadde7982006-05-16 15:32:30 +00001275 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001276}
1277#endif
1278
Eric Andersen3443bd72003-07-22 07:30:36 +00001279// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1280// then the HDIO_GET_IDENTITY only returned 142 bytes.
1281// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1282// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1283// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1284// (which they should, but they should just return -EINVAL).
1285//
1286// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1287// On a really old system, it will not, and we will be confused.
1288// Too bad, really.
1289
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001290#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko91303402007-10-30 19:36:54 +00001291static const char cfg_str[] ALIGN1 =
Denis Vlasenko6b404432008-01-07 16:13:14 +00001292 """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
1293 "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
1294 "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1295 "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
Denis Vlasenko91303402007-10-30 19:36:54 +00001296;
Eric Andersen3443bd72003-07-22 07:30:36 +00001297
Denis Vlasenko91303402007-10-30 19:36:54 +00001298static const char BuffType[] ALIGN1 =
1299 "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
1300;
Eric Andersen3443bd72003-07-22 07:30:36 +00001301
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +02001302static NOINLINE void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001303{
1304 int i;
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00001305 const unsigned short *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001306
Glenn L McGrath07085852003-10-09 07:28:22 +00001307 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1308 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001309 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001310 if (id->config & (1<<i))
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001311 printf(" %s", nth_string(cfg_str, i));
Rob Landleyadde7982006-05-16 15:32:30 +00001312 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001313 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001314 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
1315 id->cyls, id->heads, id->sectors, id->track_bytes,
1316 id->sector_bytes, id->ecc_bytes,
1317 id->buf_type,
1318 nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
1319 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001320 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001321 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001322 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001323 printf("?%u?", id->multsect);
1324 else if (id->multsect)
1325 printf("%u", id->multsect);
1326 else
1327 printf("off");
1328 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001329 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001330
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001331 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001332 printf(" (maybe):");
1333
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001334 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001335 id->cur_sectors,
1336 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001337 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1338 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001339 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001340
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001341 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001342 printf(", LBAsects=%u", id->lba_capacity);
1343
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001344 printf("\n IORDY=%s",
1345 (id->capability & 8)
1346 ? ((id->capability & 4) ? "on/off" : "yes")
1347 : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001348
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001349 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001350 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001351
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001352 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001353 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1354
1355 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001356 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001357 printf("pio0 ");
1358 if (id->tPIO >= 1) printf("pio1 ");
1359 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001360 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001361 if (id->field_valid & 2) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001362 static const masks_labels_t pio_modes = {
1363 .masks = { 1, 2, ~3 },
1364 .labels = "pio3 \0""pio4 \0""pio? \0",
1365 };
1366 print_flags(&pio_modes, id->eide_pio_modes);
Rob Landleyade7f952006-05-25 18:53:06 +00001367 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001368 if (id->capability & 1) {
1369 if (id->dma_1word | id->dma_mword) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001370 static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
Rob Landleyade7f952006-05-25 18:53:06 +00001371 printf("\n DMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001372 print_flags_separated(dma_wmode_masks,
1373 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
1374 id->dma_1word, NULL);
1375 print_flags_separated(dma_wmode_masks,
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001376 "*\0""mdma0 \0""*\0""mdma1 \0""*\0""mdma2 \0""*\0""mdma? \0",
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001377 id->dma_mword, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001378 }
1379 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001380 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001381 static const masks_labels_t ultra_modes1 = {
1382 .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
1383 .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
1384 };
Denis Vlasenko7049ff82008-06-25 09:53:17 +00001385
Rob Landleyade7f952006-05-25 18:53:06 +00001386 printf("\n UDMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001387 print_flags(&ultra_modes1, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001388#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001389 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001390#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001391 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001392#endif /* __NEW_HD_DRIVE_ID */
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001393 static const masks_labels_t ultra_modes2 = {
1394 .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
1395 0x2000, 0x0020, 0x4000, 0x0040,
1396 0x8000, 0x0080 },
1397 .labels = "*\0""udma3 \0""*\0""udma4 \0"
1398 "*\0""udma5 \0""*\0""udma6 \0"
1399 "*\0""udma7 \0"
1400 };
1401 print_flags(&ultra_modes2, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001402 }
1403 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001404 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001405 if (id_regs[83] & 8) {
1406 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001407 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001408 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001409 printf(": unknown setting");
1410 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001411 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001412 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001413 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001414 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001415#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001416 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1417 || (id->major_rev_num && id->minor_rev_num <= 31)
1418 ) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001419 printf("\n Drive conforms to: %s: ",
1420 (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
1421 if (id->major_rev_num != 0x0000 /* NOVAL_0 */
1422 && id->major_rev_num != 0xFFFF /* NOVAL_1 */
1423 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001424 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001425 if (id->major_rev_num & (1<<i))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001426 printf(" ATA/ATAPI-%u", i);
Rob Landleyadde7982006-05-16 15:32:30 +00001427 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001428 }
1429 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001430#endif /* __NEW_HD_DRIVE_ID */
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001431 puts("\n\n * current active mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001432}
1433#endif
1434
Denis Vlasenko892536f2007-09-27 10:23:34 +00001435static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001436{
Rob Landleya3e4f382006-04-29 16:06:31 +00001437 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001438 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001439#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001440 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001441 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1442 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1443 bb_perror_msg("HDIO_DRIVE_CMD");
1444 else
1445 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1446 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001447#endif
1448}
1449
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001450static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001451{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001452 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001453}
1454
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001455static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001456{
Rob Landleyadde7982006-05-16 15:32:30 +00001457 int i;
1458
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001459 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001460 /* access all sectors of buf to ensure the read fully completed */
1461 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1462 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001463}
1464
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001465static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001466{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001467 union {
1468 unsigned long long blksize64;
1469 unsigned blksize32;
1470 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001471
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001472 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1473 u.blksize64 /= (1024 * 1024);
1474 } else {
1475 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1476 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001477 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001478 if (u.blksize64 > UINT_MAX)
1479 return UINT_MAX;
1480 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001481}
Eric Andersen50af12d2003-08-06 08:47:59 +00001482
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001483static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001484{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001485 unsigned sec = elapsed_us / 1000000;
1486 unsigned hs = (elapsed_us % 1000000) / 10000;
1487
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001488 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001489 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001490 /* "| 1" prevents div-by-0 */
1491 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001492 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001493 // = kb / elapsed_sec
1494 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001495}
1496
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001497static void do_time(int cache /*,int fd*/)
1498/* cache=1: time cache: repeatedly read N MB at offset 0
1499 * cache=0: time device: linear read, starting at offset 0
1500 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001501{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001502 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001503 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001504 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001505 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001506 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001507
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001508 if (mlock(buf, TIMING_BUF_BYTES))
1509 bb_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001510
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001511 /* Clear out the device request queues & give them time to complete.
1512 * NB: *small* delay. User is expected to have a clue and to not run
1513 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001514 sync();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001515 sleep(1);
1516 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001517 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001518 read_big_block(buf);
1519 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001520 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001521 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001522 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +01001523 fflush_all();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001524
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001525 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001526 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001527 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001528 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001529 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001530 max_iterations = UINT_MAX;
1531 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001532 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001533 /* Don't want to read past the end! */
1534 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1535 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001536 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001537 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001538 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001539 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001540 read_big_block(buf);
1541 elapsed = (unsigned)monotonic_us() - start;
1542 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001543 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001544 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001545 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1546 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001547 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001548 * from elapsed */
1549 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001550 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001551 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001552 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001553 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001554 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001555 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001556 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001557 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001558 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001559 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001560 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001561 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001562}
1563
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001564#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001565static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001566{
Rob Landleyadde7982006-05-16 15:32:30 +00001567 if (value == BUSSTATE_ON)
1568 on_off(1);
1569 else if (value == BUSSTATE_OFF)
1570 on_off(0);
1571 else if (value == BUSSTATE_TRISTATE)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001572 puts(" (tristate)");
Rob Landleyadde7982006-05-16 15:32:30 +00001573 else
Denys Vlasenko327f5502013-11-29 16:45:45 +01001574 printf(" (unknown: %u)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001575}
1576#endif
1577
1578#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001579static void interpret_standby(uint8_t standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001580{
Rob Landley403777f2006-08-03 20:22:37 +00001581 printf(" (");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001582 if (standby == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001583 printf("off");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001584 } else if (standby <= 240 || standby == 252 || standby == 255) {
1585 /* standby is in 5 sec units */
Denys Vlasenko2b132e52009-05-20 23:21:42 +02001586 unsigned t = standby * 5;
1587 printf("%u minutes %u seconds", t / 60, t % 60);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001588 } else if (standby <= 251) {
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001589 unsigned t = (standby - 240); /* t is in 30 min units */;
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001590 printf("%u.%c hours", t / 2, (t & 1) ? '5' : '0');
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001591 }
1592 if (standby == 253)
1593 printf("vendor-specific");
1594 if (standby == 254)
1595 printf("reserved");
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001596 puts(")");
Eric Andersen3443bd72003-07-22 07:30:36 +00001597}
1598
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001599static const uint8_t xfermode_val[] ALIGN1 = {
1600 8, 9, 10, 11, 12, 13, 14, 15,
1601 16, 17, 18, 19, 20, 21, 22, 23,
1602 32, 33, 34, 35, 36, 37, 38, 39,
1603 64, 65, 66, 67, 68, 69, 70, 71
1604};
1605/* NB: we save size by _not_ storing terninating NUL! */
1606static const char xfermode_name[][5] ALIGN1 = {
1607 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1608 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1609 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1610 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001611};
1612
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001613static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001614{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001615 int val;
1616 unsigned i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001617
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001618 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1619 if (!strncmp(name, xfermode_name[i], 5))
1620 if (strlen(name) <= 5)
1621 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001622 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001623 /* Negative numbers are invalid and are caught later */
1624 val = bb_strtoi(name, NULL, 10);
1625 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001626 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001627 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001628}
1629
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001630static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001631{
1632 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001633 if (xfermode == 0)
1634 printf("default PIO mode");
1635 else if (xfermode == 1)
1636 printf("default PIO mode, disable IORDY");
1637 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001638 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001639 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001640 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001641 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001642 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001643 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001644 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001645 else
Denis Vlasenko91303402007-10-30 19:36:54 +00001646 printf("unknown");
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001647 puts(")");
Eric Andersen3443bd72003-07-22 07:30:36 +00001648}
1649#endif /* HDIO_DRIVE_CMD */
1650
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001651static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001652{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001653 if (flag)
Denys Vlasenko327f5502013-11-29 16:45:45 +01001654 printf(" setting %s to %lu\n", s, value);
Rob Landleyadde7982006-05-16 15:32:30 +00001655}
1656
Rob Landleya3e4f382006-04-29 16:06:31 +00001657static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001658{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001659 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001660 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001661#ifndef HDIO_DRIVE_CMD
1662 int force_operation = 0;
1663#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001664 /* Please restore args[n] to these values after each ioctl
1665 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001666 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001667 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001668
Bernhard Reutner-Fischera4830872009-10-26 23:27:08 +01001669 /*fd = xopen_nonblocking(devname);*/
1670 xmove_fd(xopen_nonblocking(devname), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001671 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001672
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001673 if (getset_readahead == IS_SET) {
1674 print_flag(getset_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001675 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001676 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001677#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1678 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001679 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001680 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001681 }
1682#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001683#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001684 if (scan_hwif == IS_SET) {
Rob Landley20deab02006-05-07 23:34:15 +00001685 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001686 args[0] = hwif_data;
1687 args[1] = hwif_ctrl;
1688 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001689 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001690 args[0] = WIN_SETFEATURES;
1691 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001692 }
1693#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001694 if (set_piomode) {
1695 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001696 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001697 if (piomode == 255)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001698 puts("auto-tune PIO mode");
Eric Andersen3443bd72003-07-22 07:30:36 +00001699 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001700 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001701 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001702 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001703 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001704 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001705 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001706 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001707 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001708 if (getset_io32bit == IS_SET) {
1709 print_flag(getset_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001710 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001711 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001712 if (getset_mult == IS_SET) {
1713 print_flag(getset_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001714#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001715 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001716#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001717 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001718#endif
1719 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001720 if (getset_readonly == IS_SET) {
1721 print_flag_on_off(getset_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001722 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001723 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001724 if (getset_unmask == IS_SET) {
1725 print_flag_on_off(getset_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001726 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001727 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001728#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001729 if (getset_dma == IS_SET) {
1730 print_flag_on_off(getset_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001731 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001732 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001733#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001734#ifdef HDIO_SET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001735 if (getset_dma_q == IS_SET) {
1736 print_flag_on_off(getset_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001737 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001738 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001739#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001740 if (getset_nowerr == IS_SET) {
1741 print_flag_on_off(getset_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001742 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001743 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001744 if (getset_keep == IS_SET) {
1745 print_flag_on_off(getset_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001746 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001747 }
1748#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001749 if (getset_doorlock == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001750 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001751 args[2] = 0;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001752 print_flag_on_off(getset_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001753 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001754 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001755 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001756 if (getset_dkeep == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001757 /* lock/unlock the drive's "feature" settings */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001758 print_flag_on_off(getset_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001759 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001760 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001761 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001762 if (getset_defects == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001763 args[2] = defects ? 0x04 : 0x84;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001764 print_flag(getset_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001765 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001766 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001767 if (getset_prefetch == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001768 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001769 args[2] = 0xab;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001770 print_flag(getset_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001771 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001772 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001773 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001774 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001775 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001776 args[2] = 3;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001777 print_flag(1, "xfermode", xfermode_requested);
1778 interpret_xfermode(xfermode_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001779 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001780 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001781 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001782 if (getset_lookahead == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001783 args[2] = lookahead ? 0xaa : 0x55;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001784 print_flag_on_off(getset_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001785 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001786 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001787 if (getset_apmmode == IS_SET) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001788 /* feature register */
1789 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */;
Rob Landleyadde7982006-05-16 15:32:30 +00001790 args[1] = apmmode; /* sector count register 1-255 */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001791 printf(" setting APM level to %s 0x%02lX (%ld)\n",
1792 (apmmode == 255) ? "disabled" : "",
1793 apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001794 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001795 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001796 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001797 if (getset_wcache == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001798#ifdef DO_FLUSHCACHE
1799#ifndef WIN_FLUSHCACHE
1800#define WIN_FLUSHCACHE 0xe7
1801#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001802#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001803 args[2] = wcache ? 0x02 : 0x82;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001804 print_flag_on_off(getset_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001805#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001806 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001807 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001808#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001809 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001810#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001811 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001812 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001813#endif /* DO_FLUSHCACHE */
1814 }
Rob Landley39cf6452006-05-05 16:52:28 +00001815
1816 /* In code below, we do not preserve args[0], but the rest
1817 is preserved, including args[2] */
1818 args[2] = 0;
1819
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001820 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001821#ifndef WIN_STANDBYNOW1
1822#define WIN_STANDBYNOW1 0xE0
1823#endif
1824#ifndef WIN_STANDBYNOW2
1825#define WIN_STANDBYNOW2 0x94
1826#endif
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001827 puts(" issuing standby command");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001828 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001829 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001830 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001831 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001832#ifndef WIN_SLEEPNOW1
1833#define WIN_SLEEPNOW1 0xE6
1834#endif
1835#ifndef WIN_SLEEPNOW2
1836#define WIN_SLEEPNOW2 0x99
1837#endif
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001838 puts(" issuing sleep command");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001839 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001840 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001841 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001842 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001843 args[0] = 0xfb;
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001844 puts(" disabling Seagate auto powersaving mode");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001845 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001846 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001847 if (getset_standby == IS_SET) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001848 args[0] = WIN_SETIDLE1;
1849 args[1] = standby_requested;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001850 print_flag(1, "standby", standby_requested);
1851 interpret_standby(standby_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001852 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001853 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001854 }
1855#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001856 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001857 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001858 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001859 if (-1 == read(fd, buf, sizeof(buf)))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001860 bb_perror_msg("read of 512 bytes failed");
Eric Andersen3443bd72003-07-22 07:30:36 +00001861 }
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001862#endif /* HDIO_DRIVE_CMD */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001863 if (getset_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001864 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001865 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001866 /* To be coherent with ioctl_or_warn. */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001867 if (getset_mult && ENABLE_IOCTL_HEX2STR_ERROR)
Eric Andersen06d4ec22004-03-19 10:53:52 +00001868 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001869 else
1870 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001871 } else if (getset_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001872 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001873 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001874 }
1875 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001876 if (getset_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001877 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001878 printf(" IO_support\t=%3ld (", parm);
1879 if (parm == 0)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001880 puts("default 16-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001881 else if (parm == 2)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001882 puts("16-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001883 else if (parm == 1)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001884 puts("32-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001885 else if (parm == 3)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001886 puts("32-bit w/sync)");
Rob Landleyadde7982006-05-16 15:32:30 +00001887 else if (parm == 8)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001888 puts("Request-Queue-Bypass)");
Rob Landleyadde7982006-05-16 15:32:30 +00001889 else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001890 puts("\?\?\?)");
Eric Andersen3443bd72003-07-22 07:30:36 +00001891 }
1892 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001893 if (getset_unmask) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001894 if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001895 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001896 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001897#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001898 if (getset_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001899 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001900 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001901 if (parm == 8)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001902 puts(" (DMA-Assisted-PIO)");
Eric Andersen3443bd72003-07-22 07:30:36 +00001903 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001904 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001905 }
1906 }
1907#endif
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001908#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001909 if (getset_dma_q) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001910 if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001911 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001912 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001913#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001914 if (getset_keep) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001915 if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001916 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001917 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001918 if (getset_nowerr) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001919 if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001920 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001921 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001922 if (getset_readonly) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001923 if (!ioctl_or_warn(fd, BLKROGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001924 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001925 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001926 if (getset_readahead) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001927 if (!ioctl_or_warn(fd, BLKRAGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001928 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001929 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001930 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001931 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001932 struct hd_geometry g;
1933
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001934 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001935 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001936 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001937 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001938 }
1939#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001940 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001941#ifndef WIN_CHECKPOWERMODE1
1942#define WIN_CHECKPOWERMODE1 0xE5
1943#endif
1944#ifndef WIN_CHECKPOWERMODE2
1945#define WIN_CHECKPOWERMODE2 0x98
1946#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001947 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001948
Rob Landleye5b281f2006-04-29 15:49:18 +00001949 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001950 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001951 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001952 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001953 else
1954 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001955 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001956 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001957 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001958
Eric Andersen3443bd72003-07-22 07:30:36 +00001959 printf(" drive state is: %s\n", state);
1960 }
1961#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001962#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1963 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001964 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001965 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001966#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1967#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1968 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001969 args[0] = 0;
1970 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001971 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001972 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001973#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1974#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1975 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001976 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001977
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001978 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1979 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001980 id.multsect = multcount;
1981 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001982 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001983 id.multsect_valid &= ~1;
1984 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001985 } else if (errno == -ENOMSG)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001986 puts(" no identification info available");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001987 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001988 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001989 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001990 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001991 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001992
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001993 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001994 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001995
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001996 memset(args1, 0, sizeof(args1));
1997 args1[0] = WIN_IDENTIFY;
1998 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001999 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00002000 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00002001 }
2002#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002003#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002004 if (getset_busstate == IS_SET) {
2005 print_flag(1, "bus state", busstate);
2006 bus_state_value(busstate);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002007 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00002008 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002009 if (getset_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002010 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00002011 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00002012 bus_state_value(parm);
2013 }
2014 }
2015#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00002016 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002017 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00002018
Eric Andersen3443bd72003-07-22 07:30:36 +00002019 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00002020 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00002021 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00002022 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00002023 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00002024 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00002025 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00002026}
2027
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002028#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00002029static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00002030{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002031 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00002032 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002033 if (c >= 'a' && c <= 'f')
2034 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00002035 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
2036}
2037
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002038static void identify_from_stdin(void) NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00002039static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00002040{
Rob Landley0753f4a2006-06-07 00:27:25 +00002041 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002042 unsigned char buf[1280];
2043 unsigned char *b = (unsigned char *)buf;
2044 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00002045
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00002046 xread(STDIN_FILENO, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00002047
Rob Landley0753f4a2006-06-07 00:27:25 +00002048 // Convert the newline-separated hex data into an identify block.
2049
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002050 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00002051 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002052 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002053 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00002054 }
Rob Landley0753f4a2006-06-07 00:27:25 +00002055
2056 // Parse the data.
2057
Rob Landley6389ff12006-05-01 19:28:53 +00002058 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00002059}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00002060#else
2061void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00002062#endif
2063
Rob Landley20deab02006-05-07 23:34:15 +00002064/* busybox specific stuff */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002065static int parse_opts(unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00002066{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00002067 if (optarg) {
Denis Vlasenko13858992006-10-08 12:49:22 +00002068 *value = xatol_range(optarg, min, max);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002069 return IS_SET;
Denis Vlasenko6429aab2006-09-23 12:22:11 +00002070 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002071 return IS_GET;
2072}
2073static int parse_opts_0_max(unsigned long *value, int max)
2074{
2075 return parse_opts(value, 0, max);
2076}
2077static int parse_opts_0_1(unsigned long *value)
2078{
2079 return parse_opts(value, 0, 1);
2080}
2081static int parse_opts_0_INTMAX(unsigned long *value)
2082{
2083 return parse_opts(value, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00002084}
2085
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00002086static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00002087{
2088 if (flag) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002089 *get = IS_GET;
Rob Landley20deab02006-05-07 23:34:15 +00002090 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002091 *value = translate_xfermode(optarg);
2092 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00002093 }
2094 }
2095}
2096
Rob Landley06208412006-05-31 22:52:57 +00002097/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002098static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00002099 "gfu::n::p:r::m::c::k::a::B:tT"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002100 IF_FEATURE_HDPARM_GET_IDENTITY("iI")
2101 IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
Rob Landley20deab02006-05-07 23:34:15 +00002102#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002103 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00002104#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002105 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
Rob Landley20deab02006-05-07 23:34:15 +00002106#ifdef HDIO_GET_QDMA
2107#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002108 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00002109#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002110 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00002111#endif
2112#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002113 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
2114 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
2115 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
Rob Landley20deab02006-05-07 23:34:15 +00002116/*-------------------------------------*/
2117
2118/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002119int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00002120int hdparm_main(int argc, char **argv)
2121{
2122 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00002123 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00002124
Denys Vlasenko16714242011-09-21 01:59:15 +02002125 INIT_G();
2126
Rob Landley06208412006-05-31 22:52:57 +00002127 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00002128 flagcount++;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002129 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
2130 IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00002131 get_geom |= (c == 'g');
2132 do_flush |= (c == 'f');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002133 if (c == 'u') getset_unmask = parse_opts_0_1(&unmask);
2134 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
2135 if (c == 'd') getset_dma = parse_opts_0_max(&dma, 9);
2136 )
2137 if (c == 'n') getset_nowerr = parse_opts_0_1(&nowerr);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002138 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002139 if (c == 'r') getset_readonly = parse_opts_0_1(&readonly);
2140 if (c == 'm') getset_mult = parse_opts_0_INTMAX(&mult /*32*/);
2141 if (c == 'c') getset_io32bit = parse_opts_0_INTMAX(&io32bit /*8*/);
2142 if (c == 'k') getset_keep = parse_opts_0_1(&keep);
2143 if (c == 'a') getset_readahead = parse_opts_0_INTMAX(&Xreadahead);
2144 if (c == 'B') getset_apmmode = parse_opts(&apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002145 do_flush |= do_timings |= (c == 't');
2146 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002147#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002148 if (c == 'S') getset_standby = parse_opts_0_max(&standby_requested, 255);
2149 if (c == 'D') getset_defects = parse_opts_0_INTMAX(&defects);
2150 if (c == 'P') getset_prefetch = parse_opts_0_INTMAX(&prefetch);
Rob Landleyade7f952006-05-25 18:53:06 +00002151 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002152 if (c == 'K') getset_dkeep = parse_opts_0_1(&prefetch);
2153 if (c == 'A') getset_lookahead = parse_opts_0_1(&lookahead);
2154 if (c == 'L') getset_doorlock = parse_opts_0_1(&doorlock);
2155 if (c == 'W') getset_wcache = parse_opts_0_1(&wcache);
Rob Landleyade7f952006-05-25 18:53:06 +00002156 get_powermode |= (c == 'C');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002157 set_standbynow |= (c == 'y');
2158 set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002159 reread_partn |= (c == 'z');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002160 set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002161#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002162 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') unregister_hwif = parse_opts_0_INTMAX(&hwif));
Rob Landley20deab02006-05-07 23:34:15 +00002163#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002164 if (c == 'Q') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002165 getset_dma_q = parse_opts_0_INTMAX(&dma_q);
Rob Landley19802562006-05-08 15:35:46 +00002166 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002167#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002168 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002169 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') perform_tristate = parse_opts_0_1(&tristate));
2170 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') getset_busstate = parse_opts_0_max(&busstate, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002171#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2172 if (c == 'R') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002173 scan_hwif = parse_opts_0_INTMAX(&hwif_data);
Denys Vlasenko77832482010-08-12 14:14:45 +02002174 hwif_ctrl = xatoi_positive((argv[optind]) ? argv[optind] : "");
2175 hwif_irq = xatoi_positive((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002176 /* Move past the 2 additional arguments */
2177 argv += 2;
2178 argc -= 2;
2179 }
2180#endif
2181 }
Rob Landleyade7f952006-05-25 18:53:06 +00002182 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002183 if (!flagcount) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002184 getset_mult = getset_io32bit = getset_unmask = getset_keep = getset_readonly = getset_readahead = get_geom = IS_GET;
2185 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(getset_dma = IS_GET);
Rob Landleyade7f952006-05-25 18:53:06 +00002186 }
Rob Landley20deab02006-05-07 23:34:15 +00002187 argv += optind;
2188
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002189 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002190 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2191 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002192 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002193 }
2194
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002195 do {
2196 process_dev(*argv++);
2197 } while (*argv);
2198
2199 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002200}