Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Feb 2009 06:10:12 +0000 (UTC)
From:      Scott Long <scottl@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r188840 - head/sys/dev/ata
Message-ID:  <200902200610.n1K6ACM1018370@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: scottl
Date: Fri Feb 20 06:10:12 2009
New Revision: 188840
URL: http://svn.freebsd.org/changeset/base/188840

Log:
  Add basic support for DDF, often found on Adaptec HostRAID controllers.
  Spares and rebuilds are not supported, so this code should be considered
  for entertainment purposes only.

Added:
  head/sys/dev/ata/ata-raid-ddf.h   (contents, props changed)
Modified:
  head/sys/dev/ata/ata-raid.c
  head/sys/dev/ata/ata-raid.h

Added: head/sys/dev/ata/ata-raid-ddf.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/ata/ata-raid-ddf.h	Fri Feb 20 06:10:12 2009	(r188840)
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2008 Scott Long
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ATA_RAID_DDF_H
+#define ATA_RAID_DDF_H
+
+/* Definitions from the SNIA DDF spec, rev 1.2 */
+
+#define	DDF_HEADER_LENGTH		512
+struct ddf_header {
+	uint32_t	Signature;
+#define	DDF_HEADER_SIGNATURE	0xde11de11
+	uint32_t	CRC;
+	uint8_t		DDF_Header_GUID[24];
+	uint8_t		DDF_rev[8];
+	uint32_t	Sequence_Number;
+	uint32_t	TimeStamp;
+	uint8_t		Open_Flag;
+#define	DDF_HEADER_CLOSED	0x00
+#define	DDF_HEADER_OPENED_MASK	0x0f
+#define	DDF_HEADER_OPEN_ANCHOR	0xff
+	uint8_t		Foreign_Flag;
+	uint8_t		Diskgrouping;
+	uint8_t		pad1[13];
+	uint8_t		Header_ext[32];
+	uint64_t	Primary_Header_LBA;
+	uint64_t	Secondary_Header_LBA;
+	uint8_t		Header_Type;
+#define	DDF_HEADER_ANCHOR	0x00
+#define	DDF_HEADER_PRIMARY	0x01
+#define	DDF_HEADER_SECONDARY	0x02
+	uint8_t		pad2[3];
+	uint32_t	WorkSpace_Length;
+	uint64_t	WorkSpace_LBA;
+	uint16_t	Max_PD_Entries;
+	uint16_t	Max_VD_Entries;
+	uint16_t	Max_Partitions;
+	uint16_t	Configuration_Record_Length;
+	uint16_t	Max_Primary_Element_Entries;
+	uint8_t		pad3[54];
+	uint32_t	cd_section;	/* Controller_Data_Section */
+	uint32_t	cd_length;	/* Controller_Data_Section_Length */
+	uint32_t	pdr_section;	/* Physical_Drive_Records_Section */
+	uint32_t	pdr_length;	/* Physical_Drive_Records_Length */
+	uint32_t	vdr_section;	/* Virtual_Drive_Records_Section */
+	uint32_t	vdr_length;	/* Virtual_Drive_Records_Length */
+	uint32_t	cr_section;	/* Configuration_Records_Section */
+	uint32_t	cr_length;	/* Configuration_Records_Length */
+	uint32_t	pdd_section;	/* Physical_Drive_Data_Section */
+	uint32_t	pdd_length;	/* Physical_Drive_Data_Length */
+	uint32_t	bbmlog_section;	/* BBM_Log_Section */
+	uint32_t	bbmlog_length;	/* BBM_Log_Section_Length */
+	uint32_t	Diagnostic_Space;
+	uint32_t	Diagnostic_Space_Length;
+	uint32_t	Vendor_Specific_Logs;
+	uint32_t	Vendor_Specific_Logs_Length;
+	uint8_t		pad4[256];
+} __packed;
+
+struct ddf_cd_record {
+	uint32_t	Signature;
+#define	DDF_CONTROLLER_DATA_SIGNATURE	0xad111111
+	uint32_t	CRC;
+	uint8_t		Controller_GUID[24];
+	struct {
+		uint16_t	Vendor_ID;
+		uint16_t	Device_ID;
+		uint16_t	SubVendor_ID;
+		uint16_t	SubDevice_ID;
+	} Controller_Type __packed;
+	uint8_t		Product_ID[16];
+	uint8_t		pad1[8];
+	uint8_t		Controller_Data[448];
+} __packed;
+
+struct ddf_device_scsi {
+	uint8_t		Lun;
+	uint8_t		Id;
+	uint8_t		Channel;
+	uint8_t		Path_Flags;
+#define DDF_DEVICE_SCSI_FLAG_BROKEN	(1 << 7)
+} __packed;
+
+struct ddf_device_sas {
+	uint64_t	Initiator_Path;
+} __packed;
+
+union ddf_pathinfo {
+	struct {
+		struct ddf_device_scsi	Path0;
+		struct ddf_device_scsi	Path1;
+		uint8_t			pad[10];
+	} __packed scsi;
+	struct {
+		struct ddf_device_sas	Path0;
+		struct ddf_device_sas	Path1;
+		uint8_t			Path0_Flags;
+		uint8_t			Path1_Flags;
+#define DDF_DEVICE_SAS_FLAG_BROKEN	(1 << 7)
+	} __packed sas;
+} __packed;
+
+struct ddf_pd_entry {
+	uint8_t			PD_GUID[24];
+	uint32_t		PD_Reference;
+	uint16_t		PD_Type;
+#define	DDF_PDE_GUID_FORCE	(1 << 0)
+#define	DDF_PDE_PARTICIPATING	(1 << 1)
+#define	DDF_PDE_GLOBAL_SPARE	(1 << 2)
+#define	DDF_PDE_CONFIG_SPARE	(1 << 3)
+#define	DDF_PDE_FOREIGN		(1 << 4)
+#define	DDF_PDE_LEGACY		(1 << 5)
+#define DDF_PDE_TYPE_MASK	(0x0f << 12)
+#define DDF_PDE_UNKNOWN		(0x00 << 12)
+#define DDF_PDE_SCSI		(0x01 << 12)
+#define DDF_PDE_SAS		(0x02 << 12)
+#define DDF_PDE_SATA		(0x03 << 12)
+#define DDF_PDE_FC		(0x04 << 12)
+	uint16_t		PD_State;
+#define	DDF_PDE_ONLINE		(1 << 0)
+#define	DDF_PDE_FAILED		(1 << 1)
+#define	DDF_PDE_REBUILD		(1 << 2)
+#define	DDF_PDE_TRANSITION	(1 << 3)
+#define	DDF_PDE_PFA		(1 << 4)
+#define	DDF_PDE_UNRECOVERED	(1 << 5)
+#define	DDF_PDE_MISSING		(1 << 6)
+	uint64_t		Configured_Size;
+	union ddf_pathinfo	Path_Information;
+	uint8_t			pad1[6];
+} __packed;
+
+struct ddf_pd_record {
+	uint32_t		Signature;
+#define	DDF_PDR_SIGNATURE	0x22222222
+	uint32_t		CRC;
+	uint16_t		Populated_PDEs;
+	uint16_t		Max_PDE_Supported;
+	uint8_t			pad1[52];
+	struct ddf_pd_entry	entry[0];
+} __packed;
+
+struct ddf_vd_entry {
+	uint8_t			VD_GUID[24];
+	uint16_t		VD_Number;
+	uint8_t			pad1[2];
+	uint16_t		VD_Type;
+#define DDF_VDE_SHARED		(1 << 0)
+#define	DDF_VDE_ENFORCE_GROUP	(1 << 1)
+#define	DDF_VDE_UNICODE_NAME	(1 << 2)
+#define	DDF_VDE_OWNER_ID_VALID	(1 << 3)
+	uint16_t		Controller_GUID_CRC;
+	uint8_t			VD_State;
+#define	DDF_VDE_OPTIMAL		0x00
+#define	DDF_VDE_DEGRADED	0x01
+#define	DDF_VDE_DELETED		0x02
+#define	DDF_VDE_MISSING		0x03
+#define	DDF_VDE_FAILED		0x04
+#define DDF_VDE_PARTIAL		0x05
+#define	DDF_VDE_STATE_MASK	0x07
+#define	DDF_VDE_MORPH		(1 << 3)
+#define	DDF_VDE_DIRTY		(1 << 4)
+	uint8_t			Init_State;
+#define	DDF_VDE_UNINTIALIZED	0x00
+#define	DDF_VDE_INIT_QUICK	0x01
+#define	DDF_VDE_INIT_FULL	0x02
+#define	DDF_VDE_INIT_MASK	0x03
+#define	DDF_VDE_UACCESS_RW	0x00
+#define	DDF_VDE_UACCESS_RO	0x80
+#define	DDF_VDE_UACCESS_BLOCKED	0xc0
+#define	DDF_VDE_UACCESS_MASK	0xc0
+	uint8_t			pad2[14];
+	uint8_t			VD_Name[16];
+} __packed;
+
+struct ddf_vd_record {
+	uint32_t		Signature;
+#define	DDF_VD_RECORD_SIGNATURE	0xdddddddd
+	uint32_t		CRC;
+	uint16_t		Populated_VDEs;
+	uint16_t		Max_VDE_Supported;
+	uint8_t			pad1[52];
+	struct ddf_vd_entry	entry[0];
+} __packed;
+
+#define DDF_CR_INVALID		0xffffffff
+
+struct ddf_vdc_record {
+	uint32_t	Signature;
+#define	DDF_VDCR_SIGNATURE	0xeeeeeeee
+	uint32_t	CRC;
+	uint8_t		VD_GUID[24];
+	uint32_t	Timestamp;
+	uint32_t	Sequence_Number;
+	uint8_t		pad1[24];
+	uint16_t	Primary_Element_Count;
+	uint8_t		Stripe_Size;
+	uint8_t		Primary_RAID_Level;
+#define DDF_VDCR_RAID0		0x00
+#define DDF_VDCR_RAID1		0x01
+#define DDF_VDCR_RAID3		0x03
+#define DDF_VDCR_RAID4		0x04
+#define DDF_VDCR_RAID5		0x05
+#define DDF_VDCR_RAID6		0x06
+#define DDF_VDCR_RAID1E		0x11
+#define DDF_VDCR_SINGLE		0x0f
+#define DDF_VDCR_CONCAT		0x1f
+#define DDF_VDCR_RAID5E		0x15
+#define DDF_VDCR_RAID5EE	0x25
+	uint8_t		RLQ;
+	uint8_t		Secondary_Element_Count;
+	uint8_t		Secondary_Element_Seq;
+	uint8_t		Secondary_RAID_Level;
+	uint64_t	Block_Count;
+	uint64_t	VD_Size;
+	uint8_t		pad2[8];
+	uint32_t	Associated_Spares[8];
+	uint64_t	Cache_Flags;
+#define DDF_VDCR_CACHE_WB		(1 << 0)
+#define	DDF_VDCR_CACHE_WB_ADAPTIVE	(1 << 1)
+#define	DDF_VDCR_CACHE_RA		(1 << 2)
+#define	DDF_VDCR_CACHE_RA_ADAPTIVE	(1 << 3)
+#define	DDF_VDCR_CACHE_WCACHE_NOBATTERY	(1 << 4)
+#define	DDF_VDCR_CACHE_WCACHE_ALLOW	(1 << 5)
+#define	DDF_VDCR_CACHE_RCACHE_ALLOW	(1 << 6)
+#define	DDF_VDCR_CACHE_VENDOR		(1 << 7)
+	uint8_t		BG_Rate;
+	uint8_t		pad3[3];
+	uint8_t		pad4[52];
+	uint8_t		pad5[192];
+	uint8_t		V0[32];
+	uint8_t		V1[32];
+	uint8_t		V2[16];
+	uint8_t		V3[16];
+	uint8_t		Vendor_Scratch[32];
+	uint32_t	Physical_Disk_Sequence[0];
+} __packed;
+
+struct ddf_vuc_record {
+	uint32_t	Signature;
+#define	DDF_VUCR_SIGNATURE	0x88888888
+	uint32_t	CRC;
+	uint8_t		VD_GUID[24];
+} __packed;
+
+struct ddf_sa_entry {
+	uint8_t		VD_GUID[24];
+	uint16_t	Secondary_Element;
+	uint8_t		rsrvd2[6];
+} __packed;
+
+struct ddf_sa_record {
+	uint32_t	Signature;
+#define	DDF_SA_SIGNATURE	0x55555555
+	uint32_t	CRC;
+	uint32_t	Timestamp;
+	uint8_t		pad1[7];
+	uint8_t		Spare_Type;
+#define	DDF_SAR_TYPE_DEDICATED		(1 << 0)
+#define	DDF_SAR_TYPE_REVERTIBLE		(1 << 1)
+#define	DDF_SAR_TYPE_ACTIVE		(1 << 2)
+#define	DDF_SAR_TYPE_ENCL_AFFINITY	(1 << 3)
+	uint16_t	Populated_SAEs;
+	uint16_t	MAX_SAE_Supported;
+	uint8_t		pad2[8];
+	struct ddf_sa_entry	entry[0];
+} __packed;
+
+struct ddf_pdd_record {
+	uint32_t	Signature;
+#define	DDF_PDD_SIGNATURE	0x33333333
+	uint32_t	CRC;
+	uint8_t		PD_GUID[24];
+	uint32_t	PD_Reference;
+	uint8_t		Forced_Ref_Flag;
+#define	DDF_PDD_FORCED_REF	0x01
+	uint8_t		Forced_PD_GUID_Flag;
+#define	DDF_PDD_FORCED_GUID	0x01
+	uint8_t		Vendor_Scratch[32];
+	uint8_t		pad2[442];
+} __packed;
+
+struct ddf_bbm_entry {
+	uint64_t	Defective_Block_Start;
+	uint32_t	Spare_Block_Offset;
+	uint16_t	Remapped_Count;
+	uint8_t	pad[2];
+};
+
+struct ddf_bbm_log {
+	uint32_t	Signature;
+#define	DDF_BBML_SIGNATURE	0xabadb10c
+	uint32_t	CRC;
+	uint16_t	Entry_Count;
+	uint32_t	Spare_Block_Count;
+	uint8_t		pad1[10];
+	uint64_t	First_Spare_LBA;
+	uint64_t	Mapped_Block_Entry[0];
+} __packed;
+
+struct ddf_vendor_log {
+	uint32_t	Signature;
+#define	DDF_VENDOR_LOG_SIGNATURE	0x01dbeef0
+	uint32_t	CRC;
+	uint64_t	Log_Owner;
+	uint8_t		pad1[16];
+} __packed;
+
+#endif

