All, This is a revised patch to add HostRAID support to dmraid. It contains a reworked asr_group function that knows how to set up multilevel RAID 10, as well as the usual RAID0 / RAID1 cases. It has seen somewhat rigorous testing in RAID0/1/10 setups on a SCSI HostRAID x226 and very light testing on SATA HostRAID on the same machine. Last Friday I was able to convert a a320raid based SLES9 SP2 system to a dmraid setup, and verified that I could (with some difficulty) bring up the system. Note that spare drives, metadata writes and I/O error handling are still not implemented. Mr. Mauelshagen: Was it ok to add subordinate raid_sets to the master raid_set manually with list_add? As usual, I'm looking for any comments or suggestions about how to improve this code. This patch should not be used in a production system at all. --D
diff -Naur orig/lib/format/ataraid/asr.c v3-test/lib/format/ataraid/asr.c --- orig/lib/format/ataraid/asr.c 1969-12-31 16:00:00.000000000 -0800 +++ v3-test/lib/format/ataraid/asr.c 2006-01-10 16:13:40.000000000 -0800 @@ -0,0 +1,821 @@ +/* + * Adaptec HostRAID ASR format interpreter for dmraid. + * Copyright (C) 2005 IBM, All rights reserved. + * + * See file LICENSE at the top of this source tree for license information. + */ + +#include <errno.h> +#include <netinet/in.h> + +#define HANDLER "asr" + +#include "internal.h" +#define FORMAT_HANDLER +#include "asr.h" +#include <datastruct/byteorder.h> + +static const char *handler = HANDLER; + +/* Map ASR disk status to dmraid status */ +static enum status asr_disk_status(struct asr_raid_configline *disk) { + if (disk == NULL) + return s_undef; + + switch (disk->raidstate) { + case LSU_COMPONENT_STATE_OPTIMAL: + return s_ok; + case LSU_COMPONENT_STATE_DEGRADED: + case LSU_COMPONENT_STATE_FAILED: + return s_broken; + case LSU_COMPONENT_STATE_UNINITIALIZED: + case LSU_COMPONENT_STATE_UNCONFIGURED: + return s_inconsistent; + case LSU_COMPONENT_SUBSTATE_BUILDING: + case LSU_COMPONENT_SUBSTATE_REBUILDING: + case LSU_COMPONENT_STATE_REPLACED: + return s_nosync; + default: + return s_undef; + } +} + +/* Extract config line from metadata */ +static struct asr_raid_configline *asr_get_config(struct asr *asr, uint32_t magic) +{ + unsigned int i; + + for (i = 0; i < asr->rt.elmcnt; i++) { + if (asr->rt.ent[i].raidmagic == magic) + return &asr->rt.ent[i]; + } + + return NULL; +} + +/* Get this disk's configuration */ +static struct asr_raid_configline *asr_this_disk(struct asr *asr) { + return asr_get_config(asr, asr->rb.drivemagic); +} + +/* Make up RAID device name. */ +static size_t _name(struct lib_context *lc, struct asr *asr, char *str, + size_t len) +{ + struct asr_raid_configline *cl = asr_this_disk(asr); + if (cl == NULL) + LOG_ERR(lc, 0, "%s: Could not find device in config table!\n", + handler); + return snprintf(str, len, "asr_%s", cl->name); +} + +/* Figure out a name for the RAID device. */ +static char *asr_name(struct lib_context *lc, struct asr *asr) +{ + size_t len; + char *ret; + + if ((ret = dbg_malloc((len = _name(lc, asr, NULL, 0) + 1)))) { + _name(lc, asr, ret, len); + /* Why do we call mk_alpha? This makes labels like + * "OS-u320-15k" become "OS-udca-bek", which is confusing. + * mk_alpha(lc, ret + HANDLER_LEN, len - HANDLER_LEN); */ + } else + log_alloc_err(lc, handler); + + return ret; +} + +/* Mapping of template types to generic types */ +/* FIXME: This needs more examination. Does HostRAID do linear + * combination? The BIOS implies that it only does RAID 0, 1 and 10. + * The emd driver implied support for RAID3/4/5, but dm doesn't + * do any of those right now. + */ +static struct types types[] = { + { ASR_RAID0, t_raid0 }, + { ASR_RAID1, t_raid1 }, + { ASR_RAIDSPR, t_spare }, + { 0, t_undef} +}; + +/* Map the ASR raid type codes into dmraid type codes. */ +static enum type asr_type(struct asr_raid_configline *cl) +{ + return cl ? rd_type(types, (unsigned int)cl->raidtype) : t_undef; +} + +/* + * Read an ASR RAID device. Fields are big endian, so + * need to convert them if we're on a LE machine (i386, etc). + */ +#define ASR_BLOCK 1 +#define ASR_TABLE 2 +#define ASR_EXTTABLE 4 + +#if BYTE_ORDER == LITTLE_ENDIAN + +static void cvt_configline(struct asr_raid_configline *cline) +{ + cline->raidcnt = ntohs(cline->raidcnt); + cline->raidseq = ntohs(cline->raidseq); + cline->raidmagic = ntohl(cline->raidmagic); + cline->raidid = ntohl(cline->raidid); + cline->loffset = ntohl(cline->loffset); + cline->lcapcty = ntohl(cline->lcapcty); + cline->strpsize = ntohs(cline->strpsize); + cline->biosInfo = ntohs(cline->biosInfo); + cline->lsu = ntohl(cline->lsu); + cline->blockStorageTid = ntohs(cline->blockStorageTid); + cline->curAppBlock = ntohl(cline->curAppBlock); + cline->appBurstCount = ntohl(cline->appBurstCount); +} + +static void to_cpu(void *meta, unsigned int cvt) { + struct asr *asr = meta; + int i; + + if (cvt & ASR_BLOCK) { + asr->rb.b0idcode = ntohl(asr->rb.b0idcode); + asr->rb.biosInfo = ntohs(asr->rb.biosInfo); + asr->rb.fstrsvrb = ntohl(asr->rb.fstrsvrb); + asr->rb.svBlockStorageTid + = ntohs(asr->rb.svBlockStorageTid); + asr->rb.svtid = ntohs(asr->rb.svtid); + asr->rb.drivemagic = ntohl(asr->rb.drivemagic); + asr->rb.fwTestMagic = ntohl(asr->rb.fwTestMagic); + asr->rb.fwTestSeqNum = ntohl(asr->rb.fwTestSeqNum); + asr->rb.smagic = ntohl(asr->rb.smagic); + asr->rb.raidtbl = ntohl(asr->rb.raidtbl); + } + + if (cvt & ASR_TABLE) { + asr->rt.ridcode = ntohl(asr->rt.ridcode); + asr->rt.rversion = ntohl(asr->rt.rversion); + asr->rt.maxelm = ntohs(asr->rt.maxelm); + asr->rt.elmcnt = ntohs(asr->rt.elmcnt); + asr->rt.elmsize = ntohs(asr->rt.elmsize); + asr->rt.raidFlags = ntohl(asr->rt.raidFlags); + asr->rt.timestamp = ntohl(asr->rt.timestamp); + asr->rt.rchksum = ntohs(asr->rt.rchksum); + asr->rt.sparedrivemagic = ntohl(asr->rt.sparedrivemagic); + asr->rt.raidmagic = ntohl(asr->rt.raidmagic); + asr->rt.verifyDate = ntohl(asr->rt.verifyDate); + asr->rt.recreateDate = ntohl(asr->rt.recreateDate); + + /* Convert the first seven config lines */ + for (i = 0; i < (asr->rt.elmcnt < 7 ? asr->rt.elmcnt : 7); i++) { + cvt_configline(&asr->rt.ent[i]); + } + + } + + if (cvt & ASR_EXTTABLE) { + for (i = 7; i < asr->rt.elmcnt; i++) { + cvt_configline(&asr->rt.ent[i]); + } + } +} +#else +# define to_cpu(x, y) +#endif + +static int asr_read_extended(struct lib_context *lc, struct dev_info *di, + struct asr *asr) +{ + unsigned int remaining, i, checksum; + int j; + uint8_t *ptr; + + log_info(lc, "%s: reading extended data", di->path); + + /* Read the RAID table. */ + if (!read_file(lc, handler, di->path, &asr->rt, ASR_DISK_BLOCK_SIZE, + (uint64_t)asr->rb.raidtbl * ASR_DISK_BLOCK_SIZE)) + { + LOG_ERR(lc, 0, "%s: Could not read metadata.", handler); + } + + /* Convert it */ + to_cpu(asr, ASR_TABLE); + + /* Is this ok? */ + if (asr->rt.ridcode != RVALID2) + LOG_ERR(lc, 0, "%s: Invalid magic number in RAID table.", + handler); + + /* Have we a valid element count? */ + if (asr->rt.elmcnt >= asr->rt.maxelm) + LOG_ERR(lc, 0, "%s: Invalid RAID config table count.\n", + handler); + + /* Is each element the right size? */ + if (asr->rt.elmsize != sizeof(struct asr_raid_configline)) + LOG_ERR(lc, 0, "%s: RAID config line is the wrong size.\n", + handler); + + /* Figure out how much else we need to read. */ + if (asr->rt.elmcnt > 7) { + remaining = asr->rt.elmsize * (asr->rt.elmcnt - 7); + if (!read_file(lc, handler, di->path, &asr->rt.ent[7], + remaining, + (uint64_t)(asr->rb.raidtbl + 1) * ASR_DISK_BLOCK_SIZE)) + { + return 0; + } + to_cpu(asr, ASR_EXTTABLE); + } + + /* Compute checksum. */ + ptr = (uint8_t *)asr->rt.ent; + checksum = 0; + for (i = 0; i < sizeof(asr->rt.ent[0]) * asr->rt.elmcnt; i++) { + checksum += ptr[i]; + } + checksum &= 0xFFFF; + if (checksum != asr->rt.rchksum) + LOG_ERR(lc, 0, "%s: Invalid RAID config table checksum (0x%X vs. 0x%X).\n", + handler, checksum, asr->rt.rchksum); + + /* Process the name of each line of the config line. */ + for (i = 0; i < asr->rt.elmcnt; i++) { + /* + * Weird quirks of the name field of the config line: + * + * - SATA HostRAID w/ ICH5 on IBM x226: The name field is null + * in the drive config lines. The zeroeth item does have a + * name, however. + * - Spares on SCSI HostRAID on IBM x226: The name field for + * all config lines is null. + * + * So, we'll assume that we can copy the name from the zeroeth + * element in the array. The twisted logic doesn't seem to + * have a problem with either of the above cases, though + * attaching spares is going to be a tad tricky (primarily + * because there doesn't seem to be a way to attach a spare to + * a particular array; presumably the binary driver knows how + * or just grabs a disk out of the spare pool. + * + * This is nuts. + */ + if (asr->rt.ent[i].name == 0) + memcpy(asr->rt.ent[i].name, asr->rt.ent[0].name, 16); + + /* Now truncate trailing whitespace in the name. */ + for (j = 15; j >= 0; j--) { + if (asr->rt.ent[i].name[j] == ' ') + asr->rt.ent[i].name[j] = 0; + } + } + + return 1; +} + +static int is_asr(struct lib_context *lc, struct dev_info *di, void *meta) +{ + struct asr *asr = meta; + + /* Check our magic numbers and that the version == v8. + * We don't support anything other than that right now. */ + if (asr->rb.b0idcode == B0RESRVD && asr->rb.smagic == SVALID) { + if (asr->rb.resver == RBLOCK_VER) { + return 1; + } + + LOG_ERR(lc, 0, "%s: ASR v%d detected, but we only support v8.\n", + handler, asr->rb.resver); + } + + return 0; +} + +/* + * Attempt to interpret ASR metadata from a block device. This function + * returns either NULL (not an ASR) or a pointer to a descriptor struct. + * Note that the struct should be fully converted to the correct endianness + * by the time this function returns. + * + * WARNING: If you take disks out of an ASR HostRAID array and plug them in + * to a normal SCSI controller, the array will still show up! Even if you + * scribble over the disks! I assume that the a320raid binary driver only + * does its HostRAID magic if your controller is in RAID mode... but dmraid + * lacks this sort of visibility as to where its block devices come from. + * This is EXTREMELY DANGEROUS if you aren't careful! + */ +static void *asr_read_metadata(struct lib_context *lc, struct dev_info *di, + size_t *sz, uint64_t *offset, + union read_info *info) +{ + size_t size = ASR_DISK_BLOCK_SIZE; + uint64_t asr_sboffset = ASR_CONFIGOFFSET; + struct asr *asr; + + /* + * Read the ASR reserved block on each disk. This is the very + * last sector of the disk, and we're really only interested in + * the two magic numbers, the version, and the pointer to the + * RAID table. Everything else appears to be unused in v8. + */ + asr = alloc_private(lc, handler, sizeof(struct asr)); + if (!asr) { + goto out; + } + + if (!read_file(lc, handler, di->path, &asr->rb, size, asr_sboffset)) + goto bad; + + /* + * Convert metadata and read in + */ + to_cpu(asr, ASR_BLOCK); + + /* Check Signature and read optional extended metadata. */ + if (!is_asr(lc, di, asr) || + !asr_read_extended(lc, di, asr)) + goto bad; + + /* + * Now that we made sure that we have all the metadata, we exit. + * XXX: Maybe we should check the disk status? Does it matter if + * we ignore a s_broken drive? + */ + goto out; + bad: + dbg_free(asr); + asr = NULL; + + out: + return (void*) asr; +} + +/* + * "File the metadata areas" -- I think this function is supposed to declare + * which parts of the drive are metadata and thus off-limits to dmraid. + */ +static void asr_file_metadata(struct lib_context *lc, struct dev_info *di, + void *meta) +{ + struct asr *asr = meta; + + /* + * NOTE: We could probably just register the last 17 sectors + * of the drive in one big operation... + */ + + /* Register the reserved block. */ + file_metadata(lc, handler, di->path, &asr->rb, ASR_DISK_BLOCK_SIZE, + ASR_CONFIGOFFSET); + + /* Register the raid table. */ + file_metadata(lc, handler, di->path, &asr->rt, ASR_DISK_BLOCK_SIZE, + (uint64_t)asr->rb.raidtbl * ASR_DISK_BLOCK_SIZE); + + /* + * Register the rest of the config table. We need to register + * all the space (i.e. maxelm), not just what we're using now. + */ + if (asr->rt.maxelm > 7) + file_metadata(lc, handler, di->path, &asr->rt.ent[7], + (asr->rt.maxelm-7) * sizeof(struct asr_raid_configline), + (uint64_t)(asr->rb.raidtbl+1) * ASR_DISK_BLOCK_SIZE); + + + /* I have no idea what this does */ + file_dev_size(lc, handler, di); +} + +static int asr_setup_rd(struct lib_context *lc, struct raid_dev *rd, + struct dev_info *di, void *meta, union read_info *info); + +static struct raid_dev *asr_read(struct lib_context *lc, + struct dev_info *di) +{ + /* + * NOTE: Everything called after asr_read_metadata assumes that + * the reserved block, raid table and config table have been + * converted to the appropriate endianness. + */ + return read_raid_dev(lc, di, asr_read_metadata, 0, 0, NULL, NULL, + asr_file_metadata, asr_setup_rd, handler); +} + +static int no_sort(struct list_head *dont, struct list_head *care) +{ + return 0; +} + +/* Sort ASR devices by for a RAID set. */ +static int asr_dev_sort(struct list_head *pos, struct list_head *new) +{ + struct asr_raid_configline *p, *n; + uint64_t one, two; + + p = asr_this_disk( META(RD(pos), asr) ); + n = asr_this_disk( META(RD(new), asr) ); + + /* Is using a 64-bit id composed of hba:ch:lun:id ok? */ + one = ((uint64_t)n->raidhba << 48) + | ((uint64_t)n->raidchnl << 40) + | ((uint64_t)n->raidlun << 32) + | ((uint64_t)n->raidid); + + two = ((uint64_t)p->raidhba << 48) + | ((uint64_t)p->raidchnl << 40) + | ((uint64_t)p->raidlun << 32) + | ((uint64_t)p->raidid); + + return (one < two); +} + +/* + * Find the top-level RAID set for an ASR context. + */ +static int asr_find_toplevel(struct lib_context *lc, + struct asr *asr) +{ + int i, toplevel = -1; + + for (i = 0; i < asr->rt.elmcnt; i++) { + if (asr->rt.ent[i].raidlevel == FWL_2) + { + toplevel = i; + break; + } + else if (asr->rt.ent[i].raidlevel == FWL) + { + toplevel = i; + } + } + + return toplevel; +} + +/* + * Find the logical drive configuration that goes with this + * physical disk configuration. + */ +static struct asr_raid_configline *asr_find_logical(struct asr *asr) +{ + int i, j; + + /* This MUST be done backwards! */ + for (i = asr->rt.elmcnt - 1; i >= 0; i--) { + if (asr->rt.ent[i].raidmagic == asr->rb.drivemagic) { + for (j = i - 1; j >= 0; j--) { + if (asr->rt.ent[j].raidlevel == FWL) { + return &asr->rt.ent[j]; + } + } + } + } + + return NULL; +} + +/* + * Add an ASR device to a RAID set. Basically, this means that + * we have to find the set to which this disk belongs (or create + * one if we haven't) and then add this disk to the list if it's + * not a spare. + * + * FIXME: Actually, HostRAID _does_ do multilevel RAID (10). + */ +static struct raid_set *asr_group(struct lib_context *lc, + struct raid_dev *rd) +{ + int top_idx, i; + struct raid_set *top_set, *set = NULL, *tmp; + struct asr *asr = META(rd, asr); + struct asr_raid_configline *cl = asr_this_disk(asr); + struct asr_raid_configline *fwl; + char inbuf[65], *outbuf; + + /* Can we find a top level raid set? */ + top_idx = asr_find_toplevel(lc, asr); + if (top_idx < 0) { + LOG_ERR(lc, NULL, "Can't find a FWL or FWL2 for FWP %x\n", + asr->rb.drivemagic); + } + top_set = find_set(lc, NULL, asr_name(lc, asr), FIND_TOP); + if (top_set != NULL) { + if (asr->rt.ent[top_idx].raidlevel == FWL_2) { + /* double-layered; find the appropriate set */ + list_for_each_entry(tmp, &top_set->sets, list) { + /* find the FWL that goes with the drive. */ + fwl = asr_find_logical(asr); + if (fwl == NULL) { + LOG_ERR(lc, NULL, + "Can't find a FWL to go with FWP %x\n", + asr->rb.drivemagic); + } + snprintf(inbuf, 64, "asr_%s_%x", fwl->name, + fwl->raidmagic); + if (strcmp(tmp->name, inbuf) == 0) { + set = tmp; + break; + } + } + } else { + set = top_set; + } + + /* now attach it */ + if (!set) { + LOG_ERR(lc, NULL, "No FWL to go with FWP %x\n", + asr->rb.drivemagic); + } + list_add_sorted(lc, &set->devs, &rd->devs, asr_dev_sort); + + return top_set; + } + + /* Otherwise, we need to create a new set structure. */ + + /* If we're dealing with a single-level array... */ + if (asr->rt.ent[top_idx].raidlevel == FWL) { + top_set = find_or_alloc_raid_set(lc, asr_name(lc, asr), + FIND_TOP, rd, LC_RS(lc), NO_CREATE, NO_CREATE_ARG); + + top_set->stride = (cl ? cl->strpsize: 0); + top_set->status = s_ok; + top_set->type = asr_type(asr_find_logical(asr)); + + /* Add the disk to the set. */ + list_add_sorted(lc, &top_set->devs, &rd->devs, asr_dev_sort); + + return top_set; + } + + /* Nope. Two-level array. */ + top_set = find_or_alloc_raid_set(lc, asr_name(lc, asr), + FIND_TOP, rd, LC_RS(lc), NO_CREATE, NO_CREATE_ARG); + top_set->stride = (cl ? cl->strpsize : 0); + top_set->status = s_ok; + top_set->type = asr_type(&asr->rt.ent[top_idx]); + + /* Find all FWLs that go with this FWL2 and add them. */ + for (i = 0; i < asr->rt.elmcnt; i++) { + if (asr->rt.ent[i].raidlevel != FWL) + continue; + if (asr->rt.ent[i].raidcnt == 0) + continue; + + outbuf = malloc(32); + if (outbuf == NULL) { + LOG_ERR(lc, NULL, "Can't allocate array name.\n"); + } + snprintf(outbuf, 64, "asr_%s_%x", asr->rt.ent[i].name, + asr->rt.ent[i].raidmagic); + set = alloc_raid_set(lc, __func__); + if (!set) { + LOG_ERR(lc, NULL, "Can't allocate RAID set.\n"); + } + + set->name = outbuf; + set->status = s_ok; + set->type = asr_type(asr_find_logical(asr)); + list_add_sorted(lc, &top_set->sets, &set->list, no_sort); + + /* Add the drive to the set too */ + fwl = asr_find_logical(asr); + if (fwl == NULL) { + LOG_ERR(lc, NULL, + "Can't find a FWL to go with FWP %x\n", + asr->rb.drivemagic); + } + if (fwl->raidmagic == asr->rt.ent[i].raidmagic) { + list_add_sorted(lc, &set->devs, &rd->devs, asr_dev_sort); + } + + } + + printf("finished!\n"); + + return set; +} + +/* Write metadata. */ +static int asr_write(struct lib_context *lc, + struct raid_dev *rd, int erase) +{ + fprintf(stderr, "ERROR: asr_write not implemented!\n"); + return EPERM; +} + +#if 0 +/* CODEME: Write private RAID metadata to device */ +static int template_write(struct lib_context *lc, + struct raid_dev *rd, int erase) +{ + int ret; +#if BYTE_ORDER != LITTLE_ENDIAN + struct template *template = META(rd, template); +#endif + + /* CODEME: in case there's more complex metadata areas */ + to_disk(template); + ret = write_metadata(lc, handler, rd, -1, erase); + to_cpu(template); + return ret; +} +#endif + +/* + * Check integrity of a RAID set. + */ + +/* Retrieve the number of devices that should be in this set. */ +static unsigned int asr_device_count(struct raid_dev *rd, void *context) +{ + /* Get the logical drive */ + struct asr_raid_configline *cl = asr_find_logical(META(rd, asr)); + return (cl ? cl->raidcnt : 0); +} + +/* Check a RAID device */ +static int asr_check_rd(struct lib_context *lc, struct raid_set *rs, + struct raid_dev *rd, void *context) +{ + /* XXX: Assume non-broken means ok. */ + return (rd->type != s_broken); +} + +/* Start the recursive RAID set check. */ +static int asr_check(struct lib_context *lc, struct raid_set *rs) +{ + int f = check_raid_set(lc, rs, asr_device_count, NULL, asr_check_rd, + NULL, handler); + return f; +} + +/* + * IO error event handler. + */ +static int event_io(struct lib_context *lc, struct event_io *e_io) +{ + LOG_ERR(lc, 0, "An I/O error event occurred. Now what?\n"); +} + +static struct event_handlers asr_event_handlers = { + .io = event_io, /* CODEME: */ + .rd = NULL, /* FIXME: no device add/remove event handler yet. */ +}; + +/* Dump a reserved block */ +static void asr_dump_rb(struct lib_context *lc, struct asr_reservedblock *rb) +{ + log_print(lc, "block magic:\t\t0x%X", rb->b0idcode); + log_print(lc, "sb0flags:\t\t0x%X", rb->sb0flags); + log_print(lc, "jbodEnable:\t\t%d", rb->jbodEnable); + log_print(lc, "biosInfo:\t\t0x%X", rb->biosInfo); + log_print(lc, "drivemagic:\t\t0x%X", rb->drivemagic); + log_print(lc, "svBlockStorageTid:\t0x%X", rb->svBlockStorageTid); + log_print(lc, "svtid:\t\t\t0x%X", rb->svtid); + log_print(lc, "resver:\t\t\t%d", rb->resver); + log_print(lc, "smagic:\t\t\t0x%X", rb->smagic); + log_print(lc, "raidtbl @ sector:\t%d", rb->raidtbl); +} + +/* Dump a raid config line */ +static void asr_dump_cl(struct lib_context *lc, struct asr_raid_configline *cl) +{ + log_print(lc, "config ID:\t\t0x%X", cl->raidmagic); + log_print(lc, " name:\t\t\t\"%s\"", cl->name); + log_print(lc, " raidcount:\t\t%d", cl->raidcnt); + log_print(lc, " sequence #:\t\t%d", cl->raidseq); + log_print(lc, " level:\t\t%d", cl->raidlevel); + log_print(lc, " type:\t\t\t%d", cl->raidtype); + log_print(lc, " state:\t\t%d", cl->raidstate); + log_print(lc, " flags:\t\t0x%X", cl->flags); + log_print(lc, " refcount:\t\t%d", cl->refcnt); + log_print(lc, " hba:\t\t\t%d", cl->raidhba); + log_print(lc, " channel:\t\t%d", cl->raidchnl); + log_print(lc, " lun:\t\t\t%d", cl->raidlun); + log_print(lc, " id:\t\t\t%d", cl->raidid); + log_print(lc, " offset:\t\t%d", cl->loffset); + log_print(lc, " capacity:\t\t%d", cl->lcapcty); + log_print(lc, " stripe size:\t\t%d KB", + cl->strpsize * ASR_DISK_BLOCK_SIZE / 1024); + log_print(lc, " BIOS info:\t\t%d", cl->biosInfo); + log_print(lc, " phys/log lun:\t\t%d", cl->lsu); + log_print(lc, " addedDrives:\t\t%d", cl->addedDrives); + log_print(lc, " appSleepRate:\t\t%d", cl->appSleepRate); + log_print(lc, " blockStorageTid:\t%d", cl->blockStorageTid); + log_print(lc, " curAppBlock:\t\t%d", cl->curAppBlock); + log_print(lc, " appBurstCount:\t%d", cl->appBurstCount); +} + +/* Dump a raid config table */ +static void asr_dump_rt(struct lib_context *lc, struct asr_raidtable *rt) +{ + unsigned int i; + log_print(lc, "ridcode:\t\t0x%X", rt->ridcode); + log_print(lc, "table ver:\t\t%d", rt->rversion); + log_print(lc, "max configs:\t\t%d", rt->maxelm); + log_print(lc, "configs:\t\t%d", rt->elmcnt); + log_print(lc, "config sz:\t\t%d", rt->elmsize); + log_print(lc, "checksum:\t\t0x%X", rt->rchksum); + log_print(lc, "raid flags:\t\t0x%X", rt->raidFlags); + log_print(lc, "timestamp:\t\t0x%X", rt->timestamp); + log_print(lc, "irocFlags:\t\t0x%X%s", rt->irocFlags, + (rt->irocFlags & ASR_IF_BOOTABLE ? " (bootable)" : "")); + log_print(lc, "dirty:\t\t\t%d", rt->dirty); + log_print(lc, "action prio:\t\t%d", rt->actionPriority); + log_print(lc, "spareid:\t\t%d", rt->spareid); + log_print(lc, "sparedrivemagic:\t0x%X", rt->sparedrivemagic); + log_print(lc, "raidmagic:\t\t0x%X", rt->raidmagic); + log_print(lc, "verifydate:\t\t0x%X", rt->verifyDate); + log_print(lc, "recreatedate:\t\t0x%X", rt->recreateDate); + log_print(lc, "RAID config table:"); + for (i = 0; i < rt->elmcnt; i++) { + asr_dump_cl(lc, &rt->ent[i]); + } +} + +#ifdef DMRAID_NATIVE_LOG +/* + * Log native information about the RAID device. + */ +static void asr_log(struct lib_context *lc, struct raid_dev *rd) +{ + struct asr *asr = META(rd, asr); + + log_print(lc, "%s (%s):", rd->di->path, handler); + asr_dump_rb(lc, &asr->rb); + asr_dump_rt(lc, &asr->rt); +} +#endif + +static struct dmraid_format asr_format = { + .name = HANDLER, + .descr = "Adaptec HostRAID ASR", + .caps = "0,1", + .format = FMT_RAID, + .read = asr_read, + .write = asr_write, // FIXME + .group = asr_group, + .check = asr_check, + .events = &asr_event_handlers, // FIXME +#ifdef DMRAID_NATIVE_LOG + .log = asr_log, +#endif +}; + +/* Register this format handler with the format core */ +int register_asr(struct lib_context *lc) +{ + return register_format_handler(lc, &asr_format); +} + +/* + * Set up a RAID device from what we've assembled out of the metadata. + */ +static int asr_setup_rd(struct lib_context *lc, struct raid_dev *rd, + struct dev_info *di, void *meta, union read_info *info) +{ + struct asr *asr = meta; + struct meta_areas *ma; + struct asr_raid_configline *cl = asr_this_disk(asr); + + if (!cl) + LOG_ERR(lc, 0, "%s: Could not find current disk!\n", + handler); + + /* We need three metadata areas */ + if (!(rd->meta_areas = alloc_meta_areas(lc, rd, handler, 3))) + return 0; + + /* First area: reserved block. */ + ma = rd->meta_areas; + ma->offset = ASR_CONFIGOFFSET >> 9; + ma->size = ASR_DISK_BLOCK_SIZE; + ma->area = (void *)asr; + + /* Second area: raid table. */ + ma++; + ma->offset = asr->rb.raidtbl; + ma->size = ASR_DISK_BLOCK_SIZE; + ma->area = (void *)asr; + + /* Third area: raid config table. */ + ma++; + ma->offset = asr->rb.raidtbl + 1; + ma->size = 15 * ASR_DISK_BLOCK_SIZE; + ma->area = (void *)asr; + + /* Now set up the rest of the metadata info */ + rd->di = di; + rd->fmt = &asr_format; + + rd->status = asr_disk_status(cl); + rd->type = asr_type(cl); + + rd->offset = ASR_DATAOFFSET; + rd->sectors = cl->lcapcty; + + if ((rd->name = asr_name(lc, asr))) { + return 1; + } + + return 0; +} diff -Naur orig/lib/format/ataraid/asr.h v3-test/lib/format/ataraid/asr.h --- orig/lib/format/ataraid/asr.h 1969-12-31 16:00:00.000000000 -0800 +++ v3-test/lib/format/ataraid/asr.h 2006-01-10 16:11:23.000000000 -0800 @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2005 IBM + * + * Copyright (c) 2001, 2002, 2004 Adaptec Inc. + * 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. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef _ASR_H +#define _ASR_H + +/* Stuff that djwong added */ +#ifdef FORMAT_HANDLER +#undef FORMAT_HANDLER + +/* ASR metadata offset in bytes */ +#define ASR_CONFIGOFFSET ((di->sectors - 1) << 9) + +/* Data offset in sectors */ +#define ASR_DATAOFFSET 0 + +/* Assume block size is 512. So much for CD dmraid... */ +#define ASR_DISK_BLOCK_SIZE 512 + +/* Copied verbatim from Adaptec's emd driver. */ + +/* + * This is a metadata versioning mechanism, but rather a versioning + * mechansim for Adaptec-sponsored changes to md. (i.e. more of a driver + * version) + */ +#define MD_ADAPTEC_MAJOR_VERSION 0 +#define MD_ADAPTEC_MINOR_VERSION 0 +#define MD_ADAPTEC_PATCHLEVEL_VERSION 13 + +#define FW_RESERVED_BLOCKS 0x800 + +#define MAX_SLEEPRATE_ENTRIES 10 + +/* define lsu levels */ +#define LSU_LEVEL_PHYSICAL 1 /* Firmware Physical */ +#define LSU_LEVEL_LOGICAL 2 /* Firmware Logical */ + +/* define RAID drive substates */ +#define FWP 0 /* Firmware Physical */ +#define FWL 1 /* Firmware Logical */ +#define OSI 2 /* Operating System Intermediate */ +#define FWL_2 3 /* Dual Level */ + +#define ASR_RAID0 0 +#define ASR_RAID1 1 +#define ASR_RAID4 4 +#define ASR_RAID5 5 +#define ASR_RAIDRED 0xFF +#define ASR_RAIDSPR 0xFE + +/*** RAID CONFIGURATION TABLE STRUCTURE ***/ + +#define RVALID2 0x900765C4 /* Version 2+ RAID table ID code + signature */ +#define RCTBL_MAX_ENTRIES 127 +#define HBA_RCTBL_MAX_ENTRIES 255 +#define RTBLBLOCKS 16 /* Size of drive's raid table + in blocks */ + +/* flag bits */ +#define RCTBLCHNG 0x80 /* Set on comp OR log (NOT AND) if tbl updates needed */ +#define COPYDIR 0x40 +#define MIRCOPY 0x20 +#define INITIAL_BUILD_COMPLETED 0x10 +#define SMART_DISABLED 0x08 +#define WRITEBACK 0x04 +#define PREDICTIVE_ENABLE 0x02 +#define RAID_ENTRY_FLAGS_ALARM_OFF_M 0x01 + +struct asr_raid_configline +{ + uint16_t raidcnt; /* Component count of an OSL/FWL array */ + uint16_t raidseq; /* Sequence # of component to look for */ + uint32_t raidmagic; /* Magic # of component to look for */ + uint8_t raidlevel; /* Array level = OSL/FWL/OSI/FWP */ + uint8_t raidtype; /* Array type = RAID0/1/3/5, RAIDRED, + RAIDSPR */ + uint8_t raidstate; /* State of logical or physical drive */ + + uint8_t flags; /* misc flags set bit positions above */ + + uint8_t refcnt; /* Number of references to this log entry */ + uint8_t raidhba; /* -- not used -- Host bus adapter number + or RAIDID */ + uint8_t raidchnl; /* Channel number */ + uint8_t raidlun; /* SCSI LUN of log/phys drv */ + uint32_t raidid; /* SCSI ID of log/phys drv */ + uint32_t loffset; /* Offset of data for this comp in the + array */ + uint32_t lcapcty; /* Capacity of log drv or space used on + phys */ + uint16_t strpsize; /* Stripe size in blocks of this drive */ + uint16_t biosInfo; /* bios info - set by + I2O_EXEC_BIOS_INFO_SET */ + uint32_t lsu; /* Pointer to phys/log lun of this entry */ + uint8_t addedDrives; + uint8_t appSleepRate; + uint16_t blockStorageTid; + uint32_t curAppBlock; + uint32_t appBurstCount; + uint8_t name[16]; /* Full name of the array. */ +} __attribute__ ((packed)); + +struct asr_raidtable +{ +/* raid Flag defines 32 bits 0 - FFFFFFFF */ +#define RAID_FLAGS_ALARM_OFF_M 0x00000001 + uint32_t ridcode; /* RAID table signature - 0x900765C4 */ + uint32_t rversion; /* Version of the RAID config table */ + uint16_t maxelm; /* Maximum number of elements */ + uint16_t elmcnt; /* Element Count (number used) */ + uint16_t elmsize; /* Size of an individual raidCLine */ + uint16_t rchksum; /* RAID table check sum + (no rconfTblV2)*/ + uint32_t res1; /* Reserved */ + uint16_t res2; /* was bldRate - Time in 1/10s + between idle build bursts */ + uint16_t res3; /* was bldAmount - Block to build + during a build burst */ + uint32_t raidFlags; + uint32_t timestamp; /* used for iROC. A stamp to find + which is latest */ + uint8_t irocFlags; +#define ASR_IF_VERIFY_WITH_AUTOFIX 0x01 +#define ASR_IF_BOOTABLE 0x80 + uint8_t dirty; /* Records "open state" for array */ +#define ARRAY_STATE_OK 0x00 +#define ARRAY_STATE_DIRTY 0x03 + uint8_t actionPriority; + uint8_t spareid; /* Stored in member disk meta data + to declare the ID of dedicated + spare to show up. */ + uint32_t sparedrivemagic;/* drivemagic (in RB) of the spare + at above ID. */ + uint32_t raidmagic; /* used to identify spare drive with + its mirror set. */ + uint32_t verifyDate; /* used by iomgr */ + uint32_t recreateDate; /* used by iomgr */ + uint8_t res4[12]; /* Reserved */ + struct asr_raid_configline ent[RCTBL_MAX_ENTRIES]; +} __attribute__ ((packed)); + + +#define RBLOCK_VER 8 /* Version of the reserved block */ +#define B0RESRVD 0x37FC4D1E /* Signature of the reserved block */ +#define SVALID 0x4450544D /* ASCII code for "DPTM" DPT Mirror */ + +struct asr_reservedblock +{ + uint32_t b0idcode; /* 0x00 - ID code signifying block 0 + reserved */ + uint8_t lunsave[8]; /* 0x04 - NOT USED - LUN mappings for + all drives */ + uint16_t sdtype; /* 0x0C - NOT USED - drive type in + boot prom */ + uint16_t ssavecyl; /* 0x0E - NOT USED - Set Parameters + cylinders */ + uint8_t ssavehed; /* 0x10 - NOT USED - Set Parameters + heads */ + uint8_t ssavesec; /* 0x11 - NOT USED - Set Parameters + sectors */ + uint8_t sb0flags; /* 0x12 - flags saved in reserved + block */ + uint8_t jbodEnable; /* 0x13 - jbod enable -- DEC drive + hiding */ + uint8_t lundsave; /* 0x14 - NOT USED - LUNMAP disable + flags */ + uint8_t svpdirty; /* 0x15 - NOT USED - saved percentage + dirty */ + uint16_t biosInfo; /* 0x16 - bios info - set by + I2O_EXEC_BIOS_INFO_SET */ + uint16_t svwbskip; /* 0x18 - NOT USED - saved write-back + skip value */ + uint16_t svwbcln; /* 0x1A - NOT USED - saved maximum + clean blocks in write-back */ + uint16_t svwbmax; /* 0x1C - NOT USED - saved maximum + write-back length */ + uint16_t res3; /* 0x1E - unused (was write-back burst + block count) */ + uint16_t svwbmin; /* 0x20 - NOT USED - saved minimum + block count to write */ + uint16_t res4; /* 0x22 - unused (was minimum + look-ahead length) */ + uint16_t svrcacth; /* 0x24 - NOT USED - saved read cache + threshold */ + uint16_t svwcacth; /* 0x26 - NOT USED - saved write + cache threshold */ + uint16_t svwbdly; /* 0x28 - NOT USED - saved write-back + delay */ + uint8_t svsdtime; /* 0x2A - NOT USED - saved spin down + time */ + uint8_t res5; /* 0x2B - unused */ + uint16_t firmval; /* 0x2C - NOT USED - firmware on + drive (dw) */ + uint16_t firmbln; /* 0x2E - NOT USED - length in blocks + for firmware */ + uint32_t firmblk; /* 0x30 - NOT USED - starting block + for firmware */ + uint32_t fstrsvrb; /* 0x34 - 1st block reserved by + Storage Manager */ + uint16_t svBlockStorageTid; /* 0x38 - */ + uint16_t svtid; /* 0x3A - */ + uint8_t svseccfl; /* 0x3C - NOT USED - reserved block + scsi bus ecc flags */ + uint8_t res6; /* 0x3D - unused */ + uint8_t svhbanum; /* 0x3E - NOT USED - HBA's unique + RAID number */ + uint8_t resver; /* 0x3F - reserved block version + number */ + uint32_t drivemagic; /* 0x40 - Magic number of this drive - + used w/ RCTBLs */ + uint8_t reserved[20]; /* 0x44 - unused */ + uint8_t testnum; /* 0x58 - NOT USED - diagnostic test + number */ + uint8_t testflags; /* 0x59 - NOT USED - diagnostic test + flags */ + uint16_t maxErrorCount; /* 0x5A - NOT USED - diagnostic test + maximum error count */ + uint32_t count; /* 0x5C - NOT USED - diagnostic test + cycles - # of iterations */ + uint32_t startTime; /* 0x60 - NOT USED - diagnostic test + absolute test start time in + seconds */ + uint32_t interval; /* 0x64 - NOT USED - diagnostic test + interval in seconds */ + uint8_t tstxt0; /* 0x68 - not used - originally + diagnostic test exclusion period + start hour */ + uint8_t tstxt1; /* 0x69 - not used - originally + diagnostic test exclusion period + end hour */ + uint8_t serNum[32]; /* 0x6A - reserved */ + uint8_t res8[102]; /* 0x8A - reserved */ + uint32_t fwTestMagic; /* 0xF0 - test magic number - used by + FW Test for automated tests */ + uint32_t fwTestSeqNum; /* 0xF4 - test sequence number - used + by FW Test for automated tests */ + uint8_t fwTestRes[8]; /* 0xF6 - reserved by FW Test for + automated tests */ + uint32_t smagic; /* 0x100 - magic value saying software + half is valid */ + uint32_t raidtbl; /* 0x104 - pointer to first block of + raid table */ + uint16_t raidline; /* 0x108 - line number of this raid + table entry - only if version <7 */ + uint8_t res9[0xF6]; /* 0x10A - reserved for software stuff*/ +} __attribute__ ((packed)); + + + +#define ARRAY_NEW 0x00 +#define ARRAY_EQUAL 0x01 +#define ARRAY_SEQ_LESS 0x02 +#define ARRAY_SEQ_GREAT 0x03 + +#define LOCK_PRIORITY 10 /* Uses 10, 11, 12 - For all three channels */ + + +/* B0FLAGS flag bits: */ + +#define SMARTENA 7 /* SMART emulation enabled */ +#define CLRERROR 4 /* Clear stage of Interpret Format + not completed */ +#define FMTERROR 3 /* Format stage of Interpret Format + not completed */ +#define WRTTHRU 2 /* write throughs */ +#define CACHEDIS 0 /* cache disable bit */ +#define PREDICTIVE_ENABLE 0x02 + +#define ID_MAP_PHYSICAL_M 1 /* Logical Map Physical */ +#define ID_MAP_LOGICAL_M 2 /* Either Dual Level or Single Level + Logical*/ + +#define MAX_LSU_COUNT 256 + +#define MAX_LSU_COMPONENTS 64 +#define MAX_LSU_INQUIRY_DATA 64 +#define MAX_LSU_SERIAL_NUMBER 8 +#define STD_INQUIRY_SIZE 48 + +#define MAX_LSU_BAD_BLOCKS 8 + +/* lsuType definitions */ +#define LT_UNCONFIGURED_M 0x00 +#define LT_RAID0_M 0x01 +#define LT_RAID1_M 0x02 +#define LT_RAID3_M 0x08 +#define LT_RAID4_M 0x10 +#define LT_RAID5_M 0x20 +#define LT_REDIR_M 0x40 +#define LT_SPARE_M 0x80 + +#define LSU_RAID_LEVEL_0 LT_RAID0_M +#define LSU_RAID_LEVEL_1 LT_RAID1_M +#define LSU_RAID_LEVEL_3 LT_RAID3_M +#define LSU_RAID_LEVEL_4 LT_RAID4_M +#define LSU_RAID_LEVEL_5 LT_RAID5_M +#define LSU_RAID_REDIRECT LT_REDIR_M +#define LSU_RAID_SPARE LT_SPARE_M + +/* raidState definitions */ +#define LS_OPTIMAL_M 0x00 +#define LS_DEGRADED_M 0x01 +#define LS_REBUILDING_M 0x02 +#define LS_MORPHING_M 0x03 +#define LS_DEAD_M 0x04 +#define LS_WARNING_M 0x05 + +#define LS_VERIFYING_M 0x0A +#define LSU_ARRAY_SUBSTATE_WITH_FIX 0x10 + +#define LS_BUILDING_M 0x0B +#define LS_CREATED_M 0x54 +#define LS_DIAGNOSING_M 0xFD + + +/* arrayState definitions */ +#define LSU_ARRAY_STATE_OPTIMAL 0x00 +#define LSU_ARRAY_STATE_DEGRADED 0x01 +/* etc. */ + +/* component raidState definitions */ +#define MAIN_STATE 0x0F +#define LSU_COMPONENT_STATE_OPTIMAL 0x00 +#define LSU_COMPONENT_STATE_DEGRADED 0x01 +#define LSU_COMPONENT_STATE_UNCONFIGURED 0x02 +#define LSU_COMPONENT_STATE_FAILED 0x03 +#define LSU_COMPONENT_STATE_REPLACED 0x04 +#define LSU_COMPONENT_STATE_UNINITIALIZED 0x0A + +#define LSU_COMPONENT_SUBSTATE_BUILDING 0x10 /* drive is being built + for first time */ +#define LSU_COMPONENT_SUBSTATE_REBUILDING 0x20 /* drive is being + rebuilt */ +#define LSU_ARRAY_SUBSTATE_AWAIT_FORMAT 0x50 +/* etc. */ + +/* Everything after here also added by djwong */ + +struct asr { + struct asr_reservedblock rb; + struct asr_raidtable rt; +}; + +#endif /* FORMAT_HANDLER */ + +int register_asr(struct lib_context *lc); + +#endif /* _ASR_H */ diff -Naur orig/lib/format/ondisk.h v3-test/lib/format/ondisk.h --- orig/lib/format/ondisk.h 2005-12-06 16:30:04.000000000 -0800 +++ v3-test/lib/format/ondisk.h 2006-01-10 16:11:23.000000000 -0800 @@ -16,6 +16,7 @@ #include "ataraid/pdc.h" #include "ataraid/via.h" #include "ataraid/sil.h" +#include "ataraid/asr.h" #include "partition/dos.h" diff -Naur orig/lib/format/register.h v3-test/lib/format/register.h --- orig/lib/format/register.h 2005-12-06 16:30:04.000000000 -0800 +++ v3-test/lib/format/register.h 2006-01-10 16:11:23.000000000 -0800 @@ -23,6 +23,7 @@ xx(pdc) xx(sil) xx(via) + xx(asr) /* DOS partition type handler. */ xx(dos) diff -Naur orig/lib/Makefile.in v3-test/lib/Makefile.in --- orig/lib/Makefile.in 2005-12-06 16:30:05.000000000 -0800 +++ v3-test/lib/Makefile.in 2006-01-10 16:11:23.000000000 -0800 @@ -33,6 +33,7 @@ format/ataraid/pdc.c \ format/ataraid/sil.c \ format/ataraid/via.c \ + format/ataraid/asr.c \ format/partition/dos.c OBJECTS=$(SOURCES:%.c=%.o)
Attachment:
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Ataraid-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/ataraid-list