MFC: Fix a panic on boot that can occur if you hit keys on the keyboard
[dragonfly.git] / sbin / atacontrol / atacontrol.c
blob5432acfe2a658cbe826942f4fb422b8f2b6a1f5e
1 /*-
2 * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.11.2.5 2002/08/21 13:18:17 sos Exp $
29 * $DragonFly: src/sbin/atacontrol/atacontrol.c,v 1.4 2005/01/09 04:43:33 cpressey Exp $
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <err.h>
38 #include <sys/ata.h>
40 static const char *mode2str(int);
41 static int str2mode(char *);
42 static void usage(void);
43 static int version(int);
44 static void param_print(struct ata_params *);
45 static void cap_print(struct ata_params *);
46 static int ata_cap_print(int, int, int);
47 static int info_print(int, int, int);
49 const char *
50 mode2str(int mode)
52 switch (mode) {
53 case ATA_PIO: return "BIOSPIO";
54 case ATA_PIO0: return "PIO0";
55 case ATA_PIO1: return "PIO1";
56 case ATA_PIO2: return "PIO2";
57 case ATA_PIO3: return "PIO3";
58 case ATA_PIO4: return "PIO4";
59 case ATA_WDMA2: return "WDMA2";
60 case ATA_UDMA2: return "UDMA33";
61 case ATA_UDMA4: return "UDMA66";
62 case ATA_UDMA5: return "UDMA100";
63 case ATA_UDMA6: return "UDMA133";
64 case ATA_DMA: return "BIOSDMA";
65 default: return "???";
69 int
70 str2mode(char *str)
72 if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
73 if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
74 if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
75 if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
76 if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
77 if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
78 if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
79 if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
80 if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
81 if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
82 if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
83 if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
84 if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
85 if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
86 if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
87 if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
88 return -1;
92 void
93 usage(void)
95 fprintf(stderr, "usage: atacontrol <command> channel [args]\n");
96 exit(1);
99 int
100 version(int ver)
102 int bit;
104 if (ver == 0xffff)
105 return 0;
106 for (bit = 15; bit >= 0; bit--)
107 if (ver & (1 << bit))
108 return bit;
109 return 0;
112 void
113 param_print(struct ata_params *parm)
115 printf("<%.40s/%.8s> ATA/ATAPI rev %d\n",
116 parm->model, parm->revision, version(parm->version_major));
119 void
120 cap_print(struct ata_params *parm)
122 printf("\n");
123 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
124 printf("device model %.40s\n", parm->model);
125 printf("serial number %.20s\n", parm->serial);
126 printf("firmware revision %.8s\n", parm->revision);
128 printf("cylinders %d\n", parm->cylinders);
129 printf("heads %d\n", parm->heads);
130 printf("sectors/track %d\n", parm->sectors);
132 printf("lba%ssupported ", parm->support_lba ? " " : " not ");
133 if (parm->lba_size)
134 printf("%d sectors\n", parm->lba_size);
135 else
136 printf("\n");
138 printf("lba48%ssupported ", parm->support.address48 ? " " : " not ");
139 if (parm->lba_size48)
140 printf("%lld sectors\n", parm->lba_size48);
141 else
142 printf("\n");
143 printf("dma%ssupported\n", parm->support_dma ? " " : " not");
145 printf("overlap%ssupported\n", parm->support_queueing ? " " : " not ");
147 printf("\nFeature Support Enable Value Vendor\n");
149 printf("write cache %s %s\n",
150 parm->support.write_cache ? "yes" : "no",
151 parm->enabled.write_cache ? "yes" : "no");
153 printf("read ahead %s %s\n",
154 parm->support.look_ahead ? "yes" : "no",
155 parm->enabled.look_ahead ? "yes" : "no");
157 printf("dma queued %s %s %d/%02X\n",
158 parm->support.queued ? "yes" : "no",
159 parm->enabled.queued ? "yes" : "no",
160 parm->queuelen, parm->queuelen);
162 printf("SMART %s %s\n",
163 parm->support.smart ? "yes" : "no",
164 parm->enabled.smart ? "yes" : "no");
166 printf("microcode download %s %s\n",
167 parm->support.microcode ? "yes" : "no",
168 parm->enabled.microcode ? "yes" : "no");
170 printf("security %s %s\n",
171 parm->support.smart ? "yes" : "no",
172 parm->enabled.smart ? "yes" : "no");
174 printf("power management %s %s\n",
175 parm->support.power_mngt ? "yes" : "no",
176 parm->enabled.power_mngt ? "yes" : "no");
178 printf("advanced power management %s %s %d/%02X\n",
179 parm->support.apm ? "yes" : "no",
180 parm->enabled.apm ? "yes" : "no",
181 parm->apm_value, parm->apm_value);
183 printf("automatic acoustic management %s %s %d/%02X %d/%02X\n",
184 parm->support.auto_acoustic ? "yes" : "no",
185 parm->enabled.auto_acoustic ? "yes" : "no",
186 parm->current_acoustic, parm->current_acoustic,
187 parm->vendor_acoustic, parm->vendor_acoustic);
191 ata_cap_print(int fd, int channel, int device)
193 struct ata_cmd iocmd;
195 bzero(&iocmd, sizeof(struct ata_cmd));
197 iocmd.channel = channel;
198 iocmd.device = -1;
199 iocmd.cmd = ATAGPARM;
201 if (ioctl(fd, IOCATA, &iocmd) < 0)
202 return errno;
204 printf("ATA channel %d, %s", channel, device==0 ? "Master" : "Slave");
206 if (iocmd.u.param.type[device]) {
207 printf(", device %s:\n", iocmd.u.param.name[device]);
208 cap_print(&iocmd.u.param.params[device]);
210 else
211 printf(": no device present\n");
212 return 0;
216 info_print(int fd, int channel, int prchan)
218 struct ata_cmd iocmd;
220 bzero(&iocmd, sizeof(struct ata_cmd));
221 iocmd.channel = channel;
222 iocmd.device = -1;
223 iocmd.cmd = ATAGPARM;
224 if (ioctl(fd, IOCATA, &iocmd) < 0)
225 return errno;
226 if (prchan)
227 printf("ATA channel %d:\n", channel);
228 printf("%sMaster: ", prchan ? " " : "");
229 if (iocmd.u.param.type[0]) {
230 printf("%4.4s ", iocmd.u.param.name[0]);
231 param_print(&iocmd.u.param.params[0]);
233 else
234 printf(" no device present\n");
235 printf("%sSlave: ", prchan ? " " : "");
236 if (iocmd.u.param.type[1]) {
237 printf("%4.4s ", iocmd.u.param.name[1]);
238 param_print(&iocmd.u.param.params[1]);
240 else
241 printf(" no device present\n");
242 return 0;
246 main(int argc, char **argv)
248 struct ata_cmd iocmd;
249 int fd;
251 if ((fd = open("/dev/ata", O_RDWR)) < 0)
252 err(1, "control device not found");
254 if (argc < 2)
255 usage();
257 bzero(&iocmd, sizeof(struct ata_cmd));
259 if (argc > 2 && strcmp(argv[1], "create")) {
260 int chan;
262 if (!strcmp(argv[1], "delete") ||
263 !strcmp(argv[1], "status") ||
264 !strcmp(argv[1], "rebuild")) {
265 if (!(sscanf(argv[2], "%d", &chan) == 1 ||
266 sscanf(argv[2], "ar%d", &chan) == 1))
267 usage();
269 else {
270 if (!(sscanf(argv[2], "%d", &chan) == 1 ||
271 sscanf(argv[2], "ata%d", &chan) == 1))
272 usage();
274 iocmd.channel = chan;
277 if (!strcmp(argv[1], "list") && argc == 2) {
278 int unit = 0;
280 while (info_print(fd, unit++, 1) != ENXIO);
282 else if (!strcmp(argv[1], "info") && argc == 3) {
283 info_print(fd, iocmd.channel, 0);
285 else if (!strcmp(argv[1], "cap") && argc == 4) {
286 ata_cap_print(fd, iocmd.channel, atoi(argv[3]));
288 else if (!strcmp(argv[1], "enclosure") && argc == 4) {
289 iocmd.device = atoi(argv[3]);
290 iocmd.cmd = ATAENCSTAT;
291 if (ioctl(fd, IOCATA, &iocmd) < 0)
292 err(1, "ioctl(ATAENCSTAT)");
293 printf("fan RPM: %d temp: %.1f 5V: %.2f 12V: %.2f\n",
294 iocmd.u.enclosure.fan,
295 (double)iocmd.u.enclosure.temp / 10,
296 (double)iocmd.u.enclosure.v05 / 1000,
297 (double)iocmd.u.enclosure.v12 / 1000);
299 else if (!strcmp(argv[1], "detach") && argc == 3) {
300 iocmd.cmd = ATADETACH;
301 if (ioctl(fd, IOCATA, &iocmd) < 0)
302 err(1, "ioctl(ATADETACH)");
304 else if (!strcmp(argv[1], "attach") && argc == 3) {
305 iocmd.cmd = ATAATTACH;
306 if (ioctl(fd, IOCATA, &iocmd) < 0)
307 err(1, "ioctl(ATAATTACH)");
308 info_print(fd, iocmd.channel, 0);
310 else if (!strcmp(argv[1], "reinit") && argc == 3) {
311 iocmd.cmd = ATAREINIT;
312 if (ioctl(fd, IOCATA, &iocmd) < 0)
313 warn("ioctl(ATAREINIT)");
314 info_print(fd, iocmd.channel, 0);
316 else if (!strcmp(argv[1], "create")) {
317 int disk, dev, offset;
319 iocmd.cmd = ATARAIDCREATE;
320 if (!strcmp(argv[2], "RAID0") || !strcmp(argv[2], "stripe"))
321 iocmd.u.raid_setup.type = 1;
322 if (!strcmp(argv[2], "RAID1") || !strcmp(argv[2],"mirror"))
323 iocmd.u.raid_setup.type = 2;
324 if (!strcmp(argv[2], "RAID0+1"))
325 iocmd.u.raid_setup.type = 3;
326 if (!strcmp(argv[2], "SPAN") || !strcmp(argv[2], "JBOD"))
327 iocmd.u.raid_setup.type = 4;
328 if (!iocmd.u.raid_setup.type)
329 usage();
331 if (iocmd.u.raid_setup.type & 1) {
332 if (!sscanf(argv[3], "%d",
333 &iocmd.u.raid_setup.interleave) == 1)
334 usage();
335 offset = 4;
337 else
338 offset = 3;
340 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
341 if (!(sscanf(argv[offset + disk], "%d", &dev) == 1 ||
342 sscanf(argv[offset + disk], "ad%d", &dev) == 1))
343 usage();
344 iocmd.u.raid_setup.disks[disk] = dev;
346 iocmd.u.raid_setup.total_disks = disk;
347 if (ioctl(fd, IOCATA, &iocmd) < 0)
348 err(1, "ioctl(ATARAIDCREATE)");
349 else
350 printf("ar%d created\n", iocmd.u.raid_setup.unit);
352 else if (!strcmp(argv[1], "delete") && argc == 3) {
353 iocmd.cmd = ATARAIDDELETE;
354 if (ioctl(fd, IOCATA, &iocmd) < 0)
355 warn("ioctl(ATARAIDDELETE)");
357 else if (!strcmp(argv[1], "rebuild") && argc == 3) {
358 iocmd.cmd = ATARAIDREBUILD;
359 if (ioctl(fd, IOCATA, &iocmd) < 0)
360 warn("ioctl(ATARAIDREBUILD)");
362 else if (!strcmp(argv[1], "status") && argc == 3) {
363 int i;
365 iocmd.cmd = ATARAIDSTATUS;
366 if (ioctl(fd, IOCATA, &iocmd) < 0)
367 err(1, "ioctl(ATARAIDSTATUS)");
368 printf("ar%d: ATA ", iocmd.channel);
369 switch (iocmd.u.raid_status.type) {
370 case AR_RAID0:
371 printf("RAID0");
372 break;
373 case AR_RAID1:
374 printf("RAID1");
375 break;
376 case AR_RAID0 | AR_RAID1:
377 printf("RAID0+1");
378 break;
379 case AR_SPAN:
380 printf("SPAN");
381 break;
383 printf(" subdisks: ");
384 for (i = 0; i < iocmd.u.raid_status.total_disks; i++) {
385 if (iocmd.u.raid_status.disks[i] >= 0)
386 printf("ad%d ", iocmd.u.raid_status.disks[i]);
387 else
388 printf("DOWN ");
390 printf("status: ");
391 switch (iocmd.u.raid_status.status) {
392 case AR_READY:
393 printf("READY\n");
394 break;
395 case AR_READY | AR_DEGRADED:
396 printf("DEGRADED\n");
397 break;
398 case AR_READY | AR_DEGRADED | AR_REBUILDING:
399 printf("REBUILDING %d%% completed\n",
400 iocmd.u.raid_status.progress);
401 break;
402 default:
403 printf("BROKEN\n");
406 else if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 5)) {
407 if (argc == 5) {
408 iocmd.cmd = ATASMODE;
409 iocmd.device = -1;
410 iocmd.u.mode.mode[0] = str2mode(argv[3]);
411 iocmd.u.mode.mode[1] = str2mode(argv[4]);
412 if (ioctl(fd, IOCATA, &iocmd) < 0)
413 warn("ioctl(ATASMODE)");
415 if (argc == 3 || argc == 5) {
416 iocmd.cmd = ATAGMODE;
417 iocmd.device = -1;
418 if (ioctl(fd, IOCATA, &iocmd) < 0)
419 err(1, "ioctl(ATAGMODE)");
420 printf("Master = %s \nSlave = %s\n",
421 mode2str(iocmd.u.mode.mode[0]),
422 mode2str(iocmd.u.mode.mode[1]));
425 else
426 usage();
427 exit(0);