blob: 869a5b246d79b6fa50105e1a8b4a8cc65a476147 [file] [log] [blame]
Eric Andersen3443bd72003-07-22 07:30:36 +00001/* vi: set sw=4 ts=4: */
2/*
3 * hdparm implementation for busybox
4 *
Glenn L McGrath5be6a202003-11-28 22:55:03 +00005 * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
Glenn L McGrath07085852003-10-09 07:28:22 +00006 * Hacked by Tito <farmatito@tiscali.it> for size optimization.
Eric Andersen3443bd72003-07-22 07:30:36 +00007 *
Mike Frysingerf284c762006-04-16 20:38:26 +00008 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen3443bd72003-07-22 07:30:36 +00009 *
10 * This program is based on the source code of hdparm: see below...
11 * hdparm.c - Command line interface to get/set hard disk parameters
12 * - by Mark Lord (C) 1994-2002 -- freely distributable
13 */
Glenn L McGrath07085852003-10-09 07:28:22 +000014
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000015#include "libbb.h"
Eric Andersen3443bd72003-07-22 07:30:36 +000016#include <linux/hdreg.h>
Eric Andersen3443bd72003-07-22 07:30:36 +000017
Eric Andersen3443bd72003-07-22 07:30:36 +000018/* device types */
19/* ------------ */
20#define NO_DEV 0xffff
21#define ATA_DEV 0x0000
22#define ATAPI_DEV 0x0001
23
24/* word definitions */
25/* ---------------- */
26#define GEN_CONFIG 0 /* general configuration */
27#define LCYLS 1 /* number of logical cylinders */
28#define CONFIG 2 /* specific configuration */
29#define LHEADS 3 /* number of logical heads */
30#define TRACK_BYTES 4 /* number of bytes/track (ATA-1) */
31#define SECT_BYTES 5 /* number of bytes/sector (ATA-1) */
32#define LSECTS 6 /* number of logical sectors/track */
33#define START_SERIAL 10 /* ASCII serial number */
34#define LENGTH_SERIAL 10 /* 10 words (20 bytes or characters) */
35#define BUF_TYPE 20 /* buffer type (ATA-1) */
36#define BUFFER__SIZE 21 /* buffer size (ATA-1) */
37#define RW_LONG 22 /* extra bytes in R/W LONG cmd ( < ATA-4)*/
38#define START_FW_REV 23 /* ASCII firmware revision */
39#define LENGTH_FW_REV 4 /* 4 words (8 bytes or characters) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000040#define START_MODEL 27 /* ASCII model number */
41#define LENGTH_MODEL 20 /* 20 words (40 bytes or characters) */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000042#define SECTOR_XFER_MAX 47 /* r/w multiple: max sectors xfered */
Eric Andersen3443bd72003-07-22 07:30:36 +000043#define DWORD_IO 48 /* can do double-word IO (ATA-1 only) */
44#define CAPAB_0 49 /* capabilities */
45#define CAPAB_1 50
46#define PIO_MODE 51 /* max PIO mode supported (obsolete)*/
47#define DMA_MODE 52 /* max Singleword DMA mode supported (obs)*/
48#define WHATS_VALID 53 /* what fields are valid */
49#define LCYLS_CUR 54 /* current logical cylinders */
50#define LHEADS_CUR 55 /* current logical heads */
Denis Vlasenko4b924f32007-05-30 00:29:55 +000051#define LSECTS_CUR 56 /* current logical sectors/track */
Eric Andersen3443bd72003-07-22 07:30:36 +000052#define CAPACITY_LSB 57 /* current capacity in sectors */
53#define CAPACITY_MSB 58
54#define SECTOR_XFER_CUR 59 /* r/w multiple: current sectors xfered */
55#define LBA_SECTS_LSB 60 /* LBA: total number of user */
56#define LBA_SECTS_MSB 61 /* addressable sectors */
57#define SINGLE_DMA 62 /* singleword DMA modes */
58#define MULTI_DMA 63 /* multiword DMA modes */
59#define ADV_PIO_MODES 64 /* advanced PIO modes supported */
60 /* multiword DMA xfer cycle time: */
61#define DMA_TIME_MIN 65 /* - minimum */
62#define DMA_TIME_NORM 66 /* - manufacturer's recommended */
63 /* minimum PIO xfer cycle time: */
64#define PIO_NO_FLOW 67 /* - without flow control */
65#define PIO_FLOW 68 /* - with IORDY flow control */
66#define PKT_REL 71 /* typical #ns from PKT cmd to bus rel */
67#define SVC_NBSY 72 /* typical #ns from SERVICE cmd to !BSY */
68#define CDR_MAJOR 73 /* CD ROM: major version number */
69#define CDR_MINOR 74 /* CD ROM: minor version number */
70#define QUEUE_DEPTH 75 /* queue depth */
71#define MAJOR 80 /* major version number */
72#define MINOR 81 /* minor version number */
73#define CMDS_SUPP_0 82 /* command/feature set(s) supported */
74#define CMDS_SUPP_1 83
75#define CMDS_SUPP_2 84
76#define CMDS_EN_0 85 /* command/feature set(s) enabled */
77#define CMDS_EN_1 86
78#define CMDS_EN_2 87
79#define ULTRA_DMA 88 /* ultra DMA modes */
80 /* time to complete security erase */
81#define ERASE_TIME 89 /* - ordinary */
82#define ENH_ERASE_TIME 90 /* - enhanced */
83#define ADV_PWR 91 /* current advanced power management level
Glenn L McGrath07085852003-10-09 07:28:22 +000084 in low byte, 0x40 in high byte. */
Eric Andersen3443bd72003-07-22 07:30:36 +000085#define PSWD_CODE 92 /* master password revision code */
86#define HWRST_RSLT 93 /* hardware reset result */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000087#define ACOUSTIC 94 /* acoustic mgmt values ( >= ATA-6) */
Eric Andersen3443bd72003-07-22 07:30:36 +000088#define LBA_LSB 100 /* LBA: maximum. Currently only 48 */
89#define LBA_MID 101 /* bits are used, but addr 103 */
90#define LBA_48_MSB 102 /* has been reserved for LBA in */
91#define LBA_64_MSB 103 /* the future. */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000092#define RM_STAT 127 /* removable media status notification feature set support */
Eric Andersen3443bd72003-07-22 07:30:36 +000093#define SECU_STATUS 128 /* security status */
94#define CFA_PWR_MODE 160 /* CFA power mode 1 */
95#define START_MEDIA 176 /* media serial number */
96#define LENGTH_MEDIA 20 /* 20 words (40 bytes or characters)*/
97#define START_MANUF 196 /* media manufacturer I.D. */
98#define LENGTH_MANUF 10 /* 10 words (20 bytes or characters) */
99#define INTEGRITY 255 /* integrity word */
100
101/* bit definitions within the words */
102/* -------------------------------- */
103
104/* many words are considered valid if bit 15 is 0 and bit 14 is 1 */
105#define VALID 0xc000
106#define VALID_VAL 0x4000
107/* many words are considered invalid if they are either all-0 or all-1 */
108#define NOVAL_0 0x0000
109#define NOVAL_1 0xffff
110
111/* word 0: gen_config */
Glenn L McGrath07085852003-10-09 07:28:22 +0000112#define NOT_ATA 0x8000
Eric Andersen3443bd72003-07-22 07:30:36 +0000113#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
114#define MEDIA_REMOVABLE 0x0080
115#define DRIVE_NOT_REMOVABLE 0x0040 /* bit obsoleted in ATA 6 */
116#define INCOMPLETE 0x0004
117#define CFA_SUPPORT_VAL 0x848a /* 848a=CFA feature set support */
118#define DRQ_RESPONSE_TIME 0x0060
119#define DRQ_3MS_VAL 0x0000
120#define DRQ_INTR_VAL 0x0020
121#define DRQ_50US_VAL 0x0040
122#define PKT_SIZE_SUPPORTED 0x0003
123#define PKT_SIZE_12_VAL 0x0000
124#define PKT_SIZE_16_VAL 0x0001
125#define EQPT_TYPE 0x1f00
126#define SHIFT_EQPT 8
127
128#define CDROM 0x0005
129
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000130#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000131static const char *const pkt_str[] = {
Eric Andersen3443bd72003-07-22 07:30:36 +0000132 "Direct-access device", /* word 0, bits 12-8 = 00 */
133 "Sequential-access device", /* word 0, bits 12-8 = 01 */
134 "Printer", /* word 0, bits 12-8 = 02 */
135 "Processor", /* word 0, bits 12-8 = 03 */
136 "Write-once device", /* word 0, bits 12-8 = 04 */
137 "CD-ROM", /* word 0, bits 12-8 = 05 */
138 "Scanner", /* word 0, bits 12-8 = 06 */
139 "Optical memory", /* word 0, bits 12-8 = 07 */
140 "Medium changer", /* word 0, bits 12-8 = 08 */
141 "Communications device", /* word 0, bits 12-8 = 09 */
142 "ACS-IT8 device", /* word 0, bits 12-8 = 0a */
143 "ACS-IT8 device", /* word 0, bits 12-8 = 0b */
144 "Array controller", /* word 0, bits 12-8 = 0c */
145 "Enclosure services", /* word 0, bits 12-8 = 0d */
146 "Reduced block command device", /* word 0, bits 12-8 = 0e */
147 "Optical card reader/writer", /* word 0, bits 12-8 = 0f */
148 "", /* word 0, bits 12-8 = 10 */
149 "", /* word 0, bits 12-8 = 11 */
150 "", /* word 0, bits 12-8 = 12 */
151 "", /* word 0, bits 12-8 = 13 */
152 "", /* word 0, bits 12-8 = 14 */
153 "", /* word 0, bits 12-8 = 15 */
154 "", /* word 0, bits 12-8 = 16 */
155 "", /* word 0, bits 12-8 = 17 */
156 "", /* word 0, bits 12-8 = 18 */
157 "", /* word 0, bits 12-8 = 19 */
158 "", /* word 0, bits 12-8 = 1a */
159 "", /* word 0, bits 12-8 = 1b */
160 "", /* word 0, bits 12-8 = 1c */
161 "", /* word 0, bits 12-8 = 1d */
162 "", /* word 0, bits 12-8 = 1e */
Rob Landleyadde7982006-05-16 15:32:30 +0000163 "Unknown", /* word 0, bits 12-8 = 1f */
Eric Andersen3443bd72003-07-22 07:30:36 +0000164};
"Vladimir N. Oleynik"b4b6d262005-10-15 14:10:36 +0000165
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000166static const char *const ata1_cfg_str[] = { /* word 0 in ATA-1 mode */
Rob Landleyadde7982006-05-16 15:32:30 +0000167 "Reserved", /* bit 0 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000168 "hard sectored", /* bit 1 */
169 "soft sectored", /* bit 2 */
170 "not MFM encoded ", /* bit 3 */
171 "head switch time > 15us", /* bit 4 */
172 "spindle motor control option", /* bit 5 */
173 "fixed drive", /* bit 6 */
174 "removable drive", /* bit 7 */
175 "disk xfer rate <= 5Mbs", /* bit 8 */
176 "disk xfer rate > 5Mbs, <= 10Mbs", /* bit 9 */
177 "disk xfer rate > 5Mbs", /* bit 10 */
178 "rotational speed tol.", /* bit 11 */
179 "data strobe offset option", /* bit 12 */
180 "track offset option", /* bit 13 */
181 "format speed tolerance gap reqd", /* bit 14 */
182 "ATAPI" /* bit 14 */
183};
184#endif
185
186/* word 1: number of logical cylinders */
187#define LCYLS_MAX 0x3fff /* maximum allowable value */
188
Eric Andersenaff114c2004-04-14 17:51:38 +0000189/* word 2: specific configuration
Eric Andersen3443bd72003-07-22 07:30:36 +0000190 * (a) require SET FEATURES to spin-up
191 * (b) require spin-up to fully reply to IDENTIFY DEVICE
192 */
193#define STBY_NID_VAL 0x37c8 /* (a) and (b) */
194#define STBY_ID_VAL 0x738c /* (a) and not (b) */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000195#define PWRD_NID_VAL 0x8c73 /* not (a) and (b) */
Eric Andersen3443bd72003-07-22 07:30:36 +0000196#define PWRD_ID_VAL 0xc837 /* not (a) and not (b) */
197
198/* words 47 & 59: sector_xfer_max & sector_xfer_cur */
199#define SECTOR_XFER 0x00ff /* sectors xfered on r/w multiple cmds*/
200#define MULTIPLE_SETTING_VALID 0x0100 /* 1=multiple sector setting is valid */
201
202/* word 49: capabilities 0 */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000203#define STD_STBY 0x2000 /* 1=standard values supported (ATA); 0=vendor specific values */
Eric Andersen3443bd72003-07-22 07:30:36 +0000204#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
205#define IORDY_OFF 0x0400 /* 1=may be disabled */
206#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
207#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
208#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
209#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
210#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
211#define SWRST_REQ 0x1000 /* 1=ATA SW reset required (ATAPI, obsolete */
212
213/* word 50: capabilities 1 */
214#define MIN_STANDBY_TIMER 0x0001 /* 1=device specific standby timer value minimum */
215
216/* words 51 & 52: PIO & DMA cycle times */
217#define MODE 0xff00 /* the mode is in the MSBs */
218
219/* word 53: whats_valid */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000220#define OK_W88 0x0004 /* the ultra_dma info is valid */
Eric Andersen3443bd72003-07-22 07:30:36 +0000221#define OK_W64_70 0x0002 /* see above for word descriptions */
222#define OK_W54_58 0x0001 /* current cyl, head, sector, cap. info valid */
223
224/*word 63,88: dma_mode, ultra_dma_mode*/
225#define MODE_MAX 7 /* bit definitions force udma <=7 (when
226 * udma >=8 comes out it'll have to be
227 * defined in a new dma_mode word!) */
228
229/* word 64: PIO transfer modes */
230#define PIO_SUP 0x00ff /* only bits 0 & 1 are used so far, */
231#define PIO_MODE_MAX 8 /* but all 8 bits are defined */
232
233/* word 75: queue_depth */
234#define DEPTH_BITS 0x001f /* bits used for queue depth */
235
236/* words 80-81: version numbers */
237/* NOVAL_0 or NOVAL_1 means device does not report version */
238
239/* word 81: minor version number */
Rob Landley0e6a3e12006-04-28 01:33:30 +0000240#define MINOR_MAX 0x22
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000241#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000242static const char *const minor_str[MINOR_MAX + 2] = {
243 /* word 81 value: */
244 "Unspecified", /* 0x0000 */
245 "ATA-1 X3T9.2 781D prior to rev.4", /* 0x0001 */
246 "ATA-1 published, ANSI X3.221-1994", /* 0x0002 */
247 "ATA-1 X3T9.2 781D rev.4", /* 0x0003 */
248 "ATA-2 published, ANSI X3.279-1996", /* 0x0004 */
249 "ATA-2 X3T10 948D prior to rev.2k", /* 0x0005 */
250 "ATA-3 X3T10 2008D rev.1", /* 0x0006 */
251 "ATA-2 X3T10 948D rev.2k", /* 0x0007 */
252 "ATA-3 X3T10 2008D rev.0", /* 0x0008 */
253 "ATA-2 X3T10 948D rev.3", /* 0x0009 */
254 "ATA-3 published, ANSI X3.298-199x", /* 0x000a */
255 "ATA-3 X3T10 2008D rev.6", /* 0x000b */
256 "ATA-3 X3T13 2008D rev.7 and 7a", /* 0x000c */
257 "ATA/ATAPI-4 X3T13 1153D rev.6", /* 0x000d */
258 "ATA/ATAPI-4 T13 1153D rev.13", /* 0x000e */
259 "ATA/ATAPI-4 X3T13 1153D rev.7", /* 0x000f */
260 "ATA/ATAPI-4 T13 1153D rev.18", /* 0x0010 */
261 "ATA/ATAPI-4 T13 1153D rev.15", /* 0x0011 */
262 "ATA/ATAPI-4 published, ANSI INCITS 317-1998", /* 0x0012 */
263 "ATA/ATAPI-5 T13 1321D rev.3", /* 0x0013 */
264 "ATA/ATAPI-4 T13 1153D rev.14", /* 0x0014 */
265 "ATA/ATAPI-5 T13 1321D rev.1", /* 0x0015 */
266 "ATA/ATAPI-5 published, ANSI INCITS 340-2000", /* 0x0016 */
267 "ATA/ATAPI-4 T13 1153D rev.17", /* 0x0017 */
268 "ATA/ATAPI-6 T13 1410D rev.0", /* 0x0018 */
269 "ATA/ATAPI-6 T13 1410D rev.3a", /* 0x0019 */
270 "ATA/ATAPI-7 T13 1532D rev.1", /* 0x001a */
271 "ATA/ATAPI-6 T13 1410D rev.2", /* 0x001b */
272 "ATA/ATAPI-6 T13 1410D rev.1", /* 0x001c */
273 "ATA/ATAPI-7 published, ANSI INCITS 397-2005", /* 0x001d */
274 "ATA/ATAPI-7 T13 1532D rev.0", /* 0x001e */
275 "Reserved" /* 0x001f */
276 "Reserved" /* 0x0020 */
277 "ATA/ATAPI-7 T13 1532D rev.4a", /* 0x0021 */
278 "ATA/ATAPI-6 published, ANSI INCITS 361-2002", /* 0x0022 */
279 "Reserved" /* 0x0023-0xfffe */
Eric Andersen3443bd72003-07-22 07:30:36 +0000280};
281#endif
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000282static const char actual_ver[MINOR_MAX + 2] ALIGN1 = {
283 /* word 81 value: */
284 0, /* 0x0000 WARNING: actual_ver[] array */
285 1, /* 0x0001 WARNING: corresponds */
286 1, /* 0x0002 WARNING: *exactly* */
287 1, /* 0x0003 WARNING: to the ATA/ */
288 2, /* 0x0004 WARNING: ATAPI version */
289 2, /* 0x0005 WARNING: listed in */
290 3, /* 0x0006 WARNING: the */
291 2, /* 0x0007 WARNING: minor_str */
292 3, /* 0x0008 WARNING: array */
293 2, /* 0x0009 WARNING: above. */
294 3, /* 0x000a WARNING: */
295 3, /* 0x000b WARNING: If you change */
296 3, /* 0x000c WARNING: that one, */
297 4, /* 0x000d WARNING: change this one */
298 4, /* 0x000e WARNING: too!!! */
299 4, /* 0x000f */
300 4, /* 0x0010 */
301 4, /* 0x0011 */
302 4, /* 0x0012 */
303 5, /* 0x0013 */
304 4, /* 0x0014 */
305 5, /* 0x0015 */
306 5, /* 0x0016 */
307 4, /* 0x0017 */
308 6, /* 0x0018 */
309 6, /* 0x0019 */
310 7, /* 0x001a */
311 6, /* 0x001b */
312 6, /* 0x001c */
313 7, /* 0x001d */
314 7, /* 0x001e */
315 0, /* 0x001f */
316 0, /* 0x0020 */
317 7, /* 0x0021 */
318 6, /* 0x0022 */
319 0 /* 0x0023-0xfffe */
Eric Andersen3443bd72003-07-22 07:30:36 +0000320};
321
322/* words 82-84: cmds/feats supported */
323#define CMDS_W82 0x77ff /* word 82: defined command locations*/
324#define CMDS_W83 0x3fff /* word 83: defined command locations*/
325#define CMDS_W84 0x002f /* word 83: defined command locations*/
Glenn L McGrath07085852003-10-09 07:28:22 +0000326#define SUPPORT_48_BIT 0x0400
Eric Andersen3443bd72003-07-22 07:30:36 +0000327#define NUM_CMD_FEAT_STR 48
328
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000329#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000330static const char *const cmd_feat_str[] = {
Eric Andersen3443bd72003-07-22 07:30:36 +0000331 "", /* word 82 bit 15: obsolete */
332 "NOP cmd", /* word 82 bit 14 */
333 "READ BUFFER cmd", /* word 82 bit 13 */
334 "WRITE BUFFER cmd", /* word 82 bit 12 */
335 "", /* word 82 bit 11: obsolete */
336 "Host Protected Area feature set", /* word 82 bit 10 */
337 "DEVICE RESET cmd", /* word 82 bit 9 */
338 "SERVICE interrupt", /* word 82 bit 8 */
339 "Release interrupt", /* word 82 bit 7 */
340 "Look-ahead", /* word 82 bit 6 */
341 "Write cache", /* word 82 bit 5 */
342 "PACKET command feature set", /* word 82 bit 4 */
343 "Power Management feature set", /* word 82 bit 3 */
344 "Removable Media feature set", /* word 82 bit 2 */
345 "Security Mode feature set", /* word 82 bit 1 */
346 "SMART feature set", /* word 82 bit 0 */
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000347 /* -------------- */
Eric Andersen3443bd72003-07-22 07:30:36 +0000348 "", /* word 83 bit 15: !valid bit */
349 "", /* word 83 bit 14: valid bit */
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000350 "FLUSH CACHE EXT cmd", /* word 83 bit 13 */
351 "Mandatory FLUSH CACHE cmd ", /* word 83 bit 12 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000352 "Device Configuration Overlay feature set ",
353 "48-bit Address feature set ", /* word 83 bit 10 */
354 "",
355 "SET MAX security extension", /* word 83 bit 8 */
356 "Address Offset Reserved Area Boot", /* word 83 bit 7 */
357 "SET FEATURES subcommand required to spinup after power up",
358 "Power-Up In Standby feature set", /* word 83 bit 5 */
359 "Removable Media Status Notification feature set",
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000360 "Adv. Power Management feature set", /* word 83 bit 3 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000361 "CFA feature set", /* word 83 bit 2 */
362 "READ/WRITE DMA QUEUED", /* word 83 bit 1 */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000363 "DOWNLOAD MICROCODE cmd", /* word 83 bit 0 */
Denis Vlasenko6a2f7f42007-08-16 10:35:17 +0000364 /* -------------- */
Eric Andersen3443bd72003-07-22 07:30:36 +0000365 "", /* word 84 bit 15: !valid bit */
366 "", /* word 84 bit 14: valid bit */
367 "", /* word 84 bit 13: reserved */
368 "", /* word 84 bit 12: reserved */
369 "", /* word 84 bit 11: reserved */
370 "", /* word 84 bit 10: reserved */
371 "", /* word 84 bit 9: reserved */
372 "", /* word 84 bit 8: reserved */
373 "", /* word 84 bit 7: reserved */
374 "", /* word 84 bit 6: reserved */
375 "General Purpose Logging feature set", /* word 84 bit 5 */
376 "", /* word 84 bit 4: reserved */
377 "Media Card Pass Through Command feature set ",
378 "Media serial number ", /* word 84 bit 2 */
379 "SMART self-test ", /* word 84 bit 1 */
380 "SMART error logging " /* word 84 bit 0 */
381};
382#endif
383
384
385/* words 85-87: cmds/feats enabled */
386/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000387 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000388 */
389
390/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000391#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000392
393/* word 92: master password revision */
394/* NOVAL_0 or NOVAL_1 means no support for master password revision */
395
396/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000397#define CBLID 0x2000 /* CBLID status */
398#define RST0 0x0001 /* 1=reset to device #0 */
399#define DEV_DET 0x0006 /* how device num determined */
400#define JUMPER_VAL 0x0002 /* device num determined by jumper */
401#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000402
403/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000404#define RM_STAT_BITS 0x0003
405#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000406
Eric Andersen3443bd72003-07-22 07:30:36 +0000407/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000408#define SECU_ENABLED 0x0002
409#define SECU_LEVEL 0x0010
410#define NUM_SECU_STR 6
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000411#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000412static const char *const secu_str[] = {
Eric Andersen3443bd72003-07-22 07:30:36 +0000413 "supported", /* word 128, bit 0 */
414 "enabled", /* word 128, bit 1 */
415 "locked", /* word 128, bit 2 */
416 "frozen", /* word 128, bit 3 */
417 "expired: security count", /* word 128, bit 4 */
418 "supported: enhanced erase" /* word 128, bit 5 */
419};
420#endif
421
422/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000423#define VALID_W160 0x8000 /* 1=word valid */
424#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
425#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
426#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000427
428/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000429#define SIG 0x00ff /* signature location */
430#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000431
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000432#define TIMING_BUF_MB 1
433#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
Glenn L McGrath07085852003-10-09 07:28:22 +0000434
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000435#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000436
Denis Vlasenko892536f2007-09-27 10:23:34 +0000437
438enum { fd = 3 };
439
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000440
441struct globals {
442 smallint get_identity, get_geom;
443 smallint do_flush;
444 smallint do_ctimings, do_timings;
445 smallint reread_partn;
446 smallint set_piomode, noisy_piomode;
447 smallint set_readahead, get_readahead;
448 smallint set_readonly, get_readonly;
449 smallint set_unmask, get_unmask;
450 smallint set_mult, get_mult;
451 smallint set_dma_q, get_dma_q;
452 smallint set_nowerr, get_nowerr;
453 smallint set_keep, get_keep;
454 smallint set_io32bit, get_io32bit;
455 int piomode;
456 unsigned long Xreadahead;
457 unsigned long readonly;
458 unsigned long unmask;
459 unsigned long mult;
460 unsigned long dma_q;
461 unsigned long nowerr;
462 unsigned long keep;
463 unsigned long io32bit;
464#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
465 unsigned long dma;
466 smallint set_dma, get_dma;
467#endif
468#ifdef HDIO_DRIVE_CMD
469 smallint set_xfermode, get_xfermode;
470 smallint set_dkeep, get_dkeep;
471 smallint set_standby, get_standby;
472 smallint set_lookahead, get_lookahead;
473 smallint set_prefetch, get_prefetch;
474 smallint set_defects, get_defects;
475 smallint set_wcache, get_wcache;
476 smallint set_doorlock, get_doorlock;
477 smallint set_seagate, get_seagate;
478 smallint set_standbynow, get_standbynow;
479 smallint set_sleepnow, get_sleepnow;
480 smallint get_powermode;
481 smallint set_apmmode, get_apmmode;
482 int xfermode_requested;
483 unsigned long dkeep;
484 unsigned long standby_requested;
485 unsigned long lookahead;
486 unsigned long prefetch;
487 unsigned long defects;
488 unsigned long wcache;
489 unsigned long doorlock;
490 unsigned long apmmode;
491#endif
492 USE_FEATURE_HDPARM_GET_IDENTITY( smallint get_IDentity;)
493 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint set_busstate, get_busstate;)
494 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( smallint perform_reset;)
495 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( smallint perform_tristate;)
496 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
497 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( smallint scan_hwif;)
498 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long busstate;)
499 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( unsigned long tristate;)
500 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
501#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
502 unsigned long hwif_data;
503 unsigned long hwif_ctrl;
504 unsigned long hwif_irq;
505#endif
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +0000506#ifdef DO_FLUSHCACHE
507 unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
508#endif
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000509};
510#define G (*(struct globals*)&bb_common_bufsiz1)
511struct BUG_G_too_big {
512 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
513};
514#define get_identity (G.get_identity )
515#define get_geom (G.get_geom )
516#define do_flush (G.do_flush )
517#define do_ctimings (G.do_ctimings )
518#define do_timings (G.do_timings )
519#define reread_partn (G.reread_partn )
520#define set_piomode (G.set_piomode )
521#define noisy_piomode (G.noisy_piomode )
522#define set_readahead (G.set_readahead )
523#define get_readahead (G.get_readahead )
524#define set_readonly (G.set_readonly )
525#define get_readonly (G.get_readonly )
526#define set_unmask (G.set_unmask )
527#define get_unmask (G.get_unmask )
528#define set_mult (G.set_mult )
529#define get_mult (G.get_mult )
530#define set_dma_q (G.set_dma_q )
531#define get_dma_q (G.get_dma_q )
532#define set_nowerr (G.set_nowerr )
533#define get_nowerr (G.get_nowerr )
534#define set_keep (G.set_keep )
535#define get_keep (G.get_keep )
536#define set_io32bit (G.set_io32bit )
537#define get_io32bit (G.get_io32bit )
538#define piomode (G.piomode )
539#define Xreadahead (G.Xreadahead )
540#define readonly (G.readonly )
541#define unmask (G.unmask )
542#define mult (G.mult )
543#define dma_q (G.dma_q )
544#define nowerr (G.nowerr )
545#define keep (G.keep )
546#define io32bit (G.io32bit )
547#define dma (G.dma )
548#define set_dma (G.set_dma )
549#define get_dma (G.get_dma )
550#define set_xfermode (G.set_xfermode )
551#define get_xfermode (G.get_xfermode )
552#define set_dkeep (G.set_dkeep )
553#define get_dkeep (G.get_dkeep )
554#define set_standby (G.set_standby )
555#define get_standby (G.get_standby )
556#define set_lookahead (G.set_lookahead )
557#define get_lookahead (G.get_lookahead )
558#define set_prefetch (G.set_prefetch )
559#define get_prefetch (G.get_prefetch )
560#define set_defects (G.set_defects )
561#define get_defects (G.get_defects )
562#define set_wcache (G.set_wcache )
563#define get_wcache (G.get_wcache )
564#define set_doorlock (G.set_doorlock )
565#define get_doorlock (G.get_doorlock )
566#define set_seagate (G.set_seagate )
567#define get_seagate (G.get_seagate )
568#define set_standbynow (G.set_standbynow )
569#define get_standbynow (G.get_standbynow )
570#define set_sleepnow (G.set_sleepnow )
571#define get_sleepnow (G.get_sleepnow )
572#define get_powermode (G.get_powermode )
573#define set_apmmode (G.set_apmmode )
574#define get_apmmode (G.get_apmmode )
575#define xfermode_requested (G.xfermode_requested )
576#define dkeep (G.dkeep )
577#define standby_requested (G.standby_requested )
578#define lookahead (G.lookahead )
579#define prefetch (G.prefetch )
580#define defects (G.defects )
581#define wcache (G.wcache )
582#define doorlock (G.doorlock )
583#define apmmode (G.apmmode )
584#define get_IDentity (G.get_IDentity )
585#define set_busstate (G.set_busstate )
586#define get_busstate (G.get_busstate )
587#define perform_reset (G.perform_reset )
588#define perform_tristate (G.perform_tristate )
589#define unregister_hwif (G.unregister_hwif )
590#define scan_hwif (G.scan_hwif )
591#define busstate (G.busstate )
592#define tristate (G.tristate )
593#define hwif (G.hwif )
594#define hwif_data (G.hwif_data )
595#define hwif_ctrl (G.hwif_ctrl )
596#define hwif_irq (G.hwif_irq )
597
598
Glenn L McGrath07085852003-10-09 07:28:22 +0000599/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000600#if ENABLE_IOCTL_HEX2STR_ERROR
Denis Vlasenko892536f2007-09-27 10:23:34 +0000601static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000602{
603 if (!ioctl(fd, cmd, args))
604 return 0;
605 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000606 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000607}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000608#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt,#cmd)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000609#else
Denis Vlasenko892536f2007-09-27 10:23:34 +0000610static int ioctl_alt_func(/*int fd,*/ int cmd, unsigned char *args, int alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000611{
612 if (!ioctl(fd, cmd, args))
613 return 0;
614 args[0] = alt;
615 return bb_ioctl_or_warn(fd, cmd, args);
616}
Denis Vlasenko892536f2007-09-27 10:23:34 +0000617#define ioctl_alt_or_warn(cmd,args,alt) ioctl_alt_func(cmd,args,alt)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000618#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000619
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000620static void on_off(int value)
621{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000622 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000623}
Glenn L McGrath07085852003-10-09 07:28:22 +0000624
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000625static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000626{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000627 if (get_arg) {
Rob Landleyadde7982006-05-16 15:32:30 +0000628 printf(" setting %s to %ld", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000629 on_off(arg);
630 }
631}
632
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000633static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000634{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000635 printf(" %s\t= %2ld", str, argp);
636 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000637}
Eric Andersen416c2422003-12-12 00:08:57 +0000638
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000639#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko4daad902007-09-27 10:20:47 +0000640static void print_ascii(const char *p, int length)
641{
642#if BB_BIG_ENDIAN
643#define LE_ONLY(x)
644 enum { ofs = 0 };
645#else
646#define LE_ONLY(x) x
647 /* every 16bit word is big-endian (i.e. inverted) */
648 /* accessing bytes in 1,0, 3,2, 5,4... sequence */
649 int ofs = 1;
650#endif
651
652 length *= 2;
653 /* find first non-space & print it */
654 while (length && p[ofs] != ' ') {
655 p++;
656 LE_ONLY(ofs = -ofs;)
657 length--;
658 }
659 while (length && p[ofs]) {
660 bb_putchar(p[ofs]);
661 p++;
662 LE_ONLY(ofs = -ofs;)
663 length--;
664 }
665 bb_putchar('\n');
666#undef LE_ONLY
667}
Glenn L McGrath07085852003-10-09 07:28:22 +0000668
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000669static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000670{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000671 if (val[i]) {
672 printf("\t%-20s", string);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000673 print_ascii((void*)&val[i], n);
Glenn L McGrath07085852003-10-09 07:28:22 +0000674 }
675}
Glenn L McGrath07085852003-10-09 07:28:22 +0000676
Glenn L McGrath07085852003-10-09 07:28:22 +0000677static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
678{
Eric Andersen3443bd72003-07-22 07:30:36 +0000679 uint16_t ii;
680 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000681
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000682 for (ii = 0; ii <= MODE_MAX; ii++) {
683 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000684 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000685 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000686 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000687 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000688 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000689 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000690
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000691 mode_sup >>= 1;
692 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000693 }
694 return err_dma;
695}
Glenn L McGrath07085852003-10-09 07:28:22 +0000696
Rob Landley0753f4a2006-06-07 00:27:25 +0000697// Parse 512 byte disk identification block and print much crap.
698
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +0000699static void identify(uint16_t *val) ATTRIBUTE_NORETURN;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000700static void identify(uint16_t *val)
Eric Andersen3443bd72003-07-22 07:30:36 +0000701{
Denis Vlasenko4daad902007-09-27 10:20:47 +0000702 uint16_t ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000703 uint16_t like_std = 1, std = 0, min_std = 0xffff;
704 uint16_t dev = NO_DEV, eqpt = NO_DEV;
705 uint8_t have_mode = 0, err_dma = 0;
706 uint8_t chksum = 0;
707 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000708 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000709 const char *strng;
Denis Vlasenko4daad902007-09-27 10:20:47 +0000710#if BB_BIG_ENDIAN
711 uint16_t buf[256];
Eric Andersen3443bd72003-07-22 07:30:36 +0000712
Denis Vlasenko4daad902007-09-27 10:20:47 +0000713 // Adjust for endianness
714 swab(val, buf, sizeof(buf));
715 val = buf;
716#endif
Eric Andersen3443bd72003-07-22 07:30:36 +0000717 /* check if we recognise the device type */
Denis Vlasenko4daad902007-09-27 10:20:47 +0000718 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000719 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000720 dev = ATA_DEV;
721 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000722 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000723 dev = ATA_DEV;
724 like_std = 4;
725 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000726 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000727 dev = ATAPI_DEV;
728 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
729 printf("ATAPI %s, with ", pkt_str[eqpt]);
730 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000731 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000732 /*"Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n"*/
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000733 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000734
Rob Landleyadde7982006-05-16 15:32:30 +0000735 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000736 /* Info from the specific configuration word says whether or not the
737 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000738 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000739 * standards. Since the values allowed for this word are extremely
740 * specific, it should be safe to check it now, even though we don't
741 * know yet what standard this device is using.
742 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000743 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
744 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
745 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000746 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000747 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Rob Landleyadde7982006-05-16 15:32:30 +0000748 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000749 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Rob Landleyadde7982006-05-16 15:32:30 +0000750 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000751 }
752
753 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000754 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
755 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
756 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
757 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
758 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000759
760 /* major & minor standards version number (Note: these words were not
761 * defined until ATA-3 & the CDROM std uses different words.) */
762 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000763 if (eqpt != CDROM) {
764 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000765 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000766 std = actual_ver[val[MINOR]];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000767 if (std) printf("\n\tUsed: %s ", minor_str[val[MINOR]]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000768
Eric Andersen3443bd72003-07-22 07:30:36 +0000769 }
770 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000771 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000772 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000773 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000774 printf("\n\tSupported: ");
775 jj = val[MAJOR] << 1;
776 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000777 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
778 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000779 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000780 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000781 like_std = ii;
782 kk = like_std >4 ? like_std-4: 0;
783 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000784 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000785 }
786 jj <<= 1;
787 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000788 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000789 }
790 /* Figure out what standard the device is using if it hasn't told
791 * us. If we know the std, check if the device is using any of
792 * the words from the next level up. It happens.
793 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000794 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000795
Rob Landleya3e4f382006-04-29 16:06:31 +0000796 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000797 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
798 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
799 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000800 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
801 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000802 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000803 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000804 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000805 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
806 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
807 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
808 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000809 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000810 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000811 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
812 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
813 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
814 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
815 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000816 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
817 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000818 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000819 } else if (((std == 2) || (!std && (like_std < 3)))
820 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
821 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000822 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000823 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000824 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
825 (val[WHATS_VALID] & OK_W64_70)) )
826 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000827 like_std = 2;
828 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000829
Rob Landleya3e4f382006-04-29 16:06:31 +0000830 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000831 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000832 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000833 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000834 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000835 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000836 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000837 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000838 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000839 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000840 kk = 1;
841 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
842 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000843 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000844 kk = 1;
845 printf("\n\tSupported: CD-ROM ATAPI");
846 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000847 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000848 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000849 jj >>= 1;
850 }
851 }
Denis Vlasenkofeb7ae72007-10-01 12:05:12 +0000852 puts(kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000853 /* the cdrom stuff is more like ATA-2 than anything else, so: */
854 like_std = 2;
855 }
856
Rob Landleya3e4f382006-04-29 16:06:31 +0000857 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000858 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000859
860 printf("Configuration:\n");
861 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000862 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000863 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000864 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000865 if (jj & 0x0001)
866 printf("\t%s\n", ata1_cfg_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000867 jj >>=1;
868 }
869 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000870 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000871 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
872 strng = "3ms";
873 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
874 strng = "<=10ms with INTRQ";
875 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
876 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000877 else
Rob Landleyadde7982006-05-16 15:32:30 +0000878 strng = "Unknown";
879 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
880
881 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
882 strng = "12 bytes";
883 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
884 strng = "16 bytes";
885 else
886 strng = "Unknown";
887 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000888 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000889 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000890 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
891 mm = 0; bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000892 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000893 printf("\tCHS addressing not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000894 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000895 jj = val[WHATS_VALID] & OK_W54_58;
Glenn L McGrath07085852003-10-09 07:28:22 +0000896 printf("\tLogical\t\tmax\tcurrent\n\tcylinders\t%u\t%u\n\theads\t\t%u\t%u\n\tsectors/track\t%u\t%u\n\t--\n",
897 val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
898
Rob Landleyadde7982006-05-16 15:32:30 +0000899 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000900 printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000901
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000902 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000903 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000904 if (like_std < 3) {
905 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000906 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
907 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000908 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +0000909 mm = oo;
910 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000911 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +0000912 }
Eric Andersen3443bd72003-07-22 07:30:36 +0000913 }
914 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000915 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000916 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
917 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
918 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000919 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
920 (uint64_t)val[LBA_48_MSB] << 32 |
921 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000922 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000923 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +0000924 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000925
926 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +0000927 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000928 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
929 bbbig = (bbbig << 9) / 1000000;
930 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +0000931
Rob Landleyadde7982006-05-16 15:32:30 +0000932 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +0000933 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000934 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000935 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000936 }
937
938 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +0000939 printf("Capabilities:\n\t");
940
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000941 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000942 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
943 if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +0000944 }
Rob Landleyadde7982006-05-16 15:32:30 +0000945 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +0000946
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000947 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000948 printf("IORDY%s(can%s be disabled)\n",
949 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
Rob Landleyadde7982006-05-16 15:32:30 +0000950 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000951 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000952 printf("no IORDY\n");
953
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000954 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000955 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000956 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
Rob Landleyadde7982006-05-16 15:32:30 +0000957 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000958 }
Rob Landleyadde7982006-05-16 15:32:30 +0000959
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000960 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000961 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +0000962 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000963 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000964 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000965 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000966 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000967 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +0000968 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000969
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000970 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000971 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000972 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000973 else {
Rob Landleyadde7982006-05-16 15:32:30 +0000974 printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +0000975 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000976 printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +0000977 else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000978 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +0000979 }
980 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000981 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Eric Andersen3443bd72003-07-22 07:30:36 +0000982 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000983 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000984 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +0000985 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
986 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
987 else
988 printf("?\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000989 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000990 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000991 /* We print out elsewhere whether the APM feature is enabled or
992 not. If it's not enabled, let's not repeat the info; just print
993 nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +0000994 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000995 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000996 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +0000997 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +0000998 }
999 else
Eric Andersen3443bd72003-07-22 07:30:36 +00001000 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001001 }
Rob Landleyadde7982006-05-16 15:32:30 +00001002 if (like_std > 5 && val[ACOUSTIC]) {
1003 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001004 (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +00001005 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001006 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +00001007 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +00001008 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
1009 printf("\tATA sw reset required\n");
Glenn L McGrath07085852003-10-09 07:28:22 +00001010
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001011 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001012 printf("\tOverlap support:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001013 if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
1014 if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001015 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001016 }
1017 }
1018
1019 /* DMA stuff. Check that only one DMA mode is selected. */
1020 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +00001021 if (!(val[CAPAB_0] & DMA_SUP))
Eric Andersen3443bd72003-07-22 07:30:36 +00001022 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001023 else {
Rob Landleyadde7982006-05-16 15:32:30 +00001024 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001025 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001026 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001027 jj = val[SINGLE_DMA];
1028 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001029 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001030 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001031 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001032 jj = val[MULTI_DMA];
1033 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001034 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001035 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001036 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001037 jj = val[ULTRA_DMA];
1038 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001039 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001040 }
Rob Landleyadde7982006-05-16 15:32:30 +00001041 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001042 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001043
Rob Landleyadde7982006-05-16 15:32:30 +00001044 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
1045 printf("\t\tInterleaved DMA support\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001046
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001047 if ((val[WHATS_VALID] & OK_W64_70)
1048 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
1049 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001050 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001051 if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
1052 if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001053 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001054 }
1055 }
1056
1057 /* Programmed IO stuff */
1058 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00001059 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +00001060 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001061 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001062 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001063 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001064 if (jj & 0x0001) printf("pio%d ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +00001065 jj >>=1;
1066 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001067 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001068 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001069 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001070 printf("pio%d ", ii);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001071 bb_putchar('\n');
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001072 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001073 printf("unknown\n");
1074
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001075 if (val[WHATS_VALID] & OK_W64_70) {
1076 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +00001077 printf("\t\tCycle time:");
1078 if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
1079 if (val[PIO_FLOW]) printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001080 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001081 }
1082 }
1083
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001084 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001085 printf("Commands/features:\n\tEnabled\tSupported:\n");
1086 jj = val[CMDS_SUPP_0];
1087 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001088 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
1089 if ((jj & 0x8000) && (*cmd_feat_str[ii] != '\0')) {
Rob Landleyadde7982006-05-16 15:32:30 +00001090 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", cmd_feat_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001091 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001092 jj <<= 1;
1093 kk <<= 1;
1094 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001095 jj = val[CMDS_SUPP_0+1+(ii/16)];
1096 kk = val[CMDS_EN_0+1+(ii/16)];
1097 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001098 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +00001099 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +00001100 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +00001101 }
1102 }
1103 }
Rob Landleyadde7982006-05-16 15:32:30 +00001104 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001105 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Rob Landleyadde7982006-05-16 15:32:30 +00001106 printf("\t%s supported\n", cmd_feat_str[27]);
Glenn L McGrath07085852003-10-09 07:28:22 +00001107
Eric Andersen3443bd72003-07-22 07:30:36 +00001108 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001109 if ((eqpt != CDROM) && (like_std > 3)
1110 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1111 ) {
Rob Landleyade7f952006-05-25 18:53:06 +00001112 printf("Security:\n");
Rob Landleyadde7982006-05-16 15:32:30 +00001113 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001114 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001115 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001116 if (jj) {
1117 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001118 printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "", secu_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +00001119 jj >>=1;
1120 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001121 if (val[SECU_STATUS] & SECU_ENABLED) {
Rob Landleyadde7982006-05-16 15:32:30 +00001122 printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +00001123 }
1124 }
1125 jj = val[ERASE_TIME] & ERASE_BITS;
1126 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001127 if (jj || kk) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001128 printf("\t");
Rob Landleyade7f952006-05-25 18:53:06 +00001129 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
1130 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenko4daad902007-09-27 10:20:47 +00001131 bb_putchar('\n');
Eric Andersen3443bd72003-07-22 07:30:36 +00001132 }
1133 }
1134
1135 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +00001136 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001137 if ((jj & VALID) == VALID_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001138 if (!(oo = (jj & RST0)))
1139 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +00001140 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001141 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +00001142 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +00001143 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001144 else
Rob Landleyadde7982006-05-16 15:32:30 +00001145 strng = "";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001146 printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
Rob Landleyadde7982006-05-16 15:32:30 +00001147 (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001148 }
1149
1150 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001151 if ((like_std > 4) && (eqpt != CDROM)) {
1152 if (val[CFA_PWR_MODE] & VALID_W160) {
Rob Landleyadde7982006-05-16 15:32:30 +00001153 printf("CFA power mode 1:\n\t%s%s\n", (val[CFA_PWR_MODE] & PWR_MODE_OFF) ? "disabled" : "enabled",
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001154 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Glenn L McGrath07085852003-10-09 07:28:22 +00001155
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001156 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001157 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001158 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001159 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001160 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001161 }
1162 }
1163
Rob Landleyadde7982006-05-16 15:32:30 +00001164 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001165}
1166#endif
1167
Eric Andersen3443bd72003-07-22 07:30:36 +00001168// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1169// then the HDIO_GET_IDENTITY only returned 142 bytes.
1170// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1171// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1172// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1173// (which they should, but they should just return -EINVAL).
1174//
1175// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1176// On a really old system, it will not, and we will be confused.
1177// Too bad, really.
1178
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001179#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001180static const char *const cfg_str[] = {
1181 "", "HardSect", "SoftSect", "NotMFM",
Rob Landleyadde7982006-05-16 15:32:30 +00001182 "HdSw>15uSec", "SpinMotCtl", "Fixed", "Removeable",
1183 "DTR<=5Mbs", "DTR>5Mbs", "DTR>10Mbs", "RotSpdTol>.5%",
1184 "dStbOff", "TrkOff", "FmtGapReq", "nonMagnetic"
Eric Andersen3443bd72003-07-22 07:30:36 +00001185};
1186
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001187static const char *const BuffType[] = {
1188 "Unknown", "1Sect", "DualPort", "DualPortCache"
1189};
Eric Andersen3443bd72003-07-22 07:30:36 +00001190
Rob Landleya3e4f382006-04-29 16:06:31 +00001191static void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001192{
1193 int i;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001194 const unsigned short int *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001195
Glenn L McGrath07085852003-10-09 07:28:22 +00001196 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1197 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001198 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001199 if (id->config & (1<<i))
1200 printf(" %s", cfg_str[i]);
Rob Landleyadde7982006-05-16 15:32:30 +00001201 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001202 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Rob Landleyadde7982006-05-16 15:32:30 +00001203 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
Glenn L McGrath07085852003-10-09 07:28:22 +00001204 id->cyls, id->heads, id->sectors, id->track_bytes,
Rob Landleyadde7982006-05-16 15:32:30 +00001205 id->sector_bytes, id->ecc_bytes,
1206 id->buf_type, BuffType[(id->buf_type > 3) ? 0 : id->buf_type],
1207 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001208 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001209 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001210 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001211 printf("?%u?", id->multsect);
1212 else if (id->multsect)
1213 printf("%u", id->multsect);
1214 else
1215 printf("off");
1216 }
Denis Vlasenko4daad902007-09-27 10:20:47 +00001217 bb_putchar('\n');
Rob Landleyade7f952006-05-25 18:53:06 +00001218
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001219 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001220 printf(" (maybe):");
1221
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001222 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001223 id->cur_sectors,
1224 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001225 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1226 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001227 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001228
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001229 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001230 printf(", LBAsects=%u", id->lba_capacity);
1231
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001232 printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ? "on/off" : "yes" : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001233
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001234 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001235 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001236
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001237 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001238 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1239
1240 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001241 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001242 printf("pio0 ");
1243 if (id->tPIO >= 1) printf("pio1 ");
1244 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001245 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001246 if (id->field_valid & 2) {
Rob Landleyade7f952006-05-25 18:53:06 +00001247 if (id->eide_pio_modes & 1) printf("pio3 ");
1248 if (id->eide_pio_modes & 2) printf("pio4 ");
1249 if (id->eide_pio_modes &~3) printf("pio? ");
1250 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001251 if (id->capability & 1) {
1252 if (id->dma_1word | id->dma_mword) {
Rob Landleyade7f952006-05-25 18:53:06 +00001253 printf("\n DMA modes: ");
1254 if (id->dma_1word & 0x100) printf("*");
1255 if (id->dma_1word & 1) printf("sdma0 ");
1256 if (id->dma_1word & 0x200) printf("*");
1257 if (id->dma_1word & 2) printf("sdma1 ");
1258 if (id->dma_1word & 0x400) printf("*");
1259 if (id->dma_1word & 4) printf("sdma2 ");
1260 if (id->dma_1word & 0xf800) printf("*");
1261 if (id->dma_1word & 0xf8) printf("sdma? ");
1262 if (id->dma_mword & 0x100) printf("*");
1263 if (id->dma_mword & 1) printf("mdma0 ");
1264 if (id->dma_mword & 0x200) printf("*");
1265 if (id->dma_mword & 2) printf("mdma1 ");
1266 if (id->dma_mword & 0x400) printf("*");
1267 if (id->dma_mword & 4) printf("mdma2 ");
1268 if (id->dma_mword & 0xf800) printf("*");
1269 if (id->dma_mword & 0xf8) printf("mdma? ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001270 }
1271 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001272 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Rob Landleyade7f952006-05-25 18:53:06 +00001273 printf("\n UDMA modes: ");
1274 if (id->dma_ultra & 0x100) printf("*");
1275 if (id->dma_ultra & 0x001) printf("udma0 ");
1276 if (id->dma_ultra & 0x200) printf("*");
1277 if (id->dma_ultra & 0x002) printf("udma1 ");
1278 if (id->dma_ultra & 0x400) printf("*");
1279 if (id->dma_ultra & 0x004) printf("udma2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001280#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001281 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001282#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001283 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001284#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001285 if (id->dma_ultra & 0x0800) printf("*");
1286 if (id->dma_ultra & 0x0008) printf("udma3 ");
1287 if (id->dma_ultra & 0x1000) printf("*");
1288 if (id->dma_ultra & 0x0010) printf("udma4 ");
1289 if (id->dma_ultra & 0x2000) printf("*");
1290 if (id->dma_ultra & 0x0020) printf("udma5 ");
1291 if (id->dma_ultra & 0x4000) printf("*");
1292 if (id->dma_ultra & 0x0040) printf("udma6 ");
1293 if (id->dma_ultra & 0x8000) printf("*");
1294 if (id->dma_ultra & 0x0080) printf("udma7 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001295 }
1296 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001297 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001298 if (id_regs[83] & 8) {
1299 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001300 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001301 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001302 printf(": unknown setting");
1303 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001304 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001305 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001306 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001307 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001308#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001309 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1310 || (id->major_rev_num && id->minor_rev_num <= 31)
1311 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001312 printf("\n Drive conforms to: %s: ", (id->minor_rev_num <= 31) ? minor_str[id->minor_rev_num] : "Unknown");
Rob Landley026147a2006-04-17 22:29:13 +00001313 if (id->major_rev_num != 0x0000 && /* NOVAL_0 */
1314 id->major_rev_num != 0xFFFF) { /* NOVAL_1 */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001315 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001316 if (id->major_rev_num & (1<<i))
1317 printf(" ATA/ATAPI-%u", i);
1318 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001319 }
1320 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001321#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001322 printf("\n\n * current active mode\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001323}
1324#endif
1325
Denis Vlasenko892536f2007-09-27 10:23:34 +00001326static void flush_buffer_cache(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001327{
Rob Landleya3e4f382006-04-29 16:06:31 +00001328 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001329 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001330#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001331 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001332 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1333 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1334 bb_perror_msg("HDIO_DRIVE_CMD");
1335 else
1336 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1337 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001338#endif
1339}
1340
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001341static void seek_to_zero(/*int fd*/ void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001342{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001343 xlseek(fd, (off_t) 0, SEEK_SET);
Eric Andersen3443bd72003-07-22 07:30:36 +00001344}
1345
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001346static void read_big_block(/*int fd,*/ char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001347{
Rob Landleyadde7982006-05-16 15:32:30 +00001348 int i;
1349
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001350 xread(fd, buf, TIMING_BUF_BYTES);
Eric Andersen3443bd72003-07-22 07:30:36 +00001351 /* access all sectors of buf to ensure the read fully completed */
1352 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1353 buf[i] &= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001354}
1355
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001356static unsigned dev_size_mb(/*int fd*/ void)
Rob Landleyadde7982006-05-16 15:32:30 +00001357{
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001358 union {
1359 unsigned long long blksize64;
1360 unsigned blksize32;
1361 } u;
Rob Landleyadde7982006-05-16 15:32:30 +00001362
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001363 if (0 == ioctl(fd, BLKGETSIZE64, &u.blksize64)) { // bytes
1364 u.blksize64 /= (1024 * 1024);
1365 } else {
1366 xioctl(fd, BLKGETSIZE, &u.blksize32); // sectors
1367 u.blksize64 = u.blksize32 / (2 * 1024);
Rob Landleyadde7982006-05-16 15:32:30 +00001368 }
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001369 if (u.blksize64 > UINT_MAX)
1370 return UINT_MAX;
1371 return u.blksize64;
Rob Landleyadde7982006-05-16 15:32:30 +00001372}
Eric Andersen50af12d2003-08-06 08:47:59 +00001373
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001374static void print_timing(unsigned m, unsigned elapsed_us)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001375{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001376 unsigned sec = elapsed_us / 1000000;
1377 unsigned hs = (elapsed_us % 1000000) / 10000;
1378
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001379 printf("%5u MB in %u.%02u seconds = %u kB/s\n",
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001380 m, sec, hs,
Denis Vlasenko0afdfdf2007-09-28 13:41:41 +00001381 /* "| 1" prevents div-by-0 */
1382 (unsigned) ((unsigned long long)m * (1024 * 1000000) / (elapsed_us | 1))
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001383 // ~= (m * 1024) / (elapsed_us / 1000000)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001384 // = kb / elapsed_sec
1385 );
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001386}
1387
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001388static void do_time(int cache /*,int fd*/)
1389/* cache=1: time cache: repeatedly read N MB at offset 0
1390 * cache=0: time device: linear read, starting at offset 0
1391 */
Eric Andersen3443bd72003-07-22 07:30:36 +00001392{
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001393 unsigned max_iterations, iterations;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001394 unsigned start; /* doesn't need to be long long */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001395 unsigned elapsed, elapsed2;
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001396 unsigned total_MB;
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001397 char *buf = xmalloc(TIMING_BUF_BYTES);
Rob Landley4ae2f512006-05-19 17:24:26 +00001398
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001399 if (mlock(buf, TIMING_BUF_BYTES))
1400 bb_perror_msg_and_die("mlock");
Rob Landleyadde7982006-05-16 15:32:30 +00001401
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001402 /* Clear out the device request queues & give them time to complete.
1403 * NB: *small* delay. User is expected to have a clue and to not run
1404 * heavy io in parallel with measurements. */
Rob Landleyadde7982006-05-16 15:32:30 +00001405 sync();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001406 sleep(1);
1407 if (cache) { /* Time cache */
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001408 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001409 read_big_block(buf);
1410 printf("Timing buffer-cache reads: ");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001411 } else { /* Time device */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001412 printf("Timing buffered disk reads:");
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001413 }
1414 fflush(stdout);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001415
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001416 /* Now do the timing */
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001417 iterations = 0;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001418 /* Max time to run (small for cache, avoids getting
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001419 * huge total_MB which can overlow unsigned type) */
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001420 elapsed2 = 510000; /* cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001421 max_iterations = UINT_MAX;
1422 if (!cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001423 elapsed2 = 3000000; /* not cache */
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001424 /* Don't want to read past the end! */
1425 max_iterations = dev_size_mb() / TIMING_BUF_MB;
1426 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001427 start = monotonic_us();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001428 do {
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001429 if (cache)
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001430 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001431 read_big_block(buf);
1432 elapsed = (unsigned)monotonic_us() - start;
1433 ++iterations;
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001434 } while (elapsed < elapsed2 && iterations < max_iterations);
Denis Vlasenko920c52a2007-09-28 13:38:08 +00001435 total_MB = iterations * TIMING_BUF_MB;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001436 //printf(" elapsed:%u iterations:%u ", elapsed, iterations);
1437 if (cache) {
Denis Vlasenkoa7bc9ac2007-09-28 11:21:47 +00001438 /* Cache: remove lseek() and monotonic_us() overheads
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001439 * from elapsed */
1440 start = monotonic_us();
Rob Landleyadde7982006-05-16 15:32:30 +00001441 do {
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001442 seek_to_zero();
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001443 elapsed2 = (unsigned)monotonic_us() - start;
Rob Landleyadde7982006-05-16 15:32:30 +00001444 } while (--iterations);
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001445 //printf(" elapsed2:%u ", elapsed2);
Rob Landleyadde7982006-05-16 15:32:30 +00001446 elapsed -= elapsed2;
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001447 total_MB *= 2; // BUFCACHE_FACTOR (why?)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001448 flush_buffer_cache();
Glenn L McGrath07085852003-10-09 07:28:22 +00001449 }
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001450 print_timing(total_MB, elapsed);
Rob Landley4ae2f512006-05-19 17:24:26 +00001451 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001452 free(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001453}
1454
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001455#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001456static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001457{
Rob Landleyadde7982006-05-16 15:32:30 +00001458 if (value == BUSSTATE_ON)
1459 on_off(1);
1460 else if (value == BUSSTATE_OFF)
1461 on_off(0);
1462 else if (value == BUSSTATE_TRISTATE)
1463 printf(" (tristate)\n");
1464 else
1465 printf(" (unknown: %d)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001466}
1467#endif
1468
1469#ifdef HDIO_DRIVE_CMD
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001470static void interpret_standby(unsigned standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001471{
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001472 unsigned t;
Rob Landleyadde7982006-05-16 15:32:30 +00001473
Rob Landley403777f2006-08-03 20:22:37 +00001474 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001475 if (standby == 0)
1476 printf("off");
1477 else if (standby == 252)
1478 printf("21 minutes");
1479 else if (standby == 253)
1480 printf("vendor-specific");
1481 else if (standby == 254)
1482 printf("Reserved");
1483 else if (standby == 255)
1484 printf("21 minutes + 15 seconds");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001485 else if (standby <= 240) {
1486 t = standby * 5;
1487 printf("%u minutes + %u seconds", t / 60, t % 60);
1488 } else if (standby <= 251) {
1489 t = (standby - 240) * 30;
1490 printf("%u hours + %u minutes", t / 60, t % 60);
1491 } else
1492 printf("illegal value");
Eric Andersen3443bd72003-07-22 07:30:36 +00001493 printf(")\n");
1494}
1495
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001496static const uint8_t xfermode_val[] ALIGN1 = {
1497 8, 9, 10, 11, 12, 13, 14, 15,
1498 16, 17, 18, 19, 20, 21, 22, 23,
1499 32, 33, 34, 35, 36, 37, 38, 39,
1500 64, 65, 66, 67, 68, 69, 70, 71
1501};
1502/* NB: we save size by _not_ storing terninating NUL! */
1503static const char xfermode_name[][5] ALIGN1 = {
1504 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1505 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1506 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1507 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001508};
1509
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001510static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001511{
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001512 int val, i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001513
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001514 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1515 if (!strncmp(name, xfermode_name[i], 5))
1516 if (strlen(name) <= 5)
1517 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001518 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001519 /* Negative numbers are invalid and are caught later */
1520 val = bb_strtoi(name, NULL, 10);
1521 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001522 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001523 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001524}
1525
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001526static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001527{
1528 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001529 if (xfermode == 0)
1530 printf("default PIO mode");
1531 else if (xfermode == 1)
1532 printf("default PIO mode, disable IORDY");
1533 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001534 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001535 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001536 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001537 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001538 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001539 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001540 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001541 else
1542 printf("Unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +00001543 printf(")\n");
1544}
1545#endif /* HDIO_DRIVE_CMD */
1546
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001547static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001548{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001549 if (flag)
Rob Landleyadde7982006-05-16 15:32:30 +00001550 printf(" setting %s to %ld\n", s, value);
1551}
1552
Rob Landleya3e4f382006-04-29 16:06:31 +00001553static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001554{
Denis Vlasenko892536f2007-09-27 10:23:34 +00001555 /*int fd;*/
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001556 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001557#ifndef HDIO_DRIVE_CMD
1558 int force_operation = 0;
1559#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001560 /* Please restore args[n] to these values after each ioctl
1561 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001562 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001563 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001564
Denis Vlasenko892536f2007-09-27 10:23:34 +00001565 /*fd = xopen(devname, O_RDONLY | O_NONBLOCK);*/
1566 xmove_fd(xopen(devname, O_RDONLY | O_NONBLOCK), fd);
Rob Landleyade7f952006-05-25 18:53:06 +00001567 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001568
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001569 if (set_readahead) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001570 print_flag(get_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001571 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001572 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001573#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1574 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001575 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001576 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001577 }
1578#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001579#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
1580 if (scan_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001581 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001582 args[0] = hwif_data;
1583 args[1] = hwif_ctrl;
1584 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001585 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001586 args[0] = WIN_SETFEATURES;
1587 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001588 }
1589#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001590 if (set_piomode) {
1591 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001592 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001593 if (piomode == 255)
Glenn L McGrath07085852003-10-09 07:28:22 +00001594 printf("auto-tune PIO mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001595 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001596 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001597 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001598 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001599 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001600 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001601 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001602 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001603 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001604 if (set_io32bit) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001605 print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001606 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001607 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001608 if (set_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001609 print_flag(get_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001610#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001611 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001612#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001613 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001614#endif
1615 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001616 if (set_readonly) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001617 print_flag_on_off(get_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001618 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001619 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001620 if (set_unmask) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001621 print_flag_on_off(get_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001622 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001623 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001624#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1625 if (set_dma) {
Rob Landleyadde7982006-05-16 15:32:30 +00001626 print_flag_on_off(get_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001627 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001628 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001629#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
1630 if (set_dma_q) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001631 print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001632 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001633 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001634 if (set_nowerr) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001635 print_flag_on_off(get_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001636 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001637 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001638 if (set_keep) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001639 print_flag_on_off(get_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001640 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001641 }
1642#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001643 if (set_doorlock) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001644 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001645 args[2] = 0;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001646 print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001647 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001648 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001649 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001650 if (set_dkeep) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001651 /* lock/unlock the drive's "feature" settings */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001652 print_flag_on_off(get_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001653 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001654 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001655 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001656 if (set_defects) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001657 args[2] = defects ? 0x04 : 0x84;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001658 print_flag(get_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001659 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001660 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001661 if (set_prefetch) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001662 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001663 args[2] = 0xab;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001664 print_flag(get_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001665 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001666 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001667 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001668 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001669 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001670 args[2] = 3;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001671 if (get_xfermode) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001672 print_flag(1, "xfermode", xfermode_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001673 interpret_xfermode(xfermode_requested);
1674 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001675 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001676 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001677 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001678 if (set_lookahead) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001679 args[2] = lookahead ? 0xaa : 0x55;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001680 print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001681 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001682 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001683 if (set_apmmode) {
Rob Landleyadde7982006-05-16 15:32:30 +00001684 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
1685 args[1] = apmmode; /* sector count register 1-255 */
1686 if (get_apmmode)
1687 printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001688 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001689 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001690 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001691 if (set_wcache) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001692#ifdef DO_FLUSHCACHE
1693#ifndef WIN_FLUSHCACHE
1694#define WIN_FLUSHCACHE 0xe7
1695#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001696#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001697 args[2] = wcache ? 0x02 : 0x82;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001698 print_flag_on_off(get_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001699#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001700 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001701 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001702#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001703 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001704#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001705 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001706 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001707#endif /* DO_FLUSHCACHE */
1708 }
Rob Landley39cf6452006-05-05 16:52:28 +00001709
1710 /* In code below, we do not preserve args[0], but the rest
1711 is preserved, including args[2] */
1712 args[2] = 0;
1713
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001714 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001715#ifndef WIN_STANDBYNOW1
1716#define WIN_STANDBYNOW1 0xE0
1717#endif
1718#ifndef WIN_STANDBYNOW2
1719#define WIN_STANDBYNOW2 0x94
1720#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001721 if (get_standbynow) printf(" issuing standby command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001722 args[0] = WIN_STANDBYNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001723 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001724 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001725 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001726#ifndef WIN_SLEEPNOW1
1727#define WIN_SLEEPNOW1 0xE6
1728#endif
1729#ifndef WIN_SLEEPNOW2
1730#define WIN_SLEEPNOW2 0x99
1731#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001732 if (get_sleepnow) printf(" issuing sleep command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001733 args[0] = WIN_SLEEPNOW1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001734 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001735 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001736 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001737 args[0] = 0xfb;
Rob Landleyadde7982006-05-16 15:32:30 +00001738 if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001739 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001740 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001741 if (set_standby) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001742 args[0] = WIN_SETIDLE1;
1743 args[1] = standby_requested;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001744 if (get_standby) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001745 print_flag(1, "standby", standby_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001746 interpret_standby(standby_requested);
1747 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001748 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001749 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001750 }
1751#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001752 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001753 char buf[512];
Denis Vlasenko892536f2007-09-27 10:23:34 +00001754 flush_buffer_cache();
Eric Andersen3443bd72003-07-22 07:30:36 +00001755 if (-1 == read(fd, buf, sizeof(buf)))
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001756 bb_perror_msg("read(%d bytes) failed (rc=-1)", sizeof(buf));
Eric Andersen3443bd72003-07-22 07:30:36 +00001757 }
1758#endif /* HDIO_DRIVE_CMD */
1759
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001760 if (get_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001761 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001762 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001763 if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
Eric Andersen06d4ec22004-03-19 10:53:52 +00001764 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001765 else
1766 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001767 } else if (get_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001768 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001769 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001770 }
1771 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001772 if (get_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001773 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001774 printf(" IO_support\t=%3ld (", parm);
1775 if (parm == 0)
1776 printf("default 16-bit)\n");
1777 else if (parm == 2)
1778 printf("16-bit)\n");
1779 else if (parm == 1)
1780 printf("32-bit)\n");
1781 else if (parm == 3)
1782 printf("32-bit w/sync)\n");
1783 else if (parm == 8)
1784 printf("Request-Queue-Bypass)\n");
1785 else
1786 printf("\?\?\?)\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001787 }
1788 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001789 if (get_unmask) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001790 if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, (unsigned long *)parm))
1791 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001792 }
1793
Glenn L McGrath07085852003-10-09 07:28:22 +00001794
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001795#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Rob Landleyade7f952006-05-25 18:53:06 +00001796 if (get_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001797 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001798 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001799 if (parm == 8)
1800 printf(" (DMA-Assisted-PIO)\n");
1801 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001802 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001803 }
1804 }
1805#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001806 if (get_dma_q) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001807 if(!ioctl_or_warn(fd, HDIO_GET_QDMA, (unsigned long *)parm))
1808 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001809 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001810 if (get_keep) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001811 if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, (unsigned long *)parm))
1812 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001813 }
1814
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001815 if (get_nowerr) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001816 if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, (unsigned long *)parm))
1817 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001818 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001819 if (get_readonly) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001820 if(!ioctl_or_warn(fd, BLKROGET, (unsigned long *)parm))
1821 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001822 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001823 if (get_readahead) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001824 if(!ioctl_or_warn(fd, BLKRAGET, (unsigned long *)parm))
1825 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001826 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001827 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001828 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001829 struct hd_geometry g;
1830
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001831 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001832 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Rob Landley2584e9b2006-05-03 20:00:00 +00001833 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001834 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001835 }
1836#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001837 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001838#ifndef WIN_CHECKPOWERMODE1
1839#define WIN_CHECKPOWERMODE1 0xE5
1840#endif
1841#ifndef WIN_CHECKPOWERMODE2
1842#define WIN_CHECKPOWERMODE2 0x98
1843#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001844 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001845
Rob Landleye5b281f2006-04-29 15:49:18 +00001846 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001847 if (ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001848 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001849 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001850 else
1851 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001852 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001853 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001854 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001855
Eric Andersen3443bd72003-07-22 07:30:36 +00001856 printf(" drive state is: %s\n", state);
1857 }
1858#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001859#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1860 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001861 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001862 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001863#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1864#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1865 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001866 args[0] = 0;
1867 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001868 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001869 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001870#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1871#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1872 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001873 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001874
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001875 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1876 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001877 id.multsect = multcount;
1878 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001879 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001880 id.multsect_valid &= ~1;
1881 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001882 } else if (errno == -ENOMSG)
Eric Andersen3443bd72003-07-22 07:30:36 +00001883 printf(" no identification info available\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001884 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001885 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001886 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001887 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001888 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001889
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001890 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001891 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001892
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001893 memset(args1, 0, sizeof(args1));
1894 args1[0] = WIN_IDENTIFY;
1895 args1[3] = 1;
Denis Vlasenko892536f2007-09-27 10:23:34 +00001896 if (!ioctl_alt_or_warn(HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001897 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00001898 }
1899#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001900#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1901 if (set_busstate) {
1902 if (get_busstate) {
Rob Landleyadde7982006-05-16 15:32:30 +00001903 print_flag(1, "bus state", busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001904 bus_state_value(busstate);
1905 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001906 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001907 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001908 if (get_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001909 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001910 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001911 bus_state_value(parm);
1912 }
1913 }
1914#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00001915 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001916 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00001917
Eric Andersen3443bd72003-07-22 07:30:36 +00001918 if (do_ctimings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001919 do_time(1 /*,fd*/); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00001920 if (do_timings)
Denis Vlasenkoc3122bc2007-09-28 10:28:03 +00001921 do_time(0 /*,fd*/); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001922 if (do_flush)
Denis Vlasenko892536f2007-09-27 10:23:34 +00001923 flush_buffer_cache();
Rob Landleya3e4f382006-04-29 16:06:31 +00001924 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00001925}
1926
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001927#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00001928static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00001929{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001930 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00001931 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001932 if (c >= 'a' && c <= 'f')
1933 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00001934 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1935}
1936
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001937static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
Rob Landley0f0b6452006-05-03 18:28:06 +00001938static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001939{
Rob Landley0753f4a2006-06-07 00:27:25 +00001940 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001941 unsigned char buf[1280];
1942 unsigned char *b = (unsigned char *)buf;
1943 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001944
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001945 xread(0, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00001946
Rob Landley0753f4a2006-06-07 00:27:25 +00001947 // Convert the newline-separated hex data into an identify block.
1948
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001949 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00001950 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001951 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001952 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00001953 }
Rob Landley0753f4a2006-06-07 00:27:25 +00001954
1955 // Parse the data.
1956
Rob Landley6389ff12006-05-01 19:28:53 +00001957 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001958}
Denis Vlasenko0d3c6af2007-09-28 10:25:32 +00001959#else
1960void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +00001961#endif
1962
Rob Landley20deab02006-05-07 23:34:15 +00001963/* busybox specific stuff */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001964static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00001965{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001966 if (get) {
1967 *get = 1;
1968 }
1969 if (optarg) {
1970 *set = 1;
Denis Vlasenko13858992006-10-08 12:49:22 +00001971 *value = xatol_range(optarg, min, max);
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001972 }
Rob Landley20deab02006-05-07 23:34:15 +00001973}
1974
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001975static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00001976{
1977 if (flag) {
Rob Landleyade7f952006-05-25 18:53:06 +00001978 *get = 1;
Rob Landley20deab02006-05-07 23:34:15 +00001979 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001980 *value = translate_xfermode(optarg);
1981 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00001982 }
1983 }
1984}
1985
Rob Landley06208412006-05-31 22:52:57 +00001986/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001987static const char hdparm_options[] ALIGN1 =
Denis Vlasenko4daad902007-09-27 10:20:47 +00001988 "gfu::n::p:r::m::c::k::a::B:tT"
Rob Landley06208412006-05-31 22:52:57 +00001989 USE_FEATURE_HDPARM_GET_IDENTITY("iI")
Rob Landley20deab02006-05-07 23:34:15 +00001990 USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
1991#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001992 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00001993#endif
1994 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
1995#ifdef HDIO_GET_QDMA
1996#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001997 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00001998#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001999 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00002000#endif
2001#endif
2002 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
2003 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
2004 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
2005/*-------------------------------------*/
2006
2007/* our main() routine: */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002008int hdparm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landley20deab02006-05-07 23:34:15 +00002009int hdparm_main(int argc, char **argv)
2010{
2011 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00002012 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00002013
Rob Landley06208412006-05-31 22:52:57 +00002014 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00002015 flagcount++;
Mike Frysingerea93f8a2006-06-07 14:25:22 +00002016 USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
2017 USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00002018 get_geom |= (c == 'g');
2019 do_flush |= (c == 'f');
Rob Landley19802562006-05-08 15:35:46 +00002020 if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
2021 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
2022 if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002023 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Rob Landley19802562006-05-08 15:35:46 +00002024 if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
2025 if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
2026 if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
2027 if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
2028 if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
2029 if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00002030 do_flush |= do_timings |= (c == 't');
2031 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00002032#ifdef HDIO_DRIVE_CMD
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002033 if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, INT_MAX);
Rob Landley19802562006-05-08 15:35:46 +00002034 if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
2035 if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
Rob Landleyade7f952006-05-25 18:53:06 +00002036 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Rob Landley19802562006-05-08 15:35:46 +00002037 if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
2038 if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
2039 if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
2040 if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
Rob Landleyade7f952006-05-25 18:53:06 +00002041 get_powermode |= (c == 'C');
2042 get_standbynow = set_standbynow |= (c == 'y');
2043 get_sleepnow = set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00002044 reread_partn |= (c == 'z');
Rob Landleyade7f952006-05-25 18:53:06 +00002045 get_seagate = set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00002046#endif
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002047 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
Rob Landley20deab02006-05-07 23:34:15 +00002048#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002049 if (c == 'Q') {
Rob Landley20deab02006-05-07 23:34:15 +00002050#ifdef HDIO_SET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00002051 parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00002052#else
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002053 parse_opts(&get_dma_q, NULL, NULL, 0, 0);
Rob Landley20deab02006-05-07 23:34:15 +00002054#endif
Rob Landley19802562006-05-08 15:35:46 +00002055 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002056#endif
Rob Landleyade7f952006-05-25 18:53:06 +00002057 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002058 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
2059 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
Rob Landley20deab02006-05-07 23:34:15 +00002060#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
2061 if (c == 'R') {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002062 parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
Denis Vlasenko13858992006-10-08 12:49:22 +00002063 hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
2064 hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00002065 /* Move past the 2 additional arguments */
2066 argv += 2;
2067 argc -= 2;
2068 }
2069#endif
2070 }
Rob Landleyade7f952006-05-25 18:53:06 +00002071 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002072 if (!flagcount) {
Rob Landleyade7f952006-05-25 18:53:06 +00002073 get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
2074 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
2075 }
Rob Landley20deab02006-05-07 23:34:15 +00002076 argv += optind;
2077
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002078 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002079 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2080 identify_from_stdin(); /* EXIT */
Denis Vlasenko4daad902007-09-27 10:20:47 +00002081 bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002082 }
2083
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002084 do {
2085 process_dev(*argv++);
2086 } while (*argv);
2087
2088 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002089}