cdf03efdd8e515e8dffc337e1015460c1b5fdfb1
[dragonfly.git] / sbin / natacontrol / natacontrol.c
1 /*-
2  * Copyright (c) 2000 - 2006 Søren Schmidt <sos@FreeBSD.org>
3  * All rights reserved.
4  *
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  *
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.
25  *
26  * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.42 2006/03/15 19:32:43 sos Exp $
27  */
28
29 #include <sys/nata.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <err.h>
37
38 #include <sysexits.h>
39 #include <unistd.h>
40
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);
49
50 const char *
51 mode2str(int mode)
52 {
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 "???";
72         }
73 }
74
75 int
76 str2mode(char *str)
77 {
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;
95 }
96
97 void
98 usage(void)
99 {
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"
116         );
117         exit(EX_USAGE);
118 }
119
120 int
121 version(int ver)
122 {
123         int bit;
124
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;
131 }
132
133 void
134 param_print(struct ata_params *parm)
135 {
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");
144         }
145         else
146                 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
147 }
148
149 void
150 cap_print(struct ata_params *parm)
151 {
152         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
153                                 ((u_int32_t)parm->lba_size_2 << 16);
154
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);
159
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");
169         }
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);
175
176         printf("cylinders             %d\n", parm->cylinders);
177         printf("heads                 %d\n", parm->heads);
178         printf("sectors/track         %d\n", parm->sectors);
179
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");
186
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");
193
194         printf("dma%ssupported\n",
195                 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
196
197         printf("overlap%ssupported\n",
198                 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
199
200         printf("\nFeature                      "
201                 "Support  Enable    Value           Vendor\n");
202
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");
206
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");
210
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);
220         }
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));
225
226         printf("SMART                          %s       %s\n",
227                 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
228                 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
229
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");
233
234         printf("security                       %s       %s\n",
235                 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
236                 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
237
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");
241
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);
246
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));
255 }
256
257 int
258 ata_cap_print(int fd)
259 {
260         struct ata_params params;
261
262         if (ioctl(fd, IOCATAGPARM, &params) < 0)
263                 return errno;
264         cap_print(&params);
265         return 0;
266 }
267
268 int
269 info_print(int fd, int channel, int prchan)
270 {
271         struct ata_ioc_devices devices;
272
273         devices.channel = channel;
274
275         if (ioctl(fd, IOCATADEVICES, &devices) < 0)
276                 return errno;
277
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]);
284         }
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]);
291         }
292         else
293                 printf("     no device present\n");
294         return 0;
295 }
296
297 int
298 main(int argc, char **argv)
299 {
300         int fd;
301
302         if (argc < 2)
303                 usage();
304
305         if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
306                 int disk, mode;
307                 char device[64];
308
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);
316                 }
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)");
324                 }
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));
329                 }
330                 exit(EX_OK);
331         }
332         if (!strcmp(argv[1], "feature") && argc == 5) {
333                 int disk;
334                 char device[64];
335                 struct ata_ioc_request request;
336
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);
344                 }
345                 sprintf(device, "/dev/%s", argv[2]);
346                 if ((fd = open(device, O_RDONLY)) < 0)
347                         err(1, "device not found");
348
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;
364
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;
372                                 }
373                                 if (offset >= 0 && offset <= 127)
374                                         request.u.ata.count += offset;
375                         }
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;
390                         }
391                 } else {
392                         usage();
393                 }
394
395                 if (ioctl(fd, IOCATAREQUEST, &request) < 0)
396                         err(1, "ioctl(IOCATAREQUEST)");
397
398                 if (request.error != 0) {
399                         fprintf(stderr,
400                             "IOCATAREQUEST returned err status %d",
401                             request.error);
402                         exit(EX_IOERR);
403                 }
404                 exit(EX_OK);
405         }
406         if (!strcmp(argv[1], "cap") && argc == 3) {
407                 int disk;
408                 char device[64];
409
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);
417                 }
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);
423         }
424
425         if ((fd = open("/dev/ata", O_RDWR)) < 0)
426                 err(1, "control device not found");
427
428         if (!strcmp(argv[1], "list") && argc == 2) {
429                 int maxchannel, channel;
430
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);
436         }
437         if (!strcmp(argv[1], "info") && argc == 3) {
438                 int channel;
439
440                 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
441                         fprintf(stderr,
442                                 "natacontrol: Invalid channel %s\n", argv[2]);
443                         exit(EX_USAGE);
444                 }
445                 info_print(fd, channel, 0);
446                 exit(EX_OK);
447         }
448         if (!strcmp(argv[1], "detach") && argc == 3) {
449                 int channel;
450
451                 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
452                         fprintf(stderr,
453                                 "natacontrol: Invalid channel %s\n", argv[2]);
454                         exit(EX_USAGE);
455                 }
456                 if (ioctl(fd, IOCATADETACH, &channel) < 0)
457                         err(1, "ioctl(IOCATADETACH)");
458                 exit(EX_OK);
459         }
460         if (!strcmp(argv[1], "attach") && argc == 3) {
461                 int channel;
462
463                 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
464                         fprintf(stderr,
465                                 "natacontrol: Invalid channel %s\n", argv[2]);
466                         exit(EX_USAGE);
467                 }
468                 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
469                         err(1, "ioctl(IOCATAATTACH)");
470                 info_print(fd, channel, 0);
471                 exit(EX_OK);
472         }
473         if (!strcmp(argv[1], "reinit") && argc == 3) {
474                 int channel;
475
476                 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
477                         fprintf(stderr,
478                                 "natacontrol: Invalid channel %s\n", argv[2]);
479                         exit(EX_USAGE);
480                 }
481                 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
482                         warn("ioctl(IOCATAREINIT)");
483                 info_print(fd, channel, 0);
484                 exit(EX_OK);
485         }
486         if (!strcmp(argv[1], "create")) {
487                 int disk, dev, offset;
488                 struct ata_ioc_raid_config config;
489
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;
507                 }
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);
516                 }
517
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);
527                         }
528                         offset = 4;
529                 }
530                 else
531                         offset = 3;
532
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);
539                         }
540                         config.disks[disk] = dev;
541                 }
542
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);
548                 }
549
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);
556         }
557         if (!strcmp(argv[1], "delete") && argc == 3) {
558                 int array;
559
560                 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
561                         fprintf(stderr,
562                                 "natacontrol: Invalid array %s\n", argv[2]);
563                         exit(EX_USAGE);
564                 }
565                 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
566                         warn("ioctl(IOCATARAIDDELETE)");
567                 exit(EX_OK);
568         }
569         if (!strcmp(argv[1], "addspare") && argc == 4) {
570                 struct ata_ioc_raid_config config;
571
572                 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
573                         fprintf(stderr,
574                                 "natacontrol: Invalid array %s\n", argv[2]);
575                         usage();
576                 }
577                 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
578                         fprintf(stderr,
579                                 "natacontrol: Invalid disk %s\n", argv[3]);
580                         usage();
581                 }
582                 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
583                         warn("ioctl(IOCATARAIDADDSPARE)");
584                 exit(EX_OK);
585         }
586         if (!strcmp(argv[1], "rebuild") && argc == 3) {
587                 int array;
588
589                 if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
590                         fprintf(stderr,
591                                 "natacontrol: Invalid array %s\n", argv[2]);
592                         usage();
593                 }
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;
601
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)
612                                 ;
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);
621                 }
622                 exit(EX_OK);
623         }
624         if (!strcmp(argv[1], "status") && argc == 3) {
625                 struct ata_ioc_raid_config config;
626                 int i;
627
628                 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
629                         fprintf(stderr,
630                                 "natacontrol: Invalid array %s\n", argv[2]);
631                         usage();
632                 }
633                 if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
634                         err(1, "ioctl(IOCATARAIDSTATUS)");
635
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;
655                 }
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 ");
662                 }
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");
677                 }
678                 exit(EX_OK);
679         }
680         usage();
681         exit(EX_OK);
682 }