--- //depot/yahoo/ybsd_6/src/sbin/atacontrol/atacontrol.8 2006/02/01 21:28:07 +++ //depot/jhb/bsd6/src/sbin/atacontrol/atacontrol.8 2007/06/05 07:41:51 @@ -55,6 +55,12 @@ .Ic addspare .Ar raid disk .Nm +.Ic rmspare +.Ar raid disk +.Nm +.Ic fail +.Ar raid disk +.Nm .Ic rebuild .Ar raid .Nm @@ -153,6 +159,10 @@ Delete a RAID array on a RAID capable ATA controller. .It Ic addspare Add a spare disk to an existing RAID. +.It Ic rmspare +Remove a spare disk from an existing RAID. +.It Ic +Fail a disk in an existing RAID. .It Ic rebuild Rebuild a RAID1 array on a RAID capable ATA controller. .It Ic status --- //depot/yahoo/ybsd_6/src/sbin/atacontrol/atacontrol.c 2006/03/18 15:10:55 +++ //depot/jhb/bsd6/src/sbin/atacontrol/atacontrol.c 2007/05/30 07:43:08 @@ -107,6 +107,8 @@ " atacontrol create type [interleave] disk0 ... diskN\n" " atacontrol delete array\n" " atacontrol addspare array disk\n" + " atacontrol rmspare array disk\n" + " atacontrol fail array disk\n" " atacontrol rebuild array\n" " atacontrol status array\n" " atacontrol mode device [mode]\n" @@ -507,6 +509,40 @@ warn("ioctl(IOCATARAIDADDSPARE)"); exit(EX_OK); } + if (!strcmp(argv[1], "rmspare") && 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, IOCATARAIDRMSPARE, &config) < 0) + warn("ioctl(IOCATARAIDRMSPARE)"); + exit(EX_OK); + } + if (!strcmp(argv[1], "fail") && 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, IOCATARAIDFAIL, &config) < 0) + warn("ioctl(IOCATARAIDFAIL)"); + exit(EX_OK); + } if (!strcmp(argv[1], "rebuild") && argc == 3) { int array; @@ -529,6 +565,7 @@ } if (!strcmp(argv[1], "status") && argc == 3) { struct ata_ioc_raid_config config; + struct ata_ioc_raid_status status; int i; if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) { @@ -536,8 +573,18 @@ "atacontrol: Invalid array %s\n", argv[2]); usage(); } - if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0) - err(1, "ioctl(IOCATARAIDSTATUS)"); + status.lun = config.lun; + if (ioctl(fd, IOCATARAIDSTATUS2, &status) < 0) { + status.lun = -1; + if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0) + err(1, "ioctl(IOCATARAIDSTATUS)"); + } else { + config.type = status.type; + config.interleave = status.interleave; + config.status = status.status; + config.progress = status.progress; + config.total_disks = status.total_disks; + } printf("ar%d: ATA ", config.lun); switch (config.type) { @@ -559,13 +606,16 @@ 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 "); - } + if (status.lun < 0) { + printf(" subdisks: "); + for (i = 0; i < config.total_disks; i++) { + if (config.disks[i] >= 0) + printf("ad%d ", config.disks[i]); + else + printf("DOWN "); + } + } else + printf(" "); printf("status: "); switch (config.status) { case AR_READY: @@ -581,6 +631,29 @@ default: printf("BROKEN\n"); } + if (status.lun >= 0) { + int lun, state; + + printf(" subdisks:\n"); + for (i = 0; i < status.total_disks; i++) { + printf(" %2d ", i); + lun = status.disks[i].lun; + state = status.disks[i].state; + if (lun < 0) + printf("---- "); + else + printf("ad%-2d ", lun); + if (state & AR_DISK_ONLINE) + printf("ONLINE"); + else if (state & AR_DISK_SPARE) + printf("SPARE"); + else if (state & AR_DISK_PRESENT) + printf("OFFLINE"); + else + printf("MISSING"); + printf("\n"); + } + } exit(EX_OK); } usage(); --- //depot/yahoo/ybsd_6/src/sys/dev/ata/ata-raid.c 2006/09/08 10:24:50 +++ //depot/jhb/bsd6/src/sys/dev/ata/ata-raid.c 2007/05/30 07:43:08 @@ -57,9 +57,12 @@ static void ata_raid_done(struct ata_request *request); static void ata_raid_config_changed(struct ar_softc *rdp, int writeback); static int ata_raid_status(struct ata_ioc_raid_config *config); +static int ata_raid_status2(struct ata_ioc_raid_status *status); static int ata_raid_create(struct ata_ioc_raid_config *config); static int ata_raid_delete(int array); static int ata_raid_addspare(struct ata_ioc_raid_config *config); +static int ata_raid_rmspare(struct ata_ioc_raid_config *config); +static int ata_raid_fail(struct ata_ioc_raid_config *config); static int ata_raid_rebuild(int array); static int ata_raid_read_metadata(device_t subdisk); static int ata_raid_write_metadata(struct ar_softc *rdp); @@ -201,6 +204,7 @@ static int ata_raid_ioctl(u_long cmd, caddr_t data) { + struct ata_ioc_raid_status *status = (struct ata_ioc_raid_status *)data; struct ata_ioc_raid_config *config = (struct ata_ioc_raid_config *)data; int *lun = (int *)data; int error = EOPNOTSUPP; @@ -209,6 +213,10 @@ case IOCATARAIDSTATUS: error = ata_raid_status(config); break; + + case IOCATARAIDSTATUS2: + error = ata_raid_status2(status); + break; case IOCATARAIDCREATE: error = ata_raid_create(config); @@ -221,6 +229,14 @@ case IOCATARAIDADDSPARE: error = ata_raid_addspare(config); break; + + case IOCATARAIDRMSPARE: + error = ata_raid_rmspare(config); + break; + + case IOCATARAIDFAIL: + error = ata_raid_fail(config); + break; case IOCATARAIDREBUILD: error = ata_raid_rebuild(*lun); @@ -865,23 +881,52 @@ static int ata_raid_status(struct ata_ioc_raid_config *config) { + struct ata_ioc_raid_status status; + int error, i; + + status.lun = config->lun; + error = ata_raid_status2(&status); + if (error) + return error; + + config->type = status.type; + config->total_disks = status.total_disks; + config->interleave = status.interleave; + config->status = status.status; + config->progress = status.progress; + + for (i = 0; i < config->total_disks; i++) + config->disks[i] = status.disks[i].lun; + return (0); +} + +static int +ata_raid_status2(struct ata_ioc_raid_status *status) +{ struct ar_softc *rdp; int i; - if (!(rdp = ata_raid_arrays[config->lun])) + if (!(rdp = ata_raid_arrays[status->lun])) return ENXIO; - config->type = rdp->type; - config->total_disks = rdp->total_disks; + status->type = rdp->type; + status->total_disks = rdp->total_disks; for (i = 0; i < rdp->total_disks; i++ ) { - if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].dev) - config->disks[i] = device_get_unit(rdp->disks[i].dev); - else - config->disks[i] = -1; + status->disks[i].state = 0; + if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].dev) { + status->disks[i].lun = device_get_unit(rdp->disks[i].dev); + if (rdp->disks[i].flags & AR_DF_PRESENT) + status->disks[i].state |= AR_DISK_PRESENT; + if (rdp->disks[i].flags & AR_DF_ONLINE) + status->disks[i].state |= AR_DISK_ONLINE; + if (rdp->disks[i].flags & AR_DF_SPARE) + status->disks[i].state |= AR_DISK_SPARE; + } else + status->disks[i].lun = -1; } - config->interleave = rdp->interleave; - config->status = rdp->status; - config->progress = 100 * rdp->rebuild_lba / rdp->total_sectors; + status->interleave = rdp->interleave; + status->status = rdp->status; + status->progress = 100 * rdp->rebuild_lba / rdp->total_sectors; return 0; } @@ -1173,7 +1218,8 @@ static int ata_raid_addspare(struct ata_ioc_raid_config *config) { - struct ar_softc *rdp; + struct ata_raid_subdisk *ars; + struct ar_softc *rdp; device_t subdisk; int disk; @@ -1182,37 +1228,46 @@ if (!(rdp->status & AR_S_DEGRADED) || !(rdp->status & AR_S_READY)) return ENXIO; if (rdp->status & AR_S_REBUILDING) - return EBUSY; + return EBUSY; switch (rdp->type) { case AR_T_RAID1: case AR_T_RAID01: case AR_T_RAID5: + subdisk = devclass_get_device(ata_raid_sub_devclass, config->disks[0]); + if (subdisk == NULL) + return ENXIO; + ars = device_get_softc(subdisk); + if (ars->raid[rdp->volume]) { + for (disk = 0; disk < rdp->total_disks; disk++ ) { + if (rdp->disks[disk].dev == device_get_parent(subdisk) && + (rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE | + AR_DF_SPARE)) == AR_DF_PRESENT) { + rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_SPARE); + device_printf(rdp->disks[disk].dev, + "converted to spare disk%d in ar%d\n", disk, rdp->lun); + ata_raid_config_changed(rdp, 1); + return 0; + } + } + return EBUSY; + } for (disk = 0; disk < rdp->total_disks; disk++ ) { if (((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[disk].dev) continue; - if ((subdisk = devclass_get_device(ata_raid_sub_devclass, - config->disks[0] ))) { - struct ata_raid_subdisk *ars = device_get_softc(subdisk); + /* XXX SOS validate size etc etc */ + ars->raid[rdp->volume] = rdp; + ars->disk_number[rdp->volume] = disk; + rdp->disks[disk].dev = device_get_parent(subdisk); + rdp->disks[disk].flags = + (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE); - if (ars->raid[rdp->volume]) - return EBUSY; - - /* XXX SOS validate size etc etc */ - ars->raid[rdp->volume] = rdp; - ars->disk_number[rdp->volume] = disk; - rdp->disks[disk].dev = device_get_parent(subdisk); - rdp->disks[disk].flags = - (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE); - - device_printf(rdp->disks[disk].dev, - "inserted into ar%d disk%d as spare\n", - rdp->lun, disk); - ata_raid_config_changed(rdp, 1); - return 0; - } + device_printf(rdp->disks[disk].dev, + "inserted into ar%d disk%d as spare\n", rdp->lun, disk); + ata_raid_config_changed(rdp, 1); + return 0; } return ENXIO; @@ -1220,7 +1275,65 @@ return EPERM; } } - + +static int +ata_raid_rmspare(struct ata_ioc_raid_config *config) +{ + struct ar_softc *rdp; + int disk; + + if (!(rdp = ata_raid_arrays[config->lun])) + return ENXIO; + if (rdp->status & AR_S_REBUILDING) + return EBUSY; + + for (disk = 0; disk < rdp->total_disks; disk++ ) { + if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_SPARE)) != + (AR_DF_PRESENT | AR_DF_SPARE)) + continue; + if (!rdp->disks[disk].dev) + continue; + if (device_get_unit(rdp->disks[disk].dev) != config->disks[0]) + continue; + + rdp->disks[disk].flags &= ~AR_DF_SPARE; + device_printf(rdp->disks[disk].dev, "removed as spare from ar%d\n", + rdp->lun); + ata_raid_config_changed(rdp, 1); + return 0; + } + return ENXIO; +} + +static int +ata_raid_fail(struct ata_ioc_raid_config *config) +{ + struct ar_softc *rdp; + int disk; + + if (!(rdp = ata_raid_arrays[config->lun])) + return ENXIO; + if (rdp->status & AR_S_REBUILDING) + return EBUSY; + + for (disk = 0; disk < rdp->total_disks; disk++ ) { + if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) != + (AR_DF_PRESENT | AR_DF_ONLINE)) + continue; + if (!rdp->disks[disk].dev) + continue; + if (device_get_unit(rdp->disks[disk].dev) != config->disks[0]) + continue; + + rdp->disks[disk].flags &= ~AR_DF_ONLINE; + device_printf(rdp->disks[disk].dev, "marked as offline from ar%d\n", + rdp->lun); + ata_raid_config_changed(rdp, 1); + return 0; + } + return ENXIO; +} + static int ata_raid_rebuild(int array) { --- //depot/yahoo/ybsd_6/src/sys/sys/ata.h 2007/02/08 13:32:11 +++ //depot/jhb/bsd6/src/sys/sys/ata.h 2007/06/05 07:46:41 @@ -447,11 +447,30 @@ int disks[16]; }; +struct ata_ioc_raid_status { + int lun; + int type; + int interleave; + int status; + int progress; + int total_disks; + struct { + int state; +#define AR_DISK_ONLINE 0x01 +#define AR_DISK_PRESENT 0x02 +#define AR_DISK_SPARE 0x04 + int lun; + } disks[16]; +}; + /* ATA RAID ioctl calls */ #define IOCATARAIDCREATE _IOWR('a', 200, struct ata_ioc_raid_config) #define IOCATARAIDDELETE _IOW('a', 201, int) #define IOCATARAIDSTATUS _IOWR('a', 202, struct ata_ioc_raid_config) #define IOCATARAIDADDSPARE _IOW('a', 203, struct ata_ioc_raid_config) #define IOCATARAIDREBUILD _IOW('a', 204, int) +#define IOCATARAIDRMSPARE _IOW('a', 205, struct ata_ioc_raid_config) +#define IOCATARAIDFAIL _IOW('a', 206, struct ata_ioc_raid_config) +#define IOCATARAIDSTATUS2 _IOWR('a', 207, struct ata_ioc_raid_status) #endif /* _SYS_ATA_H_ */