Add support for ATA "pseudo" RAID controllers as the Promise Fasttrak
and HighPoint HPT370 controllers. Use by defining the RAID in the BIOS and the "ar driver will pick it up automagically...
This commit is contained in:
parent
d851448bbf
commit
e9cf6115e4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=67071
@ -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);
|
||||
|
@ -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);
|
||||
|
571
sys/dev/ata/ata-raid.c
Normal file
571
sys/dev/ata/ata-raid.c
Normal file
@ -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;
|
||||
}
|
178
sys/dev/ata/ata-raid.h
Normal file
178
sys/dev/ata/ata-raid.h
Normal file
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user