From owner-freebsd-current@FreeBSD.ORG Tue Sep 21 08:30:41 2004 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B9DE416A4CE for ; Tue, 21 Sep 2004 08:30:41 +0000 (GMT) Received: from nulis.lt (adsl-213-190-44-175.takas.lt [213.190.44.175]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3729643D49 for ; Tue, 21 Sep 2004 08:30:39 +0000 (GMT) (envelope-from bob@nulis.lt) Received: from highland.tamsa ([10.0.1.1]) by nulis.lt with esmtp (Exim 4.34) id 1C9g1c-0004oR-Bo; Tue, 21 Sep 2004 11:29:24 +0300 Message-ID: <414FE6AD.50402@nulis.lt> Date: Tue, 21 Sep 2004 11:30:37 +0300 From: Saulius Menkevicius User-Agent: Mozilla Thunderbird 0.7.3 (X11/20040907) X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-current@freebsd.org References: <414EDFC7.2020104@mikulas.com> <20040920185935.GA9191@dragon.nuxi.com> In-Reply-To: <20040920185935.GA9191@dragon.nuxi.com> Content-Type: multipart/mixed; boundary="------------050801000401060203080200" cc: Jiri Mikulas Subject: Re: Sil 3114 SATA RAID X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Sep 2004 08:30:41 -0000 This is a multi-part message in MIME format. --------------050801000401060203080200 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit David O'Brien wrote: >On Mon, Sep 20, 2004 at 03:48:55PM +0200, Jiri Mikulas wrote: > > >>Hello >> >> > >Hello, please don't cross-post. It is appropiate to only pick one to >email this to. > > > >>I have Epox *EP-8HDA3+* motherboard >> >> >... > > >>atapci0: port >> >> >.. > > >>Is it known bug, or anything else (my fault)? >> >> > >The FreeBSD ATA-RAID driver does not reconize a raid created in the >SiI3114 BIOS either, so it is known there is a new RAID meta data format. >I've sent a copy of my RAID1 meta data to SOS to take a look at. > > > BTW I have a patch for ata-raid.[c|h] to support the intel ICH5 raid metadata format too. It was written by Doug Abrisko and I adopted to -current. Any chance to take it in? --------------050801000401060203080200 Content-Type: text/plain; name="intel-raid-patch-releng5" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="intel-raid-patch-releng5" diff -Nru /usr/src/sys/dev/ata/ata-raid.c src/sys/dev/ata/ata-raid.c --- /usr/src/sys/dev/ata/ata-raid.c Mon Aug 9 17:22:58 2004 +++ src/sys/dev/ata/ata-raid.c Fri Aug 27 21:58:46 2004 @@ -71,6 +71,8 @@ static int ar_lsi_write_conf(struct ar_softc *); static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int); static int ar_promise_write_conf(struct ar_softc *); +static int ar_intel_read_conf(struct ad_softc *, struct ar_softc **); +static int ar_intel_write_conf(struct ar_softc *); static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int); static struct ata_device *ar_locate_disk(int); static void ar_print_conf(struct ar_softc *); @@ -126,6 +128,9 @@ case ATA_SILICON_IMAGE_ID: return (ar_lsi_read_conf(adp, ar_table)); + case ATA_INTEL_ID: + return (ar_intel_read_conf(adp, ar_table)); + default: return (ar_promise_read_conf(adp, ar_table, 1)); } @@ -336,6 +341,12 @@ AD_SOFTC(rdp->disks[disk])->total_secs - 4208; /* SOS */ break; + case ATA_INTEL_ID: + ctlr |= AR_F_INTEL_RAID; + rdp->disks[disk].disk_sectors = + I_LBA(AD_SOFTC(rdp->disks[disk])) - 430; /* SOS */ + break; + default: ctlr |= AR_F_FREEBSD_RAID; /* FALLTHROUGH */ @@ -348,11 +359,14 @@ } if ((rdp->flags & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) && + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID + | AR_F_INTEL_RAID)) && (rdp->flags & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) != + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID + | AR_F_INTEL_RAID)) != (ctlr & - (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID))) { + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID + | AR_F_INTEL_RAID))) { free(rdp, M_AR); return EXDEV; } @@ -417,6 +431,8 @@ rdp->interleave = min(max(2, 1 << bit), 4096); if (rdp->flags & AR_F_PROMISE_RAID) rdp->interleave = min(max(2, 1 << bit), 2048); + if (rdp->flags & AR_F_INTEL_RAID) + rdp->interleave = min(max(2, 1 << bit), 256); } rdp->total_disks = total_disks; rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1); @@ -432,6 +448,11 @@ rdp->offset = HPT_LBA + 1; rdp->reserved = HPT_LBA + 1; } + if (rdp->flags & AR_F_INTEL_RAID) { + rdp->offset = 0; + rdp->reserved = 63; + rdp->total_sectors = (rdp->total_sectors / 512) * 512; + } rdp->lock_start = rdp->lock_end = 0xffffffff; rdp->flags |= AR_F_READY; @@ -479,6 +500,8 @@ ar_lsi_write_conf(rdp); if (rdp->flags & AR_F_PROMISE_RAID) ar_promise_write_conf(rdp); + if (rdp->flags & AR_F_INTEL_RAID) + ar_intel_write_conf(rdp); disk_destroy(rdp->disk); free(rdp, M_AR); @@ -1005,6 +1028,8 @@ ar_lsi_write_conf(rdp); if (rdp->flags & AR_F_PROMISE_RAID) ar_promise_write_conf(rdp); + if (rdp->flags & AR_F_INTEL_RAID) + ar_intel_write_conf(rdp); } } @@ -1156,7 +1181,7 @@ } } raid = raidp[array]; - if (raid->flags & (AR_F_PROMISE_RAID | AR_F_LSI_RAID)) + if (raid->flags & (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_INTEL_RAID)) continue; switch (info->type) { @@ -1386,7 +1411,8 @@ } raid = raidp[array + info->raid_number]; - if (raid->flags & (AR_F_PROMISE_RAID | AR_F_HIGHPOINT_RAID)) + if (raid->flags & (AR_F_PROMISE_RAID | AR_F_HIGHPOINT_RAID + | AR_F_INTEL_RAID)) continue; if (raid->magic_0 && @@ -1622,7 +1648,7 @@ } } raid = raidp[array]; - if (raid->flags & (AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) + if (raid->flags & (AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID | AR_F_INTEL_RAID)) continue; magic = (pci_get_device(device_get_parent( @@ -1860,6 +1886,405 @@ return 0; } +static int +ar_intel_read_conf(struct ad_softc *adp, struct ar_softc **raidp) +{ + struct intel_raid_conf *info; + struct intel_raid_config *config; + struct ar_softc *raid = NULL; + int array, disk = 0, retval = 0, size = 1024, i, matched = -1; + u_int32_t count, cksum, cksum_orig, *ckptr; + + if (!(info = (struct intel_raid_conf *) + malloc(size, M_AR, M_NOWAIT | M_ZERO))) + return retval; + + if (ar_rw(adp, I_LBA(adp), size, + (caddr_t)info, AR_READ | AR_WAIT)) { + if (bootverbose) + printf("ar: Intel read conf failed\n"); + goto intel_out; + } + + /* check if this is a Intel RAID struct */ + if (bcmp(info->intel_id, I_MAGIC, sizeof(I_MAGIC) - 1)) { + if (bootverbose) + printf("ar: Intel check1 failed\n"); + goto intel_out; + } + +#if 0 + printf("%s\n", info->intel_id); + printf("checksum %d\n",info->checksum); +#endif + + ckptr = (void *)info; + cksum_orig = info->checksum; + info->checksum = 0; + for (cksum = 0, count = 0; count < info->disk_struct_size / 4; count++) + cksum += *ckptr++; + +#if 0 + printf("calculated checksum %d\n",cksum); +#endif + + if (cksum != cksum_orig) { + if (bootverbose) + printf("ar: Intel checksum failed\n"); + goto intel_out; + } + +#if 0 + printf("disk_struct_size %d\n",info->disk_struct_size); + printf("id %d\n",info->id); + printf("generation %d\n",info->generation); + printf("reserved[0] %d\n",info->reserved[0]); + printf("reserved[1] %d\n",info->reserved[1]); + printf("total_disks %d\n",info->total_disks); + printf("bootable %d\n",info->bootable); +#endif + + for (i=0; i < info->total_disks; i++) { +#if 0 + printf("serial %s\n",info->disk[i].serial); + printf("total_sectors %d\n",info->disk[i].total_sectors); + printf("unit_id %d\n",info->disk[i].unit_id); + printf("status %d\n",info->disk[i].status); +#endif + if (strncmp(info->disk[i].serial, adp->device->param->serial, + sizeof(adp->device->param->serial)) == 0) { + matched = i; + } + } + + config = (struct intel_raid_config*)&info->disk[info->total_disks]; +#if 0 + printf("volume serial %s\n", config->serial); + printf("volume total_sectors_low %d\n", config->total_sectors_low); + printf("volume total_sectors_high %d\n", config->total_sectors_high); + printf("volume status %d\n", config->status); + printf("volume migrating %d\n", config->volume.migrating); + printf("volume state %d\n", config->volume.state); + printf("volume dirty %d\n", config->volume.dirty); + + printf("map start %d\n", config->map.start); + printf("map total_sectors %d\n", config->map.total_sectors); + printf("map stripes %d\n", config->map.stripes); + printf("map interleave %d\n", config->map.interleave); + printf("map state %d\n", config->map.state); + printf("map type %d\n", config->map.type); + printf("map total_disks %d\n", config->map.total_disks); + for(i=0; i < config->map.total_disks; i++){ + printf("Disk %d %d\n", i, config->map.disk_order[i]); + } +#endif + + if (matched == -1) { + if (bootverbose) + printf("ar: Intel couldn't match drive to config\n"); + goto intel_out; + } + + 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]) { + printf("ar%d: failed to allocate raid config storage\n", array); + goto intel_out; + raid->flags |= AR_F_DEGRADED; + } + } + raid = raidp[array]; + if (raid->flags & (AR_F_HIGHPOINT_RAID | AR_F_PROMISE_RAID + | AR_F_LSI_RAID)) + continue; + if ((raid->flags & AR_F_INTEL_RAID) && raid->magic_0 != info->id) + continue; + + raid->magic_0 = info->id; + +/*printf("HELLO gen %d %d\n",info->generation, raid->generation); */ + + if (!info->generation || info->generation > raid->generation) { + raid->generation = info->generation; + raid->flags = AR_F_INTEL_RAID; + raid->lun = array; +#if 0 + switch (config->volume.state) { +#if 0 + case I_VOLUME_DISABLED: + raid->flags |= AR_F_DEGRADED; + break; + case I_VOLUME_DEGRADED: + raid->flags |= AR_F_DEGRADED; + break; + case I_VOLUME_FAILED: + raid->flags |= AR_F_DEGRADED; + break; +#endif + default: + /* printf("Unknown Intel Volume state %x\n", config->volume.state); */ + } +#endif + + switch (config->map.state) { + case I_MAP_OKAY: + raid->flags |= AR_F_READY; + break; + case I_MAP_DEGRADED: + raid->flags |= AR_F_DEGRADED; + case I_MAP_FAILED: + raid->flags |= AR_F_DEGRADED; + i = config->map.filler1[1]; + if (i == 0xff) { + printf("INTEL BOGUS drive failed\n"); + } else { + if (raid->disks[i].flags & AR_DF_ONLINE) { + raid->disks[i].flags &= ~AR_DF_ONLINE; + } + raid->disks[i].flags |= AR_DF_SPARE; + } + break; + default: + printf("Unkown Intel Map state %x\n", config->map.state); + } + + switch (config->map.type) { + case I_MAP_RAID0: + raid->flags |= AR_F_RAID0; + break; + + case I_MAP_RAID1: + raid->flags |= AR_F_RAID1; + break; + + default: + printf("ar%d: Intel unknown RAID type 0x%02x\n", array, + config->map.type); + goto intel_out; + } + raid->width = config->map.total_disks + / ((raid->flags & AR_F_RAID1) ? 2 : 1); + raid->interleave = config->map.interleave; + raid->total_disks = config->map.total_disks; + + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = config->total_sectors_low / (63 * 255); + raid->total_sectors = config->total_sectors_low; + raid->offset = 0; + raid->reserved = 63; + raid->lock_start = raid->lock_end = 0; + + for (disk = 0; disk < config->map.total_disks; disk++) { + if (info->disk[disk].status & I_DISK_SPARE) { + raid->disks[disk].flags |= AR_DF_SPARE; + } + if (info->disk[disk].status & I_DISK_CONFIGURED) { + raid->disks[disk].flags |= AR_DF_ASSIGNED; /*normally set*/ + } + if (info->disk[disk].status & I_DISK_FAILED) { + raid->disks[disk].flags |= AR_DF_SPARE; + } + if (info->disk[disk].status & I_DISK_USABLE) { + if (!(raid->disks[disk].flags & AR_DF_SPARE)) { + raid->disks[disk].flags |= AR_DF_ONLINE; /* normally set */ + } + } + } + } + + if (info->generation == raid->generation + && !raid->disks[matched].device) { + disk = matched; + raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE); + raid->disks[disk].device = adp->device; + raid->disks[disk].disk_sectors = + info->disk[disk].total_sectors; + AD_SOFTC(raid->disks[disk])->flags |= AD_F_RAID_SUBDISK; + } + if (info->generation < raid->generation) { +/*printf("HELLO Generation was old\n"); */ + disk = matched; + raid->disks[disk].flags = AR_DF_PRESENT | AR_DF_SPARE; + raid->disks[disk].device = adp->device; + raid->disks[disk].disk_sectors = + info->disk[disk].total_sectors; + AD_SOFTC(raid->disks[disk])->flags |= AD_F_RAID_SUBDISK; + } + + for (count = 0, disk = 0; disk < config->map.total_disks; disk++) { + if (raid->disks[disk].device) + count++; + } + +#define GEN_MARGIN 15 +#define GEN_MAX 0x80000000 +#define GEN_OVERFLOW(x) ((x + GEN_MARGIN < 0)) + + if (count == raid->total_disks + && GEN_OVERFLOW(raid->generation)) + ar_intel_write_conf(raid); + if (count == raid->total_disks && (raid->flags & AR_F_DEGRADED)) + ata_raid_rebuild(array); + + break; + } + +intel_out: + free(info, M_AR); + + return retval; +} + +static int +ar_intel_write_conf(struct ar_softc *raid) +{ + struct intel_raid_conf *info; + struct intel_raid_config *config; + struct timeval timestamp; + u_int32_t cksum, *ckptr; + int count, disk, i; + + raid->generation++; + if (GEN_OVERFLOW(raid->generation)) /* give us some margin */ + raid->generation = 1; /* roll generation */ + microtime(×tamp); + + for (disk = 0; disk < raid->total_disks; disk++) { + if (!(info = (struct intel_raid_conf *) + malloc(1024, M_AR, M_NOWAIT))) { + printf("ar%d: Intel allocating conf failed\n", + raid->lun); + return -1; + } + bzero(info, 1024); + + /* need to build critical parts of structure */ + info->total_disks = raid->total_disks; + config = (struct intel_raid_config*)&info->disk[info->total_disks]; + if (raid->flags & AR_F_RAID0) + config->map.type = I_MAP_RAID0; + if (raid->flags & AR_F_RAID1) + config->map.type = I_MAP_RAID1; + + /* start to fill in */ + snprintf(info->intel_id, sizeof(info->intel_id), "%s 1.%d.00", + I_MAGIC, config->map.type); + info->checksum = 0; /* last */ + info->disk_struct_size = 480; /* Seems to be constant */ + if (!raid->magic_0) { + raid->magic_0 = 0x8253823c; + } + info->id = raid->magic_0; + info->generation = raid->generation; + info->reserved[1] = 0xc0000000; /* Unknown */ + /* info->total_disks Already done above */ + info->bootable = 1; + + for (i = 0; i < info->total_disks; i++) { + if (raid->disks[i].device) { + bcopy(raid->disks[i].device->param->serial, + info->disk[i].serial, sizeof(info->disk[i].serial)); + info->disk[i].total_sectors + = AD_SOFTC(raid->disks[i])->total_secs; + info->disk[i].unit_id = i * 0x10000; + info->disk[i].status = 0x130; + if (raid->disks[i].flags & AR_DF_SPARE) { + info->disk[i].status |= I_DISK_SPARE; + } + if (raid->disks[i].flags & AR_DF_ASSIGNED) { + info->disk[i].status |= I_DISK_CONFIGURED; /* normally set */ + } + if ((raid->disks[i].flags & AR_DF_ONLINE) + && (raid->disks[i].flags & AR_DF_PRESENT)) { + info->disk[i].status |= I_DISK_USABLE; /* normally set */ + } + /* Other options + info->disk[i].status |= I_DISK_FAILED; + */ + } + } + + snprintf(config->serial, sizeof(config->serial), + "RAID_Volume%d", raid->lun + 1); + config->total_sectors_low = raid->total_sectors; + config->total_sectors_high = 0; + config->status = 0; + config->volume.migrating = 0; +#if 0 /* Not used */ + if (raid->flags & AR_F_DEGRADED) { + config->volume.state = I_VOLUME_DEGRADED; + } + /* Other options: + config->volume.state = I_VOLUME_DISABLED + config->volume.state = I_VOLUME_FAILED + */ +#endif + + config->volume.dirty = 0; /* not used yet */ + + config->map.start = 0; + config->map.state = 0; + if (raid->flags & AR_F_RAID0) { + config->map.total_sectors = raid->total_sectors / 2; + config->map.interleave = raid->interleave; + } + if (raid->flags & AR_F_RAID1) { + config->map.total_sectors = raid->total_sectors; + config->map.interleave = 256; /* DJA ??? */ + } + config->map.stripes = raid->total_sectors / 512; + if (raid->flags & AR_F_READY) { + config->map.state |= I_MAP_OKAY; + } + if (raid->flags & AR_F_DEGRADED) { + config->map.state |= I_MAP_DEGRADED; + } + if (raid->flags & AR_F_REBUILDING) { + config->map.state |= I_MAP_DEGRADED; + } + /* Other options are + config->map.state |= I_MAP_FAILED; + */ +/* config->map.type Already defined */ + config->map.total_disks = info->total_disks; + + config->map.filler1[0] = config->map.type + 1; /* ??? */ + + config->map.filler1[1] = 0xff; /* None failed */ + for (i = 0; i < raid->total_disks; i++) { + if (!(raid->disks[i].flags & AR_DF_ONLINE)) { + config->map.filler1[1] = i; + } + } + config->map.filler1[2] = 0x1; /* ??? */ + + for (i = 0; i < raid->total_disks; i++) + config->map.disk_order[i]=i; + + ckptr = (void *)info; + for (cksum = 0, count = 0; count < info->disk_struct_size / 4; count++) + cksum += *ckptr++; + info->checksum = cksum; /* last */ + + if (raid->disks[disk].device && + !(raid->disks[disk].device->flags & ATA_D_DETACHING)) { + if (ar_rw(AD_SOFTC(raid->disks[disk]), + I_LBA(AD_SOFTC(raid->disks[disk])), + 1024, + (caddr_t)info, AR_WRITE)) { + printf("ar%d: Intel write conf failed\n", + raid->lun); + return -1; + } + } + } + return 0; +} + static void ar_rw_done(struct bio *bp) { @@ -1930,7 +2355,7 @@ printf("magic_0 0x%08x\n", config->magic_0); printf("magic_1 0x%08x\n", config->magic_1); printf("flags 0x%02x %b\n", config->flags, config->flags, - "\20\16HIGHPOINT\15PROMISE\13REBUILDING\12DEGRADED\11READY\3SPAN\2RAID1\1RAID0\n"); + "\31\27QTEC\26INTEL\25LSI\24ADAPTEC\23HIGHPOINT\22PROMISE\21FREEBSD\14TOGGLE\13REBUILDING\12DEGRADED\11READY\5RAID5\4RAID3\3RAID1\2RAID0\1SPAN\n"); printf("total_disks %d\n", config->total_disks); printf("generation %d\n", config->generation); printf("width %d\n", config->width); diff -Nru /usr/src/sys/dev/ata/ata-raid.h src/sys/dev/ata/ata-raid.h --- /usr/src/sys/dev/ata/ata-raid.h Sat Jun 26 00:21:59 2004 +++ src/sys/dev/ata/ata-raid.h Fri Aug 27 21:58:46 2004 @@ -291,6 +291,72 @@ u_int32_t checksum; } __packed; +#define I_LBA(adp) (((adp->total_secs / 2) - 1) * 2) +#define I_MAGIC "Intel Raid ISM Cfg Sig." + +struct intel_raid_conf { + int8_t intel_id[32]; + u_int32_t checksum; + + u_int32_t disk_struct_size; + u_int32_t id; + u_int32_t generation; + u_int32_t reserved[2]; + u_int8_t total_disks; + u_int8_t bootable; + u_int8_t filler1[2]; + u_int32_t filler2[39]; + struct { + int8_t serial[16]; + u_int32_t total_sectors; + u_int32_t unit_id; + u_int32_t status; +#define I_DISK_SPARE 0x1 +#define I_DISK_CONFIGURED 0x2 +#define I_DISK_FAILED 0x4 +#define I_DISK_USABLE 0x8 + u_int32_t filler2[5]; + } disk[10]; +} __attribute__((packed)); + +/* RAID DEVICE CONFIGURATION INFO */ +struct intel_raid_config { + int8_t serial[16]; + u_int32_t total_sectors_low; + u_int32_t total_sectors_high; + u_int32_t status; + u_int32_t reserved; + u_int32_t filler[12]; + struct { + u_int32_t filler[2]; + u_int8_t migrating; + u_int8_t state; +/* ??? +#define I_VOLUME_OKAY 0x0 +*/ + u_int8_t dirty; + u_int8_t filler1[1]; + u_int32_t filler2[5]; + } volume; + struct { + u_int32_t start; + u_int32_t total_sectors; + u_int32_t stripes; + u_int16_t interleave; + u_int8_t state; +#define I_MAP_OKAY 0x0 +#define I_MAP_DEGRADED 0x2 +#define I_MAP_FAILED 0x3 + u_int8_t type; +#define I_MAP_RAID0 0 +#define I_MAP_RAID1 1 + u_int8_t total_disks; + u_int8_t filler1[3]; + u_int32_t filler2[7]; + u_int32_t disk_order[10]; + } map; +} __attribute__((packed)); + int ata_raiddisk_attach(struct ad_softc *); int ata_raiddisk_detach(struct ad_softc *); void ata_raid_attach(void); --------------050801000401060203080200--