Modified: head/sys/dev/ata/ata-raid.c
==============================================================================
--- head/sys/dev/ata/ata-raid.c	Fri Feb 20 04:48:40 2009	(r188839)
+++ head/sys/dev/ata/ata-raid.c	Fri Feb 20 06:10:12 2009	(r188840)
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ata/ata-all.h>
 #include <dev/ata/ata-disk.h>
 #include <dev/ata/ata-raid.h>
+#include <dev/ata/ata-raid-ddf.h>
 #include <dev/ata/ata-pci.h>
 #include <ata_if.h>
 
@@ -65,6 +66,7 @@ static int ata_raid_read_metadata(device
 static int ata_raid_write_metadata(struct ar_softc *rdp);
 static int ata_raid_wipe_metadata(struct ar_softc *rdp);
 static int ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp);
+static int ata_raid_ddf_read_meta(device_t dev, struct ar_softc **raidp);
 static int ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp);
 static int ata_raid_hptv2_write_meta(struct ar_softc *rdp);
 static int ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp);
@@ -93,6 +95,7 @@ static char * ata_raid_flags(struct ar_s
 /* debugging only */
 static void ata_raid_print_meta(struct ar_softc *meta);
 static void ata_raid_adaptec_print_meta(struct adaptec_raid_conf *meta);
+static void ata_raid_ddf_print_meta(uint8_t *meta);
 static void ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta);
 static void ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta);
 static void ata_raid_intel_print_meta(struct intel_raid_conf *meta);
