diff options
-rw-r--r-- | sys/dev/ata/ata-disk.c | 31 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.c | 571 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.h | 178 |
4 files changed, 768 insertions, 14 deletions
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 4b2c87b..fcfe377 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -48,6 +48,7 @@ #include <machine/bus.h> #include <dev/ata/ata-all.h> #include <dev/ata/ata-disk.h> +#include <dev/ata/ata-raid.h> /* device structures */ static d_open_t adopen; @@ -156,6 +157,18 @@ ad_attach(struct ata_softc *scp, int device) printf("ad%d: disabling service interrupt failed\n", adp->lun); } + devstat_add_entry(&adp->stats, "ad", adp->lun, DEV_BSIZE, + DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, + DEVSTAT_PRIORITY_DISK); + + dev = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw, &addisk_cdevsw); + dev->si_drv1 = adp; + dev->si_iosize_max = 256 * DEV_BSIZE; + adp->dev = dev; + + bioq_init(&adp->queue); + if (bootverbose) { printf("ad%d: <%.40s/%.8s> ATA-%d disk at ata%d-%s\n", adp->lun, AD_PARAM->model, AD_PARAM->revision, @@ -178,6 +191,10 @@ ad_attach(struct ata_softc *scp, int device) ata_umode(AD_PARAM), AD_PARAM->cblid); } + + /* if this disk belongs to an ATA RAID dont print the probe */ + if (adp->controller->flags & ATA_RAID && !ar_probe(adp)) + return; else printf("ad%d: %luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n", adp->lun, adp->total_secs / ((1024L * 1024L) / DEV_BSIZE), @@ -186,25 +203,13 @@ ad_attach(struct ata_softc *scp, int device) (adp->unit == ATA_MASTER) ? "master" : "slave", (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)])); - - devstat_add_entry(&adp->stats, "ad", adp->lun, DEV_BSIZE, - DEVSTAT_NO_ORDERED_TAGS, - DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, - DEVSTAT_PRIORITY_DISK); - - dev = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw, &addisk_cdevsw); - dev->si_drv1 = adp; - dev->si_iosize_max = 256 * DEV_BSIZE; - adp->dev1 = dev; - - bioq_init(&adp->queue); } void ad_detach(struct ad_softc *adp) { disk_invalidate(&adp->disk); - disk_destroy(adp->dev1); + disk_destroy(adp->dev); devstat_remove_entry(&adp->stats); ata_free_lun(&adp_lun_map, adp->lun); free(adp, M_AD); diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index 37b0ced..b2a8de7 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -74,7 +74,7 @@ struct ad_softc { struct bio_queue_head queue; /* head of request queue */ struct devstat stats; /* devstat entry */ struct disk disk; /* disklabel/slice stuff */ - dev_t dev1, dev2; /* device place holder */ + dev_t dev; /* device place holder */ }; void ad_attach(struct ata_softc *, int); diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c new file mode 100644 index 0000000..5c46bf1 --- /dev/null +++ b/sys/dev/ata/ata-raid.c @@ -0,0 +1,571 @@ +/*- + * Copyright (c) 2000 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_global.h" +#include "opt_ata.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/bio.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/disk.h> +#include <sys/devicestat.h> +#include <sys/cons.h> +#include <machine/bus.h> +#include <dev/ata/ata-all.h> +#include <dev/ata/ata-disk.h> +#include <dev/ata/ata-raid.h> + +/* device structures */ +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, + /* bmaj */ -1 +}; +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_config *); +static int32_t ar_promise_magic(struct promise_raid_conf *); +static int ar_promise_conf(struct ad_softc *, struct ar_config *); +static int ar_read(struct ad_softc *, u_int32_t, int, char *); + +/* internal vars */ +static int ar_init = 0; +static struct ar_config ar_table; +MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver"); + +/* defines */ +#define PRINT_AD(adp) \ + printf(" ad%d: %luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n", \ + adp->lun, adp->total_secs / ((1024L * 1024L) / DEV_BSIZE), \ + adp->controller->dev_param[ATA_DEV(adp->unit)]->model, \ + adp->total_secs / (adp->heads * adp->sectors), \ + adp->heads, adp->sectors, device_get_unit(adp->controller->dev),\ + (adp->unit == ATA_MASTER) ? "master" : "slave", \ + (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", \ + ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)])) + +int +ar_probe(struct ad_softc *adp) +{ + if (!ar_init) { + bzero(&ar_table, sizeof(ar_table)); + ar_init = 1; + } + + switch(adp->controller->chiptype) { + case 0x4d33105a: + case 0x4d38105a: + case 0x4d30105a: + case 0x0d30105a: + if (ar_promise_conf(adp, &ar_table)) { + printf("ata-raid: failed to read array configuration\n"); + break; + } + return 0; + + case 0x00041103: + if (ar_highpoint_conf(adp, &ar_table)) { + printf("ata-raid: failed to read array configuration\n"); + break; + } + return 0; + } + return 1; +} + +static 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; + } + printf("array> [%d/%d/%d] subdisks: \n", + raid->cylinders, raid->heads, raid->sectors); + for (i = 0; i < raid->num_subdisks; i++) + PRINT_AD(raid->subdisk[i]); + for (i = 0; i < raid->num_mirrordisks; i++) + PRINT_AD(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 +aropen(dev_t dev, int flags, int fmt, struct proc *p) +{ + struct ar_softc *rdp = dev->si_drv1; + struct disklabel *dl; + + dl = &rdp->disk.d_label; + bzero(dl, sizeof *dl); + dl->d_secsize = DEV_BSIZE; + dl->d_nsectors = rdp->sectors; + dl->d_ntracks = rdp->heads; + dl->d_ncylinders = rdp->cylinders; + dl->d_secpercyl = rdp->sectors * rdp->heads; + dl->d_secperunit = rdp->total_secs; + return 0; +} + +static void +arstrategy(struct bio *bp) +{ + struct ar_softc *rdp = bp->bio_dev->si_drv1; + int lba, count, chunk; + caddr_t data; + + /* if it's a null transfer, return immediatly. */ + if (bp->bio_bcount == 0) { + bp->bio_resid = 0; + biodone(bp); + return; + } + + bp->bio_resid = bp->bio_bcount; + lba = bp->bio_pblkno; + data = bp->bio_data; + for (count = howmany(bp->bio_bcount, DEV_BSIZE); count > 0; + count -= chunk, lba += chunk, data += (chunk * DEV_BSIZE)) { + struct ar_buf *buf1, *buf2; + int plba; + + buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); + bzero(buf1, sizeof(struct ar_buf)); + if (rdp->flags & 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); + buf1->bp.bio_pblkno = plba; + chunk = min(rdp->subdisk[buf1->drive]->total_secs - + rdp->reserved - plba, count); +/* SOS */ + if (plba + chunk > + rdp->subdisk[buf1->drive]->total_secs - rdp->reserved) + printf("Oops! SPAN trying lba=%d > %d\n", plba + chunk, + rdp->subdisk[buf1->drive]->total_secs-rdp->reserved); +/* SOS */ + } + else if (rdp->flags & AR_F_RAID_0) { + plba = lba / rdp->interleave; + chunk = lba % rdp->interleave; + buf1->drive = plba % rdp->num_subdisks; + buf1->bp.bio_pblkno = + ((plba / rdp->num_subdisks) * rdp->interleave) + chunk; + chunk = min(rdp->interleave - chunk, count); +/* SOS */ + if (plba + chunk > + rdp->subdisk[buf1->drive]->total_secs - rdp->reserved) + printf("Oops! RAID0 trying lba=%d > %d\n", plba + chunk, + rdp->subdisk[buf1->drive]->total_secs-rdp->reserved); +/* SOS */ + } + else { + buf1->bp.bio_pblkno = lba; + buf1->drive = 0; + chunk = count; +/* SOS */ + if (lba + chunk > + rdp->subdisk[buf1->drive]->total_secs - rdp->reserved) + printf("Oops! RAID1 trying lba=%d > %d\n", lba + chunk, + rdp->subdisk[buf1->drive]->total_secs - rdp->reserved); +/* SOS */ + } + + buf1->bp.bio_pblkno += rdp->offset; + buf1->bp.bio_caller1 = (void *)rdp; + buf1->bp.bio_bcount = chunk * DEV_BSIZE; + buf1->bp.bio_data = data; + buf1->bp.bio_cmd = bp->bio_cmd; + buf1->bp.bio_flags = bp->bio_flags; + 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; + } + 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->si_disk->d_devsw->d_strategy((struct bio *)buf1); + } +} + +static void +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(); + + if (bp->bio_flags & BIO_ERROR) { + if (bp->bio_cmd == BIO_WRITE || buf->done || !(rdp->flags&AR_F_RAID_1)){ + buf->org->bio_flags |= BIO_ERROR; + buf->org->bio_error = bp->bio_error; + } + printf("ar%d: error\n", rdp->lun); + } + + if (rdp->flags & AR_F_RAID_1) { + if (bp->bio_cmd == BIO_WRITE) { + if (!buf->done) { + buf->mirror->done = 1; + goto done; + } + } + 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; + } + } + } + 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_config *raidp) +{ + struct highpoint_raid_conf info; + int array_done = 0, r; + + if (ar_read(adp, 0x09, DEV_BSIZE, (char *)&info)) { + printf("HighPoint read conf failed\n"); + return 1; + } + + /* check if this is a HighPoint RAID struct */ + if (info.magic != HPT_MAGIC_OK) { + printf("HighPoint check1 failed\n"); + return 1; + } + + /* now convert HighPoint config info into our generic form */ + for (r = 0; r < 8; r++) { + if (!raidp->raid[r]) { + raidp->raid[r] = + (struct ar_softc*)malloc(sizeof(struct ar_softc),M_AR,M_NOWAIT); + if (!raidp->raid[r]) { + printf("ar: failed to allocate raid config storage\n"); + return 1; + } + bzero(raidp->raid[r], sizeof(struct ar_softc)); + } + + switch (info.type) { + case HPT_T_RAID_0: + if (raidp->raid[r]->magic && raidp->raid[r]->magic != info.magic_0) + continue; + raidp->raid[r]->magic = info.magic_0; + + /* check for the MIRROR bit in "order" smells like bug to me :) */ + if (info.order & HPT_O_MIRROR) + goto hpt_mirror; + raidp->raid[r]->flags |= AR_F_RAID_0; + raidp->raid[r]->interleave = 1 << info.raid0_shift; + raidp->raid[r]->subdisk[raidp->raid[r]->num_subdisks] = adp; + raidp->raid[r]->num_subdisks++; + if (raidp->raid[r]->num_subdisks == info.raid_disks) + array_done = 1; + break; + + case HPT_T_RAID_1: + if (raidp->raid[r]->magic && raidp->raid[r]->magic != info.magic_1) + continue; + raidp->raid[r]->magic = info.magic_1; +hpt_mirror: + raidp->raid[r]->flags |= AR_F_RAID_1; + if (raidp->raid[r]->num_subdisks == 0) { + raidp->raid[r]->subdisk[raidp->raid[r]->num_subdisks] = adp; + raidp->raid[r]->num_subdisks = 1; + } + else if (raidp->raid[r]->num_subdisks == 1 && + raidp->raid[r]->num_mirrordisks == 0) { + raidp->raid[r]->mirrordisk[raidp->raid[r]->num_mirrordisks]=adp; + raidp->raid[r]->num_mirrordisks = 1; + } + if ((raidp->raid[r]->num_subdisks + + raidp->raid[r]->num_mirrordisks) == (info.raid_disks * 2)) + array_done = 1; + break; + + case HPT_T_SPAN: + if (raidp->raid[r]->magic && raidp->raid[r]->magic != info.magic_0) + continue; + raidp->raid[r]->magic = info.magic_0; + raidp->raid[r]->flags |= AR_F_SPAN; + raidp->raid[r]->subdisk[raidp->raid[r]->num_subdisks] = adp; + raidp->raid[r]->num_subdisks++; + if (raidp->raid[r]->num_subdisks == info.raid_disks) + array_done = 1; + break; + + default: + printf("HighPoint unknown RAID type 0x%02x\n", info.type); + } + if (array_done) { + raidp->raid[r]->lun = r; + raidp->raid[r]->heads = 255; + raidp->raid[r]->sectors = 63; + raidp->raid[r]->cylinders = (info.total_secs - 9) / (63 * 255); + raidp->raid[r]->total_secs = info.total_secs - + (9 * raidp->raid[r]->num_subdisks); + raidp->raid[r]->offset = 10; + raidp->raid[r]->reserved = 10; + ar_attach(raidp->raid[r]); + return 0; + } + break; + } + return 0; +} + +static int32_t +ar_promise_magic(struct promise_raid_conf *info) +{ + int i, j; + int32_t magic = 0; + + for (i = 0; i < 4; i++) { + if ((info->raid[i].flags != PR_F_CONFED) || + (((info->raid[i].status & (PR_S_DEFINED|PR_S_ONLINE)) != + (PR_S_DEFINED|PR_S_ONLINE)))) + continue; + for (j = 0; j < info->raid[i].total_disks; j++) { + magic <<= 8; + magic |= ((info->raid[i].disk[j].magic_0 & 0x00ff0000)>>16); + } + } + return magic; +} + +/* read the RAID info from a disk on a Promise Fasttrak controller */ +static int +ar_promise_conf(struct ad_softc *adp, struct ar_config *raidp) +{ + struct promise_raid_conf info; + u_int32_t lba; + u_int32_t cksum, *ckptr; + int count, i, j, r; + + lba = adp->total_secs - adp->sectors; + + if (ar_read(adp, lba, 4 * DEV_BSIZE, (char *)&info)) { + printf("Promise read conf failed\n"); + return 1; + } + + /* check if this is a Promise RAID struct */ + if (strncmp(info.promise_id, PR_MAGIC, sizeof(PR_MAGIC))) { + printf("Promise check1 failed\n"); + return 1; + } + + /* check if the checksum is OK */ + for (cksum = 0, ckptr = (int32_t *)&info, count = 0; count < 511; count++) + cksum += *ckptr++; + if (cksum != *ckptr) { + printf("Promise check2 failed\n"); + return 1; + } + + /* now convert Promise config info into our generic form */ + for (i = 0, r = 0; i < 4; i++) { + if ((info.raid[i].flags != PR_F_CONFED) || + (((info.raid[i].status & (PR_S_DEFINED|PR_S_ONLINE)) != + (PR_S_DEFINED|PR_S_ONLINE)))) { + continue; + } + + if (raidp->raid[r]) { + if (ar_promise_magic(&info) != raidp->raid[r]->magic) { + r++; + i--; + continue; + } + } + else { + if (!(raidp->raid[r] = (struct ar_softc *) + malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT))) { + printf("ar: failed to allocate raid config storage\n"); + return 1; + } + else + bzero(raidp->raid[r], sizeof(struct ar_softc)); + } + raidp->raid[r]->magic = ar_promise_magic(&info); + + switch (info.raid[i].type) { + case PR_T_STRIPE: + raidp->raid[r]->flags |= AR_F_RAID_0; + raidp->raid[r]->interleave = 1 << info.raid[i].raid0_shift; + break; + + case PR_T_MIRROR: + raidp->raid[r]->flags |= AR_F_RAID_1; + break; + + case PR_T_SPAN: + raidp->raid[r]->flags |= AR_F_SPAN; + break; + + default: + printf("Promise unknown RAID type 0x%02x\n", info.raid[i].type); + } + + /* find out where this disk is in the defined array */ + /* first RAID0 / SPAN disks */ + for (j = 0; j < info.raid[i].raid0_disks; j++) { + if (info.channel == info.raid[i].disk[j].channel && + info.device == info.raid[i].disk[j].device) { + /*printf("ar%d: RAID subdisk %d->ad%d\n", r, j, adp->lun);*/ + raidp->raid[r]->subdisk[raidp->raid[r]->num_subdisks] = adp; + raidp->raid[r]->num_subdisks++; + if (raidp->raid[r]->num_subdisks > 1 && + !(raidp->raid[r]->flags & AR_F_SPAN)) { + raidp->raid[r]->flags |= AR_F_RAID_0; + raidp->raid[r]->interleave = 1 << info.raid[i].raid0_shift; + } + } + } + + /* if any left they are RAID1 disks eventually in a RADI0+1 config */ + for (; j < info.raid[i].total_disks; j++) { + if (info.channel == info.raid[i].disk[j].channel && + info.device == info.raid[i].disk[j].device) { + /*printf("ar%d: RAID mirrordisk %d->ad%d\n", r, j, adp->lun);*/ + raidp->raid[r]-> + mirrordisk[raidp->raid[r]->num_mirrordisks] = adp; + raidp->raid[r]->num_mirrordisks++; + } + } + + /* do we have a complete array to attach to ? */ + if (raidp->raid[r]->num_subdisks + raidp->raid[r]->num_mirrordisks == + info.raid[i].total_disks) { + raidp->raid[r]->lun = r; + raidp->raid[r]->heads = info.raid[i].heads + 1; + raidp->raid[r]->sectors = info.raid[i].sectors; + raidp->raid[r]->cylinders = info.raid[i].cylinders + 1; + raidp->raid[r]->total_secs = info.raid[i].total_secs; + raidp->raid[r]->offset = 0; + raidp->raid[r]->reserved = 63; + ar_attach(raidp->raid[r]); + } + r++; + } + return 0; +} + +int +ar_read(struct ad_softc *adp, u_int32_t lba, int count, char *data) +{ + if (ata_command(adp->controller, adp->unit | ATA_D_LBA, + (count > DEV_BSIZE) ? ATA_C_READ_MUL : ATA_C_READ, + (lba >> 8) & 0xffff, (lba >> 24) & 0xff, lba & 0xff, + 4, 0, ATA_WAIT_INTR)) { + ata_printf(adp->controller, adp->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"); + return 1; + } + insw(adp->controller->ioaddr + ATA_DATA, data, count/sizeof(int16_t)); + inb(adp->controller->ioaddr + ATA_STATUS); + return 0; +} diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h new file mode 100644 index 0000000..a1d6705 --- /dev/null +++ b/sys/dev/ata/ata-raid.h @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 2000 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +struct ar_softc { + int lun; + int32_t magic; + int flags; +#define AR_F_RAID_0 0x0001 /* STRIPE */ +#define AR_F_RAID_1 0x0002 /* MIRROR */ +#define AR_F_SPAN 0x0004 /* SPAN */ + + int num_subdisks; + struct ad_softc *subdisk[8]; + int num_mirrordisks; + struct ad_softc *mirrordisk[8]; + int interleave; + int last_disk; + int32_t last_lba[8][2]; + + u_int16_t heads; + u_int16_t sectors; + u_int32_t cylinders; + u_int32_t total_secs; + int reserved; /* sectors that are NOT to be used */ + int offset; /* offset from start of disk */ + + struct disk disk; /* disklabel/slice stuff */ + dev_t dev; /* device place holder */ + +}; + +struct ar_config { + int num_raids; + struct ar_softc *raid[8]; /* configs for each RAID */ +}; + +struct ar_buf { + struct bio bp; + struct bio *org; + int drive; + struct ar_buf *mirror; + int done; +}; + +struct highpoint_raid_conf { + int8_t filler1[32]; + u_int32_t magic; /* 0x20 */ +#define HPT_MAGIC_OK 0x5a7816f0 +#define HPT_MAGIC_BAD 0x5a7816fd + + u_int32_t magic_0; + u_int32_t magic_1; + u_int32_t order; +#define HPT_O_MIRROR 0x01 +#define HPT_O_OK 0x04 + + u_int8_t raid_disks; + u_int8_t raid0_shift; + u_int8_t type; +#define HPT_T_RAID_0 0x00 +#define HPT_T_RAID_1 0x01 +#define HPT_T_RAID_01_RAID_0 0x02 +#define HPT_T_SPAN 0x03 +#define HPT_T_RAID_3 0x04 +#define HPT_T_RAID_5 0x05 +#define HPT_T_SINGLEDISK 0x06 +#define HPT_T_RAID_01_RAID_1 0x07 + + u_int8_t disk_number; + u_int32_t total_secs; + u_int32_t disk_mode; + u_int32_t boot_mode; + u_int8_t boot_disk; + u_int8_t boot_protect; + u_int8_t error_log_entries; + u_int8_t error_log_index; + struct { + u_int32_t timestamp; + u_int8_t reason; +#define HPT_R_REMOVED 0xfe +#define HPT_R_BROKEN 0xff + + u_int8_t disk; + u_int8_t status; + u_int8_t sectors; + u_int32_t lba; + } errorlog[32]; + int8_t filler2[60]; +}; + +struct promise_raid_conf { + char promise_id[24]; +#define PR_MAGIC "Promise Technology, Inc." + + int32_t dummy_0; + int32_t magic_0; + int16_t dummy_1; + int8_t channel; + int8_t device; + int32_t magic_1; + int16_t dummy_2; + int8_t filler1[470]; + struct { + int32_t flags; /* 0x200 */ +#define PR_F_CONFED 0x00000080 + + int8_t dummy_0; + int8_t device_0; + int8_t dummy_1; + int8_t device_1; + int32_t magic_0; + int32_t dummy_2; + int32_t dummy_3; /* 0x210 */ + int32_t disk_secs; + int32_t dummy_4; + int16_t dummy_5; + int8_t status; +#define PR_S_DEFINED 0x01 +#define PR_S_ONLINE 0x02 +#define PR_S_OFFLINE 0x10 + + int8_t type; +#define PR_T_STRIPE 0x00 +#define PR_T_MIRROR 0x01 +#define PR_T_STRIPE_MIRROR 0x04 +#define PR_T_SPAN 0x08 + + u_int8_t total_disks; /* 0x220 */ + u_int8_t raid0_shift; + u_int8_t raid0_disks; + u_int8_t dummy_6; + u_int32_t total_secs; + u_int16_t cylinders; + u_int8_t heads; + u_int8_t sectors; + int32_t magic_1; + int32_t dummy_7; /* 0x230 */ + struct { + int16_t dummy_0; + int8_t channel; + int8_t device; + int32_t magic_0; + int32_t disk_number; /* subdisk # */ + } disk[8]; + } raid[4]; + int32_t filler2[235]; + uint32_t checksum; +}; + +int ar_probe(struct ad_softc *); + |