summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-disk.c31
-rw-r--r--sys/dev/ata/ata-disk.h2
-rw-r--r--sys/dev/ata/ata-raid.c571
-rw-r--r--sys/dev/ata/ata-raid.h178
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 *);
+
OpenPOWER on IntegriCloud