diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 15db486ca527..a7612e2642fd 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -77,6 +77,7 @@ static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp); static int ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native); static int ata_raid_promise_write_meta(struct ar_softc *rdp); static int ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp); +static int ata_raid_via_read_meta(device_t dev, struct ar_softc **raidp); static struct ata_request *ata_raid_init_request(struct ar_softc *rdp, struct bio *bio); static int ata_raid_send_request(struct ata_request *request); static int ata_raid_rw(device_t dev, u_int64_t lba, void *data, u_int bcount, int flags); @@ -95,6 +96,7 @@ static void ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta); static void ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta); static void ata_raid_promise_print_meta(struct promise_raid_conf *meta); static void ata_raid_sii_print_meta(struct sii_raid_conf *meta); +static void ata_raid_via_print_meta(struct via_raid_conf *meta); /* internal vars */ static struct ar_softc *ata_raid_arrays[MAX_ARRAYS]; @@ -958,18 +960,6 @@ ata_raid_create(struct raid_setup *setup) rdp->interleave = min(max(32, rdp->interleave), 128); /*+*/ break; - case AR_F_INTEL_RAID: - rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ - break; - - case AR_F_ITE_RAID: - rdp->interleave = min(max(2, rdp->interleave), 128); /*+*/ - break; - - case AR_F_SII_RAID: - rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ - break; - case AR_F_HPTV2_RAID: rdp->interleave = min(max(8, rdp->interleave), 128); /*+*/ rdp->offset_sectors = HPTV2_LBA(x) + 1; @@ -979,6 +969,14 @@ ata_raid_create(struct raid_setup *setup) rdp->interleave = min(max(32, rdp->interleave), 4096); /*+*/ break; + case AR_F_INTEL_RAID: + rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ + break; + + case AR_F_ITE_RAID: + rdp->interleave = min(max(2, rdp->interleave), 128); /*+*/ + break; + case AR_F_LSIV2_RAID: rdp->interleave = min(max(2, rdp->interleave), 4096); break; @@ -990,6 +988,14 @@ ata_raid_create(struct raid_setup *setup) case AR_F_PROMISE_RAID: rdp->interleave = min(max(2, rdp->interleave), 2048); /*+*/ break; + + case AR_F_SII_RAID: + rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ + break; + + case AR_F_VIA_RAID: + rdp->interleave = min(max(8, rdp->interleave), 128); /*+*/ + break; } rdp->total_disks = total_disks; @@ -1177,6 +1183,11 @@ ata_raid_read_metadata(device_t subdisk) if (ata_raid_sii_read_meta(subdisk, ata_raid_arrays)) return 0; break; + + case ATA_VIA_ID: + if (ata_raid_via_read_meta(subdisk, ata_raid_arrays)) + return 0; + break; } } @@ -1219,10 +1230,10 @@ ata_raid_write_metadata(struct ar_softc *rdp) case AR_F_ADAPTEC_RAID: return ata_raid_adaptec_write_meta(rdp); - case ATA_INTEL_ID: + case AR_F_INTEL_RAID: return ata_raid_intel_write_meta(rdp); - case ATA_ITE_ID: + case AR_F_ITE_RAID: return ata_raid_ite_write_meta(rdp); case AR_F_LSIV2_RAID: @@ -1231,7 +1242,10 @@ ata_raid_write_metadata(struct ar_softc *rdp) case AR_F_LSIV3_RAID: return ata_raid_lsiv3_write_meta(rdp); - case ATA_SILICON_IMAGE_ID: + case AR_F_SII_RAID: + return ata_raid_sii_write_meta(rdp); + + case AR_F_VIA_RAID: return ata_raid_sii_write_meta(rdp); #endif default: @@ -2762,7 +2776,7 @@ ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp) raid->disks[disk_number].dev = parent; raid->disks[disk_number].sectors = - raid->total_sectors / raid->total_disks; + raid->total_sectors / raid->width; raid->disks[disk_number].flags = (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); ars->raid = raid; @@ -2778,6 +2792,123 @@ ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp) return retval; } +/* VIA Tech Metadata */ +static int +ata_raid_via_read_meta(device_t dev, struct ar_softc **raidp) +{ + struct ata_raid_subdisk *ars = device_get_softc(dev); + device_t parent = device_get_parent(dev); + struct via_raid_conf *meta; + struct ar_softc *raid = NULL; + u_int8_t checksum, *ptr; + int array, count, disk, retval = 0; + + if (!(meta = (struct via_raid_conf *) + malloc(sizeof(struct via_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return ENOMEM; + + if (ata_raid_rw(parent, VIA_LBA(parent), + meta, sizeof(struct via_raid_conf), ATA_R_READ)) { + if (testing || bootverbose) + device_printf(parent, "VIA read metadata failed\n"); + goto via_out; + } + + /* check if this is a VIA RAID struct */ + if (meta->magic != VIA_MAGIC) { + if (testing || bootverbose) + device_printf(parent, "VIA check1 failed\n"); + goto via_out; + } + + /* calc the checksum and compare for valid */ + for (checksum = 0, ptr = (u_int8_t *)meta, count = 0; count < 50; count++) + checksum += *ptr++; + if (checksum != meta->checksum) { + if (testing || bootverbose) + device_printf(parent, "VIA check2 failed\n"); + goto via_out; + } + + if (testing || bootverbose) + ata_raid_via_print_meta(meta); + + /* now convert VIA meta into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + if (!raidp[array]) { + raidp[array] = + (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array]) { + device_printf(parent, "failed to allocate metadata storage\n"); + goto via_out; + } + } + raid = raidp[array]; + if (raid->format && (raid->format != AR_F_VIA_RAID)) + continue; + + if (raid->format == AR_F_VIA_RAID && (raid->magic_0 != meta->disks[0])) + continue; + + switch (meta->type) { + case VIA_T_RAID0: + raid->type = AR_T_RAID0; + raid->width = meta->stripe_layout & VIA_L_MASK; + raid->total_sectors = meta->total_sectors; + break; + + case VIA_T_RAID1: + raid->type = AR_T_RAID1; + raid->width = 1; + raid->total_sectors = meta->total_sectors; + break; + + case VIA_T_SPAN: + raid->type = AR_T_SPAN; + raid->width = 1; + raid->total_sectors += meta->total_sectors; + break; + + default: + device_printf(parent,"VIA unknown RAID type 0x%02x\n", meta->type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto via_out; + } + raid->magic_0 = meta->disks[0]; /* XXX SOS hackish */ + raid->format = AR_F_VIA_RAID; + raid->generation = 0; + raid->interleave = 0x08 << (meta->stripe_layout >> VIA_L_SHIFT); + for (count = 0, disk = 0; disk < 8; disk++) + if (meta->disks[disk]) + count++; + raid->total_disks = count; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = raid->total_sectors / (63 * 255); + + for (disk = 0; disk < 8; disk++) { + if ((meta->disks[disk] == meta->disk_id) && + ((disk << 2) == meta->disk_index)) { + raid->disks[disk].dev = parent; + 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; + retval = 1; + break; + } + } + break; + } + +via_out: + free(meta, M_AR); + return retval; +} + static struct ata_request * ata_raid_init_request(struct ar_softc *rdp, struct bio *bio) { @@ -3019,6 +3150,7 @@ ata_raid_format(struct ar_softc *rdp) case AR_F_LSIV3_RAID: return "LSILogic v3 MegaRAID"; case AR_F_PROMISE_RAID: return "Promise Fasttrak"; case AR_F_SII_RAID: return "Silicon Image Medley"; + case AR_F_VIA_RAID: return "VIA Tech"; default: return "UNKNOWN"; } } @@ -3603,3 +3735,40 @@ ata_raid_sii_print_meta(struct sii_raid_conf *meta) printf("checksum_1 0x%04x\n", meta->checksum_1); printf("=================================================\n"); } + +static char * +ata_raid_via_type(int type) +{ + static char buffer[16]; + + switch (type) { + case VIA_T_RAID0: return "RAID0"; + case VIA_T_RAID1: return "RAID1"; + case VIA_T_SPAN: return "SPAN"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_via_print_meta(struct via_raid_conf *meta) +{ + int i; + + printf("*************** ATA VIA Metadata ****************\n"); + printf("magic 0x%02x\n", meta->magic); + printf("dummy_0 0x%02x\n", meta->dummy_0); + printf("type %s\n", ata_raid_via_type(meta->type)); + printf("disk_index 0x%02x\n", meta->disk_index); + printf("stripe_disks %d\n", meta->stripe_layout & VIA_L_MASK); + printf("stripe_sectors %d\n", (meta->stripe_layout >> VIA_L_SHIFT)); + printf("total_sectors %llu\n", meta->total_sectors); + printf("disk_id 0x%08x\n", meta->disk_id); + printf("DISK# disk_id\n"); + for (i = 0; i < 8; i++) { + if (meta->disks[i]) + printf(" %d 0x%08x\n", i, meta->disks[i]); + } + printf("checksum 0x%02x\n", meta->checksum); + printf("=================================================\n"); +} diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 31c785d9d9e8..1cba20356da2 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -72,7 +72,8 @@ struct ar_softc { #define AR_F_LSIV3_RAID 0x0080 #define AR_F_PROMISE_RAID 0x0100 #define AR_F_SII_RAID 0x0200 -#define AR_F_FORMAT_MASK 0x03ff +#define AR_F_VIA_RAID 0x0400 +#define AR_F_FORMAT_MASK 0x07ff u_int generation; /* generation of this array */ u_int64_t total_sectors; @@ -108,7 +109,7 @@ struct ar_softc { /* note all entries are big endian */ struct adaptec_raid_conf { - u_int32_t magic_0; /* 0x0000 */ + u_int32_t magic_0; #define ADP_MAGIC_0 0xc4650790 u_int32_t generation; @@ -116,13 +117,13 @@ struct adaptec_raid_conf { u_int16_t total_configs; u_int16_t dummy_1; u_int16_t checksum; - u_int32_t dummy_2; /* 0x0010 */ + u_int32_t dummy_2; u_int32_t dummy_3; u_int32_t flags; u_int32_t timestamp; - u_int32_t dummy_4[4]; /* 0x0020 */ - u_int32_t dummy_5[4]; /* 0x0030 */ - struct { /* 0x0040 */ + u_int32_t dummy_4[4]; + u_int32_t dummy_5[4]; + struct { u_int16_t total_disks; u_int16_t generation; u_int32_t magic_0; @@ -146,9 +147,8 @@ struct adaptec_raid_conf { u_int32_t dummy_8[4]; u_int8_t name[16]; - } configs[127]; /* x 0x40 bytes */ - - u_int32_t dummy_6[13]; /* 0x2000 */ + } configs[127]; + u_int32_t dummy_6[13]; u_int32_t magic_1; #define ADP_MAGIC_1 0x9ff85009 u_int32_t dummy_7[3]; @@ -283,7 +283,7 @@ struct hptv3_raid_conf { struct intel_raid_conf { u_int8_t intel_id[24]; -#define INTEL_MAGIC "Intel Raid ISM Cfg Sig. " +#define INTEL_MAGIC "Intel Raid ISM Cfg Sig. " u_int8_t version[6]; u_int8_t dummy_0[2]; @@ -344,12 +344,12 @@ struct intel_raid_mapping { struct ite_raid_conf { u_int32_t filler_1[5]; - u_int8_t timestamp_0[8]; /* BCD coded y:Y:M:D:m:h:f:s */ + u_int8_t timestamp_0[8]; u_int32_t dummy_1; u_int32_t filler_2[5]; u_int16_t filler_3; - u_int8_t ite_id[40]; /* byte swapped */ -#define ITE_MAGIC "Integrated Technology Express Inc " + u_int8_t ite_id[40]; +#define ITE_MAGIC "Integrated Technology Express Inc " u_int16_t filler_4; u_int32_t filler_5[6]; @@ -361,7 +361,7 @@ struct ite_raid_conf { u_int64_t total_sectors __packed; u_int32_t filler_8[12]; - u_int16_t filler_9; /* 0x100 */ + u_int16_t filler_9; u_int8_t type; #define ITE_T_RAID0 0x00 #define ITE_T_RAID1 0x01 @@ -374,8 +374,8 @@ struct ite_raid_conf { u_int8_t filler_11[3]; u_int32_t filler_12[54]; - u_int32_t dummy_6[4]; /* 0x200 */ - u_int8_t timestamp_1[8]; /* same as timestamp_0 */ + u_int32_t dummy_6[4]; + u_int8_t timestamp_1[8]; u_int32_t filler_13[9]; u_int8_t stripe_sectors; u_int8_t filler_14[3]; @@ -397,7 +397,7 @@ struct ite_raid_conf { struct lsiv2_raid_conf { u_int8_t lsi_id[6]; -#define LSIV2_MAGIC "$XIDE$" +#define LSIV2_MAGIC "$XIDE$" u_int8_t dummy_0; u_int8_t flags; @@ -470,7 +470,7 @@ struct lsiv3_raid_conf { u_int8_t checksum_0; u_int8_t filler_5[512*2]; u_int8_t lsi_id[6]; -#define LSIV3_MAGIC "$_IDE$" +#define LSIV3_MAGIC "$_IDE$" u_int16_t dummy_2; /* 0x33de for OK disk */ u_int16_t version; /* 0x0131 for this version */ @@ -523,18 +523,15 @@ struct lsiv3_raid_conf { /* Promise FastTrak Metadata */ #define PR_LBA(dev) \ (((struct ad_softc *)device_get_ivars(dev))->total_secs - 63) -#if 0 - (((((struct ad_softc *)device_get_ivars(dev))->total_secs / (((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors)) * ((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors) - ((struct ad_softc *)device_get_ivars(dev))->sectors) -#endif struct promise_raid_conf { char promise_id[24]; -#define PR_MAGIC "Promise Technology, Inc." +#define PR_MAGIC "Promise Technology, Inc." u_int32_t dummy_0; u_int64_t magic_0; -#define PR_MAGIC0(x) (((u_int64_t)(x.channel) << 48) | \ - ((u_int64_t)(x.device != 0) << 56)) +#define PR_MAGIC0(x) (((u_int64_t)(x.channel) << 48) | \ + ((u_int64_t)(x.device != 0) << 56)) u_int16_t magic_1; u_int32_t magic_2; u_int8_t filler1[470]; @@ -612,7 +609,7 @@ struct sii_raid_conf { u_int32_t controller_pci_id; u_int16_t version_minor; u_int16_t version_major; - u_int8_t timestamp[6]; /* BCD coded s:m:h:D:M:Y */ + u_int8_t timestamp[6]; u_int16_t stripe_sectors; u_int16_t dummy_2; u_int8_t disk_number; @@ -638,5 +635,32 @@ struct sii_raid_conf { u_int8_t name[16]; u_int16_t checksum_0; int8_t filler1[190]; - u_int16_t checksum_1; /* sum of all 128 shorts == 0 */ + u_int16_t checksum_1; +} __packed; + + +/* VIA Tech Metadata */ +#define VIA_LBA(dev) \ + ( ((struct ad_softc *)device_get_ivars(dev))->total_secs - 1) + +struct via_raid_conf { + u_int16_t magic; +#define VIA_MAGIC 0xaa55 + + u_int8_t dummy_0; + u_int8_t type; +#define VIA_T_RAID0 0x04 +#define VIA_T_RAID1 0x0c +#define VIA_T_SPAN 0x44 + + u_int8_t disk_index; + u_int8_t stripe_layout; +#define VIA_L_MASK 0x07 +#define VIA_L_SHIFT 4 + + u_int64_t total_sectors; + u_int32_t disk_id; + u_int32_t disks[8]; + u_int8_t checksum; + u_int8_t filler_1[461]; } __packed;