diff options
| author | tron <tron@NetBSD.org> | 2008-09-11 11:08:50 +0000 |
|---|---|---|
| committer | tron <tron@NetBSD.org> | 2008-09-11 11:08:50 +0000 |
| commit | 2b3ca19215621da75a014f8dcaafba2ce195e9bb (patch) | |
| tree | 5fd19cd81983148db5fa8afab5fe0e9d89ced5ab /sys/dev/ata/ata_raid_intel.c | |
| parent | 31cd18f961f163732167d5e3c9fa3153e3064fe7 (diff) | |
Add support for Intel MatrixRAID to ataraid(4). It is currently limited
to one volume.
The driver was provided by Juan RP in PR kern/39511.
Diffstat (limited to 'sys/dev/ata/ata_raid_intel.c')
| -rw-r--r-- | sys/dev/ata/ata_raid_intel.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/sys/dev/ata/ata_raid_intel.c b/sys/dev/ata/ata_raid_intel.c new file mode 100644 index 00000000000..2afc07869a1 --- /dev/null +++ b/sys/dev/ata/ata_raid_intel.c @@ -0,0 +1,281 @@ +/* $NetBSD: ata_raid_intel.c,v 1.1 2008/09/11 11:08:50 tron Exp $ */ + +/*- + * Copyright (c) 2000-2008 Søren Schmidt <sos@FreeBSD.org> + * 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. + * + * 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 Intel MatrixRAID controller configuration blocks. + * + * Adapted to NetBSD by Juan Romero Pardines (xtraeme@gmail.org). + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ata_raid_intel.c,v 1.1 2008/09/11 11:08:50 tron Exp $"); + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/bufq.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/fcntl.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/kauth.h> + +#include <miscfs/specfs/specdev.h> + +#include <dev/ata/atareg.h> +#include <dev/ata/atavar.h> +#include <dev/ata/wdvar.h> + +#include <dev/ata/ata_raidreg.h> +#include <dev/ata/ata_raidvar.h> + +#ifdef ATA_RAID_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) /* nothing */ +#endif + +#ifdef ATA_RAID_DEBUG +static const char * +ata_raid_intel_type(int type) +{ + static char buffer[16]; + + switch (type) { + case INTEL_T_RAID0: + return "RAID0"; + case INTEL_T_RAID1: + return "RAID1"; + case INTEL_T_RAID5: + return "RAID5"; + default: + sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static void +ata_raid_intel_print_info(struct intel_raid_conf *info) +{ + struct intel_raid_mapping *map; + int i, j; + + printf("********* ATA Intel MatrixRAID Metadata *********\n"); + printf("intel_id <%.24s>\n", info->intel_id); + printf("version <%.6s>\n", info->version); + printf("checksum 0x%08x\n", info->checksum); + printf("config_size 0x%08x\n", info->config_size); + printf("config_id 0x%08x\n", info->config_id); + printf("generation 0x%08x\n", info->generation); + printf("total_disks %u\n", info->total_disks); + printf("total_volumes %u\n", info->total_volumes); + printf("DISK# serial disk sectors disk_id flags\n"); + for (i = 0; i < info->total_disks; i++) { + printf(" %d <%.16s> %u 0x%08x 0x%08x\n", + i, info->disk[i].serial, info->disk[i].sectors, + info->disk[i].id, info->disk[i].flags); + } + + map = (struct intel_raid_mapping *)&info->disk[info->total_disks]; + for (j = 0; j < info->total_volumes; j++) { + printf("name %.16s\n", map->name); + printf("total_sectors %ju\n", map->total_sectors); + printf("state %u\n", map->state); + printf("reserved %u\n", map->reserved); + printf("offset %u\n", map->offset); + printf("disk_sectors %u\n", map->disk_sectors); + printf("stripe_count %u\n", map->stripe_count); + printf("stripe_sectors %u\n", map->stripe_sectors); + 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]); + + map = (struct intel_raid_mapping *) + &map->disk_idx[map->total_disks]; + } + printf("=================================================\n"); +} +#endif + +int +ata_raid_read_config_intel(struct wd_softc *sc) +{ + struct intel_raid_conf *info; + struct intel_raid_mapping *map; + struct ataraid_array_info *aai; + struct ataraid_disk_info *adi; + struct vnode *vp; + uint32_t checksum, *ptr; + static int curdrive; + int bmajor, count, error = 0; + char *tmp; + dev_t dev; + + info = malloc(1536, M_DEVBUF, M_WAITOK|M_ZERO); + + bmajor = devsw_name2blk(device_xname(sc->sc_dev), NULL, 0); + + /* Get a vnode for the raw partition of this disk. */ + dev = MAKEDISKDEV(bmajor, device_unit(sc->sc_dev), RAW_PART); + error = bdevvp(dev, &vp); + if (error) + goto out; + + error = VOP_OPEN(vp, FREAD, NOCRED); + if (error) { + vput(vp); + goto out; + } + + error = ata_raid_config_block_rw(vp, INTEL_LBA(sc), info, + 1024, B_READ); + VOP_CLOSE(vp, FREAD, NOCRED); + vput(vp); + if (error) { + DPRINTF(("%s: error %d reading Intel MatrixRAID config block\n", + device_xname(sc->sc_dev), error)); + goto out; + } + + tmp = (char *)info; + (void)memcpy(tmp + 1024, tmp, 512); + (void)memcpy(tmp, tmp + 512, 1024); + (void)memset(tmp + 1024, 0, 512); + + /* Check if this is a Intel RAID struct */ + if (strncmp(info->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) { + DPRINTF(("%s: Intel MatrixRAID signature check failed\n", + device_xname(sc->sc_dev))); + error = ESRCH; + goto out; + } + + /* calculate checksum and compare for valid */ + for (checksum = 0, ptr = (uint32_t *)info, count = 0; + count < (info->config_size / sizeof(uint32_t)); count++) + checksum += *ptr++; + + checksum -= info->checksum; + if (checksum != info->checksum) { + DPRINTF(("%s: Intel MatrixRAID checksum failed 0x%x != 0x%x\n", + device_xname(sc->sc_dev), checksum, info->checksum)); + error = ESRCH; + goto out; + } + +#ifdef ATA_RAID_DEBUG + ata_raid_intel_print_info(info); +#endif + + /* This one points to the first volume */ + map = (struct intel_raid_mapping *)&info->disk[info->total_disks]; + + /* + * Lookup or allocate a new array info structure for this array. + * + * TODO: + * We only look at the first volume. Need to solve a few issues before + * multiple volumes are working correctly. + */ + aai = ata_raid_get_array_info(ATA_RAID_TYPE_INTEL, 0); + + /* Fill in array info */ + aai->aai_generation = info->generation; + aai->aai_status = AAI_S_READY; + + switch (map->type) { + case INTEL_T_RAID0: + aai->aai_level = AAI_L_RAID0; + aai->aai_width = map->total_disks; + break; + case INTEL_T_RAID1: + aai->aai_level = AAI_L_RAID1; + aai->aai_width = 1; + break; + default: + DPRINTF(("%s: unknown Intel MatrixRAID type 0x%02x\n", + sc->sc_dev->dv_xname, map->type)); + error = EINVAL; + goto out; + } + + switch (map->state) { + case INTEL_S_DEGRADED: + aai->aai_status |= AAI_S_DEGRADED; + break; + case INTEL_S_DISABLED: + case INTEL_S_FAILURE: + aai->aai_status &= ~AAI_S_READY; + break; + } + + aai->aai_type = ATA_RAID_TYPE_INTEL; + aai->aai_capacity = map->total_sectors; + aai->aai_interleave = map->stripe_sectors; + aai->aai_ndisks = map->total_disks; + aai->aai_heads = 255; + aai->aai_sectors = 63; + aai->aai_cylinders = + aai->aai_capacity / (aai->aai_heads * aai->aai_sectors); + aai->aai_offset = map->offset; + aai->aai_reserved = 3; + + /* Fill in disk info */ + adi = &aai->aai_disks[curdrive]; + adi->adi_status = 0; + + if (info->disk[curdrive].flags & INTEL_F_ONLINE) + adi->adi_status |= ADI_S_ONLINE; + if (info->disk[curdrive].flags & INTEL_F_ASSIGNED) + adi->adi_status |= ADI_S_ASSIGNED; + if (info->disk[curdrive].flags & INTEL_F_SPARE) { + adi->adi_status &= ~ADI_S_ONLINE; + adi->adi_status |= ADI_S_SPARE; + } + if (info->disk[curdrive].flags & INTEL_F_DOWN) + adi->adi_status &= ~ADI_S_ONLINE; + + if (adi->adi_status) { + adi->adi_dev = sc->sc_dev; + adi->adi_sectors = info->disk[curdrive].sectors; + adi->adi_compsize = adi->adi_sectors - aai->aai_reserved; + curdrive++; + } + + out: + free(info, M_DEVBUF); + return error; +} |
