summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-raid.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/ata-raid.c')
-rw-r--r--sys/dev/ata/ata-raid.c744
1 files changed, 476 insertions, 268 deletions
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c
index 480b5ac..ba7e5cf 100644
--- a/sys/dev/ata/ata-raid.c
+++ b/sys/dev/ata/ata-raid.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,92 +48,165 @@
#include <dev/ata/ata-raid.h>
/* device structures */
-static d_open_t aropen;
-static d_strategy_t arstrategy;
+static d_open_t aropen;
+static d_strategy_t arstrategy;
static struct cdevsw ar_cdevsw = {
- /* open */ aropen,
- /* close */ nullclose,
- /* read */ physread,
- /* write */ physwrite,
- /* ioctl */ noioctl,
- /* poll */ nopoll,
- /* mmap */ nommap,
- /* strategy */ arstrategy,
- /* name */ "ar",
- /* maj */ 157,
- /* dump */ nodump,
- /* psize */ nopsize,
- /* flags */ D_DISK,
+ /* open */ aropen,
+ /* close */ nullclose,
+ /* read */ physread,
+ /* write */ physwrite,
+ /* ioctl */ noioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ arstrategy,
+ /* name */ "ar",
+ /* maj */ 157,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ D_DISK,
};
static struct cdevsw ardisk_cdevsw;
/* prototypes */
-static void ar_attach(struct ar_softc *);
static void ar_done(struct bio *);
-static int ar_highpoint_conf(struct ad_softc *, struct ar_softc **);
-static int ar_promise_conf(struct ad_softc *, struct ar_softc **);
-static int ar_read(struct ad_softc *, u_int32_t, int, char *);
+static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **);
+static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **);
+static int ar_read(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[16];
+static struct ar_softc *ar_table[MAX_ARRAYS];
static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver");
-
+
int
-ar_probe(struct ad_softc *adp)
-{
+ar_probe(struct ad_softc *adp) {
if (!ar_init) {
bzero(&ar_table, sizeof(ar_table));
ar_init = 1;
}
- switch(adp->controller->chiptype) {
+ switch(adp->device->channel->chiptype) {
case 0x4d33105a:
case 0x4d38105a:
case 0x4d30105a:
case 0x0d30105a:
case 0x4d68105a:
case 0x6268105a:
- return (ar_promise_conf(adp, ar_table));
+ /* test RAID bit in PCI reg */
+ return (ar_promise_read_conf(adp, ar_table));
case 0x00041103:
- return (ar_highpoint_conf(adp, ar_table));
+ /* test RAID bit in PCI reg */
+ return (ar_highpoint_read_conf(adp, ar_table));
}
return 1;
}
-static void
-ar_attach(struct ar_softc *raid)
+void
+ar_attach()
{
+ struct ar_softc *raid;
dev_t dev;
- int i;
-
- printf("ar%d: %luMB <ATA ",
- raid->lun, raid->total_secs / ((1024L * 1024L) / DEV_BSIZE));
- switch (raid->flags & (AR_F_RAID_0 | AR_F_RAID_1 | AR_F_SPAN)) {
- case AR_F_RAID_0:
- printf("RAID0 "); break;
- case AR_F_RAID_1:
- printf("RAID1 "); break;
- case AR_F_SPAN:
- printf("SPAN "); break;
- case (AR_F_RAID_0 | AR_F_RAID_1):
- printf("RAID0+1 "); break;
- default:
- printf("unknown array 0x%x ", raid->flags);
- return;
+ int array, disk;
+
+ for (array = 0; array < MAX_ARRAYS; array++) {
+ 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;
+
+ 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;
+ }
+ }
+ else {
+ raid->disks[disk].flags &=
+ ~(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
+ }
+ }
+
+ dev = disk_create(raid->lun, &raid->disk, 0, &ar_cdevsw,&ardisk_cdevsw);
+ dev->si_drv1 = raid;
+ dev->si_iosize_max = 256 * DEV_BSIZE;
+ raid->dev = dev;
+
+ printf("ar%d: %lluMB <ATA ",
+ raid->lun, raid->total_sectors / ((1024L * 1024L) / DEV_BSIZE));
+ switch (raid->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
+ case AR_F_RAID0:
+ printf("RAID0 "); break;
+ case AR_F_RAID1:
+ printf("RAID1 "); break;
+ case AR_F_SPAN:
+ printf("SPAN "); break;
+ case (AR_F_RAID0 | AR_F_RAID1):
+ printf("RAID0+1 "); break;
+ default:
+ printf("unknown 0x%x ", raid->flags);
+ return;
+ }
+ printf("array> [%d/%d/%d] status: ",
+ raid->cylinders, raid->heads, raid->sectors);
+ switch (raid->flags & (AR_F_DEGRADED | AR_F_READY)) {
+ case AR_F_READY:
+ printf("READY");
+ break;
+ case (AR_F_DEGRADED | AR_F_READY):
+ printf("DEGRADED");
+ break;
+ default:
+ printf("BROKEN");
+ break;
+ }
+ printf(" subdisks:\n");
+ for (disk = 0; disk < raid->total_disks; disk++) {
+ if (raid->disks[disk].flags & AR_DF_ONLINE)
+ printf(" %d READY ", disk);
+ else if (raid->disks[disk].flags & AR_DF_ASSIGNED)
+ printf(" %d DOWN ", disk);
+ else if (raid->disks[disk].flags & AR_DF_SPARE)
+ printf(" %d SPARE ", disk);
+ else if (raid->disks[disk].flags & AR_DF_PRESENT)
+ printf(" %d FREE ", disk);
+ else
+ printf(" %d FAILURE no device present\n", disk);
+ if (raid->disks[disk].flags & AR_DF_PRESENT)
+ ad_print(AD_SOFTC(raid->disks[disk]), "");
+ }
}
- printf("array> [%d/%d/%d] subdisks:\n",
- raid->cylinders, raid->heads, raid->sectors);
- for (i = 0; i < raid->num_subdisks; i++)
- ad_print(raid->subdisk[i], " ");
- for (i = 0; i < raid->num_mirrordisks; i++)
- ad_print(raid->mirrordisk[i], " ");
-
- dev = disk_create(raid->lun, &raid->disk, 0, &ar_cdevsw, &ardisk_cdevsw);
- dev->si_drv1 = raid;
- dev->si_iosize_max = 256 * DEV_BSIZE;
- raid->dev = dev;
}
static int
@@ -141,7 +214,7 @@ aropen(dev_t dev, int flags, int fmt, struct thread *td)
{
struct ar_softc *rdp = dev->si_drv1;
struct disklabel *dl;
-
+
dl = &rdp->disk.d_label;
bzero(dl, sizeof *dl);
dl->d_secsize = DEV_BSIZE;
@@ -149,7 +222,7 @@ aropen(dev_t dev, int flags, int fmt, struct thread *td)
dl->d_ntracks = rdp->heads;
dl->d_ncylinders = rdp->cylinders;
dl->d_secpercyl = rdp->sectors * rdp->heads;
- dl->d_secperunit = rdp->total_secs;
+ dl->d_secperunit = rdp->total_sectors;
return 0;
}
@@ -160,6 +233,12 @@ arstrategy(struct bio *bp)
int lba, count, chunk;
caddr_t data;
+ if (!(rdp->flags & AR_F_READY)) {
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_error = EIO;
+ biodone(bp);
+ return;
+ }
bp->bio_resid = bp->bio_bcount;
lba = bp->bio_pblkno;
data = bp->bio_data;
@@ -169,43 +248,56 @@ arstrategy(struct bio *bp)
int plba;
buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO);
- if (rdp->flags & AR_F_SPAN) {
+ switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
+ case AR_F_SPAN:
plba = lba;
- while (plba >= (rdp->subdisk[buf1->drive]->total_secs-rdp->reserved)
- && buf1->drive < rdp->num_subdisks)
- plba-=(rdp->subdisk[buf1->drive++]->total_secs-rdp->reserved);
+ while (plba >=
+ AD_SOFTC(rdp->disks[buf1->drive])->total_secs-rdp->reserved)
+ plba -= (AD_SOFTC(rdp->disks[buf1->drive++])->total_secs -
+ rdp->reserved);
buf1->bp.bio_pblkno = plba;
- chunk = min(rdp->subdisk[buf1->drive]->total_secs -
- rdp->reserved - plba, count);
- }
- else if (rdp->flags & AR_F_RAID_0) {
+ chunk = min(AD_SOFTC(rdp->disks[buf1->drive])->total_secs -
+ rdp->reserved - plba, count);
+ break;
+
+ case AR_F_RAID0:
+ case AR_F_RAID0 | AR_F_RAID1:
plba = lba / rdp->interleave;
chunk = lba % rdp->interleave;
- if (plba == rdp->total_secs / rdp->interleave) {
+ if (plba == rdp->total_sectors / rdp->interleave) {
int lastblksize =
- (rdp->total_secs-(plba*rdp->interleave))/rdp->num_subdisks;
+ (rdp->total_sectors-(plba*rdp->interleave))/rdp->width;
buf1->drive = chunk / lastblksize;
buf1->bp.bio_pblkno =
- ((plba / rdp->num_subdisks) * rdp->interleave) +
- chunk % lastblksize;
+ ((plba / rdp->width) * rdp->interleave) + chunk%lastblksize;
chunk = min(count, lastblksize);
}
else {
- buf1->drive = plba % rdp->num_subdisks;
+ buf1->drive = plba % rdp->width;
buf1->bp.bio_pblkno =
- ((plba / rdp->num_subdisks) * rdp->interleave) + chunk;
+ ((plba / rdp->width) * rdp->interleave) + chunk;
chunk = min(count, rdp->interleave - chunk);
}
- }
- else {
+ break;
+
+ case AR_F_RAID1:
buf1->bp.bio_pblkno = lba;
buf1->drive = 0;
chunk = count;
+ break;
+
+ default:
+ printf("Oops! unknown array type in arstrategy\n");
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_error = EIO;
+ biodone(bp);
+ return;
}
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;
@@ -214,33 +306,98 @@ arstrategy(struct bio *bp)
buf1->bp.bio_done = ar_done;
buf1->org = bp;
- /* simpleminded load balancing on RAID1 arrays */
- if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_READ) {
- if (buf1->bp.bio_pblkno <
- (rdp->last_lba[buf1->drive][rdp->last_disk] - 100) ||
- buf1->bp.bio_pblkno >
- (rdp->last_lba[buf1->drive][rdp->last_disk] + 100)) {
- rdp->last_disk = 1 - rdp->last_disk;
- rdp->last_lba[buf1->drive][rdp->last_disk] =
- buf1->bp.bio_pblkno;
+ switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
+ 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->flags &= ~AR_F_READY;
+ printf("ar%d: ERROR broken array in strategy\n", rdp->lun);
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_error = EIO;
+ biodone(bp);
+ return;
}
- if (rdp->last_disk)
- buf1->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev;
- else
- buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev;
- }
- else
- buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev;
-
- if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_WRITE) {
- buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT);
- bcopy(buf1, buf2, sizeof(struct ar_buf));
- buf2->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev;
- buf2->mirror = buf1;
- buf1->mirror = buf2;
- buf2->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf2);
+ buf1->bp.bio_dev = AD_SOFTC(rdp->disks[buf1->drive])->dev;
+ buf1->bp.bio_dev->AD_STRATEGY((struct bio *)buf1);
+ break;
+
+ case AR_F_RAID1:
+ case AR_F_RAID0 | AR_F_RAID1:
+ if (rdp->flags & AR_F_REBUILDING) {
+ if ((bp->bio_pblkno >= rdp->lock_start &&
+ bp->bio_pblkno < rdp->lock_end) ||
+ ((bp->bio_pblkno + chunk) >= rdp->lock_start &&
+ (bp->bio_pblkno + chunk) < rdp->lock_end)) {
+ tsleep(rdp, PRIBIO, "arwait", 0);
+ }
+ }
+ 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);
+ 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;
+ }
+ 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);
+ 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;
+ }
+ if (!(rdp->flags & AR_F_READY)) {
+ printf("ar%d: ERROR broken array in strategy\n", rdp->lun);
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_error = EIO;
+ biodone(bp);
+ return;
+ }
+ if (bp->bio_cmd == BIO_WRITE) {
+ if (rdp->disks[buf1->drive + rdp->width].flags & AR_DF_ONLINE) {
+ if (rdp->disks[buf1->drive].flags & AR_DF_ONLINE) {
+ buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT);
+ bcopy(buf1, buf2, sizeof(struct ar_buf));
+ buf1->mirror = buf2;
+ buf2->mirror = buf1;
+ buf2->drive = buf1->drive + rdp->width;
+ buf2->bp.bio_dev =
+ AD_SOFTC(rdp->disks[buf2->drive])->dev;
+ buf2->bp.bio_dev->AD_STRATEGY((struct bio *)buf2);
+ rdp->disks[buf2->drive].last_lba =
+ buf1->bp.bio_pblkno + chunk;
+ }
+ else
+ buf1->drive = buf1->drive + rdp->width;
+ }
+ }
+ if (bp->bio_cmd == BIO_READ) {
+ if ((buf1->bp.bio_pblkno <
+ (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) ||
+ buf1->bp.bio_pblkno >
+ (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY) ||
+ !(rdp->disks[buf1->drive].flags & AR_DF_ONLINE)) &&
+ (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE))
+ buf1->drive = buf1->drive + rdp->width;
+ }
+ buf1->bp.bio_dev = AD_SOFTC(rdp->disks[buf1->drive])->dev;
+ buf1->bp.bio_dev->AD_STRATEGY((struct bio *)buf1);
+ rdp->disks[buf1->drive].last_lba = buf1->bp.bio_pblkno + chunk;
+ break;
+ default:
+ printf("DOH!! unknown array type in arstrategy\n");
}
- buf1->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf1);
}
}
@@ -253,69 +410,116 @@ ar_done(struct bio *bp)
s = splbio();
- if (bp->bio_flags & BIO_ERROR) {
- if (bp->bio_cmd == BIO_WRITE || buf->done || !(rdp->flags&AR_F_RAID_1)){
+ 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->flags &= ~AR_F_READY;
buf->org->bio_flags |= BIO_ERROR;
- buf->org->bio_error = bp->bio_error;
+ buf->org->bio_error = EIO;
+ biodone(buf->org);
+ ata_drawerleds(rdp->disks[buf->drive].device, ATA_LED_RED);
}
- printf("ar%d: subdisk error\n", rdp->lun);
- }
+ else {
+ buf->org->bio_resid -= buf->bp.bio_bcount;
+ if (buf->org->bio_resid == 0)
+ biodone(buf->org);
+ }
+ break;
- if (rdp->flags & AR_F_RAID_1) {
- if (bp->bio_cmd == BIO_WRITE) {
- if (!buf->done) {
- buf->mirror->done = 1;
- goto done;
+ 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->flags &= ~AR_F_READY;
+ printf("ar%d: ERROR broken array in done\n", rdp->lun);
+ buf->org->bio_flags |= BIO_ERROR;
+ buf->org->bio_error = EIO;
+ biodone(buf->org);
}
- }
+ else {
+ rdp->flags |= AR_F_DEGRADED;
+ printf("ar%d: WARNING mirror lost in done\n", rdp->lun);
+ if (bp->bio_cmd == BIO_READ) {
+ if (buf->drive < rdp->width)
+ buf->drive = buf->drive + rdp->width;
+ else
+ buf->drive = buf->drive - rdp->width;
+ buf->bp.bio_dev = AD_SOFTC(rdp->disks[buf->drive])->dev;
+ buf->bp.bio_flags = buf->org->bio_flags;
+ buf->bp.bio_error = 0;
+ buf->bp.bio_dev->AD_STRATEGY((struct bio *)buf);
+ splx(s);
+ return;
+ }
+ if (bp->bio_cmd == BIO_WRITE) {
+ if (!(buf->flags & AB_F_DONE))
+ buf->mirror->flags |= AB_F_DONE;
+ else {
+ buf->org->bio_resid -= bp->bio_bcount;
+ if (buf->org->bio_resid == 0)
+ biodone(buf->org);
+ }
+ }
+ }
+ }
else {
- if (!buf->done && bp->bio_flags & BIO_ERROR) {
- /* read error on this disk, try mirror */
- buf->done = 1;
- buf->bp.bio_dev = rdp->mirrordisk[buf->drive]->dev;
- buf->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio*)buf);
- return;
+ if (bp->bio_cmd == BIO_WRITE) {
+ if (!(buf->flags & AB_F_DONE) && !(rdp->flags & AR_F_DEGRADED)){
+ buf->mirror->flags |= AB_F_DONE;
+ break;
+ }
}
+ buf->org->bio_resid -= bp->bio_bcount;
+ if (buf->org->bio_resid == 0)
+ biodone(buf->org);
}
+ break;
+
+ default:
+ printf("Oops! unknown array type in ar_done\n");
}
- buf->org->bio_resid -= bp->bio_bcount;
- if (buf->org->bio_resid == 0)
- biodone(buf->org);
-done:
free(buf, M_AR);
splx(s);
}
/* read the RAID info from a disk on a HighPoint controller */
static int
-ar_highpoint_conf(struct ad_softc *adp, struct ar_softc **raidp)
+ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
{
struct highpoint_raid_conf *info;
- struct ar_softc *raid;
- int array, error = 1;
+ struct ar_softc *raid = NULL;
+ int array, disk_number = 0, error = 1;
if (!(info = (struct highpoint_raid_conf *)
malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
return error;
- if (ar_read(adp, 0x09, DEV_BSIZE, (char *)info)) {
+ if (ar_read(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
+ (u_int8_t *)info)) {
if (bootverbose)
printf("HighPoint read conf failed\n");
goto highpoint_out;
}
/* check if this is a HighPoint RAID struct */
- if (info->magic != HPT_MAGIC_OK) {
+ if (!(info->magic == HPT_MAGIC_OK || info->magic == HPT_MAGIC_BAD)) {
if (bootverbose)
printf("HighPoint check1 failed\n");
goto highpoint_out;
}
/* now convert HighPoint config info into our generic form */
- for (array = 0; array < 8; array++) {
+ for (array = 0; array < MAX_ARRAYS; array++) {
if (!raidp[array]) {
raidp[array] =
- (struct ar_softc*)malloc(sizeof(struct ar_softc),M_AR,
+ (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");
@@ -323,69 +527,49 @@ ar_highpoint_conf(struct ad_softc *adp, struct ar_softc **raidp)
}
}
raid = raidp[array];
+ if (raid->flags & AR_F_PROMISE_RAID)
+ continue;
+ raid->flags = AR_F_HIGHPOINT_RAID;
switch (info->type) {
- case HPT_T_RAID_0:
+ case HPT_T_RAID0:
/* check the order byte to determine what this really is */
- switch (info->order & (HPT_O_MIRROR | HPT_O_STRIPE)) {
- case HPT_O_MIRROR:
- goto hpt_mirror;
-
- case HPT_O_STRIPE:
+ switch (info->order & HPT_O_RAIDMASK) {
+ case HPT_O_RAID0:
if (raid->magic_0 && raid->magic_0 != info->magic_0)
continue;
raid->magic_0 = info->magic_0;
- raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1);
- raid->interleave = 1 << info->raid0_shift;
- raid->subdisk[info->disk_number] = adp;
- raid->num_subdisks++;
- if ((raid->num_subdisks + raid->num_mirrordisks) ==
- (info->raid_disks * 2))
- raid->flags |= AR_F_CONF_DONE;
+ raid->flags |= AR_F_RAID0;
+ raid->interleave = 1 << info->stripe_shift;
+ disk_number = info->disk_number;
break;
- case (HPT_O_MIRROR | HPT_O_STRIPE):
- if (raid->magic_1 && raid->magic_1 != info->magic_0)
+ case HPT_O_RAID1:
+ if (raid->magic_0 && raid->magic_0 != info->magic_0)
continue;
- raid->magic_1 = info->magic_0;
- raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1);
- raid->mirrordisk[info->disk_number] = adp;
- raid->num_mirrordisks++;
- if ((raid->num_subdisks + raid->num_mirrordisks) ==
- (info->raid_disks * 2))
- raid->flags |= AR_F_CONF_DONE;
+ raid->magic_0 = info->magic_0;
+ raid->flags |= AR_F_RAID1;
+ disk_number = (info->disk_number > 0);
break;
-
- default:
+
+ case HPT_O_RAID01SRC:
if (raid->magic_0 && raid->magic_0 != info->magic_0)
continue;
raid->magic_0 = info->magic_0;
- raid->flags |= AR_F_RAID_0;
- raid->interleave = 1 << info->raid0_shift;
- raid->subdisk[info->disk_number] = adp;
- raid->num_subdisks++;
- if (raid->num_subdisks == info->raid_disks)
- raid->flags |= AR_F_CONF_DONE;
- }
- break;
+ raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
+ raid->interleave = 1 << info->stripe_shift;
+ disk_number = info->disk_number;
+ break;
- case HPT_T_RAID_1:
-hpt_mirror:
- if (raid->magic_0 && raid->magic_0 != info->magic_0)
- continue;
- raid->magic_0 = info->magic_0;
- raid->flags |= AR_F_RAID_1;
- if (info->disk_number == 0 && raid->num_subdisks == 0) {
- raid->subdisk[raid->num_subdisks] = adp;
- raid->num_subdisks = 1;
- }
- if (info->disk_number != 0 && raid->num_mirrordisks == 0) {
- raid->mirrordisk[raid->num_mirrordisks] = adp;
- raid->num_mirrordisks = 1;
+ case HPT_O_RAID01DST:
+ if (raid->magic_1 && raid->magic_1 != info->magic_0)
+ continue;
+ raid->magic_1 = info->magic_0;
+ raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
+ raid->interleave = 1 << info->stripe_shift;
+ disk_number = info->disk_number + info->array_width;
+ break;
}
- if ((raid->num_subdisks +
- raid->num_mirrordisks) == (info->raid_disks * 2))
- raid->flags |= AR_F_CONF_DONE;
break;
case HPT_T_SPAN:
@@ -393,30 +577,37 @@ hpt_mirror:
continue;
raid->magic_0 = info->magic_0;
raid->flags |= AR_F_SPAN;
- raid->subdisk[info->disk_number] = adp;
- raid->num_subdisks++;
- if (raid->num_subdisks == info->raid_disks)
- raid->flags |= AR_F_CONF_DONE;
+ disk_number = info->disk_number;
break;
default:
printf("HighPoint unknown RAID type 0x%02x\n", info->type);
+ goto highpoint_out;
}
- /* do we have a complete array to attach to ? */
- if (raid->flags & AR_F_CONF_DONE) {
+ raid->disks[disk_number].device = adp->device;
+ if (info->magic == HPT_MAGIC_OK) {
+ raid->disks[disk_number].flags |=
+ (AR_DF_PRESENT | AR_DF_ONLINE | AR_DF_ASSIGNED);
+ raid->flags |= AR_F_READY;
raid->lun = array;
+ raid->width = info->array_width;
raid->heads = 255;
raid->sectors = 63;
- raid->cylinders = (info->total_secs - 9) / (63 * 255);
- raid->total_secs = info->total_secs - (9 * raid->num_subdisks);
+ raid->cylinders = (info->total_sectors - 9) / (63 * 255);
+ raid->total_sectors = info->total_sectors - (9 * raid->width);
raid->offset = 10;
raid->reserved = 10;
- ar_attach(raid);
}
+ else {
+ raid->disks[disk_number].flags &= ~ AR_DF_ONLINE;
+ raid->disks[disk_number].flags |= (AR_DF_PRESENT | AR_DF_ASSIGNED);
+ }
+ if (disk_number >= raid->total_disks)
+ raid->total_disks = disk_number + 1;
error = 0;
+ break;
}
-
highpoint_out:
free(info, M_AR);
return error;
@@ -424,22 +615,19 @@ highpoint_out:
/* read the RAID info from a disk on a Promise Fasttrak controller */
static int
-ar_promise_conf(struct ad_softc *adp, struct ar_softc **raidp)
+ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
{
struct promise_raid_conf *info;
struct ar_softc *raid;
- u_int32_t lba, magic;
- u_int32_t cksum, *ckptr;
- int count, disk_number, array, error = 1;
+ u_int32_t magic, cksum, *ckptr;
+ int array, count, disk, error = 1;
if (!(info = (struct promise_raid_conf *)
malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
return error;
- lba = ((adp->total_secs / (adp->heads * adp->sectors)) *
- adp->heads * adp->sectors) - adp->sectors;
-
- if (ar_read(adp, lba, 4 * DEV_BSIZE, (char *)info)) {
+ if (ar_read(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
+ (u_int8_t *)info)) {
if (bootverbose)
printf("Promise read conf failed\n");
goto promise_out;
@@ -450,116 +638,136 @@ ar_promise_conf(struct ad_softc *adp, struct ar_softc **raidp)
if (bootverbose)
printf("Promise check1 failed\n");
goto promise_out;
- }
+ }
/* check if the checksum is OK */
for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++)
cksum += *ckptr++;
if (cksum != *ckptr) {
if (bootverbose)
- printf("Promise check2 failed\n");
+ printf("Promise check2 failed\n");
goto promise_out;
}
/* now convert Promise config info into our generic form */
- if ((info->raid.flags != PR_F_READY) ||
- (((info->raid.status & (PR_S_DEFINED|PR_S_ONLINE)) !=
- (PR_S_DEFINED|PR_S_ONLINE)))) {
+ if ((info->raid.integrity != PR_I_VALID) ||
+ (((info->raid.status & (PR_S_VALID | PR_S_ONLINE)) !=
+ (PR_S_VALID | PR_S_ONLINE)))) {
if (bootverbose)
- printf("Promise check3 failed\n");
+ printf("Promise check3 failed\n");
goto promise_out;
}
- magic = (adp->controller->chiptype >> 16) | info->raid.array_number << 16;
-
- array = info->raid.array_number;
- if (raidp[array]) {
- if (magic != raidp[array]->magic_0) {
- if (bootverbose)
- printf("Promise check4 failed\n");
- goto promise_out;
- }
- }
- else {
- if (!(raidp[array] = (struct ar_softc *)
- malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT))) {
- printf("ar: failed to allocate raid config storage\n");
- goto promise_out;
+ for (array = 0; array < MAX_ARRAYS; array++) {
+ if (!raidp[array]) {
+ raidp[array] =
+ (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");
+ goto promise_out;
+ }
}
- else
- bzero(raidp[array], sizeof(struct ar_softc));
- }
- raid = raidp[array];
- raid->magic_0 = magic;
+ raid = raidp[array];
+ if (raid->flags & AR_F_HIGHPOINT_RAID)
+ continue;
- switch (info->raid.type) {
- case PR_T_STRIPE:
- raid->flags |= AR_F_RAID_0;
- raid->interleave = 1 << info->raid.raid0_shift;
- break;
+ magic = (adp->device->channel->chiptype >> 16) |
+ (info->raid.array_number << 16);
- case PR_T_MIRROR:
- raid->flags |= AR_F_RAID_1;
- break;
+ if (raid->flags & AR_F_PROMISE_RAID && magic != raid->magic_0)
+ continue;
- case PR_T_SPAN:
- raid->flags |= AR_F_SPAN;
- break;
+ /* update our knowledge about the array config based on generation */
+ if (info->raid.generation >= raid->generation) {
+ raid->flags = AR_F_PROMISE_RAID;
+ raid->magic_0 = magic;
+ raid->lun = array;
+ if ((info->raid.status &
+ (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) ==
+ (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) {
+ raid->flags |= AR_F_READY;
+ if (info->raid.status & PR_S_DEGRADED)
+ raid->flags |= AR_F_DEGRADED;
+ }
+ else
+ raid->flags &= ~AR_F_READY;
- default:
- printf("Promise unknown RAID type 0x%02x\n", info->raid.type);
- goto promise_out;
- }
+ switch (info->raid.type) {
+ case PR_T_RAID0:
+ raid->flags |= AR_F_RAID0;
+ break;
+
+ case PR_T_RAID1:
+ raid->flags |= AR_F_RAID1;
+ if (info->raid.array_width > 1)
+ raid->flags |= AR_F_RAID0;
+ break;
- /* find out where this disk is in the defined array */
- disk_number = info->raid.disk_number;
- if (disk_number < info->raid.raid0_disks) {
- raid->subdisk[disk_number] = adp;
- raid->num_subdisks++;
- if (raid->num_subdisks > 1 && !(raid->flags & AR_F_SPAN)) {
- raid->flags |= AR_F_RAID_0;
- raid->interleave = 1 << info->raid.raid0_shift;
+ case PR_T_SPAN:
+ raid->flags |= AR_F_SPAN;
+ break;
+
+ default:
+ printf("Promise unknown RAID type 0x%02x\n", info->raid.type);
+ goto promise_out;
+ }
+ raid->interleave = 1 << info->raid.stripe_shift;
+ raid->width = info->raid.array_width;
+ raid->total_disks = info->raid.total_disks;
+ raid->heads = info->raid.heads + 1;
+ raid->sectors = info->raid.sectors;
+ raid->cylinders = info->raid.cylinders + 1;
+ raid->total_sectors = info->raid.total_sectors;
+ raid->offset = 0;
+ raid->reserved = 63;
+
+ /* 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;
+ }
+ }
}
- }
- else {
- raid->mirrordisk[disk_number - info->raid.raid0_disks] = adp;
- raid->num_mirrordisks++;
- }
- /* do we have a complete array to attach to ? */
- if (raid->num_subdisks + raid->num_mirrordisks == info->raid.total_disks) {
- raid->flags |= AR_F_CONF_DONE;
- raid->lun = array;
- raid->heads = info->raid.heads + 1;
- raid->sectors = info->raid.sectors;
- raid->cylinders = info->raid.cylinders + 1;
- raid->total_secs = info->raid.total_secs;
- raid->offset = 0;
- raid->reserved = 63;
- ar_attach(raid);
+ raid->disks[info->raid.disk_number].device = adp->device;
+ error = 0;
+ break;
}
- error = 0;
promise_out:
free(info, M_AR);
return error;
}
-int
-ar_read(struct ad_softc *adp, u_int32_t lba, int count, char *data)
+static int
+ar_read(struct ad_softc *adp, u_int32_t lba, int count, u_int8_t *data)
{
- if (ata_command(adp->controller, adp->unit | ATA_D_LBA,
- (count > DEV_BSIZE) ? ATA_C_READ_MUL : ATA_C_READ,
+ 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->controller, adp->unit, "RAID read config failed\n");
+ ata_printf(adp->device->channel, adp->device->unit,
+ "RAID read config failed\n");
return 1;
}
- if (ata_wait(adp->controller, adp->unit, ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)) {
- ata_printf(adp->controller, adp->unit, "RAID read config timeout\n");
+ 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");
return 1;
}
- ATA_INSW(adp->controller->r_io, ATA_DATA, (int16_t *)data,
+ ATA_INSW(adp->device->channel->r_io, ATA_DATA, (int16_t *)data,
count/sizeof(int16_t));
- ATA_INB(adp->controller->r_io, ATA_STATUS);
+ ATA_INB(adp->device->channel->r_io, ATA_STATUS);
return 0;
}
OpenPOWER on IntegriCloud