diff options
author | sos <sos@FreeBSD.org> | 2002-02-12 11:35:15 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2002-02-12 11:35:15 +0000 |
commit | 334f09ed2aa2cadf1a5a71122136f5ef65f30423 (patch) | |
tree | 0c8c08ffda24c52313dd92cb9925bfcc9f6e4d43 /sys/dev/ata | |
parent | 050837293fd14801c43b6cdedb8f4af1561a00de (diff) | |
download | FreeBSD-src-334f09ed2aa2cadf1a5a71122136f5ef65f30423.zip FreeBSD-src-334f09ed2aa2cadf1a5a71122136f5ef65f30423.tar.gz |
Major update of the ATA RAID code, part 2:
More cleanups of the RAID1 failure mode code.
Add functionality that writes the changed RAID config setup
back to the disks (in controller BIOS specific format), so
that a reboot will make the BIOS pick up the changed config.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r-- | sys/dev/ata/ata-all.c | 13 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 4 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.c | 525 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.h | 27 | ||||
-rw-r--r-- | sys/dev/ata/atapi-all.c | 4 |
5 files changed, 420 insertions, 153 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 7774c69..2851c3c 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -531,7 +531,7 @@ ata_boot_attach(void) if (ch->devices & ATA_ATA_SLAVE) ad_attach(&ch->device[SLAVE]); } - atar_attach(); + ata_raid_attach(); #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) /* then the atapi devices */ @@ -1075,14 +1075,6 @@ void ata_drawerleds(struct ata_device *atadev, u_int8_t color) { u_int8_t count, drive; - int s = splbio(); - int state; - - if ((state = atadev->channel->active) != ATA_CONTROL) { - while (!atomic_cmpset_int(&atadev->channel->active, - ATA_IDLE, ATA_CONTROL)) - tsleep((caddr_t)&s, PRIBIO, "ataled", hz/4); - } /* magic sequence to set the LED color on the Promise SuperSwap */ ATA_INB(atadev->channel->r_io, ATA_DRIVE); @@ -1101,9 +1093,6 @@ ata_drawerleds(struct ata_device *atadev, u_int8_t color) DELAY(1); ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit); DELAY(1); - - atadev->channel->active = state; - splx(s); } static void diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 68b5262..e97b5df 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -209,9 +209,10 @@ ad_attach(struct ata_device *atadev) adp->disk.d_label.d_secperunit = adp->total_secs; atadev->driver = adp; + atadev->flags = 0; /* if this disk belongs to an ATA RAID dont print the probe */ - if (!ar_probe(adp)) + if (!ata_raid_probe(adp)) adp->flags |= AD_F_RAID_SUBDISK; else ad_print(adp, ""); @@ -248,6 +249,7 @@ ad_detach(struct ata_device *atadev, int flush) /* get rid of flush XXX SOS */ ata_free_name(atadev); ata_free_lun(&adp_lun_map, adp->lun); atadev->driver = NULL; + atadev->flags = 0; free(adp, M_AD); } diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 3aa7fd0..b6bf07e 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -69,24 +69,30 @@ static struct cdevsw ardisk_cdevsw; /* prototypes */ static void ar_done(struct bio *); +static void ar_config_changed(struct ar_softc *, int); static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **); +static int ar_highpoint_write_conf(struct ar_softc *); static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **); +static int ar_promise_write_conf(struct ar_softc *); static int ar_read(struct ad_softc *, u_int32_t, int, u_int8_t *); +static int ar_write(struct ad_softc *, u_int32_t, int, u_int8_t *); /* misc defines */ #define AD_STRATEGY(x) si_disk->d_devsw->d_strategy(x) #define AD_SOFTC(x) ((struct ad_softc *)(x.device->driver)) /* internal vars */ -static int ar_init = 0; -static struct ar_softc *ar_table[MAX_ARRAYS]; +static struct ar_softc **ar_table = NULL; static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver"); int -ar_probe(struct ad_softc *adp) { - if (!ar_init) { - bzero(&ar_table, sizeof(ar_table)); - ar_init = 1; +ata_raid_probe(struct ad_softc *adp) { + if (!ar_table) + ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS, + M_AR, M_NOWAIT | M_ZERO); + if (!ar_table) { + ata_prtdev(adp->device, "no memory for ATA raid array\n"); + return 1; } switch(adp->device->channel->chiptype) { @@ -96,65 +102,56 @@ ar_probe(struct ad_softc *adp) { case 0x0d30105a: case 0x4d68105a: case 0x6268105a: - /* test RAID bit in PCI reg */ + /* test RAID bit in PCI reg XXX */ return (ar_promise_read_conf(adp, ar_table)); case 0x00041103: - /* test RAID bit in PCI reg */ + case 0x00081103: return (ar_highpoint_read_conf(adp, ar_table)); } return 1; } void -atar_attach() +ata_raid_attach() { struct ar_softc *raid; dev_t dev; int array, disk; for (array = 0; array < MAX_ARRAYS; array++) { - if (!(raid = ar_table[array]) || !raid->flags) { + if (!(raid = ar_table[array]) || !raid->flags) continue; - } for (disk = 0; disk < raid->total_disks; disk++) { - if (raid->disks[disk].device) { - switch (raid->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: - case AR_F_RAID0: - if (raid->disks[disk].flags & AR_DF_ONLINE) - ata_drawerleds(raid->disks[disk].device, ATA_LED_GREEN); - else { - raid->flags &= ~AR_F_READY; - ata_drawerleds(raid->disks[disk].device, ATA_LED_RED); - } - break; + switch (raid->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { + case AR_F_SPAN: + case AR_F_RAID0: + if (!(raid->disks[disk].flags & AR_DF_ONLINE)) + raid->flags &= ~AR_F_READY; + break; - case AR_F_RAID1: - case AR_F_RAID0 | AR_F_RAID1: - if (disk < raid->width) { - if (!(raid->disks[disk].flags & AR_DF_ONLINE) && - !(raid->disks[disk+raid->width].flags&AR_DF_ONLINE)) - raid->flags &= ~AR_F_READY; - else if (((raid->disks[disk].flags & AR_DF_ONLINE) && - !(raid->disks - [disk + raid->width].flags & AR_DF_ONLINE))|| - (!(raid->disks[disk].flags & AR_DF_ONLINE) && - (raid->disks - [disk + raid->width].flags & AR_DF_ONLINE))) - raid->flags |= AR_F_DEGRADED; - } - if (raid->disks[disk].flags & AR_DF_ONLINE) - ata_drawerleds(raid->disks[disk].device, ATA_LED_GREEN); - else - ata_drawerleds(raid->disks[disk].device, ATA_LED_RED); - break; + case AR_F_RAID1: + case AR_F_RAID0 | AR_F_RAID1: + if (disk < raid->width) { + if (!(raid->disks[disk].flags & AR_DF_ONLINE) && + !(raid->disks[disk+raid->width].flags&AR_DF_ONLINE)) + raid->flags &= ~AR_F_READY; + else if (((raid->disks[disk].flags & AR_DF_ONLINE) && + !(raid->disks + [disk + raid->width].flags & AR_DF_ONLINE))|| + (!(raid->disks[disk].flags & AR_DF_ONLINE) && + (raid->disks + [disk + raid->width].flags & AR_DF_ONLINE))) + raid->flags |= AR_F_DEGRADED; } + break; } - else { - raid->disks[disk].flags &= - ~(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); + if (raid->disks[disk].device) { + if (raid->disks[disk].flags & AR_DF_ONLINE) + ata_drawerleds(raid->disks[disk].device, ATA_LED_GREEN); + else + ata_drawerleds(raid->disks[disk].device, ATA_LED_RED); } } @@ -175,7 +172,7 @@ atar_attach() case (AR_F_RAID0 | AR_F_RAID1): printf("RAID0+1 "); break; default: - printf("unknown 0x%x ", raid->flags); + printf("unknown 0x%x> ", raid->flags); return; } printf("array> [%d/%d/%d] status: ", @@ -202,7 +199,7 @@ atar_attach() else if (raid->disks[disk].flags & AR_DF_PRESENT) printf(" %d FREE ", disk); else - printf(" %d FAILURE no device present\n", disk); + printf(" %d INVALID no RAID config info on this disk\n", disk); if (raid->disks[disk].flags & AR_DF_PRESENT) ad_print(AD_SOFTC(raid->disks[disk]), ""); } @@ -288,7 +285,7 @@ arstrategy(struct bio *bp) break; default: - printf("Oops! unknown array type in arstrategy\n"); + printf("ar%d: unknown array type in arstrategy\n", rdp->lun); bp->bio_flags |= BIO_ERROR; bp->bio_error = EIO; biodone(bp); @@ -297,7 +294,6 @@ arstrategy(struct bio *bp) if (buf1->drive > 0) buf1->bp.bio_pblkno += rdp->offset; - buf1->bp.bio_caller1 = (void *)rdp; buf1->bp.bio_bcount = chunk * DEV_BSIZE; buf1->bp.bio_data = data; @@ -310,10 +306,10 @@ arstrategy(struct bio *bp) case AR_F_SPAN: case AR_F_RAID0: if (!AD_SOFTC(rdp->disks[buf1->drive])->dev->si_disk) { - rdp->disks[buf1->drive].flags = ~(AR_DF_PRESENT | AR_DF_ONLINE); - ata_drawerleds(rdp->disks[buf1->drive].device, ATA_LED_RED); + rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; rdp->flags &= ~AR_F_READY; printf("ar%d: ERROR broken array in strategy\n", rdp->lun); + ar_config_changed(rdp, buf1->drive); bp->bio_flags |= BIO_ERROR; bp->bio_error = EIO; biodone(bp); @@ -335,27 +331,25 @@ arstrategy(struct bio *bp) } if (rdp->disks[buf1->drive].flags & AR_DF_ONLINE && !AD_SOFTC(rdp->disks[buf1->drive])->dev->si_disk) { - rdp->disks[buf1->drive].flags = ~(AR_DF_PRESENT | AR_DF_ONLINE); - ata_drawerleds(rdp->disks[buf1->drive].device, ATA_LED_RED); + rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; if (rdp->disks[buf1->drive + rdp->width].flags & AR_DF_ONLINE) { rdp->flags |= AR_F_DEGRADED; printf("ar%d: WARNING mirror lost in strategy\n", rdp->lun); } else rdp->flags &= ~AR_F_READY; + ar_config_changed(rdp, buf1->drive); } if (rdp->disks[buf1->drive + rdp->width].flags & AR_DF_ONLINE && !AD_SOFTC(rdp->disks[buf1->drive + rdp->width])->dev->si_disk) { - rdp->disks[buf1->drive + rdp->width].flags = - ~(AR_DF_PRESENT | AR_DF_ONLINE); - ata_drawerleds(rdp->disks[buf1->drive + rdp->width].device, - ATA_LED_RED); + rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE; if (rdp->disks[buf1->drive].flags & AR_DF_ONLINE) { rdp->flags |= AR_F_DEGRADED; printf("ar%d: WARNING mirror lost in strategy\n", rdp->lun); } else rdp->flags &= ~AR_F_READY; + ar_config_changed(rdp, buf1->drive); } if (!(rdp->flags & AR_F_READY)) { printf("ar%d: ERROR broken array in strategy\n", rdp->lun); @@ -396,7 +390,7 @@ arstrategy(struct bio *bp) rdp->disks[buf1->drive].last_lba = buf1->bp.bio_pblkno + chunk; break; default: - printf("DOH!! unknown array type in arstrategy\n"); + printf("ar%d: unknown array type in arstrategy\n", rdp->lun); } } } @@ -406,22 +400,19 @@ ar_done(struct bio *bp) { struct ar_softc *rdp = (struct ar_softc *)bp->bio_caller1; struct ar_buf *buf = (struct ar_buf *)bp; - int s; - - s = splbio(); + int s = splbio(); switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { - case AR_F_SPAN: case AR_F_RAID0: if (bp->bio_flags & BIO_ERROR) { - printf("ar%d: ERROR broken array in done\n", rdp->lun); - rdp->disks[buf->drive].flags = ~(AR_DF_PRESENT | AR_DF_ONLINE); + rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE; rdp->flags &= ~AR_F_READY; + printf("ar%d: ERROR broken array in done\n", rdp->lun); + ar_config_changed(rdp, buf->drive); buf->org->bio_flags |= BIO_ERROR; buf->org->bio_error = EIO; biodone(buf->org); - ata_drawerleds(rdp->disks[buf->drive].device, ATA_LED_RED); } else { buf->org->bio_resid -= buf->bp.bio_bcount; @@ -433,12 +424,14 @@ ar_done(struct bio *bp) case AR_F_RAID1: case AR_F_RAID0 | AR_F_RAID1: if (bp->bio_flags & BIO_ERROR) { - rdp->disks[buf->drive].flags = ~(AR_DF_PRESENT | AR_DF_ONLINE); - ata_drawerleds(rdp->disks[buf->drive].device, ATA_LED_RED); - if (rdp->flags & AR_F_DEGRADED && - !(rdp->disks[buf->mirror->drive].flags & AR_DF_ONLINE)) { + rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE; + if ((rdp->flags & AR_F_DEGRADED) && + !((buf->drive < rdp->width) ? + (rdp->disks[buf->drive + rdp->width].flags & AR_DF_ONLINE) : + (rdp->disks[buf->drive - rdp->width].flags & AR_DF_ONLINE))) { rdp->flags &= ~AR_F_READY; printf("ar%d: ERROR broken array in done\n", rdp->lun); + ar_config_changed(rdp, buf->drive); buf->org->bio_flags |= BIO_ERROR; buf->org->bio_error = EIO; biodone(buf->org); @@ -446,6 +439,7 @@ ar_done(struct bio *bp) else { rdp->flags |= AR_F_DEGRADED; printf("ar%d: WARNING mirror lost in done\n", rdp->lun); + ar_config_changed(rdp, buf->drive); if (bp->bio_cmd == BIO_READ) { if (buf->drive < rdp->width) buf->drive = buf->drive + rdp->width; @@ -483,13 +477,23 @@ ar_done(struct bio *bp) break; default: - printf("Oops! unknown array type in ar_done\n"); + printf("ar%d: unknown array type in ar_done\n", rdp->lun); } free(buf, M_AR); splx(s); } -/* read the RAID info from a disk on a HighPoint controller */ +static void +ar_config_changed(struct ar_softc *rdp, int disk) +{ + if (rdp->flags & AR_F_PROMISE_RAID) + ar_promise_write_conf(rdp); + if (rdp->flags & AR_F_HIGHPOINT_RAID) + ar_highpoint_write_conf(rdp); + if (rdp->disks[disk].device && !(rdp->disks[disk].flags & AR_DF_ONLINE)) + ata_drawerleds(rdp->disks[disk].device, ATA_LED_RED); +} + static int ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) { @@ -504,14 +508,21 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) if (ar_read(adp, HPT_LBA, sizeof(struct highpoint_raid_conf), (u_int8_t *)info)) { if (bootverbose) - printf("HighPoint read conf failed\n"); + printf("ar: HighPoint read conf failed\n"); goto highpoint_out; } /* check if this is a HighPoint RAID struct */ - if (!(info->magic == HPT_MAGIC_OK || info->magic == HPT_MAGIC_BAD)) { + if (info->magic != HPT_MAGIC_OK && info->magic != HPT_MAGIC_BAD) { if (bootverbose) - printf("HighPoint check1 failed\n"); + printf("ar: HighPoint check1 failed\n"); + goto highpoint_out; + } + + /* is this disk defined, or an old leftover/spare ? */ + if (!info->magic_0) { + if (bootverbose) + printf("ar: HighPoint check2 failed\n"); goto highpoint_out; } @@ -522,56 +533,80 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT | M_ZERO); if (!raidp[array]) { - printf("ar: failed to allocate raid config storage\n"); + printf("ar%d: failed to allocate raid config storage\n", array); goto highpoint_out; } } raid = raidp[array]; if (raid->flags & AR_F_PROMISE_RAID) continue; - raid->flags = AR_F_HIGHPOINT_RAID; + raid->flags |= AR_F_HIGHPOINT_RAID; switch (info->type) { case HPT_T_RAID0: + case HPT_T_RAID01_RAID0: /* check the order byte to determine what this really is */ - switch (info->order & HPT_O_RAIDMASK) { - case HPT_O_RAID0: + switch (info->order) { + case HPT_O_DOWN: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; + raid->magic_1 = info->magic_1; raid->flags |= AR_F_RAID0; raid->interleave = 1 << info->stripe_shift; disk_number = info->disk_number; + info->magic = 0; /* mark bad */ break; - case HPT_O_RAID1: + case HPT_O_RAID01DEGRADED: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; - raid->flags |= AR_F_RAID1; - disk_number = (info->disk_number > 0); + raid->magic_1 = info->magic_1; + raid->flags |= AR_F_RAID0; + raid->interleave = 1 << info->stripe_shift; + disk_number = info->disk_number; break; - + case HPT_O_RAID01SRC: - if (raid->magic_0 && raid->magic_0 != info->magic_0) + if ((raid->magic_0 && raid->magic_0 != info->magic_0) || + (raid->magic_1 && raid->magic_1 != info->magic_1)) continue; raid->magic_0 = info->magic_0; + raid->magic_1 = info->magic_1; raid->flags |= (AR_F_RAID0 | AR_F_RAID1); raid->interleave = 1 << info->stripe_shift; disk_number = info->disk_number; break; case HPT_O_RAID01DST: - if (raid->magic_1 && raid->magic_1 != info->magic_0) + if (raid->magic_1 && raid->magic_1 != info->magic_1) continue; - raid->magic_1 = info->magic_0; + raid->magic_1 = info->magic_1; raid->flags |= (AR_F_RAID0 | AR_F_RAID1); raid->interleave = 1 << info->stripe_shift; disk_number = info->disk_number + info->array_width; break; + + case HPT_O_READY: + if (raid->magic_0 && raid->magic_0 != info->magic_0) + continue; + raid->magic_0 = info->magic_0; + raid->flags |= AR_F_RAID0; + raid->interleave = 1 << info->stripe_shift; + disk_number = info->disk_number; + break; } break; + case HPT_T_RAID1: + if (raid->magic_0 && raid->magic_0 != info->magic_0) + continue; + raid->magic_0 = info->magic_0; + raid->flags |= AR_F_RAID1; + disk_number = (info->disk_number > 0); + break; + case HPT_T_SPAN: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; @@ -581,28 +616,30 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) break; default: - printf("HighPoint unknown RAID type 0x%02x\n", info->type); + printf("ar%d: HighPoint unknown RAID type 0x%02x\n", + array, info->type); goto highpoint_out; } raid->disks[disk_number].device = adp->device; + raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED); if (info->magic == HPT_MAGIC_OK) { - raid->disks[disk_number].flags |= - (AR_DF_PRESENT | AR_DF_ONLINE | AR_DF_ASSIGNED); + raid->disks[disk_number].flags |= AR_DF_ONLINE; raid->flags |= AR_F_READY; raid->lun = array; raid->width = info->array_width; raid->heads = 255; raid->sectors = 63; - raid->cylinders = (info->total_sectors - 9) / (63 * 255); - raid->total_sectors = info->total_sectors - (9 * raid->width); + raid->cylinders = (info->total_sectors - HPT_LBA) / (63 * 255); + raid->total_sectors = info->total_sectors - (HPT_LBA * raid->width); raid->offset = 10; raid->reserved = 10; } - else { + else raid->disks[disk_number].flags &= ~ AR_DF_ONLINE; - raid->disks[disk_number].flags |= (AR_DF_PRESENT | AR_DF_ASSIGNED); - } + + if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width)) + raid->total_disks = raid->width; if (disk_number >= raid->total_disks) raid->total_disks = disk_number + 1; error = 0; @@ -613,7 +650,96 @@ highpoint_out: return error; } -/* read the RAID info from a disk on a Promise Fasttrak controller */ +static int +ar_highpoint_write_conf(struct ar_softc *rdp) +{ + struct highpoint_raid_conf *config; + struct timeval timestamp; + int disk; + + if (!(config = (struct highpoint_raid_conf *) + malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT))) + return -1; + + microtime(×tamp); + rdp->magic_0 = timestamp.tv_sec + 1; + rdp->magic_1 = timestamp.tv_sec; + + for (disk = 0; disk < rdp->total_disks; disk++) { + bzero(config, sizeof(struct highpoint_raid_conf)); + if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == + (AR_DF_PRESENT | AR_DF_ONLINE)) + config->magic = HPT_MAGIC_OK; + if (rdp->disks[disk].flags & AR_DF_ASSIGNED) + config->magic_0 = rdp->magic_0; + config->disk_number = disk; + + switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { + case AR_F_RAID0: + config->type = HPT_T_RAID0; + if (rdp->disks[disk].flags & AR_DF_ONLINE) + config->order = HPT_O_READY; + else + config->order = HPT_O_DOWN; + break; + + case AR_F_RAID1: + config->type = HPT_T_RAID1; + config->disk_number = (disk < rdp->width) ? disk : disk + 10; + break; + + case AR_F_RAID0 | AR_F_RAID1: + config->magic_1 = rdp->magic_1; + config->type = HPT_T_RAID01_RAID0; +#if 0 + if ((rdp->flags & (AR_F_READY | AR_F_DEGRADED)) == AR_F_READY) + if (disk < rdp->width) + config->order = HPT_O_RAID01SRC; + else + config->order = HPT_O_RAID01DST; + else + if (rdp->disks[disk].flags & AR_DF_ONLINE) + config->order = HPT_O_RAID01DEGRADED; + else + config->order = HPT_O_DOWN; +#else + if (rdp->disks[disk].flags & AR_DF_ONLINE) + if (disk < rdp->width) + config->order = HPT_O_RAID01SRC; + else + config->order = HPT_O_RAID01DST; + else + config->order = HPT_O_DOWN; +#endif + if (disk >= rdp->width) { + config->magic_0 = rdp->magic_0 + 1; + config->disk_number -= rdp->width; + } + break; + + case AR_F_SPAN: + config->type = HPT_T_SPAN; + break; + } + + config->array_width = rdp->width; + config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0; + config->total_sectors = rdp->total_sectors; + + if (rdp->disks[disk].device && rdp->disks[disk].device->driver && + !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { + if (ar_write(AD_SOFTC(rdp->disks[disk]), HPT_LBA, + sizeof(struct highpoint_raid_conf), + (u_int8_t *)config)) { + if (bootverbose) + printf("ar%d: Highpoint write conf failed\n", rdp->lun); + return -1; + } + } + } + return 0; +} + static int ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) { @@ -629,14 +755,14 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) if (ar_read(adp, PR_LBA(adp), sizeof(struct promise_raid_conf), (u_int8_t *)info)) { if (bootverbose) - printf("Promise read conf failed\n"); + printf("ar: Promise read conf failed\n"); goto promise_out; } /* check if this is a Promise RAID struct */ if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) { if (bootverbose) - printf("Promise check1 failed\n"); + printf("ar: Promise check1 failed\n"); goto promise_out; } @@ -645,16 +771,14 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) cksum += *ckptr++; if (cksum != *ckptr) { if (bootverbose) - printf("Promise check2 failed\n"); + printf("ar: Promise check2 failed\n"); goto promise_out; } /* now convert Promise config info into our generic form */ - if ((info->raid.integrity != PR_I_VALID) || - (((info->raid.status & (PR_S_VALID | PR_S_ONLINE)) != - (PR_S_VALID | PR_S_ONLINE)))) { + if (info->raid.integrity != PR_I_VALID) { if (bootverbose) - printf("Promise check3 failed\n"); + printf("ar: Promise check3 failed\n"); goto promise_out; } @@ -664,7 +788,7 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT | M_ZERO); if (!raidp[array]) { - printf("ar: failed to allocate raid config storage\n"); + printf("ar%d: failed to allocate raid config storage\n", array); goto promise_out; } } @@ -679,7 +803,8 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) continue; /* update our knowledge about the array config based on generation */ - if (info->raid.generation >= raid->generation) { + if (!info->raid.generation || info->raid.generation > raid->generation){ + raid->generation = info->raid.generation; raid->flags = AR_F_PROMISE_RAID; raid->magic_0 = magic; raid->lun = array; @@ -709,7 +834,8 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) break; default: - printf("Promise unknown RAID type 0x%02x\n", info->raid.type); + printf("ar%d: Promise unknown RAID type 0x%02x\n", + array, info->raid.type); goto promise_out; } raid->interleave = 1 << info->raid.stripe_shift; @@ -725,49 +851,194 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp) /* convert disk flags to our internal types */ for (disk = 0; disk < info->raid.total_disks; disk++) { raid->disks[disk].flags = 0; - if (adp->device) { - if (info->raid.disk[disk].flags & PR_F_VALID) - raid->disks[disk].flags |= AR_DF_PRESENT; - if (info->raid.disk[disk].flags & PR_F_ONLINE) - raid->disks[disk].flags |= AR_DF_ONLINE; - if (info->raid.disk[disk].flags & PR_F_ASSIGNED) - raid->disks[disk].flags |= AR_DF_ASSIGNED; - if (info->raid.disk[disk].flags & PR_F_SPARE) - raid->disks[disk].flags |= AR_DF_SPARE; - if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN)) - raid->disks[disk].flags &= ~AR_DF_ONLINE; - if (info->raid.disk[disk].flags & PR_F_READY) - raid->disks[disk].flags |= AR_DF_PRESENT; + if (info->raid.disk[disk].flags & PR_F_ONLINE) + raid->disks[disk].flags |= AR_DF_ONLINE; + if (info->raid.disk[disk].flags & PR_F_ASSIGNED) + raid->disks[disk].flags |= AR_DF_ASSIGNED; + if (info->raid.disk[disk].flags & PR_F_SPARE) + raid->disks[disk].flags |= AR_DF_SPARE; + if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN)) { + raid->disks[disk].flags &= ~AR_DF_ONLINE; + raid->disks[disk].flags |= AR_DF_PRESENT; } } } - - raid->disks[info->raid.disk_number].device = adp->device; - error = 0; + if (raid->disks[info->raid.disk_number].flags && adp->device) { + raid->disks[info->raid.disk_number].device = adp->device; + raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT; + error = 0; + } break; } - promise_out: free(info, M_AR); return error; } static int +ar_promise_write_conf(struct ar_softc *rdp) +{ + struct promise_raid_conf *config; + struct timeval timestamp; + u_int32_t *ckptr; + int count, disk, drive; + + if (!(config = (struct promise_raid_conf *) + malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) + return -1; + + for (count = 0; count < sizeof(struct promise_raid_conf); count++) + *(((u_int8_t *)config) + count) = 255 - (count % 256); + + rdp->generation++; + microtime(×tamp); + + for (disk = 0; disk < rdp->total_disks; disk++) { + bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC)); + config->dummy_0 = 0x00020000; + config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec; + config->magic_1 = timestamp.tv_sec >> 16; + config->magic_2 = timestamp.tv_sec; + + config->raid.integrity = PR_I_VALID; + + config->raid.flags = 0; + if (rdp->disks[disk].flags & AR_DF_PRESENT) + config->raid.flags |= PR_F_VALID; + if (rdp->disks[disk].flags & AR_DF_ASSIGNED) + config->raid.flags |= PR_F_ASSIGNED; + if (rdp->disks[disk].flags & AR_DF_ONLINE) + config->raid.flags |= PR_F_ONLINE; + else + config->raid.flags |= PR_F_DOWN; + config->raid.disk_number = disk; + if (rdp->disks[disk].device) { + config->raid.channel = rdp->disks[disk].device->channel->unit; + config->raid.device = (rdp->disks[disk].device->unit != 0); + if (AD_SOFTC(rdp->disks[disk])->dev->si_disk) + config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk])); + /*config->raid.disk_offset*/ + } + config->raid.magic_0 = config->magic_0; + config->raid.rebuild_lba = 0xffffffff; + config->raid.generation = rdp->generation; + + if (rdp->flags & AR_F_READY) { + config->raid.status = + (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY); + if (rdp->flags & AR_F_DEGRADED) + config->raid.status |= PR_S_DEGRADED; + else + config->raid.status |= PR_S_FUNCTIONAL; + } + else + config->raid.status = 0; + + switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { + case AR_F_RAID0: + config->raid.type = PR_T_RAID0; + break; + case AR_F_RAID1: + config->raid.type = PR_T_RAID1; + break; + case AR_F_RAID0 | AR_F_RAID1: + config->raid.type = PR_T_RAID1; + break; + case AR_F_SPAN: + config->raid.type = PR_T_SPAN; + break; + } + + config->raid.total_disks = rdp->total_disks; + config->raid.stripe_shift = ffs(rdp->interleave) - 1; + config->raid.array_width = rdp->width; + config->raid.array_number = rdp->magic_0 >> 16; + config->raid.total_sectors = rdp->total_sectors; + config->raid.cylinders = rdp->cylinders - 1; + config->raid.heads = rdp->heads - 1; + config->raid.sectors = rdp->sectors; + config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1; + + bzero(&config->raid.disk, 8 * 12); + for (drive = 0; drive < rdp->total_disks; drive++) { + config->raid.disk[drive].flags = 0; + if (rdp->disks[drive].flags & AR_DF_PRESENT) + config->raid.disk[drive].flags |= PR_F_VALID; + if (rdp->disks[drive].flags & AR_DF_ASSIGNED) + config->raid.disk[drive].flags |= PR_F_ASSIGNED; + if (rdp->disks[drive].flags & AR_DF_ONLINE) + config->raid.disk[drive].flags |= PR_F_ONLINE; + else + config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN); + if (rdp->disks[drive].flags & AR_DF_SPARE) + config->raid.disk[drive].flags |= PR_F_SPARE; + config->raid.disk[drive].dummy_0 = 0x0; + if (rdp->disks[drive].device) { + config->raid.disk[drive].channel = + rdp->disks[drive].device->channel->unit; + config->raid.disk[drive].device = + (rdp->disks[drive].device->unit != 0); + } + config->raid.disk[drive].magic_0 = + PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec; + } + + config->checksum = 0; + for (ckptr = (int32_t *)config, count = 0; count < 511; count++) + config->checksum += *ckptr++; + + if (rdp->disks[disk].device && rdp->disks[disk].device->driver && + !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { + if (ar_write(AD_SOFTC(rdp->disks[disk]), + PR_LBA(AD_SOFTC(rdp->disks[disk])), + sizeof(struct promise_raid_conf), (u_int8_t *)config)){ + if (bootverbose) + printf("ar%d: Promise write conf failed\n", rdp->lun); + return -1; + } + } + } + return 0; +} + +static int ar_read(struct ad_softc *adp, u_int32_t lba, int count, u_int8_t *data) { if (ata_command(adp->device, count > DEV_BSIZE ? ATA_C_READ_MUL:ATA_C_READ, - lba, count / DEV_BSIZE, 0, ATA_WAIT_INTR)) { - ata_printf(adp->device->channel, adp->device->unit, - "RAID read config failed\n"); + lba, count / DEV_BSIZE, 0, ATA_IMMEDIATE)) { + ata_prtdev(adp->device, "RAID read config failed\n"); return 1; } - if (ata_wait(adp->device, ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)){ - ata_printf(adp->device->channel, adp->device->unit, - "RAID read config timeout\n"); + if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)){ + ata_prtdev(adp->device, "RAID read config timeout\n"); return 1; } ATA_INSW(adp->device->channel->r_io, ATA_DATA, (int16_t *)data, count/sizeof(int16_t)); - ATA_INB(adp->device->channel->r_io, ATA_STATUS); + if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC) < 0) { + ata_prtdev(adp->device, "timeout waiting for final ready\n"); + return 1; + } + return 0; +} + +static int +ar_write(struct ad_softc *adp, u_int32_t lba, int count, u_int8_t *data) +{ + if (ata_command(adp->device,count > DEV_BSIZE ? ATA_C_WRITE_MUL:ATA_C_WRITE, + lba, count / DEV_BSIZE, 0, ATA_IMMEDIATE)) { + ata_prtdev(adp->device, "RAID write config failed\n"); + return 1; + } + if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)){ + ata_prtdev(adp->device, "RAID write config timeout\n"); + return 1; + } + ATA_OUTSW(adp->device->channel->r_io, ATA_DATA, (int16_t *)data, + count/sizeof(int16_t)); + if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC) < 0) { + ata_prtdev(adp->device, "timeout waiting for final ready\n"); + return 1; + } return 0; } diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 06a5f8f..4061701 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -58,7 +58,7 @@ struct ar_softc { int total_disks; /* number of disks in this array */ int generation; /* generation of this array */ - struct ar_disk disks[MAX_DISKS]; /* ptr to each disk in array */ + struct ar_disk disks[MAX_DISKS+1]; /* ptr to each disk in array */ int width; /* array width in disks */ u_int16_t heads; u_int16_t sectors; @@ -93,12 +93,11 @@ struct highpoint_raid_conf { u_int32_t magic_0; u_int32_t magic_1; u_int32_t order; -#define HPT_O_RAID0 0x00 -#define HPT_O_RAID1 0x01 +#define HPT_O_DOWN 0x00 +#define HPT_O_RAID01DEGRADED 0x01 #define HPT_O_RAID01DST 0x02 #define HPT_O_RAID01SRC 0x03 -#define HPT_O_RAIDMASK 0x03 -#define HPT_O_OK 0x04 +#define HPT_O_READY 0x04 u_int8_t array_width; u_int8_t stripe_shift; @@ -134,6 +133,7 @@ struct highpoint_raid_conf { int8_t filler2[60]; } __attribute__((packed)); + #define PR_LBA(adp) \ (((adp->total_secs / (adp->heads * adp->sectors)) * \ adp->heads * adp->sectors) - adp->sectors) @@ -143,7 +143,9 @@ struct promise_raid_conf { #define PR_MAGIC "Promise Technology, Inc." u_int32_t dummy_0; - u_int8_t magic_0[8]; + u_int64_t magic_0; +#define PR_MAGIC0(x) ((u_int64_t)x.device->channel->unit << 48) | \ + ((u_int64_t)(x.device->unit != 0) << 56) u_int16_t magic_1; u_int32_t magic_2; u_int8_t filler1[470]; @@ -164,10 +166,10 @@ struct promise_raid_conf { u_int8_t disk_number; u_int8_t channel; u_int8_t device; - u_int8_t magic_0[8]; + u_int64_t magic_0; u_int32_t disk_offset; /* 0x210 */ u_int32_t disk_sectors; - u_int32_t dummy_1; + u_int32_t rebuild_lba; u_int16_t generation; u_int8_t status; #define PR_S_VALID 0x01 @@ -176,6 +178,7 @@ struct promise_raid_conf { #define PR_S_READY 0x08 #define PR_S_DEGRADED 0x10 #define PR_S_MARKED 0x20 +#define PR_S_FUNCTIONAL 0x80 u_int8_t type; #define PR_T_RAID0 0x00 @@ -192,19 +195,19 @@ struct promise_raid_conf { u_int16_t cylinders; u_int8_t heads; u_int8_t sectors; - int8_t magic_1[8]; + int64_t magic_1; struct { /* 0x240 */ u_int8_t flags; u_int8_t dummy_0; u_int8_t channel; u_int8_t device; - u_int8_t magic_0[8]; + u_int64_t magic_0; } disk[8]; } raid; int32_t filler2[346]; u_int32_t checksum; } __attribute__((packed)); -int ar_probe(struct ad_softc *); -void atar_attach(void); +int ata_raid_probe(struct ad_softc *); +void ata_raid_attach(void); diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index aab4082..c0856d4 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -158,7 +158,9 @@ atapi_detach(struct ata_device *atadev) free(request, M_ATAPI); } free(atadev->result, M_ATAPI); - atadev->driver = NULL; /* XXX SOS safetybelt */ + atadev->driver = NULL; + atadev->flags = 0; + } int |