Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Apr 2012 17:53:02 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r234848 - in head: sbin/geom/class/raid sys/conf sys/geom/raid sys/modules/geom/geom_raid
Message-ID:  <201204301753.q3UHr2XI077126@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Apr 30 17:53:02 2012
New Revision: 234848
URL: http://svn.freebsd.org/changeset/base/234848

Log:
  Add to GEOM RAID class module, supporting the DDF metadata format, as
  defined by the SNIA Common RAID Disk Data Format Specification v2.0.
  
  Supports multiple volumes per array and multiple partitions per disk.
  Supports standard big-endian and Adaptec's little-endian byte ordering.
  Supports all single-layer RAID levels. Dual-layer RAID levels except
  RAID10 are not supported now because of GEOM RAID design limitations.
  
  Some work is still to be done, but the present code already manages basic
  interoperation with RAID BIOS of the Adaptec 1430SA SATA RAID controller.
  
  MFC after:	1 month
  Sponsored by:	iXsystems, Inc.

Added:
  head/sys/geom/raid/md_ddf.c   (contents, props changed)
  head/sys/geom/raid/md_ddf.h   (contents, props changed)
Modified:
  head/sbin/geom/class/raid/graid.8
  head/sys/conf/files
  head/sys/modules/geom/geom_raid/Makefile

Modified: head/sbin/geom/class/raid/graid.8
==============================================================================
--- head/sbin/geom/class/raid/graid.8	Mon Apr 30 16:16:37 2012	(r234847)
+++ head/sbin/geom/class/raid/graid.8	Mon Apr 30 17:53:02 2012	(r234848)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 19, 2012
+.Dd April 30, 2012
 .Dt GRAID 8
 .Os
 .Sh NAME
@@ -200,6 +200,19 @@ The GEOM RAID class follows a modular de
 formats to be used.
 Support is currently implemented for the following formats:
 .Bl -tag -width "Intel"
+.It DDF
+The format defined by the SNIA Common RAID Disk Data Format v2.0 specification.
+Used by some Adaptec RAID BIOSes and some hardware RAID controllers.
+Because of high format flexibility different implementations support
+different set of features and have different on-disk metadata layouts.
+To provide compatibility, the GEOM RAID class mimics capabilities and
+metadata layout of the first detected DDF array.
+Respecting that, it may support different number of disks per volume,
+volumes per array, partitions per disk, etc.
+The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks),
+RAID1E (3+ disks), RAID3 (3+ disks), RAID4 (3+ disks), RAID5 (3+ disks),
+RAID5E (4+ disks), RAID5EE (4+ disks), RAID5R (3+ disks), RAID6 (4+ disks),
+RAIDMDF (5+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks).
 .It Intel
 The format used by Intel RAID BIOS.
 Supports up to two volumes per array.

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Apr 30 16:16:37 2012	(r234847)
+++ head/sys/conf/files	Mon Apr 30 17:53:02 2012	(r234848)
@@ -2396,6 +2396,7 @@ geom/raid/g_raid.c		optional geom_raid
 geom/raid/g_raid_ctl.c		optional geom_raid
 geom/raid/g_raid_md_if.m	optional geom_raid
 geom/raid/g_raid_tr_if.m	optional geom_raid
+geom/raid/md_ddf.c		optional geom_raid
 geom/raid/md_intel.c		optional geom_raid
 geom/raid/md_jmicron.c		optional geom_raid
 geom/raid/md_nvidia.c		optional geom_raid

