md_ddf.c revision 234868
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: head/sys/geom/raid/md_ddf.c 234868 2012-05-01 08:19:29Z mav $");
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;
91234848Smav	struct ddf_meta		 mdio_meta;
92234868Smav	int			 mdio_starting;
93234848Smav	struct callout		 mdio_start_co;	/* STARTING state timer. */
94234848Smav	int			 mdio_started;
95234848Smav	struct root_hold_token	*mdio_rootmount; /* Root mount delay token. */
96234848Smav};
97234848Smav
98234848Smavstatic g_raid_md_create_t g_raid_md_create_ddf;
99234848Smavstatic g_raid_md_taste_t g_raid_md_taste_ddf;
100234848Smavstatic g_raid_md_event_t g_raid_md_event_ddf;
101234848Smavstatic g_raid_md_volume_event_t g_raid_md_volume_event_ddf;
102234848Smavstatic g_raid_md_ctl_t g_raid_md_ctl_ddf;
103234848Smavstatic g_raid_md_write_t g_raid_md_write_ddf;
104234848Smavstatic g_raid_md_fail_disk_t g_raid_md_fail_disk_ddf;
105234848Smavstatic g_raid_md_free_disk_t g_raid_md_free_disk_ddf;
106234848Smavstatic g_raid_md_free_volume_t g_raid_md_free_volume_ddf;
107234848Smavstatic g_raid_md_free_t g_raid_md_free_ddf;
108234848Smav
109234848Smavstatic kobj_method_t g_raid_md_ddf_methods[] = {
110234848Smav	KOBJMETHOD(g_raid_md_create,	g_raid_md_create_ddf),
111234848Smav	KOBJMETHOD(g_raid_md_taste,	g_raid_md_taste_ddf),
112234848Smav	KOBJMETHOD(g_raid_md_event,	g_raid_md_event_ddf),
113234848Smav	KOBJMETHOD(g_raid_md_volume_event,	g_raid_md_volume_event_ddf),
114234848Smav	KOBJMETHOD(g_raid_md_ctl,	g_raid_md_ctl_ddf),
115234848Smav	KOBJMETHOD(g_raid_md_write,	g_raid_md_write_ddf),
116234848Smav	KOBJMETHOD(g_raid_md_fail_disk,	g_raid_md_fail_disk_ddf),
117234848Smav	KOBJMETHOD(g_raid_md_free_disk,	g_raid_md_free_disk_ddf),
118234848Smav	KOBJMETHOD(g_raid_md_free_volume,	g_raid_md_free_volume_ddf),
119234848Smav	KOBJMETHOD(g_raid_md_free,	g_raid_md_free_ddf),
120234848Smav	{ 0, 0 }
121234848Smav};
122234848Smav
123234848Smavstatic struct g_raid_md_class g_raid_md_ddf_class = {
124234848Smav	"DDF",
125234848Smav	g_raid_md_ddf_methods,
126234848Smav	sizeof(struct g_raid_md_ddf_object),
127234848Smav	.mdc_priority = 100
128234848Smav};
129234848Smav
130234848Smav#define GET8(m, f)	((m)->f)
131234848Smav#define GET16(m, f)	((m)->bigendian ? be16dec(&(m)->f) : le16dec(&(m)->f))
132234848Smav#define GET32(m, f)	((m)->bigendian ? be32dec(&(m)->f) : le32dec(&(m)->f))
133234848Smav#define GET64(m, f)	((m)->bigendian ? be64dec(&(m)->f) : le64dec(&(m)->f))
134234848Smav#define GET8D(m, f)	(f)
135234848Smav#define GET16D(m, f)	((m)->bigendian ? be16dec(&f) : le16dec(&f))
136234848Smav#define GET32D(m, f)	((m)->bigendian ? be32dec(&f) : le32dec(&f))
137234848Smav#define GET64D(m, f)	((m)->bigendian ? be64dec(&f) : le64dec(&f))
138234848Smav#define GET8P(m, f)	(*(f))
139234848Smav#define GET16P(m, f)	((m)->bigendian ? be16dec(f) : le16dec(f))
140234848Smav#define GET32P(m, f)	((m)->bigendian ? be32dec(f) : le32dec(f))
141234848Smav#define GET64P(m, f)	((m)->bigendian ? be64dec(f) : le64dec(f))
142234848Smav
143234848Smav#define SET8P(m, f, v)							\
144234848Smav	(*(f) = (v))
145234848Smav#define SET16P(m, f, v)							\
146234848Smav	do {								\
147234848Smav		if ((m)->bigendian)					\
148234848Smav			be16enc((f), (v));				\
149234848Smav		else							\
150234848Smav			le16enc((f), (v));				\
151234848Smav	} while (0)
152234848Smav#define SET32P(m, f, v)							\
153234848Smav	do {								\
154234848Smav		if ((m)->bigendian)					\
155234848Smav			be32enc((f), (v));				\
156234848Smav		else							\
157234848Smav			le32enc((f), (v));				\
158234848Smav	} while (0)
159234848Smav#define SET64P(m, f, v)							\
160234848Smav	do {								\
161234848Smav		if ((m)->bigendian)					\
162234848Smav			be64enc((f), (v));				\
163234848Smav		else							\
164234848Smav			le64enc((f), (v));				\
165234848Smav	} while (0)
166234848Smav#define SET8(m, f, v)	SET8P((m), &((m)->f), (v))
167234848Smav#define SET16(m, f, v)	SET16P((m), &((m)->f), (v))
168234848Smav#define SET32(m, f, v)	SET32P((m), &((m)->f), (v))
169234848Smav#define SET64(m, f, v)	SET64P((m), &((m)->f), (v))
170234848Smav#define SET8D(m, f, v)	SET8P((m), &(f), (v))
171234848Smav#define SET16D(m, f, v)	SET16P((m), &(f), (v))
172234848Smav#define SET32D(m, f, v)	SET32P((m), &(f), (v))
173234848Smav#define SET64D(m, f, v)	SET64P((m), &(f), (v))
174234848Smav
175234848Smavstatic int
176234848Smavisff(uint8_t *buf, int size)
177234848Smav{
178234848Smav	int i;
179234848Smav
180234848Smav	for (i = 0; i < size; i++)
181234848Smav		if (buf[i] != 0xff)
182234848Smav			return (0);
183234848Smav	return (1);
184234848Smav}
185234848Smav
186234848Smavstatic void
187234848Smavprint_guid(uint8_t *buf)
188234848Smav{
189234848Smav	int i, ascii;
190234848Smav
191234848Smav	ascii = 1;
192234848Smav	for (i = 0; i < 24; i++) {
193234848Smav		if (buf[i] != 0 && (buf[i] < ' ' || buf[i] > 127)) {
194234848Smav			ascii = 0;
195234848Smav			break;
196234848Smav		}
197234848Smav	}
198234848Smav	if (ascii) {
199234848Smav		printf("'%.24s'", buf);
200234848Smav	} else {
201234848Smav		for (i = 0; i < 24; i++)
202234848Smav			printf("%02x", buf[i]);
203234848Smav	}
204234848Smav}
205234848Smav
206234848Smavstatic void
207234848Smavg_raid_md_ddf_print(struct ddf_meta *meta)
208234848Smav{
209234848Smav	struct ddf_vdc_record *vdc;
210234848Smav	struct ddf_vuc_record *vuc;
211234848Smav	struct ddf_sa_record *sa;
212234848Smav	uint64_t *val2;
213234848Smav	uint32_t val;
214234848Smav	int i, j, k, num, num2;
215234848Smav
216234848Smav	if (g_raid_debug < 1)
217234848Smav		return;
218234848Smav
219234848Smav	printf("********* DDF Metadata *********\n");
220234848Smav	printf("**** Header ****\n");
221234848Smav	printf("DDF_Header_GUID      ");
222234848Smav	print_guid(meta->hdr->DDF_Header_GUID);
223234848Smav	printf("\n");
224234848Smav	printf("DDF_rev              %8.8s\n", (char *)&meta->hdr->DDF_rev[0]);
225234848Smav	printf("Sequence_Number      0x%08x\n", GET32(meta, hdr->Sequence_Number));
226234848Smav	printf("TimeStamp            0x%08x\n", GET32(meta, hdr->TimeStamp));
227234848Smav	printf("Open_Flag            0x%02x\n", GET16(meta, hdr->Open_Flag));
228234848Smav	printf("Foreign_Flag         0x%02x\n", GET16(meta, hdr->Foreign_Flag));
229234848Smav	printf("Diskgrouping         0x%02x\n", GET16(meta, hdr->Diskgrouping));
230234848Smav	printf("Primary_Header_LBA   %ju\n", GET64(meta, hdr->Primary_Header_LBA));
231234848Smav	printf("Secondary_Header_LBA %ju\n", GET64(meta, hdr->Secondary_Header_LBA));
232234848Smav	printf("WorkSpace_Length     %u\n", GET32(meta, hdr->WorkSpace_Length));
233234848Smav	printf("WorkSpace_LBA        %ju\n", GET64(meta, hdr->WorkSpace_LBA));
234234848Smav	printf("Max_PD_Entries       %u\n", GET16(meta, hdr->Max_PD_Entries));
235234848Smav	printf("Max_VD_Entries       %u\n", GET16(meta, hdr->Max_VD_Entries));
236234848Smav	printf("Max_Partitions       %u\n", GET16(meta, hdr->Max_Partitions));
237234848Smav	printf("Configuration_Record_Length %u\n", GET16(meta, hdr->Configuration_Record_Length));
238234848Smav	printf("Max_Primary_Element_Entries %u\n", GET16(meta, hdr->Max_Primary_Element_Entries));
239234848Smav	printf("Controller Data      %u:%u\n", GET32(meta, hdr->cd_section), GET32(meta, hdr->cd_length));
240234848Smav	printf("Physical Disk        %u:%u\n", GET32(meta, hdr->pdr_section), GET32(meta, hdr->pdr_length));
241234848Smav	printf("Virtual Disk         %u:%u\n", GET32(meta, hdr->vdr_section), GET32(meta, hdr->vdr_length));
242234848Smav	printf("Configuration Recs   %u:%u\n", GET32(meta, hdr->cr_section), GET32(meta, hdr->cr_length));
243234848Smav	printf("Physical Disk Recs   %u:%u\n", GET32(meta, hdr->pdd_section), GET32(meta, hdr->pdd_length));
244234848Smav	printf("BBM Log              %u:%u\n", GET32(meta, hdr->bbmlog_section), GET32(meta, hdr->bbmlog_length));
245234848Smav	printf("Diagnostic Space     %u:%u\n", GET32(meta, hdr->Diagnostic_Space), GET32(meta, hdr->Diagnostic_Space_Length));
246234848Smav	printf("Vendor_Specific_Logs %u:%u\n", GET32(meta, hdr->Vendor_Specific_Logs), GET32(meta, hdr->Vendor_Specific_Logs_Length));
247234848Smav	printf("**** Controler Data ****\n");
248234848Smav	printf("Controller_GUID      ");
249234848Smav	print_guid(meta->cdr->Controller_GUID);
250234848Smav	printf("\n");
251234848Smav	printf("Controller_Type      0x%04x%04x 0x%04x%04x\n",
252234848Smav	    GET16(meta, cdr->Controller_Type.Vendor_ID),
253234848Smav	    GET16(meta, cdr->Controller_Type.Device_ID),
254234848Smav	    GET16(meta, cdr->Controller_Type.SubVendor_ID),
255234848Smav	    GET16(meta, cdr->Controller_Type.SubDevice_ID));
256234848Smav	printf("Product_ID           '%.16s'\n", (char *)&meta->cdr->Product_ID[0]);
257234848Smav	printf("**** Physical Disk Data ****\n");
258234848Smav	printf("Populated_PDEs       %u\n", GET16(meta, pdr->Populated_PDEs));
259234848Smav	printf("Max_PDE_Supported    %u\n", GET16(meta, pdr->Max_PDE_Supported));
260234848Smav	for (j = 0; j < GET16(meta, pdr->Populated_PDEs); j++) {
261234848Smav		if (isff(meta->pdr->entry[j].PD_GUID, 24))
262234848Smav			continue;
263234848Smav		if (GET32(meta, pdr->entry[j].PD_Reference) == 0xffffffff)
264234848Smav			continue;
265234848Smav		printf("PD_GUID              ");
266234848Smav		print_guid(meta->pdr->entry[j].PD_GUID);
267234848Smav		printf("\n");
268234848Smav		printf("PD_Reference         0x%08x\n",
269234848Smav		    GET32(meta, pdr->entry[j].PD_Reference));
270234848Smav		printf("PD_Type              0x%04x\n",
271234848Smav		    GET16(meta, pdr->entry[j].PD_Type));
272234848Smav		printf("PD_State             0x%04x\n",
273234848Smav		    GET16(meta, pdr->entry[j].PD_State));
274234848Smav		printf("Configured_Size      %ju\n",
275234848Smav		    GET64(meta, pdr->entry[j].Configured_Size));
276234848Smav		printf("Block_Size           %u\n",
277234848Smav		    GET16(meta, pdr->entry[j].Block_Size));
278234848Smav	}
279234848Smav	printf("**** Virtual Disk Data ****\n");
280234848Smav	printf("Populated_VDEs       %u\n", GET16(meta, vdr->Populated_VDEs));
281234848Smav	printf("Max_VDE_Supported    %u\n", GET16(meta, vdr->Max_VDE_Supported));
282234848Smav	for (j = 0; j < GET16(meta, vdr->Populated_VDEs); j++) {
283234848Smav		if (isff(meta->vdr->entry[j].VD_GUID, 24))
284234848Smav			continue;
285234848Smav		printf("VD_GUID              ");
286234848Smav		print_guid(meta->vdr->entry[j].VD_GUID);
287234848Smav		printf("\n");
288234848Smav		printf("VD_Number            0x%04x\n",
289234848Smav		    GET16(meta, vdr->entry[j].VD_Number));
290234848Smav		printf("VD_Type              0x%02x\n",
291234848Smav		    GET8(meta, vdr->entry[j].VD_Type));
292234848Smav		printf("VD_State             0x%02x\n",
293234848Smav		    GET8(meta, vdr->entry[j].VD_State));
294234848Smav		printf("Init_State           0x%02x\n",
295234848Smav		    GET8(meta, vdr->entry[j].Init_State));
296234848Smav		printf("Drive_Failures_Remaining %u\n",
297234848Smav		    GET8(meta, vdr->entry[j].Drive_Failures_Remaining));
298234848Smav		printf("VD_Name              '%.16s'\n",
299234848Smav		    (char *)&meta->vdr->entry[j].VD_Name);
300234848Smav	}
301234848Smav	printf("**** Configuration Records ****\n");
302234848Smav	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
303234848Smav	for (j = 0; j < num; j++) {
304234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
305234848Smav		    j * GET16(meta, hdr->Configuration_Record_Length) *
306234848Smav		    meta->sectorsize);
307234848Smav		val = GET32D(meta, vdc->Signature);
308234848Smav		switch (val) {
309234848Smav		case DDF_VDCR_SIGNATURE:
310234848Smav			printf("** Virtual Disk Configuration **\n");
311234848Smav			printf("VD_GUID              ");
312234848Smav			print_guid(vdc->VD_GUID);
313234848Smav			printf("\n");
314234848Smav			printf("Timestamp            0x%08x\n",
315234848Smav			    GET32D(meta, vdc->Timestamp));
316234848Smav			printf("Sequence_Number      0x%08x\n",
317234848Smav			    GET32D(meta, vdc->Sequence_Number));
318234848Smav			printf("Primary_Element_Count %u\n",
319234848Smav			    GET16D(meta, vdc->Primary_Element_Count));
320234848Smav			printf("Stripe_Size          %u\n",
321234848Smav			    GET8D(meta, vdc->Stripe_Size));
322234848Smav			printf("Primary_RAID_Level   0x%02x\n",
323234848Smav			    GET8D(meta, vdc->Primary_RAID_Level));
324234848Smav			printf("RLQ                  0x%02x\n",
325234848Smav			    GET8D(meta, vdc->RLQ));
326234848Smav			printf("Secondary_Element_Count %u\n",
327234848Smav			    GET8D(meta, vdc->Secondary_Element_Count));
328234848Smav			printf("Secondary_Element_Seq %u\n",
329234848Smav			    GET8D(meta, vdc->Secondary_Element_Seq));
330234848Smav			printf("Secondary_RAID_Level 0x%02x\n",
331234848Smav			    GET8D(meta, vdc->Secondary_RAID_Level));
332234848Smav			printf("Block_Count          %ju\n",
333234848Smav			    GET64D(meta, vdc->Block_Count));
334234848Smav			printf("VD_Size              %ju\n",
335234848Smav			    GET64D(meta, vdc->VD_Size));
336234848Smav			printf("Block_Size           %u\n",
337234848Smav			    GET16D(meta, vdc->Block_Size));
338234848Smav			printf("Rotate_Parity_count  %u\n",
339234848Smav			    GET8D(meta, vdc->Rotate_Parity_count));
340234848Smav			printf("Associated_Spare_Disks");
341234848Smav			for (i = 0; i < 8; i++) {
342234848Smav				if (GET32D(meta, vdc->Associated_Spares[i]) != 0xffffffff)
343234848Smav					printf(" 0x%08x", GET32D(meta, vdc->Associated_Spares[i]));
344234848Smav			}
345234848Smav			printf("\n");
346234848Smav			printf("Cache_Flags          %016jx\n",
347234848Smav			    GET64D(meta, vdc->Cache_Flags));
348234848Smav			printf("BG_Rate              %u\n",
349234848Smav			    GET8D(meta, vdc->BG_Rate));
350234848Smav			printf("MDF_Parity_Disks     %u\n",
351234848Smav			    GET8D(meta, vdc->MDF_Parity_Disks));
352234848Smav			printf("MDF_Parity_Generator_Polynomial 0x%04x\n",
353234848Smav			    GET16D(meta, vdc->MDF_Parity_Generator_Polynomial));
354234848Smav			printf("MDF_Constant_Generation_Method 0x%02x\n",
355234848Smav			    GET8D(meta, vdc->MDF_Constant_Generation_Method));
356234848Smav			printf("Physical_Disks      ");
357234848Smav			num2 = GET16D(meta, vdc->Primary_Element_Count);
358234848Smav			val2 = (uint64_t *)&(vdc->Physical_Disk_Sequence[GET16(meta, hdr->Max_Primary_Element_Entries)]);
359234848Smav			for (i = 0; i < num2; i++)
360234848Smav				printf(" 0x%08x @ %ju",
361234848Smav				    GET32D(meta, vdc->Physical_Disk_Sequence[i]),
362234848Smav				    GET64P(meta, val2 + i));
363234848Smav			printf("\n");
364234848Smav			break;
365234848Smav		case DDF_VUCR_SIGNATURE:
366234848Smav			printf("** Vendor Unique Configuration **\n");
367234848Smav			vuc = (struct ddf_vuc_record *)vdc;
368234848Smav			printf("VD_GUID              ");
369234848Smav			print_guid(vuc->VD_GUID);
370234848Smav			printf("\n");
371234848Smav			break;
372234848Smav		case DDF_SA_SIGNATURE:
373234848Smav			printf("** Spare Assignment Configuration **\n");
374234848Smav			sa = (struct ddf_sa_record *)vdc;
375234848Smav			printf("Timestamp            0x%08x\n",
376234848Smav			    GET32D(meta, sa->Timestamp));
377234848Smav			printf("Spare_Type           0x%02x\n",
378234848Smav			    GET8D(meta, sa->Spare_Type));
379234848Smav			printf("Populated_SAEs       %u\n",
380234848Smav			    GET16D(meta, sa->Populated_SAEs));
381234848Smav			printf("MAX_SAE_Supported    %u\n",
382234848Smav			    GET16D(meta, sa->MAX_SAE_Supported));
383234848Smav			for (i = 0; i < GET16D(meta, sa->Populated_SAEs); i++) {
384234848Smav				if (isff(sa->entry[i].VD_GUID, 24))
385234848Smav					continue;
386234848Smav				printf("VD_GUID             ");
387234848Smav				for (k = 0; k < 24; k++)
388234848Smav					printf("%02x", sa->entry[i].VD_GUID[k]);
389234848Smav				printf("\n");
390234848Smav				printf("Secondary_Element   %u\n",
391234848Smav				    GET16D(meta, sa->entry[i].Secondary_Element));
392234848Smav			}
393234848Smav			break;
394234848Smav		case 0xFFFFFFFF:
395234848Smav			break;
396234848Smav		default:
397234848Smav			printf("Unknown configuration signature %08x\n", val);
398234848Smav			break;
399234848Smav		}
400234848Smav	}
401234848Smav	printf("**** Physical Disk Data ****\n");
402234848Smav	printf("PD_GUID              ");
403234848Smav	print_guid(meta->pdd->PD_GUID);
404234848Smav	printf("\n");
405234848Smav	printf("PD_Reference         0x%08x\n",
406234848Smav	    GET32(meta, pdd->PD_Reference));
407234848Smav	printf("Forced_Ref_Flag      0x%02x\n",
408234848Smav	    GET8(meta, pdd->Forced_Ref_Flag));
409234848Smav	printf("Forced_PD_GUID_Flag  0x%02x\n",
410234848Smav	    GET8(meta, pdd->Forced_PD_GUID_Flag));
411234848Smav}
412234848Smav
413234848Smavstatic int
414234848Smavddf_meta_find_pd(struct ddf_meta *meta, uint8_t *GUID, uint32_t PD_Reference)
415234848Smav{
416234848Smav	int i;
417234848Smav
418234848Smav	for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
419234848Smav		if (GUID != NULL) {
420234848Smav			if (memcmp(meta->pdr->entry[i].PD_GUID, GUID, 24) == 0)
421234848Smav				return (i);
422234848Smav		} else if (PD_Reference != 0xffffffff) {
423234848Smav			if (GET32(meta, pdr->entry[i].PD_Reference) == PD_Reference)
424234848Smav				return (i);
425234848Smav		} else
426234848Smav			if (isff(meta->pdr->entry[i].PD_GUID, 24))
427234848Smav				return (i);
428234848Smav	}
429234848Smav	if (GUID == NULL && PD_Reference == 0xffffffff) {
430234848Smav		if (i >= GET16(meta, pdr->Max_PDE_Supported))
431234848Smav			return (-1);
432234848Smav		SET16(meta, pdr->Populated_PDEs, i + 1);
433234848Smav		return (i);
434234848Smav	}
435234848Smav	return (-1);
436234848Smav}
437234848Smav
438234848Smavstatic int
439234848Smavddf_meta_find_vd(struct ddf_meta *meta, uint8_t *GUID)
440234848Smav{
441234848Smav	int i;
442234848Smav
443234848Smav	for (i = 0; i < GET16(meta, vdr->Populated_VDEs); i++) {
444234848Smav		if (GUID != NULL) {
445234848Smav			if (memcmp(meta->vdr->entry[i].VD_GUID, GUID, 24) == 0)
446234848Smav				return (i);
447234848Smav		} else
448234848Smav			if (isff(meta->vdr->entry[i].VD_GUID, 24))
449234848Smav				return (i);
450234848Smav	}
451234848Smav	if (GUID == NULL) {
452234848Smav		if (i >= GET16(meta, vdr->Max_VDE_Supported))
453234848Smav			return (-1);
454234848Smav		SET16(meta, vdr->Populated_VDEs, i + 1);
455234848Smav		return (i);
456234848Smav	}
457234848Smav	return (-1);
458234848Smav}
459234848Smav
460234848Smavstatic struct ddf_vdc_record *
461234848Smavddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID)
462234848Smav{
463234848Smav	struct ddf_vdc_record *vdc;
464234848Smav	int i, num;
465234848Smav
466234848Smav	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
467234848Smav	for (i = 0; i < num; i++) {
468234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
469234848Smav		    i * GET16(meta, hdr->Configuration_Record_Length) *
470234848Smav		    meta->sectorsize);
471234848Smav		if (GUID != NULL) {
472234848Smav			if (GET32D(meta, vdc->Signature) == DDF_VDCR_SIGNATURE &&
473234848Smav			    memcmp(vdc->VD_GUID, GUID, 24) == 0)
474234848Smav				return (vdc);
475234848Smav		} else
476234848Smav			if (GET32D(meta, vdc->Signature) == 0xffffffff)
477234848Smav				return (vdc);
478234848Smav	}
479234848Smav	return (NULL);
480234848Smav}
481234848Smav
482234848Smavstatic int
483234848Smavddf_meta_count_vdc(struct ddf_meta *meta, uint8_t *GUID)
484234848Smav{
485234848Smav	struct ddf_vdc_record *vdc;
486234848Smav	int i, num, cnt;
487234848Smav
488234848Smav	cnt = 0;
489234848Smav	num = GET32(meta, hdr->cr_length) / GET16(meta, hdr->Configuration_Record_Length);
490234848Smav	for (i = 0; i < num; i++) {
491234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
492234848Smav		    i * GET16(meta, hdr->Configuration_Record_Length) *
493234848Smav		    meta->sectorsize);
494234848Smav		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
495234848Smav			continue;
496234848Smav		if (GUID == NULL || memcmp(vdc->VD_GUID, GUID, 24) == 0)
497234848Smav			cnt++;
498234848Smav	}
499234848Smav	return (cnt);
500234848Smav}
501234848Smav
502234848Smavstatic int
503234848Smavddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference,
504234848Smav    int *bvdp, int *posp)
505234848Smav{
506234848Smav	int i, bvd, pos;
507234848Smav
508234848Smav	i = 0;
509234848Smav	for (bvd = 0; bvd < GET16(vmeta, vdc->Secondary_Element_Count); bvd++) {
510234848Smav		if (vmeta->bvdc[bvd] == NULL) {
511234848Smav			i += GET16(vmeta, vdc->Primary_Element_Count); // XXX
512234848Smav			continue;
513234848Smav		}
514234848Smav		for (pos = 0; pos < GET16(vmeta, bvdc[bvd]->Primary_Element_Count);
515234848Smav		    pos++, i++) {
516234848Smav			if (GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]) ==
517234848Smav			    PD_Reference) {
518234848Smav				if (bvdp != NULL)
519234848Smav					*bvdp = bvd;
520234848Smav				if (posp != NULL)
521234848Smav					*posp = pos;
522234848Smav				return (i);
523234848Smav			}
524234848Smav		}
525234848Smav	}
526234848Smav	return (-1);
527234848Smav}
528234848Smav
529234848Smavstatic void
530234848Smavddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
531234848Smav{
532234848Smav	struct timespec ts;
533234848Smav	struct clocktime ct;
534234848Smav	struct g_raid_md_ddf_perdisk *pd;
535234848Smav	struct ddf_meta *meta;
536234848Smav	struct ddf_pd_entry *pde;
537234848Smav	off_t anchorlba;
538234848Smav	u_int ss, pos, size;
539234848Smav	int len, error;
540234848Smav	char serial_buffer[24];
541234848Smav
542234848Smav	if (sample->hdr == NULL)
543234848Smav		sample = NULL;
544234848Smav
545234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
546234848Smav	meta = &pd->pd_meta;
547234848Smav	ss = disk->d_consumer->provider->sectorsize;
548234848Smav	anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
549234848Smav
550234848Smav	meta->sectorsize = ss;
551234848Smav	meta->bigendian = sample ? sample->bigendian : 0;
552234848Smav	getnanotime(&ts);
553234848Smav	clock_ts_to_ct(&ts, &ct);
554234848Smav
555234848Smav	/* Header */
556234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
557234848Smav	memset(meta->hdr, 0xff, ss);
558234848Smav	if (sample) {
559234848Smav		memcpy(meta->hdr, sample->hdr, sizeof(struct ddf_header));
560234848Smav		if (ss != sample->sectorsize) {
561234848Smav			SET32(meta, hdr->WorkSpace_Length,
562234848Smav			    (GET32(sample, hdr->WorkSpace_Length) *
563234848Smav			    sample->sectorsize + ss - 1) / ss);
564234848Smav			SET16(meta, hdr->Configuration_Record_Length,
565234848Smav			    (GET16(sample, hdr->Configuration_Record_Length) *
566234848Smav			    sample->sectorsize + ss - 1) / ss);
567234848Smav			SET32(meta, hdr->cd_length,
568234848Smav			    (GET32(sample, hdr->cd_length) *
569234848Smav			    sample->sectorsize + ss - 1) / ss);
570234848Smav			SET32(meta, hdr->pdr_length,
571234848Smav			    (GET32(sample, hdr->pdr_length) *
572234848Smav			    sample->sectorsize + ss - 1) / ss);
573234848Smav			SET32(meta, hdr->vdr_length,
574234848Smav			    (GET32(sample, hdr->vdr_length) *
575234848Smav			    sample->sectorsize + ss - 1) / ss);
576234848Smav			SET32(meta, hdr->cr_length,
577234848Smav			    (GET32(sample, hdr->cr_length) *
578234848Smav			    sample->sectorsize + ss - 1) / ss);
579234848Smav			SET32(meta, hdr->pdd_length,
580234848Smav			    (GET32(sample, hdr->pdd_length) *
581234848Smav			    sample->sectorsize + ss - 1) / ss);
582234848Smav			SET32(meta, hdr->bbmlog_length,
583234848Smav			    (GET32(sample, hdr->bbmlog_length) *
584234848Smav			    sample->sectorsize + ss - 1) / ss);
585234848Smav			SET32(meta, hdr->Diagnostic_Space,
586234848Smav			    (GET32(sample, hdr->bbmlog_length) *
587234848Smav			    sample->sectorsize + ss - 1) / ss);
588234848Smav			SET32(meta, hdr->Vendor_Specific_Logs,
589234848Smav			    (GET32(sample, hdr->bbmlog_length) *
590234848Smav			    sample->sectorsize + ss - 1) / ss);
591234848Smav		}
592234848Smav	} else {
593234848Smav		SET32(meta, hdr->Signature, DDF_HEADER_SIGNATURE);
594234848Smav		snprintf(meta->hdr->DDF_Header_GUID, 25, "FreeBSD %08x%08x",
595234848Smav		    (u_int)(ts.tv_sec - DECADE), arc4random());
596234848Smav		memcpy(meta->hdr->DDF_rev, "02.00.00", 8);
597234848Smav		SET32(meta, hdr->TimeStamp, (ts.tv_sec - DECADE));
598234848Smav		SET32(meta, hdr->WorkSpace_Length, 16 * 1024 * 1024 / ss);
599234848Smav		SET16(meta, hdr->Max_PD_Entries, DDF_MAX_DISKS - 1);
600234848Smav		SET16(meta, hdr->Max_VD_Entries, DDF_MAX_VDISKS);
601234848Smav		SET16(meta, hdr->Max_Partitions, DDF_MAX_PARTITIONS);
602234848Smav		SET16(meta, hdr->Max_Primary_Element_Entries, DDF_MAX_DISKS);
603234848Smav		SET16(meta, hdr->Configuration_Record_Length,
604234848Smav		    (sizeof(struct ddf_vdc_record) +
605234848Smav		     (4 + 8) * GET16(meta, hdr->Max_Primary_Element_Entries) +
606234848Smav		     ss - 1) / ss);
607234848Smav		SET32(meta, hdr->cd_length,
608234848Smav		    (sizeof(struct ddf_cd_record) + ss - 1) / ss);
609234848Smav		SET32(meta, hdr->pdr_length,
610234848Smav		    (sizeof(struct ddf_pd_record) +
611234848Smav		     sizeof(struct ddf_pd_entry) *
612234848Smav		     GET16(meta, hdr->Max_PD_Entries) + ss - 1) / ss);
613234848Smav		SET32(meta, hdr->vdr_length,
614234848Smav		    (sizeof(struct ddf_vd_record) +
615234848Smav		     sizeof(struct ddf_vd_entry) *
616234848Smav		     GET16(meta, hdr->Max_VD_Entries) + ss - 1) / ss);
617234848Smav		SET32(meta, hdr->cr_length,
618234848Smav		    GET16(meta, hdr->Configuration_Record_Length) *
619234848Smav		    (GET16(meta, hdr->Max_Partitions) + 1));
620234848Smav		SET32(meta, hdr->pdd_length,
621234848Smav		    (sizeof(struct ddf_pdd_record) + ss - 1) / ss);
622234848Smav		SET32(meta, hdr->bbmlog_length, 0);
623234848Smav		SET32(meta, hdr->Diagnostic_Space_Length, 0);
624234848Smav		SET32(meta, hdr->Vendor_Specific_Logs_Length, 0);
625234848Smav	}
626234848Smav	pos = 1;
627234848Smav	SET32(meta, hdr->cd_section, pos);
628234848Smav	pos += GET32(meta, hdr->cd_length);
629234848Smav	SET32(meta, hdr->pdr_section, pos);
630234848Smav	pos += GET32(meta, hdr->pdr_length);
631234848Smav	SET32(meta, hdr->vdr_section, pos);
632234848Smav	pos += GET32(meta, hdr->vdr_length);
633234848Smav	SET32(meta, hdr->cr_section, pos);
634234848Smav	pos += GET32(meta, hdr->cr_length);
635234848Smav	SET32(meta, hdr->pdd_section, pos);
636234848Smav	pos += GET32(meta, hdr->pdd_length);
637234848Smav	SET32(meta, hdr->bbmlog_section,
638234848Smav	    GET32(meta, hdr->bbmlog_length) != 0 ? pos : 0xffffffff);
639234848Smav	pos += GET32(meta, hdr->bbmlog_length);
640234848Smav	SET32(meta, hdr->Diagnostic_Space,
641234848Smav	    GET32(meta, hdr->Diagnostic_Space_Length) != 0 ? pos : 0xffffffff);
642234848Smav	pos += GET32(meta, hdr->Diagnostic_Space_Length);
643234848Smav	SET32(meta, hdr->Vendor_Specific_Logs,
644234848Smav	    GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff);
645234848Smav	pos += GET32(meta, hdr->Vendor_Specific_Logs_Length);
646234848Smav	SET64(meta, hdr->Primary_Header_LBA,
647234848Smav	    anchorlba - pos - 16);
648234848Smav	SET64(meta, hdr->Secondary_Header_LBA,
649234848Smav	    0xffffffffffffffffULL);
650234848Smav	SET64(meta, hdr->WorkSpace_LBA,
651234848Smav	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
652234848Smav
653234848Smav	/* Controller Data */
654234848Smav	size = GET32(meta, hdr->cd_length) * ss;
655234848Smav	meta->cdr = malloc(size, M_MD_DDF, M_WAITOK);
656234848Smav	memset(meta->cdr, 0xff, size);
657234848Smav	SET32(meta, cdr->Signature, DDF_CONTROLLER_DATA_SIGNATURE);
658234848Smav	memcpy(meta->cdr->Controller_GUID, "FreeBSD GEOM RAID SERIAL", 24);
659234848Smav	memcpy(meta->cdr->Product_ID, "FreeBSD GEOMRAID", 16);
660234848Smav
661234848Smav	/* Physical Drive Records. */
662234848Smav	size = GET32(meta, hdr->pdr_length) * ss;
663234848Smav	meta->pdr = malloc(size, M_MD_DDF, M_WAITOK);
664234848Smav	memset(meta->pdr, 0xff, size);
665234848Smav	SET32(meta, pdr->Signature, DDF_PDR_SIGNATURE);
666234848Smav	SET16(meta, pdr->Populated_PDEs, 1);
667234848Smav	SET16(meta, pdr->Max_PDE_Supported,
668234848Smav	    GET16(meta, hdr->Max_PD_Entries));
669234848Smav
670234848Smav	pde = &meta->pdr->entry[0];
671234848Smav	len = sizeof(serial_buffer);
672234848Smav	error = g_io_getattr("GEOM::ident", disk->d_consumer, &len, serial_buffer);
673234848Smav	if (error == 0 && (len = strlen (serial_buffer)) >= 6 && len <= 20)
674234848Smav		snprintf(pde->PD_GUID, 25, "DISK%20s", serial_buffer);
675234848Smav	else
676234848Smav		snprintf(pde->PD_GUID, 25, "DISK%04d%02d%02d%08x%04x",
677234848Smav		    ct.year, ct.mon, ct.day,
678234848Smav		    arc4random(), arc4random() & 0xffff);
679234848Smav	SET32D(meta, pde->PD_Reference, arc4random());
680234848Smav	SET16D(meta, pde->PD_Type, DDF_PDE_GUID_FORCE);
681234848Smav	SET16D(meta, pde->PD_State, 0);
682234848Smav	SET64D(meta, pde->Configured_Size,
683234848Smav	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
684234848Smav	SET16D(meta, pde->Block_Size, ss);
685234848Smav
686234848Smav	/* Virtual Drive Records. */
687234848Smav	size = GET32(meta, hdr->vdr_length) * ss;
688234848Smav	meta->vdr = malloc(size, M_MD_DDF, M_WAITOK);
689234848Smav	memset(meta->vdr, 0xff, size);
690234848Smav	SET32(meta, vdr->Signature, DDF_VD_RECORD_SIGNATURE);
691234848Smav	SET32(meta, vdr->Populated_VDEs, 0);
692234848Smav	SET16(meta, vdr->Max_VDE_Supported,
693234848Smav	    GET16(meta, hdr->Max_VD_Entries));
694234848Smav
695234848Smav	/* Configuration Records. */
696234848Smav	size = GET32(meta, hdr->cr_length) * ss;
697234848Smav	meta->cr = malloc(size, M_MD_DDF, M_WAITOK);
698234848Smav	memset(meta->cr, 0xff, size);
699234848Smav
700234848Smav	/* Physical Disk Data. */
701234848Smav	size = GET32(meta, hdr->pdd_length) * ss;
702234848Smav	meta->pdd = malloc(size, M_MD_DDF, M_WAITOK);
703234848Smav	memset(meta->pdd, 0xff, size);
704234848Smav	SET32(meta, pdd->Signature, DDF_PDD_SIGNATURE);
705234848Smav	memcpy(meta->pdd->PD_GUID, pde->PD_GUID, 24);
706234848Smav	SET32(meta, pdd->PD_Reference, GET32D(meta, pde->PD_Reference));
707234848Smav	SET8(meta, pdd->Forced_Ref_Flag, DDF_PDD_FORCED_REF);
708234848Smav	SET8(meta, pdd->Forced_PD_GUID_Flag, DDF_PDD_FORCED_GUID);
709234848Smav
710234848Smav	/* Bad Block Management Log. */
711234848Smav	if (GET32(meta, hdr->bbmlog_length) != 0) {
712234848Smav		size = GET32(meta, hdr->bbmlog_length) * ss;
713234848Smav		meta->bbm = malloc(size, M_MD_DDF, M_WAITOK);
714234848Smav		memset(meta->bbm, 0xff, size);
715234848Smav		SET32(meta, bbm->Signature, DDF_BBML_SIGNATURE);
716234848Smav		SET32(meta, bbm->Entry_Count, 0);
717234848Smav		SET32(meta, bbm->Spare_Block_Count, 0);
718234848Smav	}
719234848Smav}
720234848Smav
721234848Smavstatic void
722234848Smavddf_meta_copy(struct ddf_meta *dst, struct ddf_meta *src)
723234848Smav{
724234848Smav	struct ddf_header *hdr;
725234848Smav	u_int ss;
726234848Smav
727234848Smav	hdr = src->hdr;
728234848Smav	dst->bigendian = src->bigendian;
729234848Smav	ss = dst->sectorsize = src->sectorsize;
730234848Smav	dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
731234848Smav	memcpy(dst->hdr, src->hdr, ss);
732234848Smav	dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
733234848Smav	memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
734234848Smav	dst->pdr = malloc(GET32(src, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
735234848Smav	memcpy(dst->pdr, src->pdr, GET32(src, hdr->pdr_length) * ss);
736234848Smav	dst->vdr = malloc(GET32(src, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
737234848Smav	memcpy(dst->vdr, src->vdr, GET32(src, hdr->vdr_length) * ss);
738234848Smav	dst->cr = malloc(GET32(src, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
739234848Smav	memcpy(dst->cr, src->cr, GET32(src, hdr->cr_length) * ss);
740234848Smav	dst->pdd = malloc(GET32(src, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
741234848Smav	memcpy(dst->pdd, src->pdd, GET32(src, hdr->pdd_length) * ss);
742234848Smav	if (src->bbm != NULL) {
743234848Smav		dst->bbm = malloc(GET32(src, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
744234848Smav		memcpy(dst->bbm, src->bbm, GET32(src, hdr->bbmlog_length) * ss);
745234848Smav	}
746234848Smav}
747234848Smav
748234848Smavstatic void
749234848Smavddf_meta_update(struct ddf_meta *meta, struct ddf_meta *src)
750234848Smav{
751234848Smav	struct ddf_pd_entry *pde, *spde;
752234848Smav	int i, j;
753234848Smav
754234848Smav	for (i = 0; i < GET16(src, pdr->Populated_PDEs); i++) {
755234848Smav		spde = &src->pdr->entry[i];
756234848Smav		if (isff(spde->PD_GUID, 24))
757234848Smav			continue;
758234848Smav		j = ddf_meta_find_pd(meta, NULL,
759234848Smav		    src->pdr->entry[i].PD_Reference);
760234848Smav		if (j < 0) {
761234848Smav			j = ddf_meta_find_pd(meta, NULL, 0xffffffff);
762234848Smav			pde = &meta->pdr->entry[j];
763234848Smav			memcpy(pde, spde, sizeof(*pde));
764234848Smav		} else {
765234848Smav			pde = &meta->pdr->entry[j];
766234848Smav			SET16D(meta, pde->PD_State,
767234848Smav			    GET16D(meta, pde->PD_State) |
768234848Smav			    GET16D(src, pde->PD_State));
769234848Smav		}
770234848Smav	}
771234848Smav}
772234848Smav
773234848Smavstatic void
774234848Smavddf_meta_free(struct ddf_meta *meta)
775234848Smav{
776234848Smav
777234848Smav	if (meta->hdr != NULL) {
778234848Smav		free(meta->hdr, M_MD_DDF);
779234848Smav		meta->hdr = NULL;
780234848Smav	}
781234848Smav	if (meta->cdr != NULL) {
782234848Smav		free(meta->cdr, M_MD_DDF);
783234848Smav		meta->cdr = NULL;
784234848Smav	}
785234848Smav	if (meta->pdr != NULL) {
786234848Smav		free(meta->pdr, M_MD_DDF);
787234848Smav		meta->pdr = NULL;
788234848Smav	}
789234848Smav	if (meta->vdr != NULL) {
790234848Smav		free(meta->vdr, M_MD_DDF);
791234848Smav		meta->vdr = NULL;
792234848Smav	}
793234848Smav	if (meta->cr != NULL) {
794234848Smav		free(meta->cr, M_MD_DDF);
795234848Smav		meta->cr = NULL;
796234848Smav	}
797234848Smav	if (meta->pdd != NULL) {
798234848Smav		free(meta->pdd, M_MD_DDF);
799234848Smav		meta->pdd = NULL;
800234848Smav	}
801234848Smav	if (meta->bbm != NULL) {
802234848Smav		free(meta->bbm, M_MD_DDF);
803234848Smav		meta->bbm = NULL;
804234848Smav	}
805234848Smav}
806234848Smav
807234848Smavstatic void
808234848Smavddf_vol_meta_create(struct ddf_vol_meta *meta, struct ddf_meta *sample)
809234848Smav{
810234848Smav	struct timespec ts;
811234848Smav	struct clocktime ct;
812234848Smav	struct ddf_header *hdr;
813234848Smav	u_int ss, size;
814234848Smav
815234848Smav	hdr = sample->hdr;
816234848Smav	meta->bigendian = sample->bigendian;
817234848Smav	ss = meta->sectorsize = sample->sectorsize;
818234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
819234848Smav	memcpy(meta->hdr, sample->hdr, ss);
820234848Smav	meta->cdr = malloc(GET32(sample, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
821234848Smav	memcpy(meta->cdr, sample->cdr, GET32(sample, hdr->cd_length) * ss);
822234848Smav	meta->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
823234848Smav	memset(meta->vde, 0xff, sizeof(struct ddf_vd_entry));
824234848Smav	getnanotime(&ts);
825234848Smav	clock_ts_to_ct(&ts, &ct);
826234848Smav	snprintf(meta->vde->VD_GUID, 25, "FreeBSD%04d%02d%02d%08x%01x",
827234848Smav	    ct.year, ct.mon, ct.day,
828234848Smav	    arc4random(), arc4random() & 0xf);
829234848Smav	size = GET16(sample, hdr->Configuration_Record_Length) * ss;
830234848Smav	meta->vdc = malloc(size, M_MD_DDF, M_WAITOK);
831234848Smav	memset(meta->vdc, 0xff, size);
832234848Smav	SET32(meta, vdc->Signature, DDF_VDCR_SIGNATURE);
833234848Smav	memcpy(meta->vdc->VD_GUID, meta->vde->VD_GUID, 24);
834234848Smav	SET32(meta, vdc->Sequence_Number, 0);
835234848Smav}
836234848Smav
837234848Smavstatic void
838234868Smavddf_vol_meta_update(struct ddf_vol_meta *dst, struct ddf_meta *src,
839234868Smav    uint8_t *GUID, int started)
840234848Smav{
841234848Smav	struct ddf_header *hdr;
842234848Smav	struct ddf_vd_entry *vde;
843234848Smav	struct ddf_vdc_record *vdc;
844234848Smav	int vnew, bvnew, bvd, size;
845234848Smav	u_int ss;
846234848Smav
847234848Smav	hdr = src->hdr;
848234848Smav	vde = &src->vdr->entry[ddf_meta_find_vd(src, GUID)];
849234848Smav	vdc = ddf_meta_find_vdc(src, GUID);
850234848Smav	bvd = GET8D(src, vdc->Secondary_Element_Seq);
851234848Smav	size = GET16(src, hdr->Configuration_Record_Length) * src->sectorsize;
852234848Smav
853234848Smav	if (dst->vdc == NULL ||
854234868Smav	    (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
855234868Smav	    GET32(dst, vdc->Sequence_Number))) > 0))
856234848Smav		vnew = 1;
857234848Smav	else
858234848Smav		vnew = 0;
859234848Smav
860234848Smav	if (dst->bvdc[bvd] == NULL ||
861234868Smav	    (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
862234868Smav	    GET32(dst, bvdc[bvd]->Sequence_Number))) > 0))
863234848Smav		bvnew = 1;
864234848Smav	else
865234848Smav		bvnew = 0;
866234848Smav
867234848Smav	if (vnew) {
868234848Smav		dst->bigendian = src->bigendian;
869234848Smav		ss = dst->sectorsize = src->sectorsize;
870234848Smav		if (dst->hdr != NULL)
871234848Smav			free(dst->hdr, M_MD_DDF);
872234848Smav		dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
873234848Smav		memcpy(dst->hdr, src->hdr, ss);
874234848Smav		if (dst->cdr != NULL)
875234848Smav			free(dst->cdr, M_MD_DDF);
876234848Smav		dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
877234848Smav		memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
878234848Smav		if (dst->vde != NULL)
879234848Smav			free(dst->vde, M_MD_DDF);
880234848Smav		dst->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
881234848Smav		memcpy(dst->vde, vde, sizeof(struct ddf_vd_entry));
882234848Smav		if (dst->vdc != NULL)
883234848Smav			free(dst->vdc, M_MD_DDF);
884234848Smav		dst->vdc = malloc(size, M_MD_DDF, M_WAITOK);
885234848Smav		memcpy(dst->vdc, vdc, size);
886234848Smav	}
887234848Smav	if (bvnew) {
888234848Smav		if (dst->bvdc[bvd] != NULL)
889234848Smav			free(dst->bvdc[bvd], M_MD_DDF);
890234848Smav		dst->bvdc[bvd] = malloc(size, M_MD_DDF, M_WAITOK);
891234848Smav		memcpy(dst->bvdc[bvd], vdc, size);
892234848Smav	}
893234848Smav}
894234848Smav
895234848Smavstatic void
896234848Smavddf_vol_meta_free(struct ddf_vol_meta *meta)
897234848Smav{
898234848Smav	int i;
899234848Smav
900234848Smav	if (meta->hdr != NULL) {
901234848Smav		free(meta->hdr, M_MD_DDF);
902234848Smav		meta->hdr = NULL;
903234848Smav	}
904234848Smav	if (meta->cdr != NULL) {
905234848Smav		free(meta->cdr, M_MD_DDF);
906234848Smav		meta->cdr = NULL;
907234848Smav	}
908234848Smav	if (meta->vde != NULL) {
909234848Smav		free(meta->vde, M_MD_DDF);
910234848Smav		meta->vde = NULL;
911234848Smav	}
912234848Smav	if (meta->vdc != NULL) {
913234848Smav		free(meta->vdc, M_MD_DDF);
914234848Smav		meta->vdc = NULL;
915234848Smav	}
916234848Smav	for (i = 0; i < DDF_MAX_DISKS_HARD; i++) {
917234848Smav		if (meta->bvdc[i] != NULL) {
918234848Smav			free(meta->bvdc[i], M_MD_DDF);
919234848Smav			meta->bvdc[i] = NULL;
920234848Smav		}
921234848Smav	}
922234848Smav}
923234848Smav
924234848Smavstatic int
925234848Smavddf_meta_unused_range(struct ddf_meta *meta, off_t *off, off_t *size)
926234848Smav{
927234848Smav	struct ddf_vdc_record *vdc;
928234848Smav	off_t beg[32], end[32], beg1, end1;
929234848Smav	uint64_t *offp;
930234848Smav	int i, j, n, num, pos;
931234848Smav	uint32_t ref;
932234848Smav
933234848Smav	*off = 0;
934234848Smav	*size = 0;
935234848Smav	ref = GET32(meta, pdd->PD_Reference);
936234848Smav	pos = ddf_meta_find_pd(meta, NULL, ref);
937234848Smav	beg[0] = 0;
938234848Smav	end[0] = GET64(meta, pdr->entry[pos].Configured_Size);
939234848Smav	n = 1;
940234848Smav	num = GET32(meta, hdr->cr_length) /
941234848Smav	    GET16(meta, hdr->Configuration_Record_Length);
942234848Smav	for (i = 0; i < num; i++) {
943234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr +
944234848Smav		    i * GET16(meta, hdr->Configuration_Record_Length) *
945234848Smav		    meta->sectorsize);
946234848Smav		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
947234848Smav			continue;
948234848Smav		for (pos = 0; pos < GET16D(meta, vdc->Primary_Element_Count); pos++)
949234848Smav			if (GET32D(meta, vdc->Physical_Disk_Sequence[pos]) == ref)
950234848Smav				break;
951234848Smav		if (pos == GET16D(meta, vdc->Primary_Element_Count))
952234848Smav			continue;
953234848Smav		offp = (uint64_t *)&(vdc->Physical_Disk_Sequence[
954234848Smav		    GET16(meta, hdr->Max_Primary_Element_Entries)]);
955234848Smav		beg1 = GET64P(meta, offp + pos);
956234848Smav		end1 = beg1 + GET64D(meta, vdc->Block_Count);
957234848Smav		for (j = 0; j < n; j++) {
958234848Smav			if (beg[j] >= end1 || end[j] <= beg1 )
959234848Smav				continue;
960234848Smav			if (beg[j] < beg1 && end[j] > end1) {
961234848Smav				beg[n] = end1;
962234848Smav				end[n] = end[j];
963234848Smav				end[j] = beg1;
964234848Smav				n++;
965234848Smav			} else if (beg[j] < beg1)
966234848Smav				end[j] = beg1;
967234848Smav			else
968234848Smav				beg[j] = end1;
969234848Smav		}
970234848Smav	}
971234848Smav	for (j = 0; j < n; j++) {
972234848Smav		if (end[j] - beg[j] > *size) {
973234848Smav			*off = beg[j];
974234848Smav			*size = end[j] - beg[j];
975234848Smav		}
976234848Smav	}
977234848Smav	return ((*size > 0) ? 1 : 0);
978234848Smav}
979234848Smav
980234848Smavstatic void
981234848Smavddf_meta_get_name(struct ddf_meta *meta, int num, char *buf)
982234848Smav{
983234848Smav	const char *b;
984234848Smav	int i;
985234848Smav
986234848Smav	b = meta->vdr->entry[num].VD_Name;
987234848Smav	for (i = 15; i >= 0; i--)
988234848Smav		if (b[i] != 0x20)
989234848Smav			break;
990234848Smav	memcpy(buf, b, i + 1);
991234848Smav	buf[i + 1] = 0;
992234848Smav}
993234848Smav
994234848Smavstatic void
995234848Smavddf_meta_put_name(struct ddf_vol_meta *meta, char *buf)
996234848Smav{
997234848Smav	int len;
998234848Smav
999234848Smav	len = min(strlen(buf), 16);
1000234848Smav	memset(meta->vde->VD_Name, 0x20, 16);
1001234848Smav	memcpy(meta->vde->VD_Name, buf, len);
1002234848Smav}
1003234848Smav
1004234848Smavstatic int
1005234848Smavddf_meta_read(struct g_consumer *cp, struct ddf_meta *meta)
1006234848Smav{
1007234848Smav	struct g_provider *pp;
1008234848Smav	struct ddf_header *ahdr, *hdr;
1009234848Smav	char *abuf, *buf;
1010234848Smav	off_t plba, slba, lba;
1011234848Smav	int error, len, i;
1012234848Smav	u_int ss;
1013234848Smav	uint32_t val;
1014234848Smav
1015234848Smav	ddf_meta_free(meta);
1016234848Smav	pp = cp->provider;
1017234848Smav	ss = meta->sectorsize = pp->sectorsize;
1018234848Smav	/* Read anchor block. */
1019234848Smav	abuf = g_read_data(cp, pp->mediasize - ss, ss, &error);
1020234848Smav	if (abuf == NULL) {
1021234848Smav		G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).",
1022234848Smav		    pp->name, error);
1023234848Smav		return (error);
1024234848Smav	}
1025234848Smav	ahdr = (struct ddf_header *)abuf;
1026234848Smav
1027234848Smav	/* Check if this is an DDF RAID struct */
1028234848Smav	if (be32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
1029234848Smav		meta->bigendian = 1;
1030234848Smav	else if (le32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
1031234848Smav		meta->bigendian = 0;
1032234848Smav	else {
1033234848Smav		G_RAID_DEBUG(1, "DDF signature check failed on %s", pp->name);
1034234848Smav		error = EINVAL;
1035234848Smav		goto done;
1036234848Smav	}
1037234848Smav	if (ahdr->Header_Type != DDF_HEADER_ANCHOR) {
1038234848Smav		G_RAID_DEBUG(1, "DDF header type check failed on %s", pp->name);
1039234848Smav		error = EINVAL;
1040234848Smav		goto done;
1041234848Smav	}
1042234848Smav	meta->hdr = ahdr;
1043234848Smav	plba = GET64(meta, hdr->Primary_Header_LBA);
1044234848Smav	slba = GET64(meta, hdr->Secondary_Header_LBA);
1045234848Smav	val = GET32(meta, hdr->CRC);
1046234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1047234848Smav	meta->hdr = NULL;
1048234848Smav	if (crc32(ahdr, ss) != val) {
1049234848Smav		G_RAID_DEBUG(1, "DDF CRC mismatch on %s", pp->name);
1050234848Smav		error = EINVAL;
1051234848Smav		goto done;
1052234848Smav	}
1053234848Smav	if ((plba + 6) * ss >= pp->mediasize) {
1054234848Smav		G_RAID_DEBUG(1, "DDF primary header LBA is wrong on %s", pp->name);
1055234848Smav		error = EINVAL;
1056234848Smav		goto done;
1057234848Smav	}
1058234848Smav	if (slba != -1 && (slba + 6) * ss >= pp->mediasize) {
1059234848Smav		G_RAID_DEBUG(1, "DDF secondary header LBA is wrong on %s", pp->name);
1060234848Smav		error = EINVAL;
1061234848Smav		goto done;
1062234848Smav	}
1063234848Smav	lba = plba;
1064234848Smav
1065234848Smavdoread:
1066234848Smav	error = 0;
1067234848Smav	ddf_meta_free(meta);
1068234848Smav
1069234848Smav	/* Read header block. */
1070234848Smav	buf = g_read_data(cp, lba * ss, ss, &error);
1071234848Smav	if (buf == NULL) {
1072234848Smavreaderror:
1073234848Smav		G_RAID_DEBUG(1, "DDF %s metadata read error on %s (error=%d).",
1074234848Smav		    (lba == plba) ? "primary" : "secondary", pp->name, error);
1075234848Smav		if (lba == plba && slba != -1) {
1076234848Smav			lba = slba;
1077234848Smav			goto doread;
1078234848Smav		}
1079234848Smav		G_RAID_DEBUG(1, "DDF metadata read error on %s.", pp->name);
1080234848Smav		goto done;
1081234848Smav	}
1082234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
1083234848Smav	memcpy(meta->hdr, buf, ss);
1084234848Smav	g_free(buf);
1085234848Smav	hdr = meta->hdr;
1086234848Smav	val = GET32(meta, hdr->CRC);
1087234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1088234848Smav	if (hdr->Signature != ahdr->Signature ||
1089234848Smav	    crc32(meta->hdr, ss) != val ||
1090234848Smav	    memcmp(hdr->DDF_Header_GUID, ahdr->DDF_Header_GUID, 24) ||
1091234848Smav	    GET64(meta, hdr->Primary_Header_LBA) != plba ||
1092234848Smav	    GET64(meta, hdr->Secondary_Header_LBA) != slba) {
1093234848Smavhdrerror:
1094234848Smav		G_RAID_DEBUG(1, "DDF %s metadata check failed on %s",
1095234848Smav		    (lba == plba) ? "primary" : "secondary", pp->name);
1096234848Smav		if (lba == plba && slba != -1) {
1097234848Smav			lba = slba;
1098234848Smav			goto doread;
1099234848Smav		}
1100234848Smav		G_RAID_DEBUG(1, "DDF metadata check failed on %s", pp->name);
1101234848Smav		error = EINVAL;
1102234848Smav		goto done;
1103234848Smav	}
1104234848Smav	if ((lba == plba && hdr->Header_Type != DDF_HEADER_PRIMARY) ||
1105234848Smav	    (lba == slba && hdr->Header_Type != DDF_HEADER_SECONDARY))
1106234848Smav		goto hdrerror;
1107234848Smav	len = 1;
1108234848Smav	len = max(len, GET32(meta, hdr->cd_section) + GET32(meta, hdr->cd_length));
1109234848Smav	len = max(len, GET32(meta, hdr->pdr_section) + GET32(meta, hdr->pdr_length));
1110234848Smav	len = max(len, GET32(meta, hdr->vdr_section) + GET32(meta, hdr->vdr_length));
1111234848Smav	len = max(len, GET32(meta, hdr->cr_section) + GET32(meta, hdr->cr_length));
1112234848Smav	len = max(len, GET32(meta, hdr->pdd_section) + GET32(meta, hdr->pdd_length));
1113234848Smav	if ((val = GET32(meta, hdr->bbmlog_section)) != 0xffffffff)
1114234848Smav		len = max(len, val + GET32(meta, hdr->bbmlog_length));
1115234848Smav	if ((val = GET32(meta, hdr->Diagnostic_Space)) != 0xffffffff)
1116234848Smav		len = max(len, val + GET32(meta, hdr->Diagnostic_Space_Length));
1117234848Smav	if ((val = GET32(meta, hdr->Vendor_Specific_Logs)) != 0xffffffff)
1118234848Smav		len = max(len, val + GET32(meta, hdr->Vendor_Specific_Logs_Length));
1119234848Smav	if ((plba + len) * ss >= pp->mediasize)
1120234848Smav		goto hdrerror;
1121234848Smav	if (slba != -1 && (slba + len) * ss >= pp->mediasize)
1122234848Smav		goto hdrerror;
1123234848Smav	/* Workaround for Adaptec implementation. */
1124234848Smav	if (GET16(meta, hdr->Max_Primary_Element_Entries) == 0xffff) {
1125234848Smav		SET16(meta, hdr->Max_Primary_Element_Entries,
1126234848Smav		    min(GET16(meta, hdr->Max_PD_Entries),
1127234848Smav		    (GET16(meta, hdr->Configuration_Record_Length) * ss - 512) / 12));
1128234848Smav	}
1129234848Smav
1130234848Smav	/* Read controller data. */
1131234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
1132234848Smav	    GET32(meta, hdr->cd_length) * ss, &error);
1133234848Smav	if (buf == NULL)
1134234848Smav		goto readerror;
1135234848Smav	meta->cdr = malloc(GET32(meta, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
1136234848Smav	memcpy(meta->cdr, buf, GET32(meta, hdr->cd_length) * ss);
1137234848Smav	g_free(buf);
1138234848Smav	if (GET32(meta, cdr->Signature) != DDF_CONTROLLER_DATA_SIGNATURE)
1139234848Smav		goto hdrerror;
1140234848Smav
1141234848Smav	/* Read physical disk records. */
1142234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
1143234848Smav	    GET32(meta, hdr->pdr_length) * ss, &error);
1144234848Smav	if (buf == NULL)
1145234848Smav		goto readerror;
1146234848Smav	meta->pdr = malloc(GET32(meta, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
1147234848Smav	memcpy(meta->pdr, buf, GET32(meta, hdr->pdr_length) * ss);
1148234848Smav	g_free(buf);
1149234848Smav	if (GET32(meta, pdr->Signature) != DDF_PDR_SIGNATURE)
1150234848Smav		goto hdrerror;
1151234848Smav
1152234848Smav	/* Read virtual disk records. */
1153234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
1154234848Smav	    GET32(meta, hdr->vdr_length) * ss, &error);
1155234848Smav	if (buf == NULL)
1156234848Smav		goto readerror;
1157234848Smav	meta->vdr = malloc(GET32(meta, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
1158234848Smav	memcpy(meta->vdr, buf, GET32(meta, hdr->vdr_length) * ss);
1159234848Smav	g_free(buf);
1160234848Smav	if (GET32(meta, vdr->Signature) != DDF_VD_RECORD_SIGNATURE)
1161234848Smav		goto hdrerror;
1162234848Smav
1163234848Smav	/* Read configuration records. */
1164234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
1165234848Smav	    GET32(meta, hdr->cr_length) * ss, &error);
1166234848Smav	if (buf == NULL)
1167234848Smav		goto readerror;
1168234848Smav	meta->cr = malloc(GET32(meta, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
1169234848Smav	memcpy(meta->cr, buf, GET32(meta, hdr->cr_length) * ss);
1170234848Smav	g_free(buf);
1171234848Smav
1172234848Smav	/* Read physical disk data. */
1173234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
1174234848Smav	    GET32(meta, hdr->pdd_length) * ss, &error);
1175234848Smav	if (buf == NULL)
1176234848Smav		goto readerror;
1177234848Smav	meta->pdd = malloc(GET32(meta, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
1178234848Smav	memcpy(meta->pdd, buf, GET32(meta, hdr->pdd_length) * ss);
1179234848Smav	g_free(buf);
1180234848Smav	if (GET32(meta, pdd->Signature) != DDF_PDD_SIGNATURE)
1181234848Smav		goto hdrerror;
1182234848Smav	i = ddf_meta_find_pd(meta, NULL, GET32(meta, pdd->PD_Reference));
1183234848Smav	if (i < 0)
1184234848Smav		goto hdrerror;
1185234848Smav
1186234848Smav	/* Read BBM Log. */
1187234848Smav	if (GET32(meta, hdr->bbmlog_section) != 0xffffffff &&
1188234848Smav	    GET32(meta, hdr->bbmlog_length) != 0) {
1189234848Smav		buf = g_read_data(cp, (lba + GET32(meta, hdr->bbmlog_section)) * ss,
1190234848Smav		    GET32(meta, hdr->bbmlog_length) * ss, &error);
1191234848Smav		if (buf == NULL)
1192234848Smav			goto readerror;
1193234848Smav		meta->bbm = malloc(GET32(meta, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
1194234848Smav		memcpy(meta->bbm, buf, GET32(meta, hdr->bbmlog_length) * ss);
1195234848Smav		g_free(buf);
1196234848Smav		if (GET32(meta, bbm->Signature) != DDF_BBML_SIGNATURE)
1197234848Smav			goto hdrerror;
1198234848Smav	}
1199234848Smav
1200234848Smavdone:
1201234848Smav	free(abuf, M_MD_DDF);
1202234848Smav	if (error != 0)
1203234848Smav		ddf_meta_free(meta);
1204234848Smav	return (error);
1205234848Smav}
1206234848Smav
1207234848Smavstatic int
1208234848Smavddf_meta_write(struct g_consumer *cp, struct ddf_meta *meta)
1209234848Smav{
1210234848Smav	struct g_provider *pp;
1211234848Smav	struct ddf_vdc_record *vdc;
1212234848Smav	off_t alba, plba, slba, lba;
1213234848Smav	u_int ss, size;
1214234848Smav	int error, i, num;
1215234848Smav
1216234848Smav	pp = cp->provider;
1217234848Smav	ss = pp->sectorsize;
1218234848Smav	lba = alba = pp->mediasize / ss - 1;
1219234848Smav	plba = GET64(meta, hdr->Primary_Header_LBA);
1220234848Smav	slba = GET64(meta, hdr->Secondary_Header_LBA);
1221234848Smav
1222234848Smavnext:
1223234848Smav	SET8(meta, hdr->Header_Type, (lba == alba) ? DDF_HEADER_ANCHOR :
1224234848Smav	    (lba == plba) ? DDF_HEADER_PRIMARY : DDF_HEADER_SECONDARY);
1225234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1226234848Smav	SET32(meta, hdr->CRC, crc32(meta->hdr, ss));
1227234848Smav	error = g_write_data(cp, lba * ss, meta->hdr, ss);
1228234848Smav	if (error != 0) {
1229234848Smaverr:
1230234848Smav		G_RAID_DEBUG(1, "Cannot write metadata to %s (error=%d).",
1231234848Smav		    pp->name, error);
1232234848Smav		if (lba != alba)
1233234848Smav			goto done;
1234234848Smav	}
1235234848Smav	if (lba == alba) {
1236234848Smav		lba = plba;
1237234848Smav		goto next;
1238234848Smav	}
1239234848Smav
1240234848Smav	size = GET32(meta, hdr->cd_length) * ss;
1241234848Smav	SET32(meta, cdr->CRC, 0xffffffff);
1242234848Smav	SET32(meta, cdr->CRC, crc32(meta->cdr, size));
1243234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
1244234848Smav	    meta->cdr, size);
1245234848Smav	if (error != 0)
1246234848Smav		goto err;
1247234848Smav
1248234848Smav	size = GET32(meta, hdr->pdr_length) * ss;
1249234848Smav	SET32(meta, pdr->CRC, 0xffffffff);
1250234848Smav	SET32(meta, pdr->CRC, crc32(meta->pdr, size));
1251234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
1252234848Smav	    meta->pdr, size);
1253234848Smav	if (error != 0)
1254234848Smav		goto err;
1255234848Smav
1256234848Smav	size = GET32(meta, hdr->vdr_length) * ss;
1257234848Smav	SET32(meta, vdr->CRC, 0xffffffff);
1258234848Smav	SET32(meta, vdr->CRC, crc32(meta->vdr, size));
1259234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
1260234848Smav	    meta->vdr, size);
1261234848Smav	if (error != 0)
1262234848Smav		goto err;
1263234848Smav
1264234848Smav	size = GET16(meta, hdr->Configuration_Record_Length);
1265234848Smav	num = GET32(meta, hdr->cr_length) / size;
1266234848Smav	size *= ss;
1267234848Smav	for (i = 0; i < num; i++) {
1268234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)meta->cr + i * size);
1269234848Smav		SET32D(meta, vdc->CRC, 0xffffffff);
1270234848Smav		SET32D(meta, vdc->CRC, crc32(vdc, size));
1271234848Smav	}
1272234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
1273234848Smav	    meta->cr, size * num);
1274234848Smav	if (error != 0)
1275234848Smav		goto err;
1276234848Smav
1277234848Smav	size = GET32(meta, hdr->pdd_length) * ss;
1278234848Smav	SET32(meta, pdd->CRC, 0xffffffff);
1279234848Smav	SET32(meta, pdd->CRC, crc32(meta->pdd, size));
1280234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
1281234848Smav	    meta->pdd, size);
1282234848Smav	if (error != 0)
1283234848Smav		goto err;
1284234848Smav
1285234848Smav	if (GET32(meta, hdr->bbmlog_length) != 0) {
1286234848Smav		size = GET32(meta, hdr->bbmlog_length) * ss;
1287234848Smav		SET32(meta, bbm->CRC, 0xffffffff);
1288234848Smav		SET32(meta, bbm->CRC, crc32(meta->bbm, size));
1289234848Smav		error = g_write_data(cp,
1290234848Smav		    (lba + GET32(meta, hdr->bbmlog_section)) * ss,
1291234848Smav		    meta->bbm, size);
1292234848Smav		if (error != 0)
1293234848Smav			goto err;
1294234848Smav	}
1295234848Smav
1296234848Smavdone:
1297234848Smav	if (lba == plba && slba != -1) {
1298234848Smav		lba = slba;
1299234848Smav		goto next;
1300234848Smav	}
1301234848Smav
1302234848Smav	return (error);
1303234848Smav}
1304234848Smav
1305234848Smavstatic int
1306234848Smavddf_meta_erase(struct g_consumer *cp)
1307234848Smav{
1308234848Smav	struct g_provider *pp;
1309234848Smav	char *buf;
1310234848Smav	int error;
1311234848Smav
1312234848Smav	pp = cp->provider;
1313234848Smav	buf = malloc(pp->sectorsize, M_MD_DDF, M_WAITOK | M_ZERO);
1314234848Smav	error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1315234848Smav	    buf, pp->sectorsize);
1316234848Smav	if (error != 0) {
1317234848Smav		G_RAID_DEBUG(1, "Cannot erase metadata on %s (error=%d).",
1318234848Smav		    pp->name, error);
1319234848Smav	}
1320234848Smav	free(buf, M_MD_DDF);
1321234848Smav	return (error);
1322234848Smav}
1323234848Smav
1324234848Smav#if 0
1325234848Smavstatic int
1326234848Smavddf_meta_write_spare(struct g_consumer *cp)
1327234848Smav{
1328234848Smav	struct ddf_header *meta;
1329234848Smav	int error;
1330234848Smav
1331234848Smav	meta = malloc(sizeof(*meta), M_MD_DDF, M_WAITOK | M_ZERO);
1332234848Smav	memcpy(&meta->ddf_id[0], DDF_MAGIC, sizeof(DDF_MAGIC) - 1);
1333234848Smav	meta->dummy_0 = 0x00020000;
1334234848Smav	meta->integrity = DDF_I_VALID;
1335234848Smav	meta->disk.flags = DDF_F_SPARE | DDF_F_ONLINE | DDF_F_VALID;
1336234848Smav	meta->disk.number = 0xff;
1337234848Smav	arc4rand(&meta->disk.id, sizeof(meta->disk.id), 0);
1338234848Smav	meta->disk_sectors = cp->provider->mediasize / cp->provider->sectorsize;
1339234848Smav	meta->disk_sectors -= 131072;
1340234848Smav	meta->rebuild_lba = UINT32_MAX;
1341234848Smav	error = ddf_meta_write(cp, &meta, 1);
1342234848Smav	free(meta, M_MD_DDF);
1343234848Smav	return (error);
1344234848Smav}
1345234848Smav#endif
1346234848Smav
1347234848Smavstatic struct g_raid_volume *
1348234848Smavg_raid_md_ddf_get_volume(struct g_raid_softc *sc, uint8_t *GUID)
1349234848Smav{
1350234848Smav	struct g_raid_volume	*vol;
1351234848Smav	struct g_raid_md_ddf_pervolume *pv;
1352234848Smav
1353234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1354234848Smav		pv = vol->v_md_data;
1355234848Smav		if (memcmp(pv->pv_meta.vde->VD_GUID, GUID, 24) == 0)
1356234848Smav			break;
1357234848Smav	}
1358234848Smav	return (vol);
1359234848Smav}
1360234848Smav
1361234848Smavstatic struct g_raid_disk *
1362234848Smavg_raid_md_ddf_get_disk(struct g_raid_softc *sc, uint8_t *GUID, uint32_t id)
1363234848Smav{
1364234848Smav	struct g_raid_disk	*disk;
1365234848Smav	struct g_raid_md_ddf_perdisk *pd;
1366234848Smav	struct ddf_meta *meta;
1367234848Smav
1368234848Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1369234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1370234848Smav		meta = &pd->pd_meta;
1371234848Smav		if (GUID != NULL) {
1372234848Smav			if (memcmp(meta->pdd->PD_GUID, GUID, 24) == 0)
1373234848Smav				break;
1374234848Smav		} else {
1375234848Smav			if (GET32(meta, pdd->PD_Reference) == id)
1376234848Smav				break;
1377234848Smav		}
1378234848Smav	}
1379234848Smav	return (disk);
1380234848Smav}
1381234848Smav
1382234848Smavstatic int
1383234848Smavg_raid_md_ddf_purge_volumes(struct g_raid_softc *sc)
1384234848Smav{
1385234848Smav	struct g_raid_volume	*vol, *tvol;
1386234848Smav	struct g_raid_md_ddf_pervolume *pv;
1387234848Smav	int i, res;
1388234848Smav
1389234848Smav	res = 0;
1390234848Smav	TAILQ_FOREACH_SAFE(vol, &sc->sc_volumes, v_next, tvol) {
1391234848Smav		pv = vol->v_md_data;
1392234848Smav		if (vol->v_stopping)
1393234848Smav			continue;
1394234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1395234848Smav			if (vol->v_subdisks[i].sd_state != G_RAID_SUBDISK_S_NONE)
1396234848Smav				break;
1397234848Smav		}
1398234848Smav		if (i >= vol->v_disks_count) {
1399234848Smav			g_raid_destroy_volume(vol);
1400234848Smav			res = 1;
1401234848Smav		}
1402234848Smav	}
1403234848Smav	return (res);
1404234848Smav}
1405234848Smav
1406234848Smavstatic int
1407234848Smavg_raid_md_ddf_purge_disks(struct g_raid_softc *sc)
1408234848Smav{
1409234848Smav#if 0
1410234848Smav	struct g_raid_disk	*disk, *tdisk;
1411234848Smav	struct g_raid_volume	*vol;
1412234848Smav	struct g_raid_md_ddf_perdisk *pd;
1413234848Smav	int i, j, res;
1414234848Smav
1415234848Smav	res = 0;
1416234848Smav	TAILQ_FOREACH_SAFE(disk, &sc->sc_disks, d_next, tdisk) {
1417234848Smav		if (disk->d_state == G_RAID_DISK_S_SPARE)
1418234848Smav			continue;
1419234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1420234848Smav
1421234848Smav		/* Scan for deleted volumes. */
1422234848Smav		for (i = 0; i < pd->pd_subdisks; ) {
1423234848Smav			vol = g_raid_md_ddf_get_volume(sc,
1424234848Smav			    pd->pd_meta[i]->volume_id);
1425234848Smav			if (vol != NULL && !vol->v_stopping) {
1426234848Smav				i++;
1427234848Smav				continue;
1428234848Smav			}
1429234848Smav			free(pd->pd_meta[i], M_MD_DDF);
1430234848Smav			for (j = i; j < pd->pd_subdisks - 1; j++)
1431234848Smav				pd->pd_meta[j] = pd->pd_meta[j + 1];
1432234848Smav			pd->pd_meta[DDF_MAX_SUBDISKS - 1] = NULL;
1433234848Smav			pd->pd_subdisks--;
1434234848Smav			pd->pd_updated = 1;
1435234848Smav		}
1436234848Smav
1437234848Smav		/* If there is no metadata left - erase and delete disk. */
1438234848Smav		if (pd->pd_subdisks == 0) {
1439234848Smav			ddf_meta_erase(disk->d_consumer);
1440234848Smav			g_raid_destroy_disk(disk);
1441234848Smav			res = 1;
1442234848Smav		}
1443234848Smav	}
1444234848Smav	return (res);
1445234848Smav#endif
1446234848Smav	return (0);
1447234848Smav}
1448234848Smav
1449234848Smavstatic int
1450234848Smavg_raid_md_ddf_supported(int level, int qual, int disks, int force)
1451234848Smav{
1452234848Smav
1453234848Smav	if (disks > DDF_MAX_DISKS_HARD)
1454234848Smav		return (0);
1455234848Smav	switch (level) {
1456234848Smav	case G_RAID_VOLUME_RL_RAID0:
1457234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1458234848Smav			return (0);
1459234848Smav		if (disks < 1)
1460234848Smav			return (0);
1461234848Smav		if (!force && disks < 2)
1462234848Smav			return (0);
1463234848Smav		break;
1464234848Smav	case G_RAID_VOLUME_RL_RAID1:
1465234848Smav		if (disks < 1)
1466234848Smav			return (0);
1467234848Smav		if (qual == G_RAID_VOLUME_RLQ_R1SM) {
1468234848Smav			if (!force && disks != 2)
1469234848Smav				return (0);
1470234848Smav		} else if (qual == G_RAID_VOLUME_RLQ_R1MM) {
1471234848Smav			if (!force && disks != 3)
1472234848Smav				return (0);
1473234848Smav		} else
1474234848Smav			return (0);
1475234848Smav		break;
1476234848Smav	case G_RAID_VOLUME_RL_RAID3:
1477234848Smav		if (qual != G_RAID_VOLUME_RLQ_R3P0 &&
1478234848Smav		    qual != G_RAID_VOLUME_RLQ_R3PN)
1479234848Smav			return (0);
1480234848Smav		if (disks < 3)
1481234848Smav			return (0);
1482234848Smav		break;
1483234848Smav	case G_RAID_VOLUME_RL_RAID4:
1484234848Smav		if (qual != G_RAID_VOLUME_RLQ_R4P0 &&
1485234848Smav		    qual != G_RAID_VOLUME_RLQ_R4PN)
1486234848Smav			return (0);
1487234848Smav		if (disks < 3)
1488234848Smav			return (0);
1489234848Smav		break;
1490234848Smav	case G_RAID_VOLUME_RL_RAID5:
1491234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5RA &&
1492234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RS &&
1493234848Smav		    qual != G_RAID_VOLUME_RLQ_R5LA &&
1494234848Smav		    qual != G_RAID_VOLUME_RLQ_R5LS)
1495234848Smav			return (0);
1496234848Smav		if (disks < 3)
1497234848Smav			return (0);
1498234848Smav		break;
1499234848Smav	case G_RAID_VOLUME_RL_RAID6:
1500234848Smav		if (qual != G_RAID_VOLUME_RLQ_R6RA &&
1501234848Smav		    qual != G_RAID_VOLUME_RLQ_R6RS &&
1502234848Smav		    qual != G_RAID_VOLUME_RLQ_R6LA &&
1503234848Smav		    qual != G_RAID_VOLUME_RLQ_R6LS)
1504234848Smav			return (0);
1505234848Smav		if (disks < 4)
1506234848Smav			return (0);
1507234848Smav		break;
1508234848Smav	case G_RAID_VOLUME_RL_RAIDMDF:
1509234848Smav		if (qual != G_RAID_VOLUME_RLQ_RMDFRA &&
1510234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFRS &&
1511234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFLA &&
1512234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFLS)
1513234848Smav			return (0);
1514234848Smav		if (disks < 5)
1515234848Smav			return (0);
1516234848Smav		break;
1517234848Smav	case G_RAID_VOLUME_RL_RAID1E:
1518234848Smav		if (qual != G_RAID_VOLUME_RLQ_R1EA &&
1519234848Smav		    qual != G_RAID_VOLUME_RLQ_R1EO)
1520234848Smav			return (0);
1521234848Smav		if (disks < 2)
1522234848Smav			return (0);
1523234848Smav		if (disks % 2 != 0)
1524234848Smav			return (0);
1525234848Smav		break;
1526234848Smav	case G_RAID_VOLUME_RL_SINGLE:
1527234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1528234848Smav			return (0);
1529234848Smav		if (disks != 1)
1530234848Smav			return (0);
1531234848Smav		break;
1532234848Smav	case G_RAID_VOLUME_RL_CONCAT:
1533234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1534234848Smav			return (0);
1535234848Smav		if (disks < 2)
1536234848Smav			return (0);
1537234848Smav		break;
1538234848Smav	case G_RAID_VOLUME_RL_RAID5E:
1539234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5ERA &&
1540234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ERS &&
1541234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ELA &&
1542234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ELS)
1543234848Smav			return (0);
1544234848Smav		if (disks < 4)
1545234848Smav			return (0);
1546234848Smav		break;
1547234848Smav	case G_RAID_VOLUME_RL_RAID5EE:
1548234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5EERA &&
1549234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EERS &&
1550234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EELA &&
1551234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EELS)
1552234848Smav			return (0);
1553234848Smav		if (disks < 4)
1554234848Smav			return (0);
1555234848Smav		break;
1556234848Smav	case G_RAID_VOLUME_RL_RAID5R:
1557234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5RRA &&
1558234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RRS &&
1559234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RLA &&
1560234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RLS)
1561234848Smav			return (0);
1562234848Smav		if (disks < 3)
1563234848Smav			return (0);
1564234848Smav		break;
1565234848Smav	default:
1566234848Smav		return (0);
1567234848Smav	}
1568234848Smav	return (1);
1569234848Smav}
1570234848Smav
1571234848Smavstatic int
1572234848Smavg_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol)
1573234848Smav{
1574234848Smav	struct g_raid_softc *sc;
1575234848Smav	struct g_raid_subdisk *sd;
1576234848Smav	struct g_raid_md_ddf_perdisk *pd;
1577234848Smav	struct g_raid_md_ddf_pervolume *pv;
1578234848Smav	struct g_raid_md_ddf_object *mdi;
1579234848Smav	struct ddf_vol_meta *vmeta;
1580234848Smav	struct ddf_meta *pdmeta, *gmeta;
1581234848Smav	struct ddf_vdc_record *vdc1;
1582234848Smav	off_t size, eoff = 0, esize = 0;
1583234848Smav	uint64_t *val2;
1584234848Smav	int disk_pos, md_disk_bvd = -1, md_disk_pos = -1, md_pde_pos;
1585234848Smav	int i, resurrection = 0;
1586234848Smav	uint32_t reference;
1587234848Smav
1588234848Smav	sc = disk->d_softc;
1589234848Smav	mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
1590234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1591234848Smav	pdmeta = &pd->pd_meta;
1592234848Smav	reference = GET32(&pd->pd_meta, pdd->PD_Reference);
1593234848Smav
1594234848Smav	pv = vol->v_md_data;
1595234848Smav	vmeta = &pv->pv_meta;
1596234848Smav	gmeta = &mdi->mdio_meta;
1597234848Smav
1598234848Smav	/* Find disk position in metadata by it's reference. */
1599234848Smav	disk_pos = ddf_meta_find_disk(vmeta, reference,
1600234848Smav	    &md_disk_bvd, &md_disk_pos);
1601234848Smav	md_pde_pos = ddf_meta_find_pd(gmeta, NULL, reference);
1602234848Smav
1603234848Smav	if (disk_pos < 0) {
1604234848Smav		G_RAID_DEBUG1(1, sc, "Disk %s is not part of the volume %s",
1605234848Smav		    g_raid_get_diskname(disk), vol->v_name);
1606234848Smav
1607234848Smav		/* Failed stale disk is useless for us. */
1608234848Smav		if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) != 0) {
1609234848Smav			g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE_FAILED);
1610234848Smav			return (0);
1611234848Smav		}
1612234848Smav
1613234848Smav		/* If disk has some metadata for this volume - erase. */
1614234848Smav		if (pdmeta->cr != NULL &&
1615234848Smav		    (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) {
1616234848Smav			SET32D(pdmeta, vdc1->Signature, 0xffffffff);
1617234848Smav		}
1618234848Smav
1619234848Smav		/* If we are in the start process, that's all for now. */
1620234848Smav		if (!pv->pv_started)
1621234848Smav			goto nofit;
1622234848Smav		/*
1623234848Smav		 * If we have already started - try to get use of the disk.
1624234848Smav		 * Try to replace OFFLINE disks first, then FAILED.
1625234848Smav		 */
1626234848Smav		if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
1627234848Smav			GET16(&pd->pd_meta, hdr->Max_Partitions)) {
1628234848Smav			G_RAID_DEBUG1(1, sc, "No free partitions on disk %s",
1629234848Smav			    g_raid_get_diskname(disk));
1630234848Smav			goto nofit;
1631234848Smav		}
1632234848Smav		ddf_meta_unused_range(&pd->pd_meta, &eoff, &esize);
1633234848Smav		if (esize == 0) {
1634234848Smav			G_RAID_DEBUG1(1, sc, "No free space on disk %s",
1635234848Smav			    g_raid_get_diskname(disk));
1636234848Smav			goto nofit;
1637234848Smav		}
1638234848Smav		size = INT64_MAX;
1639234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1640234848Smav			sd = &vol->v_subdisks[i];
1641234848Smav			if (sd->sd_state != G_RAID_SUBDISK_S_NONE)
1642234848Smav				size = sd->sd_size;
1643234848Smav			if (sd->sd_state <= G_RAID_SUBDISK_S_FAILED &&
1644234848Smav			    (disk_pos < 0 ||
1645234848Smav			     vol->v_subdisks[i].sd_state < sd->sd_state))
1646234848Smav				disk_pos = i;
1647234848Smav		}
1648234848Smav		if (disk_pos >= 0 &&
1649234848Smav		    vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT &&
1650234848Smav		    (off_t)esize * 512 < size) {
1651234848Smav			G_RAID_DEBUG1(1, sc, "Disk %s free space "
1652234848Smav			    "is too small (%ju < %ju)",
1653234848Smav			    g_raid_get_diskname(disk),
1654234848Smav			    (off_t)esize * 512, size);
1655234848Smav			disk_pos = -1;
1656234848Smav		}
1657234848Smav		if (disk_pos >= 0) {
1658234848Smav			if (vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT)
1659234848Smav				esize = size / 512;
1660234848Smav			md_disk_bvd = disk_pos / GET16(vmeta, vdc->Primary_Element_Count); // XXX
1661234848Smav			md_disk_pos = disk_pos % GET16(vmeta, vdc->Primary_Element_Count); // XXX
1662234848Smav		} else {
1663234848Smavnofit:
1664234848Smav			if (ddf_meta_count_vdc(&pd->pd_meta, NULL) == 0) {
1665234848Smav				g_raid_change_disk_state(disk,
1666234848Smav				    G_RAID_DISK_S_SPARE);
1667234848Smav			}
1668234848Smav			return (0);
1669234848Smav		}
1670234848Smav		G_RAID_DEBUG1(1, sc, "Disk %s takes pos %d in the volume %s",
1671234848Smav		    g_raid_get_diskname(disk), disk_pos, vol->v_name);
1672234848Smav		resurrection = 1;
1673234848Smav	}
1674234848Smav
1675234848Smav	sd = &vol->v_subdisks[disk_pos];
1676234848Smav
1677234848Smav	if (resurrection && sd->sd_disk != NULL) {
1678234848Smav		g_raid_change_disk_state(sd->sd_disk,
1679234848Smav		    G_RAID_DISK_S_STALE_FAILED);
1680234848Smav		TAILQ_REMOVE(&sd->sd_disk->d_subdisks,
1681234848Smav		    sd, sd_next);
1682234848Smav	}
1683234848Smav	vol->v_subdisks[disk_pos].sd_disk = disk;
1684234848Smav	TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
1685234848Smav
1686234848Smav	/* Welcome the new disk. */
1687234848Smav	if (resurrection)
1688234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
1689234848Smav	else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA)
1690234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED);
1691234848Smav	else
1692234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
1693234848Smav
1694234848Smav	if (resurrection) {
1695234848Smav		sd->sd_offset = (off_t)eoff * 512;
1696234848Smav		sd->sd_size = (off_t)esize * 512;
1697234848Smav	} else if (pdmeta->cr != NULL &&
1698234848Smav	    (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) {
1699234848Smav		val2 = (uint64_t *)&(vdc1->Physical_Disk_Sequence[GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
1700234848Smav		sd->sd_offset = (off_t)GET64P(pdmeta, val2 + md_disk_pos) * 512;
1701234848Smav		sd->sd_size = (off_t)GET64D(pdmeta, vdc1->Block_Count) * 512;
1702234848Smav	}
1703234848Smav
1704234848Smav	if (resurrection) {
1705234848Smav		/* Stale disk, almost same as new. */
1706234848Smav		g_raid_change_subdisk_state(sd,
1707234848Smav		    G_RAID_SUBDISK_S_NEW);
1708234848Smav	} else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) {
1709234848Smav		/* Failed disk. */
1710234848Smav		g_raid_change_subdisk_state(sd,
1711234848Smav		    G_RAID_SUBDISK_S_FAILED);
1712234848Smav	} else if ((GET8(gmeta, pdr->entry[md_pde_pos].PD_State) &
1713234848Smav	     (DDF_PDE_FAILED | DDF_PDE_REBUILD)) != 0) {
1714234848Smav		/* Rebuilding disk. */
1715234848Smav		g_raid_change_subdisk_state(sd,
1716234848Smav		    G_RAID_SUBDISK_S_REBUILD);
1717234848Smav		sd->sd_rebuild_pos = 0;
1718234848Smav	} else if ((GET8(vmeta, vde->VD_State) & DDF_VDE_DIRTY) != 0 ||
1719234848Smav	    (GET8(vmeta, vde->Init_State) & DDF_VDE_INIT_MASK) !=
1720234848Smav	     DDF_VDE_INIT_FULL) {
1721234848Smav		/* Stale disk or dirty volume (unclean shutdown). */
1722234848Smav		g_raid_change_subdisk_state(sd,
1723234848Smav		    G_RAID_SUBDISK_S_STALE);
1724234848Smav	} else {
1725234848Smav		/* Up to date disk. */
1726234848Smav		g_raid_change_subdisk_state(sd,
1727234848Smav		    G_RAID_SUBDISK_S_ACTIVE);
1728234848Smav	}
1729234848Smav	g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
1730234848Smav	    G_RAID_EVENT_SUBDISK);
1731234848Smav
1732234848Smav	return (resurrection);
1733234848Smav}
1734234848Smav
1735234848Smavstatic void
1736234848Smavg_raid_md_ddf_refill(struct g_raid_softc *sc)
1737234848Smav{
1738234848Smav	struct g_raid_volume *vol;
1739234848Smav	struct g_raid_subdisk *sd;
1740234848Smav	struct g_raid_disk *disk;
1741234848Smav	struct g_raid_md_object *md;
1742234848Smav	struct g_raid_md_ddf_perdisk *pd;
1743234848Smav	struct g_raid_md_ddf_pervolume *pv;
1744234848Smav	int update, updated, i, bad;
1745234848Smav
1746234848Smav	md = sc->sc_md;
1747234848Smavrestart:
1748234848Smav	updated = 0;
1749234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1750234848Smav		pv = vol->v_md_data;
1751234848Smav		if (!pv->pv_started || vol->v_stopping)
1752234848Smav			continue;
1753234848Smav
1754234848Smav		/* Search for subdisk that needs replacement. */
1755234848Smav		bad = 0;
1756234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1757234848Smav			sd = &vol->v_subdisks[i];
1758234848Smav			if (sd->sd_state == G_RAID_SUBDISK_S_NONE ||
1759234848Smav			    sd->sd_state == G_RAID_SUBDISK_S_FAILED)
1760234848Smav			        bad = 1;
1761234848Smav		}
1762234848Smav		if (!bad)
1763234848Smav			continue;
1764234848Smav
1765234848Smav		G_RAID_DEBUG1(1, sc, "Volume %s is not complete, "
1766234848Smav		    "trying to refill.", vol->v_name);
1767234848Smav
1768234848Smav		TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1769234848Smav			/* Skip failed. */
1770234848Smav			if (disk->d_state < G_RAID_DISK_S_SPARE)
1771234848Smav				continue;
1772234848Smav			/* Skip already used by this volume. */
1773234848Smav			for (i = 0; i < vol->v_disks_count; i++) {
1774234848Smav				sd = &vol->v_subdisks[i];
1775234848Smav				if (sd->sd_disk == disk)
1776234848Smav					break;
1777234848Smav			}
1778234848Smav			if (i < vol->v_disks_count)
1779234848Smav				continue;
1780234848Smav
1781234848Smav			/* Try to use disk if it has empty extents. */
1782234848Smav			pd = disk->d_md_data;
1783234848Smav			if (ddf_meta_count_vdc(&pd->pd_meta, NULL) <
1784234848Smav			    GET16(&pd->pd_meta, hdr->Max_Partitions)) {
1785234848Smav				update = g_raid_md_ddf_start_disk(disk, vol);
1786234848Smav			} else
1787234848Smav				update = 0;
1788234848Smav			if (update) {
1789234848Smav				updated = 1;
1790234848Smav				g_raid_md_write_ddf(md, vol, NULL, disk);
1791234848Smav				break;
1792234848Smav			}
1793234848Smav		}
1794234848Smav	}
1795234848Smav	if (updated)
1796234848Smav		goto restart;
1797234848Smav}
1798234848Smav
1799234848Smavstatic void
1800234848Smavg_raid_md_ddf_start(struct g_raid_volume *vol)
1801234848Smav{
1802234848Smav	struct g_raid_softc *sc;
1803234848Smav	struct g_raid_subdisk *sd;
1804234848Smav	struct g_raid_disk *disk;
1805234848Smav	struct g_raid_md_object *md;
1806234848Smav	struct g_raid_md_ddf_pervolume *pv;
1807234868Smav	struct g_raid_md_ddf_object *mdi;
1808234848Smav	struct ddf_vol_meta *vmeta;
1809234848Smav	struct ddf_vdc_record *vdc;
1810234848Smav	uint64_t *val2;
1811234848Smav	int i, j, bvd;
1812234848Smav
1813234848Smav	sc = vol->v_softc;
1814234848Smav	md = sc->sc_md;
1815234868Smav	mdi = (struct g_raid_md_ddf_object *)md;
1816234848Smav	pv = vol->v_md_data;
1817234848Smav	vmeta = &pv->pv_meta;
1818234848Smav	vdc = vmeta->vdc;
1819234848Smav
1820234848Smav	vol->v_raid_level = GET8(vmeta, vdc->Primary_RAID_Level);
1821234848Smav	vol->v_raid_level_qualifier = GET8(vmeta, vdc->RLQ);
1822234848Smav	if (GET8(vmeta, vdc->Secondary_Element_Count) > 1 &&
1823234848Smav	    vol->v_raid_level == G_RAID_VOLUME_RL_RAID1 &&
1824234848Smav	    GET8(vmeta, vdc->Secondary_RAID_Level) == 0)
1825234848Smav		vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E;
1826234848Smav	vol->v_sectorsize = GET16(vmeta, vdc->Block_Size);
1827234848Smav	if (vol->v_sectorsize == 0xffff)
1828234848Smav		vol->v_sectorsize = vmeta->sectorsize;
1829234848Smav	vol->v_strip_size = vol->v_sectorsize << GET8(vmeta, vdc->Stripe_Size);
1830234848Smav	vol->v_disks_count = GET16(vmeta, vdc->Primary_Element_Count) *
1831234848Smav	    GET8(vmeta, vdc->Secondary_Element_Count);
1832234848Smav	vol->v_mediasize = GET64(vmeta, vdc->VD_Size) * vol->v_sectorsize;
1833234848Smav	for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) {
1834234848Smav		if (j == GET16(vmeta, vdc->Primary_Element_Count)) {
1835234848Smav			j = 0;
1836234848Smav			bvd++;
1837234848Smav		}
1838234848Smav		sd = &vol->v_subdisks[i];
1839234848Smav		if (vmeta->bvdc[bvd] == NULL) {
1840234848Smav			sd->sd_offset = 0;
1841234848Smav			sd->sd_size = GET64(vmeta, vdc->Block_Count) *
1842234848Smav			    vol->v_sectorsize;
1843234848Smav			continue;
1844234848Smav		}
1845234848Smav		val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
1846234848Smav		    GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
1847234848Smav		sd->sd_offset = GET64P(vmeta, val2 + j) * vol->v_sectorsize;
1848234848Smav		sd->sd_size = GET64(vmeta, bvdc[bvd]->Block_Count) *
1849234848Smav		    vol->v_sectorsize;
1850234848Smav	}
1851234848Smav	g_raid_start_volume(vol);
1852234848Smav
1853234848Smav	/* Make all disks found till the moment take their places. */
1854234848Smav	for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) {
1855234848Smav		if (j == GET16(vmeta, vdc->Primary_Element_Count)) {
1856234848Smav			j = 0;
1857234848Smav			bvd++;
1858234848Smav		}
1859234848Smav		if (vmeta->bvdc[bvd] == NULL)
1860234848Smav			continue;
1861234848Smav		disk = g_raid_md_ddf_get_disk(sc, NULL,
1862234848Smav		    GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[j]));
1863234848Smav		if (disk != NULL)
1864234848Smav			g_raid_md_ddf_start_disk(disk, vol);
1865234848Smav	}
1866234848Smav
1867234848Smav	pv->pv_started = 1;
1868234868Smav	mdi->mdio_starting--;
1869234848Smav	callout_stop(&pv->pv_start_co);
1870234848Smav	G_RAID_DEBUG1(0, sc, "Volume started.");
1871234848Smav	g_raid_md_write_ddf(md, vol, NULL, NULL);
1872234848Smav
1873234848Smav	/* Pickup any STALE/SPARE disks to refill array if needed. */
1874234848Smav	g_raid_md_ddf_refill(sc);
1875234848Smav
1876234848Smav	g_raid_event_send(vol, G_RAID_VOLUME_E_START, G_RAID_EVENT_VOLUME);
1877234848Smav}
1878234848Smav
1879234848Smavstatic void
1880234848Smavg_raid_ddf_go(void *arg)
1881234848Smav{
1882234848Smav	struct g_raid_volume *vol;
1883234848Smav	struct g_raid_softc *sc;
1884234848Smav	struct g_raid_md_ddf_pervolume *pv;
1885234848Smav
1886234848Smav	vol = arg;
1887234848Smav	pv = vol->v_md_data;
1888234848Smav	sc = vol->v_softc;
1889234848Smav	if (!pv->pv_started) {
1890234848Smav		G_RAID_DEBUG1(0, sc, "Force volume start due to timeout.");
1891234848Smav		g_raid_event_send(vol, G_RAID_VOLUME_E_STARTMD,
1892234848Smav		    G_RAID_EVENT_VOLUME);
1893234848Smav	}
1894234848Smav}
1895234848Smav
1896234848Smavstatic void
1897234848Smavg_raid_md_ddf_new_disk(struct g_raid_disk *disk)
1898234848Smav{
1899234848Smav	struct g_raid_softc *sc;
1900234848Smav	struct g_raid_md_object *md;
1901234848Smav	struct g_raid_md_ddf_perdisk *pd;
1902234848Smav	struct g_raid_md_ddf_pervolume *pv;
1903234848Smav	struct g_raid_md_ddf_object *mdi;
1904234848Smav	struct g_raid_volume *vol;
1905234848Smav	struct ddf_meta *pdmeta;
1906234848Smav	struct ddf_vol_meta *vmeta;
1907234848Smav	struct ddf_vdc_record *vdc;
1908234848Smav	struct ddf_vd_entry *vde;
1909234848Smav	int i, j, k, num, have, need, needthis, cnt, spare;
1910234848Smav	uint32_t val;
1911234848Smav	char buf[17];
1912234848Smav
1913234848Smav	sc = disk->d_softc;
1914234848Smav	md = sc->sc_md;
1915234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
1916234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1917234848Smav	pdmeta = &pd->pd_meta;
1918234848Smav	spare = -1;
1919234848Smav
1920234848Smav	if (mdi->mdio_meta.hdr == NULL)
1921234848Smav		ddf_meta_copy(&mdi->mdio_meta, pdmeta);
1922234848Smav	else
1923234848Smav		ddf_meta_update(&mdi->mdio_meta, pdmeta);
1924234848Smav
1925234848Smav	num = GET32(pdmeta, hdr->cr_length) / GET16(pdmeta, hdr->Configuration_Record_Length);
1926234848Smav	for (j = 0; j < num; j++) {
1927234848Smav		vdc = (struct ddf_vdc_record *)((uint8_t *)pdmeta->cr +
1928234848Smav		    j * GET16(pdmeta, hdr->Configuration_Record_Length) *
1929234848Smav		    pdmeta->sectorsize);
1930234848Smav		val = GET32D(pdmeta, vdc->Signature);
1931234848Smav
1932234848Smav		if (val == DDF_SA_SIGNATURE && spare == -1)
1933234848Smav			spare = 1;
1934234848Smav
1935234848Smav		if (val != DDF_VDCR_SIGNATURE)
1936234848Smav			continue;
1937234848Smav		spare = 0;
1938234848Smav		k = ddf_meta_find_vd(pdmeta, vdc->VD_GUID);
1939234848Smav		if (k < 0)
1940234848Smav			continue;
1941234848Smav		vde = &pdmeta->vdr->entry[k];
1942234848Smav
1943234848Smav		/* Look for volume with matching ID. */
1944234848Smav		vol = g_raid_md_ddf_get_volume(sc, vdc->VD_GUID);
1945234848Smav		if (vol == NULL) {
1946234848Smav			ddf_meta_get_name(pdmeta, k, buf);
1947234848Smav			vol = g_raid_create_volume(sc, buf,
1948234848Smav			    GET16D(pdmeta, vde->VD_Number));
1949234848Smav			pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
1950234848Smav			vol->v_md_data = pv;
1951234848Smav			callout_init(&pv->pv_start_co, 1);
1952234848Smav			callout_reset(&pv->pv_start_co,
1953234848Smav			    g_raid_start_timeout * hz,
1954234848Smav			    g_raid_ddf_go, vol);
1955234868Smav			mdi->mdio_starting++;
1956234848Smav		} else
1957234848Smav			pv = vol->v_md_data;
1958234848Smav
1959234848Smav		/* If we haven't started yet - check metadata freshness. */
1960234848Smav		vmeta = &pv->pv_meta;
1961234868Smav		ddf_vol_meta_update(vmeta, pdmeta, vdc->VD_GUID, pv->pv_started);
1962234848Smav	}
1963234848Smav
1964234848Smav	if (spare == 1) {
1965234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
1966234848Smav		g_raid_md_ddf_refill(sc);
1967234848Smav	}
1968234848Smav
1969234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1970234848Smav		pv = vol->v_md_data;
1971234848Smav		vmeta = &pv->pv_meta;
1972234848Smav
1973234848Smav		/* If we collected all needed disks - start array. */
1974234848Smav		need = 0;
1975234848Smav		needthis = 0;
1976234848Smav		have = 0;
1977234848Smav		for (k = 0; k < GET8(vmeta, vdc->Secondary_Element_Count); k++) {
1978234848Smav			if (vmeta->bvdc[k] == NULL) {
1979234848Smav				need += GET16(vmeta, vdc->Primary_Element_Count);
1980234848Smav				continue;
1981234848Smav			}
1982234848Smav			cnt = GET16(vmeta, bvdc[k]->Primary_Element_Count);
1983234848Smav			need += cnt;
1984234848Smav			for (i = 0; i < cnt; i++) {
1985234848Smav				val = GET32(vmeta, bvdc[k]->Physical_Disk_Sequence[i]);
1986234848Smav				if (GET32(pdmeta, pdd->PD_Reference) == val)
1987234848Smav					needthis++;
1988234848Smav				else if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL)
1989234848Smav					have++;
1990234848Smav			}
1991234848Smav		}
1992234848Smav		if (!needthis)
1993234848Smav			continue;
1994234848Smav		if (pv->pv_started) {
1995234848Smav			if (g_raid_md_ddf_start_disk(disk, vol))
1996234848Smav				g_raid_md_write_ddf(md, vol, NULL, NULL);
1997234848Smav		} else {
1998234848Smav			G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks",
1999234848Smav			    vol->v_name, have + needthis, need);
2000234848Smav			if (have + needthis == need)
2001234848Smav				g_raid_md_ddf_start(vol);
2002234848Smav		}
2003234848Smav	}
2004234848Smav}
2005234848Smav
2006234848Smavstatic int
2007234848Smavg_raid_md_create_ddf(struct g_raid_md_object *md, struct g_class *mp,
2008234848Smav    struct g_geom **gp)
2009234848Smav{
2010234848Smav	struct g_geom *geom;
2011234848Smav	struct g_raid_softc *sc;
2012234848Smav
2013234848Smav	/* Search for existing node. */
2014234848Smav	LIST_FOREACH(geom, &mp->geom, geom) {
2015234848Smav		sc = geom->softc;
2016234848Smav		if (sc == NULL)
2017234848Smav			continue;
2018234848Smav		if (sc->sc_stopping != 0)
2019234848Smav			continue;
2020234848Smav		if (sc->sc_md->mdo_class != md->mdo_class)
2021234848Smav			continue;
2022234848Smav		break;
2023234848Smav	}
2024234848Smav	if (geom != NULL) {
2025234848Smav		*gp = geom;
2026234848Smav		return (G_RAID_MD_TASTE_EXISTING);
2027234848Smav	}
2028234848Smav
2029234848Smav	/* Create new one if not found. */
2030234848Smav	sc = g_raid_create_node(mp, "DDF", md);
2031234848Smav	if (sc == NULL)
2032234848Smav		return (G_RAID_MD_TASTE_FAIL);
2033234848Smav	md->mdo_softc = sc;
2034234848Smav	*gp = sc->sc_geom;
2035234848Smav	return (G_RAID_MD_TASTE_NEW);
2036234848Smav}
2037234848Smav
2038234848Smavstatic int
2039234848Smavg_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
2040234848Smav                              struct g_consumer *cp, struct g_geom **gp)
2041234848Smav{
2042234848Smav	struct g_consumer *rcp;
2043234848Smav	struct g_provider *pp;
2044234848Smav	struct g_raid_softc *sc;
2045234848Smav	struct g_raid_disk *disk;
2046234848Smav	struct ddf_meta meta;
2047234848Smav	struct g_raid_md_ddf_perdisk *pd;
2048234848Smav	struct g_geom *geom;
2049234848Smav	int error, result, len;
2050234848Smav	char name[16];
2051234848Smav
2052234848Smav	G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name);
2053234848Smav	pp = cp->provider;
2054234848Smav
2055234848Smav	/* Read metadata from device. */
2056234848Smav	if (g_access(cp, 1, 0, 0) != 0)
2057234848Smav		return (G_RAID_MD_TASTE_FAIL);
2058234848Smav	g_topology_unlock();
2059234848Smav	bzero(&meta, sizeof(meta));
2060234848Smav	error = ddf_meta_read(cp, &meta);
2061234848Smav	g_topology_lock();
2062234848Smav	g_access(cp, -1, 0, 0);
2063234848Smav	if (error != 0)
2064234848Smav		return (G_RAID_MD_TASTE_FAIL);
2065234848Smav
2066234848Smav	/* Metadata valid. Print it. */
2067234848Smav	g_raid_md_ddf_print(&meta);
2068234848Smav
2069234848Smav	/* Search for matching node. */
2070234848Smav	sc = NULL;
2071234848Smav	LIST_FOREACH(geom, &mp->geom, geom) {
2072234848Smav		sc = geom->softc;
2073234848Smav		if (sc == NULL)
2074234848Smav			continue;
2075234848Smav		if (sc->sc_stopping != 0)
2076234848Smav			continue;
2077234848Smav		if (sc->sc_md->mdo_class != md->mdo_class)
2078234848Smav			continue;
2079234848Smav		break;
2080234848Smav	}
2081234848Smav
2082234848Smav	/* Found matching node. */
2083234848Smav	if (geom != NULL) {
2084234848Smav		G_RAID_DEBUG(1, "Found matching array %s", sc->sc_name);
2085234848Smav		result = G_RAID_MD_TASTE_EXISTING;
2086234848Smav
2087234848Smav	} else { /* Not found matching node -- create one. */
2088234848Smav		result = G_RAID_MD_TASTE_NEW;
2089234848Smav		snprintf(name, sizeof(name), "DDF");
2090234848Smav		sc = g_raid_create_node(mp, name, md);
2091234848Smav		md->mdo_softc = sc;
2092234848Smav		geom = sc->sc_geom;
2093234848Smav	}
2094234848Smav
2095234848Smav	rcp = g_new_consumer(geom);
2096234848Smav	g_attach(rcp, pp);
2097234848Smav	if (g_access(rcp, 1, 1, 1) != 0)
2098234848Smav		; //goto fail1;
2099234848Smav
2100234848Smav	g_topology_unlock();
2101234848Smav	sx_xlock(&sc->sc_lock);
2102234848Smav
2103234848Smav	pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2104234848Smav	pd->pd_meta = meta;
2105234848Smav	disk = g_raid_create_disk(sc);
2106234848Smav	disk->d_md_data = (void *)pd;
2107234848Smav	disk->d_consumer = rcp;
2108234848Smav	rcp->private = disk;
2109234848Smav
2110234848Smav	/* Read kernel dumping information. */
2111234848Smav	disk->d_kd.offset = 0;
2112234848Smav	disk->d_kd.length = OFF_MAX;
2113234848Smav	len = sizeof(disk->d_kd);
2114234848Smav	error = g_io_getattr("GEOM::kerneldump", rcp, &len, &disk->d_kd);
2115234848Smav	if (disk->d_kd.di.dumper == NULL)
2116234848Smav		G_RAID_DEBUG1(2, sc, "Dumping not supported by %s: %d.",
2117234848Smav		    rcp->provider->name, error);
2118234848Smav
2119234848Smav	g_raid_md_ddf_new_disk(disk);
2120234848Smav
2121234848Smav	sx_xunlock(&sc->sc_lock);
2122234848Smav	g_topology_lock();
2123234848Smav	*gp = geom;
2124234848Smav	return (result);
2125234848Smav}
2126234848Smav
2127234848Smavstatic int
2128234848Smavg_raid_md_event_ddf(struct g_raid_md_object *md,
2129234848Smav    struct g_raid_disk *disk, u_int event)
2130234848Smav{
2131234848Smav	struct g_raid_softc *sc;
2132234848Smav
2133234848Smav	sc = md->mdo_softc;
2134234848Smav	if (disk == NULL)
2135234848Smav		return (-1);
2136234848Smav	switch (event) {
2137234848Smav	case G_RAID_DISK_E_DISCONNECTED:
2138234848Smav		/* Delete disk. */
2139234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE);
2140234848Smav		g_raid_destroy_disk(disk);
2141234848Smav		g_raid_md_ddf_purge_volumes(sc);
2142234848Smav
2143234848Smav		/* Write updated metadata to all disks. */
2144234848Smav		g_raid_md_write_ddf(md, NULL, NULL, NULL);
2145234848Smav
2146234848Smav		/* Check if anything left. */
2147234848Smav		if (g_raid_ndisks(sc, -1) == 0)
2148234848Smav			g_raid_destroy_node(sc, 0);
2149234848Smav		else
2150234848Smav			g_raid_md_ddf_refill(sc);
2151234848Smav		return (0);
2152234848Smav	}
2153234848Smav	return (-2);
2154234848Smav}
2155234848Smav
2156234848Smavstatic int
2157234848Smavg_raid_md_volume_event_ddf(struct g_raid_md_object *md,
2158234848Smav    struct g_raid_volume *vol, u_int event)
2159234848Smav{
2160234848Smav	struct g_raid_md_ddf_pervolume *pv;
2161234848Smav
2162234848Smav	pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2163234848Smav	switch (event) {
2164234848Smav	case G_RAID_VOLUME_E_STARTMD:
2165234848Smav		if (!pv->pv_started)
2166234848Smav			g_raid_md_ddf_start(vol);
2167234848Smav		return (0);
2168234848Smav	}
2169234848Smav	return (-2);
2170234848Smav}
2171234848Smav
2172234848Smavstatic int
2173234848Smavg_raid_md_ctl_ddf(struct g_raid_md_object *md,
2174234848Smav    struct gctl_req *req)
2175234848Smav{
2176234848Smav	struct g_raid_softc *sc;
2177234848Smav	struct g_raid_volume *vol, *vol1;
2178234848Smav	struct g_raid_subdisk *sd;
2179234848Smav	struct g_raid_disk *disk, *disks[DDF_MAX_DISKS_HARD];
2180234848Smav	struct g_raid_md_ddf_perdisk *pd;
2181234848Smav	struct g_raid_md_ddf_pervolume *pv;
2182234848Smav	struct g_raid_md_ddf_object *mdi;
2183234848Smav	struct g_consumer *cp;
2184234848Smav	struct g_provider *pp;
2185234848Smav	char arg[16];
2186234848Smav	const char *verb, *volname, *levelname, *diskname;
2187234848Smav	char *tmp;
2188234848Smav	int *nargs, *force;
2189234848Smav	off_t size, sectorsize, strip, offs[DDF_MAX_DISKS_HARD], esize;
2190234848Smav	intmax_t *sizearg, *striparg;
2191234848Smav	int i, numdisks, len, level, qual;
2192234848Smav	int error;
2193234848Smav
2194234848Smav	sc = md->mdo_softc;
2195234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
2196234848Smav	verb = gctl_get_param(req, "verb", NULL);
2197234848Smav	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
2198234848Smav	error = 0;
2199234848Smav
2200234848Smav	if (strcmp(verb, "label") == 0) {
2201234848Smav
2202234848Smav		if (*nargs < 4) {
2203234848Smav			gctl_error(req, "Invalid number of arguments.");
2204234848Smav			return (-1);
2205234848Smav		}
2206234848Smav		volname = gctl_get_asciiparam(req, "arg1");
2207234848Smav		if (volname == NULL) {
2208234848Smav			gctl_error(req, "No volume name.");
2209234848Smav			return (-2);
2210234848Smav		}
2211234848Smav		levelname = gctl_get_asciiparam(req, "arg2");
2212234848Smav		if (levelname == NULL) {
2213234848Smav			gctl_error(req, "No RAID level.");
2214234848Smav			return (-3);
2215234848Smav		}
2216234848Smav		if (g_raid_volume_str2level(levelname, &level, &qual)) {
2217234848Smav			gctl_error(req, "Unknown RAID level '%s'.", levelname);
2218234848Smav			return (-4);
2219234848Smav		}
2220234848Smav		numdisks = *nargs - 3;
2221234848Smav		force = gctl_get_paraml(req, "force", sizeof(*force));
2222234848Smav		if (!g_raid_md_ddf_supported(level, qual, numdisks,
2223234848Smav		    force ? *force : 0)) {
2224234848Smav			gctl_error(req, "Unsupported RAID level "
2225234848Smav			    "(0x%02x/0x%02x), or number of disks (%d).",
2226234848Smav			    level, qual, numdisks);
2227234848Smav			return (-5);
2228234848Smav		}
2229234848Smav
2230234848Smav		/* Search for disks, connect them and probe. */
2231234848Smav		size = INT64_MAX;
2232234848Smav		sectorsize = 0;
2233234848Smav		bzero(disks, sizeof(disks));
2234234848Smav		bzero(offs, sizeof(offs));
2235234848Smav		for (i = 0; i < numdisks; i++) {
2236234848Smav			snprintf(arg, sizeof(arg), "arg%d", i + 3);
2237234848Smav			diskname = gctl_get_asciiparam(req, arg);
2238234848Smav			if (diskname == NULL) {
2239234848Smav				gctl_error(req, "No disk name (%s).", arg);
2240234848Smav				error = -6;
2241234848Smav				break;
2242234848Smav			}
2243234848Smav			if (strcmp(diskname, "NONE") == 0)
2244234848Smav				continue;
2245234848Smav
2246234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2247234848Smav				if (disk->d_consumer != NULL &&
2248234848Smav				    disk->d_consumer->provider != NULL &&
2249234848Smav				    strcmp(disk->d_consumer->provider->name,
2250234848Smav				     diskname) == 0)
2251234848Smav					break;
2252234848Smav			}
2253234848Smav			if (disk != NULL) {
2254234848Smav				if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
2255234848Smav					gctl_error(req, "Disk '%s' is in a "
2256234848Smav					    "wrong state (%s).", diskname,
2257234848Smav					    g_raid_disk_state2str(disk->d_state));
2258234848Smav					error = -7;
2259234848Smav					break;
2260234848Smav				}
2261234848Smav				pd = disk->d_md_data;
2262234848Smav				if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
2263234848Smav				    GET16(&pd->pd_meta, hdr->Max_Partitions)) {
2264234848Smav					gctl_error(req, "No free partitions "
2265234848Smav					    "on disk '%s'.",
2266234848Smav					    diskname);
2267234848Smav					error = -7;
2268234848Smav					break;
2269234848Smav				}
2270234848Smav				pp = disk->d_consumer->provider;
2271234848Smav				disks[i] = disk;
2272234848Smav				ddf_meta_unused_range(&pd->pd_meta,
2273234848Smav				    &offs[i], &esize);
2274234848Smav				size = MIN(size, (off_t)esize * pp->sectorsize);
2275234848Smav				sectorsize = MAX(sectorsize, pp->sectorsize);
2276234848Smav				continue;
2277234848Smav			}
2278234848Smav
2279234848Smav			g_topology_lock();
2280234848Smav			cp = g_raid_open_consumer(sc, diskname);
2281234848Smav			if (cp == NULL) {
2282234848Smav				gctl_error(req, "Can't open disk '%s'.",
2283234848Smav				    diskname);
2284234848Smav				g_topology_unlock();
2285234848Smav				error = -8;
2286234848Smav				break;
2287234848Smav			}
2288234848Smav			pp = cp->provider;
2289234848Smav			pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2290234848Smav			disk = g_raid_create_disk(sc);
2291234848Smav			disk->d_md_data = (void *)pd;
2292234848Smav			disk->d_consumer = cp;
2293234848Smav			disks[i] = disk;
2294234848Smav			cp->private = disk;
2295234848Smav			ddf_meta_create(disk, &mdi->mdio_meta);
2296234848Smav			if (mdi->mdio_meta.hdr == NULL)
2297234848Smav				ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
2298234848Smav			else
2299234848Smav				ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
2300234848Smav			g_topology_unlock();
2301234848Smav
2302234848Smav			/* Read kernel dumping information. */
2303234848Smav			disk->d_kd.offset = 0;
2304234848Smav			disk->d_kd.length = OFF_MAX;
2305234848Smav			len = sizeof(disk->d_kd);
2306234848Smav			g_io_getattr("GEOM::kerneldump", cp, &len, &disk->d_kd);
2307234848Smav			if (disk->d_kd.di.dumper == NULL)
2308234848Smav				G_RAID_DEBUG1(2, sc,
2309234848Smav				    "Dumping not supported by %s.",
2310234848Smav				    cp->provider->name);
2311234848Smav
2312234848Smav			/* Reserve some space for metadata. */
2313234848Smav			size = MIN(size, pp->mediasize - 131072llu * pp->sectorsize);
2314234848Smav			sectorsize = MAX(sectorsize, pp->sectorsize);
2315234848Smav		}
2316234848Smav		if (error != 0) {
2317234848Smav			for (i = 0; i < numdisks; i++) {
2318234848Smav				if (disks[i] != NULL &&
2319234848Smav				    disks[i]->d_state == G_RAID_DISK_S_NONE)
2320234848Smav					g_raid_destroy_disk(disks[i]);
2321234848Smav			}
2322234848Smav			return (error);
2323234848Smav		}
2324234848Smav
2325234848Smav		if (sectorsize <= 0) {
2326234848Smav			gctl_error(req, "Can't get sector size.");
2327234848Smav			return (-8);
2328234848Smav		}
2329234848Smav
2330234848Smav		/* Handle size argument. */
2331234848Smav		len = sizeof(*sizearg);
2332234848Smav		sizearg = gctl_get_param(req, "size", &len);
2333234848Smav		if (sizearg != NULL && len == sizeof(*sizearg) &&
2334234848Smav		    *sizearg > 0) {
2335234848Smav			if (*sizearg > size) {
2336234848Smav				gctl_error(req, "Size too big %lld > %lld.",
2337234848Smav				    (long long)*sizearg, (long long)size);
2338234848Smav				return (-9);
2339234848Smav			}
2340234848Smav			size = *sizearg;
2341234848Smav		}
2342234848Smav
2343234848Smav		/* Handle strip argument. */
2344234848Smav		strip = 131072;
2345234848Smav		len = sizeof(*striparg);
2346234848Smav		striparg = gctl_get_param(req, "strip", &len);
2347234848Smav		if (striparg != NULL && len == sizeof(*striparg) &&
2348234848Smav		    *striparg > 0) {
2349234848Smav			if (*striparg < sectorsize) {
2350234848Smav				gctl_error(req, "Strip size too small.");
2351234848Smav				return (-10);
2352234848Smav			}
2353234848Smav			if (*striparg % sectorsize != 0) {
2354234848Smav				gctl_error(req, "Incorrect strip size.");
2355234848Smav				return (-11);
2356234848Smav			}
2357234848Smav			strip = *striparg;
2358234848Smav		}
2359234848Smav
2360234848Smav		/* Round size down to strip or sector. */
2361234848Smav		if (level == G_RAID_VOLUME_RL_RAID1 ||
2362234848Smav		    level == G_RAID_VOLUME_RL_RAID3 ||
2363234848Smav		    level == G_RAID_VOLUME_RL_SINGLE ||
2364234848Smav		    level == G_RAID_VOLUME_RL_CONCAT)
2365234848Smav			size -= (size % sectorsize);
2366234848Smav		else if (level == G_RAID_VOLUME_RL_RAID1E &&
2367234848Smav		    (numdisks & 1) != 0)
2368234848Smav			size -= (size % (2 * strip));
2369234848Smav		else
2370234848Smav			size -= (size % strip);
2371234848Smav		if (size <= 0) {
2372234848Smav			gctl_error(req, "Size too small.");
2373234848Smav			return (-13);
2374234848Smav		}
2375234848Smav
2376234848Smav		/* We have all we need, create things: volume, ... */
2377234848Smav		pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
2378234848Smav		ddf_vol_meta_create(&pv->pv_meta, &mdi->mdio_meta);
2379234848Smav		pv->pv_started = 1;
2380234848Smav		vol = g_raid_create_volume(sc, volname, -1);
2381234848Smav		vol->v_md_data = pv;
2382234848Smav		vol->v_raid_level = level;
2383234848Smav		vol->v_raid_level_qualifier = qual;
2384234848Smav		vol->v_strip_size = strip;
2385234848Smav		vol->v_disks_count = numdisks;
2386234848Smav		if (level == G_RAID_VOLUME_RL_RAID0 ||
2387234848Smav		    level == G_RAID_VOLUME_RL_CONCAT ||
2388234848Smav		    level == G_RAID_VOLUME_RL_SINGLE)
2389234848Smav			vol->v_mediasize = size * numdisks;
2390234848Smav		else if (level == G_RAID_VOLUME_RL_RAID1)
2391234848Smav			vol->v_mediasize = size;
2392234848Smav		else if (level == G_RAID_VOLUME_RL_RAID3 ||
2393234848Smav		    level == G_RAID_VOLUME_RL_RAID4 ||
2394234848Smav		    level == G_RAID_VOLUME_RL_RAID5 ||
2395234848Smav		    level == G_RAID_VOLUME_RL_RAID5R)
2396234848Smav			vol->v_mediasize = size * (numdisks - 1);
2397234848Smav		else if (level == G_RAID_VOLUME_RL_RAID6 ||
2398234848Smav		    level == G_RAID_VOLUME_RL_RAID5E ||
2399234848Smav		    level == G_RAID_VOLUME_RL_RAID5EE)
2400234848Smav			vol->v_mediasize = size * (numdisks - 2);
2401234848Smav		else if (level == G_RAID_VOLUME_RL_RAIDMDF)
2402234848Smav			vol->v_mediasize = size * (numdisks - 3);
2403234848Smav		else { /* RAID1E */
2404234848Smav			vol->v_mediasize = ((size * numdisks) / strip / 2) *
2405234848Smav			    strip;
2406234848Smav		}
2407234848Smav		vol->v_sectorsize = sectorsize;
2408234848Smav		g_raid_start_volume(vol);
2409234848Smav
2410234848Smav		/* , and subdisks. */
2411234848Smav		for (i = 0; i < numdisks; i++) {
2412234848Smav			disk = disks[i];
2413234848Smav			sd = &vol->v_subdisks[i];
2414234848Smav			sd->sd_disk = disk;
2415234848Smav			sd->sd_offset = (off_t)offs[i] * 512;
2416234848Smav			sd->sd_size = size;
2417234848Smav			if (disk == NULL)
2418234848Smav				continue;
2419234848Smav			TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
2420234848Smav			g_raid_change_disk_state(disk,
2421234848Smav			    G_RAID_DISK_S_ACTIVE);
2422234848Smav			g_raid_change_subdisk_state(sd,
2423234848Smav			    G_RAID_SUBDISK_S_ACTIVE);
2424234848Smav			g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
2425234848Smav			    G_RAID_EVENT_SUBDISK);
2426234848Smav		}
2427234848Smav
2428234848Smav		/* Write metadata based on created entities. */
2429234848Smav		G_RAID_DEBUG1(0, sc, "Array started.");
2430234848Smav		g_raid_md_write_ddf(md, vol, NULL, NULL);
2431234848Smav
2432234848Smav		/* Pickup any STALE/SPARE disks to refill array if needed. */
2433234848Smav		g_raid_md_ddf_refill(sc);
2434234848Smav
2435234848Smav		g_raid_event_send(vol, G_RAID_VOLUME_E_START,
2436234848Smav		    G_RAID_EVENT_VOLUME);
2437234848Smav		return (0);
2438234848Smav	}
2439234848Smav	if (strcmp(verb, "add") == 0) {
2440234848Smav
2441234848Smav		gctl_error(req, "`add` command is not applicable, "
2442234848Smav		    "use `label` instead.");
2443234848Smav		return (-99);
2444234848Smav	}
2445234848Smav	if (strcmp(verb, "delete") == 0) {
2446234848Smav
2447234848Smav		/* Full node destruction. */
2448234848Smav		if (*nargs == 1) {
2449234848Smav			/* Check if some volume is still open. */
2450234848Smav			force = gctl_get_paraml(req, "force", sizeof(*force));
2451234848Smav			if (force != NULL && *force == 0 &&
2452234848Smav			    g_raid_nopens(sc) != 0) {
2453234848Smav				gctl_error(req, "Some volume is still open.");
2454234848Smav				return (-4);
2455234848Smav			}
2456234848Smav
2457234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2458234848Smav				if (disk->d_consumer)
2459234848Smav					ddf_meta_erase(disk->d_consumer);
2460234848Smav			}
2461234848Smav			g_raid_destroy_node(sc, 0);
2462234848Smav			return (0);
2463234848Smav		}
2464234848Smav
2465234848Smav		/* Destroy specified volume. If it was last - all node. */
2466234848Smav		if (*nargs != 2) {
2467234848Smav			gctl_error(req, "Invalid number of arguments.");
2468234848Smav			return (-1);
2469234848Smav		}
2470234848Smav		volname = gctl_get_asciiparam(req, "arg1");
2471234848Smav		if (volname == NULL) {
2472234848Smav			gctl_error(req, "No volume name.");
2473234848Smav			return (-2);
2474234848Smav		}
2475234848Smav
2476234848Smav		/* Search for volume. */
2477234848Smav		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2478234848Smav			if (strcmp(vol->v_name, volname) == 0)
2479234848Smav				break;
2480234848Smav		}
2481234848Smav		if (vol == NULL) {
2482234848Smav			i = strtol(volname, &tmp, 10);
2483234848Smav			if (verb != volname && tmp[0] == 0) {
2484234848Smav				TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2485234848Smav					if (vol->v_global_id == i)
2486234848Smav						break;
2487234848Smav				}
2488234848Smav			}
2489234848Smav		}
2490234848Smav		if (vol == NULL) {
2491234848Smav			gctl_error(req, "Volume '%s' not found.", volname);
2492234848Smav			return (-3);
2493234848Smav		}
2494234848Smav
2495234848Smav		/* Check if volume is still open. */
2496234848Smav		force = gctl_get_paraml(req, "force", sizeof(*force));
2497234848Smav		if (force != NULL && *force == 0 &&
2498234848Smav		    vol->v_provider_open != 0) {
2499234848Smav			gctl_error(req, "Volume is still open.");
2500234848Smav			return (-4);
2501234848Smav		}
2502234848Smav
2503234848Smav		/* Destroy volume and potentially node. */
2504234848Smav		i = 0;
2505234848Smav		TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next)
2506234848Smav			i++;
2507234848Smav		if (i >= 2) {
2508234848Smav			g_raid_destroy_volume(vol);
2509234848Smav			g_raid_md_ddf_purge_disks(sc);
2510234848Smav			g_raid_md_write_ddf(md, NULL, NULL, NULL);
2511234848Smav		} else {
2512234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2513234848Smav				if (disk->d_consumer)
2514234848Smav					ddf_meta_erase(disk->d_consumer);
2515234848Smav			}
2516234848Smav			g_raid_destroy_node(sc, 0);
2517234848Smav		}
2518234848Smav		return (0);
2519234848Smav	}
2520234848Smav	if (strcmp(verb, "remove") == 0 ||
2521234848Smav	    strcmp(verb, "fail") == 0) {
2522234848Smav		if (*nargs < 2) {
2523234848Smav			gctl_error(req, "Invalid number of arguments.");
2524234848Smav			return (-1);
2525234848Smav		}
2526234848Smav		for (i = 1; i < *nargs; i++) {
2527234848Smav			snprintf(arg, sizeof(arg), "arg%d", i);
2528234848Smav			diskname = gctl_get_asciiparam(req, arg);
2529234848Smav			if (diskname == NULL) {
2530234848Smav				gctl_error(req, "No disk name (%s).", arg);
2531234848Smav				error = -2;
2532234848Smav				break;
2533234848Smav			}
2534234848Smav			if (strncmp(diskname, "/dev/", 5) == 0)
2535234848Smav				diskname += 5;
2536234848Smav
2537234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2538234848Smav				if (disk->d_consumer != NULL &&
2539234848Smav				    disk->d_consumer->provider != NULL &&
2540234848Smav				    strcmp(disk->d_consumer->provider->name,
2541234848Smav				     diskname) == 0)
2542234848Smav					break;
2543234848Smav			}
2544234848Smav			if (disk == NULL) {
2545234848Smav				gctl_error(req, "Disk '%s' not found.",
2546234848Smav				    diskname);
2547234848Smav				error = -3;
2548234848Smav				break;
2549234848Smav			}
2550234848Smav
2551234848Smav			if (strcmp(verb, "fail") == 0) {
2552234848Smav				g_raid_md_fail_disk_ddf(md, NULL, disk);
2553234848Smav				continue;
2554234848Smav			}
2555234848Smav
2556234848Smav			/* Erase metadata on deleting disk and destroy it. */
2557234848Smav			ddf_meta_erase(disk->d_consumer);
2558234848Smav			g_raid_destroy_disk(disk);
2559234848Smav		}
2560234848Smav		g_raid_md_ddf_purge_volumes(sc);
2561234848Smav
2562234848Smav		/* Write updated metadata to remaining disks. */
2563234848Smav		g_raid_md_write_ddf(md, NULL, NULL, NULL);
2564234848Smav
2565234848Smav		/* Check if anything left. */
2566234848Smav		if (g_raid_ndisks(sc, -1) == 0)
2567234848Smav			g_raid_destroy_node(sc, 0);
2568234848Smav		else
2569234848Smav			g_raid_md_ddf_refill(sc);
2570234848Smav		return (error);
2571234848Smav	}
2572234848Smav	if (strcmp(verb, "insert") == 0) {
2573234848Smav		if (*nargs < 2) {
2574234848Smav			gctl_error(req, "Invalid number of arguments.");
2575234848Smav			return (-1);
2576234848Smav		}
2577234848Smav		for (i = 1; i < *nargs; i++) {
2578234848Smav			/* Get disk name. */
2579234848Smav			snprintf(arg, sizeof(arg), "arg%d", i);
2580234848Smav			diskname = gctl_get_asciiparam(req, arg);
2581234848Smav			if (diskname == NULL) {
2582234848Smav				gctl_error(req, "No disk name (%s).", arg);
2583234848Smav				error = -3;
2584234848Smav				break;
2585234848Smav			}
2586234848Smav
2587234848Smav			/* Try to find provider with specified name. */
2588234848Smav			g_topology_lock();
2589234848Smav			cp = g_raid_open_consumer(sc, diskname);
2590234848Smav			if (cp == NULL) {
2591234848Smav				gctl_error(req, "Can't open disk '%s'.",
2592234848Smav				    diskname);
2593234848Smav				g_topology_unlock();
2594234848Smav				error = -4;
2595234848Smav				break;
2596234848Smav			}
2597234848Smav			pp = cp->provider;
2598234848Smav			g_topology_unlock();
2599234848Smav
2600234848Smav			pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2601234848Smav
2602234848Smav			disk = g_raid_create_disk(sc);
2603234848Smav			disk->d_consumer = cp;
2604234848Smav			disk->d_md_data = (void *)pd;
2605234848Smav			cp->private = disk;
2606234848Smav
2607234848Smav			/* Read kernel dumping information. */
2608234848Smav			disk->d_kd.offset = 0;
2609234848Smav			disk->d_kd.length = OFF_MAX;
2610234848Smav			len = sizeof(disk->d_kd);
2611234848Smav			g_io_getattr("GEOM::kerneldump", cp, &len, &disk->d_kd);
2612234848Smav			if (disk->d_kd.di.dumper == NULL)
2613234848Smav				G_RAID_DEBUG1(2, sc,
2614234848Smav				    "Dumping not supported by %s.",
2615234848Smav				    cp->provider->name);
2616234848Smav
2617234848Smav			/* Welcome the "new" disk. */
2618234848Smav			g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
2619234848Smav			ddf_meta_create(disk, &mdi->mdio_meta);
2620234848Smav			if (mdi->mdio_meta.hdr == NULL)
2621234848Smav				ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
2622234848Smav			else
2623234848Smav				ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
2624234848Smav//			ddf_meta_write_spare(cp);
2625234848Smav			g_raid_md_ddf_refill(sc);
2626234848Smav		}
2627234848Smav		return (error);
2628234848Smav	}
2629234848Smav	return (-100);
2630234848Smav}
2631234848Smav
2632234848Smavstatic int
2633234848Smavg_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
2634234848Smav    struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
2635234848Smav{
2636234848Smav	struct g_raid_softc *sc;
2637234848Smav	struct g_raid_volume *vol;
2638234848Smav	struct g_raid_subdisk *sd;
2639234848Smav	struct g_raid_disk *disk;
2640234848Smav	struct g_raid_md_ddf_perdisk *pd;
2641234848Smav	struct g_raid_md_ddf_pervolume *pv;
2642234848Smav	struct g_raid_md_ddf_object *mdi;
2643234848Smav	struct ddf_meta *gmeta;
2644234848Smav	struct ddf_vol_meta *vmeta;
2645234848Smav	struct ddf_vdc_record *vdc;
2646234848Smav	uint64_t *val2;
2647234848Smav	int i, j, pos, bvd, size;
2648234848Smav
2649234848Smav	sc = md->mdo_softc;
2650234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
2651234848Smav	gmeta = &mdi->mdio_meta;
2652234848Smav
2653234848Smav	if (sc->sc_stopping == G_RAID_DESTROY_HARD)
2654234848Smav		return (0);
2655234848Smav
2656234868Smav	/*
2657234868Smav	 * Clear disk flags to let only really needed ones to be reset.
2658234868Smav	 * Do it only if there are no volumes in starting state now,
2659234868Smav	 * as they can update disk statuses yet and we may kill innocent.
2660234868Smav	 */
2661234868Smav	if (mdi->mdio_starting == 0) {
2662234868Smav		for (i = 0; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
2663234868Smav			if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
2664234848Smav				continue;
2665234868Smav			SET16(gmeta, pdr->entry[i].PD_Type,
2666234868Smav			    GET16(gmeta, pdr->entry[i].PD_Type) &
2667234868Smav			    ~DDF_PDE_PARTICIPATING);
2668234868Smav			if ((GET16(gmeta, pdr->entry[i].PD_State) &
2669234868Smav			    DDF_PDE_PFA) == 0)
2670234868Smav				SET16(gmeta, pdr->entry[i].PD_State, 0);
2671234848Smav		}
2672234868Smav	}
2673234848Smav
2674234868Smav	/* Generate/update new per-volume metadata. */
2675234868Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2676234848Smav		pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2677234868Smav		if (vol->v_stopping || !pv->pv_started)
2678234868Smav			continue;
2679234848Smav		vmeta = &pv->pv_meta;
2680234848Smav
2681234848Smav		SET32(vmeta, vdc->Sequence_Number,
2682234848Smav		    GET32(vmeta, vdc->Sequence_Number) + 1);
2683234848Smav		if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
2684234848Smav		    vol->v_disks_count % 2 == 0)
2685234848Smav			SET16(vmeta, vdc->Primary_Element_Count, 2);
2686234848Smav		else
2687234848Smav			SET16(vmeta, vdc->Primary_Element_Count,
2688234848Smav			    vol->v_disks_count);
2689234848Smav		SET8(vmeta, vdc->Stripe_Size,
2690234848Smav		    ffs(vol->v_strip_size / vol->v_sectorsize) - 1);
2691234848Smav		if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
2692234848Smav		    vol->v_disks_count % 2 == 0) {
2693234848Smav			SET8(vmeta, vdc->Primary_RAID_Level,
2694234848Smav			    DDF_VDCR_RAID1);
2695234848Smav			SET8(vmeta, vdc->RLQ, 0);
2696234848Smav			SET8(vmeta, vdc->Secondary_Element_Count,
2697234848Smav			    vol->v_disks_count / 2);
2698234848Smav			SET8(vmeta, vdc->Secondary_RAID_Level, 0);
2699234848Smav		} else {
2700234848Smav			SET8(vmeta, vdc->Primary_RAID_Level,
2701234848Smav			    vol->v_raid_level);
2702234848Smav			SET8(vmeta, vdc->RLQ,
2703234848Smav			    vol->v_raid_level_qualifier);
2704234848Smav			SET8(vmeta, vdc->Secondary_Element_Count, 1);
2705234848Smav			SET8(vmeta, vdc->Secondary_RAID_Level, 0);
2706234848Smav		}
2707234848Smav		SET8(vmeta, vdc->Secondary_Element_Seq, 0);
2708234848Smav		SET64(vmeta, vdc->Block_Count, 0);
2709234848Smav		SET64(vmeta, vdc->VD_Size, vol->v_mediasize / vol->v_sectorsize);
2710234848Smav		SET16(vmeta, vdc->Block_Size, vol->v_sectorsize);
2711234848Smav
2712234848Smav		SET16(vmeta, vde->VD_Number, vol->v_global_id);
2713234848Smav		if (vol->v_state <= G_RAID_VOLUME_S_BROKEN)
2714234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_FAILED);
2715234848Smav		else if (vol->v_state <= G_RAID_VOLUME_S_DEGRADED)
2716234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_DEGRADED);
2717234848Smav		else if (vol->v_state <= G_RAID_VOLUME_S_SUBOPTIMAL)
2718234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_PARTIAL);
2719234848Smav		else
2720234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_OPTIMAL);
2721234868Smav		if (vol->v_dirty ||
2722234868Smav		    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_STALE) > 0 ||
2723234868Smav		    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_RESYNC) > 0)
2724234848Smav			SET8(vmeta, vde->VD_State,
2725234848Smav			    GET8(vmeta, vde->VD_State) | DDF_VDE_DIRTY);
2726234848Smav		SET8(vmeta, vde->Init_State, DDF_VDE_INIT_FULL); // XXX
2727234848Smav		ddf_meta_put_name(vmeta, vol->v_name);
2728234848Smav
2729234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
2730234848Smav			sd = &vol->v_subdisks[i];
2731234848Smav			bvd = i / GET16(vmeta, vdc->Primary_Element_Count);
2732234848Smav			pos = i % GET16(vmeta, vdc->Primary_Element_Count);
2733234868Smav			disk = sd->sd_disk;
2734234868Smav			if (disk != NULL) {
2735234868Smav				pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2736234868Smav				if (vmeta->bvdc[bvd] == NULL) {
2737234868Smav					size = GET16(vmeta,
2738234868Smav					    hdr->Configuration_Record_Length) *
2739234868Smav					    vmeta->sectorsize;
2740234868Smav					vmeta->bvdc[bvd] = malloc(size,
2741234868Smav					    M_MD_DDF, M_WAITOK);
2742234868Smav					memset(vmeta->bvdc[bvd], 0xff, size);
2743234868Smav				}
2744234868Smav				memcpy(vmeta->bvdc[bvd], vmeta->vdc,
2745234868Smav				    sizeof(struct ddf_vdc_record));
2746234848Smav				SET8(vmeta, bvdc[bvd]->Secondary_Element_Seq, bvd);
2747234868Smav				SET64(vmeta, bvdc[bvd]->Block_Count,
2748234868Smav				    sd->sd_size / vol->v_sectorsize);
2749234868Smav				SET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos],
2750234868Smav				    GET32(&pd->pd_meta, pdd->PD_Reference));
2751234868Smav				val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
2752234868Smav				    GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
2753234868Smav				SET64P(vmeta, val2 + pos,
2754234868Smav				    sd->sd_offset / vol->v_sectorsize);
2755234848Smav			}
2756234868Smav			if (vmeta->bvdc[bvd] == NULL)
2757234868Smav				continue;
2758234848Smav
2759234848Smav			j = ddf_meta_find_pd(gmeta, NULL,
2760234868Smav			    GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]));
2761234848Smav			if (j < 0)
2762234848Smav				continue;
2763234848Smav			SET32(gmeta, pdr->entry[j].PD_Type,
2764234848Smav			    GET32(gmeta, pdr->entry[j].PD_Type) |
2765234848Smav			    DDF_PDE_PARTICIPATING);
2766234868Smav			if (sd->sd_state == G_RAID_SUBDISK_S_NONE)
2767234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2768234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2769234868Smav				    DDF_PDE_FAILED | DDF_PDE_MISSING);
2770234868Smav			else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED)
2771234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2772234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2773234868Smav				    DDF_PDE_FAILED | DDF_PDE_PFA);
2774234868Smav			else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD)
2775234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2776234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2777234848Smav				    DDF_PDE_FAILED);
2778234848Smav			else
2779234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2780234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2781234848Smav				    DDF_PDE_ONLINE);
2782234848Smav		}
2783234848Smav	}
2784234848Smav
2785234868Smav	/* Remove disks without "participating" flag (unused). */
2786234868Smav	for (i = 0, j = -1; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
2787234868Smav		if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
2788234868Smav			continue;
2789234868Smav		if (GET16(gmeta, pdr->entry[i].PD_Type) & DDF_PDE_PARTICIPATING)
2790234868Smav			j = i;
2791234868Smav		else
2792234868Smav			memset(&gmeta->pdr->entry[i], 0xff,
2793234868Smav			    sizeof(struct ddf_pd_entry));
2794234868Smav	}
2795234868Smav	SET16(gmeta, pdr->Populated_PDEs, j + 1);
2796234868Smav
2797234868Smav	/* Update per-disk metadata and write them. */
2798234848Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2799234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2800234848Smav		if (disk->d_state != G_RAID_DISK_S_ACTIVE)
2801234848Smav			continue;
2802234868Smav		/* Update PDR. */
2803234848Smav		memcpy(pd->pd_meta.pdr, gmeta->pdr,
2804234848Smav		    GET32(&pd->pd_meta, hdr->pdr_length) *
2805234848Smav		    pd->pd_meta.sectorsize);
2806234868Smav		/* Update VDR. */
2807234868Smav		SET16(&pd->pd_meta, vdr->Populated_VDEs, 0);
2808234868Smav		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2809234868Smav			if (vol->v_stopping)
2810234868Smav				continue;
2811234848Smav			pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2812234848Smav			i = ddf_meta_find_vd(&pd->pd_meta,
2813234848Smav			    pv->pv_meta.vde->VD_GUID);
2814234848Smav			if (i < 0)
2815234848Smav				i = ddf_meta_find_vd(&pd->pd_meta, NULL);
2816234848Smav			if (i >= 0)
2817234848Smav				memcpy(&pd->pd_meta.vdr->entry[i],
2818234848Smav				    pv->pv_meta.vde,
2819234848Smav				    sizeof(struct ddf_vd_entry));
2820234868Smav		}
2821234868Smav		/* Update VDC. */
2822234868Smav		TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
2823234868Smav			vol = sd->sd_volume;
2824234868Smav			if (vol->v_stopping)
2825234868Smav				continue;
2826234868Smav			pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2827234868Smav			vmeta = &pv->pv_meta;
2828234848Smav			vdc = ddf_meta_find_vdc(&pd->pd_meta,
2829234868Smav			    vmeta->vde->VD_GUID);
2830234848Smav			if (vdc == NULL)
2831234848Smav				vdc = ddf_meta_find_vdc(&pd->pd_meta, NULL);
2832234848Smav			if (vdc != NULL) {
2833234848Smav				bvd = sd->sd_pos / GET16(vmeta,
2834234848Smav				    vdc->Primary_Element_Count);
2835234868Smav				memcpy(vdc, vmeta->bvdc[bvd],
2836234848Smav				    GET16(&pd->pd_meta,
2837234848Smav				    hdr->Configuration_Record_Length) *
2838234848Smav				    pd->pd_meta.sectorsize);
2839234848Smav			}
2840234848Smav		}
2841234848Smav		G_RAID_DEBUG(1, "Writing DDF metadata to %s",
2842234848Smav		    g_raid_get_diskname(disk));
2843234848Smav		g_raid_md_ddf_print(&pd->pd_meta);
2844234848Smav		ddf_meta_write(disk->d_consumer, &pd->pd_meta);
2845234848Smav	}
2846234848Smav	return (0);
2847234848Smav}
2848234848Smav
2849234848Smavstatic int
2850234848Smavg_raid_md_fail_disk_ddf(struct g_raid_md_object *md,
2851234848Smav    struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
2852234848Smav{
2853234848Smav	struct g_raid_softc *sc;
2854234848Smav	struct g_raid_md_ddf_perdisk *pd;
2855234848Smav	struct g_raid_subdisk *sd;
2856234848Smav	int i;
2857234848Smav
2858234848Smav	sc = md->mdo_softc;
2859234848Smav	pd = (struct g_raid_md_ddf_perdisk *)tdisk->d_md_data;
2860234848Smav
2861234848Smav	/* We can't fail disk that is not a part of array now. */
2862234848Smav	if (tdisk->d_state != G_RAID_DISK_S_ACTIVE)
2863234848Smav		return (-1);
2864234848Smav
2865234848Smav	/*
2866234848Smav	 * Mark disk as failed in metadata and try to write that metadata
2867234848Smav	 * to the disk itself to prevent it's later resurrection as STALE.
2868234848Smav	 */
2869234848Smav	G_RAID_DEBUG(1, "Writing DDF metadata to %s",
2870234848Smav	    g_raid_get_diskname(tdisk));
2871234848Smav	i = ddf_meta_find_pd(&pd->pd_meta, NULL, GET32(&pd->pd_meta, pdd->PD_Reference));
2872234848Smav	SET16(&pd->pd_meta, pdr->entry[i].PD_State, DDF_PDE_FAILED | DDF_PDE_PFA);
2873234848Smav	if (tdisk->d_consumer != NULL)
2874234848Smav		ddf_meta_write(tdisk->d_consumer, &pd->pd_meta);
2875234848Smav
2876234848Smav	/* Change states. */
2877234848Smav	g_raid_change_disk_state(tdisk, G_RAID_DISK_S_FAILED);
2878234848Smav	TAILQ_FOREACH(sd, &tdisk->d_subdisks, sd_next) {
2879234848Smav		g_raid_change_subdisk_state(sd,
2880234848Smav		    G_RAID_SUBDISK_S_FAILED);
2881234848Smav		g_raid_event_send(sd, G_RAID_SUBDISK_E_FAILED,
2882234848Smav		    G_RAID_EVENT_SUBDISK);
2883234848Smav	}
2884234848Smav
2885234848Smav	/* Write updated metadata to remaining disks. */
2886234848Smav	g_raid_md_write_ddf(md, NULL, NULL, tdisk);
2887234848Smav
2888234848Smav	g_raid_md_ddf_refill(sc);
2889234848Smav	return (0);
2890234848Smav}
2891234848Smav
2892234848Smavstatic int
2893234848Smavg_raid_md_free_disk_ddf(struct g_raid_md_object *md,
2894234848Smav    struct g_raid_disk *disk)
2895234848Smav{
2896234848Smav	struct g_raid_md_ddf_perdisk *pd;
2897234848Smav
2898234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2899234848Smav	ddf_meta_free(&pd->pd_meta);
2900234848Smav	free(pd, M_MD_DDF);
2901234848Smav	disk->d_md_data = NULL;
2902234848Smav	return (0);
2903234848Smav}
2904234848Smav
2905234848Smavstatic int
2906234848Smavg_raid_md_free_volume_ddf(struct g_raid_md_object *md,
2907234848Smav    struct g_raid_volume *vol)
2908234848Smav{
2909234848Smav	struct g_raid_md_ddf_pervolume *pv;
2910234848Smav
2911234848Smav	pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2912234848Smav	ddf_vol_meta_free(&pv->pv_meta);
2913234848Smav	if (!pv->pv_started) {
2914234848Smav		pv->pv_started = 1;
2915234848Smav		callout_stop(&pv->pv_start_co);
2916234848Smav	}
2917234848Smav	return (0);
2918234848Smav}
2919234848Smav
2920234848Smavstatic int
2921234848Smavg_raid_md_free_ddf(struct g_raid_md_object *md)
2922234848Smav{
2923234848Smav	struct g_raid_md_ddf_object *mdi;
2924234848Smav
2925234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
2926234848Smav	if (!mdi->mdio_started) {
2927234848Smav		mdi->mdio_started = 0;
2928234848Smav		callout_stop(&mdi->mdio_start_co);
2929234848Smav		G_RAID_DEBUG1(1, md->mdo_softc,
2930234848Smav		    "root_mount_rel %p", mdi->mdio_rootmount);
2931234848Smav		root_mount_rel(mdi->mdio_rootmount);
2932234848Smav		mdi->mdio_rootmount = NULL;
2933234848Smav	}
2934234848Smav	ddf_meta_free(&mdi->mdio_meta);
2935234848Smav	return (0);
2936234848Smav}
2937234848Smav
2938234848SmavG_RAID_MD_DECLARE(g_raid_md_ddf);
2939