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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to