Added: head/sys/geom/raid/md_ddf.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/geom/raid/md_ddf.c	Mon Apr 30 17:53:02 2012	(r234848)
@@ -0,0 +1,2900 @@
+/*-
+ * Copyright (c) 2012 Alexander Motin <mav@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.
+ * 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bio.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/clock.h>
+#include <geom/geom.h>
+#include "geom/raid/g_raid.h"
+#include "geom/raid/md_ddf.h"
+#include "g_raid_md_if.h"
+
+static MALLOC_DEFINE(M_MD_DDF, "md_ddf_data", "GEOM_RAID DDF metadata");
+
+#define	DDF_MAX_DISKS_HARD	128
+
+#define	DDF_MAX_DISKS	16
+#define	DDF_MAX_VDISKS	7
+#define	DDF_MAX_PARTITIONS	1
+
+#define DECADE (3600*24*(365*10+2))	/* 10 years in seconds. */
+
+struct ddf_meta {
+	u_int	sectorsize;
+	u_int	bigendian;
+	struct ddf_header *hdr;
+	struct ddf_cd_record *cdr;
+	struct ddf_pd_record *pdr;
+	struct ddf_vd_record *vdr;
+	void *cr;
+	struct ddf_pdd_record *pdd;
+	struct ddf_bbm_log *bbm;
+};
+
+struct ddf_vol_meta {
+	u_int	sectorsize;
+	u_int	bigendian;
+	struct ddf_header *hdr;
+	struct ddf_cd_record *cdr;
+	struct ddf_vd_entry *vde;
+	struct ddf_vdc_record *vdc;
+	struct ddf_vdc_record *bvdc[DDF_MAX_DISKS_HARD];
+};
+
+struct g_raid_md_ddf_perdisk {
+	struct ddf_meta	 pd_meta;
+};
+
+struct g_raid_md_ddf_pervolume {
+	struct ddf_vol_meta		 pv_meta;
+	int				 pv_started;
+	struct callout			 pv_start_co;	/* STARTING state timer. */
+};
+
+struct g_raid_md_ddf_object {
+	struct g_raid_md_object	 mdio_base;
+	struct ddf_meta		 mdio_meta;
+	struct callout		 mdio_start_co;	/* STARTING state timer. */
+	int			 mdio_started;
+	int			 mdio_incomplete;
+	struct root_hold_token	*mdio_rootmount; /* Root mount delay token. */
+};
+
+static g_raid_md_create_t g_raid_md_create_ddf;
+static g_raid_md_taste_t g_raid_md_taste_ddf;
+static g_raid_md_event_t g_raid_md_event_ddf;
+static g_raid_md_volume_event_t g_raid_md_volume_event_ddf;
+static g_raid_md_ctl_t g_raid_md_ctl_ddf;
+static g_raid_md_write_t g_raid_md_write_ddf;
+static g_raid_md_fail_disk_t g_raid_md_fail_disk_ddf;
+static g_raid_md_free_disk_t g_raid_md_free_disk_ddf;
+static g_raid_md_free_volume_t g_raid_md_free_volume_ddf;
+static g_raid_md_free_t g_raid_md_free_ddf;
+
+static kobj_method_t g_raid_md_ddf_methods[] = {
+	KOBJMETHOD(g_raid_md_create,	g_raid_md_create_ddf),
+	KOBJMETHOD(g_raid_md_taste,	g_raid_md_taste_ddf),
+	KOBJMETHOD(g_raid_md_event,	g_raid_md_event_ddf),
+	KOBJMETHOD(g_raid_md_volume_event,	g_raid_md_volume_event_ddf),
+	KOBJMETHOD(g_raid_md_ctl,	g_raid_md_ctl_ddf),
+	KOBJMETHOD(g_raid_md_write,	g_raid_md_write_ddf),
+	KOBJMETHOD(g_raid_md_fail_disk,	g_raid_md_fail_disk_ddf),
+	KOBJMETHOD(g_raid_md_free_disk,	g_raid_md_free_disk_ddf),
+	KOBJMETHOD(g_raid_md_free_volume,	g_raid_md_free_volume_ddf),
+	KOBJMETHOD(g_raid_md_free,	g_raid_md_free_ddf),
+	{ 0, 0 }
+};
+
+static struct g_raid_md_class g_raid_md_ddf_class = {
+	"DDF",
+	g_raid_md_ddf_methods,
+	sizeof(struct g_raid_md_ddf_object),
+	.mdc_priority = 100
+};
+
+#define GET8(m, f)	((m)->f)
+#define GET16(m, f)	((m)->bigendian ? be16dec(&(m)->f) : le16dec(&(m)->f))
+#define GET32(m, f)	((m)->bigendian ? be32dec(&(m)->f) : le32dec(&(m)->f))
+#define GET64(m, f)	((m)->bigendian ? be64dec(&(m)->f) : le64dec(&(m)->f))
+#define GET8D(m, f)	(f)
+#define GET16D(m, f)	((m)->bigendian ? be16dec(&f) : le16dec(&f))
+#define GET32D(m, f)	((m)->bigendian ? be32dec(&f) : le32dec(&f))
+#define GET64D(m, f)	((m)->bigendian ? be64dec(&f) : le64dec(&f))
+#define GET8P(m, f)	(*(f))
+#define GET16P(m, f)	((m)->bigendian ? be16dec(f) : le16dec(f))
+#define GET32P(m, f)	((m)->bigendian ? be32dec(f) : le32dec(f))
+#define GET64P(m, f)	((m)->bigendian ? be64dec(f) : le64dec(f))
+
+#define SET8P(m, f, v)							\
+	(*(f) = (v))
+#define SET16P(m, f, v)							\
+	do {								\
+		if ((m)->bigendian)					\
+			be16enc((f), (v));				\
+		else							\
+			le16enc((f), (v));				\
+	} while (0)
+#define SET32P(m, f, v)							\
+	do {								\
+		if ((m)->bigendian)					\
+			be32enc((f), (v));				\
+		else							\
+			le32enc((f), (v));				\
+	} while (0)
+#define SET64P(m, f, v)							\
+	do {								\
+		if ((m)->bigendian)					\
+			be64enc((f), (v));				\
+		else							\
+			le64enc((f), (v));				\
+	} while (0)
+#define SET8(m, f, v)	SET8P((m), &((m)->f), (v))
+#define SET16(m, f, v)	SET16P((m), &((m)->f), (v))
+#define SET32(m, f, v)	SET32P((m), &((m)->f), (v))
+#define SET64(m, f, v)	SET64P((m), &((m)->f), (v))
+#define SET8D(m, f, v)	SET8P((m), &(f), (v))
+#define SET16D(m, f, v)	SET16P((m), &(f), (v))
+#define SET32D(m, f, v)	SET32P((m), &(f), (v))
+#define SET64D(m, f, v)	SET64P((m), &(f), (v))
+
+static int
+isff(uint8_t *buf, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		if (buf[i] != 0xff)
+			return (0);
+	return (1);
+}
+
+static void
+print_guid(uint8_t *buf)
+{
+	int i, ascii;
+
+	ascii = 1;
+	for (i = 0; i < 24; i++) {
+		if (buf[i] != 0 && (buf[i] < ' ' || buf[i] > 127)) {
+			ascii = 0;
+			break;
+		}
+	}
+	if (ascii) {
+		printf("'%.24s'", buf);
+	} else {
+		for (i = 0; i < 24; i++)
+			printf("%02x", buf[i]);
+	}
+}
+
+static void
+g_raid_md_ddf_print(struct ddf_meta *meta)
+{
+	struct ddf_vdc_record *vdc;
+	struct ddf_vuc_record *vuc;
+	struct ddf_sa_record *sa;
+	uint64_t *val2;
+	uint32_t val;
+	int i, j, k, num, num2;
+
+	if (g_raid_debug < 1)
+		return;
+
+	printf("********* DDF Metadata *********\n");
+	printf("**** Header ****\n");
+	printf("DDF_Header_GUID      ");
+	print_guid(meta->hdr->DDF_Header_GUID);
+	printf("\n");
+	printf("DDF_rev              %8.8s\n", (char *)&meta->hdr->DDF_rev[0]);
+	printf("Sequence_Number      0x%08x\n", GET32(meta, hdr->Sequence_Number));
+	printf("TimeStamp            0x%08x\n", GET32(meta, hdr->TimeStamp));
+	printf("Open_Flag            0x%02x\n", GET16(meta, hdr->Open_Flag));
+	printf("Foreign_Flag         0x%02x\n", GET16(meta, hdr->Foreign_Flag));
+	printf("Diskgrouping         0x%02x\n", GET16(meta, hdr->Diskgrouping));
+	printf("Primary_Header_LBA   %ju\n", GET64(meta, hdr->Primary_Header_LBA));
+	printf("Secondary_Header_LBA %ju\n", GET64(meta, hdr->Secondary_Header_LBA));
+	printf("WorkSpace_Length     %u\n", GET32(meta, hdr->WorkSpace_Length));
+	printf("WorkSpace_LBA        %ju\n", GET64(meta, hdr->WorkSpace_LBA));
+	printf("Max_PD_Entries       %u\n", GET16(meta, hdr->Max_PD_Entries));
+	printf("Max_VD_Entries       %u\n", GET16(meta, hdr->Max_VD_Entries));
+	printf("Max_Partitions       %u\n", GET16(meta, hdr->Max_Partitions));
+	printf("Configuration_Record_Length %u\n", GET16(meta, hdr->Configuration_Record_Length));
+	printf("Max_Primary_Element_Entries %u\n", GET16(meta, hdr->Max_Primary_Element_Entries));
+	printf("Controller Data      %u:%u\n", GET32(meta, hdr->cd_section), GET32(meta, hdr->cd_length));
+	printf("Physical Disk        %u:%u\n", GET32(meta, hdr->pdr_section), GET32(meta, hdr->pdr_length));
+	printf("Virtual Disk         %u:%u\n", GET32(meta, hdr->vdr_section), GET32(meta, hdr->vdr_length));
+	printf("Configuration Recs   %u:%u\n", GET32(meta, hdr->cr_section), GET32(meta, hdr->cr_length));
+	printf("Physical Disk Recs   %u:%u\n", GET32(meta, hdr->pdd_section), GET32(meta, hdr->pdd_length));
+	printf("BBM Log              %u:%u\n", GET32(meta, hdr->bbmlog_section), GET32(meta, hdr->bbmlog_length));
+	printf("Diagnostic Space     %u:%u\n", GET32(meta, hdr->Diagnostic_Space), GET32(meta, hdr->Diagnostic_Space_Length));
+	printf("Vendor_Specific_Logs %u:%u\n", GET32(meta, hdr->Vendor_Specific_Logs), GET32(meta, hdr->Vendor_Specific_Logs_Length));
+	printf("**** Controler Data ****\n");
+	printf("Controller_GUID      ");
+	print_guid(meta->cdr->Controller_GUID);
+	printf("\n");
+	printf("Controller_Type      0x%04x%04x 0x%04x%04x\n",
+	    GET16(meta, cdr->Controller_Type.Vendor_ID),
+	    GET16(meta, cdr->Controller_Type.Device_ID),
+	    GET16(meta, cdr->Controller_Type.SubVendor_ID),
+	    GET16(meta, cdr->Controller_Type.SubDevice_ID));
+	printf("Product_ID           '%.16s'\n", (char *)&meta->cdr->Product_ID[0]);
+	printf("**** Physical Disk Data ****\n");
+	printf("Populated_PDEs       %u\n", GET16(meta, pdr->Populated_PDEs));
+	printf("Max_PDE_Supported    %u\n", GET16(meta, pdr->Max_PDE_Supported));
+	for (j = 0; j < GET16(meta, pdr->Populated_PDEs); j++) {
+		if (isff(meta->pdr->entry[j].PD_GUID, 24))
+			continue;
+		if (GET32(meta, pdr->entry[j].PD_Reference) == 0xffffffff)
+			continue;
+		printf("PD_GUID              ");
+		print_guid(meta->pdr->entry[j].PD_GUID);
+		printf("\n");
+		printf("PD_Reference         0x%08x\n",
+		    GET32(meta, pdr->entry[j].PD_Reference));
+		printf("PD_Type              0x%04x\n",
+		    GET16(meta, pdr->entry[j].PD_Type));
+		printf("PD_State             0x%04x\n",
+		    GET16(meta, pdr->entry[j].PD_State));
+		printf("Configured_Size      %ju\n",
+		    GET64(meta, pdr->entry[j].Configured_Size));
+		printf("Block_Size           %u\n",
+		    GET16(meta, pdr->entry[j].Block_Size));
+	}
+	printf("**** Virtual Disk Data ****\n");
+	printf("Populated_VDEs       %u\n", GET16(meta, vdr->Populated_VDEs));
+	printf("Max_VDE_Supported    %u\n", GET16(meta, vdr->Max_VDE_Supported));
+	for (j = 0; j < GET16(meta, vdr->Populated_VDEs); j++) {
+		if (isff(meta->vdr->entry[j].VD_GUID, 24))
+			continue;
+		printf("VD_GUID              ");
+		print_guid(meta->vdr->entry[j].VD_GUID);
+		printf("\n");
+		printf("VD_Number            0x%04x\n",
+		    GET16(meta, vdr->entry[j].VD_Number));
+		printf("VD_Type              0x%02x\n",
+		    GET8(meta, vdr->entry[j].VD_Type));
+		printf("VD_State             0x%02x\n",
+		    GET8(meta, vdr->entry[j].VD_State));
+		printf("Init_State           0x%02x\n",
+		    GET8(meta, vdr->entry[j].Init_State));
+		printf("Drive_Failures_Remaining %u\n",
+		    GET8(meta, vdr->entry[j].Drive_Failures_Remaining));
+		printf("VD_Name              '%.16s'\n",
+		    (char *)&meta->vdr->entry[j].VD_Name);
+	}
+	printf("**** Configuration Records ****\n");
+	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
+	for (j = 0; j < num; j++) {
+		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
+		    j * GET16(meta, hdr->Configuration_Record_Length) *
+		    meta->sectorsize);
+		val = GET32D(meta, vdc->Signature);
+		switch (val) {
+		case DDF_VDCR_SIGNATURE:
+			printf("** Virtual Disk Configuration **\n");
+			printf("VD_GUID              ");
+			print_guid(vdc->VD_GUID);
+			printf("\n");
+			printf("Timestamp            0x%08x\n",
+			    GET32D(meta, vdc->Timestamp));
+			printf("Sequence_Number      0x%08x\n",
+			    GET32D(meta, vdc->Sequence_Number));
+			printf("Primary_Element_Count %u\n",
+			    GET16D(meta, vdc->Primary_Element_Count));
+			printf("Stripe_Size          %u\n",
+			    GET8D(meta, vdc->Stripe_Size));
+			printf("Primary_RAID_Level   0x%02x\n",
+			    GET8D(meta, vdc->Primary_RAID_Level));
+			printf("RLQ                  0x%02x\n",
+			    GET8D(meta, vdc->RLQ));
+			printf("Secondary_Element_Count %u\n",
+			    GET8D(meta, vdc->Secondary_Element_Count));
+			printf("Secondary_Element_Seq %u\n",
+			    GET8D(meta, vdc->Secondary_Element_Seq));
+			printf("Secondary_RAID_Level 0x%02x\n",
+			    GET8D(meta, vdc->Secondary_RAID_Level));
+			printf("Block_Count          %ju\n",
+			    GET64D(meta, vdc->Block_Count));
+			printf("VD_Size              %ju\n",
+			    GET64D(meta, vdc->VD_Size));
+			printf("Block_Size           %u\n",
+			    GET16D(meta, vdc->Block_Size));
+			printf("Rotate_Parity_count  %u\n",
+			    GET8D(meta, vdc->Rotate_Parity_count));
+			printf("Associated_Spare_Disks");
+			for (i = 0; i < 8; i++) {
+				if (GET32D(meta, vdc->Associated_Spares[i]) != 0xffffffff)
+					printf(" 0x%08x", GET32D(meta, vdc->Associated_Spares[i]));
+			}
+			printf("\n");
+			printf("Cache_Flags          %016jx\n",
+			    GET64D(meta, vdc->Cache_Flags));
+			printf("BG_Rate              %u\n",
+			    GET8D(meta, vdc->BG_Rate));
+			printf("MDF_Parity_Disks     %u\n",
+			    GET8D(meta, vdc->MDF_Parity_Disks));
+			printf("MDF_Parity_Generator_Polynomial 0x%04x\n",
+			    GET16D(meta, vdc->MDF_Parity_Generator_Polynomial));
+			printf("MDF_Constant_Generation_Method 0x%02x\n",
+			    GET8D(meta, vdc->MDF_Constant_Generation_Method));
+			printf("Physical_Disks      ");
+			num2 = GET16D(meta, vdc->Primary_Element_Count);
+			val2 = (uint64_t *)&(vdc->Physical_Disk_Sequence[GET16(meta, hdr->Max_Primary_Element_Entries)]);
+			for (i = 0; i < num2; i++)
+				printf(" 0x%08x @ %ju",
+				    GET32D(meta, vdc->Physical_Disk_Sequence[i]),
+				    GET64P(meta, val2 + i));
+			printf("\n");
+			break;
+		case DDF_VUCR_SIGNATURE:
+			printf("** Vendor Unique Configuration **\n");
+			vuc = (struct ddf_vuc_record *)vdc;
+			printf("VD_GUID              ");
+			print_guid(vuc->VD_GUID);
+			printf("\n");
+			break;
+		case DDF_SA_SIGNATURE:
+			printf("** Spare Assignment Configuration **\n");
+			sa = (struct ddf_sa_record *)vdc;
+			printf("Timestamp            0x%08x\n",
+			    GET32D(meta, sa->Timestamp));
+			printf("Spare_Type           0x%02x\n",
+			    GET8D(meta, sa->Spare_Type));
+			printf("Populated_SAEs       %u\n",
+			    GET16D(meta, sa->Populated_SAEs));
+			printf("MAX_SAE_Supported    %u\n",
+			    GET16D(meta, sa->MAX_SAE_Supported));
+			for (i = 0; i < GET16D(meta, sa->Populated_SAEs); i++) {
+				if (isff(sa->entry[i].VD_GUID, 24))
+					continue;
+				printf("VD_GUID             ");
+				for (k = 0; k < 24; k++)
+					printf("%02x", sa->entry[i].VD_GUID[k]);
+				printf("\n");
+				printf("Secondary_Element   %u\n",
+				    GET16D(meta, sa->entry[i].Secondary_Element));
+			}
+			break;
+		case 0xFFFFFFFF:
+			break;
+		default:
+			printf("Unknown configuration signature %08x\n", val);
+			break;
+		}
+	}
+	printf("**** Physical Disk Data ****\n");
+	printf("PD_GUID              ");
+	print_guid(meta->pdd->PD_GUID);
+	printf("\n");
+	printf("PD_Reference         0x%08x\n",
+	    GET32(meta, pdd->PD_Reference));
+	printf("Forced_Ref_Flag      0x%02x\n",
+	    GET8(meta, pdd->Forced_Ref_Flag));
+	printf("Forced_PD_GUID_Flag  0x%02x\n",
+	    GET8(meta, pdd->Forced_PD_GUID_Flag));
+}
+
+static int
+ddf_meta_find_pd(struct ddf_meta *meta, uint8_t *GUID, uint32_t PD_Reference)
+{
+	int i;
+
+	for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
+		if (GUID != NULL) {
+			if (memcmp(meta->pdr->entry[i].PD_GUID, GUID, 24) == 0)
+				return (i);
+		} else if (PD_Reference != 0xffffffff) {
+			if (GET32(meta, pdr->entry[i].PD_Reference) == PD_Reference)
+				return (i);
+		} else
+			if (isff(meta->pdr->entry[i].PD_GUID, 24))
+				return (i);
+	}
+	if (GUID == NULL && PD_Reference == 0xffffffff) {
+		if (i >= GET16(meta, pdr->Max_PDE_Supported))
+			return (-1);
+		SET16(meta, pdr->Populated_PDEs, i + 1);
+		return (i);
+	}
+	return (-1);
+}
+
+static int
+ddf_meta_find_vd(struct ddf_meta *meta, uint8_t *GUID)
+{
+	int i;
+
+	for (i = 0; i < GET16(meta, vdr->Populated_VDEs); i++) {
+		if (GUID != NULL) {
+			if (memcmp(meta->vdr->entry[i].VD_GUID, GUID, 24) == 0)
+				return (i);
+		} else
+			if (isff(meta->vdr->entry[i].VD_GUID, 24))
+				return (i);
+	}
+	if (GUID == NULL) {
+		if (i >= GET16(meta, vdr->Max_VDE_Supported))
+			return (-1);
+		SET16(meta, vdr->Populated_VDEs, i + 1);
+		return (i);
+	}
+	return (-1);
+}
+
+static struct ddf_vdc_record *
+ddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID)
+{
+	struct ddf_vdc_record *vdc;
+	int i, num;
+
+	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
+	for (i = 0; i < num; i++) {
+		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
+		    i * GET16(meta, hdr->Configuration_Record_Length) *
+		    meta->sectorsize);
+		if (GUID != NULL) {
+			if (GET32D(meta, vdc->Signature) == DDF_VDCR_SIGNATURE &&
+			    memcmp(vdc->VD_GUID, GUID, 24) == 0)
+				return (vdc);
+		} else
+			if (GET32D(meta, vdc->Signature) == 0xffffffff)
+				return (vdc);
+	}
+	return (NULL);
+}
+
+static int
+ddf_meta_count_vdc(struct ddf_meta *meta, uint8_t *GUID)
+{
+	struct ddf_vdc_record *vdc;
+	int i, num, cnt;
+
+	cnt = 0;
+	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
+	for (i = 0; i < num; i++) {
+		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
+		    i * GET16(meta, hdr->Configuration_Record_Length) *
+		    meta->sectorsize);
+		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
+			continue;
+		if (GUID == NULL || memcmp(vdc->VD_GUID, GUID, 24) == 0)
+			cnt++;
+	}
+	return (cnt);
+}
+
+static int
+ddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference,
+    int *bvdp, int *posp)
+{
+	int i, bvd, pos;
+
+	i = 0;
+	for (bvd = 0; bvd < GET16(vmeta, vdc->Secondary_Element_Count); bvd++) {
+		if (vmeta->bvdc[bvd] == NULL) {
+			i += GET16(vmeta, vdc->Primary_Element_Count); // XXX
+			continue;
+		}
+		for (pos = 0; pos < GET16(vmeta, bvdc[bvd]->Primary_Element_Count);
+		    pos++, i++) {
+			if (GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]) ==
+			    PD_Reference) {
+				if (bvdp != NULL)
+					*bvdp = bvd;
+				if (posp != NULL)
+					*posp = pos;
+				return (i);
+			}
+		}
+	}
+	return (-1);
+}
+
+static void
+ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
+{
+	struct timespec ts;
+	struct clocktime ct;
+	struct g_raid_md_ddf_perdisk *pd;
+	struct ddf_meta *meta;
+	struct ddf_pd_entry *pde;
+	off_t anchorlba;
+	u_int ss, pos, size;
+	int len, error;
+	char serial_buffer[24];
+
+	if (sample->hdr == NULL)
+		sample = NULL;
+
+	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
+	meta = &pd->pd_meta;
+	ss = disk->d_consumer->provider->sectorsize;
+	anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
+
+	meta->sectorsize = ss;
+	meta->bigendian = sample ? sample->bigendian : 0;
+	getnanotime(&ts);
+	clock_ts_to_ct(&ts, &ct);
+
+	/* Header */
+	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
+	memset(meta->hdr, 0xff, ss);
+	if (sample) {
+		memcpy(meta->hdr, sample->hdr, sizeof(struct ddf_header));
+		if (ss != sample->sectorsize) {
+			SET32(meta, hdr->WorkSpace_Length,
+			    (GET32(sample, hdr->WorkSpace_Length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET16(meta, hdr->Configuration_Record_Length,
+			    (GET16(sample, hdr->Configuration_Record_Length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->cd_length,
+			    (GET32(sample, hdr->cd_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->pdr_length,
+			    (GET32(sample, hdr->pdr_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->vdr_length,
+			    (GET32(sample, hdr->vdr_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->cr_length,
+			    (GET32(sample, hdr->cr_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->pdd_length,
+			    (GET32(sample, hdr->pdd_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->bbmlog_length,
+			    (GET32(sample, hdr->bbmlog_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->Diagnostic_Space,
+			    (GET32(sample, hdr->bbmlog_length) *
+			    sample->sectorsize + ss - 1) / ss);
+			SET32(meta, hdr->Vendor_Specific_Logs,
+			    (GET32(sample, hdr->bbmlog_length) *
+			    sample->sectorsize + ss - 1) / ss);
+		}
+	} else {
+		SET32(meta, hdr->Signature, DDF_HEADER_SIGNATURE);
+		snprintf(meta->hdr->DDF_Header_GUID, 25, "FreeBSD %08x%08x",
+		    (u_int)(ts.tv_sec - DECADE), arc4random());
+		memcpy(meta->hdr->DDF_rev, "02.00.00", 8);
+		SET32(meta, hdr->TimeStamp, (ts.tv_sec - DECADE));
+		SET32(meta, hdr->WorkSpace_Length, 16 * 1024 * 1024 / ss);
+		SET16(meta, hdr->Max_PD_Entries, DDF_MAX_DISKS - 1);
+		SET16(meta, hdr->Max_VD_Entries, DDF_MAX_VDISKS);
+		SET16(meta, hdr->Max_Partitions, DDF_MAX_PARTITIONS);
+		SET16(meta, hdr->Max_Primary_Element_Entries, DDF_MAX_DISKS);
+		SET16(meta, hdr->Configuration_Record_Length,
+		    (sizeof(struct ddf_vdc_record) +
+		     (4 + 8) * GET16(meta, hdr->Max_Primary_Element_Entries) +
+		     ss - 1) / ss);
+		SET32(meta, hdr->cd_length,
+		    (sizeof(struct ddf_cd_record) + ss - 1) / ss);
+		SET32(meta, hdr->pdr_length,
+		    (sizeof(struct ddf_pd_record) +
+		     sizeof(struct ddf_pd_entry) *
+		     GET16(meta, hdr->Max_PD_Entries) + ss - 1) / ss);
+		SET32(meta, hdr->vdr_length,
+		    (sizeof(struct ddf_vd_record) +
+		     sizeof(struct ddf_vd_entry) *
+		     GET16(meta, hdr->Max_VD_Entries) + ss - 1) / ss);
+		SET32(meta, hdr->cr_length,
+		    GET16(meta, hdr->Configuration_Record_Length) *
+		    (GET16(meta, hdr->Max_Partitions) + 1));
+		SET32(meta, hdr->pdd_length,
+		    (sizeof(struct ddf_pdd_record) + ss - 1) / ss);
+		SET32(meta, hdr->bbmlog_length, 0);
+		SET32(meta, hdr->Diagnostic_Space_Length, 0);
+		SET32(meta, hdr->Vendor_Specific_Logs_Length, 0);
+	}
+	pos = 1;
+	SET32(meta, hdr->cd_section, pos);
+	pos += GET32(meta, hdr->cd_length);
+	SET32(meta, hdr->pdr_section, pos);
+	pos += GET32(meta, hdr->pdr_length);
+	SET32(meta, hdr->vdr_section, pos);
+	pos += GET32(meta, hdr->vdr_length);
+	SET32(meta, hdr->cr_section, pos);
+	pos += GET32(meta, hdr->cr_length);
+	SET32(meta, hdr->pdd_section, pos);
+	pos += GET32(meta, hdr->pdd_length);
+	SET32(meta, hdr->bbmlog_section,
+	    GET32(meta, hdr->bbmlog_length) != 0 ? pos : 0xffffffff);
+	pos += GET32(meta, hdr->bbmlog_length);
+	SET32(meta, hdr->Diagnostic_Space,
+	    GET32(meta, hdr->Diagnostic_Space_Length) != 0 ? pos : 0xffffffff);
+	pos += GET32(meta, hdr->Diagnostic_Space_Length);
+	SET32(meta, hdr->Vendor_Specific_Logs,
+	    GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff);
+	pos += GET32(meta, hdr->Vendor_Specific_Logs_Length);
+	SET64(meta, hdr->Primary_Header_LBA,
+	    anchorlba - pos - 16);
+	SET64(meta, hdr->Secondary_Header_LBA,
+	    0xffffffffffffffffULL);
+	SET64(meta, hdr->WorkSpace_LBA,
+	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
+
+	/* Controller Data */
+	size = GET32(meta, hdr->cd_length) * ss;
+	meta->cdr = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->cdr, 0xff, size);
+	SET32(meta, cdr->Signature, DDF_CONTROLLER_DATA_SIGNATURE);
+	memcpy(meta->cdr->Controller_GUID, "FreeBSD GEOM RAID SERIAL", 24);
+	memcpy(meta->cdr->Product_ID, "FreeBSD GEOMRAID", 16);
+
+	/* Physical Drive Records. */
+	size = GET32(meta, hdr->pdr_length) * ss;
+	meta->pdr = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->pdr, 0xff, size);
+	SET32(meta, pdr->Signature, DDF_PDR_SIGNATURE);
+	SET16(meta, pdr->Populated_PDEs, 1);
+	SET16(meta, pdr->Max_PDE_Supported,
+	    GET16(meta, hdr->Max_PD_Entries));
+
+	pde = &meta->pdr->entry[0];
+	len = sizeof(serial_buffer);
+	error = g_io_getattr("GEOM::ident", disk->d_consumer, &len, serial_buffer);
+	if (error == 0 && (len = strlen (serial_buffer)) >= 6 && len <= 20)
+		snprintf(pde->PD_GUID, 25, "DISK%20s", serial_buffer);
+	else
+		snprintf(pde->PD_GUID, 25, "DISK%04d%02d%02d%08x%04x",
+		    ct.year, ct.mon, ct.day,
+		    arc4random(), arc4random() & 0xffff);
+	SET32D(meta, pde->PD_Reference, arc4random());
+	SET16D(meta, pde->PD_Type, DDF_PDE_GUID_FORCE);
+	SET16D(meta, pde->PD_State, 0);
+	SET64D(meta, pde->Configured_Size,
+	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
+	SET16D(meta, pde->Block_Size, ss);
+
+	/* Virtual Drive Records. */
+	size = GET32(meta, hdr->vdr_length) * ss;
+	meta->vdr = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->vdr, 0xff, size);
+	SET32(meta, vdr->Signature, DDF_VD_RECORD_SIGNATURE);
+	SET32(meta, vdr->Populated_VDEs, 0);
+	SET16(meta, vdr->Max_VDE_Supported,
+	    GET16(meta, hdr->Max_VD_Entries));
+
+	/* Configuration Records. */
+	size = GET32(meta, hdr->cr_length) * ss;
+	meta->cr = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->cr, 0xff, size);
+
+	/* Physical Disk Data. */
+	size = GET32(meta, hdr->pdd_length) * ss;
+	meta->pdd = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->pdd, 0xff, size);
+	SET32(meta, pdd->Signature, DDF_PDD_SIGNATURE);
+	memcpy(meta->pdd->PD_GUID, pde->PD_GUID, 24);
+	SET32(meta, pdd->PD_Reference, GET32D(meta, pde->PD_Reference));
+	SET8(meta, pdd->Forced_Ref_Flag, DDF_PDD_FORCED_REF);
+	SET8(meta, pdd->Forced_PD_GUID_Flag, DDF_PDD_FORCED_GUID);
+
+	/* Bad Block Management Log. */
+	if (GET32(meta, hdr->bbmlog_length) != 0) {
+		size = GET32(meta, hdr->bbmlog_length) * ss;
+		meta->bbm = malloc(size, M_MD_DDF, M_WAITOK);
+		memset(meta->bbm, 0xff, size);
+		SET32(meta, bbm->Signature, DDF_BBML_SIGNATURE);
+		SET32(meta, bbm->Entry_Count, 0);
+		SET32(meta, bbm->Spare_Block_Count, 0);
+	}
+}
+
+static void
+ddf_meta_copy(struct ddf_meta *dst, struct ddf_meta *src)
+{
+	struct ddf_header *hdr;
+	u_int ss;
+
+	hdr = src->hdr;
+	dst->bigendian = src->bigendian;
+	ss = dst->sectorsize = src->sectorsize;
+	dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->hdr, src->hdr, ss);
+	dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
+	dst->pdr = malloc(GET32(src, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->pdr, src->pdr, GET32(src, hdr->pdr_length) * ss);
+	dst->vdr = malloc(GET32(src, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->vdr, src->vdr, GET32(src, hdr->vdr_length) * ss);
+	dst->cr = malloc(GET32(src, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->cr, src->cr, GET32(src, hdr->cr_length) * ss);
+	dst->pdd = malloc(GET32(src, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(dst->pdd, src->pdd, GET32(src, hdr->pdd_length) * ss);
+	if (src->bbm != NULL) {
+		dst->bbm = malloc(GET32(src, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
+		memcpy(dst->bbm, src->bbm, GET32(src, hdr->bbmlog_length) * ss);
+	}
+}
+
+static void
+ddf_meta_update(struct ddf_meta *meta, struct ddf_meta *src)
+{
+	struct ddf_pd_entry *pde, *spde;
+	int i, j;
+
+	for (i = 0; i < GET16(src, pdr->Populated_PDEs); i++) {
+		spde = &src->pdr->entry[i];
+		if (isff(spde->PD_GUID, 24))
+			continue;
+		j = ddf_meta_find_pd(meta, NULL,
+		    src->pdr->entry[i].PD_Reference);
+		if (j < 0) {
+			j = ddf_meta_find_pd(meta, NULL, 0xffffffff);
+			pde = &meta->pdr->entry[j];
+			memcpy(pde, spde, sizeof(*pde));
+		} else {
+			pde = &meta->pdr->entry[j];
+			SET16D(meta, pde->PD_State,
+			    GET16D(meta, pde->PD_State) |
+			    GET16D(src, pde->PD_State));
+		}
+	}
+}
+
+static void
+ddf_meta_free(struct ddf_meta *meta)
+{
+
+	if (meta->hdr != NULL) {
+		free(meta->hdr, M_MD_DDF);
+		meta->hdr = NULL;
+	}
+	if (meta->cdr != NULL) {
+		free(meta->cdr, M_MD_DDF);
+		meta->cdr = NULL;
+	}
+	if (meta->pdr != NULL) {
+		free(meta->pdr, M_MD_DDF);
+		meta->pdr = NULL;
+	}
+	if (meta->vdr != NULL) {
+		free(meta->vdr, M_MD_DDF);
+		meta->vdr = NULL;
+	}
+	if (meta->cr != NULL) {
+		free(meta->cr, M_MD_DDF);
+		meta->cr = NULL;
+	}
+	if (meta->pdd != NULL) {
+		free(meta->pdd, M_MD_DDF);
+		meta->pdd = NULL;
+	}
+	if (meta->bbm != NULL) {
+		free(meta->bbm, M_MD_DDF);
+		meta->bbm = NULL;
+	}
+}
+
+static void
+ddf_vol_meta_create(struct ddf_vol_meta *meta, struct ddf_meta *sample)
+{
+	struct timespec ts;
+	struct clocktime ct;
+	struct ddf_header *hdr;
+	u_int ss, size;
+
+	hdr = sample->hdr;
+	meta->bigendian = sample->bigendian;
+	ss = meta->sectorsize = sample->sectorsize;
+	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
+	memcpy(meta->hdr, sample->hdr, ss);
+	meta->cdr = malloc(GET32(sample, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
+	memcpy(meta->cdr, sample->cdr, GET32(sample, hdr->cd_length) * ss);
+	meta->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
+	memset(meta->vde, 0xff, sizeof(struct ddf_vd_entry));
+	getnanotime(&ts);
+	clock_ts_to_ct(&ts, &ct);
+	snprintf(meta->vde->VD_GUID, 25, "FreeBSD%04d%02d%02d%08x%01x",
+	    ct.year, ct.mon, ct.day,
+	    arc4random(), arc4random() & 0xf);
+	size = GET16(sample, hdr->Configuration_Record_Length) * ss;
+	meta->vdc = malloc(size, M_MD_DDF, M_WAITOK);
+	memset(meta->vdc, 0xff, size);
+	SET32(meta, vdc->Signature, DDF_VDCR_SIGNATURE);
+	memcpy(meta->vdc->VD_GUID, meta->vde->VD_GUID, 24);
+	SET32(meta, vdc->Sequence_Number, 0);
+}
+
+static void
+ddf_vol_meta_update(struct ddf_vol_meta *dst, struct ddf_meta *src, uint8_t *GUID)
+{
+	struct ddf_header *hdr;
+	struct ddf_vd_entry *vde;
+	struct ddf_vdc_record *vdc;
+	int vnew, bvnew, bvd, size;
+	u_int ss;
+
+	hdr = src->hdr;
+	vde = &src->vdr->entry[ddf_meta_find_vd(src, GUID)];
+	vdc = ddf_meta_find_vdc(src, GUID);
+	bvd = GET8D(src, vdc->Secondary_Element_Seq);
+	size = GET16(src, hdr->Configuration_Record_Length) * src->sectorsize;
+
+	if (dst->vdc == NULL ||
+	    ((int32_t)(GET32D(src, vdc->Sequence_Number) -
+	    GET32(dst, vdc->Sequence_Number))) > 0)
+		vnew = 1;
+	else
+		vnew = 0;
+
+	if (dst->bvdc[bvd] == NULL ||
+	    ((int32_t)(GET32D(src, vdc->Sequence_Number) -
+	    GET32(dst, bvdc[bvd]->Sequence_Number))) > 0)
+		bvnew = 1;
+	else
+		bvnew = 0;
+
+	if (vnew) {
+		dst->bigendian = src->bigendian;
+		ss = dst->sectorsize = src->sectorsize;
+		if (dst->hdr != NULL)
+			free(dst->hdr, M_MD_DDF);
+		dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
+		memcpy(dst->hdr, src->hdr, ss);
+		if (dst->cdr != NULL)
+			free(dst->cdr, M_MD_DDF);
+		dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
+		memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
+		if (dst->vde != NULL)
+			free(dst->vde, M_MD_DDF);
+		dst->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
+		memcpy(dst->vde, vde, sizeof(struct ddf_vd_entry));
+		if (dst->vdc != NULL)
+			free(dst->vdc, M_MD_DDF);
+		dst->vdc = malloc(size, M_MD_DDF, M_WAITOK);
+		memcpy(dst->vdc, vdc, size);
+	}
+	if (bvnew) {
+		if (dst->bvdc[bvd] != NULL)
+			free(dst->bvdc[bvd], M_MD_DDF);
+		dst->bvdc[bvd] = malloc(size, M_MD_DDF, M_WAITOK);
+		memcpy(dst->bvdc[bvd], vdc, size);
+	}
+}
+
+static void
+ddf_vol_meta_free(struct ddf_vol_meta *meta)
+{
+	int i;
+
+	if (meta->hdr != NULL) {
+		free(meta->hdr, M_MD_DDF);
+		meta->hdr = NULL;
+	}
+	if (meta->cdr != NULL) {
+		free(meta->cdr, M_MD_DDF);
+		meta->cdr = NULL;
+	}
+	if (meta->vde != NULL) {
+		free(meta->vde, M_MD_DDF);
+		meta->vde = NULL;
+	}
+	if (meta->vdc != NULL) {
+		free(meta->vdc, M_MD_DDF);
+		meta->vdc = NULL;
+	}
+	for (i = 0; i < DDF_MAX_DISKS_HARD; i++) {
+		if (meta->bvdc[i] != NULL) {
+			free(meta->bvdc[i], M_MD_DDF);
+			meta->bvdc[i] = NULL;
+		}
+	}
+}
+
+static int
+ddf_meta_unused_range(struct ddf_meta *meta, off_t *off, off_t *size)
+{
+	struct ddf_vdc_record *vdc;
+	off_t beg[32], end[32], beg1, end1;
+	uint64_t *offp;
+	int i, j, n, num, pos;
+	uint32_t ref;
+
+	*off = 0;
+	*size = 0;
+	ref = GET32(meta, pdd->PD_Reference);
+	pos = ddf_meta_find_pd(meta, NULL, ref);
+	beg[0] = 0;
+	end[0] = GET64(meta, pdr->entry[pos].Configured_Size);
+	n = 1;
+	num = GET32(meta, hdr->cr_length) /
+	    GET16(meta, hdr->Configuration_Record_Length);
+	for (i = 0; i < num; i++) {
+		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
+		    i * GET16(meta, hdr->Configuration_Record_Length) *
+		    meta->sectorsize);
+		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
+			continue;
+		for (pos = 0; pos < GET16D(meta, vdc->Primary_Element_Count); pos++)
+			if (GET32D(meta, vdc->Physical_Disk_Sequence[pos]) == ref)
+				break;
+		if (pos == GET16D(meta, vdc->Primary_Element_Count))
+			continue;
+		offp = (uint64_t *)&(vdc->Physical_Disk_Sequence[
+		    GET16(meta, hdr->Max_Primary_Element_Entries)]);
+		beg1 = GET64P(meta, offp + pos);
+		end1 = beg1 + GET64D(meta, vdc->Block_Count);
+		for (j = 0; j < n; j++) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204301753.q3UHr2XI077126>