If snapshots are disabled and the snapshots directory contains no
[dragonfly.git] / sbin / natacontrol / natacontrol.c
blob8671897d6498f08c407d302290708490037af70e
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>
41 static const char *mode2str(int mode);
42 static int str2mode(char *str);
43 static void usage(void);
44 static int version(int ver);
45 static void param_print(struct ata_params *parm);
46 static void cap_print(struct ata_params *parm);
47 static int ata_cap_print(int fd);
48 static int info_print(int fd, int channel, int prchan);
50 const char *
51 mode2str(int mode)
53 switch (mode) {
54 case ATA_PIO: return "BIOSPIO";
55 case ATA_PIO0: return "PIO0";
56 case ATA_PIO1: return "PIO1";
57 case ATA_PIO2: return "PIO2";
58 case ATA_PIO3: return "PIO3";
59 case ATA_PIO4: return "PIO4";
60 case ATA_WDMA2: return "WDMA2";
61 case ATA_UDMA2: return "UDMA33";
62 case ATA_UDMA4: return "UDMA66";
63 case ATA_UDMA5: return "UDMA100";
64 case ATA_UDMA6: return "UDMA133";
65 case ATA_SA150: return "SATA150";
66 case ATA_SA300: return "SATA300";
67 case ATA_USB: return "USB";
68 case ATA_USB1: return "USB1";
69 case ATA_USB2: return "USB2";
70 case ATA_DMA: return "BIOSDMA";
71 default: return "???";
75 int
76 str2mode(char *str)
78 if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
79 if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
80 if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
81 if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
82 if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
83 if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
84 if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
85 if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
86 if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
87 if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
88 if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
89 if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
90 if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
91 if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
92 if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
93 if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
94 return -1;
97 void
98 usage(void)
100 fprintf(stderr,
101 "usage: natacontrol <command> args:\n"
102 " natacontrol list\n"
103 " natacontrol info channel\n"
104 " natacontrol attach channel\n"
105 " natacontrol detach channel\n"
106 " natacontrol reinit channel\n"
107 " natacontrol create type [interleave] disk0 ... diskN\n"
108 " natacontrol delete array\n"
109 " natacontrol addspare array disk\n"
110 " natacontrol rebuild array\n"
111 " natacontrol status array\n"
112 " natacontrol mode device [mode]\n"
113 " natacontrol cap device\n"
115 exit(EX_USAGE);
119 version(int ver)
121 int bit;
123 if (ver == 0xffff)
124 return 0;
125 for (bit = 15; bit >= 0; bit--)
126 if (ver & (1<<bit))
127 return bit;
128 return 0;
131 void
132 param_print(struct ata_params *parm)
134 printf("<%.40s/%.8s> ", parm->model, parm->revision);
135 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
136 if (parm->satacapabilities & ATA_SATA_GEN2)
137 printf("Serial ATA II\n");
138 else if (parm->satacapabilities & ATA_SATA_GEN1)
139 printf("Serial ATA v1.0\n");
140 else
141 printf("Unknown serial ATA version\n");
143 else
144 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
147 void
148 cap_print(struct ata_params *parm)
150 u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
151 ((u_int32_t)parm->lba_size_2 << 16);
153 u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
154 ((u_int64_t)parm->lba_size48_2 << 16) |
155 ((u_int64_t)parm->lba_size48_3 << 32) |
156 ((u_int64_t)parm->lba_size48_4 << 48);
158 printf("\n");
159 printf("Protocol ");
160 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
161 if (parm->satacapabilities & ATA_SATA_GEN2)
162 printf("Serial ATA II\n");
163 else if (parm->satacapabilities & ATA_SATA_GEN1)
164 printf("Serial ATA v1.0\n");
165 else
166 printf("Unknown serial ATA version\n");
168 else
169 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
170 printf("device model %.40s\n", parm->model);
171 printf("serial number %.20s\n", parm->serial);
172 printf("firmware revision %.8s\n", parm->revision);
174 printf("cylinders %d\n", parm->cylinders);
175 printf("heads %d\n", parm->heads);
176 printf("sectors/track %d\n", parm->sectors);
178 printf("lba%ssupported ",
179 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
180 if (lbasize)
181 printf("%d sectors\n", lbasize);
182 else
183 printf("\n");
185 printf("lba48%ssupported ",
186 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
187 if (lbasize48)
188 printf("%llu sectors\n", (unsigned long long)lbasize48);
189 else
190 printf("\n");
192 printf("dma%ssupported\n",
193 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
195 printf("overlap%ssupported\n",
196 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
198 printf("\nFeature "
199 "Support Enable Value Vendor\n");
201 printf("write cache %s %s\n",
202 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
203 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
205 printf("read ahead %s %s\n",
206 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
207 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
209 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
210 printf("Native Command Queuing (NCQ) %s %s"
211 " %d/0x%02X\n",
212 parm->satacapabilities & ATA_SUPPORT_NCQ ?
213 "yes" : "no", " -",
214 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
215 ATA_QUEUE_LEN(parm->queue) : 0,
216 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
217 ATA_QUEUE_LEN(parm->queue) : 0);
219 printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n",
220 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
221 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
222 ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
224 printf("SMART %s %s\n",
225 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
226 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
228 printf("microcode download %s %s\n",
229 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
230 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
232 printf("security %s %s\n",
233 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
234 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
236 printf("power management %s %s\n",
237 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
238 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
240 printf("advanced power management %s %s %d/0x%02X\n",
241 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
242 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
243 parm->apm_value, parm->apm_value);
245 printf("automatic acoustic management %s %s "
246 "%d/0x%02X %d/0x%02X\n",
247 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
248 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
249 ATA_ACOUSTIC_CURRENT(parm->acoustic),
250 ATA_ACOUSTIC_CURRENT(parm->acoustic),
251 ATA_ACOUSTIC_VENDOR(parm->acoustic),
252 ATA_ACOUSTIC_VENDOR(parm->acoustic));
256 ata_cap_print(int fd)
258 struct ata_params params;
260 if (ioctl(fd, IOCATAGPARM, &params) < 0)
261 return errno;
262 cap_print(&params);
263 return 0;
267 info_print(int fd, int channel, int prchan)
269 struct ata_ioc_devices devices;
271 devices.channel = channel;
273 if (ioctl(fd, IOCATADEVICES, &devices) < 0)
274 return errno;
276 if (prchan)
277 printf("ATA channel %d:\n", channel);
278 printf("%sMaster: ", prchan ? " " : "");
279 if (*devices.name[0]) {
280 printf("%4.4s ", devices.name[0]);
281 param_print(&devices.params[0]);
283 else
284 printf(" no device present\n");
285 printf("%sSlave: ", prchan ? " " : "");
286 if (*devices.name[1]) {
287 printf("%4.4s ", devices.name[1]);
288 param_print(&devices.params[1]);
290 else
291 printf(" no device present\n");
292 return 0;
296 main(int argc, char **argv)
298 int fd;
300 if (argc < 2)
301 usage();
303 if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
304 int disk, mode;
305 char device[64];
307 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
308 sscanf(argv[2], "acd%d", &disk) == 1 ||
309 sscanf(argv[2], "afd%d", &disk) == 1 ||
310 sscanf(argv[2], "ast%d", &disk) == 1)) {
311 fprintf(stderr, "natacontrol: Invalid device %s\n",
312 argv[2]);
313 exit(EX_USAGE);
315 sprintf(device, "/dev/%s", argv[2]);
316 if ((fd = open(device, O_RDONLY)) < 0)
317 err(1, "device not found");
318 if (argc == 4) {
319 mode = str2mode(argv[3]);
320 if (ioctl(fd, IOCATASMODE, &mode) < 0)
321 warn("ioctl(IOCATASMODE)");
323 if (argc == 3 || argc == 4) {
324 if (ioctl(fd, IOCATAGMODE, &mode) < 0)
325 err(1, "ioctl(IOCATAGMODE)");
326 printf("current mode = %s\n", mode2str(mode));
328 exit(EX_OK);
330 if (!strcmp(argv[1], "cap") && argc == 3) {
331 int disk;
332 char device[64];
334 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
335 sscanf(argv[2], "acd%d", &disk) == 1 ||
336 sscanf(argv[2], "afd%d", &disk) == 1 ||
337 sscanf(argv[2], "ast%d", &disk) == 1)) {
338 fprintf(stderr, "natacontrol: Invalid device %s\n",
339 argv[2]);
340 exit(EX_USAGE);
342 sprintf(device, "/dev/%s", argv[2]);
343 if ((fd = open(device, O_RDONLY)) < 0)
344 err(1, "device not found");
345 ata_cap_print(fd);
346 exit(EX_OK);
349 if ((fd = open("/dev/ata", O_RDWR)) < 0)
350 err(1, "control device not found");
352 if (!strcmp(argv[1], "list") && argc == 2) {
353 int maxchannel, channel;
355 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
356 err(1, "ioctl(IOCATAGMAXCHANNEL)");
357 for (channel = 0; channel < maxchannel; channel++)
358 info_print(fd, channel, 1);
359 exit(EX_OK);
361 if (!strcmp(argv[1], "info") && argc == 3) {
362 int channel;
364 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
365 fprintf(stderr,
366 "natacontrol: Invalid channel %s\n", argv[2]);
367 exit(EX_USAGE);
369 info_print(fd, channel, 0);
370 exit(EX_OK);
372 if (!strcmp(argv[1], "detach") && argc == 3) {
373 int channel;
375 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
376 fprintf(stderr,
377 "natacontrol: Invalid channel %s\n", argv[2]);
378 exit(EX_USAGE);
380 if (ioctl(fd, IOCATADETACH, &channel) < 0)
381 err(1, "ioctl(IOCATADETACH)");
382 exit(EX_OK);
384 if (!strcmp(argv[1], "attach") && argc == 3) {
385 int channel;
387 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
388 fprintf(stderr,
389 "natacontrol: Invalid channel %s\n", argv[2]);
390 exit(EX_USAGE);
392 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
393 err(1, "ioctl(IOCATAATTACH)");
394 info_print(fd, channel, 0);
395 exit(EX_OK);
397 if (!strcmp(argv[1], "reinit") && argc == 3) {
398 int channel;
400 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
401 fprintf(stderr,
402 "natacontrol: Invalid channel %s\n", argv[2]);
403 exit(EX_USAGE);
405 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
406 warn("ioctl(IOCATAREINIT)");
407 info_print(fd, channel, 0);
408 exit(EX_OK);
410 if (!strcmp(argv[1], "create")) {
411 int disk, dev, offset;
412 struct ata_ioc_raid_config config;
414 bzero(&config, sizeof(config));
415 if (argc > 2) {
416 if (!strcasecmp(argv[2], "RAID0") ||
417 !strcasecmp(argv[2], "stripe"))
418 config.type = AR_RAID0;
419 if (!strcasecmp(argv[2], "RAID1") ||
420 !strcasecmp(argv[2],"mirror"))
421 config.type = AR_RAID1;
422 if (!strcasecmp(argv[2], "RAID0+1") ||
423 !strcasecmp(argv[2],"RAID10"))
424 config.type = AR_RAID01;
425 if (!strcasecmp(argv[2], "RAID5"))
426 config.type = AR_RAID5;
427 if (!strcasecmp(argv[2], "SPAN"))
428 config.type = AR_SPAN;
429 if (!strcasecmp(argv[2], "JBOD"))
430 config.type = AR_JBOD;
432 if (!config.type) {
433 fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
434 argv[2]);
435 fprintf(stderr, "natacontrol: Valid RAID types: \n");
436 fprintf(stderr, " stripe | mirror | "
437 "RAID0 | RAID1 | RAID0+1 | RAID5 | "
438 "SPAN | JBOD\n");
439 exit(EX_USAGE);
442 if (config.type == AR_RAID0 ||
443 config.type == AR_RAID01 ||
444 config.type == AR_RAID5) {
445 if (argc < 4 ||
446 !sscanf(argv[3], "%d", &config.interleave) == 1) {
447 fprintf(stderr,
448 "natacontrol: Invalid interleave %s\n",
449 argv[3]);
450 exit(EX_USAGE);
452 offset = 4;
454 else
455 offset = 3;
457 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
458 if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
459 fprintf(stderr,
460 "natacontrol: Invalid disk %s\n",
461 argv[offset + disk]);
462 exit(EX_USAGE);
464 config.disks[disk] = dev;
467 if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
468 disk < 2) {
469 fprintf(stderr, "natacontrol: At least 2 disks must be "
470 "specified\n");
471 exit(EX_USAGE);
474 config.total_disks = disk;
475 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
476 err(1, "ioctl(IOCATARAIDCREATE)");
477 else
478 printf("ar%d created\n", config.lun);
479 exit(EX_OK);
481 if (!strcmp(argv[1], "delete") && argc == 3) {
482 int array;
484 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
485 fprintf(stderr,
486 "natacontrol: Invalid array %s\n", argv[2]);
487 exit(EX_USAGE);
489 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
490 warn("ioctl(IOCATARAIDDELETE)");
491 exit(EX_OK);
493 if (!strcmp(argv[1], "addspare") && argc == 4) {
494 struct ata_ioc_raid_config config;
496 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
497 fprintf(stderr,
498 "natacontrol: Invalid array %s\n", argv[2]);
499 usage();
501 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
502 fprintf(stderr,
503 "natacontrol: Invalid disk %s\n", argv[3]);
504 usage();
506 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
507 warn("ioctl(IOCATARAIDADDSPARE)");
508 exit(EX_OK);
510 if (!strcmp(argv[1], "rebuild") && argc == 3) {
511 int array;
513 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
514 fprintf(stderr,
515 "natacontrol: Invalid array %s\n", argv[2]);
516 usage();
518 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
519 warn("ioctl(IOCATARAIDREBUILD)");
520 else {
521 char buffer[128];
522 sprintf(buffer, "/usr/bin/nice -n 20 /bin/dd "
523 "if=/dev/ar%d of=/dev/null bs=1m &",
524 array);
525 if (system(buffer))
526 warn("background dd");
528 exit(EX_OK);
530 if (!strcmp(argv[1], "status") && argc == 3) {
531 struct ata_ioc_raid_config config;
532 int i;
534 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
535 fprintf(stderr,
536 "natacontrol: Invalid array %s\n", argv[2]);
537 usage();
539 if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
540 err(1, "ioctl(IOCATARAIDSTATUS)");
542 printf("ar%d: ATA ", config.lun);
543 switch (config.type) {
544 case AR_RAID0:
545 printf("RAID0 stripesize=%d", config.interleave);
546 break;
547 case AR_RAID1:
548 printf("RAID1");
549 break;
550 case AR_RAID01:
551 printf("RAID0+1 stripesize=%d", config.interleave);
552 break;
553 case AR_RAID5:
554 printf("RAID5 stripesize=%d", config.interleave);
555 break;
556 case AR_JBOD:
557 printf("JBOD");
558 case AR_SPAN:
559 printf("SPAN");
560 break;
562 printf(" subdisks: ");
563 for (i = 0; i < config.total_disks; i++) {
564 if (config.disks[i] >= 0)
565 printf("ad%d ", config.disks[i]);
566 else
567 printf("DOWN ");
569 printf("status: ");
570 switch (config.status) {
571 case AR_READY:
572 printf("READY\n");
573 break;
574 case AR_READY | AR_DEGRADED:
575 printf("DEGRADED\n");
576 break;
577 case AR_READY | AR_DEGRADED | AR_REBUILDING:
578 printf("REBUILDING %d%% completed\n",
579 config.progress);
580 break;
581 default:
582 printf("BROKEN\n");
584 exit(EX_OK);
586 usage();
587 exit(EX_OK);