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