blob: 83e2f8d53fd2d1e395d371117ed739b3d29e16ca [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 Vlasenkob097a842018-12-28 03:20:17 +010015//config: bool "hdparm (25 kb)"
Denys Vlasenkofb4da162016-11-22 23:14:24 +010016//config: default y
Denys Vlasenkofb4da162016-11-22 23:14:24 +010017//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020018//config: Get/Set hard drive parameters. Primarily intended for ATA
19//config: drives.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010020//config:
21//config:config FEATURE_HDPARM_GET_IDENTITY
22//config: bool "Support obtaining detailed information directly from drives"
23//config: default y
24//config: depends on HDPARM
25//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020026//config: Enable the -I and -i options to obtain detailed information
27//config: directly from drives about their capabilities and supported ATA
28//config: feature set. If no device name is specified, hdparm will read
29//config: identify data from stdin. Enabling this option will add about 16k...
Denys Vlasenkofb4da162016-11-22 23:14:24 +010030//config:
31//config:config FEATURE_HDPARM_HDIO_SCAN_HWIF
32//config: bool "Register an IDE interface (DANGEROUS)"
33//config: default y
34//config: depends on HDPARM
35//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020036//config: Enable the 'hdparm -R' option to register an IDE interface.
37//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010038//config:
39//config:config FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
40//config: bool "Un-register an IDE interface (DANGEROUS)"
41//config: default y
42//config: depends on HDPARM
43//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020044//config: Enable the 'hdparm -U' option to un-register an IDE interface.
45//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010046//config:
47//config:config FEATURE_HDPARM_HDIO_DRIVE_RESET
48//config: bool "Perform device reset (DANGEROUS)"
49//config: default y
50//config: depends on HDPARM
51//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020052//config: Enable the 'hdparm -w' option to perform a device reset.
53//config: This is dangerous stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010054//config:
55//config:config FEATURE_HDPARM_HDIO_TRISTATE_HWIF
56//config: bool "Tristate device for hotswap (DANGEROUS)"
57//config: default y
58//config: depends on HDPARM
59//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020060//config: Enable the 'hdparm -x' option to tristate device for hotswap,
61//config: and the '-b' option to get/set bus state. This is dangerous
62//config: stuff, so you should probably say N.
Denys Vlasenkofb4da162016-11-22 23:14:24 +010063//config:
64//config:config FEATURE_HDPARM_HDIO_GETSET_DMA
65//config: bool "Get/set using_dma flag"
66//config: default y
67//config: depends on HDPARM
68//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020069//config: Enable the 'hdparm -d' option to get/set using_dma flag.
Pere Orga5bc8c002011-04-11 03:29:49 +020070
Denys Vlasenkof88e3bf2016-11-22 23:54:17 +010071//applet:IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP))
72
73//kbuild:lib-$(CONFIG_HDPARM) += hdparm.o
74
Pere Orga5bc8c002011-04-11 03:29:49 +020075//usage:#define hdparm_trivial_usage
76//usage: "[OPTIONS] [DEVICE]"
77//usage:#define hdparm_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020078//usage: " -a Get/set fs readahead"
Pere Orga5bc8c002011-04-11 03:29:49 +020079//usage: "\n -A Set drive read-lookahead flag (0/1)"
80//usage: "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)"
81//usage: "\n -B Set Advanced Power Management setting (1-255)"
82//usage: "\n -c Get/set IDE 32-bit IO setting"
83//usage: "\n -C Check IDE power mode status"
84//usage: IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
85//usage: "\n -d Get/set using_dma flag")
86//usage: "\n -D Enable/disable drive defect-mgmt"
87//usage: "\n -f Flush buffer cache for device on exit"
88//usage: "\n -g Display drive geometry"
89//usage: "\n -h Display terse usage information"
90//usage: IF_FEATURE_HDPARM_GET_IDENTITY(
91//usage: "\n -i Display drive identification")
92//usage: IF_FEATURE_HDPARM_GET_IDENTITY(
93//usage: "\n -I Detailed/current information directly from drive")
94//usage: "\n -k Get/set keep_settings_over_reset flag (0/1)"
95//usage: "\n -K Set drive keep_features_over_reset flag (0/1)"
96//usage: "\n -L Set drive doorlock (0/1) (removable harddisks only)"
97//usage: "\n -m Get/set multiple sector count"
98//usage: "\n -n Get/set ignore-write-errors flag (0/1)"
99//usage: "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)"
100//usage: "\n -P Set drive prefetch count"
101/* //usage: "\n -q Change next setting quietly" - not supported ib bbox */
102//usage: "\n -Q Get/set DMA tagged-queuing depth (if supported)"
103//usage: "\n -r Get/set readonly flag (DANGEROUS to set)"
104//usage: IF_FEATURE_HDPARM_HDIO_SCAN_HWIF(
105//usage: "\n -R Register an IDE interface (DANGEROUS)")
106//usage: "\n -S Set standby (spindown) timeout"
107//usage: "\n -t Perform device read timings"
108//usage: "\n -T Perform cache read timings"
109//usage: "\n -u Get/set unmaskirq flag (0/1)"
110//usage: IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(
111//usage: "\n -U Unregister an IDE interface (DANGEROUS)")
112//usage: "\n -v Defaults; same as -mcudkrag for IDE drives"
113//usage: "\n -V Display program version and exit immediately"
114//usage: IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(
115//usage: "\n -w Perform device reset (DANGEROUS)")
116//usage: "\n -W Set drive write-caching flag (0/1) (DANGEROUS)"
117//usage: IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(
118//usage: "\n -x Tristate device for hotswap (0/1) (DANGEROUS)")
119//usage: "\n -X Set IDE xfer mode (DANGEROUS)"
120//usage: "\n -y Put IDE drive in standby mode"
121//usage: "\n -Y Put IDE drive to sleep"
122//usage: "\n -Z Disable Seagate auto-powersaving mode"
123//usage: "\n -z Reread partition table"
124
Denys Vlasenko860d2bb2009-07-10 18:37:06 +0200125#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200126#include "common_bufsiz.h"
Denys Vlasenko860d2bb2009-07-10 18:37:06 +0200127/* must be _after_ libbb.h: */
Eric Andersen3443bd72003-07-22 07:30:36 +0000128#include <linux/hdreg.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200129#include <sys/mount.h>
Denys Vlasenkoaf3fd142009-09-22 23:16:39 +0200130#if !defined(BLKGETSIZE64)
131# define BLKGETSIZE64 _IOR(0x12,114,size_t)
132#endif
Eric Andersen3443bd72003-07-22 07:30:36 +0000133
Eric Andersen3443bd72003-07-22 07:30:36 +0000134/* device types */
135/* ------------ */
136#define NO_DEV 0xffff
137#define ATA_DEV 0x0000
138#define ATAPI_DEV 0x0001
139
140/* word definitions */
141/* ---------------- */
142#define GEN_CONFIG 0 /* general configuration */
143#define LCYLS 1 /* number of logical cylinders */
144#define CONFIG 2 /* specific configuration */
145#define LHEADS 3 /* number of logical heads */
146#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
147#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
148#define LSECTS 6 /* number of logical sectors/track */
149#define START_SERIAL 10 /* ASCII serial number */
150#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
151#define BUF_TYPE 20 /* buffer type (ATA-1) */
152#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
153#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
154#define START_FW_REV 23 /* ASCII firmware revision */
155#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000156#define START_MODEL 27 /* ASCII model number */
157#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000158#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +0000159#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
160#define CAPAB_0 49 /* capabilities */
161#define CAPAB_1 50
162#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
163#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
164#define WHATS_VALID 53 /* what fields are valid */
165#define LCYLS_CUR 54 /* current logical cylinders */
166#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000167#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +0000168#define CAPACITY_LSB 57 /* current capacity in sectors */
169#define CAPACITY_MSB 58
170#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
171#define LBA_SECTS_LSB 60 /* LBA: total number of user */
172#define LBA_SECTS_MSB 61 /* addressable sectors */
173#define SINGLE_DMA 62 /* singleword DMA modes */
174#define MULTI_DMA 63 /* multiword DMA modes */
175#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
176 /* multiword DMA xfer cycle time: */
177#define DMA_TIME_MIN 65 /* - minimum */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +0000178#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
Eric Andersen3443bd72003-07-22 07:30:36 +0000179 /* minimum PIO xfer cycle time: */
180#define PIO_NO_FLOW 67 /* - without flow control */
181#define PIO_FLOW 68 /* - with IORDY flow control */
182#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
183#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
184#define CDR_MAJOR 73 /* CD ROM: major version number */
185#define CDR_MINOR 74 /* CD ROM: minor version number */
186#define QUEUE_DEPTH 75 /* queue depth */
187#define MAJOR 80 /* major version number */
188#define MINOR 81 /* minor version number */
189#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
190#define CMDS_SUPP_1 83
191#define CMDS_SUPP_2 84
192#define CMDS_EN_0 85 /* command/feature set(s) enabled */
193#define CMDS_EN_1 86
194#define CMDS_EN_2 87
195#define ULTRA_DMA 88 /* ultra DMA modes */
196 /* time to complete security erase */
197#define ERASE_TIME 89 /* - ordinary */
198#define ENH_ERASE_TIME 90 /* - enhanced */
199#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +0000200 in low byte, 0x40 in high byte. */
Denis Vlasenko551ffdc2009-04-01 19:48:05 +0000201#define PSWD_CODE 92 /* master password revision code */
Eric Andersen3443bd72003-07-22 07:30:36 +0000202#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000203#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000204#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
205#define LBA_MID 101 /* bits are used, but addr 103 */
206#define LBA_48_MSB 102 /* has been reserved for LBA in */
207#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000208#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +0000209#define SECU_STATUS 128 /* security status */
210#define CFA_PWR_MODE 160 /* CFA power mode 1 */
211#define START_MEDIA 176 /* media serial number */
212#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
213#define START_MANUF 196 /* media manufacturer I.D. */
214#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
215#define INTEGRITY 255 /* integrity word */
216
217/* bit definitions within the words */
218/* -------------------------------- */
219
220/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
221#define VALID 0xc000
222#define VALID_VAL 0x4000
223/* many words are considered invalid if they are either all-0 or all-1 */
224#define NOVAL_0 0x0000
225#define NOVAL_1 0xffff
226
227/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000228#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000229#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
230#define MEDIA_REMOVABLE 0x0080
231#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
232#define INCOMPLETE 0x0004
233#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
234#define DRQ_RESPONSE_TIME 0x0060
235#define DRQ_3MS_VAL 0x0000
236#define DRQ_INTR_VAL 0x0020
237#define DRQ_50US_VAL 0x0040
238#define PKT_SIZE_SUPPORTED 0x0003
239#define PKT_SIZE_12_VAL 0x0000
240#define PKT_SIZE_16_VAL 0x0001
241#define EQPT_TYPE 0x1f00
242#define SHIFT_EQPT 8
243
244#define CDROM 0x0005
245
Eric Andersen3443bd72003-07-22 07:30:36 +0000246/* word 1: number of logical cylinders */
247#define LCYLS_MAX 0x3fff /* maximum allowable value */
248
Eric Andersenaff114c2004-04-14 17:51:38 +0000249/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000250 * (a) require SET FEATURES to spin-up
251 * (b) require spin-up to fully reply to IDENTIFY DEVICE
252 */
253#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
254#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000255#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000256#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
257
258/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
259#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
260#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
261
262/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000263#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000264#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
265#define IORDY_OFF 0x0400 /* 1=may be disabled */
266#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
267#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
268#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
269#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
270#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
271#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
272
273/* word 50: capabilities 1 */
274#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
275
276/* words 51 & 52: PIO & DMA cycle times */
277#define MODE 0xff00 /* the mode is in the MSBs */
278
279/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000280#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000281#define OK_W64_70 0x0002 /* see above for word descriptions */
282#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
283
284/*word 63,88: dma_mode, ultra_dma_mode*/
285#define MODE_MAX 7 /* bit definitions force udma <=7 (when
286 * udma >=8 comes out it'll have to be
287 * defined in a new dma_mode word!) */
288
289/* word 64: PIO transfer modes */
290#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
291#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
292
293/* word 75: queue_depth */
294#define DEPTH_BITS 0x001f /* bits used for queue depth */
295
296/* words 80-81: version numbers */
297/* NOVAL_0 or NOVAL_1 means device does not report version */
298
299/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000300#define MINOR_MAX 0x22
Eric Andersen3443bd72003-07-22 07:30:36 +0000301/* words 82-84: cmds/feats supported */
302#define CMDS_W82 0x77ff /* word 82: defined command locations*/
303#define CMDS_W83 0x3fff /* word 83: defined command locations*/
304#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000305#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000306#define NUM_CMD_FEAT_STR 48
307
Eric Andersen3443bd72003-07-22 07:30:36 +0000308/* words 85-87: cmds/feats enabled */
309/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000310 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000311 */
312
313/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000314#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000315
316/* word 92: master password revision */
317/* NOVAL_0 or NOVAL_1 means no support for master password revision */
318
319/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000320#define CBLID 0x2000 /* CBLID status */
321#define RST0 0x0001 /* 1=reset to device #0 */
322#define DEV_DET 0x0006 /* how device num determined */
323#define JUMPER_VAL 0x0002 /* device num determined by jumper */
324#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000325
326/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000327#define RM_STAT_BITS 0x0003
328#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000329
Eric Andersen3443bd72003-07-22 07:30:36 +0000330/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000331#define SECU_ENABLED 0x0002
332#define SECU_LEVEL 0x0010
333#define NUM_SECU_STR 6
Eric Andersen3443bd72003-07-22 07:30:36 +0000334
335/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000336#define VALID_W160 0x8000 /* 1=word valid */
337#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
338#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
339#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000340
341/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000342#define SIG 0x00ff /* signature location */
343#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000344
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000345#define TIMING_BUF_MB 1
346#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000347
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000348#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000349
Denis Vlasenko892536f2007-09-27 10:23:34 +0000350
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200351#define IS_GET 1
352#define IS_SET 2
353
354
Denis Vlasenko892536f2007-09-27 10:23:34 +0000355enum { fd = 3 };
356
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000357
358struct globals {
359 smallint get_identity, get_geom;
360 smallint do_flush;
361 smallint do_ctimings, do_timings;
362 smallint reread_partn;
363 smallint set_piomode, noisy_piomode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200364 smallint getset_readahead;
365 smallint getset_readonly;
366 smallint getset_unmask;
367 smallint getset_mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000368#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200369 smallint getset_dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000370#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200371 smallint getset_nowerr;
372 smallint getset_keep;
373 smallint getset_io32bit;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000374 int piomode;
375 unsigned long Xreadahead;
376 unsigned long readonly;
377 unsigned long unmask;
378 unsigned long mult;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000379#ifdef HDIO_SET_QDMA
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000380 unsigned long dma_q;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000381#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000382 unsigned long nowerr;
383 unsigned long keep;
384 unsigned long io32bit;
385#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
386 unsigned long dma;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200387 smallint getset_dma;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000388#endif
389#ifdef HDIO_DRIVE_CMD
390 smallint set_xfermode, get_xfermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200391 smallint getset_dkeep;
392 smallint getset_standby;
393 smallint getset_lookahead;
394 smallint getset_prefetch;
395 smallint getset_defects;
396 smallint getset_wcache;
397 smallint getset_doorlock;
398 smallint set_seagate;
399 smallint set_standbynow;
400 smallint set_sleepnow;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000401 smallint get_powermode;
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200402 smallint getset_apmmode;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000403 int xfermode_requested;
404 unsigned long dkeep;
Denis Vlasenko3c96d022008-03-20 13:44:50 +0000405 unsigned long standby_requested; /* 0..255 */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000406 unsigned long lookahead;
407 unsigned long prefetch;
408 unsigned long defects;
409 unsigned long wcache;
410 unsigned long doorlock;
411 unsigned long apmmode;
412#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000413 IF_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200414 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint getset_busstate;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000415 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
416 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
417 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
418 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
419 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
420 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
421 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000422#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
423 unsigned long hwif_data;
424 unsigned long hwif_ctrl;
425 unsigned long hwif_irq;
426#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000427#ifdef DO_FLUSHCACHE
428 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
429#endif
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100430} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200431#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000432#define get_identity (G.get_identity )
433#define get_geom (G.get_geom )
434#define do_flush (G.do_flush )
435#define do_ctimings (G.do_ctimings )
436#define do_timings (G.do_timings )
437#define reread_partn (G.reread_partn )
438#define set_piomode (G.set_piomode )
439#define noisy_piomode (G.noisy_piomode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200440#define getset_readahead (G.getset_readahead )
441#define getset_readonly (G.getset_readonly )
442#define getset_unmask (G.getset_unmask )
443#define getset_mult (G.getset_mult )
444#define getset_dma_q (G.getset_dma_q )
445#define getset_nowerr (G.getset_nowerr )
446#define getset_keep (G.getset_keep )
447#define getset_io32bit (G.getset_io32bit )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000448#define piomode (G.piomode )
449#define Xreadahead (G.Xreadahead )
450#define readonly (G.readonly )
451#define unmask (G.unmask )
452#define mult (G.mult )
453#define dma_q (G.dma_q )
454#define nowerr (G.nowerr )
455#define keep (G.keep )
456#define io32bit (G.io32bit )
457#define dma (G.dma )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200458#define getset_dma (G.getset_dma )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000459#define set_xfermode (G.set_xfermode )
460#define get_xfermode (G.get_xfermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200461#define getset_dkeep (G.getset_dkeep )
462#define getset_standby (G.getset_standby )
463#define getset_lookahead (G.getset_lookahead )
464#define getset_prefetch (G.getset_prefetch )
465#define getset_defects (G.getset_defects )
466#define getset_wcache (G.getset_wcache )
467#define getset_doorlock (G.getset_doorlock )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000468#define set_seagate (G.set_seagate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000469#define set_standbynow (G.set_standbynow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000470#define set_sleepnow (G.set_sleepnow )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000471#define get_powermode (G.get_powermode )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200472#define getset_apmmode (G.getset_apmmode )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000473#define xfermode_requested (G.xfermode_requested )
474#define dkeep (G.dkeep )
475#define standby_requested (G.standby_requested )
476#define lookahead (G.lookahead )
477#define prefetch (G.prefetch )
478#define defects (G.defects )
479#define wcache (G.wcache )
480#define doorlock (G.doorlock )
481#define apmmode (G.apmmode )
482#define get_IDentity (G.get_IDentity )
Denys Vlasenkoc7068452009-05-20 16:11:41 +0200483#define getset_busstate (G.getset_busstate )
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000484#define perform_reset (G.perform_reset )
485#define perform_tristate (G.perform_tristate )
486#define unregister_hwif (G.unregister_hwif )
487#define scan_hwif (G.scan_hwif )
488#define busstate (G.busstate )
489#define tristate (G.tristate )
490#define hwif (G.hwif )
491#define hwif_data (G.hwif_data )
492#define hwif_ctrl (G.hwif_ctrl )
493#define hwif_irq (G.hwif_irq )
Denys Vlasenko7b85ec32015-10-13 17:17:34 +0200494#define INIT_G() do { \
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200495 setup_common_bufsiz(); \
Denys Vlasenko7b85ec32015-10-13 17:17:34 +0200496 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
497} while (0)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000498
499
Glenn L McGrath07085852003-10-09 07:28:22 +0000500/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000501#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000502static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000503{
504 if (!ioctl(fd, cmd, args))
505 return 0;
506 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000507 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000508}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000509#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000510#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000511static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000512{
513 if (!ioctl(fd, cmd, args))
514 return 0;
515 args[0] = alt;
516 return bb_ioctl_or_warn(fd, cmd, args);
517}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000518#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000519#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000520
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000521static void on_off(int value)
522{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000523 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000524}
Glenn L McGrath07085852003-10-09 07:28:22 +0000525
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000526static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000527{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000528 if (get_arg) {
Denys Vlasenko327f5502013-11-29 16:45:45 +0100529 printf(" setting %s to %lu", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000530 on_off(arg);
531 }
532}
533
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000534static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000535{
Denys Vlasenko327f5502013-11-29 16:45:45 +0100536 printf(" %s\t= %2lu", str, argp);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000537 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000538}
Eric Andersen416c2422003-12-12 00:08:57 +0000539
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000540#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000541static void print_ascii(const char *p, int length)
542{
543#if BB_BIG_ENDIAN
544#define LE_ONLY(x)
545 enum { ofs = 0 };
546#else
547#define LE_ONLY(x) x
548 /* every 16bit word is big-endian (i.e. inverted) */
549 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
550 int ofs = 1;
551#endif
552
553 length *= 2;
554 /* find first non-space & print it */
555 while (length && p[ofs] != ' ') {
556 p++;
557 LE_ONLY(ofs = -ofs;)
558 length--;
559 }
560 while (length && p[ofs]) {
561 bb_putchar(p[ofs]);
562 p++;
563 LE_ONLY(ofs = -ofs;)
564 length--;
565 }
566 bb_putchar('\n');
567#undef LE_ONLY
568}
Glenn L McGrath07085852003-10-09 07:28:22 +0000569
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000570static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000571{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000572 if (val[i]) {
573 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000574 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000575 }
576}
Glenn L McGrath07085852003-10-09 07:28:22 +0000577
Glenn L McGrath07085852003-10-09 07:28:22 +0000578static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
579{
Eric Andersen3443bd72003-07-22 07:30:36 +0000580 uint16_t ii;
581 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000582
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000583 for (ii = 0; ii <= MODE_MAX; ii++) {
584 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000585 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000586 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000587 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000588 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000589 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000590 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000591
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000592 mode_sup >>= 1;
593 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000594 }
595 return err_dma;
596}
Glenn L McGrath07085852003-10-09 07:28:22 +0000597
Denis Vlasenko91303402007-10-30 19:36:54 +0000598static const char pkt_str[] ALIGN1 =
599 "Direct-access device" "\0" /* word 0, bits 12-8 = 00 */
600 "Sequential-access device" "\0" /* word 0, bits 12-8 = 01 */
601 "Printer" "\0" /* word 0, bits 12-8 = 02 */
602 "Processor" "\0" /* word 0, bits 12-8 = 03 */
603 "Write-once device" "\0" /* word 0, bits 12-8 = 04 */
604 "CD-ROM" "\0" /* word 0, bits 12-8 = 05 */
605 "Scanner" "\0" /* word 0, bits 12-8 = 06 */
606 "Optical memory" "\0" /* word 0, bits 12-8 = 07 */
607 "Medium changer" "\0" /* word 0, bits 12-8 = 08 */
608 "Communications device" "\0" /* word 0, bits 12-8 = 09 */
609 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0a */
610 "ACS-IT8 device" "\0" /* word 0, bits 12-8 = 0b */
611 "Array controller" "\0" /* word 0, bits 12-8 = 0c */
612 "Enclosure services" "\0" /* word 0, bits 12-8 = 0d */
613 "Reduced block command device" "\0" /* word 0, bits 12-8 = 0e */
614 "Optical card reader/writer" "\0" /* word 0, bits 12-8 = 0f */
615;
616
617static const char ata1_cfg_str[] ALIGN1 = /* word 0 in ATA-1 mode */
618 "reserved" "\0" /* bit 0 */
619 "hard sectored" "\0" /* bit 1 */
620 "soft sectored" "\0" /* bit 2 */
621 "not MFM encoded " "\0" /* bit 3 */
622 "head switch time > 15us" "\0" /* bit 4 */
623 "spindle motor control option" "\0" /* bit 5 */
624 "fixed drive" "\0" /* bit 6 */
625 "removable drive" "\0" /* bit 7 */
626 "disk xfer rate <= 5Mbs" "\0" /* bit 8 */
627 "disk xfer rate > 5Mbs, <= 10Mbs" "\0" /* bit 9 */
628 "disk xfer rate > 5Mbs" "\0" /* bit 10 */
629 "rotational speed tol." "\0" /* bit 11 */
630 "data strobe offset option" "\0" /* bit 12 */
631 "track offset option" "\0" /* bit 13 */
632 "format speed tolerance gap reqd" "\0" /* bit 14 */
633 "ATAPI" /* bit 14 */
634;
635
636static const char minor_str[] ALIGN1 =
637 /* word 81 value: */
638 "Unspecified" "\0" /* 0x0000 */
639 "ATA-1 X3T9.2 781D prior to rev.4" "\0" /* 0x0001 */
640 "ATA-1 published, ANSI X3.221-1994" "\0" /* 0x0002 */
641 "ATA-1 X3T9.2 781D rev.4" "\0" /* 0x0003 */
642 "ATA-2 published, ANSI X3.279-1996" "\0" /* 0x0004 */
643 "ATA-2 X3T10 948D prior to rev.2k" "\0" /* 0x0005 */
644 "ATA-3 X3T10 2008D rev.1" "\0" /* 0x0006 */
645 "ATA-2 X3T10 948D rev.2k" "\0" /* 0x0007 */
646 "ATA-3 X3T10 2008D rev.0" "\0" /* 0x0008 */
647 "ATA-2 X3T10 948D rev.3" "\0" /* 0x0009 */
648 "ATA-3 published, ANSI X3.298-199x" "\0" /* 0x000a */
649 "ATA-3 X3T10 2008D rev.6" "\0" /* 0x000b */
650 "ATA-3 X3T13 2008D rev.7 and 7a" "\0" /* 0x000c */
651 "ATA/ATAPI-4 X3T13 1153D rev.6" "\0" /* 0x000d */
652 "ATA/ATAPI-4 T13 1153D rev.13" "\0" /* 0x000e */
653 "ATA/ATAPI-4 X3T13 1153D rev.7" "\0" /* 0x000f */
654 "ATA/ATAPI-4 T13 1153D rev.18" "\0" /* 0x0010 */
655 "ATA/ATAPI-4 T13 1153D rev.15" "\0" /* 0x0011 */
656 "ATA/ATAPI-4 published, ANSI INCITS 317-1998" "\0" /* 0x0012 */
657 "ATA/ATAPI-5 T13 1321D rev.3" "\0" /* 0x0013 */
658 "ATA/ATAPI-4 T13 1153D rev.14" "\0" /* 0x0014 */
659 "ATA/ATAPI-5 T13 1321D rev.1" "\0" /* 0x0015 */
660 "ATA/ATAPI-5 published, ANSI INCITS 340-2000" "\0" /* 0x0016 */
661 "ATA/ATAPI-4 T13 1153D rev.17" "\0" /* 0x0017 */
662 "ATA/ATAPI-6 T13 1410D rev.0" "\0" /* 0x0018 */
663 "ATA/ATAPI-6 T13 1410D rev.3a" "\0" /* 0x0019 */
664 "ATA/ATAPI-7 T13 1532D rev.1" "\0" /* 0x001a */
665 "ATA/ATAPI-6 T13 1410D rev.2" "\0" /* 0x001b */
666 "ATA/ATAPI-6 T13 1410D rev.1" "\0" /* 0x001c */
667 "ATA/ATAPI-7 published, ANSI INCITS 397-2005" "\0" /* 0x001d */
668 "ATA/ATAPI-7 T13 1532D rev.0" "\0" /* 0x001e */
669 "reserved" "\0" /* 0x001f */
670 "reserved" "\0" /* 0x0020 */
671 "ATA/ATAPI-7 T13 1532D rev.4a" "\0" /* 0x0021 */
672 "ATA/ATAPI-6 published, ANSI INCITS 361-2002" "\0" /* 0x0022 */
673 "reserved" /* 0x0023-0xfffe */
674;
675static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
676 /* word 81 value: */
677 0, /* 0x0000 WARNING: actual_ver[] array */
678 1, /* 0x0001 WARNING: corresponds */
679 1, /* 0x0002 WARNING: *exactly* */
680 1, /* 0x0003 WARNING: to the ATA/ */
681 2, /* 0x0004 WARNING: ATAPI version */
682 2, /* 0x0005 WARNING: listed in */
683 3, /* 0x0006 WARNING: the */
684 2, /* 0x0007 WARNING: minor_str */
685 3, /* 0x0008 WARNING: array */
686 2, /* 0x0009 WARNING: above. */
687 3, /* 0x000a WARNING: */
688 3, /* 0x000b WARNING: If you change */
689 3, /* 0x000c WARNING: that one, */
690 4, /* 0x000d WARNING: change this one */
691 4, /* 0x000e WARNING: too!!! */
692 4, /* 0x000f */
693 4, /* 0x0010 */
694 4, /* 0x0011 */
695 4, /* 0x0012 */
696 5, /* 0x0013 */
697 4, /* 0x0014 */
698 5, /* 0x0015 */
699 5, /* 0x0016 */
700 4, /* 0x0017 */
701 6, /* 0x0018 */
702 6, /* 0x0019 */
703 7, /* 0x001a */
704 6, /* 0x001b */
705 6, /* 0x001c */
706 7, /* 0x001d */
707 7, /* 0x001e */
708 0, /* 0x001f */
709 0, /* 0x0020 */
710 7, /* 0x0021 */
711 6, /* 0x0022 */
712 0 /* 0x0023-0xfffe */
713};
714
715static const char cmd_feat_str[] ALIGN1 =
716 "" "\0" /* word 82 bit 15: obsolete */
717 "NOP cmd" "\0" /* word 82 bit 14 */
718 "READ BUFFER cmd" "\0" /* word 82 bit 13 */
719 "WRITE BUFFER cmd" "\0" /* word 82 bit 12 */
720 "" "\0" /* word 82 bit 11: obsolete */
721 "Host Protected Area feature set" "\0" /* word 82 bit 10 */
722 "DEVICE RESET cmd" "\0" /* word 82 bit 9 */
723 "SERVICE interrupt" "\0" /* word 82 bit 8 */
724 "Release interrupt" "\0" /* word 82 bit 7 */
725 "Look-ahead" "\0" /* word 82 bit 6 */
726 "Write cache" "\0" /* word 82 bit 5 */
727 "PACKET command feature set" "\0" /* word 82 bit 4 */
728 "Power Management feature set" "\0" /* word 82 bit 3 */
729 "Removable Media feature set" "\0" /* word 82 bit 2 */
730 "Security Mode feature set" "\0" /* word 82 bit 1 */
731 "SMART feature set" "\0" /* word 82 bit 0 */
732 /* -------------- */
733 "" "\0" /* word 83 bit 15: !valid bit */
734 "" "\0" /* word 83 bit 14: valid bit */
735 "FLUSH CACHE EXT cmd" "\0" /* word 83 bit 13 */
736 "Mandatory FLUSH CACHE cmd " "\0" /* word 83 bit 12 */
737 "Device Configuration Overlay feature set " "\0"
738 "48-bit Address feature set " "\0" /* word 83 bit 10 */
739 "" "\0"
740 "SET MAX security extension" "\0" /* word 83 bit 8 */
741 "Address Offset Reserved Area Boot" "\0" /* word 83 bit 7 */
742 "SET FEATURES subcommand required to spinup after power up" "\0"
743 "Power-Up In Standby feature set" "\0" /* word 83 bit 5 */
744 "Removable Media Status Notification feature set" "\0"
745 "Adv. Power Management feature set" "\0" /* word 83 bit 3 */
746 "CFA feature set" "\0" /* word 83 bit 2 */
747 "READ/WRITE DMA QUEUED" "\0" /* word 83 bit 1 */
748 "DOWNLOAD MICROCODE cmd" "\0" /* word 83 bit 0 */
749 /* -------------- */
750 "" "\0" /* word 84 bit 15: !valid bit */
751 "" "\0" /* word 84 bit 14: valid bit */
752 "" "\0" /* word 84 bit 13: reserved */
753 "" "\0" /* word 84 bit 12: reserved */
754 "" "\0" /* word 84 bit 11: reserved */
755 "" "\0" /* word 84 bit 10: reserved */
756 "" "\0" /* word 84 bit 9: reserved */
757 "" "\0" /* word 84 bit 8: reserved */
758 "" "\0" /* word 84 bit 7: reserved */
759 "" "\0" /* word 84 bit 6: reserved */
760 "General Purpose Logging feature set" "\0" /* word 84 bit 5 */
761 "" "\0" /* word 84 bit 4: reserved */
762 "Media Card Pass Through Command feature set " "\0"
763 "Media serial number " "\0" /* word 84 bit 2 */
764 "SMART self-test " "\0" /* word 84 bit 1 */
765 "SMART error logging " /* word 84 bit 0 */
766;
767
768static const char secu_str[] ALIGN1 =
769 "supported" "\0" /* word 128, bit 0 */
770 "enabled" "\0" /* word 128, bit 1 */
771 "locked" "\0" /* word 128, bit 2 */
772 "frozen" "\0" /* word 128, bit 3 */
773 "expired: security count" "\0" /* word 128, bit 4 */
774 "supported: enhanced erase" /* word 128, bit 5 */
775;
776
777// Parse 512 byte disk identification block and print much crap.
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000778static void identify(uint16_t *val) NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000779static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000780{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000781 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000782 uint16_t like_std = 1, std = 0, min_std = 0xffff;
783 uint16_t dev = NO_DEV, eqpt = NO_DEV;
784 uint8_t have_mode = 0, err_dma = 0;
785 uint8_t chksum = 0;
786 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000787 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000788 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000789#if BB_BIG_ENDIAN
790 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000791
Denis Vlasenko4daad902007-09-27 10:20:47 +0000792 // Adjust for endianness
793 swab(val, buf, sizeof(buf));
794 val = buf;
795#endif
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200796 /* check if we recognize the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000797 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000798 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000799 dev = ATA_DEV;
800 printf("ATA device, with ");
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200801 } else if (val[GEN_CONFIG] == CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000802 dev = ATA_DEV;
803 like_std = 4;
804 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000805 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000806 dev = ATAPI_DEV;
807 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000808 printf("ATAPI %s, with ", eqpt <= 0xf ? nth_string(pkt_str, eqpt) : "unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +0000809 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000810 } else
Denis Vlasenko91303402007-10-30 19:36:54 +0000811 /* "Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n" */
James Byrne69374872019-07-02 11:35:03 +0200812 bb_simple_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000813
Rob Landleyadde7982006-05-16 15:32:30 +0000814 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000815 /* Info from the specific configuration word says whether or not the
816 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000817 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000818 * standards. Since the values allowed for this word are extremely
819 * specific, it should be safe to check it now, even though we don't
820 * know yet what standard this device is using.
821 */
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200822 if ((val[CONFIG] == STBY_NID_VAL) || (val[CONFIG] == STBY_ID_VAL)
823 || (val[CONFIG] == PWRD_NID_VAL) || (val[CONFIG] == PWRD_ID_VAL)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000824 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000825 like_std = 5;
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200826 if ((val[CONFIG] == STBY_NID_VAL) || (val[CONFIG] == STBY_ID_VAL))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200827 puts("powers-up in standby; SET FEATURES subcmd spins-up.");
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200828 if (((val[CONFIG] == STBY_NID_VAL) || (val[CONFIG] == PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200829 puts("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000830 }
831
832 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000833 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
834 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
835 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
836 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
837 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000838
839 /* major & minor standards version number (Note: these words were not
840 * defined until ATA-3 & the CDROM std uses different words.) */
841 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000842 if (eqpt != CDROM) {
843 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000844 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000845 std = actual_ver[val[MINOR]];
Denys Vlasenkof3ea7922010-07-26 01:06:14 +0200846 if (std)
847 printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR]));
Eric Andersen3443bd72003-07-22 07:30:36 +0000848 }
849 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000850 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000851 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000852 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000853 printf("\n\tSupported: ");
854 jj = val[MAJOR] << 1;
855 kk = like_std >4 ? like_std-4: 0;
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200856 for (ii = 14; (ii > 0) && (ii > kk); ii--) {
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000857 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000858 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000859 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000860 like_std = ii;
861 kk = like_std >4 ? like_std-4: 0;
862 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000863 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000864 }
865 jj <<= 1;
866 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000867 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000868 }
869 /* Figure out what standard the device is using if it hasn't told
870 * us. If we know the std, check if the device is using any of
871 * the words from the next level up. It happens.
872 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000873 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000874
Rob Landleya3e4f382006-04-29 16:06:31 +0000875 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000876 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
877 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
878 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000879 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
880 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000881 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000882 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000883 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000884 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
885 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
886 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
887 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000888 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000889 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000890 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
891 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
892 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
893 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
894 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000895 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
896 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000897 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000898 } else if (((std == 2) || (!std && (like_std < 3)))
899 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
900 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000901 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000902 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000903 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
904 (val[WHATS_VALID] & OK_W64_70)) )
905 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000906 like_std = 2;
907 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000908
Rob Landleya3e4f382006-04-29 16:06:31 +0000909 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000910 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000911 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000912 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000913 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000914 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000915 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000916 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000917 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000918 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000919 kk = 1;
920 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
921 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000922 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000923 kk = 1;
924 printf("\n\tSupported: CD-ROM ATAPI");
925 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000926 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000927 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000928 jj >>= 1;
929 }
930 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000931 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000932 /* the cdrom stuff is more like ATA-2 than anything else, so: */
933 like_std = 2;
934 }
935
Rob Landleya3e4f382006-04-29 16:06:31 +0000936 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000937 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000938
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200939 puts("Configuration:");
Eric Andersen3443bd72003-07-22 07:30:36 +0000940 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000941 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000942 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000943 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000944 if (jj & 0x0001)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +0000945 printf("\t%s\n", nth_string(ata1_cfg_str, ii));
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200946 jj >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000947 }
948 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000949 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000950 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
951 strng = "3ms";
952 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
953 strng = "<=10ms with INTRQ";
954 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +0200955 strng = "50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000956 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000957 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000958 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
959
960 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
961 strng = "12 bytes";
962 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
963 strng = "16 bytes";
964 else
Denis Vlasenko91303402007-10-30 19:36:54 +0000965 strng = "unknown";
Rob Landleyadde7982006-05-16 15:32:30 +0000966 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000967 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000968 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000969 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200970 mm = 0;
971 bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000972 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200973 puts("\tCHS addressing not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000974 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000975 jj = val[WHATS_VALID] & OK_W54_58;
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200976 printf("\tLogical\t\tmax\tcurrent\n"
977 "\tcylinders\t%u\t%u\n"
978 "\theads\t\t%u\t%u\n"
979 "\tsectors/track\t%u\t%u\n"
980 "\t--\n",
981 val[LCYLS],
982 jj ? val[LCYLS_CUR] : 0,
983 val[LHEADS],
984 jj ? val[LHEADS_CUR] : 0,
985 val[LSECTS],
986 jj ? val[LSECTS_CUR] : 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000987
Rob Landleyadde7982006-05-16 15:32:30 +0000988 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denys Vlasenko6d335be2009-05-20 14:48:03 +0200989 printf("\tbytes/track: %u\tbytes/sector: %u\n",
990 val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000991
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000992 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000993 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000994 if (like_std < 3) {
995 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000996 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
997 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Denys Vlasenko122a8cb2019-10-25 17:47:22 +0200998 if (abs((int)(mm - nn)) > abs((int)(oo - nn)))
Eric Andersen3443bd72003-07-22 07:30:36 +0000999 mm = oo;
1000 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001001 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +00001002 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001003 }
1004 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001005 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001006 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
1007 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
1008 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001009 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
1010 (uint64_t)val[LBA_48_MSB] << 32 |
1011 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001012 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001013 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +00001014 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001015
1016 if (!bbbig)
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +02001017 bbbig = (uint64_t)(ll > mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001018 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
1019 bbbig = (bbbig << 9) / 1000000;
1020 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +00001021
Rob Landleyadde7982006-05-16 15:32:30 +00001022 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +00001023 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001024 else
Denis Vlasenko4daad902007-09-27 10:20:47 +00001025 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001026 }
1027
1028 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +00001029 printf("Capabilities:\n\t");
1030
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001031 if (dev == ATAPI_DEV) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001032 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP))
1033 printf("Cmd queuing, ");
1034 if (val[CAPAB_0] & OVLP_SUP)
1035 printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001036 }
Rob Landleyadde7982006-05-16 15:32:30 +00001037 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +00001038
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001039 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001040 printf("IORDY%s(can%s be disabled)\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001041 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
1042 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001043 } else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001044 puts("no IORDY");
Glenn L McGrath07085852003-10-09 07:28:22 +00001045
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001046 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001047 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001048 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
1049 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001050 }
Rob Landleyadde7982006-05-16 15:32:30 +00001051
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001052 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001053 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001054 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001055 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001056 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001057 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001058 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001059 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +00001060 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001061
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001062 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001063 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001064 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001065 else {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001066 printf("\tStandby timer values: spec'd by %s",
1067 (val[CAPAB_0] & STD_STBY) ? "standard" : "vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +00001068 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001069 printf(", %s device specific minimum\n",
1070 (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +00001071 else
Denis Vlasenko4daad902007-09-27 10:20:47 +00001072 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001073 }
1074 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001075 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001076 puts("not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001077 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001078 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +00001079 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
1080 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
1081 else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001082 puts("?");
Eric Andersen3443bd72003-07-22 07:30:36 +00001083 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001084 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001085 /* We print out elsewhere whether the APM feature is enabled or
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001086 * not. If it's not enabled, let's not repeat the info; just print
1087 * nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +00001088 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001089 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001090 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +00001091 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +00001092 }
1093 else
Eric Andersen3443bd72003-07-22 07:30:36 +00001094 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001095 }
Rob Landleyadde7982006-05-16 15:32:30 +00001096 if (like_std > 5 && val[ACOUSTIC]) {
1097 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001098 (val[ACOUSTIC] >> 8) & 0x00ff,
1099 val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +00001100 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001101 } else {
Denys Vlasenko6830ade2013-01-15 13:58:01 +01001102 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +00001103 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001104 puts("\tATA sw reset required");
Glenn L McGrath07085852003-10-09 07:28:22 +00001105
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001106 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001107 printf("\tOverlap support:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001108 if (val[PKT_REL])
1109 printf(" %uus to release bus.", val[PKT_REL]);
1110 if (val[SVC_NBSY])
1111 printf(" %uus to clear BSY after SERVICE cmd.",
1112 val[SVC_NBSY]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001113 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001114 }
1115 }
1116
1117 /* DMA stuff. Check that only one DMA mode is selected. */
1118 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001119 if (!(val[CAPAB_0] & DMA_SUP))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001120 puts("not supported");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001121 else {
Rob Landleyadde7982006-05-16 15:32:30 +00001122 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001123 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001124 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001125 jj = val[SINGLE_DMA];
1126 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001127 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001128 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001129 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001130 jj = val[MULTI_DMA];
1131 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001132 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001133 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001134 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001135 jj = val[ULTRA_DMA];
1136 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001137 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001138 }
Rob Landleyadde7982006-05-16 15:32:30 +00001139 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001140 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001141
Rob Landleyadde7982006-05-16 15:32:30 +00001142 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001143 puts("\t\tInterleaved DMA support");
Eric Andersen3443bd72003-07-22 07:30:36 +00001144
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001145 if ((val[WHATS_VALID] & OK_W64_70)
1146 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1147 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001148 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001149 if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
1150 if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001151 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001152 }
1153 }
1154
1155 /* Programmed IO stuff */
1156 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001157 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +00001158 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001159 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001160 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001161 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001162 if (jj & 0x0001) printf("pio%d ", ii);
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +02001163 jj >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001164 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001165 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001166 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001167 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001168 printf("pio%d ", ii);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001169 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001170 } else
Denis Vlasenko91303402007-10-30 19:36:54 +00001171 puts("unknown");
Glenn L McGrath07085852003-10-09 07:28:22 +00001172
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001173 if (val[WHATS_VALID] & OK_W64_70) {
1174 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001175 printf("\t\tCycle time:");
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001176 if (val[PIO_NO_FLOW])
1177 printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1178 if (val[PIO_FLOW])
1179 printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001180 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001181 }
1182 }
1183
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001184 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001185 puts("Commands/features:\n"
1186 "\tEnabled\tSupported:");
Eric Andersen3443bd72003-07-22 07:30:36 +00001187 jj = val[CMDS_SUPP_0];
1188 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001189 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001190 const char *feat_str = nth_string(cmd_feat_str, ii);
Denis Vlasenko91303402007-10-30 19:36:54 +00001191 if ((jj & 0x8000) && (*feat_str != '\0')) {
1192 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", feat_str);
Eric Andersen3443bd72003-07-22 07:30:36 +00001193 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001194 jj <<= 1;
1195 kk <<= 1;
1196 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001197 jj = val[CMDS_SUPP_0+1+(ii/16)];
1198 kk = val[CMDS_EN_0+1+(ii/16)];
1199 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001200 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001201 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +02001202 ii += 16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001203 }
1204 }
1205 }
Rob Landleyadde7982006-05-16 15:32:30 +00001206 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001207 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001208 printf("\t%s supported\n", nth_string(cmd_feat_str, 27));
Glenn L McGrath07085852003-10-09 07:28:22 +00001209
Eric Andersen3443bd72003-07-22 07:30:36 +00001210 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001211 if ((eqpt != CDROM) && (like_std > 3)
1212 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1213 ) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001214 puts("Security:");
Rob Landleyadde7982006-05-16 15:32:30 +00001215 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001216 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001217 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001218 if (jj) {
1219 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001220 printf("\t%s\t%s\n",
1221 (!(jj & 0x0001)) ? "not" : "",
1222 nth_string(secu_str, ii));
Denys Vlasenkofe73c8d2022-08-30 16:41:17 +02001223 jj >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001224 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001225 if (val[SECU_STATUS] & SECU_ENABLED) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001226 printf("\tSecurity level %s\n",
1227 (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001228 }
1229 }
1230 jj = val[ERASE_TIME] & ERASE_BITS;
1231 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001232 if (jj || kk) {
Denis Vlasenko7d60fc12008-06-05 06:51:06 +00001233 bb_putchar('\t');
Rob Landleyade7f952006-05-25 18:53:06 +00001234 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1235 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001236 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001237 }
1238 }
1239
1240 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001241 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001242 if ((jj & VALID) == VALID_VAL) {
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001243 oo = (jj & RST0);
1244 if (!oo)
Rob Landleyadde7982006-05-16 15:32:30 +00001245 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001246 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001247 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001248 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001249 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001250 else
Rob Landleyadde7982006-05-16 15:32:30 +00001251 strng = "";
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001252 printf("HW reset results:\n"
1253 "\tCBLID- %s Vih\n"
1254 "\tDevice num = %i%s\n",
1255 (val[HWRST_RSLT] & CBLID) ? "above" : "below",
1256 !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001257 }
1258
1259 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001260 if ((like_std > 4) && (eqpt != CDROM)) {
1261 if (val[CFA_PWR_MODE] & VALID_W160) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001262 printf("CFA power mode 1:\n"
1263 "\t%s%s\n",
1264 (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
1265 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001266 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001267 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001268 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001269 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001270 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001271 }
1272 }
1273
Denys Vlasenkodb5546c2022-01-05 22:16:06 +01001274 exit_SUCCESS();
Eric Andersen3443bd72003-07-22 07:30:36 +00001275}
1276#endif
1277
Eric Andersen3443bd72003-07-22 07:30:36 +00001278// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1279// then the HDIO_GET_IDENTITY only returned 142 bytes.
1280// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1281// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1282// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1283// (which they should, but they should just return -EINVAL).
1284//
1285// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1286// On a really old system, it will not, and we will be confused.
1287// Too bad, really.
1288
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001289#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko91303402007-10-30 19:36:54 +00001290static const char cfg_str[] ALIGN1 =
Denis Vlasenko6b404432008-01-07 16:13:14 +00001291 """\0" "HardSect""\0" "SoftSect""\0" "NotMFM""\0"
1292 "HdSw>15uSec""\0" "SpinMotCtl""\0" "Fixed""\0" "Removeable""\0"
1293 "DTR<=5Mbs""\0" "DTR>5Mbs""\0" "DTR>10Mbs""\0" "RotSpdTol>.5%""\0"
1294 "dStbOff""\0" "TrkOff""\0" "FmtGapReq""\0" "nonMagnetic"
Denis Vlasenko91303402007-10-30 19:36:54 +00001295;
Eric Andersen3443bd72003-07-22 07:30:36 +00001296
Denis Vlasenko91303402007-10-30 19:36:54 +00001297static const char BuffType[] ALIGN1 =
1298 "unknown""\0" "1Sect""\0" "DualPort""\0" "DualPortCache"
1299;
Eric Andersen3443bd72003-07-22 07:30:36 +00001300
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +02001301static NOINLINE void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001302{
1303 int i;
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00001304 const unsigned short *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001305
Glenn L McGrath07085852003-10-09 07:28:22 +00001306 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1307 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001308 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001309 if (id->config & (1<<i))
Denis Vlasenkobfc3d822007-11-04 04:10:17 +00001310 printf(" %s", nth_string(cfg_str, i));
Rob Landleyadde7982006-05-16 15:32:30 +00001311 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001312 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001313 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
1314 id->cyls, id->heads, id->sectors, id->track_bytes,
1315 id->sector_bytes, id->ecc_bytes,
1316 id->buf_type,
1317 nth_string(BuffType, (id->buf_type > 3) ? 0 : id->buf_type),
1318 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001319 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001320 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001321 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001322 printf("?%u?", id->multsect);
1323 else if (id->multsect)
1324 printf("%u", id->multsect);
1325 else
1326 printf("off");
1327 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001328 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001329
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001330 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001331 printf(" (maybe):");
1332
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001333 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001334 id->cur_sectors,
1335 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001336 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1337 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001338 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001339
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001340 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001341 printf(", LBAsects=%u", id->lba_capacity);
1342
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001343 printf("\n IORDY=%s",
1344 (id->capability & 8)
1345 ? ((id->capability & 4) ? "on/off" : "yes")
1346 : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001347
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001348 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001349 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001350
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001351 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001352 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1353
1354 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001355 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001356 printf("pio0 ");
1357 if (id->tPIO >= 1) printf("pio1 ");
1358 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001359 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001360 if (id->field_valid & 2) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001361 static const masks_labels_t pio_modes = {
1362 .masks = { 1, 2, ~3 },
1363 .labels = "pio3 \0""pio4 \0""pio? \0",
1364 };
1365 print_flags(&pio_modes, id->eide_pio_modes);
Rob Landleyade7f952006-05-25 18:53:06 +00001366 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001367 if (id->capability & 1) {
1368 if (id->dma_1word | id->dma_mword) {
Denys Vlasenko965b7952020-11-30 13:03:03 +01001369 static const int dma_wmode_masks[] ALIGN4 = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
Rob Landleyade7f952006-05-25 18:53:06 +00001370 printf("\n DMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001371 print_flags_separated(dma_wmode_masks,
1372 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
1373 id->dma_1word, NULL);
1374 print_flags_separated(dma_wmode_masks,
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001375 "*\0""mdma0 \0""*\0""mdma1 \0""*\0""mdma2 \0""*\0""mdma? \0",
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001376 id->dma_mword, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001377 }
1378 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001379 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001380 static const masks_labels_t ultra_modes1 = {
1381 .masks = { 0x100, 0x001, 0x200, 0x002, 0x400, 0x004 },
1382 .labels = "*\0""udma0 \0""*\0""udma1 \0""*\0""udma2 \0",
1383 };
Denis Vlasenko7049ff82008-06-25 09:53:17 +00001384
Rob Landleyade7f952006-05-25 18:53:06 +00001385 printf("\n UDMA modes: ");
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001386 print_flags(&ultra_modes1, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001387#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001388 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001389#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001390 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001391#endif /* __NEW_HD_DRIVE_ID */
Denis Vlasenko53354ac2008-06-07 15:10:29 +00001392 static const masks_labels_t ultra_modes2 = {
1393 .masks = { 0x0800, 0x0008, 0x1000, 0x0010,
1394 0x2000, 0x0020, 0x4000, 0x0040,
1395 0x8000, 0x0080 },
1396 .labels = "*\0""udma3 \0""*\0""udma4 \0"
1397 "*\0""udma5 \0""*\0""udma6 \0"
1398 "*\0""udma7 \0"
1399 };
1400 print_flags(&ultra_modes2, id->dma_ultra);
Eric Andersen3443bd72003-07-22 07:30:36 +00001401 }
1402 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001403 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001404 if (id_regs[83] & 8) {
1405 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001406 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001407 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001408 printf(": unknown setting");
1409 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001410 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001411 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001412 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001413 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001414#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001415 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1416 || (id->major_rev_num && id->minor_rev_num <= 31)
1417 ) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001418 printf("\n Drive conforms to: %s: ",
1419 (id->minor_rev_num <= 31) ? nth_string(minor_str, id->minor_rev_num) : "unknown");
1420 if (id->major_rev_num != 0x0000 /* NOVAL_0 */
1421 && id->major_rev_num != 0xFFFF /* NOVAL_1 */
1422 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001423 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001424 if (id->major_rev_num & (1<<i))
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001425 printf(" ATA/ATAPI-%u", i);
Rob Landleyadde7982006-05-16 15:32:30 +00001426 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001427 }
1428 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001429#endif /* __NEW_HD_DRIVE_ID */
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001430 puts("\n\n * current active mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001431}
1432#endif
1433
Denis Vlasenko892536f2007-09-27 10:23:34 +00001434static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001435{
Rob Landleya3e4f382006-04-29 16:06:31 +00001436 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001437 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001438#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoec16c032020-11-29 11:37:34 +01001439 sleep1();
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001440 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1441 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
James Byrne69374872019-07-02 11:35:03 +02001442 bb_simple_perror_msg("HDIO_DRIVE_CMD");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001443 else
1444 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1445 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001446#endif
1447}
1448
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001449static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001450{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001451 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001452}
1453
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001454static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001455{
Rob Landleyadde7982006-05-16 15:32:30 +00001456 int i;
1457
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001458 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001459 /* access all sectors of buf to ensure the read fully completed */
1460 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1461 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001462}
1463
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001464static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001465{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001466 union {
1467 unsigned long long blksize64;
1468 unsigned blksize32;
1469 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001470
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001471 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1472 u.blksize64 /= (1024 * 1024);
1473 } else {
1474 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1475 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001476 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001477 if (u.blksize64 > UINT_MAX)
1478 return UINT_MAX;
1479 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001480}
Eric Andersen50af12d2003-08-06 08:47:59 +00001481
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001482static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001483{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001484 unsigned sec = elapsed_us / 1000000;
1485 unsigned hs = (elapsed_us % 1000000) / 10000;
1486
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001487 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001488 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001489 /* "| 1" prevents div-by-0 */
1490 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001491 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001492 // = kb / elapsed_sec
1493 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001494}
1495
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001496static void do_time(int cache /*,int fd*/)
1497/* cache=1: time cache: repeatedly read N MB at offset 0
1498 * cache=0: time device: linear read, starting at offset 0
1499 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001500{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001501 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001502 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001503 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001504 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001505 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001506
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001507 if (mlock(buf, TIMING_BUF_BYTES))
James Byrne69374872019-07-02 11:35:03 +02001508 bb_simple_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001509
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001510 /* Clear out the device request queues & give them time to complete.
1511 * NB: *small* delay. User is expected to have a clue and to not run
1512 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001513 sync();
Denys Vlasenkoec16c032020-11-29 11:37:34 +01001514 sleep1();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001515 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001516 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001517 read_big_block(buf);
1518 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001519 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001520 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001521 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +01001522 fflush_all();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001523
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001524 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001525 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001526 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001527 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001528 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001529 max_iterations = UINT_MAX;
1530 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001531 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001532 /* Don't want to read past the end! */
1533 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1534 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001535 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001536 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001537 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001538 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001539 read_big_block(buf);
1540 elapsed = (unsigned)monotonic_us() - start;
1541 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001542 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001543 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001544 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1545 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001546 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001547 * from elapsed */
1548 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001549 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001550 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001551 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001552 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001553 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001554 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001555 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001556 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001557 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001558 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001559 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001560 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001561}
1562
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001563#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001564static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001565{
Rob Landleyadde7982006-05-16 15:32:30 +00001566 if (value == BUSSTATE_ON)
1567 on_off(1);
1568 else if (value == BUSSTATE_OFF)
1569 on_off(0);
1570 else if (value == BUSSTATE_TRISTATE)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001571 puts(" (tristate)");
Rob Landleyadde7982006-05-16 15:32:30 +00001572 else
Denys Vlasenko327f5502013-11-29 16:45:45 +01001573 printf(" (unknown: %u)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001574}
1575#endif
1576
1577#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001578static void interpret_standby(uint8_t standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001579{
Rob Landley403777f2006-08-03 20:22:37 +00001580 printf(" (");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001581 if (standby == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001582 printf("off");
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001583 } else if (standby <= 240 || standby == 252 || standby == 255) {
1584 /* standby is in 5 sec units */
Denys Vlasenko2b132e52009-05-20 23:21:42 +02001585 unsigned t = standby * 5;
1586 printf("%u minutes %u seconds", t / 60, t % 60);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001587 } else if (standby <= 251) {
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001588 unsigned t = (standby - 240); /* t is in 30 min units */;
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001589 printf("%u.%c hours", t / 2, (t & 1) ? '5' : '0');
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001590 }
1591 if (standby == 253)
1592 printf("vendor-specific");
1593 if (standby == 254)
1594 printf("reserved");
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001595 puts(")");
Eric Andersen3443bd72003-07-22 07:30:36 +00001596}
1597
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001598static const uint8_t xfermode_val[] ALIGN1 = {
1599 8, 9, 10, 11, 12, 13, 14, 15,
1600 16, 17, 18, 19, 20, 21, 22, 23,
1601 32, 33, 34, 35, 36, 37, 38, 39,
1602 64, 65, 66, 67, 68, 69, 70, 71
1603};
1604/* NB: we save size by _not_ storing terninating NUL! */
1605static const char xfermode_name[][5] ALIGN1 = {
1606 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1607 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1608 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1609 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001610};
1611
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001612static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001613{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001614 int val;
1615 unsigned i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001616
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001617 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1618 if (!strncmp(name, xfermode_name[i], 5))
1619 if (strlen(name) <= 5)
1620 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001621 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001622 /* Negative numbers are invalid and are caught later */
1623 val = bb_strtoi(name, NULL, 10);
1624 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001625 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001626 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001627}
1628
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001629static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001630{
1631 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001632 if (xfermode == 0)
1633 printf("default PIO mode");
1634 else if (xfermode == 1)
1635 printf("default PIO mode, disable IORDY");
1636 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001637 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001638 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001639 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001640 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001641 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001642 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001643 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001644 else
Denis Vlasenko91303402007-10-30 19:36:54 +00001645 printf("unknown");
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001646 puts(")");
Eric Andersen3443bd72003-07-22 07:30:36 +00001647}
1648#endif /* HDIO_DRIVE_CMD */
1649
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001650static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001651{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001652 if (flag)
Denys Vlasenko327f5502013-11-29 16:45:45 +01001653 printf(" setting %s to %lu\n", s, value);
Rob Landleyadde7982006-05-16 15:32:30 +00001654}
1655
Rob Landleya3e4f382006-04-29 16:06:31 +00001656static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001657{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001658 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001659 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001660#ifndef HDIO_DRIVE_CMD
1661 int force_operation = 0;
1662#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001663 /* Please restore args[n] to these values after each ioctl
1664 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001665 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001666 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001667
Bernhard Reutner-Fischera4830872009-10-26 23:27:08 +01001668 /*fd = xopen_nonblocking(devname);*/
1669 xmove_fd(xopen_nonblocking(devname), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001670 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001671
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001672 if (getset_readahead == IS_SET) {
1673 print_flag(getset_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001674 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001675 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001676#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1677 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001678 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001679 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001680 }
1681#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001682#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001683 if (scan_hwif == IS_SET) {
Rob Landley20deab02006-05-07 23:34:15 +00001684 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001685 args[0] = hwif_data;
1686 args[1] = hwif_ctrl;
1687 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001688 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001689 args[0] = WIN_SETFEATURES;
1690 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001691 }
1692#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001693 if (set_piomode) {
1694 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001695 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001696 if (piomode == 255)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001697 puts("auto-tune PIO mode");
Eric Andersen3443bd72003-07-22 07:30:36 +00001698 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001699 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001700 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001701 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001702 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001703 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001704 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001705 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001706 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001707 if (getset_io32bit == IS_SET) {
1708 print_flag(getset_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001709 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001710 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001711 if (getset_mult == IS_SET) {
1712 print_flag(getset_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001713#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001714 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001715#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001716 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001717#endif
1718 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001719 if (getset_readonly == IS_SET) {
1720 print_flag_on_off(getset_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001721 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001722 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001723 if (getset_unmask == IS_SET) {
1724 print_flag_on_off(getset_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001725 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001726 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001727#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001728 if (getset_dma == IS_SET) {
1729 print_flag_on_off(getset_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001730 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001731 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001732#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001733#ifdef HDIO_SET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001734 if (getset_dma_q == IS_SET) {
1735 print_flag_on_off(getset_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001736 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001737 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001738#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001739 if (getset_nowerr == IS_SET) {
1740 print_flag_on_off(getset_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001741 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001742 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001743 if (getset_keep == IS_SET) {
1744 print_flag_on_off(getset_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001745 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001746 }
1747#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001748 if (getset_doorlock == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001749 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001750 args[2] = 0;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001751 print_flag_on_off(getset_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001752 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001753 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001754 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001755 if (getset_dkeep == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001756 /* lock/unlock the drive's "feature" settings */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001757 print_flag_on_off(getset_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001758 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001759 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001760 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001761 if (getset_defects == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001762 args[2] = defects ? 0x04 : 0x84;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001763 print_flag(getset_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001764 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001765 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001766 if (getset_prefetch == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001767 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001768 args[2] = 0xab;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001769 print_flag(getset_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001770 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001771 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001772 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001773 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001774 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001775 args[2] = 3;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001776 print_flag(1, "xfermode", xfermode_requested);
1777 interpret_xfermode(xfermode_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001778 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001779 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001780 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001781 if (getset_lookahead == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001782 args[2] = lookahead ? 0xaa : 0x55;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001783 print_flag_on_off(getset_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001784 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001785 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001786 if (getset_apmmode == IS_SET) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001787 /* feature register */
1788 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */;
Rob Landleyadde7982006-05-16 15:32:30 +00001789 args[1] = apmmode; /* sector count register 1-255 */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001790 printf(" setting APM level to %s 0x%02lX (%ld)\n",
1791 (apmmode == 255) ? "disabled" : "",
1792 apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001793 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001794 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001795 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001796 if (getset_wcache == IS_SET) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001797#ifdef DO_FLUSHCACHE
1798#ifndef WIN_FLUSHCACHE
1799#define WIN_FLUSHCACHE 0xe7
1800#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001801#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001802 args[2] = wcache ? 0x02 : 0x82;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001803 print_flag_on_off(getset_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001804#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001805 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001806 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001807#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001808 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001809#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001810 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001811 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001812#endif /* DO_FLUSHCACHE */
1813 }
Rob Landley39cf6452006-05-05 16:52:28 +00001814
1815 /* In code below, we do not preserve args[0], but the rest
1816 is preserved, including args[2] */
1817 args[2] = 0;
1818
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001819 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001820#ifndef WIN_STANDBYNOW1
1821#define WIN_STANDBYNOW1 0xE0
1822#endif
1823#ifndef WIN_STANDBYNOW2
1824#define WIN_STANDBYNOW2 0x94
1825#endif
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001826 puts(" issuing standby command");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001827 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001828 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001829 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001830 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001831#ifndef WIN_SLEEPNOW1
1832#define WIN_SLEEPNOW1 0xE6
1833#endif
1834#ifndef WIN_SLEEPNOW2
1835#define WIN_SLEEPNOW2 0x99
1836#endif
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001837 puts(" issuing sleep command");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001838 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001839 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001840 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001841 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001842 args[0] = 0xfb;
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001843 puts(" disabling Seagate auto powersaving mode");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001844 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001845 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001846 if (getset_standby == IS_SET) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001847 args[0] = WIN_SETIDLE1;
1848 args[1] = standby_requested;
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001849 print_flag(1, "standby", standby_requested);
1850 interpret_standby(standby_requested);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001851 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001852 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001853 }
1854#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001855 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001856 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001857 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001858 if (-1 == read(fd, buf, sizeof(buf)))
James Byrne69374872019-07-02 11:35:03 +02001859 bb_simple_perror_msg("read of 512 bytes failed");
Eric Andersen3443bd72003-07-22 07:30:36 +00001860 }
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001861#endif /* HDIO_DRIVE_CMD */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001862 if (getset_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001863 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001864 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001865 /* To be coherent with ioctl_or_warn. */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001866 if (getset_mult && ENABLE_IOCTL_HEX2STR_ERROR)
James Byrne69374872019-07-02 11:35:03 +02001867 bb_simple_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001868 else
1869 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001870 } else if (getset_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001871 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001872 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001873 }
1874 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001875 if (getset_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001876 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001877 printf(" IO_support\t=%3ld (", parm);
1878 if (parm == 0)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001879 puts("default 16-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001880 else if (parm == 2)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001881 puts("16-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001882 else if (parm == 1)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001883 puts("32-bit)");
Rob Landleyadde7982006-05-16 15:32:30 +00001884 else if (parm == 3)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001885 puts("32-bit w/sync)");
Rob Landleyadde7982006-05-16 15:32:30 +00001886 else if (parm == 8)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001887 puts("Request-Queue-Bypass)");
Rob Landleyadde7982006-05-16 15:32:30 +00001888 else
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001889 puts("\?\?\?)");
Eric Andersen3443bd72003-07-22 07:30:36 +00001890 }
1891 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001892 if (getset_unmask) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001893 if (!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001894 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001895 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001896#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001897 if (getset_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001898 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001899 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001900 if (parm == 8)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001901 puts(" (DMA-Assisted-PIO)");
Eric Andersen3443bd72003-07-22 07:30:36 +00001902 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001903 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001904 }
1905 }
1906#endif
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001907#ifdef HDIO_GET_QDMA
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001908 if (getset_dma_q) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001909 if (!ioctl_or_warn(fd, HDIO_GET_QDMA, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001910 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001911 }
Denis Vlasenko3c96d022008-03-20 13:44:50 +00001912#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001913 if (getset_keep) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001914 if (!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001915 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001916 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001917 if (getset_nowerr) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001918 if (!ioctl_or_warn(fd, HDIO_GET_NOWERR, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001919 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001920 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001921 if (getset_readonly) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001922 if (!ioctl_or_warn(fd, BLKROGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001923 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001924 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02001925 if (getset_readahead) {
Denis Vlasenkod6855d12008-09-27 14:03:25 +00001926 if (!ioctl_or_warn(fd, BLKRAGET, &parm))
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001927 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001928 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001929 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001930 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001931 struct hd_geometry g;
1932
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001933 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001934 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Denys Vlasenko6d335be2009-05-20 14:48:03 +02001935 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001936 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001937 }
1938#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001939 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001940#ifndef WIN_CHECKPOWERMODE1
1941#define WIN_CHECKPOWERMODE1 0xE5
1942#endif
1943#ifndef WIN_CHECKPOWERMODE2
1944#define WIN_CHECKPOWERMODE2 0x98
1945#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001946 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001947
Rob Landleye5b281f2006-04-29 15:49:18 +00001948 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001949 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001950 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001951 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001952 else
1953 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001954 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001955 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001956 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001957
Eric Andersen3443bd72003-07-22 07:30:36 +00001958 printf(" drive state is: %s\n", state);
1959 }
1960#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001961#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1962 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001963 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001964 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001965#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1966#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1967 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001968 args[0] = 0;
1969 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001970 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001971 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001972#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1973#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1974 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001975 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001976
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001977 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1978 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001979 id.multsect = multcount;
1980 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001981 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001982 id.multsect_valid &= ~1;
1983 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001984 } else if (errno == -ENOMSG)
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001985 puts(" no identification info available");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001986 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
James Byrne69374872019-07-02 11:35:03 +02001987 bb_simple_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001988 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001989 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001990 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001991
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001992 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001993 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001994
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001995 memset(args1, 0, sizeof(args1));
1996 args1[0] = WIN_IDENTIFY;
1997 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001998 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001999 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00002000 }
2001#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002002#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002003 if (getset_busstate == IS_SET) {
2004 print_flag(1, "bus state", busstate);
2005 bus_state_value(busstate);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002006 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00002007 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002008 if (getset_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002009 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00002010 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00002011 bus_state_value(parm);
2012 }
2013 }
2014#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00002015 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002016 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00002017
Eric Andersen3443bd72003-07-22 07:30:36 +00002018 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00002019 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00002020 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00002021 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00002022 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00002023 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00002024 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00002025}
2026
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002027#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00002028static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00002029{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002030 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00002031 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002032 if (c >= 'a' && c <= 'f')
2033 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00002034 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
2035}
2036
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002037static void identify_from_stdin(void) NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00002038static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00002039{
Rob Landley0753f4a2006-06-07 00:27:25 +00002040 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002041 unsigned char buf[1280];
2042 unsigned char *b = (unsigned char *)buf;
2043 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00002044
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00002045 xread(STDIN_FILENO, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00002046
Rob Landley0753f4a2006-06-07 00:27:25 +00002047 // Convert the newline-separated hex data into an identify block.
2048
Denis Vlasenko3bf00202007-02-18 13:36:04 +00002049 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00002050 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002051 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00002052 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00002053 }
Rob Landley0753f4a2006-06-07 00:27:25 +00002054
2055 // Parse the data.
2056
Rob Landley6389ff12006-05-01 19:28:53 +00002057 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00002058}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00002059#else
2060void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00002061#endif
2062
Rob Landley20deab02006-05-07 23:34:15 +00002063/* busybox specific stuff */
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002064static int parse_opts(unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00002065{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00002066 if (optarg) {
Denis Vlasenko13858992006-10-08 12:49:22 +00002067 *value = xatol_range(optarg, min, max);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002068 return IS_SET;
Denis Vlasenko6429aab2006-09-23 12:22:11 +00002069 }
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002070 return IS_GET;
2071}
2072static int parse_opts_0_max(unsigned long *value, int max)
2073{
2074 return parse_opts(value, 0, max);
2075}
2076static int parse_opts_0_1(unsigned long *value)
2077{
2078 return parse_opts(value, 0, 1);
2079}
2080static int parse_opts_0_INTMAX(unsigned long *value)
2081{
2082 return parse_opts(value, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00002083}
2084
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00002085static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00002086{
2087 if (flag) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002088 *get = IS_GET;
Rob Landley20deab02006-05-07 23:34:15 +00002089 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002090 *value = translate_xfermode(optarg);
2091 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00002092 }
2093 }
2094}
2095
Rob Landley06208412006-05-31 22:52:57 +00002096/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002097static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00002098 "gfu::n::p:r::m::c::k::a::B:tT"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002099 IF_FEATURE_HDPARM_GET_IDENTITY("iI")
2100 IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
Rob Landley20deab02006-05-07 23:34:15 +00002101#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002102 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00002103#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002104 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
Rob Landley20deab02006-05-07 23:34:15 +00002105#ifdef HDIO_GET_QDMA
2106#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002107 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00002108#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002109 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00002110#endif
2111#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002112 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
2113 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
2114 IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
Rob Landley20deab02006-05-07 23:34:15 +00002115/*-------------------------------------*/
2116
2117/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002118int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00002119int hdparm_main(int argc, char **argv)
2120{
2121 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00002122 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00002123
Denys Vlasenko16714242011-09-21 01:59:15 +02002124 INIT_G();
2125
Rob Landley06208412006-05-31 22:52:57 +00002126 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00002127 flagcount++;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002128 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
2129 IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00002130 get_geom |= (c == 'g');
2131 do_flush |= (c == 'f');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002132 if (c == 'u') getset_unmask = parse_opts_0_1(&unmask);
2133 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(
2134 if (c == 'd') getset_dma = parse_opts_0_max(&dma, 9);
2135 )
2136 if (c == 'n') getset_nowerr = parse_opts_0_1(&nowerr);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002137 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002138 if (c == 'r') getset_readonly = parse_opts_0_1(&readonly);
2139 if (c == 'm') getset_mult = parse_opts_0_INTMAX(&mult /*32*/);
2140 if (c == 'c') getset_io32bit = parse_opts_0_INTMAX(&io32bit /*8*/);
2141 if (c == 'k') getset_keep = parse_opts_0_1(&keep);
2142 if (c == 'a') getset_readahead = parse_opts_0_INTMAX(&Xreadahead);
2143 if (c == 'B') getset_apmmode = parse_opts(&apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002144 do_flush |= do_timings |= (c == 't');
2145 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002146#ifdef HDIO_DRIVE_CMD
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002147 if (c == 'S') getset_standby = parse_opts_0_max(&standby_requested, 255);
2148 if (c == 'D') getset_defects = parse_opts_0_INTMAX(&defects);
2149 if (c == 'P') getset_prefetch = parse_opts_0_INTMAX(&prefetch);
Rob Landleyade7f952006-05-25 18:53:06 +00002150 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002151 if (c == 'K') getset_dkeep = parse_opts_0_1(&prefetch);
2152 if (c == 'A') getset_lookahead = parse_opts_0_1(&lookahead);
2153 if (c == 'L') getset_doorlock = parse_opts_0_1(&doorlock);
2154 if (c == 'W') getset_wcache = parse_opts_0_1(&wcache);
Rob Landleyade7f952006-05-25 18:53:06 +00002155 get_powermode |= (c == 'C');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002156 set_standbynow |= (c == 'y');
2157 set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002158 reread_partn |= (c == 'z');
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002159 set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002160#endif
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002161 IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') unregister_hwif = parse_opts_0_INTMAX(&hwif));
Rob Landley20deab02006-05-07 23:34:15 +00002162#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002163 if (c == 'Q') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002164 getset_dma_q = parse_opts_0_INTMAX(&dma_q);
Rob Landley19802562006-05-08 15:35:46 +00002165 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002166#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002167 IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002168 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') perform_tristate = parse_opts_0_1(&tristate));
2169 IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') getset_busstate = parse_opts_0_max(&busstate, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002170#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2171 if (c == 'R') {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002172 scan_hwif = parse_opts_0_INTMAX(&hwif_data);
Denys Vlasenko77832482010-08-12 14:14:45 +02002173 hwif_ctrl = xatoi_positive((argv[optind]) ? argv[optind] : "");
2174 hwif_irq = xatoi_positive((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002175 /* Move past the 2 additional arguments */
2176 argv += 2;
2177 argc -= 2;
2178 }
2179#endif
2180 }
Rob Landleyade7f952006-05-25 18:53:06 +00002181 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002182 if (!flagcount) {
Denys Vlasenkoc7068452009-05-20 16:11:41 +02002183 getset_mult = getset_io32bit = getset_unmask = getset_keep = getset_readonly = getset_readahead = get_geom = IS_GET;
2184 IF_FEATURE_HDPARM_HDIO_GETSET_DMA(getset_dma = IS_GET);
Rob Landleyade7f952006-05-25 18:53:06 +00002185 }
Rob Landley20deab02006-05-07 23:34:15 +00002186 argv += optind;
2187
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002188 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002189 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2190 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002191 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002192 }
2193
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002194 do {
2195 process_dev(*argv++);
2196 } while (*argv);
2197
2198 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002199}