From: Thomas E. Spanjaard Date: Tue, 5 Dec 2006 21:32:21 +0000 (+0000) Subject: Import of the port of the new(er) FreeBSD atacontrol(8), as natacontrol(8). X-Git-Url: https://gitweb.dragonflybsd.org/~lentferj/dragonfly.git/commitdiff_plain/c0741de8bc27546be7de51e56b6a7b9a36b179c2 Import of the port of the new(er) FreeBSD atacontrol(8), as natacontrol(8). It has not yet been hooked into the build, though it does build. --- diff --git a/sbin/natacontrol/Makefile b/sbin/natacontrol/Makefile new file mode 100644 index 0000000000..7a8b755b25 --- /dev/null +++ b/sbin/natacontrol/Makefile @@ -0,0 +1,7 @@ +#$FreeBSD: src/sbin/atacontrol/Makefile,v 1.8 2003/11/05 19:20:41 johan Exp $ +#$DragonFly: src/sbin/natacontrol/Makefile,v 1.1 2006/12/05 21:32:21 tgen Exp $ + +PROG= natacontrol +MAN= natacontrol.8 + +.include diff --git a/sbin/natacontrol/natacontrol.8 b/sbin/natacontrol/natacontrol.8 new file mode 100644 index 0000000000..de928d9a1b --- /dev/null +++ b/sbin/natacontrol/natacontrol.8 @@ -0,0 +1,242 @@ +.\" +.\" Copyright (c) 2000,2001,2002 Søren Schmidt +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/sbin/atacontrol/atacontrol.8,v 1.28 2005/11/18 10:32:09 ru Exp $ +.\" $DragonFly: src/sbin/natacontrol/natacontrol.8,v 1.1 2006/12/05 21:32:21 tgen Exp $ +.\" +.Dd December 5, 2006 +.Dt NATACONTROL 8 +.Os +.Sh NAME +.Nm natacontrol +.Nd NATA device driver control program +.Sh SYNOPSIS +.Nm +.Aq Ar command +.Ar args +.Pp +.Nm +.Ic attach +.Ar channel +.Nm +.Ic detach +.Ar channel +.Nm +.Ic reinit +.Ar channel +.Nm +.Ic create +.Ar type Oo Ar interleave Oc Ar disk0 ... diskN +.Nm +.Ic delete +.Ar raid +.Nm +.Ic addspare +.Ar raid disk +.Nm +.Ic rebuild +.Ar raid +.Nm +.Ic status +.Ar raid +.Nm +.Ic mode +.Ar device +.Nm +.Ic info +.Ar channel +.Nm +.Ic cap +.Ar device +.Nm +.Ic list +.Sh DESCRIPTION +The +.Nm +utility is a control program that provides the user access and control to the +.Fx +.Xr nata 4 +subsystem. +.Pp +The +.Nm +utility +can cause severe system crashes and loss of data if used improperly. +Please +exercise caution when using this command! +.Pp +The +.Ar channel +argument is the ATA channel device (e.g., ata0) on which to operate. +The following commands are supported: +.Bl -tag -width "rebuild" +.It Ic attach +Attach an ATA +.Ar channel . +Devices on the channel are probed and attached as +is done on boot. +.It Ic detach +Detach an ATA +.Ar channel . +Devices on the channel are removed from the kernel, +and all outstanding transfers etc.\& are returned back to the system marked +as failed. +.It Ic reinit +Reinitialize an ATA +.Ar channel . +Both devices on the channel are reset and +initialized to the parameters the ATA driver has stored internally. +Devices that have gone bad and no longer respond to the probe, or devices +that have physically been removed, are removed from the kernel. +Likewise are devices that show up during a reset, probed and attached. +.It Ic create +Create a +.Ar type +ATA RAID. +The type can be +.Cm RAID0 +(stripe), +.Cm RAID1 +(mirror), +.Cm RAID0+1 , +.Cm SPAN +or +.Cm JBOD . +In case the RAID has a +.Cm RAID0 +component, +the +.Ar interleave +must be specified in number of sectors. +The RAID will be created +of the individual disks named +.Bk -words +.Ar disk0 ... diskN . +.Ek +.Pp +Although the NATA driver allows for creating an ATA RAID on disks with any +controller, there are restrictions. +It is only possible to boot on +an array if it is either located on a +.Dq real +ATA RAID controller like +the Promise or Highpoint controllers, or if the RAID declared is of +.Cm RAID1 +or +.Cm SPAN +type; in case of a +.Cm SPAN , +the partition to boot must +reside on the first disk in the SPAN. +.It Ic delete +Delete a RAID array on a RAID capable ATA controller. +.It Ic addspare +Add a spare disk to an existing RAID. +.It Ic rebuild +Rebuild a RAID1 array on a RAID capable ATA controller. +.It Ic status +Get the status of an ATA RAID. +.It Ic mode +Without the mode argument, the current transfer modes of the +device are printed. +If the mode argument is given, the NATA driver +is asked to change the transfer mode to the one given. +The NATA driver +will reject modes that are not supported by the hardware. +Modes are given like +.Dq Li PIO3 , +.Dq Li udma2 , +.Dq Li udma100 , +case does not matter. +.Pp +Currently supported modes are: +.Cm PIO0 , PIO1 , PIO2 , PIO3 , PIO4 , +.Cm WDMA2 , +.Cm UDMA2 +(alias +.Cm UDMA33 ) , +.Cm UDMA4 +(alias +.Cm UDMA66 ) , +.Cm UDMA5 +(alias +.Cm UDMA100 ) +and +.Cm UDMA6 +(alias +.Cm UDMA133 ) . +The device name and manufacture/version strings are shown. +.It Ic cap +Show detailed info about the device on +.Ar device . +.It Ic info +Show info about the attached devices on the +.Ar channel . +.It Ic list +Show info about all attached devices on all active controllers. +.El +.Sh EXAMPLES +To get information on devices attached to a channel, +use the command line: +.Pp +.Dl "natacontrol info ata0" +.Pp +To see the devices' current access modes, use the command line: +.Pp +.Dl "natacontrol mode ad0" +.Pp +which results in the modes of the devices being displayed as a string +like this: +.Pp +.Dl "current mode = UDMA100" +.Pp +You can set the mode with +.Nm +and a string like the above, +for example: +.Pp +.Dl "natacontrol mode ad0 PIO4" +.Pp +The new modes are set as soon as the +.Nm +command returns. +.Sh SEE ALSO +.Xr nata 4 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 4.6 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An S\(/oren Schmidt +.Aq sos@FreeBSD.org . +.Pp +This manual page was written by +.An S\(/oren Schmidt +.Aq sos@FreeBSD.org . diff --git a/sbin/natacontrol/natacontrol.c b/sbin/natacontrol/natacontrol.c new file mode 100644 index 0000000000..20085ac569 --- /dev/null +++ b/sbin/natacontrol/natacontrol.c @@ -0,0 +1,588 @@ +/*- + * Copyright (c) 2000 - 2006 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.42 2006/03/15 19:32:43 sos Exp $ + * $DragonFly: src/sbin/natacontrol/natacontrol.c,v 1.1 2006/12/05 21:32:21 tgen Exp $ + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +static const char *mode2str(int mode); +static int str2mode(char *str); +static void usage(void); +static int version(int ver); +static void param_print(struct ata_params *parm); +static void cap_print(struct ata_params *parm); +static int ata_cap_print(int fd); +static int info_print(int fd, int channel, int prchan); + +const char * +mode2str(int mode) +{ + switch (mode) { + case ATA_PIO: return "BIOSPIO"; + case ATA_PIO0: return "PIO0"; + case ATA_PIO1: return "PIO1"; + case ATA_PIO2: return "PIO2"; + case ATA_PIO3: return "PIO3"; + case ATA_PIO4: return "PIO4"; + case ATA_WDMA2: return "WDMA2"; + case ATA_UDMA2: return "UDMA33"; + case ATA_UDMA4: return "UDMA66"; + case ATA_UDMA5: return "UDMA100"; + case ATA_UDMA6: return "UDMA133"; + case ATA_SA150: return "SATA150"; + case ATA_SA300: return "SATA300"; + case ATA_USB: return "USB"; + case ATA_USB1: return "USB1"; + case ATA_USB2: return "USB2"; + case ATA_DMA: return "BIOSDMA"; + default: return "???"; + } +} + +int +str2mode(char *str) +{ + if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO; + if (!strcasecmp(str, "PIO0")) return ATA_PIO0; + if (!strcasecmp(str, "PIO1")) return ATA_PIO1; + if (!strcasecmp(str, "PIO2")) return ATA_PIO2; + if (!strcasecmp(str, "PIO3")) return ATA_PIO3; + if (!strcasecmp(str, "PIO4")) return ATA_PIO4; + if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2; + if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2; + if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2; + if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4; + if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4; + if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5; + if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5; + if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6; + if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6; + if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA; + return -1; +} + +void +usage() +{ + fprintf(stderr, + "usage: atacontrol args:\n" + " atacontrol list\n" + " atacontrol info channel\n" + " atacontrol attach channel\n" + " atacontrol detach channel\n" + " atacontrol reinit channel\n" + " atacontrol create type [interleave] disk0 ... diskN\n" + " atacontrol delete array\n" + " atacontrol addspare array disk\n" + " atacontrol rebuild array\n" + " atacontrol status array\n" + " atacontrol mode device [mode]\n" + " atacontrol cap device\n" + ); + exit(EX_USAGE); +} + +int +version(int ver) +{ + int bit; + + if (ver == 0xffff) + return 0; + for (bit = 15; bit >= 0; bit--) + if (ver & (1< ", parm->model, parm->revision); + if (parm->satacapabilities && parm->satacapabilities != 0xffff) { + if (parm->satacapabilities & ATA_SATA_GEN2) + printf("Serial ATA II\n"); + else if (parm->satacapabilities & ATA_SATA_GEN1) + printf("Serial ATA v1.0\n"); + else + printf("Unknown serial ATA version\n"); + } + else + printf("ATA/ATAPI revision %d\n", version(parm->version_major)); +} + +void +cap_print(struct ata_params *parm) +{ + u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | + ((u_int32_t)parm->lba_size_2 << 16); + + u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | + ((u_int64_t)parm->lba_size48_2 << 16) | + ((u_int64_t)parm->lba_size48_3 << 32) | + ((u_int64_t)parm->lba_size48_4 << 48); + + printf("\n"); + printf("Protocol "); + if (parm->satacapabilities && parm->satacapabilities != 0xffff) { + if (parm->satacapabilities & ATA_SATA_GEN2) + printf("Serial ATA II\n"); + else if (parm->satacapabilities & ATA_SATA_GEN1) + printf("Serial ATA v1.0\n"); + else + printf("Unknown serial ATA version\n"); + } + else + printf("ATA/ATAPI revision %d\n", version(parm->version_major)); + printf("device model %.40s\n", parm->model); + printf("serial number %.20s\n", parm->serial); + printf("firmware revision %.8s\n", parm->revision); + + printf("cylinders %d\n", parm->cylinders); + printf("heads %d\n", parm->heads); + printf("sectors/track %d\n", parm->sectors); + + printf("lba%ssupported ", + parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not "); + if (lbasize) + printf("%d sectors\n", lbasize); + else + printf("\n"); + + printf("lba48%ssupported ", + parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not "); + if (lbasize48) + printf("%llu sectors\n", (unsigned long long)lbasize48); + else + printf("\n"); + + printf("dma%ssupported\n", + parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not "); + + printf("overlap%ssupported\n", + parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not "); + + printf("\nFeature " + "Support Enable Value Vendor\n"); + + printf("write cache %s %s\n", + parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no", + parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no"); + + printf("read ahead %s %s\n", + parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no", + parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no"); + + if (parm->satacapabilities && parm->satacapabilities != 0xffff) { + printf("Native Command Queuing (NCQ) %s %s" + " %d/0x%02X\n", + parm->satacapabilities & ATA_SUPPORT_NCQ ? + "yes" : "no", " -", + (parm->satacapabilities & ATA_SUPPORT_NCQ) ? + ATA_QUEUE_LEN(parm->queue) : 0, + (parm->satacapabilities & ATA_SUPPORT_NCQ) ? + ATA_QUEUE_LEN(parm->queue) : 0); + } + printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n", + parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no", + parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no", + ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue)); + + printf("SMART %s %s\n", + parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no", + parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no"); + + printf("microcode download %s %s\n", + parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no", + parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no"); + + printf("security %s %s\n", + parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no", + parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no"); + + printf("power management %s %s\n", + parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no", + parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no"); + + printf("advanced power management %s %s %d/0x%02X\n", + parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no", + parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no", + parm->apm_value, parm->apm_value); + + printf("automatic acoustic management %s %s " + "%d/0x%02X %d/0x%02X\n", + parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no", + parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no", + ATA_ACOUSTIC_CURRENT(parm->acoustic), + ATA_ACOUSTIC_CURRENT(parm->acoustic), + ATA_ACOUSTIC_VENDOR(parm->acoustic), + ATA_ACOUSTIC_VENDOR(parm->acoustic)); +} + +int +ata_cap_print(int fd) +{ + struct ata_params params; + + if (ioctl(fd, IOCATAGPARM, ¶ms) < 0) + return errno; + cap_print(¶ms); + return 0; +} + +int +info_print(int fd, int channel, int prchan) +{ + struct ata_ioc_devices devices; + + devices.channel = channel; + + if (ioctl(fd, IOCATADEVICES, &devices) < 0) + return errno; + + if (prchan) + printf("ATA channel %d:\n", channel); + printf("%sMaster: ", prchan ? " " : ""); + if (*devices.name[0]) { + printf("%4.4s ", devices.name[0]); + param_print(&devices.params[0]); + } + else + printf(" no device present\n"); + printf("%sSlave: ", prchan ? " " : ""); + if (*devices.name[1]) { + printf("%4.4s ", devices.name[1]); + param_print(&devices.params[1]); + } + else + printf(" no device present\n"); + return 0; +} + +int +main(int argc, char **argv) +{ + int fd; + + if (argc < 2) + usage(); + + if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) { + int disk, mode; + char device[64]; + + if (!(sscanf(argv[2], "ad%d", &disk) == 1 || + sscanf(argv[2], "acd%d", &disk) == 1 || + sscanf(argv[2], "afd%d", &disk) == 1 || + sscanf(argv[2], "ast%d", &disk) == 1)) { + fprintf(stderr, "atacontrol: Invalid device %s\n", + argv[2]); + exit(EX_USAGE); + } + sprintf(device, "/dev/%s", argv[2]); + if ((fd = open(device, O_RDONLY)) < 0) + err(1, "device not found"); + if (argc == 4) { + mode = str2mode(argv[3]); + if (ioctl(fd, IOCATASMODE, &mode) < 0) + warn("ioctl(IOCATASMODE)"); + } + if (argc == 3 || argc == 4) { + if (ioctl(fd, IOCATAGMODE, &mode) < 0) + err(1, "ioctl(IOCATAGMODE)"); + printf("current mode = %s\n", mode2str(mode)); + } + exit(EX_OK); + } + if (!strcmp(argv[1], "cap") && argc == 3) { + int disk; + char device[64]; + + if (!(sscanf(argv[2], "ad%d", &disk) == 1 || + sscanf(argv[2], "acd%d", &disk) == 1 || + sscanf(argv[2], "afd%d", &disk) == 1 || + sscanf(argv[2], "ast%d", &disk) == 1)) { + fprintf(stderr, "atacontrol: Invalid device %s\n", + argv[2]); + exit(EX_USAGE); + } + sprintf(device, "/dev/%s", argv[2]); + if ((fd = open(device, O_RDONLY)) < 0) + err(1, "device not found"); + ata_cap_print(fd); + exit(EX_OK); + } + + if ((fd = open("/dev/ata", O_RDWR)) < 0) + err(1, "control device not found"); + + if (!strcmp(argv[1], "list") && argc == 2) { + int maxchannel, channel; + + if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) + err(1, "ioctl(IOCATAGMAXCHANNEL)"); + for (channel = 0; channel < maxchannel; channel++) + info_print(fd, channel, 1); + exit(EX_OK); + } + if (!strcmp(argv[1], "info") && argc == 3) { + int channel; + + if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { + fprintf(stderr, + "atacontrol: Invalid channel %s\n", argv[2]); + exit(EX_USAGE); + } + info_print(fd, channel, 0); + exit(EX_OK); + } + if (!strcmp(argv[1], "detach") && argc == 3) { + int channel; + + if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { + fprintf(stderr, + "atacontrol: Invalid channel %s\n", argv[2]); + exit(EX_USAGE); + } + if (ioctl(fd, IOCATADETACH, &channel) < 0) + err(1, "ioctl(IOCATADETACH)"); + exit(EX_OK); + } + if (!strcmp(argv[1], "attach") && argc == 3) { + int channel; + + if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { + fprintf(stderr, + "atacontrol: Invalid channel %s\n", argv[2]); + exit(EX_USAGE); + } + if (ioctl(fd, IOCATAATTACH, &channel) < 0) + err(1, "ioctl(IOCATAATTACH)"); + info_print(fd, channel, 0); + exit(EX_OK); + } + if (!strcmp(argv[1], "reinit") && argc == 3) { + int channel; + + if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { + fprintf(stderr, + "atacontrol: Invalid channel %s\n", argv[2]); + exit(EX_USAGE); + } + if (ioctl(fd, IOCATAREINIT, &channel) < 0) + warn("ioctl(IOCATAREINIT)"); + info_print(fd, channel, 0); + exit(EX_OK); + } + if (!strcmp(argv[1], "create")) { + int disk, dev, offset; + struct ata_ioc_raid_config config; + + bzero(&config, sizeof(config)); + if (argc > 2) { + if (!strcasecmp(argv[2], "RAID0") || + !strcasecmp(argv[2], "stripe")) + config.type = AR_RAID0; + if (!strcasecmp(argv[2], "RAID1") || + !strcasecmp(argv[2],"mirror")) + config.type = AR_RAID1; + if (!strcasecmp(argv[2], "RAID0+1") || + !strcasecmp(argv[2],"RAID10")) + config.type = AR_RAID01; + if (!strcasecmp(argv[2], "RAID5")) + config.type = AR_RAID5; + if (!strcasecmp(argv[2], "SPAN")) + config.type = AR_SPAN; + if (!strcasecmp(argv[2], "JBOD")) + config.type = AR_JBOD; + } + if (!config.type) { + fprintf(stderr, "atacontrol: Invalid RAID type %s\n", + argv[2]); + fprintf(stderr, "atacontrol: Valid RAID types: \n"); + fprintf(stderr, " stripe | mirror | " + "RAID0 | RAID1 | RAID0+1 | RAID5 | " + "SPAN | JBOD\n"); + exit(EX_USAGE); + } + + if (config.type == AR_RAID0 || + config.type == AR_RAID01 || + config.type == AR_RAID5) { + if (argc < 4 || + !sscanf(argv[3], "%d", &config.interleave) == 1) { + fprintf(stderr, + "atacontrol: Invalid interleave %s\n", + argv[3]); + exit(EX_USAGE); + } + offset = 4; + } + else + offset = 3; + + for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) { + if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) { + fprintf(stderr, + "atacontrol: Invalid disk %s\n", + argv[offset + disk]); + exit(EX_USAGE); + } + config.disks[disk] = dev; + } + + if ((config.type == AR_RAID1 || config.type == AR_RAID01) && + disk < 2) { + fprintf(stderr, "atacontrol: At least 2 disks must be " + "specified\n"); + exit(EX_USAGE); + } + + config.total_disks = disk; + if (ioctl(fd, IOCATARAIDCREATE, &config) < 0) + err(1, "ioctl(IOCATARAIDCREATE)"); + else + printf("ar%d created\n", config.lun); + exit(EX_OK); + } + if (!strcmp(argv[1], "delete") && argc == 3) { + int array; + + if (!(sscanf(argv[2], "ar%d", &array) == 1)) { + fprintf(stderr, + "atacontrol: Invalid array %s\n", argv[2]); + exit(EX_USAGE); + } + if (ioctl(fd, IOCATARAIDDELETE, &array) < 0) + warn("ioctl(IOCATARAIDDELETE)"); + exit(EX_OK); + } + if (!strcmp(argv[1], "addspare") && argc == 4) { + struct ata_ioc_raid_config config; + + if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) { + fprintf(stderr, + "atacontrol: Invalid array %s\n", argv[2]); + usage(); + } + if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) { + fprintf(stderr, + "atacontrol: Invalid disk %s\n", argv[3]); + usage(); + } + if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0) + warn("ioctl(IOCATARAIDADDSPARE)"); + exit(EX_OK); + } + if (!strcmp(argv[1], "rebuild") && argc == 3) { + int array; + + if (!(sscanf(argv[2], "ar%d", &array) == 1)) { + fprintf(stderr, + "atacontrol: Invalid array %s\n", argv[2]); + usage(); + } + if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0) + warn("ioctl(IOCATARAIDREBUILD)"); + else { + char buffer[128]; + sprintf(buffer, "/usr/bin/nice -n 20 /bin/dd " + "if=/dev/ar%d of=/dev/null bs=1m &", + array); + if (system(buffer)) + warn("background dd"); + } + exit(EX_OK); + } + if (!strcmp(argv[1], "status") && argc == 3) { + struct ata_ioc_raid_config config; + int i; + + if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) { + fprintf(stderr, + "atacontrol: Invalid array %s\n", argv[2]); + usage(); + } + if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0) + err(1, "ioctl(IOCATARAIDSTATUS)"); + + printf("ar%d: ATA ", config.lun); + switch (config.type) { + case AR_RAID0: + printf("RAID0 stripesize=%d", config.interleave); + break; + case AR_RAID1: + printf("RAID1"); + break; + case AR_RAID01: + printf("RAID0+1 stripesize=%d", config.interleave); + break; + case AR_RAID5: + printf("RAID5 stripesize=%d", config.interleave); + break; + case AR_JBOD: + printf("JBOD"); + case AR_SPAN: + printf("SPAN"); + break; + } + printf(" subdisks: "); + for (i = 0; i < config.total_disks; i++) { + if (config.disks[i] >= 0) + printf("ad%d ", config.disks[i]); + else + printf("DOWN "); + } + printf("status: "); + switch (config.status) { + case AR_READY: + printf("READY\n"); + break; + case AR_READY | AR_DEGRADED: + printf("DEGRADED\n"); + break; + case AR_READY | AR_DEGRADED | AR_REBUILDING: + printf("REBUILDING %d%% completed\n", + config.progress); + break; + default: + printf("BROKEN\n"); + } + exit(EX_OK); + } + usage(); + exit(EX_OK); +}