Add support for writing Intel MatrixRAID arrays.

Do a little better on handling volumes as well, however we cant create
multiple volumes from FreeBSD yet.

HW sponsored by:        Mullet Scandinavia AB
This commit is contained in:
Søren Schmidt 2005-12-05 17:33:57 +00:00
parent 7b710ab25b
commit eed08844c9
2 changed files with 206 additions and 66 deletions

View File

@ -70,6 +70,7 @@ static int ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_hptv2_write_meta(struct ar_softc *rdp);
static int ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_intel_write_meta(struct ar_softc *rdp);
static int ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp);
@ -105,7 +106,7 @@ static void ata_raid_via_print_meta(struct via_raid_conf *meta);
static struct ar_softc *ata_raid_arrays[MAX_ARRAYS];
static MALLOC_DEFINE(M_AR, "ar_driver", "ATA PseudoRAID driver");
static devclass_t ata_raid_sub_devclass;
static int testing = 0;
static int testing = 1;
/* device structures */
static disk_strategy_t ata_raid_strategy;
@ -875,7 +876,7 @@ ata_raid_create(struct ata_ioc_raid_config *config)
struct ata_raid_subdisk *ars = device_get_softc(subdisk);
/* is device already assigned to another array ? */
if (ars->raid) {
if (ars->raid[rdp->volume]) {
config->disks[disk] = -1;
free(rdp, M_AR);
return EBUSY;
@ -893,6 +894,11 @@ ata_raid_create(struct ata_ioc_raid_config *config)
rdp->disks[disk].sectors = HPTV3_LBA(rdp->disks[disk].dev);
break;
case ATA_INTEL_ID:
ctlr = AR_F_INTEL_RAID;
rdp->disks[disk].sectors = INTEL_LBA(rdp->disks[disk].dev);
break;
case ATA_ITE_ID:
ctlr = AR_F_ITE_RAID;
rdp->disks[disk].sectors = ITE_LBA(rdp->disks[disk].dev);
@ -1063,8 +1069,8 @@ ata_raid_create(struct ata_ioc_raid_config *config)
config->disks[disk]))) {
struct ata_raid_subdisk *ars = device_get_softc(subdisk);
ars->raid = rdp;
ars->disk_number = disk;
ars->raid[rdp->volume] = rdp;
ars->disk_number[rdp->volume] = disk;
}
}
ata_raid_attach(rdp, 1);
@ -1092,12 +1098,12 @@ ata_raid_delete(int array)
device_get_unit(rdp->disks[disk].dev)))) {
struct ata_raid_subdisk *ars = device_get_softc(subdisk);
if (ars->raid != rdp) /* XXX SOS */
if (ars->raid[rdp->volume] != rdp) /* XXX SOS */
device_printf(subdisk, "DOH! this disk doesn't belong\n");
if (ars->disk_number != disk) /* XXX SOS */
if (ars->disk_number[rdp->volume] != disk) /* XXX SOS */
device_printf(subdisk, "DOH! this disk number is wrong\n");
ars->raid = NULL;
ars->disk_number = -1;
ars->raid[rdp->volume] = NULL;
ars->disk_number[rdp->volume] = -1;
}
rdp->disks[disk].flags = 0;
}
@ -1135,12 +1141,12 @@ ata_raid_addspare(struct ata_ioc_raid_config *config)
config->disks[0] ))) {
struct ata_raid_subdisk *ars = device_get_softc(subdisk);
if (ars->raid)
if (ars->raid[rdp->volume])
return EBUSY;
/* XXX SOS validate size etc etc */
ars->raid = rdp;
ars->disk_number = disk;
ars->raid[rdp->volume] = rdp;
ars->disk_number[rdp->volume] = disk;
rdp->disks[disk].dev = device_get_parent(subdisk);
rdp->disks[disk].flags =
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE);
@ -1285,6 +1291,10 @@ ata_raid_write_metadata(struct ar_softc *rdp)
* this is handy since we cannot know what version BIOS is on there
*/
return ata_raid_hptv2_write_meta(rdp);
case AR_F_INTEL_RAID:
return ata_raid_intel_write_meta(rdp);
#if 0
case AR_F_HPTV3_RAID:
return ata_raid_hptv3_write_meta(rdp);
@ -1292,9 +1302,6 @@ ata_raid_write_metadata(struct ar_softc *rdp)
case AR_F_ADAPTEC_RAID:
return ata_raid_adaptec_write_meta(rdp);
case AR_F_INTEL_RAID:
return ata_raid_intel_write_meta(rdp);
case AR_F_ITE_RAID:
return ata_raid_ite_write_meta(rdp);
@ -1420,15 +1427,15 @@ ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp)
struct ata_device *atadev = device_get_softc(parent);
struct ata_channel *ch = device_get_softc(GRANDPARENT(dev));
int disk_number = (ch->unit << !(ch->flags & ATA_NO_SLAVE)) +
(atadev->unit == ATA_MASTER ? 0 : 1);
ATA_DEV(atadev->unit);
raid->disks[disk_number].dev = parent;
raid->disks[disk_number].sectors =
be32toh(meta->configs[disk_number + 1].sectors);
raid->disks[disk_number].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
}
break;
@ -1583,8 +1590,8 @@ highpoint_raid01:
raid->total_disks = raid->width;
if (disk_number >= raid->total_disks)
raid->total_disks = disk_number + 1;
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
break;
}
@ -1668,9 +1675,7 @@ ata_raid_hptv2_write_meta(struct ar_softc *rdp)
meta->total_sectors = rdp->total_sectors;
meta->rebuild_lba = rdp->rebuild_lba;
if (rdp->disks[disk].dev &&
(rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
(AR_DF_PRESENT | AR_DF_ONLINE)) {
if (rdp->disks[disk].dev) {
if (ata_raid_rw(rdp->disks[disk].dev,
HPTV2_LBA(rdp->disks[disk].dev), meta,
sizeof(struct promise_raid_conf),
@ -1812,8 +1817,8 @@ ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp)
raid->disks[disk_number].dev = parent;
raid->disks[disk_number].flags =
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
break;
}
@ -1948,6 +1953,7 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
raid->offset_sectors = map->offset;
raid->rebuild_lba = 0;
raid->lun = array;
raid->volume = volume - 1;
strncpy(raid->name, map->name,
min(sizeof(raid->name), sizeof(map->name)));
@ -1957,7 +1963,8 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
bcopy(meta->disk[map->disk_idx[disk]].serial,
raid->disks[disk].serial,
sizeof(raid->disks[disk].serial));
raid->disks[disk].sectors = map->disk_sectors;
raid->disks[disk].sectors =
meta->disk[map->disk_idx[disk]].sectors;
raid->disks[disk].flags = 0;
if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE)
raid->disks[disk].flags |= AR_DF_ONLINE;
@ -1979,8 +1986,8 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
sizeof(raid->disks[disk].serial))) {
raid->disks[disk].dev = parent;
raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_ONLINE);
ars->raid = raid;
ars->disk_number = disk;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk;
retval = 1;
}
}
@ -1990,10 +1997,17 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
map = (struct intel_raid_mapping *)
&map->disk_idx[map->total_disks];
volume++;
retval = 0;
continue;
}
break;
}
else {
free(raidp[array], M_AR);
raidp[array] = NULL;
if (volume == 2)
retval = 1;
}
}
intel_out:
@ -2001,6 +2015,117 @@ intel_out:
return retval;
}
static int
ata_raid_intel_write_meta(struct ar_softc *rdp)
{
struct intel_raid_conf *meta;
struct intel_raid_mapping *map;
struct timeval timestamp;
u_int32_t checksum, *ptr;
int count, disk, error = 0;
char *tmp;
if (!(meta = (struct intel_raid_conf *)
malloc(1536, M_AR, M_NOWAIT | M_ZERO))) {
printf("ar%d: failed to allocate metadata storage\n", rdp->lun);
return ENOMEM;
}
rdp->generation++;
microtime(&timestamp);
bcopy(INTEL_MAGIC, meta->intel_id, sizeof(meta->intel_id));
bcopy(INTEL_VERSION_1100, meta->version, sizeof(meta->version));
meta->config_id = timestamp.tv_sec;
meta->generation = rdp->generation;
meta->total_disks = rdp->total_disks;
meta->total_volumes = 1; /* XXX SOS */
for (disk = 0; disk < rdp->total_disks; disk++) {
if (rdp->disks[disk].dev) {
struct ata_channel *ch =
device_get_softc(device_get_parent(rdp->disks[disk].dev));
struct ata_device *atadev =
device_get_softc(rdp->disks[disk].dev);
bcopy(atadev->param.serial, meta->disk[disk].serial,
sizeof(rdp->disks[disk].serial));
meta->disk[disk].sectors = rdp->disks[disk].sectors;
meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit);
}
else
meta->disk[disk].sectors = rdp->total_sectors / rdp->width;
meta->disk[disk].flags = 0;
if (rdp->disks[disk].flags & AR_DF_SPARE)
meta->disk[disk].flags |= INTEL_F_SPARE;
else {
if (rdp->disks[disk].flags & AR_DF_ONLINE)
meta->disk[disk].flags |= INTEL_F_ONLINE;
else
meta->disk[disk].flags |= INTEL_F_DOWN;
if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
meta->disk[disk].flags |= INTEL_F_ASSIGNED;
}
}
map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];
bcopy(rdp->name, map->name, sizeof(rdp->name));
map->total_sectors = rdp->total_sectors;
map->state = 12; /* XXX SOS */
map->offset = rdp->offset_sectors;
map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks);
map->stripe_sectors = rdp->interleave;
map->disk_sectors = rdp->total_sectors / rdp->width;
map->status = INTEL_S_READY; /* XXX SOS */
switch (rdp->type) {
case AR_T_RAID0:
map->type = INTEL_T_RAID0;
break;
case AR_T_RAID1:
map->type = INTEL_T_RAID1;
break;
case AR_T_RAID01:
map->type = INTEL_T_RAID1;
break;
case AR_T_RAID5:
map->type = INTEL_T_RAID5;
break;
}
map->total_disks = rdp->total_disks;
map->magic[0] = 0x02;
map->magic[1] = 0xff;
map->magic[2] = 0x01;
for (disk = 0; disk < rdp->total_disks; disk++)
map->disk_idx[disk] = disk;
meta->config_size = (char *)&map->disk_idx[disk] - (char *)meta;
for (checksum = 0, ptr = (u_int32_t *)meta, count = 0;
count < (meta->config_size / sizeof(u_int32_t)); count++) {
checksum += *ptr++;
}
meta->checksum = checksum;
ata_raid_intel_print_meta(meta);
tmp = (char *)meta;
bcopy(tmp, tmp+1024, 512);
bcopy(tmp+512, tmp, 1024);
bzero(tmp+1024, 512);
for (disk = 0; disk < rdp->total_disks; disk++) {
if (rdp->disks[disk].dev) {
if (ata_raid_rw(rdp->disks[disk].dev,
INTEL_LBA(rdp->disks[disk].dev),
meta, 1024, ATA_R_WRITE | ATA_R_DIRECT)) {
device_printf(rdp->disks[disk].dev, "write metadata failed\n");
error = EIO;
}
}
}
free(meta, M_AR);
return error;
}
/* Integrated Technology Express Metadata */
static int
ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp)
@ -2112,8 +2237,8 @@ ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp)
raid->disks[disk_number].sectors = raid->total_sectors / raid->width;
raid->disks[disk_number].flags =
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
break;
}
@ -2230,8 +2355,8 @@ ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp)
meta->configs[conf_entry].disk.disk_sectors;
raid->disks[meta->disk_number].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid = raid;
ars->disk_number = meta->disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = meta->disk_number;
retval = 1;
}
else
@ -2369,8 +2494,8 @@ ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp)
raid->disks[disk_number].sectors = raid->total_sectors / raid->width;
raid->disks[disk_number].flags =
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
entry++;
array++;
@ -2495,8 +2620,8 @@ ata_raid_nvidia_read_meta(device_t dev, struct ar_softc **raidp)
raid->total_sectors / raid->width;
raid->disks[meta->disk_number].flags =
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
ars->raid = raid;
ars->disk_number = meta->disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = meta->disk_number;
retval = 1;
break;
}
@ -2678,8 +2803,8 @@ ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native)
if ((raid->disks[disk_number].flags &
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) ==
(AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) {
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
}
}
@ -2715,13 +2840,13 @@ ata_raid_promise_write_meta(struct ar_softc *rdp)
meta->dummy_0 = 0x00020000;
meta->raid.disk_number = disk;
if ((rdp->disks[disk].flags & AR_DF_PRESENT) && rdp->disks[disk].dev) {
if (rdp->disks[disk].dev) {
struct ata_device *atadev = device_get_softc(rdp->disks[disk].dev);
struct ata_channel *ch =
device_get_softc(device_get_parent(rdp->disks[disk].dev));
meta->raid.channel = ch->unit;
meta->raid.device = (atadev->unit != 0);
meta->raid.device = ATA_DEV(atadev->unit);
meta->raid.disk_sectors = rdp->disks[disk].sectors;
meta->raid.disk_offset = rdp->offset_sectors;
}
@ -2806,7 +2931,7 @@ ata_raid_promise_write_meta(struct ar_softc *rdp)
device_get_softc(rdp->disks[drive].dev);
meta->raid.disk[drive].channel = ch->unit;
meta->raid.disk[drive].device = (atadev->unit != 0);
meta->raid.disk[drive].device = ATA_DEV(atadev->unit);
}
meta->raid.disk[drive].magic_0 =
PR_MAGIC0(meta->raid.disk[drive]) | timestamp.tv_sec;
@ -2973,8 +3098,8 @@ ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp)
raid->total_sectors / raid->width;
raid->disks[disk_number].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
retval = 1;
}
}
@ -3092,8 +3217,8 @@ ata_raid_sis_read_meta(device_t dev, struct ar_softc **raidp)
raid->disks[disk_number].dev = parent;
raid->disks[disk_number].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid = raid;
ars->disk_number = disk_number;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk_number;
}
}
retval = 1;
@ -3209,8 +3334,8 @@ ata_raid_via_read_meta(device_t dev, struct ar_softc **raidp)
raid->disks[disk].sectors = meta->total_sectors / raid->width;
raid->disks[disk].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid = raid;
ars->disk_number = disk;
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk;
retval = 1;
break;
}
@ -3353,9 +3478,12 @@ static int
ata_raid_subdisk_attach(device_t dev)
{
struct ata_raid_subdisk *ars = device_get_softc(dev);
int volume;
ars->raid = NULL;
ars->disk_number = -1;
for (volume = 0; volume < MAX_VOLUMES; volume++) {
ars->raid[volume] = NULL;
ars->disk_number[volume] = -1;
}
ata_raid_read_metadata(dev);
return 0;
}
@ -3364,14 +3492,17 @@ static int
ata_raid_subdisk_detach(device_t dev)
{
struct ata_raid_subdisk *ars = device_get_softc(dev);
int volume;
if (ars->raid) {
ars->raid->disks[ars->disk_number].flags &=
for (volume = 0; volume < MAX_VOLUMES; volume++) {
if (ars->raid[volume]) {
ars->raid[volume]->disks[ars->disk_number[volume]].flags &=
~(AR_DF_PRESENT | AR_DF_ONLINE);
ars->raid->disks[ars->disk_number].dev = NULL;
ata_raid_config_changed(ars->raid, 1);
ars->raid = NULL;
ars->disk_number = -1;
ars->raid[volume]->disks[ars->disk_number[volume]].dev = NULL;
ata_raid_config_changed(ars->raid[volume], 1);
ars->raid[volume] = NULL;
ars->disk_number[volume] = -1;
}
}
return 0;
}
@ -3781,6 +3912,9 @@ ata_raid_intel_print_meta(struct intel_raid_conf *meta)
printf("status %u\n", map->status);
printf("type %s\n", ata_raid_intel_type(map->type));
printf("total_disks %u\n", map->total_disks);
printf("magic[0] 0x%02x\n", map->magic[0]);
printf("magic[1] 0x%02x\n", map->magic[1]);
printf("magic[2] 0x%02x\n", map->magic[2]);
for (i = 0; i < map->total_disks; i++ ) {
printf(" disk %d at disk_idx 0x%08x\n", i, map->disk_idx[i]);
}

View File

@ -30,22 +30,24 @@
/* misc defines */
#define MAX_ARRAYS 16
#define MAX_VOLUMES 4
#define MAX_DISKS 16
#define AR_PROXIMITY 2048 /* how many sectors is "close" */
#define ATA_MAGIC "FreeBSD ATA driver RAID "
struct ata_raid_subdisk {
struct ar_softc *raid;
int disk_number;
struct ar_softc *raid[MAX_VOLUMES];
int disk_number[MAX_VOLUMES];
};
/* ATA PseudoRAID Metadata */
struct ar_softc {
int lun; /* logical unit number of this RAID */
u_int8_t name[32]; /* name of array if any */
u_int64_t magic_0; /* magic for this array */
u_int64_t magic_1; /* magic for this array */
int lun;
u_int8_t name[32];
int volume;
u_int64_t magic_0;
u_int64_t magic_1;
int type;
#define AR_T_JBOD 0x0001
#define AR_T_SPAN 0x0002
@ -77,14 +79,14 @@ struct ar_softc {
#define AR_F_VIA_RAID 0x1000
#define AR_F_FORMAT_MASK 0x1fff
u_int generation; /* generation of this array */
u_int generation;
u_int64_t total_sectors;
u_int64_t offset_sectors; /* offset from start of disk */
u_int16_t heads;
u_int16_t sectors;
u_int32_t cylinders;
u_int width; /* array width in disks */
u_int interleave; /* interleave in blocks */
u_int interleave; /* interleave in sectors */
u_int total_disks; /* number of disks in this array */
struct ar_disk {
device_t dev;
@ -288,6 +290,10 @@ struct intel_raid_conf {
#define INTEL_MAGIC "Intel Raid ISM Cfg Sig. "
u_int8_t version[6];
#define INTEL_VERSION_1100 "1.1.00"
#define INTEL_VERSION_1201 "1.2.01"
#define INTEL_VERSION_1202 "1.2.02"
u_int8_t dummy_0[2];
u_int32_t checksum;
u_int32_t config_size;
@ -318,7 +324,7 @@ struct intel_raid_mapping {
u_int64_t total_sectors __packed;
u_int32_t state;
u_int32_t reserved;
u_int32_t filler_1[20];
u_int32_t filler_0[20];
u_int32_t offset;
u_int32_t disk_sectors;
u_int32_t stripe_count;
@ -335,8 +341,8 @@ struct intel_raid_mapping {
#define INTEL_T_RAID5 0x05
u_int8_t total_disks;
u_int8_t dummy_2[3];
u_int32_t filler_2[7];
u_int8_t magic[3];
u_int32_t filler_1[7];
u_int32_t disk_idx[1];
} __packed;