From owner-svn-src-head@FreeBSD.ORG Mon Apr 30 17:53:03 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4109E1065744; Mon, 30 Apr 2012 17:53:03 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B06208FC1E; Mon, 30 Apr 2012 17:53:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q3UHr2Ht077131; Mon, 30 Apr 2012 17:53:02 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q3UHr2XI077126; Mon, 30 Apr 2012 17:53:02 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201204301753.q3UHr2XI077126@svn.freebsd.org> From: Alexander Motin Date: Mon, 30 Apr 2012 17:53:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r234848 - in head: sbin/geom/class/raid sys/conf sys/geom/raid sys/modules/geom/geom_raid X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Apr 2012 17:53:03 -0000 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 ***