]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sbin/atacontrol/atacontrol.c
[CDN-Patch] atacontrol: add ATA Security command support
[FreeBSD/releng/8.2.git] / sbin / atacontrol / atacontrol.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$
27  */
28
29 #include <sys/types.h>
30 #include <sys/ata.h>
31
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sysexits.h>
40 #include <unistd.h>
41
42 static const char *
43 mode2str(int mode)
44 {
45         switch (mode & 0xff) {
46         case ATA_PIO: return "BIOSPIO";
47         case ATA_PIO0: return "PIO0";
48         case ATA_PIO1: return "PIO1";
49         case ATA_PIO2: return "PIO2";
50         case ATA_PIO3: return "PIO3";
51         case ATA_PIO4: return "PIO4";
52         case ATA_WDMA0: return "WDMA0";
53         case ATA_WDMA1: return "WDMA1";
54         case ATA_WDMA2: return "WDMA2";
55         case ATA_UDMA0: return "UDMA0";
56         case ATA_UDMA1: return "UDMA1";
57         case ATA_UDMA2: return "UDMA33";
58         case ATA_UDMA3: return "UDMA44";
59         case ATA_UDMA4: return "UDMA66";
60         case ATA_UDMA5: return "UDMA100";
61         case ATA_UDMA6: return "UDMA133";
62         case ATA_DMA: return "BIOSDMA";
63         default: return "???";
64         }
65 }
66
67 static const char *
68 satarev2str(int mode)
69 {
70         switch ((mode & 0xff00) >> 8) {
71         case 0: return "";
72         case 1: return "SATA 1.5Gb/s";
73         case 2: return "SATA 3Gb/s";
74         case 3: return "SATA 6Gb/s";
75         case 0xff: return "SATA";
76         default: return "???";
77         }
78 }
79
80 static int
81 str2mode(char *str)
82 {
83         if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
84         if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
85         if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
86         if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
87         if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
88         if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
89         if (!strcasecmp(str, "WDMA0")) return ATA_WDMA0;
90         if (!strcasecmp(str, "WDMA1")) return ATA_WDMA1;
91         if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
92         if (!strcasecmp(str, "UDMA0")) return ATA_UDMA0;
93         if (!strcasecmp(str, "UDMA16")) return ATA_UDMA0;
94         if (!strcasecmp(str, "UDMA1")) return ATA_UDMA1;
95         if (!strcasecmp(str, "UDMA25")) return ATA_UDMA1;
96         if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
97         if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
98         if (!strcasecmp(str, "UDMA3")) return ATA_UDMA3;
99         if (!strcasecmp(str, "UDMA44")) return ATA_UDMA3;
100         if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
101         if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
102         if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
103         if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
104         if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
105         if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
106         if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
107         return -1;
108 }
109
110 static void
111 usage(void)
112 {
113         fprintf(stderr,
114                 "usage:  atacontrol <command> args:\n"
115                 "        atacontrol list\n"
116                 "        atacontrol info channel\n"
117                 "        atacontrol attach channel\n"
118                 "        atacontrol detach channel\n"
119                 "        atacontrol reinit channel\n"
120                 "        atacontrol create type [interleave] disk0 ... diskN\n"
121                 "        atacontrol delete array\n"
122                 "        atacontrol addspare array disk\n"
123                 "        atacontrol rebuild array\n"
124                 "        atacontrol status array\n"
125                 "        atacontrol mode device [mode]\n"
126                 "        atacontrol cap device\n"
127                 "        atacontrol security device [<security-command>]\n"
128                 "        atacontrol spindown device [seconds]\n"
129         );
130         exit(EX_USAGE);
131 }
132
133 static void
134 security_usage(void)
135 {
136         fprintf(stderr,
137                 "usage:  atacontrol security <device> <security-command>:\n"
138                 "        atacontrol security <device>\n"
139                 "        atacontrol security <device> freeze\n"
140                 "        atacontrol security <device> set master\n"
141                 "        atacontrol security <device> set user high|maximum\n"
142                 "        atacontrol security <device> unlock master|user\n"
143                 "        atacontrol security <device> disable master|user\n"
144                 "        atacontrol security <device> erase master|user "
145                                                      "[enhanced]\n"
146         );
147         exit(EX_USAGE);
148 }
149
150 static int
151 version(int ver)
152 {
153         int bit;
154
155         if (ver == 0xffff)
156                 return 0;
157         for (bit = 15; bit >= 0; bit--)
158                 if (ver & (1<<bit))
159                         return bit;
160         return 0;
161 }
162
163 static void
164 ata_request(int fd, struct ata_ioc_request *req)
165 {
166         if (ioctl(fd, IOCATAREQUEST, req) < 0)
167                 err(1, "ioctl(IOCATAREQUEST)");
168
169         if (req->error) {
170                 fprintf(stderr, "atacontrol: ATA request failed (0x%04x)\n", req->error);
171                 exit(EX_IOERR);
172         }
173 }
174
175 static void
176 param_print(struct ata_params *parm)
177 {
178         printf("<%.40s/%.8s> ", parm->model, parm->revision);
179         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
180                 if (parm->satacapabilities & ATA_SATA_GEN2)
181                         printf("SATA revision 2.x\n");
182                 else if (parm->satacapabilities & ATA_SATA_GEN1)
183                         printf("SATA revision 1.x\n");
184                 else
185                         printf("Unknown SATA revision\n");
186         }
187         else
188                 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
189 }
190
191 static void
192 cap_print(struct ata_params *parm)
193 {
194         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
195                                 ((u_int32_t)parm->lba_size_2 << 16);
196
197         u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
198                                 ((u_int64_t)parm->lba_size48_2 << 16) |
199                                 ((u_int64_t)parm->lba_size48_3 << 32) |
200                                 ((u_int64_t)parm->lba_size48_4 << 48);
201
202         printf("\n");
203         printf("Protocol              ");
204         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
205                 if (parm->satacapabilities & ATA_SATA_GEN2)
206                         printf("SATA revision 2.x\n");
207                 else if (parm->satacapabilities & ATA_SATA_GEN1)
208                         printf("SATA revision 1.x\n");
209                 else
210                         printf("Unknown SATA revision\n");
211         }
212         else
213                 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
214         printf("device model          %.40s\n", parm->model);
215         printf("serial number         %.20s\n", parm->serial);
216         printf("firmware revision     %.8s\n", parm->revision);
217
218         printf("cylinders             %d\n", parm->cylinders);
219         printf("heads                 %d\n", parm->heads);
220         printf("sectors/track         %d\n", parm->sectors);
221
222         if (parm->config == ATA_PROTO_CFA ||
223             (parm->support.command2 & ATA_SUPPORT_CFA))
224                 printf("CFA supported\n");
225
226         printf("lba%ssupported         ",
227                 parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
228         if (lbasize)
229                 printf("%d sectors\n", lbasize);
230         else
231                 printf("\n");
232
233         printf("lba48%ssupported       ",
234                 parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
235         if (lbasize48)
236                 printf("%ju sectors\n", (uintmax_t)lbasize48);
237         else
238                 printf("\n");
239
240         printf("dma%ssupported\n",
241                 parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
242
243         printf("overlap%ssupported\n",
244                 parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
245
246         printf("\nFeature                      "
247                 "Support  Enable    Value           Vendor\n");
248
249         printf("write cache                    %s       %s\n",
250                 parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
251                 parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
252
253         printf("read ahead                     %s       %s\n",
254                 parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
255                 parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
256
257         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
258                 printf("Native Command Queuing (NCQ)   %s       %s"
259                         "       %d/0x%02X\n",
260                         parm->satacapabilities & ATA_SUPPORT_NCQ ?
261                                 "yes" : "no", " -",
262                         (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
263                                 ATA_QUEUE_LEN(parm->queue) : 0,
264                         (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
265                                 ATA_QUEUE_LEN(parm->queue) : 0);
266         }
267         printf("Tagged Command Queuing (TCQ)   %s       %s      %d/0x%02X\n",
268                 parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
269                 parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
270                 ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
271
272         printf("SMART                          %s       %s\n",
273                 parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
274                 parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
275
276         printf("microcode download             %s       %s\n",
277                 parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
278                 parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
279
280         printf("security                       %s       %s\n",
281                 parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
282                 parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
283
284         printf("power management               %s       %s\n",
285                 parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
286                 parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
287
288         printf("advanced power management      %s       %s      %d/0x%02X\n",
289                 parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
290                 parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
291                 parm->apm_value, parm->apm_value);
292
293         printf("automatic acoustic management  %s       %s      "
294                 "%d/0x%02X      %d/0x%02X\n",
295                 parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
296                 parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
297                 ATA_ACOUSTIC_CURRENT(parm->acoustic),
298                 ATA_ACOUSTIC_CURRENT(parm->acoustic),
299                 ATA_ACOUSTIC_VENDOR(parm->acoustic),
300                 ATA_ACOUSTIC_VENDOR(parm->acoustic));
301 }
302
303 static void
304 ata_cap_print(int fd)
305 {
306         struct ata_params params;
307
308         if (ioctl(fd, IOCATAGPARM, &params) < 0)
309                 err(1, "ioctl(IOCATAGPARM)");
310         cap_print(&params);
311 }
312
313 static void
314 info_print(int fd, int channel, int prchan)
315 {
316         struct ata_ioc_devices devices;
317
318         devices.channel = channel;
319
320         if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
321                 if (!prchan)
322                         err(1, "ioctl(IOCATADEVICES)");
323                 return;
324         }
325         if (prchan)
326                 printf("ATA channel %d:\n", channel);
327         printf("%sMaster: ", prchan ? "    " : "");
328         if (*devices.name[0]) {
329                 printf("%4.4s ", devices.name[0]);
330                 param_print(&devices.params[0]);
331         }
332         else
333                 printf("     no device present\n");
334         printf("%sSlave:  ", prchan ? "    " : "");
335         if (*devices.name[1]) {
336                 printf("%4.4s ", devices.name[1]);
337                 param_print(&devices.params[1]);
338         }
339         else
340                 printf("     no device present\n");
341 }
342
343 static void
344 ata_spindown(int fd, const char *dev, const char *arg)
345 {
346         int tmo;
347
348         if (arg != NULL) {
349                 tmo = strtoul(arg, NULL, 0);
350                 if (ioctl(fd, IOCATASSPINDOWN, &tmo) < 0)
351                         err(1, "ioctl(IOCATASSPINDOWN)");
352         } else {
353                 if (ioctl(fd, IOCATAGSPINDOWN, &tmo) < 0)
354                         err(1, "ioctl(IOCATAGSPINDOWN)");
355                 if (tmo == 0)
356                         printf("%s: idle spin down disabled\n", dev);
357                 else
358                         printf("%s: spin down after %d seconds idle\n",
359                             dev, tmo);
360         }
361 }
362
363 static void
364 security_print_time(u_int16_t tw)
365 {
366         if (tw == 0)
367                 printf("unspecified");
368         else if (tw >= 255)
369                 printf("> 508 min");
370         else
371                 printf("%i min", 2 * tw);
372 }
373
374 static void
375 security_print(struct ata_params *parm)
376 {
377         printf("\n");
378 #if 0
379         printf("Security status           %04x\n", parm->security_status);
380 #endif
381         printf("Security supported        %s\n",
382                 parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no");
383         if (!(parm->security_status & ATA_SECURITY_SUPPORTED))
384                 return;
385         printf("Security enabled          %s\n",
386                 parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no");
387         printf("Drive locked              %s\n",
388                 parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no");
389         printf("Security config frozen    %s\n",
390                 parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no");
391         printf("Count expired             %s\n",
392                 parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no");
393         printf("Security level            %s\n",
394                 parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high");
395         printf("Enhanced erase supported  %s\n",
396                 parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no");
397         printf("Erase time                ");
398         security_print_time(parm->erase_time);
399         printf("\n");
400         printf("Enhanced erase time       ");
401         security_print_time(parm->enhanced_erase_time);
402         printf("\n");
403         printf("Master password rev       %04x%s\n",
404                         parm->master_passwd_revision,
405                         parm->master_passwd_revision == 0x0000 ||
406                         parm->master_passwd_revision == 0xFFFF ?
407                         " (unsupported)" : "");
408 }
409
410 static void
411 security_ask_password(char *pw, size_t len, int master, int confirm)
412 {
413         char *input;
414
415         input = getpass(master ? "Master password:" : "User password:");
416         if (!input) {
417                 err(1, "getpass()");
418         }
419         if (strlen(input) > len) {
420                 fprintf(stderr, "atacontrol: Password too long\n");
421                 exit(EX_DATAERR);
422         }
423         strlcpy(pw, input, len);
424         if (!confirm)
425                 return;
426         input = getpass(master ? "Retype master password:" :
427                         "Retype user password:");
428         if (!input) {
429                 err(1, "getpass()");
430         }
431         if (strcmp(pw, input)) {
432                 fprintf(stderr, "atacontrol: Password mismatch\n");
433                 exit(EX_DATAERR);
434         }
435 }
436
437 static u_int16_t
438 security_get_revision(int fd)
439 {
440         struct ata_params params;
441
442         if (ioctl(fd, IOCATAGPARM, &params) < 0)
443                 err(1, "ioctl(IOCATAGPARM)");
444         return params.master_passwd_revision;
445 }
446
447 /*
448  * security <device>
449  */
450 static void
451 ata_security_print(int fd)
452 {
453         struct ata_params params;
454
455         if (ioctl(fd, IOCATAGPARM, &params) < 0)
456                 err(1, "ioctl(IOCATAGPARM)");
457         security_print(&params);
458 }
459
460 /*
461  * security <device> freeze
462  */
463 static void
464 ata_security_freeze(int fd)
465 {
466         struct ata_ioc_request req;
467
468         memset(&req, 0, sizeof(req));
469         req.u.ata.command = ATA_SECURITY_FREEZE_LOCK;
470         req.timeout = 5;
471         req.flags = ATA_CMD_CONTROL;
472         ata_request(fd, &req);
473 }
474
475 /*
476  * security <device> set master
477  * security <device> set user high
478  * security <device> set user maximum
479  */
480 static void
481 ata_security_set(int fd, u_int16_t ctrl)
482 {
483         struct ata_ioc_request req;
484         struct ata_security_password pwd;
485
486         memset(&pwd, 0, sizeof(pwd));
487         pwd.ctrl = ctrl;
488
489         if (ctrl & ATA_SECURITY_PASSWORD_MASTER) {
490                 pwd.revision = security_get_revision(fd);
491                 if (pwd.revision != 0 && pwd.revision != 0xffff &&
492                                 --pwd.revision == 0) {
493                         pwd.revision = 0xfffe;
494                 }
495         }
496
497         security_ask_password((char*)&pwd.password, sizeof(pwd.password),
498                         ctrl & ATA_SECURITY_PASSWORD_MASTER, 1);
499
500         memset(&req, 0, sizeof(req));
501         req.u.ata.command = ATA_SECURITY_SET_PASSWORD;
502         req.timeout = 5;
503         req.flags = ATA_CMD_WRITE;
504         req.data = (caddr_t)&pwd;
505         req.count = sizeof(pwd);
506         ata_request(fd, &req);
507 }
508
509 /*
510  * security <device> unlock master
511  * security <device> unlock user
512  */
513 static void
514 ata_security_unlock(int fd, u_int16_t ctrl)
515 {
516         struct ata_ioc_request req;
517         struct ata_security_password pwd;
518
519         memset(&pwd, 0, sizeof(pwd));
520         pwd.ctrl = ctrl;
521
522         security_ask_password((char*)&pwd.password, sizeof(pwd.password),
523                         ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
524
525         memset(&req, 0, sizeof(req));
526         req.u.ata.command = ATA_SECURITY_UNLOCK;
527         req.timeout = 5;
528         req.flags = ATA_CMD_WRITE;
529         req.data = (caddr_t)&pwd;
530         req.count = sizeof(pwd);
531         ata_request(fd, &req);
532 }
533
534 /*
535  * security <device> disable master
536  * security <device> disable user
537  */
538 static void
539 ata_security_disable(int fd, u_int16_t ctrl)
540 {
541         struct ata_ioc_request req;
542         struct ata_security_password pwd;
543
544         memset(&pwd, 0, sizeof(pwd));
545         pwd.ctrl = ctrl;
546
547         security_ask_password((char*)&pwd.password, sizeof(pwd.password),
548                         ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
549
550         memset(&req, 0, sizeof(req));
551         req.u.ata.command = ATA_SECURITY_DISABLE_PASSWORD;
552         req.timeout = 5;
553         req.flags = ATA_CMD_WRITE;
554         req.data = (caddr_t)&pwd;
555         req.count = sizeof(pwd);
556         ata_request(fd, &req);
557 }
558
559 /*
560  * security <device> erase master
561  * security <device> erase master enhanced
562  * security <device> erase user
563  * security <device> erase user enhanced
564  */
565 static void
566 ata_security_erase(int fd, u_int16_t ctrl)
567 {
568         struct ata_ioc_request req;
569         struct ata_security_password pwd;
570
571         memset(&pwd, 0, sizeof(pwd));
572         pwd.ctrl = ctrl;
573
574         security_ask_password((char*)&pwd.password, sizeof(pwd.password),
575                         ctrl & ATA_SECURITY_PASSWORD_MASTER, 0);
576
577         memset(&req, 0, sizeof(req));
578         req.u.ata.command = ATA_SECURITY_ERASE_PREPARE;
579         req.timeout = 5;
580         req.flags = ATA_CMD_CONTROL;
581         ata_request(fd, &req);
582
583         memset(&req, 0, sizeof(req));
584         req.u.ata.command = ATA_SECURITY_ERASE_UNIT;
585         req.timeout = 86400; /* may take literally hours to complete */
586         req.flags = ATA_CMD_WRITE;
587         req.data = (caddr_t)&pwd;
588         req.count = sizeof(pwd);
589         ata_request(fd, &req);
590 }
591
592 static int
593 open_dev(const char *arg, int mode)
594 {
595         int disk, fd;
596         char device[64];
597
598         if (!(sscanf(arg, "ad%d", &disk) == 1 ||
599               sscanf(arg, "acd%d", &disk) == 1 ||
600               sscanf(arg, "afd%d", &disk) == 1 ||
601               sscanf(arg, "ast%d", &disk) == 1)) {
602                 fprintf(stderr, "atacontrol: Invalid device %s\n", arg);
603                 exit(EX_USAGE);
604         }
605         sprintf(device, "/dev/%s", arg);
606         if ((fd = open(device, mode)) < 0)
607                 err(1, "device not found");
608         return (fd);
609 }
610
611 static int
612 ar_arg(const char *arg)
613 {
614         int array;
615
616         if (!(sscanf(arg, "ar%d", &array) == 1)) {
617                 fprintf(stderr, "atacontrol: Invalid array %s\n", arg);
618                 exit(EX_USAGE);
619         }
620         return (array);
621 }
622
623 static int
624 ata_arg(const char *arg)
625 {
626         int channel;
627
628         if (!(sscanf(arg, "ata%d", &channel) == 1)) {
629                 fprintf(stderr, "atacontrol: Invalid channel %s\n", arg);
630                 exit(EX_USAGE);
631         }
632         return (channel);
633 }
634
635 int
636 main(int argc, char **argv)
637 {
638         int fd, mode, channel, array;
639
640         if (argc < 2)
641                 usage();
642
643         if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
644                 fd = open_dev(argv[2], O_RDONLY);
645                 if (argc == 4) {
646                         mode = str2mode(argv[3]);
647                         if (mode == -1)
648                                 errx(1, "unknown mode");
649                         if (ioctl(fd, IOCATASMODE, &mode) < 0)
650                                 warn("ioctl(IOCATASMODE)");
651                 }
652                 if (argc == 3 || argc == 4) {
653                         if (ioctl(fd, IOCATAGMODE, &mode) < 0)
654                                 err(1, "ioctl(IOCATAGMODE)");
655                         printf("current mode = %s %s\n",
656                             mode2str(mode), satarev2str(mode));
657                 }
658                 exit(EX_OK);
659         }
660         if (!strcmp(argv[1], "cap") && argc == 3) {
661                 fd = open_dev(argv[2], O_RDONLY);
662                 ata_cap_print(fd);
663                 exit(EX_OK);
664         }
665
666         if (!strcmp(argv[1], "spindown") && (argc == 3 || argc == 4)) {
667                 fd = open_dev(argv[2], O_RDONLY);
668                 ata_spindown(fd, argv[2], argv[3]);
669                 exit(EX_OK);
670         }
671
672         if (!strcmp(argv[1], "security") && argc >= 3 && argc <= 6) {
673                 u_int16_t ctrl = 0;
674
675                 fd = open_dev(argv[2], O_RDONLY);
676                 if (argc == 3) {
677                         ata_security_print(fd);
678                         exit(EX_OK);
679                 } else if (argc == 4 && !strcmp(argv[3], "freeze")) {
680                         ata_security_freeze(fd);
681                         exit(EX_OK);
682                 } else if (argc >= 5 && !strcmp(argv[3], "set")) {
683                         if (argc == 5 && !strcmp(argv[4], "master")) {
684                                 ctrl |= ATA_SECURITY_PASSWORD_MASTER;
685                         } else if (argc == 6 && !strcmp(argv[4], "user")) {
686                                 ctrl |= ATA_SECURITY_PASSWORD_USER;
687                                 if (!strcmp(argv[5], "high"))
688                                         ctrl |= ATA_SECURITY_LEVEL_HIGH;
689                                 else if (!strcmp(argv[5], "maximum"))
690                                         ctrl |= ATA_SECURITY_LEVEL_MAXIMUM;
691                                 else
692                                         security_usage();
693                         } else {
694                                 security_usage();
695                         }
696                         ata_security_set(fd, ctrl);
697                         exit(EX_OK);
698                 } else if (argc == 5 && !strcmp(argv[3], "unlock")) {
699                         if (!strcmp(argv[4], "master"))
700                                 ctrl |= ATA_SECURITY_PASSWORD_MASTER;
701                         else if (!strcmp(argv[4], "user"))
702                                 ctrl |= ATA_SECURITY_PASSWORD_USER;
703                         else
704                                 security_usage();
705                         ata_security_unlock(fd, ctrl);
706                         exit(EX_OK);
707                 } else if (argc == 5 && !strcmp(argv[3], "disable")) {
708                         if (!strcmp(argv[4], "master"))
709                                 ctrl |= ATA_SECURITY_PASSWORD_MASTER;
710                         else if (!strcmp(argv[4], "user"))
711                                 ctrl |= ATA_SECURITY_PASSWORD_USER;
712                         else
713                                 security_usage();
714                         ata_security_disable(fd, ctrl);
715                         exit(EX_OK);
716                 } else if (argc >= 5 && !strcmp(argv[3], "erase")) {
717                         if (!strcmp(argv[4], "master"))
718                                 ctrl |= ATA_SECURITY_PASSWORD_MASTER;
719                         else if (!strcmp(argv[4], "user"))
720                                 ctrl |= ATA_SECURITY_PASSWORD_USER;
721                         else
722                                 security_usage();
723                         if (argc == 5)
724                                 ctrl |= ATA_SECURITY_ERASE_NORMAL;
725                         else if (!strcmp(argv[5], "enhanced"))
726                                 ctrl |= ATA_SECURITY_ERASE_ENHANCED;
727                         else
728                                 security_usage();
729                         ata_security_erase(fd, ctrl);
730                         exit(EX_OK);
731                 }
732                 security_usage();
733         }
734
735         if ((fd = open("/dev/ata", O_RDWR)) < 0)
736                 err(1, "control device not found");
737
738         if (!strcmp(argv[1], "list") && argc == 2) {
739                 int maxchannel;
740
741                 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
742                         err(1, "ioctl(IOCATAGMAXCHANNEL)");
743                 for (channel = 0; channel < maxchannel; channel++)
744                         info_print(fd, channel, 1);
745                 exit(EX_OK);
746         }
747         if (!strcmp(argv[1], "info") && argc == 3) {
748                 channel = ata_arg(argv[2]);
749                 info_print(fd, channel, 0);
750                 exit(EX_OK);
751         }
752         if (!strcmp(argv[1], "detach") && argc == 3) {
753                 channel = ata_arg(argv[2]);
754                 if (ioctl(fd, IOCATADETACH, &channel) < 0)
755                         err(1, "ioctl(IOCATADETACH)");
756                 exit(EX_OK);
757         }
758         if (!strcmp(argv[1], "attach") && argc == 3) {
759                 channel = ata_arg(argv[2]);
760                 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
761                         err(1, "ioctl(IOCATAATTACH)");
762                 info_print(fd, channel, 0);
763                 exit(EX_OK);
764         }
765         if (!strcmp(argv[1], "reinit") && argc == 3) {
766                 channel = ata_arg(argv[2]);
767                 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
768                         warn("ioctl(IOCATAREINIT)");
769                 info_print(fd, channel, 0);
770                 exit(EX_OK);
771         }
772         if (!strcmp(argv[1], "create")) {
773                 int disk, dev, offset;
774                 struct ata_ioc_raid_config config;
775
776                 bzero(&config, sizeof(config));
777                 if (argc > 2) {
778                         if (!strcasecmp(argv[2], "RAID0") ||
779                             !strcasecmp(argv[2], "stripe"))
780                                 config.type = AR_RAID0;
781                         if (!strcasecmp(argv[2], "RAID1") ||
782                             !strcasecmp(argv[2],"mirror"))
783                                 config.type = AR_RAID1;
784                         if (!strcasecmp(argv[2], "RAID0+1") ||
785                             !strcasecmp(argv[2],"RAID10"))
786                                 config.type = AR_RAID01;
787                         if (!strcasecmp(argv[2], "RAID5"))
788                                 config.type = AR_RAID5;
789                         if (!strcasecmp(argv[2], "SPAN"))
790                                 config.type = AR_SPAN;
791                         if (!strcasecmp(argv[2], "JBOD"))
792                                 config.type = AR_JBOD;
793                 }
794                 if (!config.type) {
795                         fprintf(stderr, "atacontrol: Invalid RAID type %s\n",
796                                 argv[2]);
797                         fprintf(stderr, "atacontrol: Valid RAID types: \n");
798                         fprintf(stderr, "            stripe | mirror | "
799                                         "RAID0 | RAID1 | RAID0+1 | RAID5 | "
800                                         "SPAN | JBOD\n");
801                         exit(EX_USAGE);
802                 }
803
804                 if (config.type == AR_RAID0 ||
805                     config.type == AR_RAID01 ||
806                     config.type == AR_RAID5) {
807                         if (argc < 4 ||
808                             !sscanf(argv[3], "%d", &config.interleave) == 1) {
809                                 fprintf(stderr,
810                                         "atacontrol: Invalid interleave %s\n",
811                                         argv[3]);
812                                 exit(EX_USAGE);
813                         }
814                         offset = 4;
815                 }
816                 else
817                         offset = 3;
818
819                 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
820                         if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
821                                 fprintf(stderr,
822                                         "atacontrol: Invalid disk %s\n",
823                                         argv[offset + disk]);
824                                 exit(EX_USAGE);
825                         }
826                         config.disks[disk] = dev;
827                 }
828
829                 if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
830                     disk < 2) {
831                         fprintf(stderr, "atacontrol: At least 2 disks must be "
832                                 "specified\n");
833                         exit(EX_USAGE);
834                 }
835
836                 config.total_disks = disk;
837                 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
838                         err(1, "ioctl(IOCATARAIDCREATE)");
839                 else
840                         printf("ar%d created\n", config.lun);
841                 exit(EX_OK);
842         }
843         if (!strcmp(argv[1], "delete") && argc == 3) {
844                 array = ar_arg(argv[2]);
845                 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
846                         warn("ioctl(IOCATARAIDDELETE)");
847                 exit(EX_OK);
848         }
849         if (!strcmp(argv[1], "addspare") && argc == 4) {
850                 struct ata_ioc_raid_config config;
851
852                 config.lun = ar_arg(argv[2]);
853                 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
854                         fprintf(stderr,
855                                 "atacontrol: Invalid disk %s\n", argv[3]);
856                         usage();
857                 }
858                 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
859                         warn("ioctl(IOCATARAIDADDSPARE)");
860                 exit(EX_OK);
861         }
862         if (!strcmp(argv[1], "rebuild") && argc == 3) {
863                 array = ar_arg(argv[2]);
864                 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
865                         warn("ioctl(IOCATARAIDREBUILD)");
866                 else {
867                         char device[64];
868                         char *buffer;
869                         ssize_t len;
870                         int arfd;
871
872                         if (daemon(0, 1) == -1)
873                                 err(1, "daemon");
874                         nice(20);
875                         snprintf(device, sizeof(device), "/dev/ar%d",
876                             array);
877                         if ((arfd = open(device, O_RDONLY)) == -1)
878                                 err(1, "open %s", device);
879                         if ((buffer = malloc(1024 * 1024)) == NULL)
880                                 err(1, "malloc");
881                         while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
882                                 ;
883                         if (len == -1)
884                                 err(1, "read");
885                         else
886                                 fprintf(stderr,
887                                     "atacontrol: ar%d rebuild completed\n",
888                                     array);
889                         free(buffer);
890                         close(arfd);
891                 }
892                 exit(EX_OK);
893         }
894         if (!strcmp(argv[1], "status") && argc == 3) {
895                 struct ata_ioc_raid_status status;
896                 int i, lun, state;
897
898                 status.lun = ar_arg(argv[2]);
899                 if (ioctl(fd, IOCATARAIDSTATUS, &status) < 0)
900                         err(1, "ioctl(IOCATARAIDSTATUS)");
901
902                 printf("ar%d: ATA ", status.lun);
903                 switch (status.type) {
904                 case AR_RAID0:
905                         printf("RAID0 stripesize=%d", status.interleave);
906                         break;
907                 case AR_RAID1:
908                         printf("RAID1");
909                         break;
910                 case AR_RAID01:
911                         printf("RAID0+1 stripesize=%d", status.interleave);
912                         break;
913                 case AR_RAID5:
914                         printf("RAID5 stripesize=%d", status.interleave);
915                         break;
916                 case AR_JBOD:
917                         printf("JBOD");
918                         break;
919                 case AR_SPAN:
920                         printf("SPAN");
921                         break;
922                 }
923                 printf(" status: ");
924                 switch (status.status) {
925                 case AR_READY:
926                         printf("READY\n");
927                         break;
928                 case AR_READY | AR_DEGRADED:
929                         printf("DEGRADED\n");
930                         break;
931                 case AR_READY | AR_DEGRADED | AR_REBUILDING:
932                         printf("REBUILDING %d%% completed\n",
933                                 status.progress);
934                         break;
935                 default:
936                         printf("BROKEN\n");
937                 }
938                 printf(" subdisks:\n");
939                 for (i = 0; i < status.total_disks; i++) {
940                         printf("  %2d ", i);
941                         lun = status.disks[i].lun;
942                         state = status.disks[i].state;
943                         if (lun < 0)
944                                 printf("---- ");
945                         else
946                                 printf("ad%-2d ", lun);
947                         if (state & AR_DISK_ONLINE)
948                                 printf("ONLINE");
949                         else if (state & AR_DISK_SPARE)
950                                 printf("SPARE");
951                         else if (state & AR_DISK_PRESENT)
952                                 printf("OFFLINE");
953                         else
954                                 printf("MISSING");
955                         printf("\n");
956                 }
957                 exit(EX_OK);
958         }
959         usage();
960         exit(EX_OK);
961 }