blob: b3c24083534122075a115f4c639d9e46dbeacdfd [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};
Rob Landley0f0b6452006-05-03 18:28:06 +0000382
383static void identify(uint16_t *id_supplied) ATTRIBUTE_NORETURN;
384static void identify_from_stdin(void) ATTRIBUTE_NORETURN;
Rob Landley9c6f9552006-06-08 14:11:36 +0000385#else
386void identify_from_stdin(void);
Eric Andersen3443bd72003-07-22 07:30:36 +0000387#endif
388
389
390/* words 85-87: cmds/feats enabled */
391/* use cmd_feat_str[] to display what commands and features have
Glenn L McGrath07085852003-10-09 07:28:22 +0000392 * been enabled with words 85-87
Eric Andersen3443bd72003-07-22 07:30:36 +0000393 */
394
395/* words 89, 90, SECU ERASE TIME */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000396#define ERASE_BITS 0x00ff
Eric Andersen3443bd72003-07-22 07:30:36 +0000397
398/* word 92: master password revision */
399/* NOVAL_0 or NOVAL_1 means no support for master password revision */
400
401/* word 93: hw reset result */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000402#define CBLID 0x2000 /* CBLID status */
403#define RST0 0x0001 /* 1=reset to device #0 */
404#define DEV_DET 0x0006 /* how device num determined */
405#define JUMPER_VAL 0x0002 /* device num determined by jumper */
406#define CSEL_VAL 0x0004 /* device num determined by CSEL_VAL */
Eric Andersen3443bd72003-07-22 07:30:36 +0000407
408/* word 127: removable media status notification feature set support */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000409#define RM_STAT_BITS 0x0003
410#define RM_STAT_SUP 0x0001
Glenn L McGrath07085852003-10-09 07:28:22 +0000411
Eric Andersen3443bd72003-07-22 07:30:36 +0000412/* word 128: security */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000413#define SECU_ENABLED 0x0002
414#define SECU_LEVEL 0x0010
415#define NUM_SECU_STR 6
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000416#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000417static const char *const secu_str[] = {
Eric Andersen3443bd72003-07-22 07:30:36 +0000418 "supported", /* word 128, bit 0 */
419 "enabled", /* word 128, bit 1 */
420 "locked", /* word 128, bit 2 */
421 "frozen", /* word 128, bit 3 */
422 "expired: security count", /* word 128, bit 4 */
423 "supported: enhanced erase" /* word 128, bit 5 */
424};
425#endif
426
427/* word 160: CFA power mode */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000428#define VALID_W160 0x8000 /* 1=word valid */
429#define PWR_MODE_REQ 0x2000 /* 1=CFA power mode req'd by some cmds*/
430#define PWR_MODE_OFF 0x1000 /* 1=CFA power moded disabled */
431#define MAX_AMPS 0x0fff /* value = max current in ma */
Eric Andersen3443bd72003-07-22 07:30:36 +0000432
433/* word 255: integrity */
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000434#define SIG 0x00ff /* signature location */
435#define SIG_VAL 0x00a5 /* signature value */
Eric Andersen3443bd72003-07-22 07:30:36 +0000436
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000437#define TIMING_MB 64
438#define TIMING_BUF_MB 1
439#define TIMING_BUF_BYTES (TIMING_BUF_MB * 1024 * 1024)
440#define BUFCACHE_FACTOR 2
Glenn L McGrath07085852003-10-09 07:28:22 +0000441
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000442#undef DO_FLUSHCACHE /* under construction: force cache flush on -W0 */
Glenn L McGrath07085852003-10-09 07:28:22 +0000443
444/* Busybox messages and functions */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000445#if ENABLE_IOCTL_HEX2STR_ERROR
446static int ioctl_alt_func(int fd, int cmd, unsigned char *args, int alt, const char *string)
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000447{
448 if (!ioctl(fd, cmd, args))
449 return 0;
450 args[0] = alt;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000451 return bb_ioctl_or_warn(fd, cmd, args, string);
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000452}
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000453#define ioctl_alt_or_warn(fd,cmd,args,alt) ioctl_alt_func(fd,cmd,args,alt,#cmd)
454#else
455static int ioctl_alt_func(int fd, int cmd, unsigned char *args, int alt)
456{
457 if (!ioctl(fd, cmd, args))
458 return 0;
459 args[0] = alt;
460 return bb_ioctl_or_warn(fd, cmd, args);
461}
462#define ioctl_alt_or_warn(fd,cmd,args,alt) ioctl_alt_func(fd,cmd,args,alt)
463#endif
Rob Landley5f8b5ec2006-04-29 16:03:40 +0000464
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000465static void on_off(int value)
466{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000467 puts(value ? " (on)" : " (off)");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000468}
Glenn L McGrath07085852003-10-09 07:28:22 +0000469
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000470static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
Glenn L McGrath07085852003-10-09 07:28:22 +0000471{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000472 if (get_arg) {
Rob Landleyadde7982006-05-16 15:32:30 +0000473 printf(" setting %s to %ld", s, arg);
Glenn L McGrath07085852003-10-09 07:28:22 +0000474 on_off(arg);
475 }
476}
477
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000478static void print_value_on_off(const char *str, unsigned long argp)
Glenn L McGrath07085852003-10-09 07:28:22 +0000479{
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +0000480 printf(" %s\t= %2ld", str, argp);
481 on_off(argp != 0);
Glenn L McGrath07085852003-10-09 07:28:22 +0000482}
Eric Andersen416c2422003-12-12 00:08:57 +0000483
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000484#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Glenn L McGrath07085852003-10-09 07:28:22 +0000485static void print_ascii(uint16_t *p, uint8_t length);
486
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000487static void xprint_ascii(uint16_t *val, int i, const char *string, int n)
Glenn L McGrath07085852003-10-09 07:28:22 +0000488{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000489 if (val[i]) {
490 printf("\t%-20s", string);
Glenn L McGrath07085852003-10-09 07:28:22 +0000491 print_ascii(&val[i], n);
492 }
493}
Eric Andersen416c2422003-12-12 00:08:57 +0000494#endif
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000495/* end of busybox specific stuff */
Glenn L McGrath07085852003-10-09 07:28:22 +0000496
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000497#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Glenn L McGrath07085852003-10-09 07:28:22 +0000498static uint8_t mode_loop(uint16_t mode_sup, uint16_t mode_sel, int cc, uint8_t *have_mode)
499{
Eric Andersen3443bd72003-07-22 07:30:36 +0000500 uint16_t ii;
501 uint8_t err_dma = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +0000502
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000503 for (ii = 0; ii <= MODE_MAX; ii++) {
504 if (mode_sel & 0x0001) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000505 printf("*%cdma%u ", cc, ii);
Rob Landleya3e4f382006-04-29 16:06:31 +0000506 if (*have_mode)
Glenn L McGrath07085852003-10-09 07:28:22 +0000507 err_dma = 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000508 *have_mode = 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000509 } else if (mode_sup & 0x0001)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000510 printf("%cdma%u ", cc, ii);
Glenn L McGrath07085852003-10-09 07:28:22 +0000511
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000512 mode_sup >>= 1;
513 mode_sel >>= 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000514 }
515 return err_dma;
516}
Glenn L McGrath07085852003-10-09 07:28:22 +0000517
Denis Vlasenkoac678ec2007-04-16 22:32:04 +0000518static void print_ascii(uint16_t *p, uint8_t length)
519{
Eric Andersen3443bd72003-07-22 07:30:36 +0000520 uint8_t ii;
521 char cl;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000522
Eric Andersen3443bd72003-07-22 07:30:36 +0000523 /* find first non-space & print it */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000524 for (ii = 0; ii < length; ii++) {
525 if ((char)((*p)>>8) != ' ')
Glenn L McGrath07085852003-10-09 07:28:22 +0000526 break;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000527 cl = (char)(*p);
528 if (cl != ' ') {
529 if (cl != '\0')
530 printf("%c", cl);
Glenn L McGrath07085852003-10-09 07:28:22 +0000531 p++;
532 ii++;
Eric Andersen3443bd72003-07-22 07:30:36 +0000533 break;
534 }
535 p++;
536 }
537 /* print the rest */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000538 for (; ii< length; ii++) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000539 if (!(*p))
Glenn L McGrath07085852003-10-09 07:28:22 +0000540 break; /* some older devices have NULLs */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000541 printf("%c%c", (char)((*p)>>8), (char)(*p));
Eric Andersen3443bd72003-07-22 07:30:36 +0000542 p++;
543 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000544 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000545}
546
Rob Landley0753f4a2006-06-07 00:27:25 +0000547// Parse 512 byte disk identification block and print much crap.
548
Rob Landley6389ff12006-05-01 19:28:53 +0000549static void identify(uint16_t *id_supplied)
Eric Andersen3443bd72003-07-22 07:30:36 +0000550{
Rob Landley5bc3f052006-04-29 19:11:24 +0000551 uint16_t buf[256];
552 uint16_t *val, ii, jj, kk;
Eric Andersen3443bd72003-07-22 07:30:36 +0000553 uint16_t like_std = 1, std = 0, min_std = 0xffff;
554 uint16_t dev = NO_DEV, eqpt = NO_DEV;
555 uint8_t have_mode = 0, err_dma = 0;
556 uint8_t chksum = 0;
557 uint32_t ll, mm, nn, oo;
Rob Landley2e2d7522006-04-29 15:23:33 +0000558 uint64_t bbbig; /* (:) */
Rob Landleyadde7982006-05-16 15:32:30 +0000559 const char *strng;
Eric Andersen3443bd72003-07-22 07:30:36 +0000560
Rob Landley0753f4a2006-06-07 00:27:25 +0000561 // Adjust for endianness if necessary.
562
Rob Landley5bc3f052006-04-29 19:11:24 +0000563 if (BB_BIG_ENDIAN) {
564 swab(id_supplied, buf, sizeof(buf));
565 val = buf;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000566 } else
567 val = id_supplied;
Rob Landley5bc3f052006-04-29 19:11:24 +0000568
Eric Andersen3443bd72003-07-22 07:30:36 +0000569 chksum &= 0xff;
570
571 /* check if we recognise the device type */
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000572 puts("");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000573 if (!(val[GEN_CONFIG] & NOT_ATA)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000574 dev = ATA_DEV;
575 printf("ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000576 } else if (val[GEN_CONFIG]==CFA_SUPPORT_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000577 dev = ATA_DEV;
578 like_std = 4;
579 printf("CompactFlash ATA device, with ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000580 } else if (!(val[GEN_CONFIG] & NOT_ATAPI)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000581 dev = ATAPI_DEV;
582 eqpt = (val[GEN_CONFIG] & EQPT_TYPE) >> SHIFT_EQPT;
583 printf("ATAPI %s, with ", pkt_str[eqpt]);
584 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000585 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000586 /*"Unknown device type:\n\tbits 15&14 of general configuration word 0 both set to 1.\n"*/
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000587 bb_error_msg_and_die("unknown device type");
Eric Andersen3443bd72003-07-22 07:30:36 +0000588
Rob Landleyadde7982006-05-16 15:32:30 +0000589 printf("%sremovable media\n", !(val[GEN_CONFIG] & MEDIA_REMOVABLE) ? "non-" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000590 /* Info from the specific configuration word says whether or not the
591 * ID command completed correctly. It is only defined, however in
Glenn L McGrath07085852003-10-09 07:28:22 +0000592 * ATA/ATAPI-5 & 6; it is reserved (value theoretically 0) in prior
Eric Andersen3443bd72003-07-22 07:30:36 +0000593 * standards. Since the values allowed for this word are extremely
594 * specific, it should be safe to check it now, even though we don't
595 * know yet what standard this device is using.
596 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000597 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)
598 || (val[CONFIG]==PWRD_NID_VAL) || (val[CONFIG]==PWRD_ID_VAL)
599 ) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000600 like_std = 5;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000601 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
Rob Landleyadde7982006-05-16 15:32:30 +0000602 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n");
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000603 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
Rob Landleyadde7982006-05-16 15:32:30 +0000604 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000605 }
606
607 /* output the model and serial numbers and the fw revision */
Glenn L McGrath07085852003-10-09 07:28:22 +0000608 xprint_ascii(val, START_MODEL, "Model Number:", LENGTH_MODEL);
609 xprint_ascii(val, START_SERIAL, "Serial Number:", LENGTH_SERIAL);
610 xprint_ascii(val, START_FW_REV, "Firmware Revision:", LENGTH_FW_REV);
611 xprint_ascii(val, START_MEDIA, "Media Serial Num:", LENGTH_MEDIA);
612 xprint_ascii(val, START_MANUF, "Media Manufacturer:", LENGTH_MANUF);
Eric Andersen3443bd72003-07-22 07:30:36 +0000613
614 /* major & minor standards version number (Note: these words were not
615 * defined until ATA-3 & the CDROM std uses different words.) */
616 printf("Standards:");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000617 if (eqpt != CDROM) {
618 if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000619 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000620 std = actual_ver[val[MINOR]];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000621 if (std) printf("\n\tUsed: %s ", minor_str[val[MINOR]]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000622
Eric Andersen3443bd72003-07-22 07:30:36 +0000623 }
624 /* looks like when they up-issue the std, they obsolete one;
Glenn L McGrath07085852003-10-09 07:28:22 +0000625 * thus, only the newest 4 issues need be supported. (That's
Eric Andersen3443bd72003-07-22 07:30:36 +0000626 * what "kk" and "min_std" are all about.) */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000627 if (val[MAJOR] && (val[MAJOR] != NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000628 printf("\n\tSupported: ");
629 jj = val[MAJOR] << 1;
630 kk = like_std >4 ? like_std-4: 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000631 for (ii = 14; (ii >0)&&(ii>kk); ii--) {
632 if (jj & 0x8000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000633 printf("%u ", ii);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000634 if (like_std < ii) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000635 like_std = ii;
636 kk = like_std >4 ? like_std-4: 0;
637 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000638 if (min_std > ii) min_std = ii;
Eric Andersen3443bd72003-07-22 07:30:36 +0000639 }
640 jj <<= 1;
641 }
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000642 if (like_std < 3) like_std = 3;
Eric Andersen3443bd72003-07-22 07:30:36 +0000643 }
644 /* Figure out what standard the device is using if it hasn't told
645 * us. If we know the std, check if the device is using any of
646 * the words from the next level up. It happens.
647 */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000648 if (like_std < std) like_std = std;
Glenn L McGrath07085852003-10-09 07:28:22 +0000649
Rob Landleya3e4f382006-04-29 16:06:31 +0000650 if (((std == 5) || (!std && (like_std < 6))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000651 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
652 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x00ff)) ||
653 ((( val[CMDS_SUPP_2] & VALID) == VALID_VAL) &&
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000654 ( val[CMDS_SUPP_2] & CMDS_W84) ) )
655 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000656 like_std = 6;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000657 } else if (((std == 4) || (!std && (like_std < 5))) &&
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000658 ((((val[INTEGRITY] & SIG) == SIG_VAL) && !chksum) ||
Glenn L McGrath07085852003-10-09 07:28:22 +0000659 (( val[HWRST_RSLT] & VALID) == VALID_VAL) ||
660 ((( val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
661 (( val[CMDS_SUPP_1] & CMDS_W83) > 0x001f)) ) )
662 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000663 like_std = 5;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000664 } else if (((std == 3) || (!std && (like_std < 4))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000665 ((((val[CMDS_SUPP_1] & VALID) == VALID_VAL) &&
666 ((( val[CMDS_SUPP_1] & CMDS_W83) > 0x0000) ||
667 (( val[CMDS_SUPP_0] & CMDS_W82) > 0x000f))) ||
668 (( val[CAPAB_1] & VALID) == VALID_VAL) ||
669 (( val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) ||
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000670 (( val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP) )
671 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000672 like_std = 4;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000673 } else if (((std == 2) || (!std && (like_std < 3)))
674 && ((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
675 ) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000676 like_std = 3;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000677 } else if (((std == 1) || (!std && (like_std < 2))) &&
Glenn L McGrath07085852003-10-09 07:28:22 +0000678 ((val[CAPAB_0] & (IORDY_SUP | IORDY_OFF)) ||
679 (val[WHATS_VALID] & OK_W64_70)) )
680 {
Eric Andersen3443bd72003-07-22 07:30:36 +0000681 like_std = 2;
682 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000683
Rob Landleya3e4f382006-04-29 16:06:31 +0000684 if (!std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000685 printf("\n\tLikely used: %u\n", like_std);
Rob Landleya3e4f382006-04-29 16:06:31 +0000686 else if (like_std > std)
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000687 printf("& some of %u\n", like_std);
Glenn L McGrath07085852003-10-09 07:28:22 +0000688 else
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000689 puts("");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000690 } else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000691 /* TBD: do CDROM stuff more thoroughly. For now... */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000692 kk = 0;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000693 if (val[CDR_MINOR] == 9) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000694 kk = 1;
695 printf("\n\tUsed: ATAPI for CD-ROMs, SFF-8020i, r2.5");
696 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000697 if (val[CDR_MAJOR] && (val[CDR_MAJOR] !=NOVAL_1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000698 kk = 1;
699 printf("\n\tSupported: CD-ROM ATAPI");
700 jj = val[CDR_MAJOR] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000701 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000702 if (jj & 0x0001) printf("-%u ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000703 jj >>= 1;
704 }
705 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000706 printf("%s\n", kk ? "" : "\n\tLikely used CD-ROM ATAPI-1");
Eric Andersen3443bd72003-07-22 07:30:36 +0000707 /* the cdrom stuff is more like ATA-2 than anything else, so: */
708 like_std = 2;
709 }
710
Rob Landleya3e4f382006-04-29 16:06:31 +0000711 if (min_std == 0xffff)
Glenn L McGrath07085852003-10-09 07:28:22 +0000712 min_std = like_std > 4 ? like_std - 3 : 1;
Eric Andersen3443bd72003-07-22 07:30:36 +0000713
714 printf("Configuration:\n");
715 /* more info from the general configuration word */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000716 if ((eqpt != CDROM) && (like_std == 1)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000717 jj = val[GEN_CONFIG] >> 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000718 for (ii = 1; ii < 15; ii++) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000719 if (jj & 0x0001)
720 printf("\t%s\n", ata1_cfg_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000721 jj >>=1;
722 }
723 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000724 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000725 if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_3MS_VAL)
726 strng = "3ms";
727 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_INTR_VAL)
728 strng = "<=10ms with INTRQ";
729 else if ((val[GEN_CONFIG] & DRQ_RESPONSE_TIME) == DRQ_50US_VAL)
730 strng ="50us";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000731 else
Rob Landleyadde7982006-05-16 15:32:30 +0000732 strng = "Unknown";
733 printf("\tDRQ response: %s\n\tPacket size: ", strng); /* Data Request (DRQ) */
734
735 if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_12_VAL)
736 strng = "12 bytes";
737 else if ((val[GEN_CONFIG] & PKT_SIZE_SUPPORTED) == PKT_SIZE_16_VAL)
738 strng = "16 bytes";
739 else
740 strng = "Unknown";
741 puts(strng);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000742 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000743 /* addressing...CHS? See section 6.2 of ATA specs 4 or 5 */
Eric Andersen3443bd72003-07-22 07:30:36 +0000744 ll = (uint32_t)val[LBA_SECTS_MSB] << 16 | val[LBA_SECTS_LSB];
745 mm = 0; bbbig = 0;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000746 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000747 printf("\tCHS addressing not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000748 else {
Eric Andersen3443bd72003-07-22 07:30:36 +0000749 jj = val[WHATS_VALID] & OK_W54_58;
Glenn L McGrath07085852003-10-09 07:28:22 +0000750 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",
751 val[LCYLS],jj?val[LCYLS_CUR]:0, val[LHEADS],jj?val[LHEADS_CUR]:0, val[LSECTS],jj?val[LSECTS_CUR]:0);
752
Rob Landleyadde7982006-05-16 15:32:30 +0000753 if ((min_std == 1) && (val[TRACK_BYTES] || val[SECT_BYTES]))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000754 printf("\tbytes/track: %u\tbytes/sector: %u\n", val[TRACK_BYTES], val[SECT_BYTES]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000755
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000756 if (jj) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000757 mm = (uint32_t)val[CAPACITY_MSB] << 16 | val[CAPACITY_LSB];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000758 if (like_std < 3) {
759 /* check Endian of capacity bytes */
Eric Andersen3443bd72003-07-22 07:30:36 +0000760 nn = val[LCYLS_CUR] * val[LHEADS_CUR] * val[LSECTS_CUR];
761 oo = (uint32_t)val[CAPACITY_LSB] << 16 | val[CAPACITY_MSB];
Rob Landleya3e4f382006-04-29 16:06:31 +0000762 if (abs(mm - nn) > abs(oo - nn))
Eric Andersen3443bd72003-07-22 07:30:36 +0000763 mm = oo;
764 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000765 printf("\tCHS current addressable sectors:%11u\n", mm);
Glenn L McGrath07085852003-10-09 07:28:22 +0000766 }
Eric Andersen3443bd72003-07-22 07:30:36 +0000767 }
768 /* LBA addressing */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000769 printf("\tLBA user addressable sectors:%11u\n", ll);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000770 if (((val[CMDS_SUPP_1] & VALID) == VALID_VAL)
771 && (val[CMDS_SUPP_1] & SUPPORT_48_BIT)
772 ) {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +0000773 bbbig = (uint64_t)val[LBA_64_MSB] << 48 |
774 (uint64_t)val[LBA_48_MSB] << 32 |
775 (uint64_t)val[LBA_MID] << 16 |
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000776 val[LBA_LSB];
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000777 printf("\tLBA48 user addressable sectors:%11"PRIu64"\n", bbbig);
Eric Andersen3443bd72003-07-22 07:30:36 +0000778 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000779
780 if (!bbbig)
Rob Landley2e2d7522006-04-29 15:23:33 +0000781 bbbig = (uint64_t)(ll>mm ? ll : mm); /* # 512 byte blocks */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000782 printf("\tdevice size with M = 1024*1024: %11"PRIu64" MBytes\n", bbbig>>11);
783 bbbig = (bbbig << 9) / 1000000;
784 printf("\tdevice size with M = 1000*1000: %11"PRIu64" MBytes ", bbbig);
Glenn L McGrath07085852003-10-09 07:28:22 +0000785
Rob Landleyadde7982006-05-16 15:32:30 +0000786 if (bbbig > 1000)
Rob Landley81dab2c2006-05-28 01:56:08 +0000787 printf("(%"PRIu64" GB)\n", bbbig/1000);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000788 else
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000789 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000790 }
791
792 /* hw support of commands (capabilities) */
Glenn L McGrath07085852003-10-09 07:28:22 +0000793 printf("Capabilities:\n\t");
794
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000795 if (dev == ATAPI_DEV) {
Rob Landleyadde7982006-05-16 15:32:30 +0000796 if (eqpt != CDROM && (val[CAPAB_0] & CMD_Q_SUP)) printf("Cmd queuing, ");
797 if (val[CAPAB_0] & OVLP_SUP) printf("Cmd overlap, ");
Eric Andersen3443bd72003-07-22 07:30:36 +0000798 }
Rob Landleyadde7982006-05-16 15:32:30 +0000799 if (val[CAPAB_0] & LBA_SUP) printf("LBA, ");
Glenn L McGrath07085852003-10-09 07:28:22 +0000800
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000801 if (like_std != 1) {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000802 printf("IORDY%s(can%s be disabled)\n",
803 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
Rob Landleyadde7982006-05-16 15:32:30 +0000804 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000805 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000806 printf("no IORDY\n");
807
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000808 if ((like_std == 1) && val[BUF_TYPE]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000809 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000810 (val[BUF_TYPE] < 2) ? "single port, single-sector" : "dual port, multi-sector",
Rob Landleyadde7982006-05-16 15:32:30 +0000811 (val[BUF_TYPE] > 2) ? " with read caching ability" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +0000812 }
Rob Landleyadde7982006-05-16 15:32:30 +0000813
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000814 if ((min_std == 1) && (val[BUFFER__SIZE] && (val[BUFFER__SIZE] != NOVAL_1))) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000815 printf("\tBuffer size: %.1fkB\n", (float)val[BUFFER__SIZE]/2);
Eric Andersen3443bd72003-07-22 07:30:36 +0000816 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000817 if ((min_std < 4) && (val[RW_LONG])) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000818 printf("\tbytes avail on r/w long: %u\n", val[RW_LONG]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000819 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000820 if ((eqpt != CDROM) && (like_std > 3)) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000821 printf("\tQueue depth: %u\n", (val[QUEUE_DEPTH] & DEPTH_BITS) + 1);
Eric Andersen3443bd72003-07-22 07:30:36 +0000822 }
Glenn L McGrath07085852003-10-09 07:28:22 +0000823
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000824 if (dev == ATA_DEV) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000825 if (like_std == 1)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000826 printf("\tCan%s perform double-word IO\n", (!val[DWORD_IO]) ? "not" : "");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000827 else {
Rob Landleyadde7982006-05-16 15:32:30 +0000828 printf("\tStandby timer values: spec'd by %s", (val[CAPAB_0] & STD_STBY) ? "Standard" : "Vendor");
Rob Landleya3e4f382006-04-29 16:06:31 +0000829 if ((like_std > 3) && ((val[CAPAB_1] & VALID) == VALID_VAL))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000830 printf(", %s device specific minimum\n", (val[CAPAB_1] & MIN_STANDBY_TIMER) ? "with" : "no");
Glenn L McGrath07085852003-10-09 07:28:22 +0000831 else
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000832 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000833 }
834 printf("\tR/W multiple sector transfer: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000835 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
Eric Andersen3443bd72003-07-22 07:30:36 +0000836 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000837 else {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000838 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
Rob Landleyadde7982006-05-16 15:32:30 +0000839 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
840 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
841 else
842 printf("?\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000843 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000844 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000845 /* We print out elsewhere whether the APM feature is enabled or
846 not. If it's not enabled, let's not repeat the info; just print
847 nothing here. */
Glenn L McGrath07085852003-10-09 07:28:22 +0000848 printf("\tAdvancedPM level: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000849 if ((val[ADV_PWR] & 0xFF00) == 0x4000) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000850 uint8_t apm_level = val[ADV_PWR] & 0x00FF;
Eric Andersen3443bd72003-07-22 07:30:36 +0000851 printf("%u (0x%x)\n", apm_level, apm_level);
Glenn L McGrath07085852003-10-09 07:28:22 +0000852 }
853 else
Eric Andersen3443bd72003-07-22 07:30:36 +0000854 printf("unknown setting (0x%04x)\n", val[ADV_PWR]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000855 }
Rob Landleyadde7982006-05-16 15:32:30 +0000856 if (like_std > 5 && val[ACOUSTIC]) {
857 printf("\tRecommended acoustic management value: %u, current value: %u\n",
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000858 (val[ACOUSTIC] >> 8) & 0x00ff, val[ACOUSTIC] & 0x00ff);
Eric Andersen3443bd72003-07-22 07:30:36 +0000859 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000860 } else {
Glenn L McGrath07085852003-10-09 07:28:22 +0000861 /* ATAPI */
Rob Landleyadde7982006-05-16 15:32:30 +0000862 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
863 printf("\tATA sw reset required\n");
Glenn L McGrath07085852003-10-09 07:28:22 +0000864
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000865 if (val[PKT_REL] || val[SVC_NBSY]) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000866 printf("\tOverlap support:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000867 if (val[PKT_REL]) printf(" %uus to release bus.", val[PKT_REL]);
868 if (val[SVC_NBSY]) printf(" %uus to clear BSY after SERVICE cmd.", val[SVC_NBSY]);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000869 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000870 }
871 }
872
873 /* DMA stuff. Check that only one DMA mode is selected. */
874 printf("\tDMA: ");
Rob Landleya3e4f382006-04-29 16:06:31 +0000875 if (!(val[CAPAB_0] & DMA_SUP))
Eric Andersen3443bd72003-07-22 07:30:36 +0000876 printf("not supported\n");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000877 else {
Rob Landleyadde7982006-05-16 15:32:30 +0000878 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000879 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000880 if (val[SINGLE_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000881 jj = val[SINGLE_DMA];
882 kk = val[SINGLE_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000883 err_dma += mode_loop(jj, kk, 's', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +0000884 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000885 if (val[MULTI_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000886 jj = val[MULTI_DMA];
887 kk = val[MULTI_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000888 err_dma += mode_loop(jj, kk, 'm', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +0000889 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000890 if ((val[WHATS_VALID] & OK_W88) && val[ULTRA_DMA]) {
Glenn L McGrath07085852003-10-09 07:28:22 +0000891 jj = val[ULTRA_DMA];
892 kk = val[ULTRA_DMA] >> 8;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000893 err_dma += mode_loop(jj, kk, 'u', &have_mode);
Eric Andersen3443bd72003-07-22 07:30:36 +0000894 }
Rob Landleyadde7982006-05-16 15:32:30 +0000895 if (err_dma || !have_mode) printf("(?)");
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000896 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000897
Rob Landleyadde7982006-05-16 15:32:30 +0000898 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
899 printf("\t\tInterleaved DMA support\n");
Eric Andersen3443bd72003-07-22 07:30:36 +0000900
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000901 if ((val[WHATS_VALID] & OK_W64_70)
902 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
903 ) {
Rob Landleyadde7982006-05-16 15:32:30 +0000904 printf("\t\tCycle time:");
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000905 if (val[DMA_TIME_MIN]) printf(" min=%uns", val[DMA_TIME_MIN]);
906 if (val[DMA_TIME_NORM]) printf(" recommended=%uns", val[DMA_TIME_NORM]);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000907 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000908 }
909 }
910
911 /* Programmed IO stuff */
912 printf("\tPIO: ");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000913 /* If a drive supports mode n (e.g. 3), it also supports all modes less
Eric Andersen3443bd72003-07-22 07:30:36 +0000914 * than n (e.g. 3, 2, 1 and 0). Print all the modes. */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000915 if ((val[WHATS_VALID] & OK_W64_70) && (val[ADV_PIO_MODES] & PIO_SUP)) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000916 jj = ((val[ADV_PIO_MODES] & PIO_SUP) << 3) | 0x0007;
Denis Vlasenko6963eb52007-05-22 21:46:11 +0000917 for (ii = 0; ii <= PIO_MODE_MAX; ii++) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000918 if (jj & 0x0001) printf("pio%d ", ii);
Eric Andersen3443bd72003-07-22 07:30:36 +0000919 jj >>=1;
920 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000921 puts("");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000922 } else if (((min_std < 5) || (eqpt == CDROM)) && (val[PIO_MODE] & MODE)) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000923 for (ii = 0; ii <= val[PIO_MODE]>>8; ii++)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000924 printf("pio%d ", ii);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000925 puts("");
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000926 } else
Glenn L McGrath07085852003-10-09 07:28:22 +0000927 printf("unknown\n");
928
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000929 if (val[WHATS_VALID] & OK_W64_70) {
930 if (val[PIO_NO_FLOW] || val[PIO_FLOW]) {
Rob Landleyadde7982006-05-16 15:32:30 +0000931 printf("\t\tCycle time:");
932 if (val[PIO_NO_FLOW]) printf(" no flow control=%uns", val[PIO_NO_FLOW]);
933 if (val[PIO_FLOW]) printf(" IORDY flow control=%uns", val[PIO_FLOW]);
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000934 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000935 }
936 }
937
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000938 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000939 printf("Commands/features:\n\tEnabled\tSupported:\n");
940 jj = val[CMDS_SUPP_0];
941 kk = val[CMDS_EN_0];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000942 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
943 if ((jj & 0x8000) && (*cmd_feat_str[ii] != '\0')) {
Rob Landleyadde7982006-05-16 15:32:30 +0000944 printf("\t%s\t%s\n", (kk & 0x8000) ? " *" : "", cmd_feat_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000945 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000946 jj <<= 1;
947 kk <<= 1;
948 if (ii % 16 == 15) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000949 jj = val[CMDS_SUPP_0+1+(ii/16)];
950 kk = val[CMDS_EN_0+1+(ii/16)];
951 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000952 if (ii == 31) {
Rob Landleya3e4f382006-04-29 16:06:31 +0000953 if ((val[CMDS_SUPP_2] & VALID) != VALID_VAL)
Glenn L McGrath07085852003-10-09 07:28:22 +0000954 ii +=16;
Eric Andersen3443bd72003-07-22 07:30:36 +0000955 }
956 }
957 }
Rob Landleyadde7982006-05-16 15:32:30 +0000958 /* Removable Media Status Notification feature set */
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000959 if ((val[RM_STAT] & RM_STAT_BITS) == RM_STAT_SUP)
Rob Landleyadde7982006-05-16 15:32:30 +0000960 printf("\t%s supported\n", cmd_feat_str[27]);
Glenn L McGrath07085852003-10-09 07:28:22 +0000961
Eric Andersen3443bd72003-07-22 07:30:36 +0000962 /* security */
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000963 if ((eqpt != CDROM) && (like_std > 3)
964 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
965 ) {
Rob Landleyade7f952006-05-25 18:53:06 +0000966 printf("Security:\n");
Rob Landleyadde7982006-05-16 15:32:30 +0000967 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
Denis Vlasenkof1ba7492007-03-28 00:14:01 +0000968 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000969 jj = val[SECU_STATUS];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000970 if (jj) {
971 for (ii = 0; ii < NUM_SECU_STR; ii++) {
Rob Landleyadde7982006-05-16 15:32:30 +0000972 printf("\t%s\t%s\n", (!(jj & 0x0001)) ? "not" : "", secu_str[ii]);
Eric Andersen3443bd72003-07-22 07:30:36 +0000973 jj >>=1;
974 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000975 if (val[SECU_STATUS] & SECU_ENABLED) {
Rob Landleyadde7982006-05-16 15:32:30 +0000976 printf("\tSecurity level %s\n", (val[SECU_STATUS] & SECU_LEVEL) ? "maximum" : "high");
Eric Andersen3443bd72003-07-22 07:30:36 +0000977 }
978 }
979 jj = val[ERASE_TIME] & ERASE_BITS;
980 kk = val[ENH_ERASE_TIME] & ERASE_BITS;
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000981 if (jj || kk) {
Eric Andersen3443bd72003-07-22 07:30:36 +0000982 printf("\t");
Rob Landleyade7f952006-05-25 18:53:06 +0000983 if (jj) printf("%umin for %sSECURITY ERASE UNIT. ", jj==ERASE_BITS ? 508 : jj<<1, "");
984 if (kk) printf("%umin for %sSECURITY ERASE UNIT. ", kk==ERASE_BITS ? 508 : kk<<1, "ENHANCED ");
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +0000985 puts("");
Eric Andersen3443bd72003-07-22 07:30:36 +0000986 }
987 }
988
989 /* reset result */
Rob Landleyadde7982006-05-16 15:32:30 +0000990 jj = val[HWRST_RSLT];
Denis Vlasenko3bf00202007-02-18 13:36:04 +0000991 if ((jj & VALID) == VALID_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +0000992 if (!(oo = (jj & RST0)))
993 jj >>= 8;
Rob Landleya3e4f382006-04-29 16:06:31 +0000994 if ((jj & DEV_DET) == JUMPER_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +0000995 strng = " determined by the jumper";
Rob Landleya3e4f382006-04-29 16:06:31 +0000996 else if ((jj & DEV_DET) == CSEL_VAL)
Rob Landleyadde7982006-05-16 15:32:30 +0000997 strng = " determined by CSEL";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000998 else
Rob Landleyadde7982006-05-16 15:32:30 +0000999 strng = "";
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001000 printf("HW reset results:\n\tCBLID- %s Vih\n\tDevice num = %i%s\n",
Rob Landleyadde7982006-05-16 15:32:30 +00001001 (val[HWRST_RSLT] & CBLID) ? "above" : "below", !(oo), strng);
Eric Andersen3443bd72003-07-22 07:30:36 +00001002 }
1003
1004 /* more stuff from std 5 */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001005 if ((like_std > 4) && (eqpt != CDROM)) {
1006 if (val[CFA_PWR_MODE] & VALID_W160) {
Rob Landleyadde7982006-05-16 15:32:30 +00001007 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 +00001008 (val[CFA_PWR_MODE] & PWR_MODE_REQ) ? " and required by some commands" : "");
Glenn L McGrath07085852003-10-09 07:28:22 +00001009
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001010 if (val[CFA_PWR_MODE] & MAX_AMPS)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001011 printf("\tMaximum current = %uma\n", val[CFA_PWR_MODE] & MAX_AMPS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001012 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001013 if ((val[INTEGRITY] & SIG) == SIG_VAL) {
Rob Landleyadde7982006-05-16 15:32:30 +00001014 printf("Checksum: %scorrect\n", chksum ? "in" : "");
Eric Andersen3443bd72003-07-22 07:30:36 +00001015 }
1016 }
1017
Rob Landleyadde7982006-05-16 15:32:30 +00001018 exit(EXIT_SUCCESS);
Eric Andersen3443bd72003-07-22 07:30:36 +00001019}
1020#endif
1021
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001022static smallint get_identity, get_geom;
1023static smallint do_flush;
1024static smallint do_ctimings, do_timings;
1025static smallint reread_partn;
1026
1027static smallint set_piomode, noisy_piomode;
1028static smallint set_readahead, get_readahead;
1029static smallint set_readonly, get_readonly;
1030static smallint set_unmask, get_unmask;
1031static smallint set_mult, get_mult;
1032static smallint set_dma_q, get_dma_q;
1033static smallint set_nowerr, get_nowerr;
1034static smallint set_keep, get_keep;
1035static smallint set_io32bit, get_io32bit;
"Vladimir N. Oleynik"b4b6d262005-10-15 14:10:36 +00001036static int piomode;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001037static unsigned long Xreadahead;
1038static unsigned long readonly;
1039static unsigned long unmask;
1040static unsigned long mult;
1041static unsigned long dma_q;
1042static unsigned long nowerr;
1043static unsigned long keep;
1044static unsigned long io32bit;
1045#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1046static unsigned long dma;
1047static smallint set_dma, get_dma;
1048#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001049#ifdef HDIO_DRIVE_CMD
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001050static smallint set_xfermode, get_xfermode;
1051static smallint set_dkeep, get_dkeep;
1052static smallint set_standby, get_standby;
1053static smallint set_lookahead, get_lookahead;
1054static smallint set_prefetch, get_prefetch;
1055static smallint set_defects, get_defects;
1056static smallint set_wcache, get_wcache;
1057static smallint set_doorlock, get_doorlock;
1058static smallint set_seagate, get_seagate;
1059static smallint set_standbynow, get_standbynow;
1060static smallint set_sleepnow, get_sleepnow;
1061static smallint get_powermode;
1062static smallint set_apmmode, get_apmmode;
"Vladimir N. Oleynik"b4b6d262005-10-15 14:10:36 +00001063static int xfermode_requested;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001064static unsigned long dkeep;
1065static unsigned long standby_requested;
1066static unsigned long lookahead;
1067static unsigned long prefetch;
1068static unsigned long defects;
1069static unsigned long wcache;
1070static unsigned long doorlock;
1071static unsigned long apmmode;
Eric Andersen3443bd72003-07-22 07:30:36 +00001072#endif
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001073USE_FEATURE_HDPARM_GET_IDENTITY( static smallint get_IDentity;)
1074USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( static smallint set_busstate, get_busstate;)
1075USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( static smallint perform_reset;)
1076USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( static smallint perform_tristate;)
1077USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(static smallint unregister_hwif;)
1078USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( static smallint scan_hwif;)
1079USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( static unsigned long busstate;)
1080USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( static unsigned long tristate;)
1081USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(static unsigned long hwif;)
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001082#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
Rob Landley20deab02006-05-07 23:34:15 +00001083static unsigned long hwif_data;
1084static unsigned long hwif_ctrl;
1085static unsigned long hwif_irq;
Eric Andersen3443bd72003-07-22 07:30:36 +00001086#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001087
1088// Historically, if there was no HDIO_OBSOLETE_IDENTITY, then
1089// then the HDIO_GET_IDENTITY only returned 142 bytes.
1090// Otherwise, HDIO_OBSOLETE_IDENTITY returns 142 bytes,
1091// and HDIO_GET_IDENTITY returns 512 bytes. But the latest
1092// 2.5.xx kernels no longer define HDIO_OBSOLETE_IDENTITY
1093// (which they should, but they should just return -EINVAL).
1094//
1095// So.. we must now assume that HDIO_GET_IDENTITY returns 512 bytes.
1096// On a really old system, it will not, and we will be confused.
1097// Too bad, really.
1098
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001099#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001100static const char *const cfg_str[] = {
1101 "", "HardSect", "SoftSect", "NotMFM",
Rob Landleyadde7982006-05-16 15:32:30 +00001102 "HdSw>15uSec", "SpinMotCtl", "Fixed", "Removeable",
1103 "DTR<=5Mbs", "DTR>5Mbs", "DTR>10Mbs", "RotSpdTol>.5%",
1104 "dStbOff", "TrkOff", "FmtGapReq", "nonMagnetic"
Eric Andersen3443bd72003-07-22 07:30:36 +00001105};
1106
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001107static const char *const BuffType[] = {
1108 "Unknown", "1Sect", "DualPort", "DualPortCache"
1109};
Eric Andersen3443bd72003-07-22 07:30:36 +00001110
Rob Landleya3e4f382006-04-29 16:06:31 +00001111static void dump_identity(const struct hd_driveid *id)
Eric Andersen3443bd72003-07-22 07:30:36 +00001112{
1113 int i;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001114 const unsigned short int *id_regs = (const void*) id;
Rob Landley0a7c8ef2006-02-22 17:01:00 +00001115
Glenn L McGrath07085852003-10-09 07:28:22 +00001116 printf("\n Model=%.40s, FwRev=%.8s, SerialNo=%.20s\n Config={",
1117 id->model, id->fw_rev, id->serial_no);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001118 for (i = 0; i <= 15; i++) {
Rob Landleyade7f952006-05-25 18:53:06 +00001119 if (id->config & (1<<i))
1120 printf(" %s", cfg_str[i]);
Rob Landleyadde7982006-05-16 15:32:30 +00001121 }
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001122 printf(" }\n RawCHS=%u/%u/%u, TrkSize=%u, SectSize=%u, ECCbytes=%u\n"
Rob Landleyadde7982006-05-16 15:32:30 +00001123 " BuffType=(%u) %s, BuffSize=%ukB, MaxMultSect=%u",
Glenn L McGrath07085852003-10-09 07:28:22 +00001124 id->cyls, id->heads, id->sectors, id->track_bytes,
Rob Landleyadde7982006-05-16 15:32:30 +00001125 id->sector_bytes, id->ecc_bytes,
1126 id->buf_type, BuffType[(id->buf_type > 3) ? 0 : id->buf_type],
1127 id->buf_size/2, id->max_multsect);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001128 if (id->max_multsect) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001129 printf(", MultSect=");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001130 if (!(id->multsect_valid & 1))
Eric Andersen3443bd72003-07-22 07:30:36 +00001131 printf("?%u?", id->multsect);
1132 else if (id->multsect)
1133 printf("%u", id->multsect);
1134 else
1135 printf("off");
1136 }
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00001137 puts("");
Rob Landleyade7f952006-05-25 18:53:06 +00001138
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001139 if (!(id->field_valid & 1))
Rob Landleyade7f952006-05-25 18:53:06 +00001140 printf(" (maybe):");
1141
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001142 printf(" CurCHS=%u/%u/%u, CurSects=%lu, LBA=%s", id->cur_cyls, id->cur_heads,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001143 id->cur_sectors,
1144 (BB_BIG_ENDIAN) ?
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001145 (unsigned long)(id->cur_capacity0 << 16) | id->cur_capacity1 :
1146 (unsigned long)(id->cur_capacity1 << 16) | id->cur_capacity0,
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001147 ((id->capability&2) == 0) ? "no" : "yes");
Rob Landleyade7f952006-05-25 18:53:06 +00001148
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001149 if (id->capability & 2)
Rob Landleyade7f952006-05-25 18:53:06 +00001150 printf(", LBAsects=%u", id->lba_capacity);
1151
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001152 printf("\n IORDY=%s", (id->capability & 8) ? (id->capability & 4) ? "on/off" : "yes" : "no");
Rob Landleyade7f952006-05-25 18:53:06 +00001153
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001154 if (((id->capability & 8) || (id->field_valid & 2)) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001155 printf(", tPIO={min:%u,w/IORDY:%u}", id->eide_pio, id->eide_pio_iordy);
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001156
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001157 if ((id->capability & 1) && (id->field_valid & 2))
Rob Landleyade7f952006-05-25 18:53:06 +00001158 printf(", tDMA={min:%u,rec:%u}", id->eide_dma_min, id->eide_dma_time);
1159
1160 printf("\n PIO modes: ");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001161 if (id->tPIO <= 5) {
Rob Landleyade7f952006-05-25 18:53:06 +00001162 printf("pio0 ");
1163 if (id->tPIO >= 1) printf("pio1 ");
1164 if (id->tPIO >= 2) printf("pio2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001165 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001166 if (id->field_valid & 2) {
Rob Landleyade7f952006-05-25 18:53:06 +00001167 if (id->eide_pio_modes & 1) printf("pio3 ");
1168 if (id->eide_pio_modes & 2) printf("pio4 ");
1169 if (id->eide_pio_modes &~3) printf("pio? ");
1170 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001171 if (id->capability & 1) {
1172 if (id->dma_1word | id->dma_mword) {
Rob Landleyade7f952006-05-25 18:53:06 +00001173 printf("\n DMA modes: ");
1174 if (id->dma_1word & 0x100) printf("*");
1175 if (id->dma_1word & 1) printf("sdma0 ");
1176 if (id->dma_1word & 0x200) printf("*");
1177 if (id->dma_1word & 2) printf("sdma1 ");
1178 if (id->dma_1word & 0x400) printf("*");
1179 if (id->dma_1word & 4) printf("sdma2 ");
1180 if (id->dma_1word & 0xf800) printf("*");
1181 if (id->dma_1word & 0xf8) printf("sdma? ");
1182 if (id->dma_mword & 0x100) printf("*");
1183 if (id->dma_mword & 1) printf("mdma0 ");
1184 if (id->dma_mword & 0x200) printf("*");
1185 if (id->dma_mword & 2) printf("mdma1 ");
1186 if (id->dma_mword & 0x400) printf("*");
1187 if (id->dma_mword & 4) printf("mdma2 ");
1188 if (id->dma_mword & 0xf800) printf("*");
1189 if (id->dma_mword & 0xf8) printf("mdma? ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001190 }
1191 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001192 if (((id->capability & 8) || (id->field_valid & 2)) && id->field_valid & 4) {
Rob Landleyade7f952006-05-25 18:53:06 +00001193 printf("\n UDMA modes: ");
1194 if (id->dma_ultra & 0x100) printf("*");
1195 if (id->dma_ultra & 0x001) printf("udma0 ");
1196 if (id->dma_ultra & 0x200) printf("*");
1197 if (id->dma_ultra & 0x002) printf("udma1 ");
1198 if (id->dma_ultra & 0x400) printf("*");
1199 if (id->dma_ultra & 0x004) printf("udma2 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001200#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001201 if (id->hw_config & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001202#else /* !__NEW_HD_DRIVE_ID */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001203 if (id->word93 & 0x2000) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001204#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001205 if (id->dma_ultra & 0x0800) printf("*");
1206 if (id->dma_ultra & 0x0008) printf("udma3 ");
1207 if (id->dma_ultra & 0x1000) printf("*");
1208 if (id->dma_ultra & 0x0010) printf("udma4 ");
1209 if (id->dma_ultra & 0x2000) printf("*");
1210 if (id->dma_ultra & 0x0020) printf("udma5 ");
1211 if (id->dma_ultra & 0x4000) printf("*");
1212 if (id->dma_ultra & 0x0040) printf("udma6 ");
1213 if (id->dma_ultra & 0x8000) printf("*");
1214 if (id->dma_ultra & 0x0080) printf("udma7 ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001215 }
1216 }
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001217 printf("\n AdvancedPM=%s", (!(id_regs[83] & 8)) ? "no" : "yes");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001218 if (id_regs[83] & 8) {
1219 if (!(id_regs[86] & 8))
Glenn L McGrath07085852003-10-09 07:28:22 +00001220 printf(": disabled (255)");
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001221 else if ((id_regs[91] & 0xFF00) != 0x4000)
Glenn L McGrath07085852003-10-09 07:28:22 +00001222 printf(": unknown setting");
1223 else
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001224 printf(": mode=0x%02X (%u)", id_regs[91] & 0xFF, id_regs[91] & 0xFF);
Glenn L McGrath07085852003-10-09 07:28:22 +00001225 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001226 if (id_regs[82] & 0x20)
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001227 printf(" WriteCache=%s", (id_regs[85] & 0x20) ? "enabled" : "disabled");
Glenn L McGrath07085852003-10-09 07:28:22 +00001228#ifdef __NEW_HD_DRIVE_ID
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001229 if ((id->minor_rev_num && id->minor_rev_num <= 31)
1230 || (id->major_rev_num && id->minor_rev_num <= 31)
1231 ) {
Rob Landleyadde7982006-05-16 15:32:30 +00001232 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 +00001233 if (id->major_rev_num != 0x0000 && /* NOVAL_0 */
1234 id->major_rev_num != 0xFFFF) { /* NOVAL_1 */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001235 for (i = 0; i <= 15; i++) {
Rob Landleyadde7982006-05-16 15:32:30 +00001236 if (id->major_rev_num & (1<<i))
1237 printf(" ATA/ATAPI-%u", i);
1238 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001239 }
1240 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001241#endif /* __NEW_HD_DRIVE_ID */
Rob Landleyade7f952006-05-25 18:53:06 +00001242 printf("\n\n * current active mode\n\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001243}
1244#endif
1245
Rob Landleya3e4f382006-04-29 16:06:31 +00001246static void flush_buffer_cache(int fd)
Eric Andersen3443bd72003-07-22 07:30:36 +00001247{
Rob Landleya3e4f382006-04-29 16:06:31 +00001248 fsync(fd); /* flush buffers */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001249 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
Eric Andersen3443bd72003-07-22 07:30:36 +00001250#ifdef HDIO_DRIVE_CMD
Glenn L McGrath07085852003-10-09 07:28:22 +00001251 sleep(1);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001252 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1253 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1254 bb_perror_msg("HDIO_DRIVE_CMD");
1255 else
1256 bb_perror_msg("ioctl %#x failed", HDIO_DRIVE_CMD);
1257 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001258#endif
1259}
1260
Rob Landleya3e4f382006-04-29 16:06:31 +00001261static int seek_to_zero(int fd)
Eric Andersen3443bd72003-07-22 07:30:36 +00001262{
Glenn L McGrath07085852003-10-09 07:28:22 +00001263 if (lseek(fd, (off_t) 0, SEEK_SET))
Eric Andersen3443bd72003-07-22 07:30:36 +00001264 return 1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001265 return 0;
1266}
1267
Rob Landleya3e4f382006-04-29 16:06:31 +00001268static int read_big_block(int fd, char *buf)
Eric Andersen3443bd72003-07-22 07:30:36 +00001269{
Rob Landleyadde7982006-05-16 15:32:30 +00001270 int i;
1271
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001272 i = read(fd, buf, TIMING_BUF_BYTES);
1273 if (i != TIMING_BUF_BYTES) {
Rob Landleyadde7982006-05-16 15:32:30 +00001274 bb_error_msg("read(%d bytes) failed (rc=%d)", TIMING_BUF_BYTES, i);
Eric Andersen3443bd72003-07-22 07:30:36 +00001275 return 1;
1276 }
1277 /* access all sectors of buf to ensure the read fully completed */
1278 for (i = 0; i < TIMING_BUF_BYTES; i += 512)
1279 buf[i] &= 1;
1280 return 0;
1281}
1282
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001283static int do_blkgetsize(int fd, unsigned long long *blksize64)
Rob Landleyadde7982006-05-16 15:32:30 +00001284{
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001285 int rc;
1286 unsigned blksize32 = 0;
Rob Landleyadde7982006-05-16 15:32:30 +00001287
1288 if (0 == ioctl(fd, BLKGETSIZE64, blksize64)) { // returns bytes
1289 *blksize64 /= 512;
1290 return 0;
1291 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001292 rc = ioctl_or_warn(fd, BLKGETSIZE, &blksize32); // returns sectors
Rob Landleyadde7982006-05-16 15:32:30 +00001293 *blksize64 = blksize32;
1294 return rc;
1295}
Eric Andersen50af12d2003-08-06 08:47:59 +00001296
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001297static void print_timing(unsigned t, double e)
1298{
1299 if (t >= e) /* more than 1MB/s */
1300 printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e, 'M');
1301 else
1302 printf("%4d MB in %.2f seconds = %.2f %cB/sec\n", t, e, t / e * 1024, 'k');
1303}
1304
Rob Landleya3e4f382006-04-29 16:06:31 +00001305static void do_time(int flag, int fd)
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001306/* flag = 0 time_cache, 1 time_device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001307{
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001308 static const struct itimerval thousand = {{1000, 0}, {1000, 0}};
1309
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001310 struct itimerval itv;
1311 unsigned elapsed, elapsed2;
1312 unsigned max_iterations, total_MB, iterations;
Rob Landleyadde7982006-05-16 15:32:30 +00001313 unsigned long long blksize;
Rob Landley4ae2f512006-05-19 17:24:26 +00001314 RESERVE_CONFIG_BUFFER(buf, TIMING_BUF_BYTES);
1315
1316 if (mlock(buf, TIMING_BUF_BYTES)) {
1317 bb_perror_msg("mlock");
1318 goto quit2;
1319 }
Rob Landleyadde7982006-05-16 15:32:30 +00001320
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001321 max_iterations = 1024;
Rob Landleyadde7982006-05-16 15:32:30 +00001322 if (0 == do_blkgetsize(fd, &blksize)) {
1323 max_iterations = blksize / (2 * 1024) / TIMING_BUF_MB;
1324 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001325
Eric Andersen3443bd72003-07-22 07:30:36 +00001326 /* Clear out the device request queues & give them time to complete */
Rob Landleyadde7982006-05-16 15:32:30 +00001327 sync();
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001328 sleep(2);
1329 if (flag == 0) { /* Time cache */
1330 if (seek_to_zero(fd))
1331 goto quit;
1332 if (read_big_block(fd, buf))
1333 goto quit;
1334 printf(" Timing buffer-cache reads: ");
1335 } else { /* Time device */
1336 printf(" Timing buffered disk reads: ");
1337 }
1338 fflush(stdout);
1339 iterations = 0;
1340 /*
1341 * getitimer() is used rather than gettimeofday() because
1342 * it is much more consistent (on my machine, at least).
1343 */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001344 setitimer(ITIMER_REAL, &thousand, NULL);
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001345 /* Now do the timing */
1346 do {
1347 ++iterations;
1348 if ((flag == 0) && seek_to_zero(fd))
1349 goto quit;
1350 if (read_big_block(fd, buf))
1351 goto quit;
1352 getitimer(ITIMER_REAL, &itv);
1353 elapsed = (1000 - itv.it_value.tv_sec) * 1000000
1354 - itv.it_value.tv_usec;
1355 } while (elapsed < 3000000 && iterations < max_iterations);
1356 total_MB = iterations * TIMING_BUF_MB;
1357 if (flag == 0) {
Rob Landleyadde7982006-05-16 15:32:30 +00001358 /* Now remove the lseek() and getitimer() overheads from the elapsed time */
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001359 setitimer(ITIMER_REAL, &thousand, NULL);
Rob Landleyadde7982006-05-16 15:32:30 +00001360 do {
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001361 if (seek_to_zero(fd))
Rob Landleyadde7982006-05-16 15:32:30 +00001362 goto quit;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001363 getitimer(ITIMER_REAL, &itv);
1364 elapsed2 = (1000 - itv.it_value.tv_sec) * 1000000
1365 - itv.it_value.tv_usec;
Rob Landleyadde7982006-05-16 15:32:30 +00001366 } while (--iterations);
Rob Landleyadde7982006-05-16 15:32:30 +00001367 elapsed -= elapsed2;
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001368 total_MB *= BUFCACHE_FACTOR;
Glenn L McGrath07085852003-10-09 07:28:22 +00001369 flush_buffer_cache(fd);
Glenn L McGrath07085852003-10-09 07:28:22 +00001370 }
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001371 print_timing(total_MB, elapsed / 1000000.0);
1372 quit:
Rob Landley4ae2f512006-05-19 17:24:26 +00001373 munlock(buf, TIMING_BUF_BYTES);
Denis Vlasenko6963eb52007-05-22 21:46:11 +00001374 quit2:
Rob Landley4ae2f512006-05-19 17:24:26 +00001375 RELEASE_CONFIG_BUFFER(buf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001376}
1377
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001378#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001379static void bus_state_value(unsigned value)
Eric Andersen3443bd72003-07-22 07:30:36 +00001380{
Rob Landleyadde7982006-05-16 15:32:30 +00001381 if (value == BUSSTATE_ON)
1382 on_off(1);
1383 else if (value == BUSSTATE_OFF)
1384 on_off(0);
1385 else if (value == BUSSTATE_TRISTATE)
1386 printf(" (tristate)\n");
1387 else
1388 printf(" (unknown: %d)\n", value);
Eric Andersen3443bd72003-07-22 07:30:36 +00001389}
1390#endif
1391
1392#ifdef HDIO_DRIVE_CMD
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001393static void interpret_standby(unsigned standby)
Eric Andersen3443bd72003-07-22 07:30:36 +00001394{
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001395 unsigned t;
Rob Landleyadde7982006-05-16 15:32:30 +00001396
Rob Landley403777f2006-08-03 20:22:37 +00001397 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001398 if (standby == 0)
1399 printf("off");
1400 else if (standby == 252)
1401 printf("21 minutes");
1402 else if (standby == 253)
1403 printf("vendor-specific");
1404 else if (standby == 254)
1405 printf("Reserved");
1406 else if (standby == 255)
1407 printf("21 minutes + 15 seconds");
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001408 else if (standby <= 240) {
1409 t = standby * 5;
1410 printf("%u minutes + %u seconds", t / 60, t % 60);
1411 } else if (standby <= 251) {
1412 t = (standby - 240) * 30;
1413 printf("%u hours + %u minutes", t / 60, t % 60);
1414 } else
1415 printf("illegal value");
Eric Andersen3443bd72003-07-22 07:30:36 +00001416 printf(")\n");
1417}
1418
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001419static const uint8_t xfermode_val[] ALIGN1 = {
1420 8, 9, 10, 11, 12, 13, 14, 15,
1421 16, 17, 18, 19, 20, 21, 22, 23,
1422 32, 33, 34, 35, 36, 37, 38, 39,
1423 64, 65, 66, 67, 68, 69, 70, 71
1424};
1425/* NB: we save size by _not_ storing terninating NUL! */
1426static const char xfermode_name[][5] ALIGN1 = {
1427 "pio0", "pio1", "pio2", "pio3", "pio4", "pio5", "pio6", "pio7",
1428 "sdma0","sdma1","sdma2","sdma3","sdma4","sdma5","sdma6","sdma7",
1429 "mdma0","mdma1","mdma2","mdma3","mdma4","mdma5","mdma6","mdma7",
1430 "udma0","udma1","udma2","udma3","udma4","udma5","udma6","udma7"
Eric Andersen3443bd72003-07-22 07:30:36 +00001431};
1432
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001433static int translate_xfermode(const char *name)
Eric Andersen3443bd72003-07-22 07:30:36 +00001434{
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001435 int val, i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001436
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001437 for (i = 0; i < ARRAY_SIZE(xfermode_val); i++) {
1438 if (!strncmp(name, xfermode_name[i], 5))
1439 if (strlen(name) <= 5)
1440 return xfermode_val[i];
Glenn L McGrath07085852003-10-09 07:28:22 +00001441 }
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001442 /* Negative numbers are invalid and are caught later */
1443 val = bb_strtoi(name, NULL, 10);
1444 if (!errno)
Glenn L McGrath07085852003-10-09 07:28:22 +00001445 return val;
Glenn L McGrath07085852003-10-09 07:28:22 +00001446 return -1;
Eric Andersen3443bd72003-07-22 07:30:36 +00001447}
1448
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001449static void interpret_xfermode(unsigned xfermode)
Eric Andersen3443bd72003-07-22 07:30:36 +00001450{
1451 printf(" (");
Rob Landleyadde7982006-05-16 15:32:30 +00001452 if (xfermode == 0)
1453 printf("default PIO mode");
1454 else if (xfermode == 1)
1455 printf("default PIO mode, disable IORDY");
1456 else if (xfermode >= 8 && xfermode <= 15)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001457 printf("PIO flow control mode%u", xfermode - 8);
Rob Landleyadde7982006-05-16 15:32:30 +00001458 else if (xfermode >= 16 && xfermode <= 23)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001459 printf("singleword DMA mode%u", xfermode - 16);
Rob Landleyadde7982006-05-16 15:32:30 +00001460 else if (xfermode >= 32 && xfermode <= 39)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001461 printf("multiword DMA mode%u", xfermode - 32);
Rob Landleyadde7982006-05-16 15:32:30 +00001462 else if (xfermode >= 64 && xfermode <= 71)
Denis Vlasenkoa0319ba2007-08-16 10:37:49 +00001463 printf("UltraDMA mode%u", xfermode - 64);
Rob Landleyadde7982006-05-16 15:32:30 +00001464 else
1465 printf("Unknown");
Eric Andersen3443bd72003-07-22 07:30:36 +00001466 printf(")\n");
1467}
1468#endif /* HDIO_DRIVE_CMD */
1469
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001470static void print_flag(int flag, const char *s, unsigned long value)
Rob Landleyadde7982006-05-16 15:32:30 +00001471{
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001472 if (flag)
Rob Landleyadde7982006-05-16 15:32:30 +00001473 printf(" setting %s to %ld\n", s, value);
1474}
1475
Rob Landleya3e4f382006-04-29 16:06:31 +00001476static void process_dev(char *devname)
Eric Andersen3443bd72003-07-22 07:30:36 +00001477{
1478 int fd;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001479 long parm, multcount;
Eric Andersen3443bd72003-07-22 07:30:36 +00001480#ifndef HDIO_DRIVE_CMD
1481 int force_operation = 0;
1482#endif
Rob Landley39cf6452006-05-05 16:52:28 +00001483 /* Please restore args[n] to these values after each ioctl
1484 except for args[2] */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001485 unsigned char args[4] = { WIN_SETFEATURES, 0, 0, 0 };
Rob Landleyadde7982006-05-16 15:32:30 +00001486 const char *fmt = " %s\t= %2ld";
Rob Landleye5b281f2006-04-29 15:49:18 +00001487
Rob Landleyd921b2e2006-08-03 15:41:12 +00001488 fd = xopen(devname, O_RDONLY|O_NONBLOCK);
Rob Landleyade7f952006-05-25 18:53:06 +00001489 printf("\n%s:\n", devname);
Eric Andersen3443bd72003-07-22 07:30:36 +00001490
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001491 if (set_readahead) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001492 print_flag(get_readahead, "fs readahead", Xreadahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001493 ioctl_or_warn(fd, BLKRASET, (int *)Xreadahead);
Eric Andersen3443bd72003-07-22 07:30:36 +00001494 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001495#if ENABLE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
1496 if (unregister_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001497 printf(" attempting to unregister hwif#%lu\n", hwif);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001498 ioctl_or_warn(fd, HDIO_UNREGISTER_HWIF, (int *)(unsigned long)hwif);
Eric Andersen3443bd72003-07-22 07:30:36 +00001499 }
1500#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001501#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
1502 if (scan_hwif) {
Rob Landley20deab02006-05-07 23:34:15 +00001503 printf(" attempting to scan hwif (0x%lx, 0x%lx, %lu)\n", hwif_data, hwif_ctrl, hwif_irq);
Eric Andersen3443bd72003-07-22 07:30:36 +00001504 args[0] = hwif_data;
1505 args[1] = hwif_ctrl;
1506 args[2] = hwif_irq;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001507 ioctl_or_warn(fd, HDIO_SCAN_HWIF, args);
Rob Landley39cf6452006-05-05 16:52:28 +00001508 args[0] = WIN_SETFEATURES;
1509 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001510 }
1511#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001512 if (set_piomode) {
1513 if (noisy_piomode) {
Glenn L McGrath07085852003-10-09 07:28:22 +00001514 printf(" attempting to ");
Eric Andersen3443bd72003-07-22 07:30:36 +00001515 if (piomode == 255)
Glenn L McGrath07085852003-10-09 07:28:22 +00001516 printf("auto-tune PIO mode\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001517 else if (piomode < 100)
Glenn L McGrath07085852003-10-09 07:28:22 +00001518 printf("set PIO mode to %d\n", piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001519 else if (piomode < 200)
Glenn L McGrath07085852003-10-09 07:28:22 +00001520 printf("set MDMA mode to %d\n", (piomode-100));
Eric Andersen3443bd72003-07-22 07:30:36 +00001521 else
Glenn L McGrath07085852003-10-09 07:28:22 +00001522 printf("set UDMA mode to %d\n", (piomode-200));
Eric Andersen3443bd72003-07-22 07:30:36 +00001523 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001524 ioctl_or_warn(fd, HDIO_SET_PIO_MODE, (int *)(unsigned long)piomode);
Eric Andersen3443bd72003-07-22 07:30:36 +00001525 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001526 if (set_io32bit) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001527 print_flag(get_io32bit, "32-bit IO_support flag", io32bit);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001528 ioctl_or_warn(fd, HDIO_SET_32BIT, (int *)io32bit);
Eric Andersen3443bd72003-07-22 07:30:36 +00001529 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001530 if (set_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001531 print_flag(get_mult, "multcount", mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001532#ifdef HDIO_DRIVE_CMD
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001533 ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult);
Rob Landleyade7f952006-05-25 18:53:06 +00001534#else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001535 force_operation |= (!ioctl_or_warn(fd, HDIO_SET_MULTCOUNT, (void *)mult));
Eric Andersen3443bd72003-07-22 07:30:36 +00001536#endif
1537 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001538 if (set_readonly) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001539 print_flag_on_off(get_readonly, "readonly", readonly);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001540 ioctl_or_warn(fd, BLKROSET, &readonly);
Eric Andersen3443bd72003-07-22 07:30:36 +00001541 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001542 if (set_unmask) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001543 print_flag_on_off(get_unmask, "unmaskirq", unmask);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001544 ioctl_or_warn(fd, HDIO_SET_UNMASKINTR, (int *)unmask);
Eric Andersen3443bd72003-07-22 07:30:36 +00001545 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001546#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
1547 if (set_dma) {
Rob Landleyadde7982006-05-16 15:32:30 +00001548 print_flag_on_off(get_dma, "using_dma", dma);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001549 ioctl_or_warn(fd, HDIO_SET_DMA, (int *)dma);
Eric Andersen3443bd72003-07-22 07:30:36 +00001550 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001551#endif /* FEATURE_HDPARM_HDIO_GETSET_DMA */
1552 if (set_dma_q) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001553 print_flag_on_off(get_dma_q, "DMA queue_depth", dma_q);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001554 ioctl_or_warn(fd, HDIO_SET_QDMA, (int *)dma_q);
Eric Andersen3443bd72003-07-22 07:30:36 +00001555 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001556 if (set_nowerr) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001557 print_flag_on_off(get_nowerr, "nowerr", nowerr);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001558 ioctl_or_warn(fd, HDIO_SET_NOWERR, (int *)nowerr);
Eric Andersen3443bd72003-07-22 07:30:36 +00001559 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001560 if (set_keep) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001561 print_flag_on_off(get_keep, "keep_settings", keep);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001562 ioctl_or_warn(fd, HDIO_SET_KEEPSETTINGS, (int *)keep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001563 }
1564#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001565 if (set_doorlock) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001566 args[0] = doorlock ? WIN_DOORLOCK : WIN_DOORUNLOCK;
Rob Landley39cf6452006-05-05 16:52:28 +00001567 args[2] = 0;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001568 print_flag_on_off(get_doorlock, "drive doorlock", doorlock);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001569 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001570 args[0] = WIN_SETFEATURES;
Eric Andersen3443bd72003-07-22 07:30:36 +00001571 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001572 if (set_dkeep) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001573 /* lock/unlock the drive's "feature" settings */
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001574 print_flag_on_off(get_dkeep, "drive keep features", dkeep);
Eric Andersen3443bd72003-07-22 07:30:36 +00001575 args[2] = dkeep ? 0x66 : 0xcc;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001576 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001577 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001578 if (set_defects) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001579 args[2] = defects ? 0x04 : 0x84;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001580 print_flag(get_defects, "drive defect-mgmt", defects);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001581 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001582 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001583 if (set_prefetch) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001584 args[1] = prefetch;
Rob Landleye5b281f2006-04-29 15:49:18 +00001585 args[2] = 0xab;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001586 print_flag(get_prefetch, "drive prefetch", prefetch);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001587 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001588 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001589 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001590 if (set_xfermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001591 args[1] = xfermode_requested;
Rob Landleye5b281f2006-04-29 15:49:18 +00001592 args[2] = 3;
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001593 if (get_xfermode) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001594 print_flag(1, "xfermode", xfermode_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001595 interpret_xfermode(xfermode_requested);
1596 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001597 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001598 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001599 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001600 if (set_lookahead) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001601 args[2] = lookahead ? 0xaa : 0x55;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001602 print_flag_on_off(get_lookahead, "drive read-lookahead", lookahead);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001603 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001604 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001605 if (set_apmmode) {
Rob Landleyadde7982006-05-16 15:32:30 +00001606 args[2] = (apmmode == 255) ? 0x85 /* disable */ : 0x05 /* set */; /* feature register */
1607 args[1] = apmmode; /* sector count register 1-255 */
1608 if (get_apmmode)
1609 printf(" setting APM level to %s 0x%02lX (%ld)\n", (apmmode == 255) ? "disabled" : "", apmmode, apmmode);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001610 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001611 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001612 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001613 if (set_wcache) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001614#ifdef DO_FLUSHCACHE
1615#ifndef WIN_FLUSHCACHE
1616#define WIN_FLUSHCACHE 0xe7
1617#endif
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001618 static unsigned char flushcache[4] = { WIN_FLUSHCACHE, 0, 0, 0 };
Eric Andersen3443bd72003-07-22 07:30:36 +00001619#endif /* DO_FLUSHCACHE */
Eric Andersen3443bd72003-07-22 07:30:36 +00001620 args[2] = wcache ? 0x02 : 0x82;
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001621 print_flag_on_off(get_wcache, "drive write-caching", wcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001622#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001623 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001624 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001625#endif /* DO_FLUSHCACHE */
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001626 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001627#ifdef DO_FLUSHCACHE
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001628 if (!wcache)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001629 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &flushcache);
Eric Andersen3443bd72003-07-22 07:30:36 +00001630#endif /* DO_FLUSHCACHE */
1631 }
Rob Landley39cf6452006-05-05 16:52:28 +00001632
1633 /* In code below, we do not preserve args[0], but the rest
1634 is preserved, including args[2] */
1635 args[2] = 0;
1636
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001637 if (set_standbynow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001638#ifndef WIN_STANDBYNOW1
1639#define WIN_STANDBYNOW1 0xE0
1640#endif
1641#ifndef WIN_STANDBYNOW2
1642#define WIN_STANDBYNOW2 0x94
1643#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001644 if (get_standbynow) printf(" issuing standby command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001645 args[0] = WIN_STANDBYNOW1;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001646 ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001647 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001648 if (set_sleepnow) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001649#ifndef WIN_SLEEPNOW1
1650#define WIN_SLEEPNOW1 0xE6
1651#endif
1652#ifndef WIN_SLEEPNOW2
1653#define WIN_SLEEPNOW2 0x99
1654#endif
Rob Landleyadde7982006-05-16 15:32:30 +00001655 if (get_sleepnow) printf(" issuing sleep command\n");
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001656 args[0] = WIN_SLEEPNOW1;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001657 ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
Eric Andersen3443bd72003-07-22 07:30:36 +00001658 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001659 if (set_seagate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001660 args[0] = 0xfb;
Rob Landleyadde7982006-05-16 15:32:30 +00001661 if (get_seagate) printf(" disabling Seagate auto powersaving mode\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001662 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001663 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001664 if (set_standby) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001665 args[0] = WIN_SETIDLE1;
1666 args[1] = standby_requested;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001667 if (get_standby) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001668 print_flag(1, "standby", standby_requested);
Eric Andersen3443bd72003-07-22 07:30:36 +00001669 interpret_standby(standby_requested);
1670 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001671 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
Rob Landley39cf6452006-05-05 16:52:28 +00001672 args[1] = 0;
Eric Andersen3443bd72003-07-22 07:30:36 +00001673 }
1674#else /* HDIO_DRIVE_CMD */
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001675 if (force_operation) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001676 char buf[512];
1677 flush_buffer_cache(fd);
1678 if (-1 == read(fd, buf, sizeof(buf)))
Rob Landleyadde7982006-05-16 15:32:30 +00001679 bb_perror_msg("read(%d bytes) failed (rc=%d)", sizeof(buf), -1);
Eric Andersen3443bd72003-07-22 07:30:36 +00001680 }
1681#endif /* HDIO_DRIVE_CMD */
1682
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001683 if (get_mult || get_identity) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001684 multcount = -1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001685 if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001686 if (get_mult && ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn. */
Eric Andersen06d4ec22004-03-19 10:53:52 +00001687 bb_perror_msg("HDIO_GET_MULTCOUNT");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001688 else
1689 bb_perror_msg("ioctl %#x failed", HDIO_GET_MULTCOUNT);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001690 } else if (get_mult) {
Rob Landleyadde7982006-05-16 15:32:30 +00001691 printf(fmt, "multcount", multcount);
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001692 on_off(multcount != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001693 }
1694 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001695 if (get_io32bit) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001696 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001697 printf(" IO_support\t=%3ld (", parm);
1698 if (parm == 0)
1699 printf("default 16-bit)\n");
1700 else if (parm == 2)
1701 printf("16-bit)\n");
1702 else if (parm == 1)
1703 printf("32-bit)\n");
1704 else if (parm == 3)
1705 printf("32-bit w/sync)\n");
1706 else if (parm == 8)
1707 printf("Request-Queue-Bypass)\n");
1708 else
1709 printf("\?\?\?)\n");
Eric Andersen3443bd72003-07-22 07:30:36 +00001710 }
1711 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001712 if (get_unmask) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001713 if(!ioctl_or_warn(fd, HDIO_GET_UNMASKINTR, (unsigned long *)parm))
1714 print_value_on_off("unmaskirq", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001715 }
1716
Glenn L McGrath07085852003-10-09 07:28:22 +00001717
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001718#if ENABLE_FEATURE_HDPARM_HDIO_GETSET_DMA
Rob Landleyade7f952006-05-25 18:53:06 +00001719 if (get_dma) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001720 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001721 printf(fmt, "using_dma", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001722 if (parm == 8)
1723 printf(" (DMA-Assisted-PIO)\n");
1724 else
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001725 on_off(parm != 0);
Eric Andersen3443bd72003-07-22 07:30:36 +00001726 }
1727 }
1728#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001729 if (get_dma_q) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001730 if(!ioctl_or_warn(fd, HDIO_GET_QDMA, (unsigned long *)parm))
1731 print_value_on_off("queue_depth", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001732 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001733 if (get_keep) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001734 if(!ioctl_or_warn(fd, HDIO_GET_KEEPSETTINGS, (unsigned long *)parm))
1735 print_value_on_off("keepsettings", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001736 }
1737
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001738 if (get_nowerr) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001739 if(!ioctl_or_warn(fd, HDIO_GET_NOWERR, (unsigned long *)parm))
1740 print_value_on_off("nowerr", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001741 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001742 if (get_readonly) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001743 if(!ioctl_or_warn(fd, BLKROGET, (unsigned long *)parm))
1744 print_value_on_off("readonly", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001745 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001746 if (get_readahead) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001747 if(!ioctl_or_warn(fd, BLKRAGET, (unsigned long *)parm))
1748 print_value_on_off("readahead", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001749 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001750 if (get_geom) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001751 if (!ioctl_or_warn(fd, BLKGETSIZE, &parm)) {
Rob Landley2584e9b2006-05-03 20:00:00 +00001752 struct hd_geometry g;
1753
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001754 if (!ioctl_or_warn(fd, HDIO_GETGEO, &g))
Rob Landleyadde7982006-05-16 15:32:30 +00001755 printf(" geometry\t= %u/%u/%u, sectors = %ld, start = %ld\n",
Rob Landley2584e9b2006-05-03 20:00:00 +00001756 g.cylinders, g.heads, g.sectors, parm, g.start);
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001757 }
Eric Andersen3443bd72003-07-22 07:30:36 +00001758 }
1759#ifdef HDIO_DRIVE_CMD
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001760 if (get_powermode) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001761#ifndef WIN_CHECKPOWERMODE1
1762#define WIN_CHECKPOWERMODE1 0xE5
1763#endif
1764#ifndef WIN_CHECKPOWERMODE2
1765#define WIN_CHECKPOWERMODE2 0x98
1766#endif
Eric Andersen3443bd72003-07-22 07:30:36 +00001767 const char *state;
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001768
Rob Landleye5b281f2006-04-29 15:49:18 +00001769 args[0] = WIN_CHECKPOWERMODE1;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001770 if (ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args, WIN_CHECKPOWERMODE2)) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001771 if (errno != EIO || args[0] != 0 || args[1] != 0)
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001772 state = "unknown";
Eric Andersen3443bd72003-07-22 07:30:36 +00001773 else
1774 state = "sleeping";
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001775 } else
Glenn L McGrath07085852003-10-09 07:28:22 +00001776 state = (args[2] == 255) ? "active/idle" : "standby";
Rob Landley39cf6452006-05-05 16:52:28 +00001777 args[1] = args[2] = 0;
Glenn L McGrath07085852003-10-09 07:28:22 +00001778
Eric Andersen3443bd72003-07-22 07:30:36 +00001779 printf(" drive state is: %s\n", state);
1780 }
1781#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001782#if ENABLE_FEATURE_HDPARM_HDIO_DRIVE_RESET
1783 if (perform_reset) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001784 ioctl_or_warn(fd, HDIO_DRIVE_RESET, NULL);
Eric Andersen3443bd72003-07-22 07:30:36 +00001785 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001786#endif /* FEATURE_HDPARM_HDIO_DRIVE_RESET */
1787#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1788 if (perform_tristate) {
Rob Landleye5b281f2006-04-29 15:49:18 +00001789 args[0] = 0;
1790 args[1] = tristate;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001791 ioctl_or_warn(fd, HDIO_TRISTATE_HWIF, &args);
Eric Andersen3443bd72003-07-22 07:30:36 +00001792 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001793#endif /* FEATURE_HDPARM_HDIO_TRISTATE_HWIF */
1794#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
1795 if (get_identity) {
Denis Vlasenko7c282a22007-03-28 00:14:54 +00001796 struct hd_driveid id;
Eric Andersen3443bd72003-07-22 07:30:36 +00001797
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001798 if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
1799 if (multcount != -1) {
Eric Andersen3443bd72003-07-22 07:30:36 +00001800 id.multsect = multcount;
1801 id.multsect_valid |= 1;
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001802 } else
Eric Andersen3443bd72003-07-22 07:30:36 +00001803 id.multsect_valid &= ~1;
1804 dump_identity(&id);
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001805 } else if (errno == -ENOMSG)
Eric Andersen3443bd72003-07-22 07:30:36 +00001806 printf(" no identification info available\n");
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001807 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
Denis Vlasenko49a128a2007-07-17 21:42:59 +00001808 bb_perror_msg("HDIO_GET_IDENTITY");
Eric Andersen3443bd72003-07-22 07:30:36 +00001809 else
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001810 bb_perror_msg("ioctl %#x failed", HDIO_GET_IDENTITY);
Eric Andersen3443bd72003-07-22 07:30:36 +00001811 }
Glenn L McGrath07085852003-10-09 07:28:22 +00001812
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001813 if (get_IDentity) {
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001814 unsigned char args1[4+512]; /* = { ... } will eat 0.5k of rodata! */
Glenn L McGrath07085852003-10-09 07:28:22 +00001815
Rob Landley5f8b5ec2006-04-29 16:03:40 +00001816 memset(args1, 0, sizeof(args1));
1817 args1[0] = WIN_IDENTIFY;
1818 args1[3] = 1;
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001819 if (!ioctl_alt_or_warn(fd, HDIO_DRIVE_CMD, args1, WIN_PIDENTIFY))
Rob Landley0753f4a2006-06-07 00:27:25 +00001820 identify((void *)(args1 + 4));
Eric Andersen3443bd72003-07-22 07:30:36 +00001821 }
1822#endif
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001823#if ENABLE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
1824 if (set_busstate) {
1825 if (get_busstate) {
Rob Landleyadde7982006-05-16 15:32:30 +00001826 print_flag(1, "bus state", busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001827 bus_state_value(busstate);
1828 }
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001829 ioctl_or_warn(fd, HDIO_SET_BUSSTATE, (int *)(unsigned long)busstate);
Eric Andersen3443bd72003-07-22 07:30:36 +00001830 }
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001831 if (get_busstate) {
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001832 if (!ioctl_or_warn(fd, HDIO_GET_BUSSTATE, &parm)) {
Rob Landleyadde7982006-05-16 15:32:30 +00001833 printf(fmt, "bus state", parm);
Eric Andersen3443bd72003-07-22 07:30:36 +00001834 bus_state_value(parm);
1835 }
1836 }
1837#endif
Glenn L McGrath07085852003-10-09 07:28:22 +00001838 if (reread_partn)
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00001839 ioctl_or_warn(fd, BLKRRPART, NULL);
Glenn L McGrath07085852003-10-09 07:28:22 +00001840
Eric Andersen3443bd72003-07-22 07:30:36 +00001841 if (do_ctimings)
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001842 do_time(0, fd); /* time cache */
Eric Andersen3443bd72003-07-22 07:30:36 +00001843 if (do_timings)
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001844 do_time(1, fd); /* time device */
Eric Andersen3443bd72003-07-22 07:30:36 +00001845 if (do_flush)
Rob Landleya3e4f382006-04-29 16:06:31 +00001846 flush_buffer_cache(fd);
1847 close(fd);
Eric Andersen3443bd72003-07-22 07:30:36 +00001848}
1849
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001850#if ENABLE_FEATURE_HDPARM_GET_IDENTITY
Rob Landleya3e4f382006-04-29 16:06:31 +00001851static int fromhex(unsigned char c)
Eric Andersen3443bd72003-07-22 07:30:36 +00001852{
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001853 if (isdigit(c))
Eric Andersen3443bd72003-07-22 07:30:36 +00001854 return (c - '0');
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001855 if (c >= 'a' && c <= 'f')
1856 return (c - ('a' - 10));
Eric Andersen3443bd72003-07-22 07:30:36 +00001857 bb_error_msg_and_die("bad char: '%c' 0x%02x", c, c);
1858}
1859
Rob Landley0f0b6452006-05-03 18:28:06 +00001860static void identify_from_stdin(void)
Eric Andersen3443bd72003-07-22 07:30:36 +00001861{
Rob Landley0753f4a2006-06-07 00:27:25 +00001862 uint16_t sbuf[256];
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001863 unsigned char buf[1280];
1864 unsigned char *b = (unsigned char *)buf;
1865 int i;
Eric Andersen3443bd72003-07-22 07:30:36 +00001866
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001867 xread(0, buf, 1280);
Rob Landleyade7f952006-05-25 18:53:06 +00001868
Rob Landley0753f4a2006-06-07 00:27:25 +00001869 // Convert the newline-separated hex data into an identify block.
1870
Denis Vlasenko3bf00202007-02-18 13:36:04 +00001871 for (i = 0; i < 256; i++) {
Rob Landley0753f4a2006-06-07 00:27:25 +00001872 int j;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001873 for (j = 0; j < 4; j++)
Denis Vlasenko3a34d0c2007-01-12 22:10:34 +00001874 sbuf[i] = (sbuf[i] << 4) + fromhex(*(b++));
Eric Andersen3443bd72003-07-22 07:30:36 +00001875 }
Rob Landley0753f4a2006-06-07 00:27:25 +00001876
1877 // Parse the data.
1878
Rob Landley6389ff12006-05-01 19:28:53 +00001879 identify(sbuf);
Eric Andersen3443bd72003-07-22 07:30:36 +00001880}
1881#endif
1882
Rob Landley20deab02006-05-07 23:34:15 +00001883/* busybox specific stuff */
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001884static void parse_opts(smallint *get, smallint *set, unsigned long *value, int min, int max)
Eric Andersenb2aa7762004-04-05 13:08:08 +00001885{
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001886 if (get) {
1887 *get = 1;
1888 }
1889 if (optarg) {
1890 *set = 1;
Denis Vlasenko13858992006-10-08 12:49:22 +00001891 *value = xatol_range(optarg, min, max);
Denis Vlasenko6429aab2006-09-23 12:22:11 +00001892 }
Rob Landley20deab02006-05-07 23:34:15 +00001893}
1894
Denis Vlasenko0eec4ab2007-03-28 01:00:45 +00001895static void parse_xfermode(int flag, smallint *get, smallint *set, int *value)
Rob Landley20deab02006-05-07 23:34:15 +00001896{
1897 if (flag) {
Rob Landleyade7f952006-05-25 18:53:06 +00001898 *get = 1;
Rob Landley20deab02006-05-07 23:34:15 +00001899 if (optarg) {
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001900 *value = translate_xfermode(optarg);
1901 *set = (*value > -1);
Rob Landley20deab02006-05-07 23:34:15 +00001902 }
1903 }
1904}
1905
Rob Landley06208412006-05-31 22:52:57 +00001906/*------- getopt short options --------*/
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001907static const char hdparm_options[] ALIGN1 =
1908 "gfu::n::p:r::m::c::k::a::B:tTh"
Rob Landley06208412006-05-31 22:52:57 +00001909 USE_FEATURE_HDPARM_GET_IDENTITY("iI")
Rob Landley20deab02006-05-07 23:34:15 +00001910 USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
1911#ifdef HDIO_DRIVE_CMD
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001912 "S:D:P:X:K:A:L:W:CyYzZ"
Rob Landley20deab02006-05-07 23:34:15 +00001913#endif
1914 USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
1915#ifdef HDIO_GET_QDMA
1916#ifdef HDIO_SET_QDMA
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001917 "Q:"
Rob Landley20deab02006-05-07 23:34:15 +00001918#else
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001919 "Q"
Rob Landley20deab02006-05-07 23:34:15 +00001920#endif
1921#endif
1922 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
1923 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
1924 USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
1925/*-------------------------------------*/
1926
1927/* our main() routine: */
Denis Vlasenko06af2162007-02-03 17:28:39 +00001928int hdparm_main(int argc, char **argv);
Rob Landley20deab02006-05-07 23:34:15 +00001929int hdparm_main(int argc, char **argv)
1930{
1931 int c;
Rob Landleyade7f952006-05-25 18:53:06 +00001932 int flagcount = 0;
Rob Landley20deab02006-05-07 23:34:15 +00001933
Rob Landley06208412006-05-31 22:52:57 +00001934 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
Rob Landley20deab02006-05-07 23:34:15 +00001935 flagcount++;
Rob Landley06208412006-05-31 22:52:57 +00001936 if (c == 'h') bb_show_usage(); /* EXIT */
Mike Frysingerea93f8a2006-06-07 14:25:22 +00001937 USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
1938 USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
Rob Landleyadde7982006-05-16 15:32:30 +00001939 get_geom |= (c == 'g');
1940 do_flush |= (c == 'f');
Rob Landley19802562006-05-08 15:35:46 +00001941 if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
1942 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
1943 if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001944 parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
Rob Landley19802562006-05-08 15:35:46 +00001945 if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
1946 if (c == 'm') parse_opts(&get_mult, &set_mult, &mult, 0, INT_MAX /*32*/);
1947 if (c == 'c') parse_opts(&get_io32bit, &set_io32bit, &io32bit, 0, INT_MAX /*8*/);
1948 if (c == 'k') parse_opts(&get_keep, &set_keep, &keep, 0, 1);
1949 if (c == 'a') parse_opts(&get_readahead, &set_readahead, &Xreadahead, 0, INT_MAX);
1950 if (c == 'B') parse_opts(&get_apmmode, &set_apmmode, &apmmode, 1, 255);
Rob Landleyadde7982006-05-16 15:32:30 +00001951 do_flush |= do_timings |= (c == 't');
1952 do_flush |= do_ctimings |= (c == 'T');
Rob Landley20deab02006-05-07 23:34:15 +00001953#ifdef HDIO_DRIVE_CMD
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001954 if (c == 'S') parse_opts(&get_standby, &set_standby, &standby_requested, 0, INT_MAX);
Rob Landley19802562006-05-08 15:35:46 +00001955 if (c == 'D') parse_opts(&get_defects, &set_defects, &defects, 0, INT_MAX);
1956 if (c == 'P') parse_opts(&get_prefetch, &set_prefetch, &prefetch, 0, INT_MAX);
Rob Landleyade7f952006-05-25 18:53:06 +00001957 parse_xfermode((c == 'X'), &get_xfermode, &set_xfermode, &xfermode_requested);
Rob Landley19802562006-05-08 15:35:46 +00001958 if (c == 'K') parse_opts(&get_dkeep, &set_dkeep, &prefetch, 0, 1);
1959 if (c == 'A') parse_opts(&get_lookahead, &set_lookahead, &lookahead, 0, 1);
1960 if (c == 'L') parse_opts(&get_doorlock, &set_doorlock, &doorlock, 0, 1);
1961 if (c == 'W') parse_opts(&get_wcache, &set_wcache, &wcache, 0, 1);
Rob Landleyade7f952006-05-25 18:53:06 +00001962 get_powermode |= (c == 'C');
1963 get_standbynow = set_standbynow |= (c == 'y');
1964 get_sleepnow = set_sleepnow |= (c == 'Y');
Rob Landleyadde7982006-05-16 15:32:30 +00001965 reread_partn |= (c == 'z');
Rob Landleyade7f952006-05-25 18:53:06 +00001966 get_seagate = set_seagate |= (c == 'Z');
Rob Landley20deab02006-05-07 23:34:15 +00001967#endif
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001968 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 +00001969#ifdef HDIO_GET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00001970 if (c == 'Q') {
Rob Landley20deab02006-05-07 23:34:15 +00001971#ifdef HDIO_SET_QDMA
Rob Landley19802562006-05-08 15:35:46 +00001972 parse_opts(&get_dma_q, &set_dma_q, &dma_q, 0, INT_MAX);
Rob Landley20deab02006-05-07 23:34:15 +00001973#else
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001974 parse_opts(&get_dma_q, NULL, NULL, 0, 0);
Rob Landley20deab02006-05-07 23:34:15 +00001975#endif
Rob Landley19802562006-05-08 15:35:46 +00001976 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001977#endif
Rob Landleyade7f952006-05-25 18:53:06 +00001978 USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001979 USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
1980 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 +00001981#if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
1982 if (c == 'R') {
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001983 parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
Denis Vlasenko13858992006-10-08 12:49:22 +00001984 hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : "");
1985 hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : "");
Rob Landley20deab02006-05-07 23:34:15 +00001986 /* Move past the 2 additional arguments */
1987 argv += 2;
1988 argc -= 2;
1989 }
1990#endif
1991 }
Rob Landleyade7f952006-05-25 18:53:06 +00001992 /* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001993 if (!flagcount) {
Rob Landleyade7f952006-05-25 18:53:06 +00001994 get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
1995 USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
1996 }
Rob Landley20deab02006-05-07 23:34:15 +00001997 argv += optind;
1998
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00001999 if (!*argv) {
Rob Landley6d8ce172006-06-07 21:22:42 +00002000 if (ENABLE_FEATURE_HDPARM_GET_IDENTITY && !isatty(STDIN_FILENO))
2001 identify_from_stdin(); /* EXIT */
2002 else bb_show_usage();
Rob Landley20deab02006-05-07 23:34:15 +00002003 }
2004
Denis Vlasenkof1ba7492007-03-28 00:14:01 +00002005 do {
2006 process_dev(*argv++);
2007 } while (*argv);
2008
2009 return EXIT_SUCCESS;
Eric Andersen3443bd72003-07-22 07:30:36 +00002010}