1234848Smav/*- 2234848Smav * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org> 3234848Smav * All rights reserved. 4234848Smav * 5234848Smav * Redistribution and use in source and binary forms, with or without 6234848Smav * modification, are permitted provided that the following conditions 7234848Smav * are met: 8234848Smav * 1. Redistributions of source code must retain the above copyright 9234848Smav * notice, this list of conditions and the following disclaimer. 10234848Smav * 2. Redistributions in binary form must reproduce the above copyright 11234848Smav * notice, this list of conditions and the following disclaimer in the 12234848Smav * documentation and/or other materials provided with the distribution. 13234848Smav * 14234848Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15234848Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234848Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17234848Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18234848Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19234848Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20234848Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21234848Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22234848Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23234848Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24234848Smav * SUCH DAMAGE. 25234848Smav */ 26234848Smav 27234848Smav#include <sys/cdefs.h> 28234848Smav__FBSDID("$FreeBSD$"); 29234848Smav 30234848Smav#include <sys/param.h> 31234848Smav#include <sys/bio.h> 32234848Smav#include <sys/endian.h> 33234848Smav#include <sys/kernel.h> 34234848Smav#include <sys/kobj.h> 35234848Smav#include <sys/limits.h> 36234848Smav#include <sys/lock.h> 37234848Smav#include <sys/malloc.h> 38234848Smav#include <sys/mutex.h> 39234848Smav#include <sys/systm.h> 40234848Smav#include <sys/time.h> 41234848Smav#include <sys/clock.h> 42234848Smav#include <geom/geom.h> 43234848Smav#include "geom/raid/g_raid.h" 44234848Smav#include "geom/raid/md_ddf.h" 45234848Smav#include "g_raid_md_if.h" 46234848Smav 47234848Smavstatic MALLOC_DEFINE(M_MD_DDF, "md_ddf_data", "GEOM_RAID DDF metadata"); 48234848Smav 49234848Smav#define DDF_MAX_DISKS_HARD 128 50234848Smav 51234848Smav#define DDF_MAX_DISKS 16 52234848Smav#define DDF_MAX_VDISKS 7 53234848Smav#define DDF_MAX_PARTITIONS 1 54234848Smav 55234848Smav#define DECADE (3600*24*(365*10+2)) /* 10 years in seconds. */ 56234848Smav 57234848Smavstruct ddf_meta { 58234848Smav u_int sectorsize; 59234848Smav u_int bigendian; 60234848Smav struct ddf_header *hdr; 61234848Smav struct ddf_cd_record *cdr; 62234848Smav struct ddf_pd_record *pdr; 63234848Smav struct ddf_vd_record *vdr; 64234848Smav void *cr; 65234848Smav struct ddf_pdd_record *pdd; 66234848Smav struct ddf_bbm_log *bbm; 67234848Smav}; 68234848Smav 69234848Smavstruct ddf_vol_meta { 70234848Smav u_int sectorsize; 71234848Smav u_int bigendian; 72234848Smav struct ddf_header *hdr; 73234848Smav struct ddf_cd_record *cdr; 74234848Smav struct ddf_vd_entry *vde; 75234848Smav struct ddf_vdc_record *vdc; 76234848Smav struct ddf_vdc_record *bvdc[DDF_MAX_DISKS_HARD]; 77234848Smav}; 78234848Smav 79234848Smavstruct g_raid_md_ddf_perdisk { 80234848Smav struct ddf_meta pd_meta; 81234848Smav}; 82234848Smav 83234848Smavstruct g_raid_md_ddf_pervolume { 84234848Smav struct ddf_vol_meta pv_meta; 85234848Smav int pv_started; 86234848Smav struct callout pv_start_co; /* STARTING state timer. */ 87234848Smav}; 88234848Smav 89234848Smavstruct g_raid_md_ddf_object { 90234848Smav struct g_raid_md_object mdio_base; 91234940Smav u_int mdio_bigendian; 92234848Smav struct ddf_meta mdio_meta; 93234868Smav int mdio_starting; 94234848Smav struct callout mdio_start_co; /* STARTING state timer. */ 95234848Smav int mdio_started; 96234848Smav struct root_hold_token *mdio_rootmount; /* Root mount delay token. */ 97234848Smav}; 98234848Smav 99234940Smavstatic g_raid_md_create_req_t g_raid_md_create_req_ddf; 100234848Smavstatic g_raid_md_taste_t g_raid_md_taste_ddf; 101234848Smavstatic g_raid_md_event_t g_raid_md_event_ddf; 102234848Smavstatic g_raid_md_volume_event_t g_raid_md_volume_event_ddf; 103234848Smavstatic g_raid_md_ctl_t g_raid_md_ctl_ddf; 104234848Smavstatic g_raid_md_write_t g_raid_md_write_ddf; 105234848Smavstatic g_raid_md_fail_disk_t g_raid_md_fail_disk_ddf; 106234848Smavstatic g_raid_md_free_disk_t g_raid_md_free_disk_ddf; 107234848Smavstatic g_raid_md_free_volume_t g_raid_md_free_volume_ddf; 108234848Smavstatic g_raid_md_free_t g_raid_md_free_ddf; 109234848Smav 110234848Smavstatic kobj_method_t g_raid_md_ddf_methods[] = { 111234940Smav KOBJMETHOD(g_raid_md_create_req, g_raid_md_create_req_ddf), 112234848Smav KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_ddf), 113234848Smav KOBJMETHOD(g_raid_md_event, g_raid_md_event_ddf), 114234848Smav KOBJMETHOD(g_raid_md_volume_event, g_raid_md_volume_event_ddf), 115234848Smav KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_ddf), 116234848Smav KOBJMETHOD(g_raid_md_write, g_raid_md_write_ddf), 117234848Smav KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_ddf), 118234848Smav KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_ddf), 119234848Smav KOBJMETHOD(g_raid_md_free_volume, g_raid_md_free_volume_ddf), 120234848Smav KOBJMETHOD(g_raid_md_free, g_raid_md_free_ddf), 121234848Smav { 0, 0 } 122234848Smav}; 123234848Smav 124234848Smavstatic struct g_raid_md_class g_raid_md_ddf_class = { 125234848Smav "DDF", 126234848Smav g_raid_md_ddf_methods, 127234848Smav sizeof(struct g_raid_md_ddf_object), 128240465Smav .mdc_enable = 1, 129234848Smav .mdc_priority = 100 130234848Smav}; 131234848Smav 132234848Smav#define GET8(m, f) ((m)->f) 133234848Smav#define GET16(m, f) ((m)->bigendian ? be16dec(&(m)->f) : le16dec(&(m)->f)) 134234848Smav#define GET32(m, f) ((m)->bigendian ? be32dec(&(m)->f) : le32dec(&(m)->f)) 135234848Smav#define GET64(m, f) ((m)->bigendian ? be64dec(&(m)->f) : le64dec(&(m)->f)) 136234848Smav#define GET8D(m, f) (f) 137234848Smav#define GET16D(m, f) ((m)->bigendian ? be16dec(&f) : le16dec(&f)) 138234848Smav#define GET32D(m, f) ((m)->bigendian ? be32dec(&f) : le32dec(&f)) 139234848Smav#define GET64D(m, f) ((m)->bigendian ? be64dec(&f) : le64dec(&f)) 140234848Smav#define GET8P(m, f) (*(f)) 141234848Smav#define GET16P(m, f) ((m)->bigendian ? be16dec(f) : le16dec(f)) 142234848Smav#define GET32P(m, f) ((m)->bigendian ? be32dec(f) : le32dec(f)) 143234848Smav#define GET64P(m, f) ((m)->bigendian ? be64dec(f) : le64dec(f)) 144234848Smav 145234848Smav#define SET8P(m, f, v) \ 146234848Smav (*(f) = (v)) 147234848Smav#define SET16P(m, f, v) \ 148234848Smav do { \ 149234848Smav if ((m)->bigendian) \ 150234848Smav be16enc((f), (v)); \ 151234848Smav else \ 152234848Smav le16enc((f), (v)); \ 153234848Smav } while (0) 154234848Smav#define SET32P(m, f, v) \ 155234848Smav do { \ 156234848Smav if ((m)->bigendian) \ 157234848Smav be32enc((f), (v)); \ 158234848Smav else \ 159234848Smav le32enc((f), (v)); \ 160234848Smav } while (0) 161234848Smav#define SET64P(m, f, v) \ 162234848Smav do { \ 163234848Smav if ((m)->bigendian) \ 164234848Smav be64enc((f), (v)); \ 165234848Smav else \ 166234848Smav le64enc((f), (v)); \ 167234848Smav } while (0) 168234848Smav#define SET8(m, f, v) SET8P((m), &((m)->f), (v)) 169234848Smav#define SET16(m, f, v) SET16P((m), &((m)->f), (v)) 170234848Smav#define SET32(m, f, v) SET32P((m), &((m)->f), (v)) 171234848Smav#define SET64(m, f, v) SET64P((m), &((m)->f), (v)) 172234848Smav#define SET8D(m, f, v) SET8P((m), &(f), (v)) 173234848Smav#define SET16D(m, f, v) SET16P((m), &(f), (v)) 174234848Smav#define SET32D(m, f, v) SET32P((m), &(f), (v)) 175234848Smav#define SET64D(m, f, v) SET64P((m), &(f), (v)) 176234848Smav 177234869Smav#define GETCRNUM(m) (GET32((m), hdr->cr_length) / \ 178234869Smav GET16((m), hdr->Configuration_Record_Length)) 179234869Smav 180234869Smav#define GETVDCPTR(m, n) ((struct ddf_vdc_record *)((uint8_t *)(m)->cr + \ 181234869Smav (n) * GET16((m), hdr->Configuration_Record_Length) * \ 182234869Smav (m)->sectorsize)) 183234869Smav 184234899Smav#define GETSAPTR(m, n) ((struct ddf_sa_record *)((uint8_t *)(m)->cr + \ 185234899Smav (n) * GET16((m), hdr->Configuration_Record_Length) * \ 186234899Smav (m)->sectorsize)) 187234899Smav 188234848Smavstatic int 189234848Smavisff(uint8_t *buf, int size) 190234848Smav{ 191234848Smav int i; 192234848Smav 193234848Smav for (i = 0; i < size; i++) 194234848Smav if (buf[i] != 0xff) 195234848Smav return (0); 196234848Smav return (1); 197234848Smav} 198234848Smav 199234848Smavstatic void 200234848Smavprint_guid(uint8_t *buf) 201234848Smav{ 202234848Smav int i, ascii; 203234848Smav 204234848Smav ascii = 1; 205234848Smav for (i = 0; i < 24; i++) { 206234848Smav if (buf[i] != 0 && (buf[i] < ' ' || buf[i] > 127)) { 207234848Smav ascii = 0; 208234848Smav break; 209234848Smav } 210234848Smav } 211234848Smav if (ascii) { 212234848Smav printf("'%.24s'", buf); 213234848Smav } else { 214234848Smav for (i = 0; i < 24; i++) 215234848Smav printf("%02x", buf[i]); 216234848Smav } 217234848Smav} 218234848Smav 219234848Smavstatic void 220234848Smavg_raid_md_ddf_print(struct ddf_meta *meta) 221234848Smav{ 222234848Smav struct ddf_vdc_record *vdc; 223234848Smav struct ddf_vuc_record *vuc; 224234848Smav struct ddf_sa_record *sa; 225234848Smav uint64_t *val2; 226234848Smav uint32_t val; 227234848Smav int i, j, k, num, num2; 228234848Smav 229234848Smav if (g_raid_debug < 1) 230234848Smav return; 231234848Smav 232234848Smav printf("********* DDF Metadata *********\n"); 233234848Smav printf("**** Header ****\n"); 234234848Smav printf("DDF_Header_GUID "); 235234848Smav print_guid(meta->hdr->DDF_Header_GUID); 236234848Smav printf("\n"); 237234848Smav printf("DDF_rev %8.8s\n", (char *)&meta->hdr->DDF_rev[0]); 238234848Smav printf("Sequence_Number 0x%08x\n", GET32(meta, hdr->Sequence_Number)); 239234848Smav printf("TimeStamp 0x%08x\n", GET32(meta, hdr->TimeStamp)); 240234848Smav printf("Open_Flag 0x%02x\n", GET16(meta, hdr->Open_Flag)); 241234848Smav printf("Foreign_Flag 0x%02x\n", GET16(meta, hdr->Foreign_Flag)); 242234848Smav printf("Diskgrouping 0x%02x\n", GET16(meta, hdr->Diskgrouping)); 243234848Smav printf("Primary_Header_LBA %ju\n", GET64(meta, hdr->Primary_Header_LBA)); 244234848Smav printf("Secondary_Header_LBA %ju\n", GET64(meta, hdr->Secondary_Header_LBA)); 245234848Smav printf("WorkSpace_Length %u\n", GET32(meta, hdr->WorkSpace_Length)); 246234848Smav printf("WorkSpace_LBA %ju\n", GET64(meta, hdr->WorkSpace_LBA)); 247234848Smav printf("Max_PD_Entries %u\n", GET16(meta, hdr->Max_PD_Entries)); 248234848Smav printf("Max_VD_Entries %u\n", GET16(meta, hdr->Max_VD_Entries)); 249234848Smav printf("Max_Partitions %u\n", GET16(meta, hdr->Max_Partitions)); 250234848Smav printf("Configuration_Record_Length %u\n", GET16(meta, hdr->Configuration_Record_Length)); 251234848Smav printf("Max_Primary_Element_Entries %u\n", GET16(meta, hdr->Max_Primary_Element_Entries)); 252234848Smav printf("Controller Data %u:%u\n", GET32(meta, hdr->cd_section), GET32(meta, hdr->cd_length)); 253234848Smav printf("Physical Disk %u:%u\n", GET32(meta, hdr->pdr_section), GET32(meta, hdr->pdr_length)); 254234848Smav printf("Virtual Disk %u:%u\n", GET32(meta, hdr->vdr_section), GET32(meta, hdr->vdr_length)); 255234848Smav printf("Configuration Recs %u:%u\n", GET32(meta, hdr->cr_section), GET32(meta, hdr->cr_length)); 256234848Smav printf("Physical Disk Recs %u:%u\n", GET32(meta, hdr->pdd_section), GET32(meta, hdr->pdd_length)); 257234848Smav printf("BBM Log %u:%u\n", GET32(meta, hdr->bbmlog_section), GET32(meta, hdr->bbmlog_length)); 258234848Smav printf("Diagnostic Space %u:%u\n", GET32(meta, hdr->Diagnostic_Space), GET32(meta, hdr->Diagnostic_Space_Length)); 259234848Smav printf("Vendor_Specific_Logs %u:%u\n", GET32(meta, hdr->Vendor_Specific_Logs), GET32(meta, hdr->Vendor_Specific_Logs_Length)); 260298755Spfg printf("**** Controller Data ****\n"); 261234848Smav printf("Controller_GUID "); 262234848Smav print_guid(meta->cdr->Controller_GUID); 263234848Smav printf("\n"); 264234848Smav printf("Controller_Type 0x%04x%04x 0x%04x%04x\n", 265234848Smav GET16(meta, cdr->Controller_Type.Vendor_ID), 266234848Smav GET16(meta, cdr->Controller_Type.Device_ID), 267234848Smav GET16(meta, cdr->Controller_Type.SubVendor_ID), 268234848Smav GET16(meta, cdr->Controller_Type.SubDevice_ID)); 269234848Smav printf("Product_ID '%.16s'\n", (char *)&meta->cdr->Product_ID[0]); 270234869Smav printf("**** Physical Disk Records ****\n"); 271234848Smav printf("Populated_PDEs %u\n", GET16(meta, pdr->Populated_PDEs)); 272234848Smav printf("Max_PDE_Supported %u\n", GET16(meta, pdr->Max_PDE_Supported)); 273234848Smav for (j = 0; j < GET16(meta, pdr->Populated_PDEs); j++) { 274234848Smav if (isff(meta->pdr->entry[j].PD_GUID, 24)) 275234848Smav continue; 276234848Smav if (GET32(meta, pdr->entry[j].PD_Reference) == 0xffffffff) 277234848Smav continue; 278234848Smav printf("PD_GUID "); 279234848Smav print_guid(meta->pdr->entry[j].PD_GUID); 280234848Smav printf("\n"); 281234848Smav printf("PD_Reference 0x%08x\n", 282234848Smav GET32(meta, pdr->entry[j].PD_Reference)); 283234848Smav printf("PD_Type 0x%04x\n", 284234848Smav GET16(meta, pdr->entry[j].PD_Type)); 285234848Smav printf("PD_State 0x%04x\n", 286234848Smav GET16(meta, pdr->entry[j].PD_State)); 287234848Smav printf("Configured_Size %ju\n", 288234848Smav GET64(meta, pdr->entry[j].Configured_Size)); 289234848Smav printf("Block_Size %u\n", 290234848Smav GET16(meta, pdr->entry[j].Block_Size)); 291234848Smav } 292234869Smav printf("**** Virtual Disk Records ****\n"); 293234848Smav printf("Populated_VDEs %u\n", GET16(meta, vdr->Populated_VDEs)); 294234848Smav printf("Max_VDE_Supported %u\n", GET16(meta, vdr->Max_VDE_Supported)); 295234848Smav for (j = 0; j < GET16(meta, vdr->Populated_VDEs); j++) { 296234848Smav if (isff(meta->vdr->entry[j].VD_GUID, 24)) 297234848Smav continue; 298234848Smav printf("VD_GUID "); 299234848Smav print_guid(meta->vdr->entry[j].VD_GUID); 300234848Smav printf("\n"); 301234848Smav printf("VD_Number 0x%04x\n", 302234848Smav GET16(meta, vdr->entry[j].VD_Number)); 303234899Smav printf("VD_Type 0x%04x\n", 304234899Smav GET16(meta, vdr->entry[j].VD_Type)); 305234848Smav printf("VD_State 0x%02x\n", 306234848Smav GET8(meta, vdr->entry[j].VD_State)); 307234848Smav printf("Init_State 0x%02x\n", 308234848Smav GET8(meta, vdr->entry[j].Init_State)); 309234848Smav printf("Drive_Failures_Remaining %u\n", 310234848Smav GET8(meta, vdr->entry[j].Drive_Failures_Remaining)); 311234848Smav printf("VD_Name '%.16s'\n", 312234848Smav (char *)&meta->vdr->entry[j].VD_Name); 313234848Smav } 314234848Smav printf("**** Configuration Records ****\n"); 315234869Smav num = GETCRNUM(meta); 316234848Smav for (j = 0; j < num; j++) { 317234869Smav vdc = GETVDCPTR(meta, j); 318234848Smav val = GET32D(meta, vdc->Signature); 319234848Smav switch (val) { 320234848Smav case DDF_VDCR_SIGNATURE: 321234848Smav printf("** Virtual Disk Configuration **\n"); 322234848Smav printf("VD_GUID "); 323234848Smav print_guid(vdc->VD_GUID); 324234848Smav printf("\n"); 325234848Smav printf("Timestamp 0x%08x\n", 326234848Smav GET32D(meta, vdc->Timestamp)); 327234848Smav printf("Sequence_Number 0x%08x\n", 328234848Smav GET32D(meta, vdc->Sequence_Number)); 329234848Smav printf("Primary_Element_Count %u\n", 330234848Smav GET16D(meta, vdc->Primary_Element_Count)); 331234848Smav printf("Stripe_Size %u\n", 332234848Smav GET8D(meta, vdc->Stripe_Size)); 333234848Smav printf("Primary_RAID_Level 0x%02x\n", 334234848Smav GET8D(meta, vdc->Primary_RAID_Level)); 335234848Smav printf("RLQ 0x%02x\n", 336234848Smav GET8D(meta, vdc->RLQ)); 337234848Smav printf("Secondary_Element_Count %u\n", 338234848Smav GET8D(meta, vdc->Secondary_Element_Count)); 339234848Smav printf("Secondary_Element_Seq %u\n", 340234848Smav GET8D(meta, vdc->Secondary_Element_Seq)); 341234848Smav printf("Secondary_RAID_Level 0x%02x\n", 342234848Smav GET8D(meta, vdc->Secondary_RAID_Level)); 343234848Smav printf("Block_Count %ju\n", 344234848Smav GET64D(meta, vdc->Block_Count)); 345234848Smav printf("VD_Size %ju\n", 346234848Smav GET64D(meta, vdc->VD_Size)); 347234848Smav printf("Block_Size %u\n", 348234848Smav GET16D(meta, vdc->Block_Size)); 349234848Smav printf("Rotate_Parity_count %u\n", 350234848Smav GET8D(meta, vdc->Rotate_Parity_count)); 351234848Smav printf("Associated_Spare_Disks"); 352234848Smav for (i = 0; i < 8; i++) { 353234848Smav if (GET32D(meta, vdc->Associated_Spares[i]) != 0xffffffff) 354234848Smav printf(" 0x%08x", GET32D(meta, vdc->Associated_Spares[i])); 355234848Smav } 356234848Smav printf("\n"); 357234848Smav printf("Cache_Flags %016jx\n", 358234848Smav GET64D(meta, vdc->Cache_Flags)); 359234848Smav printf("BG_Rate %u\n", 360234848Smav GET8D(meta, vdc->BG_Rate)); 361234848Smav printf("MDF_Parity_Disks %u\n", 362234848Smav GET8D(meta, vdc->MDF_Parity_Disks)); 363234848Smav printf("MDF_Parity_Generator_Polynomial 0x%04x\n", 364234848Smav GET16D(meta, vdc->MDF_Parity_Generator_Polynomial)); 365234848Smav printf("MDF_Constant_Generation_Method 0x%02x\n", 366234848Smav GET8D(meta, vdc->MDF_Constant_Generation_Method)); 367234848Smav printf("Physical_Disks "); 368234848Smav num2 = GET16D(meta, vdc->Primary_Element_Count); 369234848Smav val2 = (uint64_t *)&(vdc->Physical_Disk_Sequence[GET16(meta, hdr->Max_Primary_Element_Entries)]); 370234848Smav for (i = 0; i < num2; i++) 371234848Smav printf(" 0x%08x @ %ju", 372234848Smav GET32D(meta, vdc->Physical_Disk_Sequence[i]), 373234848Smav GET64P(meta, val2 + i)); 374234848Smav printf("\n"); 375234848Smav break; 376234848Smav case DDF_VUCR_SIGNATURE: 377234848Smav printf("** Vendor Unique Configuration **\n"); 378234848Smav vuc = (struct ddf_vuc_record *)vdc; 379234848Smav printf("VD_GUID "); 380234848Smav print_guid(vuc->VD_GUID); 381234848Smav printf("\n"); 382234848Smav break; 383234848Smav case DDF_SA_SIGNATURE: 384234848Smav printf("** Spare Assignment Configuration **\n"); 385234848Smav sa = (struct ddf_sa_record *)vdc; 386234848Smav printf("Timestamp 0x%08x\n", 387234848Smav GET32D(meta, sa->Timestamp)); 388234848Smav printf("Spare_Type 0x%02x\n", 389234848Smav GET8D(meta, sa->Spare_Type)); 390234848Smav printf("Populated_SAEs %u\n", 391234848Smav GET16D(meta, sa->Populated_SAEs)); 392234848Smav printf("MAX_SAE_Supported %u\n", 393234848Smav GET16D(meta, sa->MAX_SAE_Supported)); 394234848Smav for (i = 0; i < GET16D(meta, sa->Populated_SAEs); i++) { 395234848Smav if (isff(sa->entry[i].VD_GUID, 24)) 396234848Smav continue; 397234848Smav printf("VD_GUID "); 398234848Smav for (k = 0; k < 24; k++) 399234848Smav printf("%02x", sa->entry[i].VD_GUID[k]); 400234848Smav printf("\n"); 401234848Smav printf("Secondary_Element %u\n", 402234848Smav GET16D(meta, sa->entry[i].Secondary_Element)); 403234848Smav } 404234848Smav break; 405234899Smav case 0x00000000: 406234848Smav case 0xFFFFFFFF: 407234848Smav break; 408234848Smav default: 409234848Smav printf("Unknown configuration signature %08x\n", val); 410234848Smav break; 411234848Smav } 412234848Smav } 413234848Smav printf("**** Physical Disk Data ****\n"); 414234848Smav printf("PD_GUID "); 415234848Smav print_guid(meta->pdd->PD_GUID); 416234848Smav printf("\n"); 417234848Smav printf("PD_Reference 0x%08x\n", 418234848Smav GET32(meta, pdd->PD_Reference)); 419234848Smav printf("Forced_Ref_Flag 0x%02x\n", 420234848Smav GET8(meta, pdd->Forced_Ref_Flag)); 421234848Smav printf("Forced_PD_GUID_Flag 0x%02x\n", 422234848Smav GET8(meta, pdd->Forced_PD_GUID_Flag)); 423234848Smav} 424234848Smav 425234848Smavstatic int 426234848Smavddf_meta_find_pd(struct ddf_meta *meta, uint8_t *GUID, uint32_t PD_Reference) 427234848Smav{ 428234848Smav int i; 429234848Smav 430234848Smav for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) { 431234848Smav if (GUID != NULL) { 432234848Smav if (memcmp(meta->pdr->entry[i].PD_GUID, GUID, 24) == 0) 433234848Smav return (i); 434234848Smav } else if (PD_Reference != 0xffffffff) { 435234848Smav if (GET32(meta, pdr->entry[i].PD_Reference) == PD_Reference) 436234848Smav return (i); 437234848Smav } else 438234848Smav if (isff(meta->pdr->entry[i].PD_GUID, 24)) 439234848Smav return (i); 440234848Smav } 441234848Smav if (GUID == NULL && PD_Reference == 0xffffffff) { 442234848Smav if (i >= GET16(meta, pdr->Max_PDE_Supported)) 443234848Smav return (-1); 444234848Smav SET16(meta, pdr->Populated_PDEs, i + 1); 445234848Smav return (i); 446234848Smav } 447234848Smav return (-1); 448234848Smav} 449234848Smav 450234848Smavstatic int 451234848Smavddf_meta_find_vd(struct ddf_meta *meta, uint8_t *GUID) 452234848Smav{ 453234848Smav int i; 454234848Smav 455234848Smav for (i = 0; i < GET16(meta, vdr->Populated_VDEs); i++) { 456234848Smav if (GUID != NULL) { 457234848Smav if (memcmp(meta->vdr->entry[i].VD_GUID, GUID, 24) == 0) 458234848Smav return (i); 459234848Smav } else 460234848Smav if (isff(meta->vdr->entry[i].VD_GUID, 24)) 461234848Smav return (i); 462234848Smav } 463234848Smav if (GUID == NULL) { 464234848Smav if (i >= GET16(meta, vdr->Max_VDE_Supported)) 465234848Smav return (-1); 466234848Smav SET16(meta, vdr->Populated_VDEs, i + 1); 467234848Smav return (i); 468234848Smav } 469234848Smav return (-1); 470234848Smav} 471234848Smav 472234848Smavstatic struct ddf_vdc_record * 473234848Smavddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID) 474234848Smav{ 475234848Smav struct ddf_vdc_record *vdc; 476234848Smav int i, num; 477234848Smav 478234869Smav num = GETCRNUM(meta); 479234848Smav for (i = 0; i < num; i++) { 480234869Smav vdc = GETVDCPTR(meta, i); 481234848Smav if (GUID != NULL) { 482234848Smav if (GET32D(meta, vdc->Signature) == DDF_VDCR_SIGNATURE && 483234848Smav memcmp(vdc->VD_GUID, GUID, 24) == 0) 484234848Smav return (vdc); 485234848Smav } else 486234899Smav if (GET32D(meta, vdc->Signature) == 0xffffffff || 487234899Smav GET32D(meta, vdc->Signature) == 0) 488234848Smav return (vdc); 489234848Smav } 490234848Smav return (NULL); 491234848Smav} 492234848Smav 493234848Smavstatic int 494234848Smavddf_meta_count_vdc(struct ddf_meta *meta, uint8_t *GUID) 495234848Smav{ 496234848Smav struct ddf_vdc_record *vdc; 497234848Smav int i, num, cnt; 498234848Smav 499234848Smav cnt = 0; 500234869Smav num = GETCRNUM(meta); 501234848Smav for (i = 0; i < num; i++) { 502234869Smav vdc = GETVDCPTR(meta, i); 503234848Smav if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE) 504234848Smav continue; 505234848Smav if (GUID == NULL || memcmp(vdc->VD_GUID, GUID, 24) == 0) 506234848Smav cnt++; 507234848Smav } 508234848Smav return (cnt); 509234848Smav} 510234848Smav 511234848Smavstatic int 512234848Smavddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference, 513234848Smav int *bvdp, int *posp) 514234848Smav{ 515234848Smav int i, bvd, pos; 516234848Smav 517234848Smav i = 0; 518250819Smav for (bvd = 0; bvd < GET8(vmeta, vdc->Secondary_Element_Count); bvd++) { 519234848Smav if (vmeta->bvdc[bvd] == NULL) { 520234848Smav i += GET16(vmeta, vdc->Primary_Element_Count); // XXX 521234848Smav continue; 522234848Smav } 523234848Smav for (pos = 0; pos < GET16(vmeta, bvdc[bvd]->Primary_Element_Count); 524234848Smav pos++, i++) { 525234848Smav if (GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]) == 526234848Smav PD_Reference) { 527234848Smav if (bvdp != NULL) 528234848Smav *bvdp = bvd; 529234848Smav if (posp != NULL) 530234848Smav *posp = pos; 531234848Smav return (i); 532234848Smav } 533234848Smav } 534234848Smav } 535234848Smav return (-1); 536234848Smav} 537234848Smav 538234899Smavstatic struct ddf_sa_record * 539234899Smavddf_meta_find_sa(struct ddf_meta *meta, int create) 540234899Smav{ 541234899Smav struct ddf_sa_record *sa; 542234899Smav int i, num; 543234899Smav 544234899Smav num = GETCRNUM(meta); 545234899Smav for (i = 0; i < num; i++) { 546234899Smav sa = GETSAPTR(meta, i); 547234899Smav if (GET32D(meta, sa->Signature) == DDF_SA_SIGNATURE) 548234899Smav return (sa); 549234899Smav } 550234899Smav if (create) { 551234899Smav for (i = 0; i < num; i++) { 552234899Smav sa = GETSAPTR(meta, i); 553234899Smav if (GET32D(meta, sa->Signature) == 0xffffffff || 554234899Smav GET32D(meta, sa->Signature) == 0) 555234899Smav return (sa); 556234899Smav } 557234899Smav } 558234899Smav return (NULL); 559234899Smav} 560234899Smav 561234848Smavstatic void 562234848Smavddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample) 563234848Smav{ 564234848Smav struct timespec ts; 565234848Smav struct clocktime ct; 566234848Smav struct g_raid_md_ddf_perdisk *pd; 567234940Smav struct g_raid_md_ddf_object *mdi; 568234848Smav struct ddf_meta *meta; 569234848Smav struct ddf_pd_entry *pde; 570234848Smav off_t anchorlba; 571234848Smav u_int ss, pos, size; 572234848Smav int len, error; 573234848Smav char serial_buffer[24]; 574234848Smav 575234848Smav if (sample->hdr == NULL) 576234848Smav sample = NULL; 577234848Smav 578234940Smav mdi = (struct g_raid_md_ddf_object *)disk->d_softc->sc_md; 579234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 580234848Smav meta = &pd->pd_meta; 581234848Smav ss = disk->d_consumer->provider->sectorsize; 582234848Smav anchorlba = disk->d_consumer->provider->mediasize / ss - 1; 583234848Smav 584234848Smav meta->sectorsize = ss; 585234940Smav meta->bigendian = sample ? sample->bigendian : mdi->mdio_bigendian; 586234848Smav getnanotime(&ts); 587234848Smav clock_ts_to_ct(&ts, &ct); 588234848Smav 589234848Smav /* Header */ 590234848Smav meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK); 591234848Smav memset(meta->hdr, 0xff, ss); 592234848Smav if (sample) { 593234848Smav memcpy(meta->hdr, sample->hdr, sizeof(struct ddf_header)); 594234848Smav if (ss != sample->sectorsize) { 595234848Smav SET32(meta, hdr->WorkSpace_Length, 596298649Spfg howmany(GET32(sample, hdr->WorkSpace_Length) * 597298649Spfg sample->sectorsize, ss)); 598234848Smav SET16(meta, hdr->Configuration_Record_Length, 599298649Spfg howmany(GET16(sample, 600298649Spfg hdr->Configuration_Record_Length) * 601298649Spfg sample->sectorsize, ss)); 602234848Smav SET32(meta, hdr->cd_length, 603298649Spfg howmany(GET32(sample, hdr->cd_length) * 604298649Spfg sample->sectorsize, ss)); 605234848Smav SET32(meta, hdr->pdr_length, 606298649Spfg howmany(GET32(sample, hdr->pdr_length) * 607298649Spfg sample->sectorsize, ss)); 608234848Smav SET32(meta, hdr->vdr_length, 609298649Spfg howmany(GET32(sample, hdr->vdr_length) * 610298649Spfg sample->sectorsize, ss)); 611234848Smav SET32(meta, hdr->cr_length, 612298649Spfg howmany(GET32(sample, hdr->cr_length) * 613298649Spfg sample->sectorsize, ss)); 614234848Smav SET32(meta, hdr->pdd_length, 615298649Spfg howmany(GET32(sample, hdr->pdd_length) * 616298649Spfg sample->sectorsize, ss)); 617234848Smav SET32(meta, hdr->bbmlog_length, 618298649Spfg howmany(GET32(sample, hdr->bbmlog_length) * 619298649Spfg sample->sectorsize, ss)); 620234848Smav SET32(meta, hdr->Diagnostic_Space, 621298649Spfg howmany(GET32(sample, hdr->bbmlog_length) * 622298649Spfg sample->sectorsize, ss)); 623234848Smav SET32(meta, hdr->Vendor_Specific_Logs, 624298649Spfg howmany(GET32(sample, hdr->bbmlog_length) * 625298649Spfg sample->sectorsize, ss)); 626234848Smav } 627234848Smav } else { 628234848Smav SET32(meta, hdr->Signature, DDF_HEADER_SIGNATURE); 629234848Smav snprintf(meta->hdr->DDF_Header_GUID, 25, "FreeBSD %08x%08x", 630234848Smav (u_int)(ts.tv_sec - DECADE), arc4random()); 631234848Smav memcpy(meta->hdr->DDF_rev, "02.00.00", 8); 632234848Smav SET32(meta, hdr->TimeStamp, (ts.tv_sec - DECADE)); 633234848Smav SET32(meta, hdr->WorkSpace_Length, 16 * 1024 * 1024 / ss); 634234848Smav SET16(meta, hdr->Max_PD_Entries, DDF_MAX_DISKS - 1); 635234848Smav SET16(meta, hdr->Max_VD_Entries, DDF_MAX_VDISKS); 636234848Smav SET16(meta, hdr->Max_Partitions, DDF_MAX_PARTITIONS); 637234848Smav SET16(meta, hdr->Max_Primary_Element_Entries, DDF_MAX_DISKS); 638234848Smav SET16(meta, hdr->Configuration_Record_Length, 639298649Spfg howmany(sizeof(struct ddf_vdc_record) + (4 + 8) * 640298649Spfg GET16(meta, hdr->Max_Primary_Element_Entries), ss)); 641234848Smav SET32(meta, hdr->cd_length, 642298649Spfg howmany(sizeof(struct ddf_cd_record), ss)); 643234848Smav SET32(meta, hdr->pdr_length, 644298649Spfg howmany(sizeof(struct ddf_pd_record) + 645298649Spfg sizeof(struct ddf_pd_entry) * GET16(meta, 646298649Spfg hdr->Max_PD_Entries), ss)); 647234848Smav SET32(meta, hdr->vdr_length, 648298649Spfg howmany(sizeof(struct ddf_vd_record) + 649298649Spfg sizeof(struct ddf_vd_entry) * 650298649Spfg GET16(meta, hdr->Max_VD_Entries), ss)); 651234848Smav SET32(meta, hdr->cr_length, 652234848Smav GET16(meta, hdr->Configuration_Record_Length) * 653234848Smav (GET16(meta, hdr->Max_Partitions) + 1)); 654234848Smav SET32(meta, hdr->pdd_length, 655298649Spfg howmany(sizeof(struct ddf_pdd_record), ss)); 656234848Smav SET32(meta, hdr->bbmlog_length, 0); 657234848Smav SET32(meta, hdr->Diagnostic_Space_Length, 0); 658234848Smav SET32(meta, hdr->Vendor_Specific_Logs_Length, 0); 659234848Smav } 660234848Smav pos = 1; 661234848Smav SET32(meta, hdr->cd_section, pos); 662234848Smav pos += GET32(meta, hdr->cd_length); 663234848Smav SET32(meta, hdr->pdr_section, pos); 664234848Smav pos += GET32(meta, hdr->pdr_length); 665234848Smav SET32(meta, hdr->vdr_section, pos); 666234848Smav pos += GET32(meta, hdr->vdr_length); 667234848Smav SET32(meta, hdr->cr_section, pos); 668234848Smav pos += GET32(meta, hdr->cr_length); 669234848Smav SET32(meta, hdr->pdd_section, pos); 670234848Smav pos += GET32(meta, hdr->pdd_length); 671234848Smav SET32(meta, hdr->bbmlog_section, 672234848Smav GET32(meta, hdr->bbmlog_length) != 0 ? pos : 0xffffffff); 673234848Smav pos += GET32(meta, hdr->bbmlog_length); 674234848Smav SET32(meta, hdr->Diagnostic_Space, 675234848Smav GET32(meta, hdr->Diagnostic_Space_Length) != 0 ? pos : 0xffffffff); 676234848Smav pos += GET32(meta, hdr->Diagnostic_Space_Length); 677234848Smav SET32(meta, hdr->Vendor_Specific_Logs, 678234848Smav GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff); 679234899Smav pos += min(GET32(meta, hdr->Vendor_Specific_Logs_Length), 1); 680234848Smav SET64(meta, hdr->Primary_Header_LBA, 681234899Smav anchorlba - pos); 682234848Smav SET64(meta, hdr->Secondary_Header_LBA, 683234848Smav 0xffffffffffffffffULL); 684234848Smav SET64(meta, hdr->WorkSpace_LBA, 685234848Smav anchorlba + 1 - 32 * 1024 * 1024 / ss); 686234848Smav 687234848Smav /* Controller Data */ 688234848Smav size = GET32(meta, hdr->cd_length) * ss; 689234848Smav meta->cdr = malloc(size, M_MD_DDF, M_WAITOK); 690234848Smav memset(meta->cdr, 0xff, size); 691234848Smav SET32(meta, cdr->Signature, DDF_CONTROLLER_DATA_SIGNATURE); 692234848Smav memcpy(meta->cdr->Controller_GUID, "FreeBSD GEOM RAID SERIAL", 24); 693234848Smav memcpy(meta->cdr->Product_ID, "FreeBSD GEOMRAID", 16); 694234848Smav 695234848Smav /* Physical Drive Records. */ 696234848Smav size = GET32(meta, hdr->pdr_length) * ss; 697234848Smav meta->pdr = malloc(size, M_MD_DDF, M_WAITOK); 698234848Smav memset(meta->pdr, 0xff, size); 699234848Smav SET32(meta, pdr->Signature, DDF_PDR_SIGNATURE); 700234848Smav SET16(meta, pdr->Populated_PDEs, 1); 701234848Smav SET16(meta, pdr->Max_PDE_Supported, 702234848Smav GET16(meta, hdr->Max_PD_Entries)); 703234848Smav 704234848Smav pde = &meta->pdr->entry[0]; 705234848Smav len = sizeof(serial_buffer); 706234848Smav error = g_io_getattr("GEOM::ident", disk->d_consumer, &len, serial_buffer); 707234848Smav if (error == 0 && (len = strlen (serial_buffer)) >= 6 && len <= 20) 708234848Smav snprintf(pde->PD_GUID, 25, "DISK%20s", serial_buffer); 709234848Smav else 710234848Smav snprintf(pde->PD_GUID, 25, "DISK%04d%02d%02d%08x%04x", 711234848Smav ct.year, ct.mon, ct.day, 712234848Smav arc4random(), arc4random() & 0xffff); 713234848Smav SET32D(meta, pde->PD_Reference, arc4random()); 714234848Smav SET16D(meta, pde->PD_Type, DDF_PDE_GUID_FORCE); 715234848Smav SET16D(meta, pde->PD_State, 0); 716234848Smav SET64D(meta, pde->Configured_Size, 717234848Smav anchorlba + 1 - 32 * 1024 * 1024 / ss); 718234848Smav SET16D(meta, pde->Block_Size, ss); 719234848Smav 720234848Smav /* Virtual Drive Records. */ 721234848Smav size = GET32(meta, hdr->vdr_length) * ss; 722234848Smav meta->vdr = malloc(size, M_MD_DDF, M_WAITOK); 723234848Smav memset(meta->vdr, 0xff, size); 724234848Smav SET32(meta, vdr->Signature, DDF_VD_RECORD_SIGNATURE); 725234848Smav SET32(meta, vdr->Populated_VDEs, 0); 726234848Smav SET16(meta, vdr->Max_VDE_Supported, 727234848Smav GET16(meta, hdr->Max_VD_Entries)); 728234848Smav 729234848Smav /* Configuration Records. */ 730234848Smav size = GET32(meta, hdr->cr_length) * ss; 731234848Smav meta->cr = malloc(size, M_MD_DDF, M_WAITOK); 732234848Smav memset(meta->cr, 0xff, size); 733234848Smav 734234848Smav /* Physical Disk Data. */ 735234848Smav size = GET32(meta, hdr->pdd_length) * ss; 736234848Smav meta->pdd = malloc(size, M_MD_DDF, M_WAITOK); 737234848Smav memset(meta->pdd, 0xff, size); 738234848Smav SET32(meta, pdd->Signature, DDF_PDD_SIGNATURE); 739234848Smav memcpy(meta->pdd->PD_GUID, pde->PD_GUID, 24); 740234848Smav SET32(meta, pdd->PD_Reference, GET32D(meta, pde->PD_Reference)); 741234848Smav SET8(meta, pdd->Forced_Ref_Flag, DDF_PDD_FORCED_REF); 742234848Smav SET8(meta, pdd->Forced_PD_GUID_Flag, DDF_PDD_FORCED_GUID); 743234848Smav 744234848Smav /* Bad Block Management Log. */ 745234848Smav if (GET32(meta, hdr->bbmlog_length) != 0) { 746234848Smav size = GET32(meta, hdr->bbmlog_length) * ss; 747234848Smav meta->bbm = malloc(size, M_MD_DDF, M_WAITOK); 748234848Smav memset(meta->bbm, 0xff, size); 749234848Smav SET32(meta, bbm->Signature, DDF_BBML_SIGNATURE); 750234848Smav SET32(meta, bbm->Entry_Count, 0); 751234848Smav SET32(meta, bbm->Spare_Block_Count, 0); 752234848Smav } 753234848Smav} 754234848Smav 755234848Smavstatic void 756234848Smavddf_meta_copy(struct ddf_meta *dst, struct ddf_meta *src) 757234848Smav{ 758234848Smav struct ddf_header *hdr; 759234848Smav u_int ss; 760234848Smav 761234848Smav hdr = src->hdr; 762234848Smav dst->bigendian = src->bigendian; 763234848Smav ss = dst->sectorsize = src->sectorsize; 764234848Smav dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK); 765234848Smav memcpy(dst->hdr, src->hdr, ss); 766234848Smav dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK); 767234848Smav memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss); 768234848Smav dst->pdr = malloc(GET32(src, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK); 769234848Smav memcpy(dst->pdr, src->pdr, GET32(src, hdr->pdr_length) * ss); 770234848Smav dst->vdr = malloc(GET32(src, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK); 771234848Smav memcpy(dst->vdr, src->vdr, GET32(src, hdr->vdr_length) * ss); 772234848Smav dst->cr = malloc(GET32(src, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK); 773234848Smav memcpy(dst->cr, src->cr, GET32(src, hdr->cr_length) * ss); 774234848Smav dst->pdd = malloc(GET32(src, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK); 775234848Smav memcpy(dst->pdd, src->pdd, GET32(src, hdr->pdd_length) * ss); 776234848Smav if (src->bbm != NULL) { 777234848Smav dst->bbm = malloc(GET32(src, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK); 778234848Smav memcpy(dst->bbm, src->bbm, GET32(src, hdr->bbmlog_length) * ss); 779234848Smav } 780234848Smav} 781234848Smav 782234848Smavstatic void 783234848Smavddf_meta_update(struct ddf_meta *meta, struct ddf_meta *src) 784234848Smav{ 785234848Smav struct ddf_pd_entry *pde, *spde; 786234848Smav int i, j; 787234848Smav 788234848Smav for (i = 0; i < GET16(src, pdr->Populated_PDEs); i++) { 789234848Smav spde = &src->pdr->entry[i]; 790234848Smav if (isff(spde->PD_GUID, 24)) 791234848Smav continue; 792234848Smav j = ddf_meta_find_pd(meta, NULL, 793234994Smav GET32(src, pdr->entry[i].PD_Reference)); 794234848Smav if (j < 0) { 795234848Smav j = ddf_meta_find_pd(meta, NULL, 0xffffffff); 796234848Smav pde = &meta->pdr->entry[j]; 797234848Smav memcpy(pde, spde, sizeof(*pde)); 798234848Smav } else { 799234848Smav pde = &meta->pdr->entry[j]; 800234848Smav SET16D(meta, pde->PD_State, 801234848Smav GET16D(meta, pde->PD_State) | 802234848Smav GET16D(src, pde->PD_State)); 803234848Smav } 804234848Smav } 805234848Smav} 806234848Smav 807234848Smavstatic void 808234848Smavddf_meta_free(struct ddf_meta *meta) 809234848Smav{ 810234848Smav 811234848Smav if (meta->hdr != NULL) { 812234848Smav free(meta->hdr, M_MD_DDF); 813234848Smav meta->hdr = NULL; 814234848Smav } 815234848Smav if (meta->cdr != NULL) { 816234848Smav free(meta->cdr, M_MD_DDF); 817234848Smav meta->cdr = NULL; 818234848Smav } 819234848Smav if (meta->pdr != NULL) { 820234848Smav free(meta->pdr, M_MD_DDF); 821234848Smav meta->pdr = NULL; 822234848Smav } 823234848Smav if (meta->vdr != NULL) { 824234848Smav free(meta->vdr, M_MD_DDF); 825234848Smav meta->vdr = NULL; 826234848Smav } 827234848Smav if (meta->cr != NULL) { 828234848Smav free(meta->cr, M_MD_DDF); 829234848Smav meta->cr = NULL; 830234848Smav } 831234848Smav if (meta->pdd != NULL) { 832234848Smav free(meta->pdd, M_MD_DDF); 833234848Smav meta->pdd = NULL; 834234848Smav } 835234848Smav if (meta->bbm != NULL) { 836234848Smav free(meta->bbm, M_MD_DDF); 837234848Smav meta->bbm = NULL; 838234848Smav } 839234848Smav} 840234848Smav 841234848Smavstatic void 842234848Smavddf_vol_meta_create(struct ddf_vol_meta *meta, struct ddf_meta *sample) 843234848Smav{ 844234848Smav struct timespec ts; 845234848Smav struct clocktime ct; 846234848Smav struct ddf_header *hdr; 847234848Smav u_int ss, size; 848234848Smav 849234848Smav hdr = sample->hdr; 850234848Smav meta->bigendian = sample->bigendian; 851234848Smav ss = meta->sectorsize = sample->sectorsize; 852234848Smav meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK); 853234848Smav memcpy(meta->hdr, sample->hdr, ss); 854234848Smav meta->cdr = malloc(GET32(sample, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK); 855234848Smav memcpy(meta->cdr, sample->cdr, GET32(sample, hdr->cd_length) * ss); 856234848Smav meta->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK); 857234848Smav memset(meta->vde, 0xff, sizeof(struct ddf_vd_entry)); 858234848Smav getnanotime(&ts); 859234848Smav clock_ts_to_ct(&ts, &ct); 860234848Smav snprintf(meta->vde->VD_GUID, 25, "FreeBSD%04d%02d%02d%08x%01x", 861234848Smav ct.year, ct.mon, ct.day, 862234848Smav arc4random(), arc4random() & 0xf); 863234848Smav size = GET16(sample, hdr->Configuration_Record_Length) * ss; 864234848Smav meta->vdc = malloc(size, M_MD_DDF, M_WAITOK); 865234848Smav memset(meta->vdc, 0xff, size); 866234848Smav SET32(meta, vdc->Signature, DDF_VDCR_SIGNATURE); 867234848Smav memcpy(meta->vdc->VD_GUID, meta->vde->VD_GUID, 24); 868234848Smav SET32(meta, vdc->Sequence_Number, 0); 869234848Smav} 870234848Smav 871234848Smavstatic void 872234868Smavddf_vol_meta_update(struct ddf_vol_meta *dst, struct ddf_meta *src, 873234868Smav uint8_t *GUID, int started) 874234848Smav{ 875234848Smav struct ddf_header *hdr; 876234848Smav struct ddf_vd_entry *vde; 877234848Smav struct ddf_vdc_record *vdc; 878234848Smav int vnew, bvnew, bvd, size; 879234848Smav u_int ss; 880234848Smav 881234848Smav hdr = src->hdr; 882234848Smav vde = &src->vdr->entry[ddf_meta_find_vd(src, GUID)]; 883234848Smav vdc = ddf_meta_find_vdc(src, GUID); 884247918Smav if (GET8D(src, vdc->Secondary_Element_Count) == 1) 885247918Smav bvd = 0; 886247918Smav else 887247918Smav bvd = GET8D(src, vdc->Secondary_Element_Seq); 888234848Smav size = GET16(src, hdr->Configuration_Record_Length) * src->sectorsize; 889234848Smav 890234848Smav if (dst->vdc == NULL || 891234868Smav (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) - 892234868Smav GET32(dst, vdc->Sequence_Number))) > 0)) 893234848Smav vnew = 1; 894234848Smav else 895234848Smav vnew = 0; 896234848Smav 897234848Smav if (dst->bvdc[bvd] == NULL || 898234868Smav (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) - 899234868Smav GET32(dst, bvdc[bvd]->Sequence_Number))) > 0)) 900234848Smav bvnew = 1; 901234848Smav else 902234848Smav bvnew = 0; 903234848Smav 904234848Smav if (vnew) { 905234848Smav dst->bigendian = src->bigendian; 906234848Smav ss = dst->sectorsize = src->sectorsize; 907234848Smav if (dst->hdr != NULL) 908234848Smav free(dst->hdr, M_MD_DDF); 909234848Smav dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK); 910234848Smav memcpy(dst->hdr, src->hdr, ss); 911234848Smav if (dst->cdr != NULL) 912234848Smav free(dst->cdr, M_MD_DDF); 913234848Smav dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK); 914234848Smav memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss); 915234848Smav if (dst->vde != NULL) 916234848Smav free(dst->vde, M_MD_DDF); 917234848Smav dst->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK); 918234848Smav memcpy(dst->vde, vde, sizeof(struct ddf_vd_entry)); 919234848Smav if (dst->vdc != NULL) 920234848Smav free(dst->vdc, M_MD_DDF); 921234848Smav dst->vdc = malloc(size, M_MD_DDF, M_WAITOK); 922234848Smav memcpy(dst->vdc, vdc, size); 923234848Smav } 924234848Smav if (bvnew) { 925234848Smav if (dst->bvdc[bvd] != NULL) 926234848Smav free(dst->bvdc[bvd], M_MD_DDF); 927234848Smav dst->bvdc[bvd] = malloc(size, M_MD_DDF, M_WAITOK); 928234848Smav memcpy(dst->bvdc[bvd], vdc, size); 929234848Smav } 930234848Smav} 931234848Smav 932234848Smavstatic void 933234848Smavddf_vol_meta_free(struct ddf_vol_meta *meta) 934234848Smav{ 935234848Smav int i; 936234848Smav 937234848Smav if (meta->hdr != NULL) { 938234848Smav free(meta->hdr, M_MD_DDF); 939234848Smav meta->hdr = NULL; 940234848Smav } 941234848Smav if (meta->cdr != NULL) { 942234848Smav free(meta->cdr, M_MD_DDF); 943234848Smav meta->cdr = NULL; 944234848Smav } 945234848Smav if (meta->vde != NULL) { 946234848Smav free(meta->vde, M_MD_DDF); 947234848Smav meta->vde = NULL; 948234848Smav } 949234848Smav if (meta->vdc != NULL) { 950234848Smav free(meta->vdc, M_MD_DDF); 951234848Smav meta->vdc = NULL; 952234848Smav } 953234848Smav for (i = 0; i < DDF_MAX_DISKS_HARD; i++) { 954234848Smav if (meta->bvdc[i] != NULL) { 955234848Smav free(meta->bvdc[i], M_MD_DDF); 956234848Smav meta->bvdc[i] = NULL; 957234848Smav } 958234848Smav } 959234848Smav} 960234848Smav 961234848Smavstatic int 962234848Smavddf_meta_unused_range(struct ddf_meta *meta, off_t *off, off_t *size) 963234848Smav{ 964234848Smav struct ddf_vdc_record *vdc; 965234848Smav off_t beg[32], end[32], beg1, end1; 966234848Smav uint64_t *offp; 967234848Smav int i, j, n, num, pos; 968234848Smav uint32_t ref; 969234848Smav 970234848Smav *off = 0; 971234848Smav *size = 0; 972234848Smav ref = GET32(meta, pdd->PD_Reference); 973234848Smav pos = ddf_meta_find_pd(meta, NULL, ref); 974234848Smav beg[0] = 0; 975234848Smav end[0] = GET64(meta, pdr->entry[pos].Configured_Size); 976234848Smav n = 1; 977234869Smav num = GETCRNUM(meta); 978234848Smav for (i = 0; i < num; i++) { 979234869Smav vdc = GETVDCPTR(meta, i); 980234848Smav if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE) 981234848Smav continue; 982234848Smav for (pos = 0; pos < GET16D(meta, vdc->Primary_Element_Count); pos++) 983234848Smav if (GET32D(meta, vdc->Physical_Disk_Sequence[pos]) == ref) 984234848Smav break; 985234848Smav if (pos == GET16D(meta, vdc->Primary_Element_Count)) 986234848Smav continue; 987234848Smav offp = (uint64_t *)&(vdc->Physical_Disk_Sequence[ 988234848Smav GET16(meta, hdr->Max_Primary_Element_Entries)]); 989234848Smav beg1 = GET64P(meta, offp + pos); 990234848Smav end1 = beg1 + GET64D(meta, vdc->Block_Count); 991234848Smav for (j = 0; j < n; j++) { 992234848Smav if (beg[j] >= end1 || end[j] <= beg1 ) 993234848Smav continue; 994234848Smav if (beg[j] < beg1 && end[j] > end1) { 995234848Smav beg[n] = end1; 996234848Smav end[n] = end[j]; 997234848Smav end[j] = beg1; 998234848Smav n++; 999234848Smav } else if (beg[j] < beg1) 1000234848Smav end[j] = beg1; 1001234848Smav else 1002234848Smav beg[j] = end1; 1003234848Smav } 1004234848Smav } 1005234848Smav for (j = 0; j < n; j++) { 1006234848Smav if (end[j] - beg[j] > *size) { 1007234848Smav *off = beg[j]; 1008234848Smav *size = end[j] - beg[j]; 1009234848Smav } 1010234848Smav } 1011234848Smav return ((*size > 0) ? 1 : 0); 1012234848Smav} 1013234848Smav 1014234848Smavstatic void 1015234848Smavddf_meta_get_name(struct ddf_meta *meta, int num, char *buf) 1016234848Smav{ 1017234848Smav const char *b; 1018234848Smav int i; 1019234848Smav 1020234848Smav b = meta->vdr->entry[num].VD_Name; 1021234848Smav for (i = 15; i >= 0; i--) 1022234848Smav if (b[i] != 0x20) 1023234848Smav break; 1024234848Smav memcpy(buf, b, i + 1); 1025234848Smav buf[i + 1] = 0; 1026234848Smav} 1027234848Smav 1028234848Smavstatic void 1029234848Smavddf_meta_put_name(struct ddf_vol_meta *meta, char *buf) 1030234848Smav{ 1031234848Smav int len; 1032234848Smav 1033234848Smav len = min(strlen(buf), 16); 1034234848Smav memset(meta->vde->VD_Name, 0x20, 16); 1035234848Smav memcpy(meta->vde->VD_Name, buf, len); 1036234848Smav} 1037234848Smav 1038234848Smavstatic int 1039234848Smavddf_meta_read(struct g_consumer *cp, struct ddf_meta *meta) 1040234848Smav{ 1041234848Smav struct g_provider *pp; 1042234848Smav struct ddf_header *ahdr, *hdr; 1043234848Smav char *abuf, *buf; 1044234848Smav off_t plba, slba, lba; 1045234848Smav int error, len, i; 1046234848Smav u_int ss; 1047234848Smav uint32_t val; 1048234848Smav 1049234848Smav ddf_meta_free(meta); 1050234848Smav pp = cp->provider; 1051234848Smav ss = meta->sectorsize = pp->sectorsize; 1052234848Smav /* Read anchor block. */ 1053234848Smav abuf = g_read_data(cp, pp->mediasize - ss, ss, &error); 1054234848Smav if (abuf == NULL) { 1055234848Smav G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).", 1056234848Smav pp->name, error); 1057234848Smav return (error); 1058234848Smav } 1059234848Smav ahdr = (struct ddf_header *)abuf; 1060234848Smav 1061234848Smav /* Check if this is an DDF RAID struct */ 1062234848Smav if (be32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE) 1063234848Smav meta->bigendian = 1; 1064234848Smav else if (le32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE) 1065234848Smav meta->bigendian = 0; 1066234848Smav else { 1067234848Smav G_RAID_DEBUG(1, "DDF signature check failed on %s", pp->name); 1068234848Smav error = EINVAL; 1069234848Smav goto done; 1070234848Smav } 1071234848Smav if (ahdr->Header_Type != DDF_HEADER_ANCHOR) { 1072234848Smav G_RAID_DEBUG(1, "DDF header type check failed on %s", pp->name); 1073234848Smav error = EINVAL; 1074234848Smav goto done; 1075234848Smav } 1076234848Smav meta->hdr = ahdr; 1077234848Smav plba = GET64(meta, hdr->Primary_Header_LBA); 1078234848Smav slba = GET64(meta, hdr->Secondary_Header_LBA); 1079234848Smav val = GET32(meta, hdr->CRC); 1080234848Smav SET32(meta, hdr->CRC, 0xffffffff); 1081234848Smav meta->hdr = NULL; 1082234848Smav if (crc32(ahdr, ss) != val) { 1083234848Smav G_RAID_DEBUG(1, "DDF CRC mismatch on %s", pp->name); 1084234848Smav error = EINVAL; 1085234848Smav goto done; 1086234848Smav } 1087234848Smav if ((plba + 6) * ss >= pp->mediasize) { 1088234848Smav G_RAID_DEBUG(1, "DDF primary header LBA is wrong on %s", pp->name); 1089234848Smav error = EINVAL; 1090234848Smav goto done; 1091234848Smav } 1092234848Smav if (slba != -1 && (slba + 6) * ss >= pp->mediasize) { 1093234848Smav G_RAID_DEBUG(1, "DDF secondary header LBA is wrong on %s", pp->name); 1094234848Smav error = EINVAL; 1095234848Smav goto done; 1096234848Smav } 1097234848Smav lba = plba; 1098234848Smav 1099234848Smavdoread: 1100234848Smav error = 0; 1101234848Smav ddf_meta_free(meta); 1102234848Smav 1103234848Smav /* Read header block. */ 1104234848Smav buf = g_read_data(cp, lba * ss, ss, &error); 1105234848Smav if (buf == NULL) { 1106234848Smavreaderror: 1107234848Smav G_RAID_DEBUG(1, "DDF %s metadata read error on %s (error=%d).", 1108234848Smav (lba == plba) ? "primary" : "secondary", pp->name, error); 1109234848Smav if (lba == plba && slba != -1) { 1110234848Smav lba = slba; 1111234848Smav goto doread; 1112234848Smav } 1113234848Smav G_RAID_DEBUG(1, "DDF metadata read error on %s.", pp->name); 1114234848Smav goto done; 1115234848Smav } 1116234848Smav meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK); 1117234848Smav memcpy(meta->hdr, buf, ss); 1118234848Smav g_free(buf); 1119234848Smav hdr = meta->hdr; 1120234848Smav val = GET32(meta, hdr->CRC); 1121234848Smav SET32(meta, hdr->CRC, 0xffffffff); 1122234848Smav if (hdr->Signature != ahdr->Signature || 1123234848Smav crc32(meta->hdr, ss) != val || 1124234848Smav memcmp(hdr->DDF_Header_GUID, ahdr->DDF_Header_GUID, 24) || 1125234848Smav GET64(meta, hdr->Primary_Header_LBA) != plba || 1126234848Smav GET64(meta, hdr->Secondary_Header_LBA) != slba) { 1127234848Smavhdrerror: 1128234848Smav G_RAID_DEBUG(1, "DDF %s metadata check failed on %s", 1129234848Smav (lba == plba) ? "primary" : "secondary", pp->name); 1130234848Smav if (lba == plba && slba != -1) { 1131234848Smav lba = slba; 1132234848Smav goto doread; 1133234848Smav } 1134234848Smav G_RAID_DEBUG(1, "DDF metadata check failed on %s", pp->name); 1135234848Smav error = EINVAL; 1136234848Smav goto done; 1137234848Smav } 1138234848Smav if ((lba == plba && hdr->Header_Type != DDF_HEADER_PRIMARY) || 1139234848Smav (lba == slba && hdr->Header_Type != DDF_HEADER_SECONDARY)) 1140234848Smav goto hdrerror; 1141234848Smav len = 1; 1142234848Smav len = max(len, GET32(meta, hdr->cd_section) + GET32(meta, hdr->cd_length)); 1143234848Smav len = max(len, GET32(meta, hdr->pdr_section) + GET32(meta, hdr->pdr_length)); 1144234848Smav len = max(len, GET32(meta, hdr->vdr_section) + GET32(meta, hdr->vdr_length)); 1145234848Smav len = max(len, GET32(meta, hdr->cr_section) + GET32(meta, hdr->cr_length)); 1146234848Smav len = max(len, GET32(meta, hdr->pdd_section) + GET32(meta, hdr->pdd_length)); 1147234848Smav if ((val = GET32(meta, hdr->bbmlog_section)) != 0xffffffff) 1148234848Smav len = max(len, val + GET32(meta, hdr->bbmlog_length)); 1149234848Smav if ((val = GET32(meta, hdr->Diagnostic_Space)) != 0xffffffff) 1150234848Smav len = max(len, val + GET32(meta, hdr->Diagnostic_Space_Length)); 1151234848Smav if ((val = GET32(meta, hdr->Vendor_Specific_Logs)) != 0xffffffff) 1152234848Smav len = max(len, val + GET32(meta, hdr->Vendor_Specific_Logs_Length)); 1153234848Smav if ((plba + len) * ss >= pp->mediasize) 1154234848Smav goto hdrerror; 1155234848Smav if (slba != -1 && (slba + len) * ss >= pp->mediasize) 1156234848Smav goto hdrerror; 1157234848Smav /* Workaround for Adaptec implementation. */ 1158234848Smav if (GET16(meta, hdr->Max_Primary_Element_Entries) == 0xffff) { 1159234848Smav SET16(meta, hdr->Max_Primary_Element_Entries, 1160234848Smav min(GET16(meta, hdr->Max_PD_Entries), 1161234848Smav (GET16(meta, hdr->Configuration_Record_Length) * ss - 512) / 12)); 1162234848Smav } 1163234848Smav 1164234848Smav /* Read controller data. */ 1165234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss, 1166234848Smav GET32(meta, hdr->cd_length) * ss, &error); 1167234848Smav if (buf == NULL) 1168234848Smav goto readerror; 1169234848Smav meta->cdr = malloc(GET32(meta, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK); 1170234848Smav memcpy(meta->cdr, buf, GET32(meta, hdr->cd_length) * ss); 1171234848Smav g_free(buf); 1172234848Smav if (GET32(meta, cdr->Signature) != DDF_CONTROLLER_DATA_SIGNATURE) 1173234848Smav goto hdrerror; 1174234848Smav 1175234848Smav /* Read physical disk records. */ 1176234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss, 1177234848Smav GET32(meta, hdr->pdr_length) * ss, &error); 1178234848Smav if (buf == NULL) 1179234848Smav goto readerror; 1180234848Smav meta->pdr = malloc(GET32(meta, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK); 1181234848Smav memcpy(meta->pdr, buf, GET32(meta, hdr->pdr_length) * ss); 1182234848Smav g_free(buf); 1183234848Smav if (GET32(meta, pdr->Signature) != DDF_PDR_SIGNATURE) 1184234848Smav goto hdrerror; 1185264318Smav /* 1186264318Smav * Workaround for reading metadata corrupted due to graid bug. 1187264318Smav * XXX: Remove this before we have disks above 128PB. :) 1188264318Smav */ 1189264318Smav if (meta->bigendian) { 1190264318Smav for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) { 1191264318Smav if (isff(meta->pdr->entry[i].PD_GUID, 24)) 1192264318Smav continue; 1193264318Smav if (GET32(meta, pdr->entry[i].PD_Reference) == 1194264318Smav 0xffffffff) 1195264318Smav continue; 1196264318Smav if (GET64(meta, pdr->entry[i].Configured_Size) >= 1197264318Smav (1ULL << 48)) { 1198264318Smav SET16(meta, pdr->entry[i].PD_State, 1199264318Smav GET16(meta, pdr->entry[i].PD_State) & 1200264318Smav ~DDF_PDE_FAILED); 1201264318Smav SET64(meta, pdr->entry[i].Configured_Size, 1202264318Smav GET64(meta, pdr->entry[i].Configured_Size) & 1203264318Smav ((1ULL << 48) - 1)); 1204264318Smav } 1205264318Smav } 1206264318Smav } 1207234848Smav 1208234848Smav /* Read virtual disk records. */ 1209234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss, 1210234848Smav GET32(meta, hdr->vdr_length) * ss, &error); 1211234848Smav if (buf == NULL) 1212234848Smav goto readerror; 1213234848Smav meta->vdr = malloc(GET32(meta, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK); 1214234848Smav memcpy(meta->vdr, buf, GET32(meta, hdr->vdr_length) * ss); 1215234848Smav g_free(buf); 1216234848Smav if (GET32(meta, vdr->Signature) != DDF_VD_RECORD_SIGNATURE) 1217234848Smav goto hdrerror; 1218234848Smav 1219234848Smav /* Read configuration records. */ 1220234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss, 1221234848Smav GET32(meta, hdr->cr_length) * ss, &error); 1222234848Smav if (buf == NULL) 1223234848Smav goto readerror; 1224234848Smav meta->cr = malloc(GET32(meta, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK); 1225234848Smav memcpy(meta->cr, buf, GET32(meta, hdr->cr_length) * ss); 1226234848Smav g_free(buf); 1227234848Smav 1228234848Smav /* Read physical disk data. */ 1229234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss, 1230234848Smav GET32(meta, hdr->pdd_length) * ss, &error); 1231234848Smav if (buf == NULL) 1232234848Smav goto readerror; 1233234848Smav meta->pdd = malloc(GET32(meta, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK); 1234234848Smav memcpy(meta->pdd, buf, GET32(meta, hdr->pdd_length) * ss); 1235234848Smav g_free(buf); 1236234848Smav if (GET32(meta, pdd->Signature) != DDF_PDD_SIGNATURE) 1237234848Smav goto hdrerror; 1238234848Smav i = ddf_meta_find_pd(meta, NULL, GET32(meta, pdd->PD_Reference)); 1239234848Smav if (i < 0) 1240234848Smav goto hdrerror; 1241234848Smav 1242234848Smav /* Read BBM Log. */ 1243234848Smav if (GET32(meta, hdr->bbmlog_section) != 0xffffffff && 1244234848Smav GET32(meta, hdr->bbmlog_length) != 0) { 1245234848Smav buf = g_read_data(cp, (lba + GET32(meta, hdr->bbmlog_section)) * ss, 1246234848Smav GET32(meta, hdr->bbmlog_length) * ss, &error); 1247234848Smav if (buf == NULL) 1248234848Smav goto readerror; 1249234848Smav meta->bbm = malloc(GET32(meta, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK); 1250234848Smav memcpy(meta->bbm, buf, GET32(meta, hdr->bbmlog_length) * ss); 1251234848Smav g_free(buf); 1252234848Smav if (GET32(meta, bbm->Signature) != DDF_BBML_SIGNATURE) 1253234848Smav goto hdrerror; 1254234848Smav } 1255234848Smav 1256234848Smavdone: 1257235080Smav g_free(abuf); 1258234848Smav if (error != 0) 1259234848Smav ddf_meta_free(meta); 1260234848Smav return (error); 1261234848Smav} 1262234848Smav 1263234848Smavstatic int 1264234848Smavddf_meta_write(struct g_consumer *cp, struct ddf_meta *meta) 1265234848Smav{ 1266234848Smav struct g_provider *pp; 1267234848Smav struct ddf_vdc_record *vdc; 1268234848Smav off_t alba, plba, slba, lba; 1269234848Smav u_int ss, size; 1270234848Smav int error, i, num; 1271234848Smav 1272234848Smav pp = cp->provider; 1273234848Smav ss = pp->sectorsize; 1274234848Smav lba = alba = pp->mediasize / ss - 1; 1275234848Smav plba = GET64(meta, hdr->Primary_Header_LBA); 1276234848Smav slba = GET64(meta, hdr->Secondary_Header_LBA); 1277234848Smav 1278234848Smavnext: 1279234848Smav SET8(meta, hdr->Header_Type, (lba == alba) ? DDF_HEADER_ANCHOR : 1280234848Smav (lba == plba) ? DDF_HEADER_PRIMARY : DDF_HEADER_SECONDARY); 1281234848Smav SET32(meta, hdr->CRC, 0xffffffff); 1282234848Smav SET32(meta, hdr->CRC, crc32(meta->hdr, ss)); 1283234848Smav error = g_write_data(cp, lba * ss, meta->hdr, ss); 1284234848Smav if (error != 0) { 1285234848Smaverr: 1286234848Smav G_RAID_DEBUG(1, "Cannot write metadata to %s (error=%d).", 1287234848Smav pp->name, error); 1288234848Smav if (lba != alba) 1289234848Smav goto done; 1290234848Smav } 1291234848Smav if (lba == alba) { 1292234848Smav lba = plba; 1293234848Smav goto next; 1294234848Smav } 1295234848Smav 1296234848Smav size = GET32(meta, hdr->cd_length) * ss; 1297234848Smav SET32(meta, cdr->CRC, 0xffffffff); 1298234848Smav SET32(meta, cdr->CRC, crc32(meta->cdr, size)); 1299234848Smav error = g_write_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss, 1300234848Smav meta->cdr, size); 1301234848Smav if (error != 0) 1302234848Smav goto err; 1303234848Smav 1304234848Smav size = GET32(meta, hdr->pdr_length) * ss; 1305234848Smav SET32(meta, pdr->CRC, 0xffffffff); 1306234848Smav SET32(meta, pdr->CRC, crc32(meta->pdr, size)); 1307234848Smav error = g_write_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss, 1308234848Smav meta->pdr, size); 1309234848Smav if (error != 0) 1310234848Smav goto err; 1311234848Smav 1312234848Smav size = GET32(meta, hdr->vdr_length) * ss; 1313234848Smav SET32(meta, vdr->CRC, 0xffffffff); 1314234848Smav SET32(meta, vdr->CRC, crc32(meta->vdr, size)); 1315234848Smav error = g_write_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss, 1316234848Smav meta->vdr, size); 1317234848Smav if (error != 0) 1318234848Smav goto err; 1319234848Smav 1320234869Smav size = GET16(meta, hdr->Configuration_Record_Length) * ss; 1321234869Smav num = GETCRNUM(meta); 1322234848Smav for (i = 0; i < num; i++) { 1323234869Smav vdc = GETVDCPTR(meta, i); 1324234848Smav SET32D(meta, vdc->CRC, 0xffffffff); 1325234848Smav SET32D(meta, vdc->CRC, crc32(vdc, size)); 1326234848Smav } 1327234848Smav error = g_write_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss, 1328234848Smav meta->cr, size * num); 1329234848Smav if (error != 0) 1330234848Smav goto err; 1331234848Smav 1332234848Smav size = GET32(meta, hdr->pdd_length) * ss; 1333234848Smav SET32(meta, pdd->CRC, 0xffffffff); 1334234848Smav SET32(meta, pdd->CRC, crc32(meta->pdd, size)); 1335234848Smav error = g_write_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss, 1336234848Smav meta->pdd, size); 1337234848Smav if (error != 0) 1338234848Smav goto err; 1339234848Smav 1340234848Smav if (GET32(meta, hdr->bbmlog_length) != 0) { 1341234848Smav size = GET32(meta, hdr->bbmlog_length) * ss; 1342234848Smav SET32(meta, bbm->CRC, 0xffffffff); 1343234848Smav SET32(meta, bbm->CRC, crc32(meta->bbm, size)); 1344234848Smav error = g_write_data(cp, 1345234848Smav (lba + GET32(meta, hdr->bbmlog_section)) * ss, 1346234848Smav meta->bbm, size); 1347234848Smav if (error != 0) 1348234848Smav goto err; 1349234848Smav } 1350234848Smav 1351234848Smavdone: 1352234848Smav if (lba == plba && slba != -1) { 1353234848Smav lba = slba; 1354234848Smav goto next; 1355234848Smav } 1356234848Smav 1357234848Smav return (error); 1358234848Smav} 1359234848Smav 1360234848Smavstatic int 1361234848Smavddf_meta_erase(struct g_consumer *cp) 1362234848Smav{ 1363234848Smav struct g_provider *pp; 1364234848Smav char *buf; 1365234848Smav int error; 1366234848Smav 1367234848Smav pp = cp->provider; 1368234848Smav buf = malloc(pp->sectorsize, M_MD_DDF, M_WAITOK | M_ZERO); 1369234848Smav error = g_write_data(cp, pp->mediasize - pp->sectorsize, 1370234848Smav buf, pp->sectorsize); 1371234848Smav if (error != 0) { 1372234848Smav G_RAID_DEBUG(1, "Cannot erase metadata on %s (error=%d).", 1373234848Smav pp->name, error); 1374234848Smav } 1375234848Smav free(buf, M_MD_DDF); 1376234848Smav return (error); 1377234848Smav} 1378234848Smav 1379234848Smavstatic struct g_raid_volume * 1380234848Smavg_raid_md_ddf_get_volume(struct g_raid_softc *sc, uint8_t *GUID) 1381234848Smav{ 1382234848Smav struct g_raid_volume *vol; 1383234848Smav struct g_raid_md_ddf_pervolume *pv; 1384234848Smav 1385234848Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 1386234848Smav pv = vol->v_md_data; 1387234848Smav if (memcmp(pv->pv_meta.vde->VD_GUID, GUID, 24) == 0) 1388234848Smav break; 1389234848Smav } 1390234848Smav return (vol); 1391234848Smav} 1392234848Smav 1393234848Smavstatic struct g_raid_disk * 1394234848Smavg_raid_md_ddf_get_disk(struct g_raid_softc *sc, uint8_t *GUID, uint32_t id) 1395234848Smav{ 1396234848Smav struct g_raid_disk *disk; 1397234848Smav struct g_raid_md_ddf_perdisk *pd; 1398234848Smav struct ddf_meta *meta; 1399234848Smav 1400234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 1401234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 1402234848Smav meta = &pd->pd_meta; 1403234848Smav if (GUID != NULL) { 1404234848Smav if (memcmp(meta->pdd->PD_GUID, GUID, 24) == 0) 1405234848Smav break; 1406234848Smav } else { 1407234848Smav if (GET32(meta, pdd->PD_Reference) == id) 1408234848Smav break; 1409234848Smav } 1410234848Smav } 1411234848Smav return (disk); 1412234848Smav} 1413234848Smav 1414234848Smavstatic int 1415234848Smavg_raid_md_ddf_purge_volumes(struct g_raid_softc *sc) 1416234848Smav{ 1417234848Smav struct g_raid_volume *vol, *tvol; 1418234848Smav struct g_raid_md_ddf_pervolume *pv; 1419234848Smav int i, res; 1420234848Smav 1421234848Smav res = 0; 1422234848Smav TAILQ_FOREACH_SAFE(vol, &sc->sc_volumes, v_next, tvol) { 1423234848Smav pv = vol->v_md_data; 1424234848Smav if (vol->v_stopping) 1425234848Smav continue; 1426234848Smav for (i = 0; i < vol->v_disks_count; i++) { 1427234848Smav if (vol->v_subdisks[i].sd_state != G_RAID_SUBDISK_S_NONE) 1428234848Smav break; 1429234848Smav } 1430234848Smav if (i >= vol->v_disks_count) { 1431234848Smav g_raid_destroy_volume(vol); 1432234848Smav res = 1; 1433234848Smav } 1434234848Smav } 1435234848Smav return (res); 1436234848Smav} 1437234848Smav 1438234848Smavstatic int 1439234848Smavg_raid_md_ddf_purge_disks(struct g_raid_softc *sc) 1440234848Smav{ 1441234848Smav#if 0 1442234848Smav struct g_raid_disk *disk, *tdisk; 1443234848Smav struct g_raid_volume *vol; 1444234848Smav struct g_raid_md_ddf_perdisk *pd; 1445234848Smav int i, j, res; 1446234848Smav 1447234848Smav res = 0; 1448234848Smav TAILQ_FOREACH_SAFE(disk, &sc->sc_disks, d_next, tdisk) { 1449234848Smav if (disk->d_state == G_RAID_DISK_S_SPARE) 1450234848Smav continue; 1451234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 1452234848Smav 1453234848Smav /* Scan for deleted volumes. */ 1454234848Smav for (i = 0; i < pd->pd_subdisks; ) { 1455234848Smav vol = g_raid_md_ddf_get_volume(sc, 1456234848Smav pd->pd_meta[i]->volume_id); 1457234848Smav if (vol != NULL && !vol->v_stopping) { 1458234848Smav i++; 1459234848Smav continue; 1460234848Smav } 1461234848Smav free(pd->pd_meta[i], M_MD_DDF); 1462234848Smav for (j = i; j < pd->pd_subdisks - 1; j++) 1463234848Smav pd->pd_meta[j] = pd->pd_meta[j + 1]; 1464234848Smav pd->pd_meta[DDF_MAX_SUBDISKS - 1] = NULL; 1465234848Smav pd->pd_subdisks--; 1466234848Smav pd->pd_updated = 1; 1467234848Smav } 1468234848Smav 1469234848Smav /* If there is no metadata left - erase and delete disk. */ 1470234848Smav if (pd->pd_subdisks == 0) { 1471234848Smav ddf_meta_erase(disk->d_consumer); 1472234848Smav g_raid_destroy_disk(disk); 1473234848Smav res = 1; 1474234848Smav } 1475234848Smav } 1476234848Smav return (res); 1477234848Smav#endif 1478234848Smav return (0); 1479234848Smav} 1480234848Smav 1481234848Smavstatic int 1482234848Smavg_raid_md_ddf_supported(int level, int qual, int disks, int force) 1483234848Smav{ 1484234848Smav 1485234848Smav if (disks > DDF_MAX_DISKS_HARD) 1486234848Smav return (0); 1487234848Smav switch (level) { 1488234848Smav case G_RAID_VOLUME_RL_RAID0: 1489234848Smav if (qual != G_RAID_VOLUME_RLQ_NONE) 1490234848Smav return (0); 1491234848Smav if (disks < 1) 1492234848Smav return (0); 1493234848Smav if (!force && disks < 2) 1494234848Smav return (0); 1495234848Smav break; 1496234848Smav case G_RAID_VOLUME_RL_RAID1: 1497234848Smav if (disks < 1) 1498234848Smav return (0); 1499234848Smav if (qual == G_RAID_VOLUME_RLQ_R1SM) { 1500234848Smav if (!force && disks != 2) 1501234848Smav return (0); 1502234848Smav } else if (qual == G_RAID_VOLUME_RLQ_R1MM) { 1503234848Smav if (!force && disks != 3) 1504234848Smav return (0); 1505234848Smav } else 1506234848Smav return (0); 1507234848Smav break; 1508234848Smav case G_RAID_VOLUME_RL_RAID3: 1509234848Smav if (qual != G_RAID_VOLUME_RLQ_R3P0 && 1510234848Smav qual != G_RAID_VOLUME_RLQ_R3PN) 1511234848Smav return (0); 1512234848Smav if (disks < 3) 1513234848Smav return (0); 1514234848Smav break; 1515234848Smav case G_RAID_VOLUME_RL_RAID4: 1516234848Smav if (qual != G_RAID_VOLUME_RLQ_R4P0 && 1517234848Smav qual != G_RAID_VOLUME_RLQ_R4PN) 1518234848Smav return (0); 1519234848Smav if (disks < 3) 1520234848Smav return (0); 1521234848Smav break; 1522234848Smav case G_RAID_VOLUME_RL_RAID5: 1523234848Smav if (qual != G_RAID_VOLUME_RLQ_R5RA && 1524234848Smav qual != G_RAID_VOLUME_RLQ_R5RS && 1525234848Smav qual != G_RAID_VOLUME_RLQ_R5LA && 1526234848Smav qual != G_RAID_VOLUME_RLQ_R5LS) 1527234848Smav return (0); 1528234848Smav if (disks < 3) 1529234848Smav return (0); 1530234848Smav break; 1531234848Smav case G_RAID_VOLUME_RL_RAID6: 1532234848Smav if (qual != G_RAID_VOLUME_RLQ_R6RA && 1533234848Smav qual != G_RAID_VOLUME_RLQ_R6RS && 1534234848Smav qual != G_RAID_VOLUME_RLQ_R6LA && 1535234848Smav qual != G_RAID_VOLUME_RLQ_R6LS) 1536234848Smav return (0); 1537234848Smav if (disks < 4) 1538234848Smav return (0); 1539234848Smav break; 1540234848Smav case G_RAID_VOLUME_RL_RAIDMDF: 1541234848Smav if (qual != G_RAID_VOLUME_RLQ_RMDFRA && 1542234848Smav qual != G_RAID_VOLUME_RLQ_RMDFRS && 1543234848Smav qual != G_RAID_VOLUME_RLQ_RMDFLA && 1544234848Smav qual != G_RAID_VOLUME_RLQ_RMDFLS) 1545234848Smav return (0); 1546235076Smav if (disks < 4) 1547234848Smav return (0); 1548234848Smav break; 1549234848Smav case G_RAID_VOLUME_RL_RAID1E: 1550234848Smav if (qual != G_RAID_VOLUME_RLQ_R1EA && 1551234848Smav qual != G_RAID_VOLUME_RLQ_R1EO) 1552234848Smav return (0); 1553234869Smav if (disks < 3) 1554234848Smav return (0); 1555234848Smav break; 1556234848Smav case G_RAID_VOLUME_RL_SINGLE: 1557234848Smav if (qual != G_RAID_VOLUME_RLQ_NONE) 1558234848Smav return (0); 1559234848Smav if (disks != 1) 1560234848Smav return (0); 1561234848Smav break; 1562234848Smav case G_RAID_VOLUME_RL_CONCAT: 1563234848Smav if (qual != G_RAID_VOLUME_RLQ_NONE) 1564234848Smav return (0); 1565234848Smav if (disks < 2) 1566234848Smav return (0); 1567234848Smav break; 1568234848Smav case G_RAID_VOLUME_RL_RAID5E: 1569234848Smav if (qual != G_RAID_VOLUME_RLQ_R5ERA && 1570234848Smav qual != G_RAID_VOLUME_RLQ_R5ERS && 1571234848Smav qual != G_RAID_VOLUME_RLQ_R5ELA && 1572234848Smav qual != G_RAID_VOLUME_RLQ_R5ELS) 1573234848Smav return (0); 1574234848Smav if (disks < 4) 1575234848Smav return (0); 1576234848Smav break; 1577234848Smav case G_RAID_VOLUME_RL_RAID5EE: 1578234848Smav if (qual != G_RAID_VOLUME_RLQ_R5EERA && 1579234848Smav qual != G_RAID_VOLUME_RLQ_R5EERS && 1580234848Smav qual != G_RAID_VOLUME_RLQ_R5EELA && 1581234848Smav qual != G_RAID_VOLUME_RLQ_R5EELS) 1582234848Smav return (0); 1583234848Smav if (disks < 4) 1584234848Smav return (0); 1585234848Smav break; 1586234848Smav case G_RAID_VOLUME_RL_RAID5R: 1587234848Smav if (qual != G_RAID_VOLUME_RLQ_R5RRA && 1588234848Smav qual != G_RAID_VOLUME_RLQ_R5RRS && 1589234848Smav qual != G_RAID_VOLUME_RLQ_R5RLA && 1590234848Smav qual != G_RAID_VOLUME_RLQ_R5RLS) 1591234848Smav return (0); 1592234848Smav if (disks < 3) 1593234848Smav return (0); 1594234848Smav break; 1595234848Smav default: 1596234848Smav return (0); 1597234848Smav } 1598234848Smav return (1); 1599234848Smav} 1600234848Smav 1601234848Smavstatic int 1602234848Smavg_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol) 1603234848Smav{ 1604234848Smav struct g_raid_softc *sc; 1605234848Smav struct g_raid_subdisk *sd; 1606234848Smav struct g_raid_md_ddf_perdisk *pd; 1607234848Smav struct g_raid_md_ddf_pervolume *pv; 1608234848Smav struct g_raid_md_ddf_object *mdi; 1609234848Smav struct ddf_vol_meta *vmeta; 1610234848Smav struct ddf_meta *pdmeta, *gmeta; 1611234848Smav struct ddf_vdc_record *vdc1; 1612234899Smav struct ddf_sa_record *sa; 1613234848Smav off_t size, eoff = 0, esize = 0; 1614234848Smav uint64_t *val2; 1615234848Smav int disk_pos, md_disk_bvd = -1, md_disk_pos = -1, md_pde_pos; 1616234848Smav int i, resurrection = 0; 1617234848Smav uint32_t reference; 1618234848Smav 1619234848Smav sc = disk->d_softc; 1620234848Smav mdi = (struct g_raid_md_ddf_object *)sc->sc_md; 1621234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 1622234848Smav pdmeta = &pd->pd_meta; 1623234848Smav reference = GET32(&pd->pd_meta, pdd->PD_Reference); 1624234848Smav 1625234848Smav pv = vol->v_md_data; 1626234848Smav vmeta = &pv->pv_meta; 1627234848Smav gmeta = &mdi->mdio_meta; 1628234848Smav 1629234848Smav /* Find disk position in metadata by it's reference. */ 1630234848Smav disk_pos = ddf_meta_find_disk(vmeta, reference, 1631234848Smav &md_disk_bvd, &md_disk_pos); 1632234848Smav md_pde_pos = ddf_meta_find_pd(gmeta, NULL, reference); 1633234848Smav 1634234848Smav if (disk_pos < 0) { 1635234899Smav G_RAID_DEBUG1(1, sc, 1636234899Smav "Disk %s is not a present part of the volume %s", 1637234848Smav g_raid_get_diskname(disk), vol->v_name); 1638234848Smav 1639234848Smav /* Failed stale disk is useless for us. */ 1640234848Smav if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) != 0) { 1641234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE_FAILED); 1642234848Smav return (0); 1643234848Smav } 1644234848Smav 1645234848Smav /* If disk has some metadata for this volume - erase. */ 1646234899Smav if ((vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) 1647234848Smav SET32D(pdmeta, vdc1->Signature, 0xffffffff); 1648234848Smav 1649234848Smav /* If we are in the start process, that's all for now. */ 1650234848Smav if (!pv->pv_started) 1651234848Smav goto nofit; 1652234848Smav /* 1653234848Smav * If we have already started - try to get use of the disk. 1654234848Smav * Try to replace OFFLINE disks first, then FAILED. 1655234848Smav */ 1656234848Smav if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >= 1657234848Smav GET16(&pd->pd_meta, hdr->Max_Partitions)) { 1658234848Smav G_RAID_DEBUG1(1, sc, "No free partitions on disk %s", 1659234848Smav g_raid_get_diskname(disk)); 1660234848Smav goto nofit; 1661234848Smav } 1662234848Smav ddf_meta_unused_range(&pd->pd_meta, &eoff, &esize); 1663234848Smav if (esize == 0) { 1664234848Smav G_RAID_DEBUG1(1, sc, "No free space on disk %s", 1665234848Smav g_raid_get_diskname(disk)); 1666234848Smav goto nofit; 1667234848Smav } 1668235096Smav eoff *= pd->pd_meta.sectorsize; 1669235096Smav esize *= pd->pd_meta.sectorsize; 1670234848Smav size = INT64_MAX; 1671234848Smav for (i = 0; i < vol->v_disks_count; i++) { 1672234848Smav sd = &vol->v_subdisks[i]; 1673234848Smav if (sd->sd_state != G_RAID_SUBDISK_S_NONE) 1674234848Smav size = sd->sd_size; 1675234848Smav if (sd->sd_state <= G_RAID_SUBDISK_S_FAILED && 1676234848Smav (disk_pos < 0 || 1677234848Smav vol->v_subdisks[i].sd_state < sd->sd_state)) 1678234848Smav disk_pos = i; 1679234848Smav } 1680234848Smav if (disk_pos >= 0 && 1681234848Smav vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT && 1682235096Smav esize < size) { 1683234848Smav G_RAID_DEBUG1(1, sc, "Disk %s free space " 1684234848Smav "is too small (%ju < %ju)", 1685235096Smav g_raid_get_diskname(disk), esize, size); 1686234848Smav disk_pos = -1; 1687234848Smav } 1688234848Smav if (disk_pos >= 0) { 1689234848Smav if (vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT) 1690235096Smav esize = size; 1691234848Smav md_disk_bvd = disk_pos / GET16(vmeta, vdc->Primary_Element_Count); // XXX 1692234848Smav md_disk_pos = disk_pos % GET16(vmeta, vdc->Primary_Element_Count); // XXX 1693234848Smav } else { 1694234848Smavnofit: 1695234899Smav if (disk->d_state == G_RAID_DISK_S_NONE) 1696234848Smav g_raid_change_disk_state(disk, 1697234899Smav G_RAID_DISK_S_STALE); 1698234848Smav return (0); 1699234848Smav } 1700234899Smav 1701234899Smav /* 1702234899Smav * If spare is committable, delete spare record. 1703234899Smav * Othersize, mark it active and leave there. 1704234899Smav */ 1705234899Smav sa = ddf_meta_find_sa(&pd->pd_meta, 0); 1706234899Smav if (sa != NULL) { 1707234899Smav if ((GET8D(&pd->pd_meta, sa->Spare_Type) & 1708234899Smav DDF_SAR_TYPE_REVERTIBLE) == 0) { 1709234899Smav SET32D(&pd->pd_meta, sa->Signature, 0xffffffff); 1710234899Smav } else { 1711234899Smav SET8D(&pd->pd_meta, sa->Spare_Type, 1712234899Smav GET8D(&pd->pd_meta, sa->Spare_Type) | 1713234899Smav DDF_SAR_TYPE_ACTIVE); 1714234899Smav } 1715234899Smav } 1716234899Smav 1717234848Smav G_RAID_DEBUG1(1, sc, "Disk %s takes pos %d in the volume %s", 1718234848Smav g_raid_get_diskname(disk), disk_pos, vol->v_name); 1719234848Smav resurrection = 1; 1720234848Smav } 1721234848Smav 1722234848Smav sd = &vol->v_subdisks[disk_pos]; 1723234848Smav 1724234848Smav if (resurrection && sd->sd_disk != NULL) { 1725234848Smav g_raid_change_disk_state(sd->sd_disk, 1726234848Smav G_RAID_DISK_S_STALE_FAILED); 1727234848Smav TAILQ_REMOVE(&sd->sd_disk->d_subdisks, 1728234848Smav sd, sd_next); 1729234848Smav } 1730234848Smav vol->v_subdisks[disk_pos].sd_disk = disk; 1731234848Smav TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next); 1732234848Smav 1733234848Smav /* Welcome the new disk. */ 1734234848Smav if (resurrection) 1735234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE); 1736264318Smav else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) 1737234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED); 1738234848Smav else 1739234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE); 1740234848Smav 1741234848Smav if (resurrection) { 1742235096Smav sd->sd_offset = eoff; 1743235096Smav sd->sd_size = esize; 1744234848Smav } else if (pdmeta->cr != NULL && 1745234848Smav (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) { 1746234848Smav val2 = (uint64_t *)&(vdc1->Physical_Disk_Sequence[GET16(vmeta, hdr->Max_Primary_Element_Entries)]); 1747234848Smav sd->sd_offset = (off_t)GET64P(pdmeta, val2 + md_disk_pos) * 512; 1748234848Smav sd->sd_size = (off_t)GET64D(pdmeta, vdc1->Block_Count) * 512; 1749234848Smav } 1750234848Smav 1751234848Smav if (resurrection) { 1752234848Smav /* Stale disk, almost same as new. */ 1753234848Smav g_raid_change_subdisk_state(sd, 1754234848Smav G_RAID_SUBDISK_S_NEW); 1755264318Smav } else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) { 1756234848Smav /* Failed disk. */ 1757234848Smav g_raid_change_subdisk_state(sd, 1758234848Smav G_RAID_SUBDISK_S_FAILED); 1759264318Smav } else if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & 1760234848Smav (DDF_PDE_FAILED | DDF_PDE_REBUILD)) != 0) { 1761234848Smav /* Rebuilding disk. */ 1762234848Smav g_raid_change_subdisk_state(sd, 1763234848Smav G_RAID_SUBDISK_S_REBUILD); 1764234848Smav sd->sd_rebuild_pos = 0; 1765234848Smav } else if ((GET8(vmeta, vde->VD_State) & DDF_VDE_DIRTY) != 0 || 1766234848Smav (GET8(vmeta, vde->Init_State) & DDF_VDE_INIT_MASK) != 1767234848Smav DDF_VDE_INIT_FULL) { 1768234848Smav /* Stale disk or dirty volume (unclean shutdown). */ 1769234848Smav g_raid_change_subdisk_state(sd, 1770234848Smav G_RAID_SUBDISK_S_STALE); 1771234848Smav } else { 1772234848Smav /* Up to date disk. */ 1773234848Smav g_raid_change_subdisk_state(sd, 1774234848Smav G_RAID_SUBDISK_S_ACTIVE); 1775234848Smav } 1776234848Smav g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW, 1777234848Smav G_RAID_EVENT_SUBDISK); 1778234848Smav 1779234848Smav return (resurrection); 1780234848Smav} 1781234848Smav 1782234848Smavstatic void 1783234848Smavg_raid_md_ddf_refill(struct g_raid_softc *sc) 1784234848Smav{ 1785234848Smav struct g_raid_volume *vol; 1786234848Smav struct g_raid_subdisk *sd; 1787234848Smav struct g_raid_disk *disk; 1788234848Smav struct g_raid_md_object *md; 1789234848Smav struct g_raid_md_ddf_perdisk *pd; 1790234848Smav struct g_raid_md_ddf_pervolume *pv; 1791234848Smav int update, updated, i, bad; 1792234848Smav 1793234848Smav md = sc->sc_md; 1794234848Smavrestart: 1795234848Smav updated = 0; 1796234848Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 1797234848Smav pv = vol->v_md_data; 1798234848Smav if (!pv->pv_started || vol->v_stopping) 1799234848Smav continue; 1800234848Smav 1801234848Smav /* Search for subdisk that needs replacement. */ 1802234848Smav bad = 0; 1803234848Smav for (i = 0; i < vol->v_disks_count; i++) { 1804234848Smav sd = &vol->v_subdisks[i]; 1805234848Smav if (sd->sd_state == G_RAID_SUBDISK_S_NONE || 1806234848Smav sd->sd_state == G_RAID_SUBDISK_S_FAILED) 1807234848Smav bad = 1; 1808234848Smav } 1809234848Smav if (!bad) 1810234848Smav continue; 1811234848Smav 1812234848Smav G_RAID_DEBUG1(1, sc, "Volume %s is not complete, " 1813234848Smav "trying to refill.", vol->v_name); 1814234848Smav 1815234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 1816234848Smav /* Skip failed. */ 1817234848Smav if (disk->d_state < G_RAID_DISK_S_SPARE) 1818234848Smav continue; 1819234848Smav /* Skip already used by this volume. */ 1820234848Smav for (i = 0; i < vol->v_disks_count; i++) { 1821234848Smav sd = &vol->v_subdisks[i]; 1822234848Smav if (sd->sd_disk == disk) 1823234848Smav break; 1824234848Smav } 1825234848Smav if (i < vol->v_disks_count) 1826234848Smav continue; 1827234848Smav 1828234848Smav /* Try to use disk if it has empty extents. */ 1829234848Smav pd = disk->d_md_data; 1830234848Smav if (ddf_meta_count_vdc(&pd->pd_meta, NULL) < 1831234848Smav GET16(&pd->pd_meta, hdr->Max_Partitions)) { 1832234848Smav update = g_raid_md_ddf_start_disk(disk, vol); 1833234848Smav } else 1834234848Smav update = 0; 1835234848Smav if (update) { 1836234848Smav updated = 1; 1837234848Smav g_raid_md_write_ddf(md, vol, NULL, disk); 1838234848Smav break; 1839234848Smav } 1840234848Smav } 1841234848Smav } 1842234848Smav if (updated) 1843234848Smav goto restart; 1844234848Smav} 1845234848Smav 1846234848Smavstatic void 1847234848Smavg_raid_md_ddf_start(struct g_raid_volume *vol) 1848234848Smav{ 1849234848Smav struct g_raid_softc *sc; 1850234848Smav struct g_raid_subdisk *sd; 1851234848Smav struct g_raid_disk *disk; 1852234848Smav struct g_raid_md_object *md; 1853234899Smav struct g_raid_md_ddf_perdisk *pd; 1854234848Smav struct g_raid_md_ddf_pervolume *pv; 1855234868Smav struct g_raid_md_ddf_object *mdi; 1856234848Smav struct ddf_vol_meta *vmeta; 1857234848Smav struct ddf_vdc_record *vdc; 1858234848Smav uint64_t *val2; 1859234848Smav int i, j, bvd; 1860234848Smav 1861234848Smav sc = vol->v_softc; 1862234848Smav md = sc->sc_md; 1863234868Smav mdi = (struct g_raid_md_ddf_object *)md; 1864234848Smav pv = vol->v_md_data; 1865234848Smav vmeta = &pv->pv_meta; 1866234848Smav vdc = vmeta->vdc; 1867234848Smav 1868234848Smav vol->v_raid_level = GET8(vmeta, vdc->Primary_RAID_Level); 1869234848Smav vol->v_raid_level_qualifier = GET8(vmeta, vdc->RLQ); 1870234848Smav if (GET8(vmeta, vdc->Secondary_Element_Count) > 1 && 1871234848Smav vol->v_raid_level == G_RAID_VOLUME_RL_RAID1 && 1872234848Smav GET8(vmeta, vdc->Secondary_RAID_Level) == 0) 1873234848Smav vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E; 1874234848Smav vol->v_sectorsize = GET16(vmeta, vdc->Block_Size); 1875234848Smav if (vol->v_sectorsize == 0xffff) 1876234848Smav vol->v_sectorsize = vmeta->sectorsize; 1877234848Smav vol->v_strip_size = vol->v_sectorsize << GET8(vmeta, vdc->Stripe_Size); 1878234848Smav vol->v_disks_count = GET16(vmeta, vdc->Primary_Element_Count) * 1879234848Smav GET8(vmeta, vdc->Secondary_Element_Count); 1880235076Smav vol->v_mdf_pdisks = GET8(vmeta, vdc->MDF_Parity_Disks); 1881235076Smav vol->v_mdf_polynomial = GET16(vmeta, vdc->MDF_Parity_Generator_Polynomial); 1882235076Smav vol->v_mdf_method = GET8(vmeta, vdc->MDF_Constant_Generation_Method); 1883235076Smav if (GET8(vmeta, vdc->Rotate_Parity_count) > 31) 1884235076Smav vol->v_rotate_parity = 1; 1885235076Smav else 1886235076Smav vol->v_rotate_parity = 1 << GET8(vmeta, vdc->Rotate_Parity_count); 1887234848Smav vol->v_mediasize = GET64(vmeta, vdc->VD_Size) * vol->v_sectorsize; 1888234848Smav for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) { 1889234848Smav if (j == GET16(vmeta, vdc->Primary_Element_Count)) { 1890234848Smav j = 0; 1891234848Smav bvd++; 1892234848Smav } 1893234848Smav sd = &vol->v_subdisks[i]; 1894234848Smav if (vmeta->bvdc[bvd] == NULL) { 1895234848Smav sd->sd_offset = 0; 1896234848Smav sd->sd_size = GET64(vmeta, vdc->Block_Count) * 1897234848Smav vol->v_sectorsize; 1898234848Smav continue; 1899234848Smav } 1900234848Smav val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[ 1901234848Smav GET16(vmeta, hdr->Max_Primary_Element_Entries)]); 1902234848Smav sd->sd_offset = GET64P(vmeta, val2 + j) * vol->v_sectorsize; 1903234848Smav sd->sd_size = GET64(vmeta, bvdc[bvd]->Block_Count) * 1904234848Smav vol->v_sectorsize; 1905234848Smav } 1906234848Smav g_raid_start_volume(vol); 1907234848Smav 1908234848Smav /* Make all disks found till the moment take their places. */ 1909234899Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 1910234899Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 1911234899Smav if (ddf_meta_find_vdc(&pd->pd_meta, vmeta->vdc->VD_GUID) != NULL) 1912234848Smav g_raid_md_ddf_start_disk(disk, vol); 1913234848Smav } 1914234848Smav 1915234848Smav pv->pv_started = 1; 1916234868Smav mdi->mdio_starting--; 1917234848Smav callout_stop(&pv->pv_start_co); 1918234848Smav G_RAID_DEBUG1(0, sc, "Volume started."); 1919234848Smav g_raid_md_write_ddf(md, vol, NULL, NULL); 1920234848Smav 1921234848Smav /* Pickup any STALE/SPARE disks to refill array if needed. */ 1922234848Smav g_raid_md_ddf_refill(sc); 1923234848Smav 1924234848Smav g_raid_event_send(vol, G_RAID_VOLUME_E_START, G_RAID_EVENT_VOLUME); 1925234848Smav} 1926234848Smav 1927234848Smavstatic void 1928234848Smavg_raid_ddf_go(void *arg) 1929234848Smav{ 1930234848Smav struct g_raid_volume *vol; 1931234848Smav struct g_raid_softc *sc; 1932234848Smav struct g_raid_md_ddf_pervolume *pv; 1933234848Smav 1934234848Smav vol = arg; 1935234848Smav pv = vol->v_md_data; 1936234848Smav sc = vol->v_softc; 1937234848Smav if (!pv->pv_started) { 1938234848Smav G_RAID_DEBUG1(0, sc, "Force volume start due to timeout."); 1939234848Smav g_raid_event_send(vol, G_RAID_VOLUME_E_STARTMD, 1940234848Smav G_RAID_EVENT_VOLUME); 1941234848Smav } 1942234848Smav} 1943234848Smav 1944234848Smavstatic void 1945234848Smavg_raid_md_ddf_new_disk(struct g_raid_disk *disk) 1946234848Smav{ 1947234848Smav struct g_raid_softc *sc; 1948234848Smav struct g_raid_md_object *md; 1949234848Smav struct g_raid_md_ddf_perdisk *pd; 1950234848Smav struct g_raid_md_ddf_pervolume *pv; 1951234848Smav struct g_raid_md_ddf_object *mdi; 1952234848Smav struct g_raid_volume *vol; 1953234848Smav struct ddf_meta *pdmeta; 1954234848Smav struct ddf_vol_meta *vmeta; 1955234848Smav struct ddf_vdc_record *vdc; 1956234848Smav struct ddf_vd_entry *vde; 1957234899Smav int i, j, k, num, have, need, cnt, spare; 1958234848Smav uint32_t val; 1959234848Smav char buf[17]; 1960234848Smav 1961234848Smav sc = disk->d_softc; 1962234848Smav md = sc->sc_md; 1963234848Smav mdi = (struct g_raid_md_ddf_object *)md; 1964234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 1965234848Smav pdmeta = &pd->pd_meta; 1966234848Smav spare = -1; 1967234848Smav 1968234848Smav if (mdi->mdio_meta.hdr == NULL) 1969234848Smav ddf_meta_copy(&mdi->mdio_meta, pdmeta); 1970234848Smav else 1971234848Smav ddf_meta_update(&mdi->mdio_meta, pdmeta); 1972234848Smav 1973234869Smav num = GETCRNUM(pdmeta); 1974234848Smav for (j = 0; j < num; j++) { 1975234869Smav vdc = GETVDCPTR(pdmeta, j); 1976234848Smav val = GET32D(pdmeta, vdc->Signature); 1977234848Smav 1978234848Smav if (val == DDF_SA_SIGNATURE && spare == -1) 1979234848Smav spare = 1; 1980234848Smav 1981234848Smav if (val != DDF_VDCR_SIGNATURE) 1982234848Smav continue; 1983234848Smav spare = 0; 1984234848Smav k = ddf_meta_find_vd(pdmeta, vdc->VD_GUID); 1985234848Smav if (k < 0) 1986234848Smav continue; 1987234848Smav vde = &pdmeta->vdr->entry[k]; 1988234848Smav 1989234848Smav /* Look for volume with matching ID. */ 1990234848Smav vol = g_raid_md_ddf_get_volume(sc, vdc->VD_GUID); 1991234848Smav if (vol == NULL) { 1992234848Smav ddf_meta_get_name(pdmeta, k, buf); 1993234848Smav vol = g_raid_create_volume(sc, buf, 1994234848Smav GET16D(pdmeta, vde->VD_Number)); 1995234848Smav pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO); 1996234848Smav vol->v_md_data = pv; 1997234848Smav callout_init(&pv->pv_start_co, 1); 1998234848Smav callout_reset(&pv->pv_start_co, 1999234848Smav g_raid_start_timeout * hz, 2000234848Smav g_raid_ddf_go, vol); 2001234868Smav mdi->mdio_starting++; 2002234848Smav } else 2003234848Smav pv = vol->v_md_data; 2004234848Smav 2005234848Smav /* If we haven't started yet - check metadata freshness. */ 2006234848Smav vmeta = &pv->pv_meta; 2007234868Smav ddf_vol_meta_update(vmeta, pdmeta, vdc->VD_GUID, pv->pv_started); 2008234848Smav } 2009234848Smav 2010234848Smav if (spare == 1) { 2011234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE); 2012234848Smav g_raid_md_ddf_refill(sc); 2013234848Smav } 2014234848Smav 2015234848Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 2016234848Smav pv = vol->v_md_data; 2017234848Smav vmeta = &pv->pv_meta; 2018234848Smav 2019234899Smav if (ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID) == NULL) 2020234899Smav continue; 2021234899Smav 2022234899Smav if (pv->pv_started) { 2023234899Smav if (g_raid_md_ddf_start_disk(disk, vol)) 2024234899Smav g_raid_md_write_ddf(md, vol, NULL, NULL); 2025234899Smav continue; 2026234899Smav } 2027234899Smav 2028234848Smav /* If we collected all needed disks - start array. */ 2029234848Smav need = 0; 2030234848Smav have = 0; 2031234848Smav for (k = 0; k < GET8(vmeta, vdc->Secondary_Element_Count); k++) { 2032234848Smav if (vmeta->bvdc[k] == NULL) { 2033234848Smav need += GET16(vmeta, vdc->Primary_Element_Count); 2034234848Smav continue; 2035234848Smav } 2036234848Smav cnt = GET16(vmeta, bvdc[k]->Primary_Element_Count); 2037234848Smav need += cnt; 2038234848Smav for (i = 0; i < cnt; i++) { 2039234848Smav val = GET32(vmeta, bvdc[k]->Physical_Disk_Sequence[i]); 2040234899Smav if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL) 2041234848Smav have++; 2042234848Smav } 2043234848Smav } 2044234899Smav G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks", 2045234899Smav vol->v_name, have, need); 2046234899Smav if (have == need) 2047234899Smav g_raid_md_ddf_start(vol); 2048234848Smav } 2049234848Smav} 2050234848Smav 2051234848Smavstatic int 2052234940Smavg_raid_md_create_req_ddf(struct g_raid_md_object *md, struct g_class *mp, 2053234940Smav struct gctl_req *req, struct g_geom **gp) 2054234848Smav{ 2055234848Smav struct g_geom *geom; 2056234848Smav struct g_raid_softc *sc; 2057234940Smav struct g_raid_md_ddf_object *mdi, *mdi1; 2058234940Smav char name[16]; 2059234940Smav const char *fmtopt; 2060234940Smav int be = 1; 2061234848Smav 2062234940Smav mdi = (struct g_raid_md_ddf_object *)md; 2063234940Smav fmtopt = gctl_get_asciiparam(req, "fmtopt"); 2064234940Smav if (fmtopt == NULL || strcasecmp(fmtopt, "BE") == 0) 2065234940Smav be = 1; 2066234940Smav else if (strcasecmp(fmtopt, "LE") == 0) 2067234940Smav be = 0; 2068234940Smav else { 2069234940Smav gctl_error(req, "Incorrect fmtopt argument."); 2070234940Smav return (G_RAID_MD_TASTE_FAIL); 2071234940Smav } 2072234940Smav 2073234848Smav /* Search for existing node. */ 2074234848Smav LIST_FOREACH(geom, &mp->geom, geom) { 2075234848Smav sc = geom->softc; 2076234848Smav if (sc == NULL) 2077234848Smav continue; 2078234848Smav if (sc->sc_stopping != 0) 2079234848Smav continue; 2080234848Smav if (sc->sc_md->mdo_class != md->mdo_class) 2081234848Smav continue; 2082234940Smav mdi1 = (struct g_raid_md_ddf_object *)sc->sc_md; 2083234940Smav if (mdi1->mdio_bigendian != be) 2084234940Smav continue; 2085234848Smav break; 2086234848Smav } 2087234848Smav if (geom != NULL) { 2088234848Smav *gp = geom; 2089234848Smav return (G_RAID_MD_TASTE_EXISTING); 2090234848Smav } 2091234848Smav 2092234848Smav /* Create new one if not found. */ 2093234940Smav mdi->mdio_bigendian = be; 2094234940Smav snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE"); 2095234940Smav sc = g_raid_create_node(mp, name, md); 2096234848Smav if (sc == NULL) 2097234848Smav return (G_RAID_MD_TASTE_FAIL); 2098234848Smav md->mdo_softc = sc; 2099234848Smav *gp = sc->sc_geom; 2100234848Smav return (G_RAID_MD_TASTE_NEW); 2101234848Smav} 2102234848Smav 2103234848Smavstatic int 2104234848Smavg_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp, 2105234848Smav struct g_consumer *cp, struct g_geom **gp) 2106234848Smav{ 2107234848Smav struct g_consumer *rcp; 2108234848Smav struct g_provider *pp; 2109234848Smav struct g_raid_softc *sc; 2110234848Smav struct g_raid_disk *disk; 2111234848Smav struct ddf_meta meta; 2112234848Smav struct g_raid_md_ddf_perdisk *pd; 2113234940Smav struct g_raid_md_ddf_object *mdi; 2114234848Smav struct g_geom *geom; 2115242323Smav int error, result, be; 2116234848Smav char name[16]; 2117234848Smav 2118234848Smav G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name); 2119234940Smav mdi = (struct g_raid_md_ddf_object *)md; 2120234848Smav pp = cp->provider; 2121234848Smav 2122234848Smav /* Read metadata from device. */ 2123234848Smav g_topology_unlock(); 2124234848Smav bzero(&meta, sizeof(meta)); 2125234848Smav error = ddf_meta_read(cp, &meta); 2126234848Smav g_topology_lock(); 2127234848Smav if (error != 0) 2128234848Smav return (G_RAID_MD_TASTE_FAIL); 2129234940Smav be = meta.bigendian; 2130234848Smav 2131234848Smav /* Metadata valid. Print it. */ 2132234848Smav g_raid_md_ddf_print(&meta); 2133234848Smav 2134234848Smav /* Search for matching node. */ 2135234848Smav sc = NULL; 2136234848Smav LIST_FOREACH(geom, &mp->geom, geom) { 2137234848Smav sc = geom->softc; 2138234848Smav if (sc == NULL) 2139234848Smav continue; 2140234848Smav if (sc->sc_stopping != 0) 2141234848Smav continue; 2142234848Smav if (sc->sc_md->mdo_class != md->mdo_class) 2143234848Smav continue; 2144234940Smav mdi = (struct g_raid_md_ddf_object *)sc->sc_md; 2145234940Smav if (mdi->mdio_bigendian != be) 2146234940Smav continue; 2147234848Smav break; 2148234848Smav } 2149234848Smav 2150234848Smav /* Found matching node. */ 2151234848Smav if (geom != NULL) { 2152234848Smav G_RAID_DEBUG(1, "Found matching array %s", sc->sc_name); 2153234848Smav result = G_RAID_MD_TASTE_EXISTING; 2154234848Smav 2155234848Smav } else { /* Not found matching node -- create one. */ 2156234848Smav result = G_RAID_MD_TASTE_NEW; 2157234940Smav mdi->mdio_bigendian = be; 2158234940Smav snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE"); 2159234848Smav sc = g_raid_create_node(mp, name, md); 2160234848Smav md->mdo_softc = sc; 2161234848Smav geom = sc->sc_geom; 2162234848Smav } 2163234848Smav 2164265054Smav /* There is no return after this point, so we close passed consumer. */ 2165265054Smav g_access(cp, -1, 0, 0); 2166265054Smav 2167234848Smav rcp = g_new_consumer(geom); 2168256880Smav rcp->flags |= G_CF_DIRECT_RECEIVE; 2169234848Smav g_attach(rcp, pp); 2170234848Smav if (g_access(rcp, 1, 1, 1) != 0) 2171234848Smav ; //goto fail1; 2172234848Smav 2173234848Smav g_topology_unlock(); 2174234848Smav sx_xlock(&sc->sc_lock); 2175234848Smav 2176234848Smav pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO); 2177234848Smav pd->pd_meta = meta; 2178234848Smav disk = g_raid_create_disk(sc); 2179234848Smav disk->d_md_data = (void *)pd; 2180234848Smav disk->d_consumer = rcp; 2181234848Smav rcp->private = disk; 2182234848Smav 2183242323Smav g_raid_get_disk_info(disk); 2184234848Smav 2185234848Smav g_raid_md_ddf_new_disk(disk); 2186234848Smav 2187234848Smav sx_xunlock(&sc->sc_lock); 2188234848Smav g_topology_lock(); 2189234848Smav *gp = geom; 2190234848Smav return (result); 2191234848Smav} 2192234848Smav 2193234848Smavstatic int 2194234848Smavg_raid_md_event_ddf(struct g_raid_md_object *md, 2195234848Smav struct g_raid_disk *disk, u_int event) 2196234848Smav{ 2197234848Smav struct g_raid_softc *sc; 2198234848Smav 2199234848Smav sc = md->mdo_softc; 2200234848Smav if (disk == NULL) 2201234848Smav return (-1); 2202234848Smav switch (event) { 2203234848Smav case G_RAID_DISK_E_DISCONNECTED: 2204234848Smav /* Delete disk. */ 2205234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE); 2206234848Smav g_raid_destroy_disk(disk); 2207234848Smav g_raid_md_ddf_purge_volumes(sc); 2208234848Smav 2209234848Smav /* Write updated metadata to all disks. */ 2210234848Smav g_raid_md_write_ddf(md, NULL, NULL, NULL); 2211234848Smav 2212234848Smav /* Check if anything left. */ 2213234848Smav if (g_raid_ndisks(sc, -1) == 0) 2214234848Smav g_raid_destroy_node(sc, 0); 2215234848Smav else 2216234848Smav g_raid_md_ddf_refill(sc); 2217234848Smav return (0); 2218234848Smav } 2219234848Smav return (-2); 2220234848Smav} 2221234848Smav 2222234848Smavstatic int 2223234848Smavg_raid_md_volume_event_ddf(struct g_raid_md_object *md, 2224234848Smav struct g_raid_volume *vol, u_int event) 2225234848Smav{ 2226234848Smav struct g_raid_md_ddf_pervolume *pv; 2227234848Smav 2228234848Smav pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data; 2229234848Smav switch (event) { 2230234848Smav case G_RAID_VOLUME_E_STARTMD: 2231234848Smav if (!pv->pv_started) 2232234848Smav g_raid_md_ddf_start(vol); 2233234848Smav return (0); 2234234848Smav } 2235234848Smav return (-2); 2236234848Smav} 2237234848Smav 2238234848Smavstatic int 2239234848Smavg_raid_md_ctl_ddf(struct g_raid_md_object *md, 2240234848Smav struct gctl_req *req) 2241234848Smav{ 2242234848Smav struct g_raid_softc *sc; 2243234848Smav struct g_raid_volume *vol, *vol1; 2244234848Smav struct g_raid_subdisk *sd; 2245234848Smav struct g_raid_disk *disk, *disks[DDF_MAX_DISKS_HARD]; 2246234848Smav struct g_raid_md_ddf_perdisk *pd; 2247234848Smav struct g_raid_md_ddf_pervolume *pv; 2248234848Smav struct g_raid_md_ddf_object *mdi; 2249234899Smav struct ddf_sa_record *sa; 2250234848Smav struct g_consumer *cp; 2251234848Smav struct g_provider *pp; 2252234848Smav char arg[16]; 2253241329Smav const char *nodename, *verb, *volname, *levelname, *diskname; 2254234848Smav char *tmp; 2255234848Smav int *nargs, *force; 2256234848Smav off_t size, sectorsize, strip, offs[DDF_MAX_DISKS_HARD], esize; 2257234848Smav intmax_t *sizearg, *striparg; 2258234848Smav int i, numdisks, len, level, qual; 2259234848Smav int error; 2260234848Smav 2261234848Smav sc = md->mdo_softc; 2262234848Smav mdi = (struct g_raid_md_ddf_object *)md; 2263234848Smav verb = gctl_get_param(req, "verb", NULL); 2264234848Smav nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 2265234848Smav error = 0; 2266234848Smav 2267234848Smav if (strcmp(verb, "label") == 0) { 2268234848Smav 2269234848Smav if (*nargs < 4) { 2270234848Smav gctl_error(req, "Invalid number of arguments."); 2271234848Smav return (-1); 2272234848Smav } 2273234848Smav volname = gctl_get_asciiparam(req, "arg1"); 2274234848Smav if (volname == NULL) { 2275234848Smav gctl_error(req, "No volume name."); 2276234848Smav return (-2); 2277234848Smav } 2278234848Smav levelname = gctl_get_asciiparam(req, "arg2"); 2279234848Smav if (levelname == NULL) { 2280234848Smav gctl_error(req, "No RAID level."); 2281234848Smav return (-3); 2282234848Smav } 2283234848Smav if (g_raid_volume_str2level(levelname, &level, &qual)) { 2284234848Smav gctl_error(req, "Unknown RAID level '%s'.", levelname); 2285234848Smav return (-4); 2286234848Smav } 2287234848Smav numdisks = *nargs - 3; 2288234848Smav force = gctl_get_paraml(req, "force", sizeof(*force)); 2289234848Smav if (!g_raid_md_ddf_supported(level, qual, numdisks, 2290234848Smav force ? *force : 0)) { 2291234848Smav gctl_error(req, "Unsupported RAID level " 2292234848Smav "(0x%02x/0x%02x), or number of disks (%d).", 2293234848Smav level, qual, numdisks); 2294234848Smav return (-5); 2295234848Smav } 2296234848Smav 2297234848Smav /* Search for disks, connect them and probe. */ 2298234848Smav size = INT64_MAX; 2299234848Smav sectorsize = 0; 2300234848Smav bzero(disks, sizeof(disks)); 2301234848Smav bzero(offs, sizeof(offs)); 2302234848Smav for (i = 0; i < numdisks; i++) { 2303234848Smav snprintf(arg, sizeof(arg), "arg%d", i + 3); 2304234848Smav diskname = gctl_get_asciiparam(req, arg); 2305234848Smav if (diskname == NULL) { 2306234848Smav gctl_error(req, "No disk name (%s).", arg); 2307234848Smav error = -6; 2308234848Smav break; 2309234848Smav } 2310234848Smav if (strcmp(diskname, "NONE") == 0) 2311234848Smav continue; 2312234848Smav 2313234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2314234848Smav if (disk->d_consumer != NULL && 2315234848Smav disk->d_consumer->provider != NULL && 2316234848Smav strcmp(disk->d_consumer->provider->name, 2317234848Smav diskname) == 0) 2318234848Smav break; 2319234848Smav } 2320234848Smav if (disk != NULL) { 2321234848Smav if (disk->d_state != G_RAID_DISK_S_ACTIVE) { 2322234848Smav gctl_error(req, "Disk '%s' is in a " 2323234848Smav "wrong state (%s).", diskname, 2324234848Smav g_raid_disk_state2str(disk->d_state)); 2325234848Smav error = -7; 2326234848Smav break; 2327234848Smav } 2328234848Smav pd = disk->d_md_data; 2329234848Smav if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >= 2330234848Smav GET16(&pd->pd_meta, hdr->Max_Partitions)) { 2331234848Smav gctl_error(req, "No free partitions " 2332234848Smav "on disk '%s'.", 2333234848Smav diskname); 2334234848Smav error = -7; 2335234848Smav break; 2336234848Smav } 2337234848Smav pp = disk->d_consumer->provider; 2338234848Smav disks[i] = disk; 2339234848Smav ddf_meta_unused_range(&pd->pd_meta, 2340234848Smav &offs[i], &esize); 2341235096Smav offs[i] *= pp->sectorsize; 2342234848Smav size = MIN(size, (off_t)esize * pp->sectorsize); 2343234848Smav sectorsize = MAX(sectorsize, pp->sectorsize); 2344234848Smav continue; 2345234848Smav } 2346234848Smav 2347234848Smav g_topology_lock(); 2348234848Smav cp = g_raid_open_consumer(sc, diskname); 2349234848Smav if (cp == NULL) { 2350234848Smav gctl_error(req, "Can't open disk '%s'.", 2351234848Smav diskname); 2352234848Smav g_topology_unlock(); 2353234848Smav error = -8; 2354234848Smav break; 2355234848Smav } 2356234848Smav pp = cp->provider; 2357234848Smav pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO); 2358234848Smav disk = g_raid_create_disk(sc); 2359234848Smav disk->d_md_data = (void *)pd; 2360234848Smav disk->d_consumer = cp; 2361234848Smav disks[i] = disk; 2362234848Smav cp->private = disk; 2363234848Smav ddf_meta_create(disk, &mdi->mdio_meta); 2364234848Smav if (mdi->mdio_meta.hdr == NULL) 2365234848Smav ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta); 2366234848Smav else 2367234848Smav ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta); 2368234848Smav g_topology_unlock(); 2369234848Smav 2370242323Smav g_raid_get_disk_info(disk); 2371234848Smav 2372234848Smav /* Reserve some space for metadata. */ 2373235096Smav size = MIN(size, GET64(&pd->pd_meta, 2374235096Smav pdr->entry[0].Configured_Size) * pp->sectorsize); 2375234848Smav sectorsize = MAX(sectorsize, pp->sectorsize); 2376234848Smav } 2377234848Smav if (error != 0) { 2378234848Smav for (i = 0; i < numdisks; i++) { 2379234848Smav if (disks[i] != NULL && 2380234848Smav disks[i]->d_state == G_RAID_DISK_S_NONE) 2381234848Smav g_raid_destroy_disk(disks[i]); 2382234848Smav } 2383234848Smav return (error); 2384234848Smav } 2385234848Smav 2386234848Smav if (sectorsize <= 0) { 2387234848Smav gctl_error(req, "Can't get sector size."); 2388234848Smav return (-8); 2389234848Smav } 2390234848Smav 2391234848Smav /* Handle size argument. */ 2392234848Smav len = sizeof(*sizearg); 2393234848Smav sizearg = gctl_get_param(req, "size", &len); 2394234848Smav if (sizearg != NULL && len == sizeof(*sizearg) && 2395234848Smav *sizearg > 0) { 2396234848Smav if (*sizearg > size) { 2397234848Smav gctl_error(req, "Size too big %lld > %lld.", 2398234848Smav (long long)*sizearg, (long long)size); 2399234848Smav return (-9); 2400234848Smav } 2401234848Smav size = *sizearg; 2402234848Smav } 2403234848Smav 2404234848Smav /* Handle strip argument. */ 2405234848Smav strip = 131072; 2406234848Smav len = sizeof(*striparg); 2407234848Smav striparg = gctl_get_param(req, "strip", &len); 2408234848Smav if (striparg != NULL && len == sizeof(*striparg) && 2409234848Smav *striparg > 0) { 2410234848Smav if (*striparg < sectorsize) { 2411234848Smav gctl_error(req, "Strip size too small."); 2412234848Smav return (-10); 2413234848Smav } 2414234848Smav if (*striparg % sectorsize != 0) { 2415234848Smav gctl_error(req, "Incorrect strip size."); 2416234848Smav return (-11); 2417234848Smav } 2418234848Smav strip = *striparg; 2419234848Smav } 2420234848Smav 2421234848Smav /* Round size down to strip or sector. */ 2422234848Smav if (level == G_RAID_VOLUME_RL_RAID1 || 2423234848Smav level == G_RAID_VOLUME_RL_RAID3 || 2424234848Smav level == G_RAID_VOLUME_RL_SINGLE || 2425234848Smav level == G_RAID_VOLUME_RL_CONCAT) 2426234848Smav size -= (size % sectorsize); 2427234848Smav else if (level == G_RAID_VOLUME_RL_RAID1E && 2428234848Smav (numdisks & 1) != 0) 2429234848Smav size -= (size % (2 * strip)); 2430234848Smav else 2431234848Smav size -= (size % strip); 2432234848Smav if (size <= 0) { 2433234848Smav gctl_error(req, "Size too small."); 2434234848Smav return (-13); 2435234848Smav } 2436234848Smav 2437234848Smav /* We have all we need, create things: volume, ... */ 2438234848Smav pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO); 2439234848Smav ddf_vol_meta_create(&pv->pv_meta, &mdi->mdio_meta); 2440234848Smav pv->pv_started = 1; 2441234848Smav vol = g_raid_create_volume(sc, volname, -1); 2442234848Smav vol->v_md_data = pv; 2443234848Smav vol->v_raid_level = level; 2444234848Smav vol->v_raid_level_qualifier = qual; 2445234848Smav vol->v_strip_size = strip; 2446234848Smav vol->v_disks_count = numdisks; 2447234848Smav if (level == G_RAID_VOLUME_RL_RAID0 || 2448234848Smav level == G_RAID_VOLUME_RL_CONCAT || 2449234848Smav level == G_RAID_VOLUME_RL_SINGLE) 2450234848Smav vol->v_mediasize = size * numdisks; 2451234848Smav else if (level == G_RAID_VOLUME_RL_RAID1) 2452234848Smav vol->v_mediasize = size; 2453234848Smav else if (level == G_RAID_VOLUME_RL_RAID3 || 2454234848Smav level == G_RAID_VOLUME_RL_RAID4 || 2455235076Smav level == G_RAID_VOLUME_RL_RAID5) 2456234848Smav vol->v_mediasize = size * (numdisks - 1); 2457235076Smav else if (level == G_RAID_VOLUME_RL_RAID5R) { 2458235076Smav vol->v_mediasize = size * (numdisks - 1); 2459235076Smav vol->v_rotate_parity = 1024; 2460235076Smav } else if (level == G_RAID_VOLUME_RL_RAID6 || 2461234848Smav level == G_RAID_VOLUME_RL_RAID5E || 2462234848Smav level == G_RAID_VOLUME_RL_RAID5EE) 2463234848Smav vol->v_mediasize = size * (numdisks - 2); 2464235076Smav else if (level == G_RAID_VOLUME_RL_RAIDMDF) { 2465235076Smav if (numdisks < 5) 2466235076Smav vol->v_mdf_pdisks = 2; 2467235076Smav else 2468235076Smav vol->v_mdf_pdisks = 3; 2469235076Smav vol->v_mdf_polynomial = 0x11d; 2470235076Smav vol->v_mdf_method = 0x00; 2471235076Smav vol->v_mediasize = size * (numdisks - vol->v_mdf_pdisks); 2472235076Smav } else { /* RAID1E */ 2473234848Smav vol->v_mediasize = ((size * numdisks) / strip / 2) * 2474234848Smav strip; 2475234848Smav } 2476234848Smav vol->v_sectorsize = sectorsize; 2477234848Smav g_raid_start_volume(vol); 2478234848Smav 2479234848Smav /* , and subdisks. */ 2480234848Smav for (i = 0; i < numdisks; i++) { 2481234848Smav disk = disks[i]; 2482234848Smav sd = &vol->v_subdisks[i]; 2483234848Smav sd->sd_disk = disk; 2484235096Smav sd->sd_offset = offs[i]; 2485234848Smav sd->sd_size = size; 2486234848Smav if (disk == NULL) 2487234848Smav continue; 2488234848Smav TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next); 2489234848Smav g_raid_change_disk_state(disk, 2490234848Smav G_RAID_DISK_S_ACTIVE); 2491234848Smav g_raid_change_subdisk_state(sd, 2492234848Smav G_RAID_SUBDISK_S_ACTIVE); 2493234848Smav g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW, 2494234848Smav G_RAID_EVENT_SUBDISK); 2495234848Smav } 2496234848Smav 2497234848Smav /* Write metadata based on created entities. */ 2498234848Smav G_RAID_DEBUG1(0, sc, "Array started."); 2499234848Smav g_raid_md_write_ddf(md, vol, NULL, NULL); 2500234848Smav 2501234848Smav /* Pickup any STALE/SPARE disks to refill array if needed. */ 2502234848Smav g_raid_md_ddf_refill(sc); 2503234848Smav 2504234848Smav g_raid_event_send(vol, G_RAID_VOLUME_E_START, 2505234848Smav G_RAID_EVENT_VOLUME); 2506234848Smav return (0); 2507234848Smav } 2508234848Smav if (strcmp(verb, "add") == 0) { 2509234848Smav 2510234848Smav gctl_error(req, "`add` command is not applicable, " 2511234848Smav "use `label` instead."); 2512234848Smav return (-99); 2513234848Smav } 2514234848Smav if (strcmp(verb, "delete") == 0) { 2515234848Smav 2516241329Smav nodename = gctl_get_asciiparam(req, "arg0"); 2517241329Smav if (nodename != NULL && strcasecmp(sc->sc_name, nodename) != 0) 2518241329Smav nodename = NULL; 2519241329Smav 2520234848Smav /* Full node destruction. */ 2521241329Smav if (*nargs == 1 && nodename != NULL) { 2522234848Smav /* Check if some volume is still open. */ 2523234848Smav force = gctl_get_paraml(req, "force", sizeof(*force)); 2524234848Smav if (force != NULL && *force == 0 && 2525234848Smav g_raid_nopens(sc) != 0) { 2526234848Smav gctl_error(req, "Some volume is still open."); 2527234848Smav return (-4); 2528234848Smav } 2529234848Smav 2530234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2531234848Smav if (disk->d_consumer) 2532234848Smav ddf_meta_erase(disk->d_consumer); 2533234848Smav } 2534234848Smav g_raid_destroy_node(sc, 0); 2535234848Smav return (0); 2536234848Smav } 2537234848Smav 2538234848Smav /* Destroy specified volume. If it was last - all node. */ 2539241329Smav if (*nargs > 2) { 2540234848Smav gctl_error(req, "Invalid number of arguments."); 2541234848Smav return (-1); 2542234848Smav } 2543241329Smav volname = gctl_get_asciiparam(req, 2544241329Smav nodename != NULL ? "arg1" : "arg0"); 2545234848Smav if (volname == NULL) { 2546234848Smav gctl_error(req, "No volume name."); 2547234848Smav return (-2); 2548234848Smav } 2549234848Smav 2550234848Smav /* Search for volume. */ 2551234848Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 2552234848Smav if (strcmp(vol->v_name, volname) == 0) 2553234848Smav break; 2554241329Smav pp = vol->v_provider; 2555241329Smav if (pp == NULL) 2556241329Smav continue; 2557241329Smav if (strcmp(pp->name, volname) == 0) 2558241329Smav break; 2559241329Smav if (strncmp(pp->name, "raid/", 5) == 0 && 2560241329Smav strcmp(pp->name + 5, volname) == 0) 2561241329Smav break; 2562234848Smav } 2563234848Smav if (vol == NULL) { 2564234848Smav i = strtol(volname, &tmp, 10); 2565234848Smav if (verb != volname && tmp[0] == 0) { 2566234848Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 2567234848Smav if (vol->v_global_id == i) 2568234848Smav break; 2569234848Smav } 2570234848Smav } 2571234848Smav } 2572234848Smav if (vol == NULL) { 2573234848Smav gctl_error(req, "Volume '%s' not found.", volname); 2574234848Smav return (-3); 2575234848Smav } 2576234848Smav 2577234848Smav /* Check if volume is still open. */ 2578234848Smav force = gctl_get_paraml(req, "force", sizeof(*force)); 2579234848Smav if (force != NULL && *force == 0 && 2580234848Smav vol->v_provider_open != 0) { 2581234848Smav gctl_error(req, "Volume is still open."); 2582234848Smav return (-4); 2583234848Smav } 2584234848Smav 2585234848Smav /* Destroy volume and potentially node. */ 2586234848Smav i = 0; 2587234848Smav TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next) 2588234848Smav i++; 2589234848Smav if (i >= 2) { 2590234848Smav g_raid_destroy_volume(vol); 2591234848Smav g_raid_md_ddf_purge_disks(sc); 2592234848Smav g_raid_md_write_ddf(md, NULL, NULL, NULL); 2593234848Smav } else { 2594234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2595234848Smav if (disk->d_consumer) 2596234848Smav ddf_meta_erase(disk->d_consumer); 2597234848Smav } 2598234848Smav g_raid_destroy_node(sc, 0); 2599234848Smav } 2600234848Smav return (0); 2601234848Smav } 2602234848Smav if (strcmp(verb, "remove") == 0 || 2603234848Smav strcmp(verb, "fail") == 0) { 2604234848Smav if (*nargs < 2) { 2605234848Smav gctl_error(req, "Invalid number of arguments."); 2606234848Smav return (-1); 2607234848Smav } 2608234848Smav for (i = 1; i < *nargs; i++) { 2609234848Smav snprintf(arg, sizeof(arg), "arg%d", i); 2610234848Smav diskname = gctl_get_asciiparam(req, arg); 2611234848Smav if (diskname == NULL) { 2612234848Smav gctl_error(req, "No disk name (%s).", arg); 2613234848Smav error = -2; 2614234848Smav break; 2615234848Smav } 2616234848Smav if (strncmp(diskname, "/dev/", 5) == 0) 2617234848Smav diskname += 5; 2618234848Smav 2619234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2620234848Smav if (disk->d_consumer != NULL && 2621234848Smav disk->d_consumer->provider != NULL && 2622234848Smav strcmp(disk->d_consumer->provider->name, 2623234848Smav diskname) == 0) 2624234848Smav break; 2625234848Smav } 2626234848Smav if (disk == NULL) { 2627234848Smav gctl_error(req, "Disk '%s' not found.", 2628234848Smav diskname); 2629234848Smav error = -3; 2630234848Smav break; 2631234848Smav } 2632234848Smav 2633234848Smav if (strcmp(verb, "fail") == 0) { 2634234848Smav g_raid_md_fail_disk_ddf(md, NULL, disk); 2635234848Smav continue; 2636234848Smav } 2637234848Smav 2638234848Smav /* Erase metadata on deleting disk and destroy it. */ 2639234848Smav ddf_meta_erase(disk->d_consumer); 2640234848Smav g_raid_destroy_disk(disk); 2641234848Smav } 2642234848Smav g_raid_md_ddf_purge_volumes(sc); 2643234848Smav 2644234848Smav /* Write updated metadata to remaining disks. */ 2645234848Smav g_raid_md_write_ddf(md, NULL, NULL, NULL); 2646234848Smav 2647234848Smav /* Check if anything left. */ 2648234848Smav if (g_raid_ndisks(sc, -1) == 0) 2649234848Smav g_raid_destroy_node(sc, 0); 2650234848Smav else 2651234848Smav g_raid_md_ddf_refill(sc); 2652234848Smav return (error); 2653234848Smav } 2654234848Smav if (strcmp(verb, "insert") == 0) { 2655234848Smav if (*nargs < 2) { 2656234848Smav gctl_error(req, "Invalid number of arguments."); 2657234848Smav return (-1); 2658234848Smav } 2659234848Smav for (i = 1; i < *nargs; i++) { 2660234848Smav /* Get disk name. */ 2661234848Smav snprintf(arg, sizeof(arg), "arg%d", i); 2662234848Smav diskname = gctl_get_asciiparam(req, arg); 2663234848Smav if (diskname == NULL) { 2664234848Smav gctl_error(req, "No disk name (%s).", arg); 2665234848Smav error = -3; 2666234848Smav break; 2667234848Smav } 2668234848Smav 2669234848Smav /* Try to find provider with specified name. */ 2670234848Smav g_topology_lock(); 2671234848Smav cp = g_raid_open_consumer(sc, diskname); 2672234848Smav if (cp == NULL) { 2673234848Smav gctl_error(req, "Can't open disk '%s'.", 2674234848Smav diskname); 2675234848Smav g_topology_unlock(); 2676234848Smav error = -4; 2677234848Smav break; 2678234848Smav } 2679234848Smav pp = cp->provider; 2680234848Smav g_topology_unlock(); 2681234848Smav 2682234848Smav pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO); 2683234848Smav 2684234848Smav disk = g_raid_create_disk(sc); 2685234848Smav disk->d_consumer = cp; 2686234848Smav disk->d_md_data = (void *)pd; 2687234848Smav cp->private = disk; 2688234848Smav 2689242323Smav g_raid_get_disk_info(disk); 2690234848Smav 2691234848Smav /* Welcome the "new" disk. */ 2692234848Smav g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE); 2693234848Smav ddf_meta_create(disk, &mdi->mdio_meta); 2694234899Smav sa = ddf_meta_find_sa(&pd->pd_meta, 1); 2695234899Smav if (sa != NULL) { 2696234899Smav SET32D(&pd->pd_meta, sa->Signature, 2697234899Smav DDF_SA_SIGNATURE); 2698234899Smav SET8D(&pd->pd_meta, sa->Spare_Type, 0); 2699234899Smav SET16D(&pd->pd_meta, sa->Populated_SAEs, 0); 2700234899Smav SET16D(&pd->pd_meta, sa->MAX_SAE_Supported, 2701234899Smav (GET16(&pd->pd_meta, hdr->Configuration_Record_Length) * 2702234899Smav pd->pd_meta.sectorsize - 2703234899Smav sizeof(struct ddf_sa_record)) / 2704234899Smav sizeof(struct ddf_sa_entry)); 2705234899Smav } 2706234848Smav if (mdi->mdio_meta.hdr == NULL) 2707234848Smav ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta); 2708234848Smav else 2709234848Smav ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta); 2710234899Smav g_raid_md_write_ddf(md, NULL, NULL, NULL); 2711234848Smav g_raid_md_ddf_refill(sc); 2712234848Smav } 2713234848Smav return (error); 2714234848Smav } 2715234848Smav return (-100); 2716234848Smav} 2717234848Smav 2718234848Smavstatic int 2719234848Smavg_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol, 2720234848Smav struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk) 2721234848Smav{ 2722234848Smav struct g_raid_softc *sc; 2723234848Smav struct g_raid_volume *vol; 2724234848Smav struct g_raid_subdisk *sd; 2725234848Smav struct g_raid_disk *disk; 2726234848Smav struct g_raid_md_ddf_perdisk *pd; 2727234848Smav struct g_raid_md_ddf_pervolume *pv; 2728234848Smav struct g_raid_md_ddf_object *mdi; 2729234848Smav struct ddf_meta *gmeta; 2730234848Smav struct ddf_vol_meta *vmeta; 2731234848Smav struct ddf_vdc_record *vdc; 2732234899Smav struct ddf_sa_record *sa; 2733234848Smav uint64_t *val2; 2734234848Smav int i, j, pos, bvd, size; 2735234848Smav 2736234848Smav sc = md->mdo_softc; 2737234848Smav mdi = (struct g_raid_md_ddf_object *)md; 2738234848Smav gmeta = &mdi->mdio_meta; 2739234848Smav 2740234848Smav if (sc->sc_stopping == G_RAID_DESTROY_HARD) 2741234848Smav return (0); 2742234848Smav 2743234868Smav /* 2744234868Smav * Clear disk flags to let only really needed ones to be reset. 2745234868Smav * Do it only if there are no volumes in starting state now, 2746234868Smav * as they can update disk statuses yet and we may kill innocent. 2747234868Smav */ 2748234868Smav if (mdi->mdio_starting == 0) { 2749234868Smav for (i = 0; i < GET16(gmeta, pdr->Populated_PDEs); i++) { 2750234868Smav if (isff(gmeta->pdr->entry[i].PD_GUID, 24)) 2751234848Smav continue; 2752234868Smav SET16(gmeta, pdr->entry[i].PD_Type, 2753234868Smav GET16(gmeta, pdr->entry[i].PD_Type) & 2754234899Smav ~(DDF_PDE_PARTICIPATING | 2755234899Smav DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)); 2756234868Smav if ((GET16(gmeta, pdr->entry[i].PD_State) & 2757234868Smav DDF_PDE_PFA) == 0) 2758234868Smav SET16(gmeta, pdr->entry[i].PD_State, 0); 2759234848Smav } 2760234868Smav } 2761234848Smav 2762234868Smav /* Generate/update new per-volume metadata. */ 2763234868Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 2764234848Smav pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data; 2765234868Smav if (vol->v_stopping || !pv->pv_started) 2766234868Smav continue; 2767234848Smav vmeta = &pv->pv_meta; 2768234848Smav 2769234848Smav SET32(vmeta, vdc->Sequence_Number, 2770234848Smav GET32(vmeta, vdc->Sequence_Number) + 1); 2771234848Smav if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E && 2772234848Smav vol->v_disks_count % 2 == 0) 2773234848Smav SET16(vmeta, vdc->Primary_Element_Count, 2); 2774234848Smav else 2775234848Smav SET16(vmeta, vdc->Primary_Element_Count, 2776234848Smav vol->v_disks_count); 2777234848Smav SET8(vmeta, vdc->Stripe_Size, 2778234848Smav ffs(vol->v_strip_size / vol->v_sectorsize) - 1); 2779234848Smav if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E && 2780234848Smav vol->v_disks_count % 2 == 0) { 2781234848Smav SET8(vmeta, vdc->Primary_RAID_Level, 2782234848Smav DDF_VDCR_RAID1); 2783234848Smav SET8(vmeta, vdc->RLQ, 0); 2784234848Smav SET8(vmeta, vdc->Secondary_Element_Count, 2785234848Smav vol->v_disks_count / 2); 2786234848Smav SET8(vmeta, vdc->Secondary_RAID_Level, 0); 2787234848Smav } else { 2788234848Smav SET8(vmeta, vdc->Primary_RAID_Level, 2789234848Smav vol->v_raid_level); 2790234848Smav SET8(vmeta, vdc->RLQ, 2791234848Smav vol->v_raid_level_qualifier); 2792234848Smav SET8(vmeta, vdc->Secondary_Element_Count, 1); 2793234848Smav SET8(vmeta, vdc->Secondary_RAID_Level, 0); 2794234848Smav } 2795234848Smav SET8(vmeta, vdc->Secondary_Element_Seq, 0); 2796234848Smav SET64(vmeta, vdc->Block_Count, 0); 2797234848Smav SET64(vmeta, vdc->VD_Size, vol->v_mediasize / vol->v_sectorsize); 2798234848Smav SET16(vmeta, vdc->Block_Size, vol->v_sectorsize); 2799235076Smav SET8(vmeta, vdc->Rotate_Parity_count, 2800235076Smav fls(vol->v_rotate_parity) - 1); 2801235076Smav SET8(vmeta, vdc->MDF_Parity_Disks, vol->v_mdf_pdisks); 2802235076Smav SET16(vmeta, vdc->MDF_Parity_Generator_Polynomial, 2803235076Smav vol->v_mdf_polynomial); 2804235076Smav SET8(vmeta, vdc->MDF_Constant_Generation_Method, 2805235076Smav vol->v_mdf_method); 2806234848Smav 2807234848Smav SET16(vmeta, vde->VD_Number, vol->v_global_id); 2808234848Smav if (vol->v_state <= G_RAID_VOLUME_S_BROKEN) 2809234848Smav SET8(vmeta, vde->VD_State, DDF_VDE_FAILED); 2810234848Smav else if (vol->v_state <= G_RAID_VOLUME_S_DEGRADED) 2811234848Smav SET8(vmeta, vde->VD_State, DDF_VDE_DEGRADED); 2812234848Smav else if (vol->v_state <= G_RAID_VOLUME_S_SUBOPTIMAL) 2813234848Smav SET8(vmeta, vde->VD_State, DDF_VDE_PARTIAL); 2814234848Smav else 2815234848Smav SET8(vmeta, vde->VD_State, DDF_VDE_OPTIMAL); 2816234868Smav if (vol->v_dirty || 2817234868Smav g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_STALE) > 0 || 2818234868Smav g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_RESYNC) > 0) 2819234848Smav SET8(vmeta, vde->VD_State, 2820234848Smav GET8(vmeta, vde->VD_State) | DDF_VDE_DIRTY); 2821234848Smav SET8(vmeta, vde->Init_State, DDF_VDE_INIT_FULL); // XXX 2822234848Smav ddf_meta_put_name(vmeta, vol->v_name); 2823234848Smav 2824234848Smav for (i = 0; i < vol->v_disks_count; i++) { 2825234848Smav sd = &vol->v_subdisks[i]; 2826234848Smav bvd = i / GET16(vmeta, vdc->Primary_Element_Count); 2827234848Smav pos = i % GET16(vmeta, vdc->Primary_Element_Count); 2828234868Smav disk = sd->sd_disk; 2829234868Smav if (disk != NULL) { 2830234868Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 2831234868Smav if (vmeta->bvdc[bvd] == NULL) { 2832234868Smav size = GET16(vmeta, 2833234868Smav hdr->Configuration_Record_Length) * 2834234868Smav vmeta->sectorsize; 2835234868Smav vmeta->bvdc[bvd] = malloc(size, 2836234868Smav M_MD_DDF, M_WAITOK); 2837234868Smav memset(vmeta->bvdc[bvd], 0xff, size); 2838234868Smav } 2839234868Smav memcpy(vmeta->bvdc[bvd], vmeta->vdc, 2840234868Smav sizeof(struct ddf_vdc_record)); 2841234848Smav SET8(vmeta, bvdc[bvd]->Secondary_Element_Seq, bvd); 2842234868Smav SET64(vmeta, bvdc[bvd]->Block_Count, 2843234868Smav sd->sd_size / vol->v_sectorsize); 2844234868Smav SET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos], 2845234868Smav GET32(&pd->pd_meta, pdd->PD_Reference)); 2846234868Smav val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[ 2847234868Smav GET16(vmeta, hdr->Max_Primary_Element_Entries)]); 2848234868Smav SET64P(vmeta, val2 + pos, 2849234868Smav sd->sd_offset / vol->v_sectorsize); 2850234848Smav } 2851234868Smav if (vmeta->bvdc[bvd] == NULL) 2852234868Smav continue; 2853234848Smav 2854234848Smav j = ddf_meta_find_pd(gmeta, NULL, 2855234868Smav GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos])); 2856234848Smav if (j < 0) 2857234848Smav continue; 2858264318Smav SET16(gmeta, pdr->entry[j].PD_Type, 2859264318Smav GET16(gmeta, pdr->entry[j].PD_Type) | 2860234848Smav DDF_PDE_PARTICIPATING); 2861234868Smav if (sd->sd_state == G_RAID_SUBDISK_S_NONE) 2862264318Smav SET16(gmeta, pdr->entry[j].PD_State, 2863264318Smav GET16(gmeta, pdr->entry[j].PD_State) | 2864234899Smav (DDF_PDE_FAILED | DDF_PDE_MISSING)); 2865234868Smav else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED) 2866264318Smav SET16(gmeta, pdr->entry[j].PD_State, 2867264318Smav GET16(gmeta, pdr->entry[j].PD_State) | 2868234899Smav (DDF_PDE_FAILED | DDF_PDE_PFA)); 2869234868Smav else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD) 2870264318Smav SET16(gmeta, pdr->entry[j].PD_State, 2871264318Smav GET16(gmeta, pdr->entry[j].PD_State) | 2872234899Smav DDF_PDE_REBUILD); 2873234848Smav else 2874264318Smav SET16(gmeta, pdr->entry[j].PD_State, 2875264318Smav GET16(gmeta, pdr->entry[j].PD_State) | 2876234848Smav DDF_PDE_ONLINE); 2877234848Smav } 2878234848Smav } 2879234848Smav 2880234899Smav /* Mark spare and failed disks as such. */ 2881234899Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2882234899Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 2883234899Smav i = ddf_meta_find_pd(gmeta, NULL, 2884234899Smav GET32(&pd->pd_meta, pdd->PD_Reference)); 2885234899Smav if (i < 0) 2886234899Smav continue; 2887234899Smav if (disk->d_state == G_RAID_DISK_S_FAILED) { 2888264318Smav SET16(gmeta, pdr->entry[i].PD_State, 2889264318Smav GET16(gmeta, pdr->entry[i].PD_State) | 2890234899Smav (DDF_PDE_FAILED | DDF_PDE_PFA)); 2891234899Smav } 2892234899Smav if (disk->d_state != G_RAID_DISK_S_SPARE) 2893234899Smav continue; 2894234899Smav sa = ddf_meta_find_sa(&pd->pd_meta, 0); 2895234899Smav if (sa == NULL || 2896234899Smav (GET8D(&pd->pd_meta, sa->Spare_Type) & 2897234899Smav DDF_SAR_TYPE_DEDICATED) == 0) { 2898234899Smav SET16(gmeta, pdr->entry[i].PD_Type, 2899234899Smav GET16(gmeta, pdr->entry[i].PD_Type) | 2900234899Smav DDF_PDE_GLOBAL_SPARE); 2901234899Smav } else { 2902234899Smav SET16(gmeta, pdr->entry[i].PD_Type, 2903234899Smav GET16(gmeta, pdr->entry[i].PD_Type) | 2904234899Smav DDF_PDE_CONFIG_SPARE); 2905234899Smav } 2906264318Smav SET16(gmeta, pdr->entry[i].PD_State, 2907264318Smav GET16(gmeta, pdr->entry[i].PD_State) | 2908234899Smav DDF_PDE_ONLINE); 2909234899Smav } 2910234899Smav 2911234868Smav /* Remove disks without "participating" flag (unused). */ 2912234868Smav for (i = 0, j = -1; i < GET16(gmeta, pdr->Populated_PDEs); i++) { 2913234868Smav if (isff(gmeta->pdr->entry[i].PD_GUID, 24)) 2914234868Smav continue; 2915234899Smav if ((GET16(gmeta, pdr->entry[i].PD_Type) & 2916234899Smav (DDF_PDE_PARTICIPATING | 2917234899Smav DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)) != 0 || 2918234899Smav g_raid_md_ddf_get_disk(sc, 2919234899Smav NULL, GET32(gmeta, pdr->entry[i].PD_Reference)) != NULL) 2920234868Smav j = i; 2921234868Smav else 2922234868Smav memset(&gmeta->pdr->entry[i], 0xff, 2923234868Smav sizeof(struct ddf_pd_entry)); 2924234868Smav } 2925234868Smav SET16(gmeta, pdr->Populated_PDEs, j + 1); 2926234868Smav 2927234868Smav /* Update per-disk metadata and write them. */ 2928234848Smav TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { 2929234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 2930234899Smav if (disk->d_state != G_RAID_DISK_S_ACTIVE && 2931234899Smav disk->d_state != G_RAID_DISK_S_SPARE) 2932234848Smav continue; 2933234868Smav /* Update PDR. */ 2934234848Smav memcpy(pd->pd_meta.pdr, gmeta->pdr, 2935234848Smav GET32(&pd->pd_meta, hdr->pdr_length) * 2936234848Smav pd->pd_meta.sectorsize); 2937234868Smav /* Update VDR. */ 2938234868Smav SET16(&pd->pd_meta, vdr->Populated_VDEs, 0); 2939234868Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 2940234868Smav if (vol->v_stopping) 2941234868Smav continue; 2942234848Smav pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data; 2943234848Smav i = ddf_meta_find_vd(&pd->pd_meta, 2944234848Smav pv->pv_meta.vde->VD_GUID); 2945234848Smav if (i < 0) 2946234848Smav i = ddf_meta_find_vd(&pd->pd_meta, NULL); 2947234848Smav if (i >= 0) 2948234848Smav memcpy(&pd->pd_meta.vdr->entry[i], 2949234848Smav pv->pv_meta.vde, 2950234848Smav sizeof(struct ddf_vd_entry)); 2951234868Smav } 2952234868Smav /* Update VDC. */ 2953234869Smav if (mdi->mdio_starting == 0) { 2954234869Smav /* Remove all VDCs to restore needed later. */ 2955234869Smav j = GETCRNUM(&pd->pd_meta); 2956234869Smav for (i = 0; i < j; i++) { 2957234869Smav vdc = GETVDCPTR(&pd->pd_meta, i); 2958234869Smav if (GET32D(&pd->pd_meta, vdc->Signature) != 2959234869Smav DDF_VDCR_SIGNATURE) 2960234869Smav continue; 2961234869Smav SET32D(&pd->pd_meta, vdc->Signature, 0xffffffff); 2962234869Smav } 2963234869Smav } 2964234868Smav TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) { 2965234868Smav vol = sd->sd_volume; 2966234868Smav if (vol->v_stopping) 2967234868Smav continue; 2968234868Smav pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data; 2969234868Smav vmeta = &pv->pv_meta; 2970234848Smav vdc = ddf_meta_find_vdc(&pd->pd_meta, 2971234868Smav vmeta->vde->VD_GUID); 2972234848Smav if (vdc == NULL) 2973234848Smav vdc = ddf_meta_find_vdc(&pd->pd_meta, NULL); 2974234848Smav if (vdc != NULL) { 2975234848Smav bvd = sd->sd_pos / GET16(vmeta, 2976234848Smav vdc->Primary_Element_Count); 2977234868Smav memcpy(vdc, vmeta->bvdc[bvd], 2978234848Smav GET16(&pd->pd_meta, 2979234848Smav hdr->Configuration_Record_Length) * 2980234848Smav pd->pd_meta.sectorsize); 2981234848Smav } 2982234848Smav } 2983234848Smav G_RAID_DEBUG(1, "Writing DDF metadata to %s", 2984234848Smav g_raid_get_diskname(disk)); 2985234848Smav g_raid_md_ddf_print(&pd->pd_meta); 2986234848Smav ddf_meta_write(disk->d_consumer, &pd->pd_meta); 2987234848Smav } 2988234848Smav return (0); 2989234848Smav} 2990234848Smav 2991234848Smavstatic int 2992234848Smavg_raid_md_fail_disk_ddf(struct g_raid_md_object *md, 2993234848Smav struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk) 2994234848Smav{ 2995234848Smav struct g_raid_softc *sc; 2996234848Smav struct g_raid_md_ddf_perdisk *pd; 2997234848Smav struct g_raid_subdisk *sd; 2998234848Smav int i; 2999234848Smav 3000234848Smav sc = md->mdo_softc; 3001234848Smav pd = (struct g_raid_md_ddf_perdisk *)tdisk->d_md_data; 3002234848Smav 3003234848Smav /* We can't fail disk that is not a part of array now. */ 3004234848Smav if (tdisk->d_state != G_RAID_DISK_S_ACTIVE) 3005234848Smav return (-1); 3006234848Smav 3007234848Smav /* 3008234848Smav * Mark disk as failed in metadata and try to write that metadata 3009234848Smav * to the disk itself to prevent it's later resurrection as STALE. 3010234848Smav */ 3011234848Smav G_RAID_DEBUG(1, "Writing DDF metadata to %s", 3012234848Smav g_raid_get_diskname(tdisk)); 3013234848Smav i = ddf_meta_find_pd(&pd->pd_meta, NULL, GET32(&pd->pd_meta, pdd->PD_Reference)); 3014234848Smav SET16(&pd->pd_meta, pdr->entry[i].PD_State, DDF_PDE_FAILED | DDF_PDE_PFA); 3015234848Smav if (tdisk->d_consumer != NULL) 3016234848Smav ddf_meta_write(tdisk->d_consumer, &pd->pd_meta); 3017234848Smav 3018234848Smav /* Change states. */ 3019234848Smav g_raid_change_disk_state(tdisk, G_RAID_DISK_S_FAILED); 3020234848Smav TAILQ_FOREACH(sd, &tdisk->d_subdisks, sd_next) { 3021234848Smav g_raid_change_subdisk_state(sd, 3022234848Smav G_RAID_SUBDISK_S_FAILED); 3023234848Smav g_raid_event_send(sd, G_RAID_SUBDISK_E_FAILED, 3024234848Smav G_RAID_EVENT_SUBDISK); 3025234848Smav } 3026234848Smav 3027234848Smav /* Write updated metadata to remaining disks. */ 3028234848Smav g_raid_md_write_ddf(md, NULL, NULL, tdisk); 3029234848Smav 3030234848Smav g_raid_md_ddf_refill(sc); 3031234848Smav return (0); 3032234848Smav} 3033234848Smav 3034234848Smavstatic int 3035234848Smavg_raid_md_free_disk_ddf(struct g_raid_md_object *md, 3036234848Smav struct g_raid_disk *disk) 3037234848Smav{ 3038234848Smav struct g_raid_md_ddf_perdisk *pd; 3039234848Smav 3040234848Smav pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data; 3041234848Smav ddf_meta_free(&pd->pd_meta); 3042234848Smav free(pd, M_MD_DDF); 3043234848Smav disk->d_md_data = NULL; 3044234848Smav return (0); 3045234848Smav} 3046234848Smav 3047234848Smavstatic int 3048234848Smavg_raid_md_free_volume_ddf(struct g_raid_md_object *md, 3049234848Smav struct g_raid_volume *vol) 3050234848Smav{ 3051234869Smav struct g_raid_md_ddf_object *mdi; 3052234848Smav struct g_raid_md_ddf_pervolume *pv; 3053234848Smav 3054234869Smav mdi = (struct g_raid_md_ddf_object *)md; 3055234848Smav pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data; 3056234848Smav ddf_vol_meta_free(&pv->pv_meta); 3057234848Smav if (!pv->pv_started) { 3058234848Smav pv->pv_started = 1; 3059234869Smav mdi->mdio_starting--; 3060234848Smav callout_stop(&pv->pv_start_co); 3061234848Smav } 3062235080Smav free(pv, M_MD_DDF); 3063235080Smav vol->v_md_data = NULL; 3064234848Smav return (0); 3065234848Smav} 3066234848Smav 3067234848Smavstatic int 3068234848Smavg_raid_md_free_ddf(struct g_raid_md_object *md) 3069234848Smav{ 3070234848Smav struct g_raid_md_ddf_object *mdi; 3071234848Smav 3072234848Smav mdi = (struct g_raid_md_ddf_object *)md; 3073234848Smav if (!mdi->mdio_started) { 3074234848Smav mdi->mdio_started = 0; 3075234848Smav callout_stop(&mdi->mdio_start_co); 3076234848Smav G_RAID_DEBUG1(1, md->mdo_softc, 3077234848Smav "root_mount_rel %p", mdi->mdio_rootmount); 3078234848Smav root_mount_rel(mdi->mdio_rootmount); 3079234848Smav mdi->mdio_rootmount = NULL; 3080234848Smav } 3081234848Smav ddf_meta_free(&mdi->mdio_meta); 3082234848Smav return (0); 3083234848Smav} 3084234848Smav 3085240465SmavG_RAID_MD_DECLARE(ddf, "DDF"); 3086