From b0366b2ebd2ec8e1cc955f82b204828ac4c96aed Mon Sep 17 00:00:00 2001 From: briggs Date: Mon, 20 Jun 2005 02:11:57 +0000 Subject: [PATCH] Basic support for RAID0 and RAID1 for the Adaptec HostRAID format as found on the Intel 6300ESB on-board RAID. Adapted from FreeBSD. --- sys/dev/ata/ata_raid.c | 6 +- sys/dev/ata/ata_raid_adaptec.c | 187 +++++++++++++++++++++++++++++++++ sys/dev/ata/ata_raidreg.h | 62 ++++++++++- sys/dev/ata/ata_raidvar.h | 8 +- sys/dev/ata/files.ata | 3 +- 5 files changed, 260 insertions(+), 6 deletions(-) create mode 100644 sys/dev/ata/ata_raid_adaptec.c diff --git a/sys/dev/ata/ata_raid.c b/sys/dev/ata/ata_raid.c index 7acd9bec6c7c..0d1f66326137 100644 --- a/sys/dev/ata/ata_raid.c +++ b/sys/dev/ata/ata_raid.c @@ -1,4 +1,4 @@ -/* $NetBSD: ata_raid.c,v 1.12 2005/05/29 22:11:28 christos Exp $ */ +/* $NetBSD: ata_raid.c,v 1.13 2005/06/20 02:11:57 briggs Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ata_raid.c,v 1.12 2005/05/29 22:11:28 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata_raid.c,v 1.13 2005/06/20 02:11:57 briggs Exp $"); #include #include @@ -259,6 +259,8 @@ ata_raid_check_component(struct device *self) { struct wd_softc *sc = (void *) self; + if (ata_raid_read_config_adaptec(sc) == 0) + return; if (ata_raid_read_config_promise(sc) == 0) return; } diff --git a/sys/dev/ata/ata_raid_adaptec.c b/sys/dev/ata/ata_raid_adaptec.c new file mode 100644 index 000000000000..487af18bee21 --- /dev/null +++ b/sys/dev/ata/ata_raid_adaptec.c @@ -0,0 +1,187 @@ +/* $NetBSD: ata_raid_adaptec.c,v 1.1 2005/06/20 02:11:57 briggs Exp $ */ + +/*- + * Copyright (c) 2000,2001,2002 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. + */ + +/* + * Support for parsing Adaptec ATA RAID controller configuration blocks. + * + * Adapted to NetBSD by Allen K. Briggs + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ata_raid_adaptec.c,v 1.1 2005/06/20 02:11:57 briggs Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#ifdef ATA_RAID_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) /* nothing */ +#endif + +int +ata_raid_read_config_adaptec(struct wd_softc *sc) +{ + struct adaptec_raid_conf *info; + struct atabus_softc *atabus; + struct vnode *vp; + int bmajor, error; + dev_t dev; + uint32_t gen, drive; + struct ataraid_array_info *aai; + struct ataraid_disk_info *adi; + + info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); + + bmajor = devsw_name2blk(sc->sc_dev.dv_xname, NULL, 0); + + /* Get a vnode for the raw partition of this disk. */ + dev = MAKEDISKDEV(bmajor, sc->sc_dev.dv_unit, RAW_PART); + error = bdevvp(dev, &vp); + if (error) + goto out; + + error = VOP_OPEN(vp, FREAD, NOCRED, 0); + if (error) { + vput(vp); + goto out; + } + + error = ata_raid_config_block_rw(vp, ADP_LBA(sc), info, + sizeof(*info), B_READ); + vput(vp); + if (error) { + printf("%s: error %d reading Adaptec config block\n", + sc->sc_dev.dv_xname, error); + goto out; + } + + info->magic_0 = be32toh(info->magic_0); + info->magic_1 = be32toh(info->magic_1); + info->magic_2 = be32toh(info->magic_2); + info->magic_3 = be32toh(info->magic_3); + info->magic_4 = be32toh(info->magic_4); + /* Check the signature. */ + if (info->magic_0 != ADP_MAGIC_0 || info->magic_3 != ADP_MAGIC_3) { + DPRINTF(("%s: Adaptec signature check failed\n", + sc->sc_dev.dv_xname)); + error = ESRCH; + goto out; + } + + /* + * Lookup or allocate a new array info structure for + * this array. + */ + aai = ata_raid_get_array_info(ATA_RAID_TYPE_ADAPTEC, + be32toh(info->configs[0].disk_number)); + + gen = be32toh(info->generation); + + if (gen == 0 || gen > aai->aai_generation) { + aai->aai_generation = gen; + + aai->aai_status = AAI_S_READY; + + switch (info->configs[0].type) { + case ADP_T_RAID0: + aai->aai_level = AAI_L_RAID0; + aai->aai_interleave = + (be16toh(info->configs[0].stripe_sectors) >> 1); + aai->aai_width = be16toh(info->configs[0].total_disks); + break; + + case ADP_T_RAID1: + aai->aai_level = AAI_L_RAID1; + aai->aai_interleave = 0; + aai->aai_width = be16toh(info->configs[0].total_disks) + / 2; + break; + + default: + aprint_error("%s: unknown Adaptec RAID type 0x%02x\n", + sc->sc_dev.dv_xname, info->configs[0].type); + error = EINVAL; + goto out; + } + + aai->aai_type = ATA_RAID_TYPE_ADAPTEC; + aai->aai_ndisks = be16toh(info->configs[0].total_disks); + aai->aai_capacity = be32toh(info->configs[0].sectors); + aai->aai_heads = 255; + aai->aai_sectors = 63; + aai->aai_cylinders = aai->aai_capacity / (63 * 255); + aai->aai_offset = 0; + aai->aai_reserved = 17; + + /* XXX - bogus. RAID1 shouldn't really have an interleave */ + if (aai->aai_interleave == 0) + aai->aai_interleave = aai->aai_capacity; + } + + atabus = (struct atabus_softc *) sc->sc_dev.dv_parent; + drive = atabus->sc_chan->ch_channel; + if (drive >= aai->aai_ndisks) { + aprint_error("%s: drive number %d doesn't make sense within " + "%d-disk array\n", + sc->sc_dev.dv_xname, drive, aai->aai_ndisks); + error = EINVAL; + goto out; + } + + adi = &aai->aai_disks[drive]; + adi->adi_dev = &sc->sc_dev; + adi->adi_status = ADI_S_ONLINE | ADI_S_ASSIGNED; + adi->adi_sectors = aai->aai_capacity; + adi->adi_compsize = be32toh(info->configs[drive+1].sectors); + + error = 0; + + out: + free(info, M_DEVBUF); + return (error); +} diff --git a/sys/dev/ata/ata_raidreg.h b/sys/dev/ata/ata_raidreg.h index e931417f8840..5466529447ea 100644 --- a/sys/dev/ata/ata_raidreg.h +++ b/sys/dev/ata/ata_raidreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: ata_raidreg.h,v 1.1 2003/01/27 18:21:28 thorpej Exp $ */ +/* $NetBSD: ata_raidreg.h,v 1.2 2005/06/20 02:11:57 briggs Exp $ */ /*- * Copyright (c) 2000,2001,2002 Søren Schmidt @@ -110,4 +110,64 @@ struct promise_raid_conf { uint32_t checksum; } __attribute__((__packed__)); +/* + * Macro to compute the LBA of the Adaptec HostRAID configuration structure, + * using the disk's softc structure. + */ +#define ADP_LBA(wd) \ + ((wd)->sc_capacity - 17) + +struct adaptec_raid_conf { + uint32_t magic_0; +#define ADP_MAGIC_0 0x900765c4 + + uint32_t generation; + uint16_t dummy_0; + uint16_t total_configs; + uint16_t dummy_1; + uint16_t checksum; + uint32_t dummy_2; + uint32_t dummy_3; + uint32_t flags; + uint32_t timestamp; + uint32_t dummy_4[4]; + uint32_t dummy_5[4]; + struct { + uint16_t total_disks; + uint16_t generation; + uint32_t magic_0; + uint8_t dummy_0; + uint8_t type; +#define ADP_T_RAID0 0x00 +#define ADP_T_RAID1 0x01 + uint8_t dummy_1; + uint8_t flags; + + uint8_t dummy_2; + uint8_t dummy_3; + uint8_t dummy_4; + uint8_t dummy_5; + + uint32_t disk_number; + uint32_t dummy_6; + uint32_t sectors; + uint16_t stripe_sectors; + uint16_t dummy_7; + + uint32_t dummy_8[4]; + uint8_t name[16]; + } configs[127]; + uint32_t dummy_6[13]; + uint32_t magic_1; +#define ADP_MAGIC_1 0x0950f89f + uint32_t dummy_7[3]; + uint32_t magic_2; + uint32_t dummy_8[46]; + uint32_t magic_3; +#define ADP_MAGIC_3 0x4450544d + uint32_t magic_4; +#define ADP_MAGIC_4 0x0950f89f + uint32_t dummy_9[62]; +} __attribute__((__packed__)); + #endif /* _DEV_PCI_PCIIDE_PROMISE_RAID_H_ */ diff --git a/sys/dev/ata/ata_raidvar.h b/sys/dev/ata/ata_raidvar.h index fe490fedc01d..615fb50eeee7 100644 --- a/sys/dev/ata/ata_raidvar.h +++ b/sys/dev/ata/ata_raidvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: ata_raidvar.h,v 1.1 2003/01/27 18:21:28 thorpej Exp $ */ +/* $NetBSD: ata_raidvar.h,v 1.2 2005/06/20 02:11:57 briggs Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -46,7 +46,8 @@ * sorted. */ #define ATA_RAID_TYPE_PROMISE 0 -#define ATA_RAID_TYPE_MAX 0 +#define ATA_RAID_TYPE_ADAPTEC 1 +#define ATA_RAID_TYPE_MAX 1 /* * Max # of disks supported by a single array. This is limited by @@ -118,4 +119,7 @@ int ata_raid_config_block_rw(struct vnode *, daddr_t, void *, /* Promise RAID support */ int ata_raid_read_config_promise(struct wd_softc *); +/* Adaptec HostRAID support */ +int ata_raid_read_config_adaptec(struct wd_softc *); + #endif /* _DEV_ATA_ATA_RAIDVAR_H_ */ diff --git a/sys/dev/ata/files.ata b/sys/dev/ata/files.ata index 6fc191731dae..806fef5da6e3 100644 --- a/sys/dev/ata/files.ata +++ b/sys/dev/ata/files.ata @@ -1,4 +1,4 @@ -# $NetBSD: files.ata,v 1.11 2004/08/30 09:34:41 drochner Exp $ +# $NetBSD: files.ata,v 1.12 2005/06/20 02:11:57 briggs Exp $ # # Config file and device description for machine-independent devices # which attach to ATA busses. Included by ports that need it. Ports @@ -19,6 +19,7 @@ file dev/ata/ata.c (ata_hl | atapi) & atabus defpseudo ataraid {[vendtype = -1], [unit = -1]} file dev/ata/ata_raid.c ataraid needs-flag file dev/ata/ata_raid_promise.c ataraid +file dev/ata/ata_raid_adaptec.c ataraid attach ld at ataraid with ld_ataraid file dev/ata/ld_ataraid.c ld_ataraid