sdhci - Implement ADMA2 transfer support. Keep SDMA support for now.
[dragonfly.git] / sbin / natacontrol / natacontrol.c
blob9ec113b468996f95797ca4a626f05be66fbb7f9f
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 $
29 #include <sys/nata.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <err.h>
38 #include <sysexits.h>
39 #include <unistd.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 feature device apm apmlevel\n"
114 " natacontrol feature device acoustic soundsupplevel\n"
115 " natacontrol cap device\n"
117 exit(EX_USAGE);
121 version(int ver)
123 int bit;
125 if (ver == 0xffff)
126 return 0;
127 for (bit = 15; bit >= 0; bit--)
128 if (ver & (1<<bit))
129 return bit;
130 return 0;
133 void
134 param_print(struct ata_params *parm)
136 printf("<%.40s/%.8s> ", parm->model, parm->revision);
137 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
138 if (parm->satacapabilities & ATA_SATA_GEN2)
139 printf("Serial ATA II\n");
140 else if (parm->satacapabilities & ATA_SATA_GEN1)
141 printf("Serial ATA v1.0\n");
142 else
143 printf("Unknown serial ATA version\n");
145 else
146 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
149 void
150 cap_print(struct ata_params *parm)
152 u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
153 ((u_int32_t)parm->lba_size_2 << 16);
155 u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
156 ((u_int64_t)parm->lba_size48_2 << 16) |
157 ((u_int64_t)parm->lba_size48_3 << 32) |
158 ((u_int64_t)parm->lba_size48_4 << 48);
160 printf("\n");
161 printf("Protocol ");
162 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
163 if (parm->satacapabilities & ATA_SATA_GEN2)
164 printf("Serial ATA II\n");
165 else if (parm->satacapabilities & ATA_SATA_GEN1)
166 printf("Serial ATA v1.0\n");
167 else
168 printf("Unknown serial ATA version\n");
170 else
171 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
172 printf("device model %.40s\n", parm->model);
173 printf("serial number %.20s\n", parm->serial);
174 printf("firmware revision %.8s\n", parm->revision);
176 printf("cylinders %d\n", parm->cylinders);
177 printf("heads %d\n", parm->heads);
178 printf("sectors/track %d\n", parm->sectors);
180 printf("lba%ssupported ",
181 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
182 if (lbasize)
183 printf("%d sectors\n", lbasize);
184 else
185 printf("\n");
187 printf("lba48%ssupported ",
188 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
189 if (lbasize48)
190 printf("%llu sectors\n", (unsigned long long)lbasize48);
191 else
192 printf("\n");
194 printf("dma%ssupported\n",
195 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
197 printf("overlap%ssupported\n",
198 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
200 printf("\nFeature "
201 "Support Enable Value Vendor\n");
203 printf("write cache %s %s\n",
204 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
205 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
207 printf("read ahead %s %s\n",
208 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
209 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
211 if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
212 printf("Native Command Queuing (NCQ) %s %s"
213 " %d/0x%02X\n",
214 parm->satacapabilities & ATA_SUPPORT_NCQ ?
215 "yes" : "no", " -",
216 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
217 ATA_QUEUE_LEN(parm->queue) : 0,
218 (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
219 ATA_QUEUE_LEN(parm->queue) : 0);
221 printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n",
222 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
223 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
224 ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
226 printf("SMART %s %s\n",
227 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
228 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
230 printf("microcode download %s %s\n",
231 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
232 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
234 printf("security %s %s\n",
235 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
236 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
238 printf("power management %s %s\n",
239 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
240 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
242 printf("advanced power management %s %s %d/0x%02X\n",
243 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
244 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
245 parm->apm_value, parm->apm_value);
247 printf("automatic acoustic management %s %s "
248 "%d/0x%02X %d/0x%02X\n",
249 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
250 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
251 ATA_ACOUSTIC_CURRENT(parm->acoustic),
252 ATA_ACOUSTIC_CURRENT(parm->acoustic),
253 ATA_ACOUSTIC_VENDOR(parm->acoustic),
254 ATA_ACOUSTIC_VENDOR(parm->acoustic));
258 ata_cap_print(int fd)
260 struct ata_params params;
262 if (ioctl(fd, IOCATAGPARM, &params) < 0)
263 return errno;
264 cap_print(&params);
265 return 0;
269 info_print(int fd, int channel, int prchan)
271 struct ata_ioc_devices devices;
273 devices.channel = channel;
275 if (ioctl(fd, IOCATADEVICES, &devices) < 0)
276 return errno;
278 if (prchan)
279 printf("ATA channel %d:\n", channel);
280 printf("%sMaster: ", prchan ? " " : "");
281 if (*devices.name[0]) {
282 printf("%4.4s ", devices.name[0]);
283 param_print(&devices.params[0]);
285 else
286 printf(" no device present\n");
287 printf("%sSlave: ", prchan ? " " : "");
288 if (*devices.name[1]) {
289 printf("%4.4s ", devices.name[1]);
290 param_print(&devices.params[1]);
292 else
293 printf(" no device present\n");
294 return 0;
298 main(int argc, char **argv)
300 int fd;
302 if (argc < 2)
303 usage();
305 if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
306 int disk, mode;
307 char device[64];
309 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
310 sscanf(argv[2], "acd%d", &disk) == 1 ||
311 sscanf(argv[2], "afd%d", &disk) == 1 ||
312 sscanf(argv[2], "ast%d", &disk) == 1)) {
313 fprintf(stderr, "natacontrol: Invalid device %s\n",
314 argv[2]);
315 exit(EX_USAGE);
317 sprintf(device, "/dev/%s", argv[2]);
318 if ((fd = open(device, O_RDONLY)) < 0)
319 err(1, "device not found");
320 if (argc == 4) {
321 mode = str2mode(argv[3]);
322 if (ioctl(fd, IOCATASMODE, &mode) < 0)
323 warn("ioctl(IOCATASMODE)");
325 if (argc == 3 || argc == 4) {
326 if (ioctl(fd, IOCATAGMODE, &mode) < 0)
327 err(1, "ioctl(IOCATAGMODE)");
328 printf("current mode = %s\n", mode2str(mode));
330 exit(EX_OK);
332 if (!strcmp(argv[1], "feature") && argc == 5) {
333 int disk;
334 char device[64];
335 struct ata_ioc_request request;
337 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
338 sscanf(argv[2], "acd%d", &disk) == 1 ||
339 sscanf(argv[2], "afd%d", &disk) == 1 ||
340 sscanf(argv[2], "ast%d", &disk) == 1)) {
341 fprintf(stderr, "natacontrol: Invalid device %s\n",
342 argv[2]);
343 exit(EX_USAGE);
345 sprintf(device, "/dev/%s", argv[2]);
346 if ((fd = open(device, O_RDONLY)) < 0)
347 err(1, "device not found");
349 bzero(&request, sizeof(struct ata_ioc_request));
350 request.u.ata.command = ATA_SETFEATURES;
351 request.flags = ATA_CMD_CONTROL;
352 request.timeout = 500;
353 if (!strcmp(argv[3], "apm")) {
354 if (!strcmp(argv[4], "off")) {
355 request.u.ata.feature = ATA_SF_DIS_APM;
356 } else if (!strcmp(argv[4], "maxperf")) {
357 request.u.ata.feature = ATA_SF_ENAB_APM;
358 request.u.ata.count = 0xfe;
359 } else if (!strcmp(argv[4], "minpower")) {
360 request.u.ata.feature = ATA_SF_ENAB_APM;
361 request.u.ata.count = 0x01;
362 } else {
363 int offset = 0;
365 request.u.ata.feature = ATA_SF_ENAB_APM;
366 if (argv[4][0] == 's') {
367 offset = atoi(&argv[4][1]);
368 request.u.ata.count = 0x01;
369 } else {
370 offset = atoi(&argv[4][1]);
371 request.u.ata.count = 0x80;
373 if (offset >= 0 && offset <= 127)
374 request.u.ata.count += offset;
376 } else if (!strcmp(argv[3], "acoustic")) {
377 if (!strcmp(argv[4], "off")) {
378 request.u.ata.feature = ATA_SF_DIS_ACCOUS;
379 } else if (!strcmp(argv[4], "maxperf")) {
380 request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
381 request.u.ata.count = 0xfe;
382 } else if (!strcmp(argv[4], "maxquiet")) {
383 request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
384 request.u.ata.count = 0x80;
385 } else {
386 request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
387 request.u.ata.count = atoi(argv[4]);
388 if (request.u.ata.count > 124)
389 request.u.ata.count = 124;
391 } else {
392 usage();
395 if (ioctl(fd, IOCATAREQUEST, &request) < 0)
396 err(1, "ioctl(IOCATAREQUEST)");
398 if (request.error != 0) {
399 fprintf(stderr,
400 "IOCATAREQUEST returned err status %d",
401 request.error);
402 exit(EX_IOERR);
404 exit(EX_OK);
406 if (!strcmp(argv[1], "cap") && argc == 3) {
407 int disk;
408 char device[64];
410 if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
411 sscanf(argv[2], "acd%d", &disk) == 1 ||
412 sscanf(argv[2], "afd%d", &disk) == 1 ||
413 sscanf(argv[2], "ast%d", &disk) == 1)) {
414 fprintf(stderr, "natacontrol: Invalid device %s\n",
415 argv[2]);
416 exit(EX_USAGE);
418 sprintf(device, "/dev/%s", argv[2]);
419 if ((fd = open(device, O_RDONLY)) < 0)
420 err(1, "device not found");
421 ata_cap_print(fd);
422 exit(EX_OK);
425 if ((fd = open("/dev/ata", O_RDWR)) < 0)
426 err(1, "control device not found");
428 if (!strcmp(argv[1], "list") && argc == 2) {
429 int maxchannel, channel;
431 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
432 err(1, "ioctl(IOCATAGMAXCHANNEL)");
433 for (channel = 0; channel < maxchannel; channel++)
434 info_print(fd, channel, 1);
435 exit(EX_OK);
437 if (!strcmp(argv[1], "info") && argc == 3) {
438 int channel;
440 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
441 fprintf(stderr,
442 "natacontrol: Invalid channel %s\n", argv[2]);
443 exit(EX_USAGE);
445 info_print(fd, channel, 0);
446 exit(EX_OK);
448 if (!strcmp(argv[1], "detach") && argc == 3) {
449 int channel;
451 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
452 fprintf(stderr,
453 "natacontrol: Invalid channel %s\n", argv[2]);
454 exit(EX_USAGE);
456 if (ioctl(fd, IOCATADETACH, &channel) < 0)
457 err(1, "ioctl(IOCATADETACH)");
458 exit(EX_OK);
460 if (!strcmp(argv[1], "attach") && argc == 3) {
461 int channel;
463 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
464 fprintf(stderr,
465 "natacontrol: Invalid channel %s\n", argv[2]);
466 exit(EX_USAGE);
468 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
469 err(1, "ioctl(IOCATAATTACH)");
470 info_print(fd, channel, 0);
471 exit(EX_OK);
473 if (!strcmp(argv[1], "reinit") && argc == 3) {
474 int channel;
476 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
477 fprintf(stderr,
478 "natacontrol: Invalid channel %s\n", argv[2]);
479 exit(EX_USAGE);
481 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
482 warn("ioctl(IOCATAREINIT)");
483 info_print(fd, channel, 0);
484 exit(EX_OK);
486 if (!strcmp(argv[1], "create")) {
487 int disk, dev, offset;
488 struct ata_ioc_raid_config config;
490 bzero(&config, sizeof(config));
491 if (argc > 2) {
492 if (!strcasecmp(argv[2], "RAID0") ||
493 !strcasecmp(argv[2], "stripe"))
494 config.type = AR_RAID0;
495 if (!strcasecmp(argv[2], "RAID1") ||
496 !strcasecmp(argv[2],"mirror"))
497 config.type = AR_RAID1;
498 if (!strcasecmp(argv[2], "RAID0+1") ||
499 !strcasecmp(argv[2],"RAID10"))
500 config.type = AR_RAID01;
501 if (!strcasecmp(argv[2], "RAID5"))
502 config.type = AR_RAID5;
503 if (!strcasecmp(argv[2], "SPAN"))
504 config.type = AR_SPAN;
505 if (!strcasecmp(argv[2], "JBOD"))
506 config.type = AR_JBOD;
508 if (!config.type) {
509 fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
510 argv[2]);
511 fprintf(stderr, "natacontrol: Valid RAID types: \n");
512 fprintf(stderr, " stripe | mirror | "
513 "RAID0 | RAID1 | RAID0+1 | RAID5 | "
514 "SPAN | JBOD\n");
515 exit(EX_USAGE);
518 if (config.type == AR_RAID0 ||
519 config.type == AR_RAID01 ||
520 config.type == AR_RAID5) {
521 if (argc < 4 ||
522 sscanf(argv[3], "%d", &config.interleave) != 1) {
523 fprintf(stderr,
524 "natacontrol: Invalid interleave %s\n",
525 argv[3]);
526 exit(EX_USAGE);
528 offset = 4;
530 else
531 offset = 3;
533 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
534 if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
535 fprintf(stderr,
536 "natacontrol: Invalid disk %s\n",
537 argv[offset + disk]);
538 exit(EX_USAGE);
540 config.disks[disk] = dev;
543 if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
544 disk < 2) {
545 fprintf(stderr, "natacontrol: At least 2 disks must be "
546 "specified\n");
547 exit(EX_USAGE);
550 config.total_disks = disk;
551 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
552 err(1, "ioctl(IOCATARAIDCREATE)");
553 else
554 printf("ar%d created\n", config.lun);
555 exit(EX_OK);
557 if (!strcmp(argv[1], "delete") && argc == 3) {
558 int array;
560 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
561 fprintf(stderr,
562 "natacontrol: Invalid array %s\n", argv[2]);
563 exit(EX_USAGE);
565 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
566 warn("ioctl(IOCATARAIDDELETE)");
567 exit(EX_OK);
569 if (!strcmp(argv[1], "addspare") && argc == 4) {
570 struct ata_ioc_raid_config config;
572 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
573 fprintf(stderr,
574 "natacontrol: Invalid array %s\n", argv[2]);
575 usage();
577 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
578 fprintf(stderr,
579 "natacontrol: Invalid disk %s\n", argv[3]);
580 usage();
582 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
583 warn("ioctl(IOCATARAIDADDSPARE)");
584 exit(EX_OK);
586 if (!strcmp(argv[1], "rebuild") && argc == 3) {
587 int array;
589 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
590 fprintf(stderr,
591 "natacontrol: Invalid array %s\n", argv[2]);
592 usage();
594 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
595 warn("ioctl(IOCATARAIDREBUILD)");
596 else {
597 char device[64];
598 char *buffer;
599 ssize_t len;
600 int arfd;
602 if (daemon(0, 1) == -1)
603 err(1, "daemon");
604 nice(20);
605 snprintf(device, sizeof(device), "/dev/ar%d",
606 array);
607 if ((arfd = open(device, O_RDONLY)) == -1)
608 err(1, "open %s", device);
609 if ((buffer = malloc(1024 * 1024)) == NULL)
610 err(1, "malloc");
611 while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
613 if (len == -1)
614 err(1, "read");
615 else
616 fprintf(stderr,
617 "natacontrol: ar%d rebuild completed\n",
618 array);
619 free(buffer);
620 close(arfd);
622 exit(EX_OK);
624 if (!strcmp(argv[1], "status") && argc == 3) {
625 struct ata_ioc_raid_config config;
626 int i;
628 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
629 fprintf(stderr,
630 "natacontrol: Invalid array %s\n", argv[2]);
631 usage();
633 if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
634 err(1, "ioctl(IOCATARAIDSTATUS)");
636 printf("ar%d: ATA ", config.lun);
637 switch (config.type) {
638 case AR_RAID0:
639 printf("RAID0 stripesize=%d", config.interleave);
640 break;
641 case AR_RAID1:
642 printf("RAID1");
643 break;
644 case AR_RAID01:
645 printf("RAID0+1 stripesize=%d", config.interleave);
646 break;
647 case AR_RAID5:
648 printf("RAID5 stripesize=%d", config.interleave);
649 break;
650 case AR_JBOD:
651 printf("JBOD");
652 case AR_SPAN:
653 printf("SPAN");
654 break;
656 printf(" subdisks: ");
657 for (i = 0; i < config.total_disks; i++) {
658 if (config.disks[i] >= 0)
659 printf("ad%d ", config.disks[i]);
660 else
661 printf("DOWN ");
663 printf("status: ");
664 switch (config.status) {
665 case AR_READY:
666 printf("READY\n");
667 break;
668 case AR_READY | AR_DEGRADED:
669 printf("DEGRADED\n");
670 break;
671 case AR_READY | AR_DEGRADED | AR_REBUILDING:
672 printf("REBUILDING %d%% completed\n",
673 config.progress);
674 break;
675 default:
676 printf("BROKEN\n");
678 exit(EX_OK);
680 usage();
681 exit(EX_OK);