summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2002-02-12 11:35:15 +0000
committersos <sos@FreeBSD.org>2002-02-12 11:35:15 +0000
commit334f09ed2aa2cadf1a5a71122136f5ef65f30423 (patch)
tree0c8c08ffda24c52313dd92cb9925bfcc9f6e4d43 /sys/dev/ata
parent050837293fd14801c43b6cdedb8f4af1561a00de (diff)
downloadFreeBSD-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.c13
-rw-r--r--sys/dev/ata/ata-disk.c4
-rw-r--r--sys/dev/ata/ata-raid.c525
-rw-r--r--sys/dev/ata/ata-raid.h27
-rw-r--r--sys/dev/ata/atapi-all.c4
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(&timestamp);
+ 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(&timestamp);
+
+ 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
OpenPOWER on IntegriCloud