From eed08844c993e299a723a7b14102012a42d32fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Schmidt?= Date: Mon, 5 Dec 2005 17:33:57 +0000 Subject: [PATCH] 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 --- sys/dev/ata/ata-raid.c | 244 +++++++++++++++++++++++++++++++---------- sys/dev/ata/ata-raid.h | 28 +++-- 2 files changed, 206 insertions(+), 66 deletions(-) diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index ad269238b33..cbb641bf43f 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -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(×tamp); + + 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 &= - ~(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; + 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[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]); } diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 55ecbf5f8bf..30f66528360 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -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;