@@ -1417,6 +1420,10 @@ ata_raid_read_metadata(device_t subdisk)
     if (ata_raid_lsiv2_read_meta(subdisk, ata_raid_arrays))
 	return 0;
 
+    /* DDF (used by Adaptec, maybe others) */
+    if (ata_raid_ddf_read_meta(subdisk, ata_raid_arrays))
+	return 0;
+
     /* if none of the above matched, try FreeBSD native format */
     return ata_raid_promise_read_meta(subdisk, ata_raid_arrays, 1);
 }
@@ -1688,6 +1695,338 @@ adaptec_out:
     return retval;
 }
 
+static uint64_t
+ddfbe64toh(uint64_t val)
+{
+    return (be64toh(val));
+}
+
+static uint32_t
+ddfbe32toh(uint32_t val)
+{
+    return (be32toh(val));
+}
+
+static uint16_t
+ddfbe16toh(uint16_t val)
+{
+    return (be16toh(val));
+}
+
+static uint64_t
+ddfle64toh(uint64_t val)
+{
+    return (le64toh(val));
+}
+
+static uint32_t
+ddfle32toh(uint32_t val)
+{
+    return (le32toh(val));
+}
+
+static uint16_t
+ddfle16toh(uint16_t val)
+{
+    return (le16toh(val));
+}
+
+static int
+ata_raid_ddf_read_meta(device_t dev, struct ar_softc **raidp)
+{
+    struct ata_raid_subdisk *ars;
+    device_t parent = device_get_parent(dev);
+    struct ddf_header *hdr;
+    struct ddf_pd_record *pdr;
+    struct ddf_pd_entry *pde = NULL;
+    struct ddf_vd_record *vdr;
+    struct ddf_pdd_record *pdd;
+    struct ddf_sa_record *sa = NULL;
+    struct ddf_vdc_record *vdcr = NULL;
+    struct ddf_vd_entry *vde = NULL;
+    struct ar_softc *raid;
+    uint64_t pri_lba;
+    uint32_t pd_ref, pd_pos;
+    uint8_t *meta, *cr;
+    int hdr_len, vd_state = 0, pd_state = 0;
+    int i, disk, array, retval = 0;
+    uintptr_t max_cr_addr;
+    uint64_t (*ddf64toh)(uint64_t) = NULL;
+    uint32_t (*ddf32toh)(uint32_t) = NULL;
+    uint16_t (*ddf16toh)(uint16_t) = NULL;
+
+    ars = device_get_softc(dev);
+    raid = NULL;
+
+    /* Read in the anchor header */
+    if (!(meta = malloc(DDF_HEADER_LENGTH, M_AR, M_NOWAIT | M_ZERO)))
+	return ENOMEM;
+
+    if (ata_raid_rw(parent, DDF_LBA(parent),
+		    meta, DDF_HEADER_LENGTH, ATA_R_READ)) {
+	if (testing || bootverbose)
+	    device_printf(parent, "DDF read metadata failed\n");
+	goto ddf_out;
+    }
+
+    /*
+     * Check if this is a DDF RAID struct.  Note the apparent "flexibility"
+     * regarding endianness.
+     */
+    hdr = (struct ddf_header *)meta;
+    if (be32toh(hdr->Signature) == DDF_HEADER_SIGNATURE) {
+	ddf64toh = ddfbe64toh;
+	ddf32toh = ddfbe32toh;
+	ddf16toh = ddfbe16toh;
+    } else if (le32toh(hdr->Signature) == DDF_HEADER_SIGNATURE) {
+	ddf64toh = ddfle64toh;
+	ddf32toh = ddfle32toh;
+	ddf16toh = ddfle16toh;
+    } else
+	goto ddf_out;
+
+    if (hdr->Header_Type != DDF_HEADER_ANCHOR) {
+	if (testing || bootverbose)
+	    device_printf(parent, "DDF check1 failed\n");
+	goto ddf_out;
+    }
+
+    pri_lba = ddf64toh(hdr->Primary_Header_LBA);
+    hdr_len = ddf32toh(hdr->cd_section) + ddf32toh(hdr->cd_length);
+    hdr_len = max(hdr_len,ddf32toh(hdr->pdr_section)+ddf32toh(hdr->pdr_length));
+    hdr_len = max(hdr_len,ddf32toh(hdr->vdr_section)+ddf32toh(hdr->vdr_length));
+    hdr_len = max(hdr_len,ddf32toh(hdr->cr_section) +ddf32toh(hdr->cr_length));
+    hdr_len = max(hdr_len,ddf32toh(hdr->pdd_section)+ddf32toh(hdr->pdd_length));
+    if (testing || bootverbose)
+		device_printf(parent, "DDF pri_lba= %llu length= %d blocks\n",
+			      (unsigned long long)pri_lba, hdr_len);
+    if ((pri_lba + hdr_len) > DDF_LBA(parent)) {
+	device_printf(parent, "DDF exceeds length of disk\n");
+	goto ddf_out;
+    }
+
+    /* Don't need the anchor anymore, read the rest of the metadata */
+    free(meta, M_AR);
+    if (!(meta = malloc(hdr_len * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO)))
+	return ENOMEM;
+
+    if (ata_raid_rw(parent, pri_lba, meta, hdr_len * DEV_BSIZE, ATA_R_READ)) {
+	if (testing || bootverbose)
+	    device_printf(parent, "DDF read full metadata failed\n");
+	goto ddf_out;
+    }
+
+    /* Check that we got a Primary Header */
+    hdr = (struct ddf_header *)meta;
+    if ((ddf32toh(hdr->Signature) != DDF_HEADER_SIGNATURE) ||
+	(hdr->Header_Type != DDF_HEADER_PRIMARY)) {
+	if (testing || bootverbose)
+	    device_printf(parent, "DDF check2 failed\n");
+	goto ddf_out;
+    }
+
+    if (testing || bootverbose)
+	ata_raid_ddf_print_meta(meta);
+
+    if ((hdr->Open_Flag >= 0x01) && (hdr->Open_Flag <= 0x0f)) {
+	device_printf(parent, "DDF Header open, possibly corrupt metadata\n");
+	goto ddf_out;
+    }
+
+    pdr = (struct ddf_pd_record*)(meta + ddf32toh(hdr->pdr_section)*DEV_BSIZE);
+    vdr = (struct ddf_vd_record*)(meta + ddf32toh(hdr->vdr_section)*DEV_BSIZE);
+    cr = (uint8_t *)(meta + ddf32toh(hdr->cr_section)*DEV_BSIZE);
+    pdd = (struct ddf_pdd_record*)(meta + ddf32toh(hdr->pdd_section)*DEV_BSIZE);
+
+    /* Verify the Physical Disk Device Record */
+    if (ddf32toh(pdd->Signature) != DDF_PDD_SIGNATURE) {
+	device_printf(parent, "Invalid PD Signature\n");
+	goto ddf_out;
+    }
+    pd_ref = ddf32toh(pdd->PD_Reference);
+    pd_pos = -1;
+
+    /* Verify the Physical Disk Record and make sure the disk is usable */
+    if (ddf32toh(pdr->Signature) != DDF_PDR_SIGNATURE) {
+	device_printf(parent, "Invalid PDR Signature\n");
+	goto ddf_out;
+    }
+    for (i = 0; i < ddf16toh(pdr->Populated_PDEs); i++) {
+	if (ddf32toh(pdr->entry[i].PD_Reference) != pd_ref)
+	    continue;
+	pde = &pdr->entry[i];
+	pd_state = ddf16toh(pde->PD_State);
+    }
+    if ((pde == NULL) ||
+	((pd_state & DDF_PDE_ONLINE) == 0) || 
+	(pd_state & (DDF_PDE_FAILED|DDF_PDE_MISSING|DDF_PDE_UNRECOVERED))) {
+	device_printf(parent, "Physical disk not usable\n");
+	goto ddf_out;
+    }
+
+    /* Parse out the configuration record, look for spare and VD records.
+     * While DDF supports a disk being part of more than one array, and
+     * thus having more than one VDCR record, that feature is not supported
+     * by ATA-RAID.  Therefore, the first record found takes precedence.
+     */
+    max_cr_addr = (uintptr_t)cr + ddf32toh(hdr->cr_length) * DEV_BSIZE - 1;
+    for ( ; (uintptr_t)cr < max_cr_addr;
+	cr += ddf16toh(hdr->Configuration_Record_Length) * DEV_BSIZE) {
+	switch (ddf32toh(((uint32_t *)cr)[0])) {
+	case DDF_VDCR_SIGNATURE:
+	    vdcr = (struct ddf_vdc_record *)cr;
+	    goto cr_found;
+	    break;
+	case DDF_VUCR_SIGNATURE:
+	    /* Don't care about this record */
+	    break;
+	case DDF_SA_SIGNATURE:
+	    sa = (struct ddf_sa_record *)cr;
+	    goto cr_found;
+	    break;
+	case DDF_CR_INVALID:
+	    /* A record was deliberately invalidated */
+	    break;
+	default:
+	    device_printf(parent, "Invalid CR signature found\n");
+	}
+    }
+cr_found:
+    if ((vdcr == NULL) /* && (sa == NULL) * Spares not supported yet */) {
+	device_printf(parent, "No usable configuration record found\n");
+	goto ddf_out;
+    }
+
+    if (vdcr != NULL) {
+	if (vdcr->Secondary_Element_Count != 1) {
+	    device_printf(parent, "Unsupported multi-level Virtual Disk\n");
+	    goto ddf_out;
+	}
+
+	/* Find the Virtual Disk Entry for this array */
+	if (ddf32toh(vdr->Signature) != DDF_VD_RECORD_SIGNATURE) {
+	    device_printf(parent, "Invalid VDR Signature\n");
+	    goto ddf_out;
+	}
+	for (i = 0; i < ddf16toh(vdr->Populated_VDEs); i++) {
+	    if (bcmp(vdr->entry[i].VD_GUID, vdcr->VD_GUID, 24))
+		continue;
+	    vde = &vdr->entry[i];
+	    vd_state = vde->VD_State & DDF_VDE_STATE_MASK;
+	}
+	if ((vde == NULL) ||
+	    ((vd_state != DDF_VDE_OPTIMAL) && (vd_state != DDF_VDE_DEGRADED))) {
+	    device_printf(parent, "Unusable Virtual Disk\n");
+	    goto ddf_out;
+	}
+	for (i = 0; i < ddf16toh(hdr->Max_Primary_Element_Entries); i++) {
+	    uint32_t pd_tmp;
+
+	    pd_tmp = ddf32toh(vdcr->Physical_Disk_Sequence[i]);
+	    if ((pd_tmp == 0x00000000) || (pd_tmp == 0xffffffff))
+		continue;
+	    if (pd_tmp == pd_ref) {
+		pd_pos = i;
+		break;
+	    }
+	}
+	if (pd_pos == -1) {
+	    device_printf(parent, "Physical device not part of array\n");
+	    goto ddf_out;
+	}
+    }
+
+    /* now convert DDF metadata into our generic form */
+    for (array = 0; array < MAX_ARRAYS; array++) {
+	if (!raidp[array]) {
+	    raid = (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR,
+					  M_NOWAIT | M_ZERO);
+	    if (!raid) {
+		device_printf(parent, "failed to allocate metadata storage\n");
+		goto ddf_out;
+	    }
+	} else
+	    raid = raidp[array];
+
+	if (raid->format && (raid->format != AR_F_DDF_RAID))
+	    continue;
+
+	if (raid->magic_0 && (raid->magic_0 != crc32(vde->VD_GUID, 24)))
+	    continue;
+
+	if (!raidp[array]) {
+	    raidp[array] = raid;
+
+	    switch (vdcr->Primary_RAID_Level) {
+	    case DDF_VDCR_RAID0:
+		raid->magic_0 = crc32(vde->VD_GUID, 24);
+		raid->magic_1 = ddf16toh(vde->VD_Number);
+		raid->type = AR_T_RAID0;
+		raid->interleave = 1 << vdcr->Stripe_Size;
+		raid->width = ddf16toh(vdcr->Primary_Element_Count);
+		break;
+	    
+	    case DDF_VDCR_RAID1:
+		raid->magic_0 = crc32(vde->VD_GUID, 24);
+		raid->magic_1 = ddf16toh(vde->VD_Number);
+		raid->type = AR_T_RAID1;
+		raid->width = 1;
+		break;
+
+	    default:
+		device_printf(parent, "DDF unsupported RAID type 0x%02x\n",
+			      vdcr->Primary_RAID_Level);
+		free(raidp[array], M_AR);
+		raidp[array] = NULL;
+		goto ddf_out;
+	    }
+
+	    raid->format = AR_F_DDF_RAID;
+	    raid->generation = ddf32toh(vdcr->Sequence_Number);
+	    raid->total_disks = ddf16toh(vdcr->Primary_Element_Count);
+	    raid->total_sectors = ddf64toh(vdcr->VD_Size);
+	    raid->heads = 255;
+	    raid->sectors = 63;
+	    raid->cylinders = raid->total_sectors / (63 * 255);
+	    raid->offset_sectors = 0;
+	    raid->rebuild_lba = 0;
+	    raid->lun = array;
+	    strncpy(raid->name, vde->VD_Name,
+		    min(sizeof(raid->name), sizeof(vde->VD_Name)));
+
+	    /* clear out any old info */
+	    if (raid->generation) {
+		for (disk = 0; disk < raid->total_disks; disk++) {
+		    raid->disks[disk].dev = NULL;
+		    raid->disks[disk].flags = 0;
+		}
+	    }
+	}
+	if (ddf32toh(vdcr->Sequence_Number) >= raid->generation) {
+	    int disk_number = pd_pos;
+
+	    raid->disks[disk_number].dev = parent;
+
+	    /* Adaptec appears to not set vdcr->Block_Count, yet again in
+	     * gross violation of the spec.
+	     */
+	    raid->disks[disk_number].sectors = ddf64toh(vdcr->Block_Count);
+            if (raid->disks[disk_number].sectors == 0)
+                raid->disks[disk_number].sectors=ddf64toh(pde->Configured_Size);
+	    raid->disks[disk_number].flags =
+		(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
+	    ars->raid[raid->volume] = raid;
+	    ars->disk_number[raid->volume] = disk_number;
+	    retval = 1;
+	}
+	break;
+    }
+
+ddf_out:
+    free(meta, M_AR);
+    return retval;
+}
+
 /* Highpoint V2 RocketRAID Metadata */
 static int
 ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp)
