[PATCH] very rough cut of adaptec hostraid support for dmraid

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Below is a very preliminary patch to enable Adaptec HostRAID support in
dmraid.  I've been able to configure RAID 0 and 1 arrays on an IBM x226,
though I've not had a chance to test it on anything else, such as the
SATA HostRAID machine that I have sitting nearby.  I'm sending this
patch to this list for review and feedback; at this stage, this patch
should not be used by anyone with any valuable data at all.

So far, the only testing it's seen is an ad-hoc setup wherein I loaded
the a320raid module in SLES9, made a filesystem on the RAID, filled it
up with assorted junk, rebooted into to 2.6.14, ran dmraid -ay, and then
compared what was on the RAID with the originals.  That worked, so I
wrote some data, rebooted back into SLES9, and compared the filesystem
contents under a320raid.  That worked too, so off goes the patch.

Note that there's quite a bit missing right now--it can't write
metadata, spares are totally ignored, and nested RAID setups (RAID10 in
particular) are not implemented.  Yet.  Indeed, I'm only interested in
making sure that I'm not barking up the wrong tree with this. :)

Questions?  Comments?

--D
diff -Naurp orig/lib/format/ataraid/asr.c new/lib/format/ataraid/asr.c
--- orig/lib/format/ataraid/asr.c	1969-12-31 16:00:00.000000000 -0800
+++ new/lib/format/ataraid/asr.c	2005-12-14 16:07:44.000000000 -0800
@@ -0,0 +1,696 @@
+/*
+ * 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?  Does dmraid/hostraid even do RAID4/5?
+ * Constants are defined, but I don't recall seeing a RAID5
+ * setting in the BIOS.  Maybe I need more drives.  Looks like
+ * we can at least do 0, 1 and 10; right now we'll only claim
+ * to do 0 and 1.
+ *
+ * (header file implies RAID 0/1/4/5)
+ */
+static struct types types[] = {
+	{ ASR_RAID0, t_raid0 },
+	{ ASR_RAID1, t_raid1 },
+        { 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.\n",
+			handler);
+
+	/* Now truncate trailing whitespace in the name. */
+	for (i = 0; i < asr->rt.elmcnt; i++) {
+		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);
+}
+
+#if 0
+/*
+ * Decide about ordering sequence of RAID device.
+ * (Called by list_add_sorted().
+ */
+static int dev_sort(struct list_head *pos, struct list_head *new)
+{
+	return (META(RD(new), template))->disk_number <
+	       (META(RD(pos), template))->disk_number;
+}
+
+/*
+ * Decide about ordering sequence of RAID device.
+ * (Called by join_superset().
+ */
+static int set_sort(struct list_head *pos, struct list_head *new)
+{
+	return _subset(META(RD_RS(RS(new)), via)) <
+	       _subset(META(RD_RS(RS(pos)), via));
+}
+#endif
+
+/* 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;
+
+	p = asr_this_disk( META(RD(pos), asr) );
+	n = asr_this_disk( META(RD(new), asr) );
+
+	/*
+	 * Hopefully the user is not foolish enough to create
+	 * multiple arrays with the same name and LUN?
+	 */
+	return (n->raidlun < p->raidlun);
+}
+
+/* 
+ * 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)
+{
+	struct asr *asr = META(rd, asr);
+	struct asr_raid_configline *cl = asr_this_disk(asr);
+	struct raid_set *set;
+
+	/* FIXME: Ignore spares for now */
+	if (T_SPARE(rd))
+		return NULL;
+	
+	/* FIXME: This should be multilevel RAID. */
+	if (!(set = find_or_alloc_raid_set(lc, asr_name(lc, asr),
+		FIND_TOP, rd, LC_RS(lc), NO_CREATE, NO_CREATE_ARG)))
+	{
+		return NULL;
+	}
+
+	/* Set stride and status.  Stride is sectors, same as the
+	 * strsize field. */
+	set->stride = (cl ? cl->strpsize: 0);
+	set->status = s_ok;
+
+	/* Now that we have a set, add the disk to the set. */
+	list_add_sorted(lc, &set->devs, &rd->devs, asr_dev_sort);
+
+	return set;
+}
+
+/* Write metadata. */
+static int asr_write(struct lib_context *lc,
+			  struct raid_dev *rd, int erase)
+{
+	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.
+ */
+
+/*
+ * Find the logical drive configuration that goes with this
+ * physical disk configuration.
+ */
+static struct asr_raid_configline *asr_find_logical(struct asr *asr)
+{
+	struct asr_raid_configline *thisdisk = asr_this_disk(asr);
+	unsigned int i;
+
+	for (i = 0; i < asr->rt.elmcnt; i++) {
+		if (strcmp((char *)asr->rt.ent[i].name, (char *)thisdisk->name) == 0
+			&& asr->rt.ent[i].raidlevel == FWL)
+			return &asr->rt.ent[i];
+	}
+
+	return NULL;
+}
+
+/* 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, "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 -Naurp orig/lib/format/ataraid/asr.h new/lib/format/ataraid/asr.h
--- orig/lib/format/ataraid/asr.h	1969-12-31 16:00:00.000000000 -0800
+++ new/lib/format/ataraid/asr.h	2005-12-14 15:54:57.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 -Naurp orig/lib/format/ondisk.h new/lib/format/ondisk.h
--- orig/lib/format/ondisk.h	2005-12-06 16:30:04.000000000 -0800
+++ new/lib/format/ondisk.h	2005-12-14 15:56:47.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 -Naurp orig/lib/format/register.h new/lib/format/register.h
--- orig/lib/format/register.h	2005-12-06 16:30:04.000000000 -0800
+++ new/lib/format/register.h	2005-12-14 15:56:21.000000000 -0800
@@ -23,6 +23,7 @@
 	xx(pdc)
 	xx(sil)
 	xx(via)
+	xx(asr)
 
 	/* DOS partition type handler. */
 	xx(dos)
diff -Naurp orig/lib/Makefile.in new/lib/Makefile.in
--- orig/lib/Makefile.in	2005-12-06 16:30:05.000000000 -0800
+++ new/lib/Makefile.in	2005-12-14 15:55:27.000000000 -0800
@@ -33,6 +33,7 @@ SOURCES=\
 	format/ataraid/pdc.c \
 	format/ataraid/sil.c \
 	format/ataraid/via.c \
+	format/ataraid/asr.c \
 	format/partition/dos.c
 
 OBJECTS=$(SOURCES:%.c=%.o)
_______________________________________________

Ataraid-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/ataraid-list

[Index of Archives]     [Linux RAID]     [Linux Device Mapper]     [Linux IDE]     [Linux SCSI]     [Kernel]     [Linux Books]     [Linux Admin]     [GFS]     [RPM]     [Yosemite Campgrounds]     [AMD 64]

  Powered by Linux