Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sbin / natacontrol / natacontrol.c
blob594b4b088a9523369cae8cd3ba60eeb5660d0999
1 /*-
2 * Copyright (c) 2000 - 2006 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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.42 2006/03/15 19:32:43 sos Exp $
27 * $DragonFly: src/sbin/natacontrol/natacontrol.c,v 1.3 2008/09/04 21:00:28 swildner Exp $
30 #include <sys/nata.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <err.h>
39 #include <sysexits.h>
40 #include <unistd.h>
42 static const char *mode2str(int mode);
43 static int str2mode(char *str);
44 static void usage(void);
45 static int version(int ver);
46 static void param_print(struct ata_params *parm);
47 static void cap_print(struct ata_params *parm);
48 static int ata_cap_print(int fd);
49 static int info_print(int fd, int channel, int prchan);
51 const char *
52 mode2str(int mode)
54 switch (mode) {
55 case ATA_PIO: return "BIOSPIO";
56 case ATA_PIO0: return "PIO0";
57 case ATA_PIO1: return "PIO1";
58 case ATA_PIO2: return "PIO2";
59 case ATA_PIO3: return "PIO3";
60 case ATA_PIO4: return "PIO4";
61 case ATA_WDMA2: return "WDMA2";
62 case ATA_UDMA2: return "UDMA33";
63 case ATA_UDMA4: return "UDMA66";
64 case ATA_UDMA5: return "UDMA100";
65 case ATA_UDMA6: return "UDMA133";
66 case ATA_SA150: return "SATA150";
67 case ATA_SA300: return "SATA300";
68 case ATA_USB: return "USB";
69 case ATA_USB1: return "USB1";
70 case ATA_USB2: return "USB2";
71 case ATA_DMA: return "BIOSDMA";
72 default: return "???";
76 int
77 str2mode(char *str)
79 if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
80 if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
81 if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
82 if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
83 if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
84 if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
85 if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
86 if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
87 if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
88 if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
89 if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
90 if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
91 if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
92 if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
93 if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
94 if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
95 return -1;
98 void
99 usage(void)
101 fprintf(stderr,
102 "usage: natacontrol <command> args:\n"
103 " natacontrol list\n"
104 " natacontrol info channel\n"
105 " natacontrol attach channel\n"
106 " natacontrol detach channel\n"
107 " natacontrol reinit channel\n"
108 " natacontrol create type [interleave] disk0 ... diskN\n"
109 " natacontrol delete array\n"
110 " natacontrol addspare array disk\n"
111 " natacontrol rebuild array\n"
112 " natacontrol status array\n"
113 " natacontrol mode device [mode]\n"
114 " natacontrol cap device\n"
116 exit(EX_USAGE);
120 version(int ver)
122 int bit;
124 if (ver == 0xffff)
125 return 0;
126 for (bit = 15; bit >= 0; bit--)
127 if (ver & (1<<bit))
128 return bit;
129 return 0;
132 void
133 param_print(struct ata_params *parm)
135 printf("<%.40s/%.8s> ", parm->model, parm->revision);
136 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
137 if (parm->satacapabilities & ATA_SATA_GEN2)
138 printf("Serial ATA II\n");
139 else if (parm->satacapabilities & ATA_SATA_GEN1)
140 printf("Serial ATA v1.0\n");
141 else
142 printf("Unknown serial ATA version\n");
144 else
145 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
148 void
149 cap_print(struct ata_params *parm)
151 u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
152 ((u_int32_t)parm->lba_size_2 << 16);
154 u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
155 ((u_int64_t)parm->lba_size48_2 << 16) |
156 ((u_int64_t)parm->lba_size48_3 << 32) |
157 ((u_int64_t)parm->lba_size48_4 << 48);
159 printf("\n");
160 printf("Protocol ");
161 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
162 if (parm->satacapabilities & ATA_SATA_GEN2)
163 printf("Serial ATA II\n");
164 else if (parm->satacapabilities & ATA_SATA_GEN1)
165 printf("Serial ATA v1.0\n");
166 else
167 printf("Unknown serial ATA version\n");
169 else
170 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
171 printf("device model %.40s\n", parm->model);
172 printf("serial number %.20s\n", parm->serial);
173 printf("firmware revision %.8s\n", parm->revision);
175 printf("cylinders %d\n", parm->cylinders);
176 printf("heads %d\n", parm->heads);
177 printf("sectors/track %d\n", parm->sectors);
179 printf("lba%ssupported ",
180 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
181 if (lbasize)
182 printf("%d sectors\n", lbasize);
183 else
184 printf("\n");
186 printf("lba48%ssupported ",
187 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
188 if (lbasize48)
189 printf("%llu sectors\n", (unsigned long long)lbasize48);
190 else
191 printf("\n");
193 printf("dma%ssupported\n",
194 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
196 printf("overlap%ssupported\n",
197 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
199 printf("\nFeature "
200 "Support Enable Value Vendor\n");
202 printf("write cache %s %s\n",
203 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
204 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
206 printf("read ahead %s %s\n",
207 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
208 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
210 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
211 printf("Native Command Queuing (NCQ) %s %s"
212 " %d/0x%02X\n",
213 parm->satacapabilities & ATA_SUPPORT_NCQ ?
214 "yes" : "no", " -",
215 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
216 ATA_QUEUE_LEN(parm->queue) : 0,
217 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
218 ATA_QUEUE_LEN(parm->queue) : 0);
220 printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n",
221 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
222 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
223 ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
225 printf("SMART %s %s\n",
226 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
227 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
229 printf("microcode download %s %s\n",
230 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
231 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
233 printf("security %s %s\n",
234 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
235 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
237 printf("power management %s %s\n",
238 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
239 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
241 printf("advanced power management %s %s %d/0x%02X\n",
242 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
243 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
244 parm->apm_value, parm->apm_value);
246 printf("automatic acoustic management %s %s "
247 "%d/0x%02X %d/0x%02X\n",
248 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
249 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
250 ATA_ACOUSTIC_CURRENT(parm->acoustic),
251 ATA_ACOUSTIC_CURRENT(parm->acoustic),
252 ATA_ACOUSTIC_VENDOR(parm->acoustic),
253 ATA_ACOUSTIC_VENDOR(parm->acoustic));
257 ata_cap_print(int fd)
259 struct ata_params params;
261 if (ioctl(fd, IOCATAGPARM, &params) < 0)
262 return errno;
263 cap_print(&params);
264 return 0;
268 info_print(int fd, int channel, int prchan)
270 struct ata_ioc_devices devices;
272 devices.channel = channel;
274 if (ioctl(fd, IOCATADEVICES, &devices) < 0)
275 return errno;
277 if (prchan)
278 printf("ATA channel %d:\n", channel);
279 printf("%sMaster: ", prchan ? " " : "");
280 if (*devices.name[0]) {
281 printf("%4.4s ", devices.name[0]);
282 param_print(&devices.params[0]);
284 else
285 printf(" no device present\n");
286 printf("%sSlave: ", prchan ? " " : "");
287 if (*devices.name[1]) {
288 printf("%4.4s ", devices.name[1]);
289 param_print(&devices.params[1]);
291 else
292 printf(" no device present\n");
293 return 0;
297 main(int argc, char **argv)
299 int fd;
301 if (argc < 2)
302 usage();
304 if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
305 int disk, mode;
306 char device[64];
308 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
309 sscanf(argv[2], "acd%d", &disk) == 1 ||
310 sscanf(argv[2], "afd%d", &disk) == 1 ||
311 sscanf(argv[2], "ast%d", &disk) == 1)) {
312 fprintf(stderr, "natacontrol: Invalid device %s\n",
313 argv[2]);
314 exit(EX_USAGE);
316 sprintf(device, "/dev/%s", argv[2]);
317 if ((fd = open(device, O_RDONLY)) < 0)
318 err(1, "device not found");
319 if (argc == 4) {
320 mode = str2mode(argv[3]);
321 if (ioctl(fd, IOCATASMODE, &mode) < 0)
322 warn("ioctl(IOCATASMODE)");
324 if (argc == 3 || argc == 4) {
325 if (ioctl(fd, IOCATAGMODE, &mode) < 0)
326 err(1, "ioctl(IOCATAGMODE)");
327 printf("current mode = %s\n", mode2str(mode));
329 exit(EX_OK);
331 if (!strcmp(argv[1], "cap") && argc == 3) {
332 int disk;
333 char device[64];
335 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
336 sscanf(argv[2], "acd%d", &disk) == 1 ||
337 sscanf(argv[2], "afd%d", &disk) == 1 ||
338 sscanf(argv[2], "ast%d", &disk) == 1)) {
339 fprintf(stderr, "natacontrol: Invalid device %s\n",
340 argv[2]);
341 exit(EX_USAGE);
343 sprintf(device, "/dev/%s", argv[2]);
344 if ((fd = open(device, O_RDONLY)) < 0)
345 err(1, "device not found");
346 ata_cap_print(fd);
347 exit(EX_OK);
350 if ((fd = open("/dev/ata", O_RDWR)) < 0)
351 err(1, "control device not found");
353 if (!strcmp(argv[1], "list") && argc == 2) {
354 int maxchannel, channel;
356 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
357 err(1, "ioctl(IOCATAGMAXCHANNEL)");
358 for (channel = 0; channel < maxchannel; channel++)
359 info_print(fd, channel, 1);
360 exit(EX_OK);
362 if (!strcmp(argv[1], "info") && argc == 3) {
363 int channel;
365 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
366 fprintf(stderr,
367 "natacontrol: Invalid channel %s\n", argv[2]);
368 exit(EX_USAGE);
370 info_print(fd, channel, 0);
371 exit(EX_OK);
373 if (!strcmp(argv[1], "detach") && argc == 3) {
374 int channel;
376 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
377 fprintf(stderr,
378 "natacontrol: Invalid channel %s\n", argv[2]);
379 exit(EX_USAGE);
381 if (ioctl(fd, IOCATADETACH, &channel) < 0)
382 err(1, "ioctl(IOCATADETACH)");
383 exit(EX_OK);
385 if (!strcmp(argv[1], "attach") && argc == 3) {
386 int channel;
388 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
389 fprintf(stderr,
390 "natacontrol: Invalid channel %s\n", argv[2]);
391 exit(EX_USAGE);
393 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
394 err(1, "ioctl(IOCATAATTACH)");
395 info_print(fd, channel, 0);
396 exit(EX_OK);
398 if (!strcmp(argv[1], "reinit") && argc == 3) {
399 int channel;
401 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
402 fprintf(stderr,
403 "natacontrol: Invalid channel %s\n", argv[2]);
404 exit(EX_USAGE);
406 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
407 warn("ioctl(IOCATAREINIT)");
408 info_print(fd, channel, 0);
409 exit(EX_OK);
411 if (!strcmp(argv[1], "create")) {
412 int disk, dev, offset;
413 struct ata_ioc_raid_config config;
415 bzero(&config, sizeof(config));
416 if (argc > 2) {
417 if (!strcasecmp(argv[2], "RAID0") ||
418 !strcasecmp(argv[2], "stripe"))
419 config.type = AR_RAID0;
420 if (!strcasecmp(argv[2], "RAID1") ||
421 !strcasecmp(argv[2],"mirror"))
422 config.type = AR_RAID1;
423 if (!strcasecmp(argv[2], "RAID0+1") ||
424 !strcasecmp(argv[2],"RAID10"))
425 config.type = AR_RAID01;
426 if (!strcasecmp(argv[2], "RAID5"))
427 config.type = AR_RAID5;
428 if (!strcasecmp(argv[2], "SPAN"))
429 config.type = AR_SPAN;
430 if (!strcasecmp(argv[2], "JBOD"))
431 config.type = AR_JBOD;
433 if (!config.type) {
434 fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
435 argv[2]);
436 fprintf(stderr, "natacontrol: Valid RAID types: \n");
437 fprintf(stderr, " stripe | mirror | "
438 "RAID0 | RAID1 | RAID0+1 | RAID5 | "
439 "SPAN | JBOD\n");
440 exit(EX_USAGE);
443 if (config.type == AR_RAID0 ||
444 config.type == AR_RAID01 ||
445 config.type == AR_RAID5) {
446 if (argc < 4 ||
447 !sscanf(argv[3], "%d", &config.interleave) == 1) {
448 fprintf(stderr,
449 "natacontrol: Invalid interleave %s\n",
450 argv[3]);
451 exit(EX_USAGE);
453 offset = 4;
455 else
456 offset = 3;
458 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
459 if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
460 fprintf(stderr,
461 "natacontrol: Invalid disk %s\n",
462 argv[offset + disk]);
463 exit(EX_USAGE);
465 config.disks[disk] = dev;
468 if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
469 disk < 2) {
470 fprintf(stderr, "natacontrol: At least 2 disks must be "
471 "specified\n");
472 exit(EX_USAGE);
475 config.total_disks = disk;
476 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
477 err(1, "ioctl(IOCATARAIDCREATE)");
478 else
479 printf("ar%d created\n", config.lun);
480 exit(EX_OK);
482 if (!strcmp(argv[1], "delete") && argc == 3) {
483 int array;
485 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
486 fprintf(stderr,
487 "natacontrol: Invalid array %s\n", argv[2]);
488 exit(EX_USAGE);
490 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
491 warn("ioctl(IOCATARAIDDELETE)");
492 exit(EX_OK);
494 if (!strcmp(argv[1], "addspare") && argc == 4) {
495 struct ata_ioc_raid_config config;
497 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
498 fprintf(stderr,
499 "natacontrol: Invalid array %s\n", argv[2]);
500 usage();
502 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
503 fprintf(stderr,
504 "natacontrol: Invalid disk %s\n", argv[3]);
505 usage();
507 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
508 warn("ioctl(IOCATARAIDADDSPARE)");
509 exit(EX_OK);
511 if (!strcmp(argv[1], "rebuild") && argc == 3) {
512 int array;
514 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
515 fprintf(stderr,
516 "natacontrol: Invalid array %s\n", argv[2]);
517 usage();
519 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
520 warn("ioctl(IOCATARAIDREBUILD)");
521 else {
522 char device[64];
523 char *buffer;
524 ssize_t len;
525 int arfd;
527 if (daemon(0, 1) == -1)
528 err(1, "daemon");
529 nice(20);
530 snprintf(device, sizeof(device), "/dev/ar%d",
531 array);
532 if ((arfd = open(device, O_RDONLY)) == -1)
533 err(1, "open %s", device);
534 if ((buffer = malloc(1024 * 1024)) == NULL)
535 err(1, "malloc");
536 while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
538 if (len == -1)
539 err(1, "read");
540 else
541 fprintf(stderr,
542 "atacontrol: ar%d rebuild completed\n",
543 array);
544 free(buffer);
545 close(arfd);
547 exit(EX_OK);
549 if (!strcmp(argv[1], "status") && argc == 3) {
550 struct ata_ioc_raid_config config;
551 int i;
553 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
554 fprintf(stderr,
555 "natacontrol: Invalid array %s\n", argv[2]);
556 usage();
558 if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
559 err(1, "ioctl(IOCATARAIDSTATUS)");
561 printf("ar%d: ATA ", config.lun);
562 switch (config.type) {
563 case AR_RAID0:
564 printf("RAID0 stripesize=%d", config.interleave);
565 break;
566 case AR_RAID1:
567 printf("RAID1");
568 break;
569 case AR_RAID01:
570 printf("RAID0+1 stripesize=%d", config.interleave);
571 break;
572 case AR_RAID5:
573 printf("RAID5 stripesize=%d", config.interleave);
574 break;
575 case AR_JBOD:
576 printf("JBOD");
577 case AR_SPAN:
578 printf("SPAN");
579 break;
581 printf(" subdisks: ");
582 for (i = 0; i < config.total_disks; i++) {
583 if (config.disks[i] >= 0)
584 printf("ad%d ", config.disks[i]);
585 else
586 printf("DOWN ");
588 printf("status: ");
589 switch (config.status) {
590 case AR_READY:
591 printf("READY\n");
592 break;
593 case AR_READY | AR_DEGRADED:
594 printf("DEGRADED\n");
595 break;
596 case AR_READY | AR_DEGRADED | AR_REBUILDING:
597 printf("REBUILDING %d%% completed\n",
598 config.progress);
599 break;
600 default:
601 printf("BROKEN\n");
603 exit(EX_OK);
605 usage();
606 exit(EX_OK);