@@ -4271,6 +4610,7 @@ ata_raid_format(struct ar_softc *rdp)
     switch (rdp->format) {
     case AR_F_FREEBSD_RAID:     return "FreeBSD PseudoRAID";
     case AR_F_ADAPTEC_RAID:     return "Adaptec HostRAID";
+    case AR_F_DDF_RAID:		return "DDF";
     case AR_F_HPTV2_RAID:       return "HighPoint v2 RocketRAID";
     case AR_F_HPTV3_RAID:       return "HighPoint v3 RocketRAID";
     case AR_F_INTEL_RAID:       return "Intel MatrixRAID";
@@ -4427,6 +4767,71 @@ ata_raid_adaptec_print_meta(struct adapt
     printf("=================================================\n");
 }
 
+static void
+ata_raid_ddf_print_meta(uint8_t *meta)
+{
+    struct ddf_header *hdr;
+    struct ddf_cd_record *cd;
+    struct ddf_pd_record *pdr;
+    struct ddf_pd_entry *pde;
+    struct ddf_vd_record *vdr;
+    struct ddf_vd_entry *vde;
+    struct ddf_pdd_record *pdd;
+    uint64_t (*ddf64toh)(uint64_t) = NULL;
+    uint32_t (*ddf32toh)(uint32_t) = NULL;
+    uint16_t (*ddf16toh)(uint16_t) = NULL;
+    uint8_t *cr;
+    char *r;
+
+    /* Check if this is a DDF RAID struct */
+    hdr = (struct ddf_header *)meta;
+    if (be32toh(hdr->Signature) == DDF_HEADER_SIGNATURE) {
+	ddf64toh = ddfbe64toh;
+	ddf32toh = ddfbe32toh;
+	ddf16toh = ddfbe16toh;
+    } else {
+	ddf64toh = ddfle64toh;
+	ddf32toh = ddfle32toh;
+	ddf16toh = ddfle16toh;
+    }
+
+    hdr = (struct ddf_header*)meta;
+    cd = (struct ddf_cd_record*)(meta + ddf32toh(hdr->cd_section) *DEV_BSIZE);
+    pdr = (struct ddf_pd_record*)(meta + ddf32toh(hdr->pdr_section)*DEV_BSIZE);
+    vdr = (struct ddf_vd_record*)(meta + ddf32toh(hdr->vdr_section)*DEV_BSIZE);
+    cr = (uint8_t *)(meta + ddf32toh(hdr->cr_section) * DEV_BSIZE);
+    pdd = (struct ddf_pdd_record*)(meta + ddf32toh(hdr->pdd_section)*DEV_BSIZE);
+    pde = NULL;
+    vde = NULL;
+
+    printf("********* ATA DDF Metadata *********\n");
+    printf("**** Header ****\n");
+    r = (char *)&hdr->DDF_rev[0];
+    printf("DDF_rev= %8.8s Sequence_Number= 0x%x Open_Flag= 0x%x\n", r,
+	   ddf32toh(hdr->Sequence_Number), hdr->Open_Flag);
+    printf("Primary Header LBA= %llu Header_Type = 0x%x\n",
+	   (unsigned long long)ddf64toh(hdr->Primary_Header_LBA),
+	   hdr->Header_Type);
+    printf("Max_PD_Entries= %d Max_VD_Entries= %d Max_Partitions= %d "
+	   "CR_Length= %d\n",  ddf16toh(hdr->Max_PD_Entries),
+	    ddf16toh(hdr->Max_VD_Entries), ddf16toh(hdr->Max_Partitions),
+	    ddf16toh(hdr->Configuration_Record_Length));
+    printf("CD= %d:%d PDR= %d:%d VDR= %d:%d CR= %d:%d PDD= %d%d\n",
+	   ddf32toh(hdr->cd_section), ddf32toh(hdr->cd_length),
+	   ddf32toh(hdr->pdr_section), ddf32toh(hdr->pdr_length),
+	   ddf32toh(hdr->vdr_section), ddf32toh(hdr->vdr_length),
+	   ddf32toh(hdr->cr_section), ddf32toh(hdr->cr_length),
+	   ddf32toh(hdr->pdd_section), ddf32toh(hdr->pdd_length));
+    printf("**** Controler Data ****\n");
+    r = (char *)&cd->Product_ID[0];
+    printf("Product_ID: %16.16s\n", r);
+    printf("Vendor 0x%x, Device 0x%x, SubVendor 0x%x, Sub_Device 0x%x\n",
+	   ddf16toh(cd->Controller_Type.Vendor_ID),
+	   ddf16toh(cd->Controller_Type.Device_ID),
+	   ddf16toh(cd->Controller_Type.SubVendor_ID),
+	   ddf16toh(cd->Controller_Type.SubDevice_ID));
+}
+
 static char *
 ata_raid_hptv2_type(int type)
 {

Modified: head/sys/dev/ata/ata-raid.h
==============================================================================
--- head/sys/dev/ata/ata-raid.h	Fri Feb 20 04:48:40 2009	(r188839)
+++ head/sys/dev/ata/ata-raid.h	Fri Feb 20 06:10:12 2009	(r188840)
@@ -76,7 +76,8 @@ struct ar_softc {
 #define AR_F_SII_RAID           0x0800
 #define AR_F_SIS_RAID           0x1000
 #define AR_F_VIA_RAID           0x2000
-#define AR_F_FORMAT_MASK        0x3fff
+#define AR_F_DDF_RAID		0x4000
+#define AR_F_FORMAT_MASK        0x7fff
 
     u_int               generation;
     u_int64_t           total_sectors;
@@ -164,6 +165,9 @@ struct adaptec_raid_conf {
     u_int32_t           dummy_9[62];
 } __packed;
 
+/* DDF Information.  Metadata definitions are in another file */
+#define DDF_LBA(dev) \
+	(((struct ad_softc *)device_get_ivars(dev))->total_secs - 1)
 
 /* Highpoint V2 RocketRAID Metadata */
 #define HPTV2_LBA(dev)  9



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