md_ddf.c revision 235076
1234848Smav/*-
2234848Smav * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
3234848Smav * All rights reserved.
4234848Smav *
5234848Smav * Redistribution and use in source and binary forms, with or without
6234848Smav * modification, are permitted provided that the following conditions
7234848Smav * are met:
8234848Smav * 1. Redistributions of source code must retain the above copyright
9234848Smav *    notice, this list of conditions and the following disclaimer.
10234848Smav * 2. Redistributions in binary form must reproduce the above copyright
11234848Smav *    notice, this list of conditions and the following disclaimer in the
12234848Smav *    documentation and/or other materials provided with the distribution.
13234848Smav *
14234848Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15234848Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16234848Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17234848Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18234848Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19234848Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20234848Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21234848Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22234848Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23234848Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24234848Smav * SUCH DAMAGE.
25234848Smav */
26234848Smav
27234848Smav#include <sys/cdefs.h>
28234848Smav__FBSDID("$FreeBSD: head/sys/geom/raid/md_ddf.c 235076 2012-05-06 11:32:36Z mav $");
29234848Smav
30234848Smav#include <sys/param.h>
31234848Smav#include <sys/bio.h>
32234848Smav#include <sys/endian.h>
33234848Smav#include <sys/kernel.h>
34234848Smav#include <sys/kobj.h>
35234848Smav#include <sys/limits.h>
36234848Smav#include <sys/lock.h>
37234848Smav#include <sys/malloc.h>
38234848Smav#include <sys/mutex.h>
39234848Smav#include <sys/systm.h>
40234848Smav#include <sys/time.h>
41234848Smav#include <sys/clock.h>
42234848Smav#include <geom/geom.h>
43234848Smav#include "geom/raid/g_raid.h"
44234848Smav#include "geom/raid/md_ddf.h"
45234848Smav#include "g_raid_md_if.h"
46234848Smav
47234848Smavstatic MALLOC_DEFINE(M_MD_DDF, "md_ddf_data", "GEOM_RAID DDF metadata");
48234848Smav
49234848Smav#define	DDF_MAX_DISKS_HARD	128
50234848Smav
51234848Smav#define	DDF_MAX_DISKS	16
52234848Smav#define	DDF_MAX_VDISKS	7
53234848Smav#define	DDF_MAX_PARTITIONS	1
54234848Smav
55234848Smav#define DECADE (3600*24*(365*10+2))	/* 10 years in seconds. */
56234848Smav
57234848Smavstruct ddf_meta {
58234848Smav	u_int	sectorsize;
59234848Smav	u_int	bigendian;
60234848Smav	struct ddf_header *hdr;
61234848Smav	struct ddf_cd_record *cdr;
62234848Smav	struct ddf_pd_record *pdr;
63234848Smav	struct ddf_vd_record *vdr;
64234848Smav	void *cr;
65234848Smav	struct ddf_pdd_record *pdd;
66234848Smav	struct ddf_bbm_log *bbm;
67234848Smav};
68234848Smav
69234848Smavstruct ddf_vol_meta {
70234848Smav	u_int	sectorsize;
71234848Smav	u_int	bigendian;
72234848Smav	struct ddf_header *hdr;
73234848Smav	struct ddf_cd_record *cdr;
74234848Smav	struct ddf_vd_entry *vde;
75234848Smav	struct ddf_vdc_record *vdc;
76234848Smav	struct ddf_vdc_record *bvdc[DDF_MAX_DISKS_HARD];
77234848Smav};
78234848Smav
79234848Smavstruct g_raid_md_ddf_perdisk {
80234848Smav	struct ddf_meta	 pd_meta;
81234848Smav};
82234848Smav
83234848Smavstruct g_raid_md_ddf_pervolume {
84234848Smav	struct ddf_vol_meta		 pv_meta;
85234848Smav	int				 pv_started;
86234848Smav	struct callout			 pv_start_co;	/* STARTING state timer. */
87234848Smav};
88234848Smav
89234848Smavstruct g_raid_md_ddf_object {
90234848Smav	struct g_raid_md_object	 mdio_base;
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),
128234848Smav	.mdc_priority = 100
129234848Smav};
130234848Smav
131234848Smav#define GET8(m, f)	((m)->f)
132234848Smav#define GET16(m, f)	((m)->bigendian ? be16dec(&(m)->f) : le16dec(&(m)->f))
133234848Smav#define GET32(m, f)	((m)->bigendian ? be32dec(&(m)->f) : le32dec(&(m)->f))
134234848Smav#define GET64(m, f)	((m)->bigendian ? be64dec(&(m)->f) : le64dec(&(m)->f))
135234848Smav#define GET8D(m, f)	(f)
136234848Smav#define GET16D(m, f)	((m)->bigendian ? be16dec(&f) : le16dec(&f))
137234848Smav#define GET32D(m, f)	((m)->bigendian ? be32dec(&f) : le32dec(&f))
138234848Smav#define GET64D(m, f)	((m)->bigendian ? be64dec(&f) : le64dec(&f))
139234848Smav#define GET8P(m, f)	(*(f))
140234848Smav#define GET16P(m, f)	((m)->bigendian ? be16dec(f) : le16dec(f))
141234848Smav#define GET32P(m, f)	((m)->bigendian ? be32dec(f) : le32dec(f))
142234848Smav#define GET64P(m, f)	((m)->bigendian ? be64dec(f) : le64dec(f))
143234848Smav
144234848Smav#define SET8P(m, f, v)							\
145234848Smav	(*(f) = (v))
146234848Smav#define SET16P(m, f, v)							\
147234848Smav	do {								\
148234848Smav		if ((m)->bigendian)					\
149234848Smav			be16enc((f), (v));				\
150234848Smav		else							\
151234848Smav			le16enc((f), (v));				\
152234848Smav	} while (0)
153234848Smav#define SET32P(m, f, v)							\
154234848Smav	do {								\
155234848Smav		if ((m)->bigendian)					\
156234848Smav			be32enc((f), (v));				\
157234848Smav		else							\
158234848Smav			le32enc((f), (v));				\
159234848Smav	} while (0)
160234848Smav#define SET64P(m, f, v)							\
161234848Smav	do {								\
162234848Smav		if ((m)->bigendian)					\
163234848Smav			be64enc((f), (v));				\
164234848Smav		else							\
165234848Smav			le64enc((f), (v));				\
166234848Smav	} while (0)
167234848Smav#define SET8(m, f, v)	SET8P((m), &((m)->f), (v))
168234848Smav#define SET16(m, f, v)	SET16P((m), &((m)->f), (v))
169234848Smav#define SET32(m, f, v)	SET32P((m), &((m)->f), (v))
170234848Smav#define SET64(m, f, v)	SET64P((m), &((m)->f), (v))
171234848Smav#define SET8D(m, f, v)	SET8P((m), &(f), (v))
172234848Smav#define SET16D(m, f, v)	SET16P((m), &(f), (v))
173234848Smav#define SET32D(m, f, v)	SET32P((m), &(f), (v))
174234848Smav#define SET64D(m, f, v)	SET64P((m), &(f), (v))
175234848Smav
176234869Smav#define GETCRNUM(m)	(GET32((m), hdr->cr_length) /			\
177234869Smav	GET16((m), hdr->Configuration_Record_Length))
178234869Smav
179234869Smav#define GETVDCPTR(m, n)	((struct ddf_vdc_record *)((uint8_t *)(m)->cr +	\
180234869Smav	(n) * GET16((m), hdr->Configuration_Record_Length) *		\
181234869Smav	(m)->sectorsize))
182234869Smav
183234899Smav#define GETSAPTR(m, n)	((struct ddf_sa_record *)((uint8_t *)(m)->cr +	\
184234899Smav	(n) * GET16((m), hdr->Configuration_Record_Length) *		\
185234899Smav	(m)->sectorsize))
186234899Smav
187234848Smavstatic int
188234848Smavisff(uint8_t *buf, int size)
189234848Smav{
190234848Smav	int i;
191234848Smav
192234848Smav	for (i = 0; i < size; i++)
193234848Smav		if (buf[i] != 0xff)
194234848Smav			return (0);
195234848Smav	return (1);
196234848Smav}
197234848Smav
198234848Smavstatic void
199234848Smavprint_guid(uint8_t *buf)
200234848Smav{
201234848Smav	int i, ascii;
202234848Smav
203234848Smav	ascii = 1;
204234848Smav	for (i = 0; i < 24; i++) {
205234848Smav		if (buf[i] != 0 && (buf[i] < ' ' || buf[i] > 127)) {
206234848Smav			ascii = 0;
207234848Smav			break;
208234848Smav		}
209234848Smav	}
210234848Smav	if (ascii) {
211234848Smav		printf("'%.24s'", buf);
212234848Smav	} else {
213234848Smav		for (i = 0; i < 24; i++)
214234848Smav			printf("%02x", buf[i]);
215234848Smav	}
216234848Smav}
217234848Smav
218234848Smavstatic void
219234848Smavg_raid_md_ddf_print(struct ddf_meta *meta)
220234848Smav{
221234848Smav	struct ddf_vdc_record *vdc;
222234848Smav	struct ddf_vuc_record *vuc;
223234848Smav	struct ddf_sa_record *sa;
224234848Smav	uint64_t *val2;
225234848Smav	uint32_t val;
226234848Smav	int i, j, k, num, num2;
227234848Smav
228234848Smav	if (g_raid_debug < 1)
229234848Smav		return;
230234848Smav
231234848Smav	printf("********* DDF Metadata *********\n");
232234848Smav	printf("**** Header ****\n");
233234848Smav	printf("DDF_Header_GUID      ");
234234848Smav	print_guid(meta->hdr->DDF_Header_GUID);
235234848Smav	printf("\n");
236234848Smav	printf("DDF_rev              %8.8s\n", (char *)&meta->hdr->DDF_rev[0]);
237234848Smav	printf("Sequence_Number      0x%08x\n", GET32(meta, hdr->Sequence_Number));
238234848Smav	printf("TimeStamp            0x%08x\n", GET32(meta, hdr->TimeStamp));
239234848Smav	printf("Open_Flag            0x%02x\n", GET16(meta, hdr->Open_Flag));
240234848Smav	printf("Foreign_Flag         0x%02x\n", GET16(meta, hdr->Foreign_Flag));
241234848Smav	printf("Diskgrouping         0x%02x\n", GET16(meta, hdr->Diskgrouping));
242234848Smav	printf("Primary_Header_LBA   %ju\n", GET64(meta, hdr->Primary_Header_LBA));
243234848Smav	printf("Secondary_Header_LBA %ju\n", GET64(meta, hdr->Secondary_Header_LBA));
244234848Smav	printf("WorkSpace_Length     %u\n", GET32(meta, hdr->WorkSpace_Length));
245234848Smav	printf("WorkSpace_LBA        %ju\n", GET64(meta, hdr->WorkSpace_LBA));
246234848Smav	printf("Max_PD_Entries       %u\n", GET16(meta, hdr->Max_PD_Entries));
247234848Smav	printf("Max_VD_Entries       %u\n", GET16(meta, hdr->Max_VD_Entries));
248234848Smav	printf("Max_Partitions       %u\n", GET16(meta, hdr->Max_Partitions));
249234848Smav	printf("Configuration_Record_Length %u\n", GET16(meta, hdr->Configuration_Record_Length));
250234848Smav	printf("Max_Primary_Element_Entries %u\n", GET16(meta, hdr->Max_Primary_Element_Entries));
251234848Smav	printf("Controller Data      %u:%u\n", GET32(meta, hdr->cd_section), GET32(meta, hdr->cd_length));
252234848Smav	printf("Physical Disk        %u:%u\n", GET32(meta, hdr->pdr_section), GET32(meta, hdr->pdr_length));
253234848Smav	printf("Virtual Disk         %u:%u\n", GET32(meta, hdr->vdr_section), GET32(meta, hdr->vdr_length));
254234848Smav	printf("Configuration Recs   %u:%u\n", GET32(meta, hdr->cr_section), GET32(meta, hdr->cr_length));
255234848Smav	printf("Physical Disk Recs   %u:%u\n", GET32(meta, hdr->pdd_section), GET32(meta, hdr->pdd_length));
256234848Smav	printf("BBM Log              %u:%u\n", GET32(meta, hdr->bbmlog_section), GET32(meta, hdr->bbmlog_length));
257234848Smav	printf("Diagnostic Space     %u:%u\n", GET32(meta, hdr->Diagnostic_Space), GET32(meta, hdr->Diagnostic_Space_Length));
258234848Smav	printf("Vendor_Specific_Logs %u:%u\n", GET32(meta, hdr->Vendor_Specific_Logs), GET32(meta, hdr->Vendor_Specific_Logs_Length));
259234848Smav	printf("**** Controler Data ****\n");
260234848Smav	printf("Controller_GUID      ");
261234848Smav	print_guid(meta->cdr->Controller_GUID);
262234848Smav	printf("\n");
263234848Smav	printf("Controller_Type      0x%04x%04x 0x%04x%04x\n",
264234848Smav	    GET16(meta, cdr->Controller_Type.Vendor_ID),
265234848Smav	    GET16(meta, cdr->Controller_Type.Device_ID),
266234848Smav	    GET16(meta, cdr->Controller_Type.SubVendor_ID),
267234848Smav	    GET16(meta, cdr->Controller_Type.SubDevice_ID));
268234848Smav	printf("Product_ID           '%.16s'\n", (char *)&meta->cdr->Product_ID[0]);
269234869Smav	printf("**** Physical Disk Records ****\n");
270234848Smav	printf("Populated_PDEs       %u\n", GET16(meta, pdr->Populated_PDEs));
271234848Smav	printf("Max_PDE_Supported    %u\n", GET16(meta, pdr->Max_PDE_Supported));
272234848Smav	for (j = 0; j < GET16(meta, pdr->Populated_PDEs); j++) {
273234848Smav		if (isff(meta->pdr->entry[j].PD_GUID, 24))
274234848Smav			continue;
275234848Smav		if (GET32(meta, pdr->entry[j].PD_Reference) == 0xffffffff)
276234848Smav			continue;
277234848Smav		printf("PD_GUID              ");
278234848Smav		print_guid(meta->pdr->entry[j].PD_GUID);
279234848Smav		printf("\n");
280234848Smav		printf("PD_Reference         0x%08x\n",
281234848Smav		    GET32(meta, pdr->entry[j].PD_Reference));
282234848Smav		printf("PD_Type              0x%04x\n",
283234848Smav		    GET16(meta, pdr->entry[j].PD_Type));
284234848Smav		printf("PD_State             0x%04x\n",
285234848Smav		    GET16(meta, pdr->entry[j].PD_State));
286234848Smav		printf("Configured_Size      %ju\n",
287234848Smav		    GET64(meta, pdr->entry[j].Configured_Size));
288234848Smav		printf("Block_Size           %u\n",
289234848Smav		    GET16(meta, pdr->entry[j].Block_Size));
290234848Smav	}
291234869Smav	printf("**** Virtual Disk Records ****\n");
292234848Smav	printf("Populated_VDEs       %u\n", GET16(meta, vdr->Populated_VDEs));
293234848Smav	printf("Max_VDE_Supported    %u\n", GET16(meta, vdr->Max_VDE_Supported));
294234848Smav	for (j = 0; j < GET16(meta, vdr->Populated_VDEs); j++) {
295234848Smav		if (isff(meta->vdr->entry[j].VD_GUID, 24))
296234848Smav			continue;
297234848Smav		printf("VD_GUID              ");
298234848Smav		print_guid(meta->vdr->entry[j].VD_GUID);
299234848Smav		printf("\n");
300234848Smav		printf("VD_Number            0x%04x\n",
301234848Smav		    GET16(meta, vdr->entry[j].VD_Number));
302234899Smav		printf("VD_Type              0x%04x\n",
303234899Smav		    GET16(meta, vdr->entry[j].VD_Type));
304234848Smav		printf("VD_State             0x%02x\n",
305234848Smav		    GET8(meta, vdr->entry[j].VD_State));
306234848Smav		printf("Init_State           0x%02x\n",
307234848Smav		    GET8(meta, vdr->entry[j].Init_State));
308234848Smav		printf("Drive_Failures_Remaining %u\n",
309234848Smav		    GET8(meta, vdr->entry[j].Drive_Failures_Remaining));
310234848Smav		printf("VD_Name              '%.16s'\n",
311234848Smav		    (char *)&meta->vdr->entry[j].VD_Name);
312234848Smav	}
313234848Smav	printf("**** Configuration Records ****\n");
314234869Smav	num = GETCRNUM(meta);
315234848Smav	for (j = 0; j < num; j++) {
316234869Smav		vdc = GETVDCPTR(meta, j);
317234848Smav		val = GET32D(meta, vdc->Signature);
318234848Smav		switch (val) {
319234848Smav		case DDF_VDCR_SIGNATURE:
320234848Smav			printf("** Virtual Disk Configuration **\n");
321234848Smav			printf("VD_GUID              ");
322234848Smav			print_guid(vdc->VD_GUID);
323234848Smav			printf("\n");
324234848Smav			printf("Timestamp            0x%08x\n",
325234848Smav			    GET32D(meta, vdc->Timestamp));
326234848Smav			printf("Sequence_Number      0x%08x\n",
327234848Smav			    GET32D(meta, vdc->Sequence_Number));
328234848Smav			printf("Primary_Element_Count %u\n",
329234848Smav			    GET16D(meta, vdc->Primary_Element_Count));
330234848Smav			printf("Stripe_Size          %u\n",
331234848Smav			    GET8D(meta, vdc->Stripe_Size));
332234848Smav			printf("Primary_RAID_Level   0x%02x\n",
333234848Smav			    GET8D(meta, vdc->Primary_RAID_Level));
334234848Smav			printf("RLQ                  0x%02x\n",
335234848Smav			    GET8D(meta, vdc->RLQ));
336234848Smav			printf("Secondary_Element_Count %u\n",
337234848Smav			    GET8D(meta, vdc->Secondary_Element_Count));
338234848Smav			printf("Secondary_Element_Seq %u\n",
339234848Smav			    GET8D(meta, vdc->Secondary_Element_Seq));
340234848Smav			printf("Secondary_RAID_Level 0x%02x\n",
341234848Smav			    GET8D(meta, vdc->Secondary_RAID_Level));
342234848Smav			printf("Block_Count          %ju\n",
343234848Smav			    GET64D(meta, vdc->Block_Count));
344234848Smav			printf("VD_Size              %ju\n",
345234848Smav			    GET64D(meta, vdc->VD_Size));
346234848Smav			printf("Block_Size           %u\n",
347234848Smav			    GET16D(meta, vdc->Block_Size));
348234848Smav			printf("Rotate_Parity_count  %u\n",
349234848Smav			    GET8D(meta, vdc->Rotate_Parity_count));
350234848Smav			printf("Associated_Spare_Disks");
351234848Smav			for (i = 0; i < 8; i++) {
352234848Smav				if (GET32D(meta, vdc->Associated_Spares[i]) != 0xffffffff)
353234848Smav					printf(" 0x%08x", GET32D(meta, vdc->Associated_Spares[i]));
354234848Smav			}
355234848Smav			printf("\n");
356234848Smav			printf("Cache_Flags          %016jx\n",
357234848Smav			    GET64D(meta, vdc->Cache_Flags));
358234848Smav			printf("BG_Rate              %u\n",
359234848Smav			    GET8D(meta, vdc->BG_Rate));
360234848Smav			printf("MDF_Parity_Disks     %u\n",
361234848Smav			    GET8D(meta, vdc->MDF_Parity_Disks));
362234848Smav			printf("MDF_Parity_Generator_Polynomial 0x%04x\n",
363234848Smav			    GET16D(meta, vdc->MDF_Parity_Generator_Polynomial));
364234848Smav			printf("MDF_Constant_Generation_Method 0x%02x\n",
365234848Smav			    GET8D(meta, vdc->MDF_Constant_Generation_Method));
366234848Smav			printf("Physical_Disks      ");
367234848Smav			num2 = GET16D(meta, vdc->Primary_Element_Count);
368234848Smav			val2 = (uint64_t *)&(vdc->Physical_Disk_Sequence[GET16(meta, hdr->Max_Primary_Element_Entries)]);
369234848Smav			for (i = 0; i < num2; i++)
370234848Smav				printf(" 0x%08x @ %ju",
371234848Smav				    GET32D(meta, vdc->Physical_Disk_Sequence[i]),
372234848Smav				    GET64P(meta, val2 + i));
373234848Smav			printf("\n");
374234848Smav			break;
375234848Smav		case DDF_VUCR_SIGNATURE:
376234848Smav			printf("** Vendor Unique Configuration **\n");
377234848Smav			vuc = (struct ddf_vuc_record *)vdc;
378234848Smav			printf("VD_GUID              ");
379234848Smav			print_guid(vuc->VD_GUID);
380234848Smav			printf("\n");
381234848Smav			break;
382234848Smav		case DDF_SA_SIGNATURE:
383234848Smav			printf("** Spare Assignment Configuration **\n");
384234848Smav			sa = (struct ddf_sa_record *)vdc;
385234848Smav			printf("Timestamp            0x%08x\n",
386234848Smav			    GET32D(meta, sa->Timestamp));
387234848Smav			printf("Spare_Type           0x%02x\n",
388234848Smav			    GET8D(meta, sa->Spare_Type));
389234848Smav			printf("Populated_SAEs       %u\n",
390234848Smav			    GET16D(meta, sa->Populated_SAEs));
391234848Smav			printf("MAX_SAE_Supported    %u\n",
392234848Smav			    GET16D(meta, sa->MAX_SAE_Supported));
393234848Smav			for (i = 0; i < GET16D(meta, sa->Populated_SAEs); i++) {
394234848Smav				if (isff(sa->entry[i].VD_GUID, 24))
395234848Smav					continue;
396234848Smav				printf("VD_GUID             ");
397234848Smav				for (k = 0; k < 24; k++)
398234848Smav					printf("%02x", sa->entry[i].VD_GUID[k]);
399234848Smav				printf("\n");
400234848Smav				printf("Secondary_Element   %u\n",
401234848Smav				    GET16D(meta, sa->entry[i].Secondary_Element));
402234848Smav			}
403234848Smav			break;
404234899Smav		case 0x00000000:
405234848Smav		case 0xFFFFFFFF:
406234848Smav			break;
407234848Smav		default:
408234848Smav			printf("Unknown configuration signature %08x\n", val);
409234848Smav			break;
410234848Smav		}
411234848Smav	}
412234848Smav	printf("**** Physical Disk Data ****\n");
413234848Smav	printf("PD_GUID              ");
414234848Smav	print_guid(meta->pdd->PD_GUID);
415234848Smav	printf("\n");
416234848Smav	printf("PD_Reference         0x%08x\n",
417234848Smav	    GET32(meta, pdd->PD_Reference));
418234848Smav	printf("Forced_Ref_Flag      0x%02x\n",
419234848Smav	    GET8(meta, pdd->Forced_Ref_Flag));
420234848Smav	printf("Forced_PD_GUID_Flag  0x%02x\n",
421234848Smav	    GET8(meta, pdd->Forced_PD_GUID_Flag));
422234848Smav}
423234848Smav
424234848Smavstatic int
425234848Smavddf_meta_find_pd(struct ddf_meta *meta, uint8_t *GUID, uint32_t PD_Reference)
426234848Smav{
427234848Smav	int i;
428234848Smav
429234848Smav	for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
430234848Smav		if (GUID != NULL) {
431234848Smav			if (memcmp(meta->pdr->entry[i].PD_GUID, GUID, 24) == 0)
432234848Smav				return (i);
433234848Smav		} else if (PD_Reference != 0xffffffff) {
434234848Smav			if (GET32(meta, pdr->entry[i].PD_Reference) == PD_Reference)
435234848Smav				return (i);
436234848Smav		} else
437234848Smav			if (isff(meta->pdr->entry[i].PD_GUID, 24))
438234848Smav				return (i);
439234848Smav	}
440234848Smav	if (GUID == NULL && PD_Reference == 0xffffffff) {
441234848Smav		if (i >= GET16(meta, pdr->Max_PDE_Supported))
442234848Smav			return (-1);
443234848Smav		SET16(meta, pdr->Populated_PDEs, i + 1);
444234848Smav		return (i);
445234848Smav	}
446234848Smav	return (-1);
447234848Smav}
448234848Smav
449234848Smavstatic int
450234848Smavddf_meta_find_vd(struct ddf_meta *meta, uint8_t *GUID)
451234848Smav{
452234848Smav	int i;
453234848Smav
454234848Smav	for (i = 0; i < GET16(meta, vdr->Populated_VDEs); i++) {
455234848Smav		if (GUID != NULL) {
456234848Smav			if (memcmp(meta->vdr->entry[i].VD_GUID, GUID, 24) == 0)
457234848Smav				return (i);
458234848Smav		} else
459234848Smav			if (isff(meta->vdr->entry[i].VD_GUID, 24))
460234848Smav				return (i);
461234848Smav	}
462234848Smav	if (GUID == NULL) {
463234848Smav		if (i >= GET16(meta, vdr->Max_VDE_Supported))
464234848Smav			return (-1);
465234848Smav		SET16(meta, vdr->Populated_VDEs, i + 1);
466234848Smav		return (i);
467234848Smav	}
468234848Smav	return (-1);
469234848Smav}
470234848Smav
471234848Smavstatic struct ddf_vdc_record *
472234848Smavddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID)
473234848Smav{
474234848Smav	struct ddf_vdc_record *vdc;
475234848Smav	int i, num;
476234848Smav
477234869Smav	num = GETCRNUM(meta);
478234848Smav	for (i = 0; i < num; i++) {
479234869Smav		vdc = GETVDCPTR(meta, i);
480234848Smav		if (GUID != NULL) {
481234848Smav			if (GET32D(meta, vdc->Signature) == DDF_VDCR_SIGNATURE &&
482234848Smav			    memcmp(vdc->VD_GUID, GUID, 24) == 0)
483234848Smav				return (vdc);
484234848Smav		} else
485234899Smav			if (GET32D(meta, vdc->Signature) == 0xffffffff ||
486234899Smav			    GET32D(meta, vdc->Signature) == 0)
487234848Smav				return (vdc);
488234848Smav	}
489234848Smav	return (NULL);
490234848Smav}
491234848Smav
492234848Smavstatic int
493234848Smavddf_meta_count_vdc(struct ddf_meta *meta, uint8_t *GUID)
494234848Smav{
495234848Smav	struct ddf_vdc_record *vdc;
496234848Smav	int i, num, cnt;
497234848Smav
498234848Smav	cnt = 0;
499234869Smav	num = GETCRNUM(meta);
500234848Smav	for (i = 0; i < num; i++) {
501234869Smav		vdc = GETVDCPTR(meta, i);
502234848Smav		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
503234848Smav			continue;
504234848Smav		if (GUID == NULL || memcmp(vdc->VD_GUID, GUID, 24) == 0)
505234848Smav			cnt++;
506234848Smav	}
507234848Smav	return (cnt);
508234848Smav}
509234848Smav
510234848Smavstatic int
511234848Smavddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference,
512234848Smav    int *bvdp, int *posp)
513234848Smav{
514234848Smav	int i, bvd, pos;
515234848Smav
516234848Smav	i = 0;
517234848Smav	for (bvd = 0; bvd < GET16(vmeta, vdc->Secondary_Element_Count); bvd++) {
518234848Smav		if (vmeta->bvdc[bvd] == NULL) {
519234848Smav			i += GET16(vmeta, vdc->Primary_Element_Count); // XXX
520234848Smav			continue;
521234848Smav		}
522234848Smav		for (pos = 0; pos < GET16(vmeta, bvdc[bvd]->Primary_Element_Count);
523234848Smav		    pos++, i++) {
524234848Smav			if (GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]) ==
525234848Smav			    PD_Reference) {
526234848Smav				if (bvdp != NULL)
527234848Smav					*bvdp = bvd;
528234848Smav				if (posp != NULL)
529234848Smav					*posp = pos;
530234848Smav				return (i);
531234848Smav			}
532234848Smav		}
533234848Smav	}
534234848Smav	return (-1);
535234848Smav}
536234848Smav
537234899Smavstatic struct ddf_sa_record *
538234899Smavddf_meta_find_sa(struct ddf_meta *meta, int create)
539234899Smav{
540234899Smav	struct ddf_sa_record *sa;
541234899Smav	int i, num;
542234899Smav
543234899Smav	num = GETCRNUM(meta);
544234899Smav	for (i = 0; i < num; i++) {
545234899Smav		sa = GETSAPTR(meta, i);
546234899Smav		if (GET32D(meta, sa->Signature) == DDF_SA_SIGNATURE)
547234899Smav			return (sa);
548234899Smav	}
549234899Smav	if (create) {
550234899Smav		for (i = 0; i < num; i++) {
551234899Smav			sa = GETSAPTR(meta, i);
552234899Smav			if (GET32D(meta, sa->Signature) == 0xffffffff ||
553234899Smav			    GET32D(meta, sa->Signature) == 0)
554234899Smav				return (sa);
555234899Smav		}
556234899Smav	}
557234899Smav	return (NULL);
558234899Smav}
559234899Smav
560234848Smavstatic void
561234848Smavddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
562234848Smav{
563234848Smav	struct timespec ts;
564234848Smav	struct clocktime ct;
565234848Smav	struct g_raid_md_ddf_perdisk *pd;
566234940Smav	struct g_raid_md_ddf_object *mdi;
567234848Smav	struct ddf_meta *meta;
568234848Smav	struct ddf_pd_entry *pde;
569234848Smav	off_t anchorlba;
570234848Smav	u_int ss, pos, size;
571234848Smav	int len, error;
572234848Smav	char serial_buffer[24];
573234848Smav
574234848Smav	if (sample->hdr == NULL)
575234848Smav		sample = NULL;
576234848Smav
577234940Smav	mdi = (struct g_raid_md_ddf_object *)disk->d_softc->sc_md;
578234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
579234848Smav	meta = &pd->pd_meta;
580234848Smav	ss = disk->d_consumer->provider->sectorsize;
581234848Smav	anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
582234848Smav
583234848Smav	meta->sectorsize = ss;
584234940Smav	meta->bigendian = sample ? sample->bigendian : mdi->mdio_bigendian;
585234848Smav	getnanotime(&ts);
586234848Smav	clock_ts_to_ct(&ts, &ct);
587234848Smav
588234848Smav	/* Header */
589234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
590234848Smav	memset(meta->hdr, 0xff, ss);
591234848Smav	if (sample) {
592234848Smav		memcpy(meta->hdr, sample->hdr, sizeof(struct ddf_header));
593234848Smav		if (ss != sample->sectorsize) {
594234848Smav			SET32(meta, hdr->WorkSpace_Length,
595234848Smav			    (GET32(sample, hdr->WorkSpace_Length) *
596234848Smav			    sample->sectorsize + ss - 1) / ss);
597234848Smav			SET16(meta, hdr->Configuration_Record_Length,
598234848Smav			    (GET16(sample, hdr->Configuration_Record_Length) *
599234848Smav			    sample->sectorsize + ss - 1) / ss);
600234848Smav			SET32(meta, hdr->cd_length,
601234848Smav			    (GET32(sample, hdr->cd_length) *
602234848Smav			    sample->sectorsize + ss - 1) / ss);
603234848Smav			SET32(meta, hdr->pdr_length,
604234848Smav			    (GET32(sample, hdr->pdr_length) *
605234848Smav			    sample->sectorsize + ss - 1) / ss);
606234848Smav			SET32(meta, hdr->vdr_length,
607234848Smav			    (GET32(sample, hdr->vdr_length) *
608234848Smav			    sample->sectorsize + ss - 1) / ss);
609234848Smav			SET32(meta, hdr->cr_length,
610234848Smav			    (GET32(sample, hdr->cr_length) *
611234848Smav			    sample->sectorsize + ss - 1) / ss);
612234848Smav			SET32(meta, hdr->pdd_length,
613234848Smav			    (GET32(sample, hdr->pdd_length) *
614234848Smav			    sample->sectorsize + ss - 1) / ss);
615234848Smav			SET32(meta, hdr->bbmlog_length,
616234848Smav			    (GET32(sample, hdr->bbmlog_length) *
617234848Smav			    sample->sectorsize + ss - 1) / ss);
618234848Smav			SET32(meta, hdr->Diagnostic_Space,
619234848Smav			    (GET32(sample, hdr->bbmlog_length) *
620234848Smav			    sample->sectorsize + ss - 1) / ss);
621234848Smav			SET32(meta, hdr->Vendor_Specific_Logs,
622234848Smav			    (GET32(sample, hdr->bbmlog_length) *
623234848Smav			    sample->sectorsize + ss - 1) / ss);
624234848Smav		}
625234848Smav	} else {
626234848Smav		SET32(meta, hdr->Signature, DDF_HEADER_SIGNATURE);
627234848Smav		snprintf(meta->hdr->DDF_Header_GUID, 25, "FreeBSD %08x%08x",
628234848Smav		    (u_int)(ts.tv_sec - DECADE), arc4random());
629234848Smav		memcpy(meta->hdr->DDF_rev, "02.00.00", 8);
630234848Smav		SET32(meta, hdr->TimeStamp, (ts.tv_sec - DECADE));
631234848Smav		SET32(meta, hdr->WorkSpace_Length, 16 * 1024 * 1024 / ss);
632234848Smav		SET16(meta, hdr->Max_PD_Entries, DDF_MAX_DISKS - 1);
633234848Smav		SET16(meta, hdr->Max_VD_Entries, DDF_MAX_VDISKS);
634234848Smav		SET16(meta, hdr->Max_Partitions, DDF_MAX_PARTITIONS);
635234848Smav		SET16(meta, hdr->Max_Primary_Element_Entries, DDF_MAX_DISKS);
636234848Smav		SET16(meta, hdr->Configuration_Record_Length,
637234848Smav		    (sizeof(struct ddf_vdc_record) +
638234848Smav		     (4 + 8) * GET16(meta, hdr->Max_Primary_Element_Entries) +
639234848Smav		     ss - 1) / ss);
640234848Smav		SET32(meta, hdr->cd_length,
641234848Smav		    (sizeof(struct ddf_cd_record) + ss - 1) / ss);
642234848Smav		SET32(meta, hdr->pdr_length,
643234848Smav		    (sizeof(struct ddf_pd_record) +
644234848Smav		     sizeof(struct ddf_pd_entry) *
645234848Smav		     GET16(meta, hdr->Max_PD_Entries) + ss - 1) / ss);
646234848Smav		SET32(meta, hdr->vdr_length,
647234848Smav		    (sizeof(struct ddf_vd_record) +
648234848Smav		     sizeof(struct ddf_vd_entry) *
649234848Smav		     GET16(meta, hdr->Max_VD_Entries) + ss - 1) / ss);
650234848Smav		SET32(meta, hdr->cr_length,
651234848Smav		    GET16(meta, hdr->Configuration_Record_Length) *
652234848Smav		    (GET16(meta, hdr->Max_Partitions) + 1));
653234848Smav		SET32(meta, hdr->pdd_length,
654234848Smav		    (sizeof(struct ddf_pdd_record) + ss - 1) / ss);
655234848Smav		SET32(meta, hdr->bbmlog_length, 0);
656234848Smav		SET32(meta, hdr->Diagnostic_Space_Length, 0);
657234848Smav		SET32(meta, hdr->Vendor_Specific_Logs_Length, 0);
658234848Smav	}
659234848Smav	pos = 1;
660234848Smav	SET32(meta, hdr->cd_section, pos);
661234848Smav	pos += GET32(meta, hdr->cd_length);
662234848Smav	SET32(meta, hdr->pdr_section, pos);
663234848Smav	pos += GET32(meta, hdr->pdr_length);
664234848Smav	SET32(meta, hdr->vdr_section, pos);
665234848Smav	pos += GET32(meta, hdr->vdr_length);
666234848Smav	SET32(meta, hdr->cr_section, pos);
667234848Smav	pos += GET32(meta, hdr->cr_length);
668234848Smav	SET32(meta, hdr->pdd_section, pos);
669234848Smav	pos += GET32(meta, hdr->pdd_length);
670234848Smav	SET32(meta, hdr->bbmlog_section,
671234848Smav	    GET32(meta, hdr->bbmlog_length) != 0 ? pos : 0xffffffff);
672234848Smav	pos += GET32(meta, hdr->bbmlog_length);
673234848Smav	SET32(meta, hdr->Diagnostic_Space,
674234848Smav	    GET32(meta, hdr->Diagnostic_Space_Length) != 0 ? pos : 0xffffffff);
675234848Smav	pos += GET32(meta, hdr->Diagnostic_Space_Length);
676234848Smav	SET32(meta, hdr->Vendor_Specific_Logs,
677234848Smav	    GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff);
678234899Smav	pos += min(GET32(meta, hdr->Vendor_Specific_Logs_Length), 1);
679234848Smav	SET64(meta, hdr->Primary_Header_LBA,
680234899Smav	    anchorlba - pos);
681234848Smav	SET64(meta, hdr->Secondary_Header_LBA,
682234848Smav	    0xffffffffffffffffULL);
683234848Smav	SET64(meta, hdr->WorkSpace_LBA,
684234848Smav	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
685234848Smav
686234848Smav	/* Controller Data */
687234848Smav	size = GET32(meta, hdr->cd_length) * ss;
688234848Smav	meta->cdr = malloc(size, M_MD_DDF, M_WAITOK);
689234848Smav	memset(meta->cdr, 0xff, size);
690234848Smav	SET32(meta, cdr->Signature, DDF_CONTROLLER_DATA_SIGNATURE);
691234848Smav	memcpy(meta->cdr->Controller_GUID, "FreeBSD GEOM RAID SERIAL", 24);
692234848Smav	memcpy(meta->cdr->Product_ID, "FreeBSD GEOMRAID", 16);
693234848Smav
694234848Smav	/* Physical Drive Records. */
695234848Smav	size = GET32(meta, hdr->pdr_length) * ss;
696234848Smav	meta->pdr = malloc(size, M_MD_DDF, M_WAITOK);
697234848Smav	memset(meta->pdr, 0xff, size);
698234848Smav	SET32(meta, pdr->Signature, DDF_PDR_SIGNATURE);
699234848Smav	SET16(meta, pdr->Populated_PDEs, 1);
700234848Smav	SET16(meta, pdr->Max_PDE_Supported,
701234848Smav	    GET16(meta, hdr->Max_PD_Entries));
702234848Smav
703234848Smav	pde = &meta->pdr->entry[0];
704234848Smav	len = sizeof(serial_buffer);
705234848Smav	error = g_io_getattr("GEOM::ident", disk->d_consumer, &len, serial_buffer);
706234848Smav	if (error == 0 && (len = strlen (serial_buffer)) >= 6 && len <= 20)
707234848Smav		snprintf(pde->PD_GUID, 25, "DISK%20s", serial_buffer);
708234848Smav	else
709234848Smav		snprintf(pde->PD_GUID, 25, "DISK%04d%02d%02d%08x%04x",
710234848Smav		    ct.year, ct.mon, ct.day,
711234848Smav		    arc4random(), arc4random() & 0xffff);
712234848Smav	SET32D(meta, pde->PD_Reference, arc4random());
713234848Smav	SET16D(meta, pde->PD_Type, DDF_PDE_GUID_FORCE);
714234848Smav	SET16D(meta, pde->PD_State, 0);
715234848Smav	SET64D(meta, pde->Configured_Size,
716234848Smav	    anchorlba + 1 - 32 * 1024 * 1024 / ss);
717234848Smav	SET16D(meta, pde->Block_Size, ss);
718234848Smav
719234848Smav	/* Virtual Drive Records. */
720234848Smav	size = GET32(meta, hdr->vdr_length) * ss;
721234848Smav	meta->vdr = malloc(size, M_MD_DDF, M_WAITOK);
722234848Smav	memset(meta->vdr, 0xff, size);
723234848Smav	SET32(meta, vdr->Signature, DDF_VD_RECORD_SIGNATURE);
724234848Smav	SET32(meta, vdr->Populated_VDEs, 0);
725234848Smav	SET16(meta, vdr->Max_VDE_Supported,
726234848Smav	    GET16(meta, hdr->Max_VD_Entries));
727234848Smav
728234848Smav	/* Configuration Records. */
729234848Smav	size = GET32(meta, hdr->cr_length) * ss;
730234848Smav	meta->cr = malloc(size, M_MD_DDF, M_WAITOK);
731234848Smav	memset(meta->cr, 0xff, size);
732234848Smav
733234848Smav	/* Physical Disk Data. */
734234848Smav	size = GET32(meta, hdr->pdd_length) * ss;
735234848Smav	meta->pdd = malloc(size, M_MD_DDF, M_WAITOK);
736234848Smav	memset(meta->pdd, 0xff, size);
737234848Smav	SET32(meta, pdd->Signature, DDF_PDD_SIGNATURE);
738234848Smav	memcpy(meta->pdd->PD_GUID, pde->PD_GUID, 24);
739234848Smav	SET32(meta, pdd->PD_Reference, GET32D(meta, pde->PD_Reference));
740234848Smav	SET8(meta, pdd->Forced_Ref_Flag, DDF_PDD_FORCED_REF);
741234848Smav	SET8(meta, pdd->Forced_PD_GUID_Flag, DDF_PDD_FORCED_GUID);
742234848Smav
743234848Smav	/* Bad Block Management Log. */
744234848Smav	if (GET32(meta, hdr->bbmlog_length) != 0) {
745234848Smav		size = GET32(meta, hdr->bbmlog_length) * ss;
746234848Smav		meta->bbm = malloc(size, M_MD_DDF, M_WAITOK);
747234848Smav		memset(meta->bbm, 0xff, size);
748234848Smav		SET32(meta, bbm->Signature, DDF_BBML_SIGNATURE);
749234848Smav		SET32(meta, bbm->Entry_Count, 0);
750234848Smav		SET32(meta, bbm->Spare_Block_Count, 0);
751234848Smav	}
752234848Smav}
753234848Smav
754234848Smavstatic void
755234848Smavddf_meta_copy(struct ddf_meta *dst, struct ddf_meta *src)
756234848Smav{
757234848Smav	struct ddf_header *hdr;
758234848Smav	u_int ss;
759234848Smav
760234848Smav	hdr = src->hdr;
761234848Smav	dst->bigendian = src->bigendian;
762234848Smav	ss = dst->sectorsize = src->sectorsize;
763234848Smav	dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
764234848Smav	memcpy(dst->hdr, src->hdr, ss);
765234848Smav	dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
766234848Smav	memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
767234848Smav	dst->pdr = malloc(GET32(src, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
768234848Smav	memcpy(dst->pdr, src->pdr, GET32(src, hdr->pdr_length) * ss);
769234848Smav	dst->vdr = malloc(GET32(src, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
770234848Smav	memcpy(dst->vdr, src->vdr, GET32(src, hdr->vdr_length) * ss);
771234848Smav	dst->cr = malloc(GET32(src, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
772234848Smav	memcpy(dst->cr, src->cr, GET32(src, hdr->cr_length) * ss);
773234848Smav	dst->pdd = malloc(GET32(src, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
774234848Smav	memcpy(dst->pdd, src->pdd, GET32(src, hdr->pdd_length) * ss);
775234848Smav	if (src->bbm != NULL) {
776234848Smav		dst->bbm = malloc(GET32(src, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
777234848Smav		memcpy(dst->bbm, src->bbm, GET32(src, hdr->bbmlog_length) * ss);
778234848Smav	}
779234848Smav}
780234848Smav
781234848Smavstatic void
782234848Smavddf_meta_update(struct ddf_meta *meta, struct ddf_meta *src)
783234848Smav{
784234848Smav	struct ddf_pd_entry *pde, *spde;
785234848Smav	int i, j;
786234848Smav
787234848Smav	for (i = 0; i < GET16(src, pdr->Populated_PDEs); i++) {
788234848Smav		spde = &src->pdr->entry[i];
789234848Smav		if (isff(spde->PD_GUID, 24))
790234848Smav			continue;
791234848Smav		j = ddf_meta_find_pd(meta, NULL,
792234994Smav		    GET32(src, pdr->entry[i].PD_Reference));
793234848Smav		if (j < 0) {
794234848Smav			j = ddf_meta_find_pd(meta, NULL, 0xffffffff);
795234848Smav			pde = &meta->pdr->entry[j];
796234848Smav			memcpy(pde, spde, sizeof(*pde));
797234848Smav		} else {
798234848Smav			pde = &meta->pdr->entry[j];
799234848Smav			SET16D(meta, pde->PD_State,
800234848Smav			    GET16D(meta, pde->PD_State) |
801234848Smav			    GET16D(src, pde->PD_State));
802234848Smav		}
803234848Smav	}
804234848Smav}
805234848Smav
806234848Smavstatic void
807234848Smavddf_meta_free(struct ddf_meta *meta)
808234848Smav{
809234848Smav
810234848Smav	if (meta->hdr != NULL) {
811234848Smav		free(meta->hdr, M_MD_DDF);
812234848Smav		meta->hdr = NULL;
813234848Smav	}
814234848Smav	if (meta->cdr != NULL) {
815234848Smav		free(meta->cdr, M_MD_DDF);
816234848Smav		meta->cdr = NULL;
817234848Smav	}
818234848Smav	if (meta->pdr != NULL) {
819234848Smav		free(meta->pdr, M_MD_DDF);
820234848Smav		meta->pdr = NULL;
821234848Smav	}
822234848Smav	if (meta->vdr != NULL) {
823234848Smav		free(meta->vdr, M_MD_DDF);
824234848Smav		meta->vdr = NULL;
825234848Smav	}
826234848Smav	if (meta->cr != NULL) {
827234848Smav		free(meta->cr, M_MD_DDF);
828234848Smav		meta->cr = NULL;
829234848Smav	}
830234848Smav	if (meta->pdd != NULL) {
831234848Smav		free(meta->pdd, M_MD_DDF);
832234848Smav		meta->pdd = NULL;
833234848Smav	}
834234848Smav	if (meta->bbm != NULL) {
835234848Smav		free(meta->bbm, M_MD_DDF);
836234848Smav		meta->bbm = NULL;
837234848Smav	}
838234848Smav}
839234848Smav
840234848Smavstatic void
841234848Smavddf_vol_meta_create(struct ddf_vol_meta *meta, struct ddf_meta *sample)
842234848Smav{
843234848Smav	struct timespec ts;
844234848Smav	struct clocktime ct;
845234848Smav	struct ddf_header *hdr;
846234848Smav	u_int ss, size;
847234848Smav
848234848Smav	hdr = sample->hdr;
849234848Smav	meta->bigendian = sample->bigendian;
850234848Smav	ss = meta->sectorsize = sample->sectorsize;
851234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
852234848Smav	memcpy(meta->hdr, sample->hdr, ss);
853234848Smav	meta->cdr = malloc(GET32(sample, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
854234848Smav	memcpy(meta->cdr, sample->cdr, GET32(sample, hdr->cd_length) * ss);
855234848Smav	meta->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
856234848Smav	memset(meta->vde, 0xff, sizeof(struct ddf_vd_entry));
857234848Smav	getnanotime(&ts);
858234848Smav	clock_ts_to_ct(&ts, &ct);
859234848Smav	snprintf(meta->vde->VD_GUID, 25, "FreeBSD%04d%02d%02d%08x%01x",
860234848Smav	    ct.year, ct.mon, ct.day,
861234848Smav	    arc4random(), arc4random() & 0xf);
862234848Smav	size = GET16(sample, hdr->Configuration_Record_Length) * ss;
863234848Smav	meta->vdc = malloc(size, M_MD_DDF, M_WAITOK);
864234848Smav	memset(meta->vdc, 0xff, size);
865234848Smav	SET32(meta, vdc->Signature, DDF_VDCR_SIGNATURE);
866234848Smav	memcpy(meta->vdc->VD_GUID, meta->vde->VD_GUID, 24);
867234848Smav	SET32(meta, vdc->Sequence_Number, 0);
868234848Smav}
869234848Smav
870234848Smavstatic void
871234868Smavddf_vol_meta_update(struct ddf_vol_meta *dst, struct ddf_meta *src,
872234868Smav    uint8_t *GUID, int started)
873234848Smav{
874234848Smav	struct ddf_header *hdr;
875234848Smav	struct ddf_vd_entry *vde;
876234848Smav	struct ddf_vdc_record *vdc;
877234848Smav	int vnew, bvnew, bvd, size;
878234848Smav	u_int ss;
879234848Smav
880234848Smav	hdr = src->hdr;
881234848Smav	vde = &src->vdr->entry[ddf_meta_find_vd(src, GUID)];
882234848Smav	vdc = ddf_meta_find_vdc(src, GUID);
883234848Smav	bvd = GET8D(src, vdc->Secondary_Element_Seq);
884234848Smav	size = GET16(src, hdr->Configuration_Record_Length) * src->sectorsize;
885234848Smav
886234848Smav	if (dst->vdc == NULL ||
887234868Smav	    (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
888234868Smav	    GET32(dst, vdc->Sequence_Number))) > 0))
889234848Smav		vnew = 1;
890234848Smav	else
891234848Smav		vnew = 0;
892234848Smav
893234848Smav	if (dst->bvdc[bvd] == NULL ||
894234868Smav	    (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
895234868Smav	    GET32(dst, bvdc[bvd]->Sequence_Number))) > 0))
896234848Smav		bvnew = 1;
897234848Smav	else
898234848Smav		bvnew = 0;
899234848Smav
900234848Smav	if (vnew) {
901234848Smav		dst->bigendian = src->bigendian;
902234848Smav		ss = dst->sectorsize = src->sectorsize;
903234848Smav		if (dst->hdr != NULL)
904234848Smav			free(dst->hdr, M_MD_DDF);
905234848Smav		dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
906234848Smav		memcpy(dst->hdr, src->hdr, ss);
907234848Smav		if (dst->cdr != NULL)
908234848Smav			free(dst->cdr, M_MD_DDF);
909234848Smav		dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
910234848Smav		memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
911234848Smav		if (dst->vde != NULL)
912234848Smav			free(dst->vde, M_MD_DDF);
913234848Smav		dst->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
914234848Smav		memcpy(dst->vde, vde, sizeof(struct ddf_vd_entry));
915234848Smav		if (dst->vdc != NULL)
916234848Smav			free(dst->vdc, M_MD_DDF);
917234848Smav		dst->vdc = malloc(size, M_MD_DDF, M_WAITOK);
918234848Smav		memcpy(dst->vdc, vdc, size);
919234848Smav	}
920234848Smav	if (bvnew) {
921234848Smav		if (dst->bvdc[bvd] != NULL)
922234848Smav			free(dst->bvdc[bvd], M_MD_DDF);
923234848Smav		dst->bvdc[bvd] = malloc(size, M_MD_DDF, M_WAITOK);
924234848Smav		memcpy(dst->bvdc[bvd], vdc, size);
925234848Smav	}
926234848Smav}
927234848Smav
928234848Smavstatic void
929234848Smavddf_vol_meta_free(struct ddf_vol_meta *meta)
930234848Smav{
931234848Smav	int i;
932234848Smav
933234848Smav	if (meta->hdr != NULL) {
934234848Smav		free(meta->hdr, M_MD_DDF);
935234848Smav		meta->hdr = NULL;
936234848Smav	}
937234848Smav	if (meta->cdr != NULL) {
938234848Smav		free(meta->cdr, M_MD_DDF);
939234848Smav		meta->cdr = NULL;
940234848Smav	}
941234848Smav	if (meta->vde != NULL) {
942234848Smav		free(meta->vde, M_MD_DDF);
943234848Smav		meta->vde = NULL;
944234848Smav	}
945234848Smav	if (meta->vdc != NULL) {
946234848Smav		free(meta->vdc, M_MD_DDF);
947234848Smav		meta->vdc = NULL;
948234848Smav	}
949234848Smav	for (i = 0; i < DDF_MAX_DISKS_HARD; i++) {
950234848Smav		if (meta->bvdc[i] != NULL) {
951234848Smav			free(meta->bvdc[i], M_MD_DDF);
952234848Smav			meta->bvdc[i] = NULL;
953234848Smav		}
954234848Smav	}
955234848Smav}
956234848Smav
957234848Smavstatic int
958234848Smavddf_meta_unused_range(struct ddf_meta *meta, off_t *off, off_t *size)
959234848Smav{
960234848Smav	struct ddf_vdc_record *vdc;
961234848Smav	off_t beg[32], end[32], beg1, end1;
962234848Smav	uint64_t *offp;
963234848Smav	int i, j, n, num, pos;
964234848Smav	uint32_t ref;
965234848Smav
966234848Smav	*off = 0;
967234848Smav	*size = 0;
968234848Smav	ref = GET32(meta, pdd->PD_Reference);
969234848Smav	pos = ddf_meta_find_pd(meta, NULL, ref);
970234848Smav	beg[0] = 0;
971234848Smav	end[0] = GET64(meta, pdr->entry[pos].Configured_Size);
972234848Smav	n = 1;
973234869Smav	num = GETCRNUM(meta);
974234848Smav	for (i = 0; i < num; i++) {
975234869Smav		vdc = GETVDCPTR(meta, i);
976234848Smav		if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
977234848Smav			continue;
978234848Smav		for (pos = 0; pos < GET16D(meta, vdc->Primary_Element_Count); pos++)
979234848Smav			if (GET32D(meta, vdc->Physical_Disk_Sequence[pos]) == ref)
980234848Smav				break;
981234848Smav		if (pos == GET16D(meta, vdc->Primary_Element_Count))
982234848Smav			continue;
983234848Smav		offp = (uint64_t *)&(vdc->Physical_Disk_Sequence[
984234848Smav		    GET16(meta, hdr->Max_Primary_Element_Entries)]);
985234848Smav		beg1 = GET64P(meta, offp + pos);
986234848Smav		end1 = beg1 + GET64D(meta, vdc->Block_Count);
987234848Smav		for (j = 0; j < n; j++) {
988234848Smav			if (beg[j] >= end1 || end[j] <= beg1 )
989234848Smav				continue;
990234848Smav			if (beg[j] < beg1 && end[j] > end1) {
991234848Smav				beg[n] = end1;
992234848Smav				end[n] = end[j];
993234848Smav				end[j] = beg1;
994234848Smav				n++;
995234848Smav			} else if (beg[j] < beg1)
996234848Smav				end[j] = beg1;
997234848Smav			else
998234848Smav				beg[j] = end1;
999234848Smav		}
1000234848Smav	}
1001234848Smav	for (j = 0; j < n; j++) {
1002234848Smav		if (end[j] - beg[j] > *size) {
1003234848Smav			*off = beg[j];
1004234848Smav			*size = end[j] - beg[j];
1005234848Smav		}
1006234848Smav	}
1007234848Smav	return ((*size > 0) ? 1 : 0);
1008234848Smav}
1009234848Smav
1010234848Smavstatic void
1011234848Smavddf_meta_get_name(struct ddf_meta *meta, int num, char *buf)
1012234848Smav{
1013234848Smav	const char *b;
1014234848Smav	int i;
1015234848Smav
1016234848Smav	b = meta->vdr->entry[num].VD_Name;
1017234848Smav	for (i = 15; i >= 0; i--)
1018234848Smav		if (b[i] != 0x20)
1019234848Smav			break;
1020234848Smav	memcpy(buf, b, i + 1);
1021234848Smav	buf[i + 1] = 0;
1022234848Smav}
1023234848Smav
1024234848Smavstatic void
1025234848Smavddf_meta_put_name(struct ddf_vol_meta *meta, char *buf)
1026234848Smav{
1027234848Smav	int len;
1028234848Smav
1029234848Smav	len = min(strlen(buf), 16);
1030234848Smav	memset(meta->vde->VD_Name, 0x20, 16);
1031234848Smav	memcpy(meta->vde->VD_Name, buf, len);
1032234848Smav}
1033234848Smav
1034234848Smavstatic int
1035234848Smavddf_meta_read(struct g_consumer *cp, struct ddf_meta *meta)
1036234848Smav{
1037234848Smav	struct g_provider *pp;
1038234848Smav	struct ddf_header *ahdr, *hdr;
1039234848Smav	char *abuf, *buf;
1040234848Smav	off_t plba, slba, lba;
1041234848Smav	int error, len, i;
1042234848Smav	u_int ss;
1043234848Smav	uint32_t val;
1044234848Smav
1045234848Smav	ddf_meta_free(meta);
1046234848Smav	pp = cp->provider;
1047234848Smav	ss = meta->sectorsize = pp->sectorsize;
1048234848Smav	/* Read anchor block. */
1049234848Smav	abuf = g_read_data(cp, pp->mediasize - ss, ss, &error);
1050234848Smav	if (abuf == NULL) {
1051234848Smav		G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).",
1052234848Smav		    pp->name, error);
1053234848Smav		return (error);
1054234848Smav	}
1055234848Smav	ahdr = (struct ddf_header *)abuf;
1056234848Smav
1057234848Smav	/* Check if this is an DDF RAID struct */
1058234848Smav	if (be32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
1059234848Smav		meta->bigendian = 1;
1060234848Smav	else if (le32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
1061234848Smav		meta->bigendian = 0;
1062234848Smav	else {
1063234848Smav		G_RAID_DEBUG(1, "DDF signature check failed on %s", pp->name);
1064234848Smav		error = EINVAL;
1065234848Smav		goto done;
1066234848Smav	}
1067234848Smav	if (ahdr->Header_Type != DDF_HEADER_ANCHOR) {
1068234848Smav		G_RAID_DEBUG(1, "DDF header type check failed on %s", pp->name);
1069234848Smav		error = EINVAL;
1070234848Smav		goto done;
1071234848Smav	}
1072234848Smav	meta->hdr = ahdr;
1073234848Smav	plba = GET64(meta, hdr->Primary_Header_LBA);
1074234848Smav	slba = GET64(meta, hdr->Secondary_Header_LBA);
1075234848Smav	val = GET32(meta, hdr->CRC);
1076234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1077234848Smav	meta->hdr = NULL;
1078234848Smav	if (crc32(ahdr, ss) != val) {
1079234848Smav		G_RAID_DEBUG(1, "DDF CRC mismatch on %s", pp->name);
1080234848Smav		error = EINVAL;
1081234848Smav		goto done;
1082234848Smav	}
1083234848Smav	if ((plba + 6) * ss >= pp->mediasize) {
1084234848Smav		G_RAID_DEBUG(1, "DDF primary header LBA is wrong on %s", pp->name);
1085234848Smav		error = EINVAL;
1086234848Smav		goto done;
1087234848Smav	}
1088234848Smav	if (slba != -1 && (slba + 6) * ss >= pp->mediasize) {
1089234848Smav		G_RAID_DEBUG(1, "DDF secondary header LBA is wrong on %s", pp->name);
1090234848Smav		error = EINVAL;
1091234848Smav		goto done;
1092234848Smav	}
1093234848Smav	lba = plba;
1094234848Smav
1095234848Smavdoread:
1096234848Smav	error = 0;
1097234848Smav	ddf_meta_free(meta);
1098234848Smav
1099234848Smav	/* Read header block. */
1100234848Smav	buf = g_read_data(cp, lba * ss, ss, &error);
1101234848Smav	if (buf == NULL) {
1102234848Smavreaderror:
1103234848Smav		G_RAID_DEBUG(1, "DDF %s metadata read error on %s (error=%d).",
1104234848Smav		    (lba == plba) ? "primary" : "secondary", pp->name, error);
1105234848Smav		if (lba == plba && slba != -1) {
1106234848Smav			lba = slba;
1107234848Smav			goto doread;
1108234848Smav		}
1109234848Smav		G_RAID_DEBUG(1, "DDF metadata read error on %s.", pp->name);
1110234848Smav		goto done;
1111234848Smav	}
1112234848Smav	meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
1113234848Smav	memcpy(meta->hdr, buf, ss);
1114234848Smav	g_free(buf);
1115234848Smav	hdr = meta->hdr;
1116234848Smav	val = GET32(meta, hdr->CRC);
1117234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1118234848Smav	if (hdr->Signature != ahdr->Signature ||
1119234848Smav	    crc32(meta->hdr, ss) != val ||
1120234848Smav	    memcmp(hdr->DDF_Header_GUID, ahdr->DDF_Header_GUID, 24) ||
1121234848Smav	    GET64(meta, hdr->Primary_Header_LBA) != plba ||
1122234848Smav	    GET64(meta, hdr->Secondary_Header_LBA) != slba) {
1123234848Smavhdrerror:
1124234848Smav		G_RAID_DEBUG(1, "DDF %s metadata check failed on %s",
1125234848Smav		    (lba == plba) ? "primary" : "secondary", pp->name);
1126234848Smav		if (lba == plba && slba != -1) {
1127234848Smav			lba = slba;
1128234848Smav			goto doread;
1129234848Smav		}
1130234848Smav		G_RAID_DEBUG(1, "DDF metadata check failed on %s", pp->name);
1131234848Smav		error = EINVAL;
1132234848Smav		goto done;
1133234848Smav	}
1134234848Smav	if ((lba == plba && hdr->Header_Type != DDF_HEADER_PRIMARY) ||
1135234848Smav	    (lba == slba && hdr->Header_Type != DDF_HEADER_SECONDARY))
1136234848Smav		goto hdrerror;
1137234848Smav	len = 1;
1138234848Smav	len = max(len, GET32(meta, hdr->cd_section) + GET32(meta, hdr->cd_length));
1139234848Smav	len = max(len, GET32(meta, hdr->pdr_section) + GET32(meta, hdr->pdr_length));
1140234848Smav	len = max(len, GET32(meta, hdr->vdr_section) + GET32(meta, hdr->vdr_length));
1141234848Smav	len = max(len, GET32(meta, hdr->cr_section) + GET32(meta, hdr->cr_length));
1142234848Smav	len = max(len, GET32(meta, hdr->pdd_section) + GET32(meta, hdr->pdd_length));
1143234848Smav	if ((val = GET32(meta, hdr->bbmlog_section)) != 0xffffffff)
1144234848Smav		len = max(len, val + GET32(meta, hdr->bbmlog_length));
1145234848Smav	if ((val = GET32(meta, hdr->Diagnostic_Space)) != 0xffffffff)
1146234848Smav		len = max(len, val + GET32(meta, hdr->Diagnostic_Space_Length));
1147234848Smav	if ((val = GET32(meta, hdr->Vendor_Specific_Logs)) != 0xffffffff)
1148234848Smav		len = max(len, val + GET32(meta, hdr->Vendor_Specific_Logs_Length));
1149234848Smav	if ((plba + len) * ss >= pp->mediasize)
1150234848Smav		goto hdrerror;
1151234848Smav	if (slba != -1 && (slba + len) * ss >= pp->mediasize)
1152234848Smav		goto hdrerror;
1153234848Smav	/* Workaround for Adaptec implementation. */
1154234848Smav	if (GET16(meta, hdr->Max_Primary_Element_Entries) == 0xffff) {
1155234848Smav		SET16(meta, hdr->Max_Primary_Element_Entries,
1156234848Smav		    min(GET16(meta, hdr->Max_PD_Entries),
1157234848Smav		    (GET16(meta, hdr->Configuration_Record_Length) * ss - 512) / 12));
1158234848Smav	}
1159234848Smav
1160234848Smav	/* Read controller data. */
1161234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
1162234848Smav	    GET32(meta, hdr->cd_length) * ss, &error);
1163234848Smav	if (buf == NULL)
1164234848Smav		goto readerror;
1165234848Smav	meta->cdr = malloc(GET32(meta, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
1166234848Smav	memcpy(meta->cdr, buf, GET32(meta, hdr->cd_length) * ss);
1167234848Smav	g_free(buf);
1168234848Smav	if (GET32(meta, cdr->Signature) != DDF_CONTROLLER_DATA_SIGNATURE)
1169234848Smav		goto hdrerror;
1170234848Smav
1171234848Smav	/* Read physical disk records. */
1172234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
1173234848Smav	    GET32(meta, hdr->pdr_length) * ss, &error);
1174234848Smav	if (buf == NULL)
1175234848Smav		goto readerror;
1176234848Smav	meta->pdr = malloc(GET32(meta, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
1177234848Smav	memcpy(meta->pdr, buf, GET32(meta, hdr->pdr_length) * ss);
1178234848Smav	g_free(buf);
1179234848Smav	if (GET32(meta, pdr->Signature) != DDF_PDR_SIGNATURE)
1180234848Smav		goto hdrerror;
1181234848Smav
1182234848Smav	/* Read virtual disk records. */
1183234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
1184234848Smav	    GET32(meta, hdr->vdr_length) * ss, &error);
1185234848Smav	if (buf == NULL)
1186234848Smav		goto readerror;
1187234848Smav	meta->vdr = malloc(GET32(meta, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
1188234848Smav	memcpy(meta->vdr, buf, GET32(meta, hdr->vdr_length) * ss);
1189234848Smav	g_free(buf);
1190234848Smav	if (GET32(meta, vdr->Signature) != DDF_VD_RECORD_SIGNATURE)
1191234848Smav		goto hdrerror;
1192234848Smav
1193234848Smav	/* Read configuration records. */
1194234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
1195234848Smav	    GET32(meta, hdr->cr_length) * ss, &error);
1196234848Smav	if (buf == NULL)
1197234848Smav		goto readerror;
1198234848Smav	meta->cr = malloc(GET32(meta, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
1199234848Smav	memcpy(meta->cr, buf, GET32(meta, hdr->cr_length) * ss);
1200234848Smav	g_free(buf);
1201234848Smav
1202234848Smav	/* Read physical disk data. */
1203234848Smav	buf = g_read_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
1204234848Smav	    GET32(meta, hdr->pdd_length) * ss, &error);
1205234848Smav	if (buf == NULL)
1206234848Smav		goto readerror;
1207234848Smav	meta->pdd = malloc(GET32(meta, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
1208234848Smav	memcpy(meta->pdd, buf, GET32(meta, hdr->pdd_length) * ss);
1209234848Smav	g_free(buf);
1210234848Smav	if (GET32(meta, pdd->Signature) != DDF_PDD_SIGNATURE)
1211234848Smav		goto hdrerror;
1212234848Smav	i = ddf_meta_find_pd(meta, NULL, GET32(meta, pdd->PD_Reference));
1213234848Smav	if (i < 0)
1214234848Smav		goto hdrerror;
1215234848Smav
1216234848Smav	/* Read BBM Log. */
1217234848Smav	if (GET32(meta, hdr->bbmlog_section) != 0xffffffff &&
1218234848Smav	    GET32(meta, hdr->bbmlog_length) != 0) {
1219234848Smav		buf = g_read_data(cp, (lba + GET32(meta, hdr->bbmlog_section)) * ss,
1220234848Smav		    GET32(meta, hdr->bbmlog_length) * ss, &error);
1221234848Smav		if (buf == NULL)
1222234848Smav			goto readerror;
1223234848Smav		meta->bbm = malloc(GET32(meta, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
1224234848Smav		memcpy(meta->bbm, buf, GET32(meta, hdr->bbmlog_length) * ss);
1225234848Smav		g_free(buf);
1226234848Smav		if (GET32(meta, bbm->Signature) != DDF_BBML_SIGNATURE)
1227234848Smav			goto hdrerror;
1228234848Smav	}
1229234848Smav
1230234848Smavdone:
1231234848Smav	free(abuf, M_MD_DDF);
1232234848Smav	if (error != 0)
1233234848Smav		ddf_meta_free(meta);
1234234848Smav	return (error);
1235234848Smav}
1236234848Smav
1237234848Smavstatic int
1238234848Smavddf_meta_write(struct g_consumer *cp, struct ddf_meta *meta)
1239234848Smav{
1240234848Smav	struct g_provider *pp;
1241234848Smav	struct ddf_vdc_record *vdc;
1242234848Smav	off_t alba, plba, slba, lba;
1243234848Smav	u_int ss, size;
1244234848Smav	int error, i, num;
1245234848Smav
1246234848Smav	pp = cp->provider;
1247234848Smav	ss = pp->sectorsize;
1248234848Smav	lba = alba = pp->mediasize / ss - 1;
1249234848Smav	plba = GET64(meta, hdr->Primary_Header_LBA);
1250234848Smav	slba = GET64(meta, hdr->Secondary_Header_LBA);
1251234848Smav
1252234848Smavnext:
1253234848Smav	SET8(meta, hdr->Header_Type, (lba == alba) ? DDF_HEADER_ANCHOR :
1254234848Smav	    (lba == plba) ? DDF_HEADER_PRIMARY : DDF_HEADER_SECONDARY);
1255234848Smav	SET32(meta, hdr->CRC, 0xffffffff);
1256234848Smav	SET32(meta, hdr->CRC, crc32(meta->hdr, ss));
1257234848Smav	error = g_write_data(cp, lba * ss, meta->hdr, ss);
1258234848Smav	if (error != 0) {
1259234848Smaverr:
1260234848Smav		G_RAID_DEBUG(1, "Cannot write metadata to %s (error=%d).",
1261234848Smav		    pp->name, error);
1262234848Smav		if (lba != alba)
1263234848Smav			goto done;
1264234848Smav	}
1265234848Smav	if (lba == alba) {
1266234848Smav		lba = plba;
1267234848Smav		goto next;
1268234848Smav	}
1269234848Smav
1270234848Smav	size = GET32(meta, hdr->cd_length) * ss;
1271234848Smav	SET32(meta, cdr->CRC, 0xffffffff);
1272234848Smav	SET32(meta, cdr->CRC, crc32(meta->cdr, size));
1273234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
1274234848Smav	    meta->cdr, size);
1275234848Smav	if (error != 0)
1276234848Smav		goto err;
1277234848Smav
1278234848Smav	size = GET32(meta, hdr->pdr_length) * ss;
1279234848Smav	SET32(meta, pdr->CRC, 0xffffffff);
1280234848Smav	SET32(meta, pdr->CRC, crc32(meta->pdr, size));
1281234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
1282234848Smav	    meta->pdr, size);
1283234848Smav	if (error != 0)
1284234848Smav		goto err;
1285234848Smav
1286234848Smav	size = GET32(meta, hdr->vdr_length) * ss;
1287234848Smav	SET32(meta, vdr->CRC, 0xffffffff);
1288234848Smav	SET32(meta, vdr->CRC, crc32(meta->vdr, size));
1289234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
1290234848Smav	    meta->vdr, size);
1291234848Smav	if (error != 0)
1292234848Smav		goto err;
1293234848Smav
1294234869Smav	size = GET16(meta, hdr->Configuration_Record_Length) * ss;
1295234869Smav	num = GETCRNUM(meta);
1296234848Smav	for (i = 0; i < num; i++) {
1297234869Smav		vdc = GETVDCPTR(meta, i);
1298234848Smav		SET32D(meta, vdc->CRC, 0xffffffff);
1299234848Smav		SET32D(meta, vdc->CRC, crc32(vdc, size));
1300234848Smav	}
1301234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
1302234848Smav	    meta->cr, size * num);
1303234848Smav	if (error != 0)
1304234848Smav		goto err;
1305234848Smav
1306234848Smav	size = GET32(meta, hdr->pdd_length) * ss;
1307234848Smav	SET32(meta, pdd->CRC, 0xffffffff);
1308234848Smav	SET32(meta, pdd->CRC, crc32(meta->pdd, size));
1309234848Smav	error = g_write_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
1310234848Smav	    meta->pdd, size);
1311234848Smav	if (error != 0)
1312234848Smav		goto err;
1313234848Smav
1314234848Smav	if (GET32(meta, hdr->bbmlog_length) != 0) {
1315234848Smav		size = GET32(meta, hdr->bbmlog_length) * ss;
1316234848Smav		SET32(meta, bbm->CRC, 0xffffffff);
1317234848Smav		SET32(meta, bbm->CRC, crc32(meta->bbm, size));
1318234848Smav		error = g_write_data(cp,
1319234848Smav		    (lba + GET32(meta, hdr->bbmlog_section)) * ss,
1320234848Smav		    meta->bbm, size);
1321234848Smav		if (error != 0)
1322234848Smav			goto err;
1323234848Smav	}
1324234848Smav
1325234848Smavdone:
1326234848Smav	if (lba == plba && slba != -1) {
1327234848Smav		lba = slba;
1328234848Smav		goto next;
1329234848Smav	}
1330234848Smav
1331234848Smav	return (error);
1332234848Smav}
1333234848Smav
1334234848Smavstatic int
1335234848Smavddf_meta_erase(struct g_consumer *cp)
1336234848Smav{
1337234848Smav	struct g_provider *pp;
1338234848Smav	char *buf;
1339234848Smav	int error;
1340234848Smav
1341234848Smav	pp = cp->provider;
1342234848Smav	buf = malloc(pp->sectorsize, M_MD_DDF, M_WAITOK | M_ZERO);
1343234848Smav	error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1344234848Smav	    buf, pp->sectorsize);
1345234848Smav	if (error != 0) {
1346234848Smav		G_RAID_DEBUG(1, "Cannot erase metadata on %s (error=%d).",
1347234848Smav		    pp->name, error);
1348234848Smav	}
1349234848Smav	free(buf, M_MD_DDF);
1350234848Smav	return (error);
1351234848Smav}
1352234848Smav
1353234848Smavstatic struct g_raid_volume *
1354234848Smavg_raid_md_ddf_get_volume(struct g_raid_softc *sc, uint8_t *GUID)
1355234848Smav{
1356234848Smav	struct g_raid_volume	*vol;
1357234848Smav	struct g_raid_md_ddf_pervolume *pv;
1358234848Smav
1359234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1360234848Smav		pv = vol->v_md_data;
1361234848Smav		if (memcmp(pv->pv_meta.vde->VD_GUID, GUID, 24) == 0)
1362234848Smav			break;
1363234848Smav	}
1364234848Smav	return (vol);
1365234848Smav}
1366234848Smav
1367234848Smavstatic struct g_raid_disk *
1368234848Smavg_raid_md_ddf_get_disk(struct g_raid_softc *sc, uint8_t *GUID, uint32_t id)
1369234848Smav{
1370234848Smav	struct g_raid_disk	*disk;
1371234848Smav	struct g_raid_md_ddf_perdisk *pd;
1372234848Smav	struct ddf_meta *meta;
1373234848Smav
1374234848Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1375234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1376234848Smav		meta = &pd->pd_meta;
1377234848Smav		if (GUID != NULL) {
1378234848Smav			if (memcmp(meta->pdd->PD_GUID, GUID, 24) == 0)
1379234848Smav				break;
1380234848Smav		} else {
1381234848Smav			if (GET32(meta, pdd->PD_Reference) == id)
1382234848Smav				break;
1383234848Smav		}
1384234848Smav	}
1385234848Smav	return (disk);
1386234848Smav}
1387234848Smav
1388234848Smavstatic int
1389234848Smavg_raid_md_ddf_purge_volumes(struct g_raid_softc *sc)
1390234848Smav{
1391234848Smav	struct g_raid_volume	*vol, *tvol;
1392234848Smav	struct g_raid_md_ddf_pervolume *pv;
1393234848Smav	int i, res;
1394234848Smav
1395234848Smav	res = 0;
1396234848Smav	TAILQ_FOREACH_SAFE(vol, &sc->sc_volumes, v_next, tvol) {
1397234848Smav		pv = vol->v_md_data;
1398234848Smav		if (vol->v_stopping)
1399234848Smav			continue;
1400234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1401234848Smav			if (vol->v_subdisks[i].sd_state != G_RAID_SUBDISK_S_NONE)
1402234848Smav				break;
1403234848Smav		}
1404234848Smav		if (i >= vol->v_disks_count) {
1405234848Smav			g_raid_destroy_volume(vol);
1406234848Smav			res = 1;
1407234848Smav		}
1408234848Smav	}
1409234848Smav	return (res);
1410234848Smav}
1411234848Smav
1412234848Smavstatic int
1413234848Smavg_raid_md_ddf_purge_disks(struct g_raid_softc *sc)
1414234848Smav{
1415234848Smav#if 0
1416234848Smav	struct g_raid_disk	*disk, *tdisk;
1417234848Smav	struct g_raid_volume	*vol;
1418234848Smav	struct g_raid_md_ddf_perdisk *pd;
1419234848Smav	int i, j, res;
1420234848Smav
1421234848Smav	res = 0;
1422234848Smav	TAILQ_FOREACH_SAFE(disk, &sc->sc_disks, d_next, tdisk) {
1423234848Smav		if (disk->d_state == G_RAID_DISK_S_SPARE)
1424234848Smav			continue;
1425234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1426234848Smav
1427234848Smav		/* Scan for deleted volumes. */
1428234848Smav		for (i = 0; i < pd->pd_subdisks; ) {
1429234848Smav			vol = g_raid_md_ddf_get_volume(sc,
1430234848Smav			    pd->pd_meta[i]->volume_id);
1431234848Smav			if (vol != NULL && !vol->v_stopping) {
1432234848Smav				i++;
1433234848Smav				continue;
1434234848Smav			}
1435234848Smav			free(pd->pd_meta[i], M_MD_DDF);
1436234848Smav			for (j = i; j < pd->pd_subdisks - 1; j++)
1437234848Smav				pd->pd_meta[j] = pd->pd_meta[j + 1];
1438234848Smav			pd->pd_meta[DDF_MAX_SUBDISKS - 1] = NULL;
1439234848Smav			pd->pd_subdisks--;
1440234848Smav			pd->pd_updated = 1;
1441234848Smav		}
1442234848Smav
1443234848Smav		/* If there is no metadata left - erase and delete disk. */
1444234848Smav		if (pd->pd_subdisks == 0) {
1445234848Smav			ddf_meta_erase(disk->d_consumer);
1446234848Smav			g_raid_destroy_disk(disk);
1447234848Smav			res = 1;
1448234848Smav		}
1449234848Smav	}
1450234848Smav	return (res);
1451234848Smav#endif
1452234848Smav	return (0);
1453234848Smav}
1454234848Smav
1455234848Smavstatic int
1456234848Smavg_raid_md_ddf_supported(int level, int qual, int disks, int force)
1457234848Smav{
1458234848Smav
1459234848Smav	if (disks > DDF_MAX_DISKS_HARD)
1460234848Smav		return (0);
1461234848Smav	switch (level) {
1462234848Smav	case G_RAID_VOLUME_RL_RAID0:
1463234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1464234848Smav			return (0);
1465234848Smav		if (disks < 1)
1466234848Smav			return (0);
1467234848Smav		if (!force && disks < 2)
1468234848Smav			return (0);
1469234848Smav		break;
1470234848Smav	case G_RAID_VOLUME_RL_RAID1:
1471234848Smav		if (disks < 1)
1472234848Smav			return (0);
1473234848Smav		if (qual == G_RAID_VOLUME_RLQ_R1SM) {
1474234848Smav			if (!force && disks != 2)
1475234848Smav				return (0);
1476234848Smav		} else if (qual == G_RAID_VOLUME_RLQ_R1MM) {
1477234848Smav			if (!force && disks != 3)
1478234848Smav				return (0);
1479234848Smav		} else
1480234848Smav			return (0);
1481234848Smav		break;
1482234848Smav	case G_RAID_VOLUME_RL_RAID3:
1483234848Smav		if (qual != G_RAID_VOLUME_RLQ_R3P0 &&
1484234848Smav		    qual != G_RAID_VOLUME_RLQ_R3PN)
1485234848Smav			return (0);
1486234848Smav		if (disks < 3)
1487234848Smav			return (0);
1488234848Smav		break;
1489234848Smav	case G_RAID_VOLUME_RL_RAID4:
1490234848Smav		if (qual != G_RAID_VOLUME_RLQ_R4P0 &&
1491234848Smav		    qual != G_RAID_VOLUME_RLQ_R4PN)
1492234848Smav			return (0);
1493234848Smav		if (disks < 3)
1494234848Smav			return (0);
1495234848Smav		break;
1496234848Smav	case G_RAID_VOLUME_RL_RAID5:
1497234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5RA &&
1498234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RS &&
1499234848Smav		    qual != G_RAID_VOLUME_RLQ_R5LA &&
1500234848Smav		    qual != G_RAID_VOLUME_RLQ_R5LS)
1501234848Smav			return (0);
1502234848Smav		if (disks < 3)
1503234848Smav			return (0);
1504234848Smav		break;
1505234848Smav	case G_RAID_VOLUME_RL_RAID6:
1506234848Smav		if (qual != G_RAID_VOLUME_RLQ_R6RA &&
1507234848Smav		    qual != G_RAID_VOLUME_RLQ_R6RS &&
1508234848Smav		    qual != G_RAID_VOLUME_RLQ_R6LA &&
1509234848Smav		    qual != G_RAID_VOLUME_RLQ_R6LS)
1510234848Smav			return (0);
1511234848Smav		if (disks < 4)
1512234848Smav			return (0);
1513234848Smav		break;
1514234848Smav	case G_RAID_VOLUME_RL_RAIDMDF:
1515234848Smav		if (qual != G_RAID_VOLUME_RLQ_RMDFRA &&
1516234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFRS &&
1517234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFLA &&
1518234848Smav		    qual != G_RAID_VOLUME_RLQ_RMDFLS)
1519234848Smav			return (0);
1520235076Smav		if (disks < 4)
1521234848Smav			return (0);
1522234848Smav		break;
1523234848Smav	case G_RAID_VOLUME_RL_RAID1E:
1524234848Smav		if (qual != G_RAID_VOLUME_RLQ_R1EA &&
1525234848Smav		    qual != G_RAID_VOLUME_RLQ_R1EO)
1526234848Smav			return (0);
1527234869Smav		if (disks < 3)
1528234848Smav			return (0);
1529234848Smav		break;
1530234848Smav	case G_RAID_VOLUME_RL_SINGLE:
1531234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1532234848Smav			return (0);
1533234848Smav		if (disks != 1)
1534234848Smav			return (0);
1535234848Smav		break;
1536234848Smav	case G_RAID_VOLUME_RL_CONCAT:
1537234848Smav		if (qual != G_RAID_VOLUME_RLQ_NONE)
1538234848Smav			return (0);
1539234848Smav		if (disks < 2)
1540234848Smav			return (0);
1541234848Smav		break;
1542234848Smav	case G_RAID_VOLUME_RL_RAID5E:
1543234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5ERA &&
1544234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ERS &&
1545234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ELA &&
1546234848Smav		    qual != G_RAID_VOLUME_RLQ_R5ELS)
1547234848Smav			return (0);
1548234848Smav		if (disks < 4)
1549234848Smav			return (0);
1550234848Smav		break;
1551234848Smav	case G_RAID_VOLUME_RL_RAID5EE:
1552234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5EERA &&
1553234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EERS &&
1554234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EELA &&
1555234848Smav		    qual != G_RAID_VOLUME_RLQ_R5EELS)
1556234848Smav			return (0);
1557234848Smav		if (disks < 4)
1558234848Smav			return (0);
1559234848Smav		break;
1560234848Smav	case G_RAID_VOLUME_RL_RAID5R:
1561234848Smav		if (qual != G_RAID_VOLUME_RLQ_R5RRA &&
1562234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RRS &&
1563234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RLA &&
1564234848Smav		    qual != G_RAID_VOLUME_RLQ_R5RLS)
1565234848Smav			return (0);
1566234848Smav		if (disks < 3)
1567234848Smav			return (0);
1568234848Smav		break;
1569234848Smav	default:
1570234848Smav		return (0);
1571234848Smav	}
1572234848Smav	return (1);
1573234848Smav}
1574234848Smav
1575234848Smavstatic int
1576234848Smavg_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol)
1577234848Smav{
1578234848Smav	struct g_raid_softc *sc;
1579234848Smav	struct g_raid_subdisk *sd;
1580234848Smav	struct g_raid_md_ddf_perdisk *pd;
1581234848Smav	struct g_raid_md_ddf_pervolume *pv;
1582234848Smav	struct g_raid_md_ddf_object *mdi;
1583234848Smav	struct ddf_vol_meta *vmeta;
1584234848Smav	struct ddf_meta *pdmeta, *gmeta;
1585234848Smav	struct ddf_vdc_record *vdc1;
1586234899Smav	struct ddf_sa_record *sa;
1587234848Smav	off_t size, eoff = 0, esize = 0;
1588234848Smav	uint64_t *val2;
1589234848Smav	int disk_pos, md_disk_bvd = -1, md_disk_pos = -1, md_pde_pos;
1590234848Smav	int i, resurrection = 0;
1591234848Smav	uint32_t reference;
1592234848Smav
1593234848Smav	sc = disk->d_softc;
1594234848Smav	mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
1595234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1596234848Smav	pdmeta = &pd->pd_meta;
1597234848Smav	reference = GET32(&pd->pd_meta, pdd->PD_Reference);
1598234848Smav
1599234848Smav	pv = vol->v_md_data;
1600234848Smav	vmeta = &pv->pv_meta;
1601234848Smav	gmeta = &mdi->mdio_meta;
1602234848Smav
1603234848Smav	/* Find disk position in metadata by it's reference. */
1604234848Smav	disk_pos = ddf_meta_find_disk(vmeta, reference,
1605234848Smav	    &md_disk_bvd, &md_disk_pos);
1606234848Smav	md_pde_pos = ddf_meta_find_pd(gmeta, NULL, reference);
1607234848Smav
1608234848Smav	if (disk_pos < 0) {
1609234899Smav		G_RAID_DEBUG1(1, sc,
1610234899Smav		    "Disk %s is not a present part of the volume %s",
1611234848Smav		    g_raid_get_diskname(disk), vol->v_name);
1612234848Smav
1613234848Smav		/* Failed stale disk is useless for us. */
1614234848Smav		if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) != 0) {
1615234848Smav			g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE_FAILED);
1616234848Smav			return (0);
1617234848Smav		}
1618234848Smav
1619234848Smav		/* If disk has some metadata for this volume - erase. */
1620234899Smav		if ((vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL)
1621234848Smav			SET32D(pdmeta, vdc1->Signature, 0xffffffff);
1622234848Smav
1623234848Smav		/* If we are in the start process, that's all for now. */
1624234848Smav		if (!pv->pv_started)
1625234848Smav			goto nofit;
1626234848Smav		/*
1627234848Smav		 * If we have already started - try to get use of the disk.
1628234848Smav		 * Try to replace OFFLINE disks first, then FAILED.
1629234848Smav		 */
1630234848Smav		if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
1631234848Smav			GET16(&pd->pd_meta, hdr->Max_Partitions)) {
1632234848Smav			G_RAID_DEBUG1(1, sc, "No free partitions on disk %s",
1633234848Smav			    g_raid_get_diskname(disk));
1634234848Smav			goto nofit;
1635234848Smav		}
1636234848Smav		ddf_meta_unused_range(&pd->pd_meta, &eoff, &esize);
1637234848Smav		if (esize == 0) {
1638234848Smav			G_RAID_DEBUG1(1, sc, "No free space on disk %s",
1639234848Smav			    g_raid_get_diskname(disk));
1640234848Smav			goto nofit;
1641234848Smav		}
1642234848Smav		size = INT64_MAX;
1643234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1644234848Smav			sd = &vol->v_subdisks[i];
1645234848Smav			if (sd->sd_state != G_RAID_SUBDISK_S_NONE)
1646234848Smav				size = sd->sd_size;
1647234848Smav			if (sd->sd_state <= G_RAID_SUBDISK_S_FAILED &&
1648234848Smav			    (disk_pos < 0 ||
1649234848Smav			     vol->v_subdisks[i].sd_state < sd->sd_state))
1650234848Smav				disk_pos = i;
1651234848Smav		}
1652234848Smav		if (disk_pos >= 0 &&
1653234848Smav		    vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT &&
1654234848Smav		    (off_t)esize * 512 < size) {
1655234848Smav			G_RAID_DEBUG1(1, sc, "Disk %s free space "
1656234848Smav			    "is too small (%ju < %ju)",
1657234848Smav			    g_raid_get_diskname(disk),
1658234848Smav			    (off_t)esize * 512, size);
1659234848Smav			disk_pos = -1;
1660234848Smav		}
1661234848Smav		if (disk_pos >= 0) {
1662234848Smav			if (vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT)
1663234848Smav				esize = size / 512;
1664234848Smav			md_disk_bvd = disk_pos / GET16(vmeta, vdc->Primary_Element_Count); // XXX
1665234848Smav			md_disk_pos = disk_pos % GET16(vmeta, vdc->Primary_Element_Count); // XXX
1666234848Smav		} else {
1667234848Smavnofit:
1668234899Smav			if (disk->d_state == G_RAID_DISK_S_NONE)
1669234848Smav				g_raid_change_disk_state(disk,
1670234899Smav				    G_RAID_DISK_S_STALE);
1671234848Smav			return (0);
1672234848Smav		}
1673234899Smav
1674234899Smav		/*
1675234899Smav		 * If spare is committable, delete spare record.
1676234899Smav		 * Othersize, mark it active and leave there.
1677234899Smav		 */
1678234899Smav		sa = ddf_meta_find_sa(&pd->pd_meta, 0);
1679234899Smav		if (sa != NULL) {
1680234899Smav			if ((GET8D(&pd->pd_meta, sa->Spare_Type) &
1681234899Smav			    DDF_SAR_TYPE_REVERTIBLE) == 0) {
1682234899Smav				SET32D(&pd->pd_meta, sa->Signature, 0xffffffff);
1683234899Smav			} else {
1684234899Smav				SET8D(&pd->pd_meta, sa->Spare_Type,
1685234899Smav				    GET8D(&pd->pd_meta, sa->Spare_Type) |
1686234899Smav				    DDF_SAR_TYPE_ACTIVE);
1687234899Smav			}
1688234899Smav		}
1689234899Smav
1690234848Smav		G_RAID_DEBUG1(1, sc, "Disk %s takes pos %d in the volume %s",
1691234848Smav		    g_raid_get_diskname(disk), disk_pos, vol->v_name);
1692234848Smav		resurrection = 1;
1693234848Smav	}
1694234848Smav
1695234848Smav	sd = &vol->v_subdisks[disk_pos];
1696234848Smav
1697234848Smav	if (resurrection && sd->sd_disk != NULL) {
1698234848Smav		g_raid_change_disk_state(sd->sd_disk,
1699234848Smav		    G_RAID_DISK_S_STALE_FAILED);
1700234848Smav		TAILQ_REMOVE(&sd->sd_disk->d_subdisks,
1701234848Smav		    sd, sd_next);
1702234848Smav	}
1703234848Smav	vol->v_subdisks[disk_pos].sd_disk = disk;
1704234848Smav	TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
1705234848Smav
1706234848Smav	/* Welcome the new disk. */
1707234848Smav	if (resurrection)
1708234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
1709234848Smav	else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA)
1710234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED);
1711234848Smav	else
1712234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
1713234848Smav
1714234848Smav	if (resurrection) {
1715234848Smav		sd->sd_offset = (off_t)eoff * 512;
1716234848Smav		sd->sd_size = (off_t)esize * 512;
1717234848Smav	} else if (pdmeta->cr != NULL &&
1718234848Smav	    (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) {
1719234848Smav		val2 = (uint64_t *)&(vdc1->Physical_Disk_Sequence[GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
1720234848Smav		sd->sd_offset = (off_t)GET64P(pdmeta, val2 + md_disk_pos) * 512;
1721234848Smav		sd->sd_size = (off_t)GET64D(pdmeta, vdc1->Block_Count) * 512;
1722234848Smav	}
1723234848Smav
1724234848Smav	if (resurrection) {
1725234848Smav		/* Stale disk, almost same as new. */
1726234848Smav		g_raid_change_subdisk_state(sd,
1727234848Smav		    G_RAID_SUBDISK_S_NEW);
1728234848Smav	} else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) {
1729234848Smav		/* Failed disk. */
1730234848Smav		g_raid_change_subdisk_state(sd,
1731234848Smav		    G_RAID_SUBDISK_S_FAILED);
1732234848Smav	} else if ((GET8(gmeta, pdr->entry[md_pde_pos].PD_State) &
1733234848Smav	     (DDF_PDE_FAILED | DDF_PDE_REBUILD)) != 0) {
1734234848Smav		/* Rebuilding disk. */
1735234848Smav		g_raid_change_subdisk_state(sd,
1736234848Smav		    G_RAID_SUBDISK_S_REBUILD);
1737234848Smav		sd->sd_rebuild_pos = 0;
1738234848Smav	} else if ((GET8(vmeta, vde->VD_State) & DDF_VDE_DIRTY) != 0 ||
1739234848Smav	    (GET8(vmeta, vde->Init_State) & DDF_VDE_INIT_MASK) !=
1740234848Smav	     DDF_VDE_INIT_FULL) {
1741234848Smav		/* Stale disk or dirty volume (unclean shutdown). */
1742234848Smav		g_raid_change_subdisk_state(sd,
1743234848Smav		    G_RAID_SUBDISK_S_STALE);
1744234848Smav	} else {
1745234848Smav		/* Up to date disk. */
1746234848Smav		g_raid_change_subdisk_state(sd,
1747234848Smav		    G_RAID_SUBDISK_S_ACTIVE);
1748234848Smav	}
1749234848Smav	g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
1750234848Smav	    G_RAID_EVENT_SUBDISK);
1751234848Smav
1752234848Smav	return (resurrection);
1753234848Smav}
1754234848Smav
1755234848Smavstatic void
1756234848Smavg_raid_md_ddf_refill(struct g_raid_softc *sc)
1757234848Smav{
1758234848Smav	struct g_raid_volume *vol;
1759234848Smav	struct g_raid_subdisk *sd;
1760234848Smav	struct g_raid_disk *disk;
1761234848Smav	struct g_raid_md_object *md;
1762234848Smav	struct g_raid_md_ddf_perdisk *pd;
1763234848Smav	struct g_raid_md_ddf_pervolume *pv;
1764234848Smav	int update, updated, i, bad;
1765234848Smav
1766234848Smav	md = sc->sc_md;
1767234848Smavrestart:
1768234848Smav	updated = 0;
1769234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1770234848Smav		pv = vol->v_md_data;
1771234848Smav		if (!pv->pv_started || vol->v_stopping)
1772234848Smav			continue;
1773234848Smav
1774234848Smav		/* Search for subdisk that needs replacement. */
1775234848Smav		bad = 0;
1776234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
1777234848Smav			sd = &vol->v_subdisks[i];
1778234848Smav			if (sd->sd_state == G_RAID_SUBDISK_S_NONE ||
1779234848Smav			    sd->sd_state == G_RAID_SUBDISK_S_FAILED)
1780234848Smav			        bad = 1;
1781234848Smav		}
1782234848Smav		if (!bad)
1783234848Smav			continue;
1784234848Smav
1785234848Smav		G_RAID_DEBUG1(1, sc, "Volume %s is not complete, "
1786234848Smav		    "trying to refill.", vol->v_name);
1787234848Smav
1788234848Smav		TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1789234848Smav			/* Skip failed. */
1790234848Smav			if (disk->d_state < G_RAID_DISK_S_SPARE)
1791234848Smav				continue;
1792234848Smav			/* Skip already used by this volume. */
1793234848Smav			for (i = 0; i < vol->v_disks_count; i++) {
1794234848Smav				sd = &vol->v_subdisks[i];
1795234848Smav				if (sd->sd_disk == disk)
1796234848Smav					break;
1797234848Smav			}
1798234848Smav			if (i < vol->v_disks_count)
1799234848Smav				continue;
1800234848Smav
1801234848Smav			/* Try to use disk if it has empty extents. */
1802234848Smav			pd = disk->d_md_data;
1803234848Smav			if (ddf_meta_count_vdc(&pd->pd_meta, NULL) <
1804234848Smav			    GET16(&pd->pd_meta, hdr->Max_Partitions)) {
1805234848Smav				update = g_raid_md_ddf_start_disk(disk, vol);
1806234848Smav			} else
1807234848Smav				update = 0;
1808234848Smav			if (update) {
1809234848Smav				updated = 1;
1810234848Smav				g_raid_md_write_ddf(md, vol, NULL, disk);
1811234848Smav				break;
1812234848Smav			}
1813234848Smav		}
1814234848Smav	}
1815234848Smav	if (updated)
1816234848Smav		goto restart;
1817234848Smav}
1818234848Smav
1819234848Smavstatic void
1820234848Smavg_raid_md_ddf_start(struct g_raid_volume *vol)
1821234848Smav{
1822234848Smav	struct g_raid_softc *sc;
1823234848Smav	struct g_raid_subdisk *sd;
1824234848Smav	struct g_raid_disk *disk;
1825234848Smav	struct g_raid_md_object *md;
1826234899Smav	struct g_raid_md_ddf_perdisk *pd;
1827234848Smav	struct g_raid_md_ddf_pervolume *pv;
1828234868Smav	struct g_raid_md_ddf_object *mdi;
1829234848Smav	struct ddf_vol_meta *vmeta;
1830234848Smav	struct ddf_vdc_record *vdc;
1831234848Smav	uint64_t *val2;
1832234848Smav	int i, j, bvd;
1833234848Smav
1834234848Smav	sc = vol->v_softc;
1835234848Smav	md = sc->sc_md;
1836234868Smav	mdi = (struct g_raid_md_ddf_object *)md;
1837234848Smav	pv = vol->v_md_data;
1838234848Smav	vmeta = &pv->pv_meta;
1839234848Smav	vdc = vmeta->vdc;
1840234848Smav
1841234848Smav	vol->v_raid_level = GET8(vmeta, vdc->Primary_RAID_Level);
1842234848Smav	vol->v_raid_level_qualifier = GET8(vmeta, vdc->RLQ);
1843234848Smav	if (GET8(vmeta, vdc->Secondary_Element_Count) > 1 &&
1844234848Smav	    vol->v_raid_level == G_RAID_VOLUME_RL_RAID1 &&
1845234848Smav	    GET8(vmeta, vdc->Secondary_RAID_Level) == 0)
1846234848Smav		vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E;
1847234848Smav	vol->v_sectorsize = GET16(vmeta, vdc->Block_Size);
1848234848Smav	if (vol->v_sectorsize == 0xffff)
1849234848Smav		vol->v_sectorsize = vmeta->sectorsize;
1850234848Smav	vol->v_strip_size = vol->v_sectorsize << GET8(vmeta, vdc->Stripe_Size);
1851234848Smav	vol->v_disks_count = GET16(vmeta, vdc->Primary_Element_Count) *
1852234848Smav	    GET8(vmeta, vdc->Secondary_Element_Count);
1853235076Smav	vol->v_mdf_pdisks = GET8(vmeta, vdc->MDF_Parity_Disks);
1854235076Smav	vol->v_mdf_polynomial = GET16(vmeta, vdc->MDF_Parity_Generator_Polynomial);
1855235076Smav	vol->v_mdf_method = GET8(vmeta, vdc->MDF_Constant_Generation_Method);
1856235076Smav	if (GET8(vmeta, vdc->Rotate_Parity_count) > 31)
1857235076Smav		vol->v_rotate_parity = 1;
1858235076Smav	else
1859235076Smav		vol->v_rotate_parity = 1 << GET8(vmeta, vdc->Rotate_Parity_count);
1860234848Smav	vol->v_mediasize = GET64(vmeta, vdc->VD_Size) * vol->v_sectorsize;
1861234848Smav	for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) {
1862234848Smav		if (j == GET16(vmeta, vdc->Primary_Element_Count)) {
1863234848Smav			j = 0;
1864234848Smav			bvd++;
1865234848Smav		}
1866234848Smav		sd = &vol->v_subdisks[i];
1867234848Smav		if (vmeta->bvdc[bvd] == NULL) {
1868234848Smav			sd->sd_offset = 0;
1869234848Smav			sd->sd_size = GET64(vmeta, vdc->Block_Count) *
1870234848Smav			    vol->v_sectorsize;
1871234848Smav			continue;
1872234848Smav		}
1873234848Smav		val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
1874234848Smav		    GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
1875234848Smav		sd->sd_offset = GET64P(vmeta, val2 + j) * vol->v_sectorsize;
1876234848Smav		sd->sd_size = GET64(vmeta, bvdc[bvd]->Block_Count) *
1877234848Smav		    vol->v_sectorsize;
1878234848Smav	}
1879234848Smav	g_raid_start_volume(vol);
1880234848Smav
1881234848Smav	/* Make all disks found till the moment take their places. */
1882234899Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1883234899Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1884234899Smav		if (ddf_meta_find_vdc(&pd->pd_meta, vmeta->vdc->VD_GUID) != NULL)
1885234848Smav			g_raid_md_ddf_start_disk(disk, vol);
1886234848Smav	}
1887234848Smav
1888234848Smav	pv->pv_started = 1;
1889234868Smav	mdi->mdio_starting--;
1890234848Smav	callout_stop(&pv->pv_start_co);
1891234848Smav	G_RAID_DEBUG1(0, sc, "Volume started.");
1892234848Smav	g_raid_md_write_ddf(md, vol, NULL, NULL);
1893234848Smav
1894234848Smav	/* Pickup any STALE/SPARE disks to refill array if needed. */
1895234848Smav	g_raid_md_ddf_refill(sc);
1896234848Smav
1897234848Smav	g_raid_event_send(vol, G_RAID_VOLUME_E_START, G_RAID_EVENT_VOLUME);
1898234848Smav}
1899234848Smav
1900234848Smavstatic void
1901234848Smavg_raid_ddf_go(void *arg)
1902234848Smav{
1903234848Smav	struct g_raid_volume *vol;
1904234848Smav	struct g_raid_softc *sc;
1905234848Smav	struct g_raid_md_ddf_pervolume *pv;
1906234848Smav
1907234848Smav	vol = arg;
1908234848Smav	pv = vol->v_md_data;
1909234848Smav	sc = vol->v_softc;
1910234848Smav	if (!pv->pv_started) {
1911234848Smav		G_RAID_DEBUG1(0, sc, "Force volume start due to timeout.");
1912234848Smav		g_raid_event_send(vol, G_RAID_VOLUME_E_STARTMD,
1913234848Smav		    G_RAID_EVENT_VOLUME);
1914234848Smav	}
1915234848Smav}
1916234848Smav
1917234848Smavstatic void
1918234848Smavg_raid_md_ddf_new_disk(struct g_raid_disk *disk)
1919234848Smav{
1920234848Smav	struct g_raid_softc *sc;
1921234848Smav	struct g_raid_md_object *md;
1922234848Smav	struct g_raid_md_ddf_perdisk *pd;
1923234848Smav	struct g_raid_md_ddf_pervolume *pv;
1924234848Smav	struct g_raid_md_ddf_object *mdi;
1925234848Smav	struct g_raid_volume *vol;
1926234848Smav	struct ddf_meta *pdmeta;
1927234848Smav	struct ddf_vol_meta *vmeta;
1928234848Smav	struct ddf_vdc_record *vdc;
1929234848Smav	struct ddf_vd_entry *vde;
1930234899Smav	int i, j, k, num, have, need, cnt, spare;
1931234848Smav	uint32_t val;
1932234848Smav	char buf[17];
1933234848Smav
1934234848Smav	sc = disk->d_softc;
1935234848Smav	md = sc->sc_md;
1936234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
1937234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1938234848Smav	pdmeta = &pd->pd_meta;
1939234848Smav	spare = -1;
1940234848Smav
1941234848Smav	if (mdi->mdio_meta.hdr == NULL)
1942234848Smav		ddf_meta_copy(&mdi->mdio_meta, pdmeta);
1943234848Smav	else
1944234848Smav		ddf_meta_update(&mdi->mdio_meta, pdmeta);
1945234848Smav
1946234869Smav	num = GETCRNUM(pdmeta);
1947234848Smav	for (j = 0; j < num; j++) {
1948234869Smav		vdc = GETVDCPTR(pdmeta, j);
1949234848Smav		val = GET32D(pdmeta, vdc->Signature);
1950234848Smav
1951234848Smav		if (val == DDF_SA_SIGNATURE && spare == -1)
1952234848Smav			spare = 1;
1953234848Smav
1954234848Smav		if (val != DDF_VDCR_SIGNATURE)
1955234848Smav			continue;
1956234848Smav		spare = 0;
1957234848Smav		k = ddf_meta_find_vd(pdmeta, vdc->VD_GUID);
1958234848Smav		if (k < 0)
1959234848Smav			continue;
1960234848Smav		vde = &pdmeta->vdr->entry[k];
1961234848Smav
1962234848Smav		/* Look for volume with matching ID. */
1963234848Smav		vol = g_raid_md_ddf_get_volume(sc, vdc->VD_GUID);
1964234848Smav		if (vol == NULL) {
1965234848Smav			ddf_meta_get_name(pdmeta, k, buf);
1966234848Smav			vol = g_raid_create_volume(sc, buf,
1967234848Smav			    GET16D(pdmeta, vde->VD_Number));
1968234848Smav			pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
1969234848Smav			vol->v_md_data = pv;
1970234848Smav			callout_init(&pv->pv_start_co, 1);
1971234848Smav			callout_reset(&pv->pv_start_co,
1972234848Smav			    g_raid_start_timeout * hz,
1973234848Smav			    g_raid_ddf_go, vol);
1974234868Smav			mdi->mdio_starting++;
1975234848Smav		} else
1976234848Smav			pv = vol->v_md_data;
1977234848Smav
1978234848Smav		/* If we haven't started yet - check metadata freshness. */
1979234848Smav		vmeta = &pv->pv_meta;
1980234868Smav		ddf_vol_meta_update(vmeta, pdmeta, vdc->VD_GUID, pv->pv_started);
1981234848Smav	}
1982234848Smav
1983234848Smav	if (spare == 1) {
1984234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
1985234848Smav		g_raid_md_ddf_refill(sc);
1986234848Smav	}
1987234848Smav
1988234848Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
1989234848Smav		pv = vol->v_md_data;
1990234848Smav		vmeta = &pv->pv_meta;
1991234848Smav
1992234899Smav		if (ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID) == NULL)
1993234899Smav			continue;
1994234899Smav
1995234899Smav		if (pv->pv_started) {
1996234899Smav			if (g_raid_md_ddf_start_disk(disk, vol))
1997234899Smav				g_raid_md_write_ddf(md, vol, NULL, NULL);
1998234899Smav			continue;
1999234899Smav		}
2000234899Smav
2001234848Smav		/* If we collected all needed disks - start array. */
2002234848Smav		need = 0;
2003234848Smav		have = 0;
2004234848Smav		for (k = 0; k < GET8(vmeta, vdc->Secondary_Element_Count); k++) {
2005234848Smav			if (vmeta->bvdc[k] == NULL) {
2006234848Smav				need += GET16(vmeta, vdc->Primary_Element_Count);
2007234848Smav				continue;
2008234848Smav			}
2009234848Smav			cnt = GET16(vmeta, bvdc[k]->Primary_Element_Count);
2010234848Smav			need += cnt;
2011234848Smav			for (i = 0; i < cnt; i++) {
2012234848Smav				val = GET32(vmeta, bvdc[k]->Physical_Disk_Sequence[i]);
2013234899Smav				if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL)
2014234848Smav					have++;
2015234848Smav			}
2016234848Smav		}
2017234899Smav		G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks",
2018234899Smav		    vol->v_name, have, need);
2019234899Smav		if (have == need)
2020234899Smav			g_raid_md_ddf_start(vol);
2021234848Smav	}
2022234848Smav}
2023234848Smav
2024234848Smavstatic int
2025234940Smavg_raid_md_create_req_ddf(struct g_raid_md_object *md, struct g_class *mp,
2026234940Smav    struct gctl_req *req, struct g_geom **gp)
2027234848Smav{
2028234848Smav	struct g_geom *geom;
2029234848Smav	struct g_raid_softc *sc;
2030234940Smav	struct g_raid_md_ddf_object *mdi, *mdi1;
2031234940Smav	char name[16];
2032234940Smav	const char *fmtopt;
2033234940Smav	int be = 1;
2034234848Smav
2035234940Smav	mdi = (struct g_raid_md_ddf_object *)md;
2036234940Smav	fmtopt = gctl_get_asciiparam(req, "fmtopt");
2037234940Smav	if (fmtopt == NULL || strcasecmp(fmtopt, "BE") == 0)
2038234940Smav		be = 1;
2039234940Smav	else if (strcasecmp(fmtopt, "LE") == 0)
2040234940Smav		be = 0;
2041234940Smav	else {
2042234940Smav		gctl_error(req, "Incorrect fmtopt argument.");
2043234940Smav		return (G_RAID_MD_TASTE_FAIL);
2044234940Smav	}
2045234940Smav
2046234848Smav	/* Search for existing node. */
2047234848Smav	LIST_FOREACH(geom, &mp->geom, geom) {
2048234848Smav		sc = geom->softc;
2049234848Smav		if (sc == NULL)
2050234848Smav			continue;
2051234848Smav		if (sc->sc_stopping != 0)
2052234848Smav			continue;
2053234848Smav		if (sc->sc_md->mdo_class != md->mdo_class)
2054234848Smav			continue;
2055234940Smav		mdi1 = (struct g_raid_md_ddf_object *)sc->sc_md;
2056234940Smav		if (mdi1->mdio_bigendian != be)
2057234940Smav			continue;
2058234848Smav		break;
2059234848Smav	}
2060234848Smav	if (geom != NULL) {
2061234848Smav		*gp = geom;
2062234848Smav		return (G_RAID_MD_TASTE_EXISTING);
2063234848Smav	}
2064234848Smav
2065234848Smav	/* Create new one if not found. */
2066234940Smav	mdi->mdio_bigendian = be;
2067234940Smav	snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
2068234940Smav	sc = g_raid_create_node(mp, name, md);
2069234848Smav	if (sc == NULL)
2070234848Smav		return (G_RAID_MD_TASTE_FAIL);
2071234848Smav	md->mdo_softc = sc;
2072234848Smav	*gp = sc->sc_geom;
2073234848Smav	return (G_RAID_MD_TASTE_NEW);
2074234848Smav}
2075234848Smav
2076234848Smavstatic int
2077234848Smavg_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
2078234848Smav                              struct g_consumer *cp, struct g_geom **gp)
2079234848Smav{
2080234848Smav	struct g_consumer *rcp;
2081234848Smav	struct g_provider *pp;
2082234848Smav	struct g_raid_softc *sc;
2083234848Smav	struct g_raid_disk *disk;
2084234848Smav	struct ddf_meta meta;
2085234848Smav	struct g_raid_md_ddf_perdisk *pd;
2086234940Smav	struct g_raid_md_ddf_object *mdi;
2087234848Smav	struct g_geom *geom;
2088234940Smav	int error, result, len, be;
2089234848Smav	char name[16];
2090234848Smav
2091234848Smav	G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name);
2092234940Smav	mdi = (struct g_raid_md_ddf_object *)md;
2093234848Smav	pp = cp->provider;
2094234848Smav
2095234848Smav	/* Read metadata from device. */
2096234848Smav	if (g_access(cp, 1, 0, 0) != 0)
2097234848Smav		return (G_RAID_MD_TASTE_FAIL);
2098234848Smav	g_topology_unlock();
2099234848Smav	bzero(&meta, sizeof(meta));
2100234848Smav	error = ddf_meta_read(cp, &meta);
2101234848Smav	g_topology_lock();
2102234848Smav	g_access(cp, -1, 0, 0);
2103234848Smav	if (error != 0)
2104234848Smav		return (G_RAID_MD_TASTE_FAIL);
2105234940Smav	be = meta.bigendian;
2106234848Smav
2107234848Smav	/* Metadata valid. Print it. */
2108234848Smav	g_raid_md_ddf_print(&meta);
2109234848Smav
2110234848Smav	/* Search for matching node. */
2111234848Smav	sc = NULL;
2112234848Smav	LIST_FOREACH(geom, &mp->geom, geom) {
2113234848Smav		sc = geom->softc;
2114234848Smav		if (sc == NULL)
2115234848Smav			continue;
2116234848Smav		if (sc->sc_stopping != 0)
2117234848Smav			continue;
2118234848Smav		if (sc->sc_md->mdo_class != md->mdo_class)
2119234848Smav			continue;
2120234940Smav		mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
2121234940Smav		if (mdi->mdio_bigendian != be)
2122234940Smav			continue;
2123234848Smav		break;
2124234848Smav	}
2125234848Smav
2126234848Smav	/* Found matching node. */
2127234848Smav	if (geom != NULL) {
2128234848Smav		G_RAID_DEBUG(1, "Found matching array %s", sc->sc_name);
2129234848Smav		result = G_RAID_MD_TASTE_EXISTING;
2130234848Smav
2131234848Smav	} else { /* Not found matching node -- create one. */
2132234848Smav		result = G_RAID_MD_TASTE_NEW;
2133234940Smav		mdi->mdio_bigendian = be;
2134234940Smav		snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
2135234848Smav		sc = g_raid_create_node(mp, name, md);
2136234848Smav		md->mdo_softc = sc;
2137234848Smav		geom = sc->sc_geom;
2138234848Smav	}
2139234848Smav
2140234848Smav	rcp = g_new_consumer(geom);
2141234848Smav	g_attach(rcp, pp);
2142234848Smav	if (g_access(rcp, 1, 1, 1) != 0)
2143234848Smav		; //goto fail1;
2144234848Smav
2145234848Smav	g_topology_unlock();
2146234848Smav	sx_xlock(&sc->sc_lock);
2147234848Smav
2148234848Smav	pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2149234848Smav	pd->pd_meta = meta;
2150234848Smav	disk = g_raid_create_disk(sc);
2151234848Smav	disk->d_md_data = (void *)pd;
2152234848Smav	disk->d_consumer = rcp;
2153234848Smav	rcp->private = disk;
2154234848Smav
2155234848Smav	/* Read kernel dumping information. */
2156234848Smav	disk->d_kd.offset = 0;
2157234848Smav	disk->d_kd.length = OFF_MAX;
2158234848Smav	len = sizeof(disk->d_kd);
2159234848Smav	error = g_io_getattr("GEOM::kerneldump", rcp, &len, &disk->d_kd);
2160234848Smav	if (disk->d_kd.di.dumper == NULL)
2161234848Smav		G_RAID_DEBUG1(2, sc, "Dumping not supported by %s: %d.",
2162234848Smav		    rcp->provider->name, error);
2163234848Smav
2164234848Smav	g_raid_md_ddf_new_disk(disk);
2165234848Smav
2166234848Smav	sx_xunlock(&sc->sc_lock);
2167234848Smav	g_topology_lock();
2168234848Smav	*gp = geom;
2169234848Smav	return (result);
2170234848Smav}
2171234848Smav
2172234848Smavstatic int
2173234848Smavg_raid_md_event_ddf(struct g_raid_md_object *md,
2174234848Smav    struct g_raid_disk *disk, u_int event)
2175234848Smav{
2176234848Smav	struct g_raid_softc *sc;
2177234848Smav
2178234848Smav	sc = md->mdo_softc;
2179234848Smav	if (disk == NULL)
2180234848Smav		return (-1);
2181234848Smav	switch (event) {
2182234848Smav	case G_RAID_DISK_E_DISCONNECTED:
2183234848Smav		/* Delete disk. */
2184234848Smav		g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE);
2185234848Smav		g_raid_destroy_disk(disk);
2186234848Smav		g_raid_md_ddf_purge_volumes(sc);
2187234848Smav
2188234848Smav		/* Write updated metadata to all disks. */
2189234848Smav		g_raid_md_write_ddf(md, NULL, NULL, NULL);
2190234848Smav
2191234848Smav		/* Check if anything left. */
2192234848Smav		if (g_raid_ndisks(sc, -1) == 0)
2193234848Smav			g_raid_destroy_node(sc, 0);
2194234848Smav		else
2195234848Smav			g_raid_md_ddf_refill(sc);
2196234848Smav		return (0);
2197234848Smav	}
2198234848Smav	return (-2);
2199234848Smav}
2200234848Smav
2201234848Smavstatic int
2202234848Smavg_raid_md_volume_event_ddf(struct g_raid_md_object *md,
2203234848Smav    struct g_raid_volume *vol, u_int event)
2204234848Smav{
2205234848Smav	struct g_raid_md_ddf_pervolume *pv;
2206234848Smav
2207234848Smav	pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2208234848Smav	switch (event) {
2209234848Smav	case G_RAID_VOLUME_E_STARTMD:
2210234848Smav		if (!pv->pv_started)
2211234848Smav			g_raid_md_ddf_start(vol);
2212234848Smav		return (0);
2213234848Smav	}
2214234848Smav	return (-2);
2215234848Smav}
2216234848Smav
2217234848Smavstatic int
2218234848Smavg_raid_md_ctl_ddf(struct g_raid_md_object *md,
2219234848Smav    struct gctl_req *req)
2220234848Smav{
2221234848Smav	struct g_raid_softc *sc;
2222234848Smav	struct g_raid_volume *vol, *vol1;
2223234848Smav	struct g_raid_subdisk *sd;
2224234848Smav	struct g_raid_disk *disk, *disks[DDF_MAX_DISKS_HARD];
2225234848Smav	struct g_raid_md_ddf_perdisk *pd;
2226234848Smav	struct g_raid_md_ddf_pervolume *pv;
2227234848Smav	struct g_raid_md_ddf_object *mdi;
2228234899Smav	struct ddf_sa_record *sa;
2229234848Smav	struct g_consumer *cp;
2230234848Smav	struct g_provider *pp;
2231234848Smav	char arg[16];
2232234848Smav	const char *verb, *volname, *levelname, *diskname;
2233234848Smav	char *tmp;
2234234848Smav	int *nargs, *force;
2235234848Smav	off_t size, sectorsize, strip, offs[DDF_MAX_DISKS_HARD], esize;
2236234848Smav	intmax_t *sizearg, *striparg;
2237234848Smav	int i, numdisks, len, level, qual;
2238234848Smav	int error;
2239234848Smav
2240234848Smav	sc = md->mdo_softc;
2241234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
2242234848Smav	verb = gctl_get_param(req, "verb", NULL);
2243234848Smav	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
2244234848Smav	error = 0;
2245234848Smav
2246234848Smav	if (strcmp(verb, "label") == 0) {
2247234848Smav
2248234848Smav		if (*nargs < 4) {
2249234848Smav			gctl_error(req, "Invalid number of arguments.");
2250234848Smav			return (-1);
2251234848Smav		}
2252234848Smav		volname = gctl_get_asciiparam(req, "arg1");
2253234848Smav		if (volname == NULL) {
2254234848Smav			gctl_error(req, "No volume name.");
2255234848Smav			return (-2);
2256234848Smav		}
2257234848Smav		levelname = gctl_get_asciiparam(req, "arg2");
2258234848Smav		if (levelname == NULL) {
2259234848Smav			gctl_error(req, "No RAID level.");
2260234848Smav			return (-3);
2261234848Smav		}
2262234848Smav		if (g_raid_volume_str2level(levelname, &level, &qual)) {
2263234848Smav			gctl_error(req, "Unknown RAID level '%s'.", levelname);
2264234848Smav			return (-4);
2265234848Smav		}
2266234848Smav		numdisks = *nargs - 3;
2267234848Smav		force = gctl_get_paraml(req, "force", sizeof(*force));
2268234848Smav		if (!g_raid_md_ddf_supported(level, qual, numdisks,
2269234848Smav		    force ? *force : 0)) {
2270234848Smav			gctl_error(req, "Unsupported RAID level "
2271234848Smav			    "(0x%02x/0x%02x), or number of disks (%d).",
2272234848Smav			    level, qual, numdisks);
2273234848Smav			return (-5);
2274234848Smav		}
2275234848Smav
2276234848Smav		/* Search for disks, connect them and probe. */
2277234848Smav		size = INT64_MAX;
2278234848Smav		sectorsize = 0;
2279234848Smav		bzero(disks, sizeof(disks));
2280234848Smav		bzero(offs, sizeof(offs));
2281234848Smav		for (i = 0; i < numdisks; i++) {
2282234848Smav			snprintf(arg, sizeof(arg), "arg%d", i + 3);
2283234848Smav			diskname = gctl_get_asciiparam(req, arg);
2284234848Smav			if (diskname == NULL) {
2285234848Smav				gctl_error(req, "No disk name (%s).", arg);
2286234848Smav				error = -6;
2287234848Smav				break;
2288234848Smav			}
2289234848Smav			if (strcmp(diskname, "NONE") == 0)
2290234848Smav				continue;
2291234848Smav
2292234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2293234848Smav				if (disk->d_consumer != NULL &&
2294234848Smav				    disk->d_consumer->provider != NULL &&
2295234848Smav				    strcmp(disk->d_consumer->provider->name,
2296234848Smav				     diskname) == 0)
2297234848Smav					break;
2298234848Smav			}
2299234848Smav			if (disk != NULL) {
2300234848Smav				if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
2301234848Smav					gctl_error(req, "Disk '%s' is in a "
2302234848Smav					    "wrong state (%s).", diskname,
2303234848Smav					    g_raid_disk_state2str(disk->d_state));
2304234848Smav					error = -7;
2305234848Smav					break;
2306234848Smav				}
2307234848Smav				pd = disk->d_md_data;
2308234848Smav				if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
2309234848Smav				    GET16(&pd->pd_meta, hdr->Max_Partitions)) {
2310234848Smav					gctl_error(req, "No free partitions "
2311234848Smav					    "on disk '%s'.",
2312234848Smav					    diskname);
2313234848Smav					error = -7;
2314234848Smav					break;
2315234848Smav				}
2316234848Smav				pp = disk->d_consumer->provider;
2317234848Smav				disks[i] = disk;
2318234848Smav				ddf_meta_unused_range(&pd->pd_meta,
2319234848Smav				    &offs[i], &esize);
2320234848Smav				size = MIN(size, (off_t)esize * pp->sectorsize);
2321234848Smav				sectorsize = MAX(sectorsize, pp->sectorsize);
2322234848Smav				continue;
2323234848Smav			}
2324234848Smav
2325234848Smav			g_topology_lock();
2326234848Smav			cp = g_raid_open_consumer(sc, diskname);
2327234848Smav			if (cp == NULL) {
2328234848Smav				gctl_error(req, "Can't open disk '%s'.",
2329234848Smav				    diskname);
2330234848Smav				g_topology_unlock();
2331234848Smav				error = -8;
2332234848Smav				break;
2333234848Smav			}
2334234848Smav			pp = cp->provider;
2335234848Smav			pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2336234848Smav			disk = g_raid_create_disk(sc);
2337234848Smav			disk->d_md_data = (void *)pd;
2338234848Smav			disk->d_consumer = cp;
2339234848Smav			disks[i] = disk;
2340234848Smav			cp->private = disk;
2341234848Smav			ddf_meta_create(disk, &mdi->mdio_meta);
2342234848Smav			if (mdi->mdio_meta.hdr == NULL)
2343234848Smav				ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
2344234848Smav			else
2345234848Smav				ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
2346234848Smav			g_topology_unlock();
2347234848Smav
2348234848Smav			/* Read kernel dumping information. */
2349234848Smav			disk->d_kd.offset = 0;
2350234848Smav			disk->d_kd.length = OFF_MAX;
2351234848Smav			len = sizeof(disk->d_kd);
2352234848Smav			g_io_getattr("GEOM::kerneldump", cp, &len, &disk->d_kd);
2353234848Smav			if (disk->d_kd.di.dumper == NULL)
2354234848Smav				G_RAID_DEBUG1(2, sc,
2355234848Smav				    "Dumping not supported by %s.",
2356234848Smav				    cp->provider->name);
2357234848Smav
2358234848Smav			/* Reserve some space for metadata. */
2359234848Smav			size = MIN(size, pp->mediasize - 131072llu * pp->sectorsize);
2360234848Smav			sectorsize = MAX(sectorsize, pp->sectorsize);
2361234848Smav		}
2362234848Smav		if (error != 0) {
2363234848Smav			for (i = 0; i < numdisks; i++) {
2364234848Smav				if (disks[i] != NULL &&
2365234848Smav				    disks[i]->d_state == G_RAID_DISK_S_NONE)
2366234848Smav					g_raid_destroy_disk(disks[i]);
2367234848Smav			}
2368234848Smav			return (error);
2369234848Smav		}
2370234848Smav
2371234848Smav		if (sectorsize <= 0) {
2372234848Smav			gctl_error(req, "Can't get sector size.");
2373234848Smav			return (-8);
2374234848Smav		}
2375234848Smav
2376234848Smav		/* Handle size argument. */
2377234848Smav		len = sizeof(*sizearg);
2378234848Smav		sizearg = gctl_get_param(req, "size", &len);
2379234848Smav		if (sizearg != NULL && len == sizeof(*sizearg) &&
2380234848Smav		    *sizearg > 0) {
2381234848Smav			if (*sizearg > size) {
2382234848Smav				gctl_error(req, "Size too big %lld > %lld.",
2383234848Smav				    (long long)*sizearg, (long long)size);
2384234848Smav				return (-9);
2385234848Smav			}
2386234848Smav			size = *sizearg;
2387234848Smav		}
2388234848Smav
2389234848Smav		/* Handle strip argument. */
2390234848Smav		strip = 131072;
2391234848Smav		len = sizeof(*striparg);
2392234848Smav		striparg = gctl_get_param(req, "strip", &len);
2393234848Smav		if (striparg != NULL && len == sizeof(*striparg) &&
2394234848Smav		    *striparg > 0) {
2395234848Smav			if (*striparg < sectorsize) {
2396234848Smav				gctl_error(req, "Strip size too small.");
2397234848Smav				return (-10);
2398234848Smav			}
2399234848Smav			if (*striparg % sectorsize != 0) {
2400234848Smav				gctl_error(req, "Incorrect strip size.");
2401234848Smav				return (-11);
2402234848Smav			}
2403234848Smav			strip = *striparg;
2404234848Smav		}
2405234848Smav
2406234848Smav		/* Round size down to strip or sector. */
2407234848Smav		if (level == G_RAID_VOLUME_RL_RAID1 ||
2408234848Smav		    level == G_RAID_VOLUME_RL_RAID3 ||
2409234848Smav		    level == G_RAID_VOLUME_RL_SINGLE ||
2410234848Smav		    level == G_RAID_VOLUME_RL_CONCAT)
2411234848Smav			size -= (size % sectorsize);
2412234848Smav		else if (level == G_RAID_VOLUME_RL_RAID1E &&
2413234848Smav		    (numdisks & 1) != 0)
2414234848Smav			size -= (size % (2 * strip));
2415234848Smav		else
2416234848Smav			size -= (size % strip);
2417234848Smav		if (size <= 0) {
2418234848Smav			gctl_error(req, "Size too small.");
2419234848Smav			return (-13);
2420234848Smav		}
2421234848Smav
2422234848Smav		/* We have all we need, create things: volume, ... */
2423234848Smav		pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
2424234848Smav		ddf_vol_meta_create(&pv->pv_meta, &mdi->mdio_meta);
2425234848Smav		pv->pv_started = 1;
2426234848Smav		vol = g_raid_create_volume(sc, volname, -1);
2427234848Smav		vol->v_md_data = pv;
2428234848Smav		vol->v_raid_level = level;
2429234848Smav		vol->v_raid_level_qualifier = qual;
2430234848Smav		vol->v_strip_size = strip;
2431234848Smav		vol->v_disks_count = numdisks;
2432234848Smav		if (level == G_RAID_VOLUME_RL_RAID0 ||
2433234848Smav		    level == G_RAID_VOLUME_RL_CONCAT ||
2434234848Smav		    level == G_RAID_VOLUME_RL_SINGLE)
2435234848Smav			vol->v_mediasize = size * numdisks;
2436234848Smav		else if (level == G_RAID_VOLUME_RL_RAID1)
2437234848Smav			vol->v_mediasize = size;
2438234848Smav		else if (level == G_RAID_VOLUME_RL_RAID3 ||
2439234848Smav		    level == G_RAID_VOLUME_RL_RAID4 ||
2440235076Smav		    level == G_RAID_VOLUME_RL_RAID5)
2441234848Smav			vol->v_mediasize = size * (numdisks - 1);
2442235076Smav		else if (level == G_RAID_VOLUME_RL_RAID5R) {
2443235076Smav			vol->v_mediasize = size * (numdisks - 1);
2444235076Smav			vol->v_rotate_parity = 1024;
2445235076Smav		} else if (level == G_RAID_VOLUME_RL_RAID6 ||
2446234848Smav		    level == G_RAID_VOLUME_RL_RAID5E ||
2447234848Smav		    level == G_RAID_VOLUME_RL_RAID5EE)
2448234848Smav			vol->v_mediasize = size * (numdisks - 2);
2449235076Smav		else if (level == G_RAID_VOLUME_RL_RAIDMDF) {
2450235076Smav			if (numdisks < 5)
2451235076Smav				vol->v_mdf_pdisks = 2;
2452235076Smav			else
2453235076Smav				vol->v_mdf_pdisks = 3;
2454235076Smav			vol->v_mdf_polynomial = 0x11d;
2455235076Smav			vol->v_mdf_method = 0x00;
2456235076Smav			vol->v_mediasize = size * (numdisks - vol->v_mdf_pdisks);
2457235076Smav		} else { /* RAID1E */
2458234848Smav			vol->v_mediasize = ((size * numdisks) / strip / 2) *
2459234848Smav			    strip;
2460234848Smav		}
2461234848Smav		vol->v_sectorsize = sectorsize;
2462234848Smav		g_raid_start_volume(vol);
2463234848Smav
2464234848Smav		/* , and subdisks. */
2465234848Smav		for (i = 0; i < numdisks; i++) {
2466234848Smav			disk = disks[i];
2467234848Smav			sd = &vol->v_subdisks[i];
2468234848Smav			sd->sd_disk = disk;
2469234848Smav			sd->sd_offset = (off_t)offs[i] * 512;
2470234848Smav			sd->sd_size = size;
2471234848Smav			if (disk == NULL)
2472234848Smav				continue;
2473234848Smav			TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
2474234848Smav			g_raid_change_disk_state(disk,
2475234848Smav			    G_RAID_DISK_S_ACTIVE);
2476234848Smav			g_raid_change_subdisk_state(sd,
2477234848Smav			    G_RAID_SUBDISK_S_ACTIVE);
2478234848Smav			g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
2479234848Smav			    G_RAID_EVENT_SUBDISK);
2480234848Smav		}
2481234848Smav
2482234848Smav		/* Write metadata based on created entities. */
2483234848Smav		G_RAID_DEBUG1(0, sc, "Array started.");
2484234848Smav		g_raid_md_write_ddf(md, vol, NULL, NULL);
2485234848Smav
2486234848Smav		/* Pickup any STALE/SPARE disks to refill array if needed. */
2487234848Smav		g_raid_md_ddf_refill(sc);
2488234848Smav
2489234848Smav		g_raid_event_send(vol, G_RAID_VOLUME_E_START,
2490234848Smav		    G_RAID_EVENT_VOLUME);
2491234848Smav		return (0);
2492234848Smav	}
2493234848Smav	if (strcmp(verb, "add") == 0) {
2494234848Smav
2495234848Smav		gctl_error(req, "`add` command is not applicable, "
2496234848Smav		    "use `label` instead.");
2497234848Smav		return (-99);
2498234848Smav	}
2499234848Smav	if (strcmp(verb, "delete") == 0) {
2500234848Smav
2501234848Smav		/* Full node destruction. */
2502234848Smav		if (*nargs == 1) {
2503234848Smav			/* Check if some volume is still open. */
2504234848Smav			force = gctl_get_paraml(req, "force", sizeof(*force));
2505234848Smav			if (force != NULL && *force == 0 &&
2506234848Smav			    g_raid_nopens(sc) != 0) {
2507234848Smav				gctl_error(req, "Some volume is still open.");
2508234848Smav				return (-4);
2509234848Smav			}
2510234848Smav
2511234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2512234848Smav				if (disk->d_consumer)
2513234848Smav					ddf_meta_erase(disk->d_consumer);
2514234848Smav			}
2515234848Smav			g_raid_destroy_node(sc, 0);
2516234848Smav			return (0);
2517234848Smav		}
2518234848Smav
2519234848Smav		/* Destroy specified volume. If it was last - all node. */
2520234848Smav		if (*nargs != 2) {
2521234848Smav			gctl_error(req, "Invalid number of arguments.");
2522234848Smav			return (-1);
2523234848Smav		}
2524234848Smav		volname = gctl_get_asciiparam(req, "arg1");
2525234848Smav		if (volname == NULL) {
2526234848Smav			gctl_error(req, "No volume name.");
2527234848Smav			return (-2);
2528234848Smav		}
2529234848Smav
2530234848Smav		/* Search for volume. */
2531234848Smav		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2532234848Smav			if (strcmp(vol->v_name, volname) == 0)
2533234848Smav				break;
2534234848Smav		}
2535234848Smav		if (vol == NULL) {
2536234848Smav			i = strtol(volname, &tmp, 10);
2537234848Smav			if (verb != volname && tmp[0] == 0) {
2538234848Smav				TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2539234848Smav					if (vol->v_global_id == i)
2540234848Smav						break;
2541234848Smav				}
2542234848Smav			}
2543234848Smav		}
2544234848Smav		if (vol == NULL) {
2545234848Smav			gctl_error(req, "Volume '%s' not found.", volname);
2546234848Smav			return (-3);
2547234848Smav		}
2548234848Smav
2549234848Smav		/* Check if volume is still open. */
2550234848Smav		force = gctl_get_paraml(req, "force", sizeof(*force));
2551234848Smav		if (force != NULL && *force == 0 &&
2552234848Smav		    vol->v_provider_open != 0) {
2553234848Smav			gctl_error(req, "Volume is still open.");
2554234848Smav			return (-4);
2555234848Smav		}
2556234848Smav
2557234848Smav		/* Destroy volume and potentially node. */
2558234848Smav		i = 0;
2559234848Smav		TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next)
2560234848Smav			i++;
2561234848Smav		if (i >= 2) {
2562234848Smav			g_raid_destroy_volume(vol);
2563234848Smav			g_raid_md_ddf_purge_disks(sc);
2564234848Smav			g_raid_md_write_ddf(md, NULL, NULL, NULL);
2565234848Smav		} else {
2566234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2567234848Smav				if (disk->d_consumer)
2568234848Smav					ddf_meta_erase(disk->d_consumer);
2569234848Smav			}
2570234848Smav			g_raid_destroy_node(sc, 0);
2571234848Smav		}
2572234848Smav		return (0);
2573234848Smav	}
2574234848Smav	if (strcmp(verb, "remove") == 0 ||
2575234848Smav	    strcmp(verb, "fail") == 0) {
2576234848Smav		if (*nargs < 2) {
2577234848Smav			gctl_error(req, "Invalid number of arguments.");
2578234848Smav			return (-1);
2579234848Smav		}
2580234848Smav		for (i = 1; i < *nargs; i++) {
2581234848Smav			snprintf(arg, sizeof(arg), "arg%d", i);
2582234848Smav			diskname = gctl_get_asciiparam(req, arg);
2583234848Smav			if (diskname == NULL) {
2584234848Smav				gctl_error(req, "No disk name (%s).", arg);
2585234848Smav				error = -2;
2586234848Smav				break;
2587234848Smav			}
2588234848Smav			if (strncmp(diskname, "/dev/", 5) == 0)
2589234848Smav				diskname += 5;
2590234848Smav
2591234848Smav			TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2592234848Smav				if (disk->d_consumer != NULL &&
2593234848Smav				    disk->d_consumer->provider != NULL &&
2594234848Smav				    strcmp(disk->d_consumer->provider->name,
2595234848Smav				     diskname) == 0)
2596234848Smav					break;
2597234848Smav			}
2598234848Smav			if (disk == NULL) {
2599234848Smav				gctl_error(req, "Disk '%s' not found.",
2600234848Smav				    diskname);
2601234848Smav				error = -3;
2602234848Smav				break;
2603234848Smav			}
2604234848Smav
2605234848Smav			if (strcmp(verb, "fail") == 0) {
2606234848Smav				g_raid_md_fail_disk_ddf(md, NULL, disk);
2607234848Smav				continue;
2608234848Smav			}
2609234848Smav
2610234848Smav			/* Erase metadata on deleting disk and destroy it. */
2611234848Smav			ddf_meta_erase(disk->d_consumer);
2612234848Smav			g_raid_destroy_disk(disk);
2613234848Smav		}
2614234848Smav		g_raid_md_ddf_purge_volumes(sc);
2615234848Smav
2616234848Smav		/* Write updated metadata to remaining disks. */
2617234848Smav		g_raid_md_write_ddf(md, NULL, NULL, NULL);
2618234848Smav
2619234848Smav		/* Check if anything left. */
2620234848Smav		if (g_raid_ndisks(sc, -1) == 0)
2621234848Smav			g_raid_destroy_node(sc, 0);
2622234848Smav		else
2623234848Smav			g_raid_md_ddf_refill(sc);
2624234848Smav		return (error);
2625234848Smav	}
2626234848Smav	if (strcmp(verb, "insert") == 0) {
2627234848Smav		if (*nargs < 2) {
2628234848Smav			gctl_error(req, "Invalid number of arguments.");
2629234848Smav			return (-1);
2630234848Smav		}
2631234848Smav		for (i = 1; i < *nargs; i++) {
2632234848Smav			/* Get disk name. */
2633234848Smav			snprintf(arg, sizeof(arg), "arg%d", i);
2634234848Smav			diskname = gctl_get_asciiparam(req, arg);
2635234848Smav			if (diskname == NULL) {
2636234848Smav				gctl_error(req, "No disk name (%s).", arg);
2637234848Smav				error = -3;
2638234848Smav				break;
2639234848Smav			}
2640234848Smav
2641234848Smav			/* Try to find provider with specified name. */
2642234848Smav			g_topology_lock();
2643234848Smav			cp = g_raid_open_consumer(sc, diskname);
2644234848Smav			if (cp == NULL) {
2645234848Smav				gctl_error(req, "Can't open disk '%s'.",
2646234848Smav				    diskname);
2647234848Smav				g_topology_unlock();
2648234848Smav				error = -4;
2649234848Smav				break;
2650234848Smav			}
2651234848Smav			pp = cp->provider;
2652234848Smav			g_topology_unlock();
2653234848Smav
2654234848Smav			pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
2655234848Smav
2656234848Smav			disk = g_raid_create_disk(sc);
2657234848Smav			disk->d_consumer = cp;
2658234848Smav			disk->d_md_data = (void *)pd;
2659234848Smav			cp->private = disk;
2660234848Smav
2661234848Smav			/* Read kernel dumping information. */
2662234848Smav			disk->d_kd.offset = 0;
2663234848Smav			disk->d_kd.length = OFF_MAX;
2664234848Smav			len = sizeof(disk->d_kd);
2665234848Smav			g_io_getattr("GEOM::kerneldump", cp, &len, &disk->d_kd);
2666234848Smav			if (disk->d_kd.di.dumper == NULL)
2667234848Smav				G_RAID_DEBUG1(2, sc,
2668234848Smav				    "Dumping not supported by %s.",
2669234848Smav				    cp->provider->name);
2670234848Smav
2671234848Smav			/* Welcome the "new" disk. */
2672234848Smav			g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
2673234848Smav			ddf_meta_create(disk, &mdi->mdio_meta);
2674234899Smav			sa = ddf_meta_find_sa(&pd->pd_meta, 1);
2675234899Smav			if (sa != NULL) {
2676234899Smav				SET32D(&pd->pd_meta, sa->Signature,
2677234899Smav				    DDF_SA_SIGNATURE);
2678234899Smav				SET8D(&pd->pd_meta, sa->Spare_Type, 0);
2679234899Smav				SET16D(&pd->pd_meta, sa->Populated_SAEs, 0);
2680234899Smav				SET16D(&pd->pd_meta, sa->MAX_SAE_Supported,
2681234899Smav				    (GET16(&pd->pd_meta, hdr->Configuration_Record_Length) *
2682234899Smav				     pd->pd_meta.sectorsize -
2683234899Smav				     sizeof(struct ddf_sa_record)) /
2684234899Smav				    sizeof(struct ddf_sa_entry));
2685234899Smav			}
2686234848Smav			if (mdi->mdio_meta.hdr == NULL)
2687234848Smav				ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
2688234848Smav			else
2689234848Smav				ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
2690234899Smav			g_raid_md_write_ddf(md, NULL, NULL, NULL);
2691234848Smav			g_raid_md_ddf_refill(sc);
2692234848Smav		}
2693234848Smav		return (error);
2694234848Smav	}
2695234848Smav	return (-100);
2696234848Smav}
2697234848Smav
2698234848Smavstatic int
2699234848Smavg_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
2700234848Smav    struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
2701234848Smav{
2702234848Smav	struct g_raid_softc *sc;
2703234848Smav	struct g_raid_volume *vol;
2704234848Smav	struct g_raid_subdisk *sd;
2705234848Smav	struct g_raid_disk *disk;
2706234848Smav	struct g_raid_md_ddf_perdisk *pd;
2707234848Smav	struct g_raid_md_ddf_pervolume *pv;
2708234848Smav	struct g_raid_md_ddf_object *mdi;
2709234848Smav	struct ddf_meta *gmeta;
2710234848Smav	struct ddf_vol_meta *vmeta;
2711234848Smav	struct ddf_vdc_record *vdc;
2712234899Smav	struct ddf_sa_record *sa;
2713234848Smav	uint64_t *val2;
2714234848Smav	int i, j, pos, bvd, size;
2715234848Smav
2716234848Smav	sc = md->mdo_softc;
2717234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
2718234848Smav	gmeta = &mdi->mdio_meta;
2719234848Smav
2720234848Smav	if (sc->sc_stopping == G_RAID_DESTROY_HARD)
2721234848Smav		return (0);
2722234848Smav
2723234868Smav	/*
2724234868Smav	 * Clear disk flags to let only really needed ones to be reset.
2725234868Smav	 * Do it only if there are no volumes in starting state now,
2726234868Smav	 * as they can update disk statuses yet and we may kill innocent.
2727234868Smav	 */
2728234868Smav	if (mdi->mdio_starting == 0) {
2729234868Smav		for (i = 0; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
2730234868Smav			if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
2731234848Smav				continue;
2732234868Smav			SET16(gmeta, pdr->entry[i].PD_Type,
2733234868Smav			    GET16(gmeta, pdr->entry[i].PD_Type) &
2734234899Smav			    ~(DDF_PDE_PARTICIPATING |
2735234899Smav			      DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE));
2736234868Smav			if ((GET16(gmeta, pdr->entry[i].PD_State) &
2737234868Smav			    DDF_PDE_PFA) == 0)
2738234868Smav				SET16(gmeta, pdr->entry[i].PD_State, 0);
2739234848Smav		}
2740234868Smav	}
2741234848Smav
2742234868Smav	/* Generate/update new per-volume metadata. */
2743234868Smav	TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2744234848Smav		pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2745234868Smav		if (vol->v_stopping || !pv->pv_started)
2746234868Smav			continue;
2747234848Smav		vmeta = &pv->pv_meta;
2748234848Smav
2749234848Smav		SET32(vmeta, vdc->Sequence_Number,
2750234848Smav		    GET32(vmeta, vdc->Sequence_Number) + 1);
2751234848Smav		if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
2752234848Smav		    vol->v_disks_count % 2 == 0)
2753234848Smav			SET16(vmeta, vdc->Primary_Element_Count, 2);
2754234848Smav		else
2755234848Smav			SET16(vmeta, vdc->Primary_Element_Count,
2756234848Smav			    vol->v_disks_count);
2757234848Smav		SET8(vmeta, vdc->Stripe_Size,
2758234848Smav		    ffs(vol->v_strip_size / vol->v_sectorsize) - 1);
2759234848Smav		if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
2760234848Smav		    vol->v_disks_count % 2 == 0) {
2761234848Smav			SET8(vmeta, vdc->Primary_RAID_Level,
2762234848Smav			    DDF_VDCR_RAID1);
2763234848Smav			SET8(vmeta, vdc->RLQ, 0);
2764234848Smav			SET8(vmeta, vdc->Secondary_Element_Count,
2765234848Smav			    vol->v_disks_count / 2);
2766234848Smav			SET8(vmeta, vdc->Secondary_RAID_Level, 0);
2767234848Smav		} else {
2768234848Smav			SET8(vmeta, vdc->Primary_RAID_Level,
2769234848Smav			    vol->v_raid_level);
2770234848Smav			SET8(vmeta, vdc->RLQ,
2771234848Smav			    vol->v_raid_level_qualifier);
2772234848Smav			SET8(vmeta, vdc->Secondary_Element_Count, 1);
2773234848Smav			SET8(vmeta, vdc->Secondary_RAID_Level, 0);
2774234848Smav		}
2775234848Smav		SET8(vmeta, vdc->Secondary_Element_Seq, 0);
2776234848Smav		SET64(vmeta, vdc->Block_Count, 0);
2777234848Smav		SET64(vmeta, vdc->VD_Size, vol->v_mediasize / vol->v_sectorsize);
2778234848Smav		SET16(vmeta, vdc->Block_Size, vol->v_sectorsize);
2779235076Smav		SET8(vmeta, vdc->Rotate_Parity_count,
2780235076Smav		    fls(vol->v_rotate_parity) - 1);
2781235076Smav		SET8(vmeta, vdc->MDF_Parity_Disks, vol->v_mdf_pdisks);
2782235076Smav		SET16(vmeta, vdc->MDF_Parity_Generator_Polynomial,
2783235076Smav		    vol->v_mdf_polynomial);
2784235076Smav		SET8(vmeta, vdc->MDF_Constant_Generation_Method,
2785235076Smav		    vol->v_mdf_method);
2786234848Smav
2787234848Smav		SET16(vmeta, vde->VD_Number, vol->v_global_id);
2788234848Smav		if (vol->v_state <= G_RAID_VOLUME_S_BROKEN)
2789234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_FAILED);
2790234848Smav		else if (vol->v_state <= G_RAID_VOLUME_S_DEGRADED)
2791234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_DEGRADED);
2792234848Smav		else if (vol->v_state <= G_RAID_VOLUME_S_SUBOPTIMAL)
2793234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_PARTIAL);
2794234848Smav		else
2795234848Smav			SET8(vmeta, vde->VD_State, DDF_VDE_OPTIMAL);
2796234868Smav		if (vol->v_dirty ||
2797234868Smav		    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_STALE) > 0 ||
2798234868Smav		    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_RESYNC) > 0)
2799234848Smav			SET8(vmeta, vde->VD_State,
2800234848Smav			    GET8(vmeta, vde->VD_State) | DDF_VDE_DIRTY);
2801234848Smav		SET8(vmeta, vde->Init_State, DDF_VDE_INIT_FULL); // XXX
2802234848Smav		ddf_meta_put_name(vmeta, vol->v_name);
2803234848Smav
2804234848Smav		for (i = 0; i < vol->v_disks_count; i++) {
2805234848Smav			sd = &vol->v_subdisks[i];
2806234848Smav			bvd = i / GET16(vmeta, vdc->Primary_Element_Count);
2807234848Smav			pos = i % GET16(vmeta, vdc->Primary_Element_Count);
2808234868Smav			disk = sd->sd_disk;
2809234868Smav			if (disk != NULL) {
2810234868Smav				pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2811234868Smav				if (vmeta->bvdc[bvd] == NULL) {
2812234868Smav					size = GET16(vmeta,
2813234868Smav					    hdr->Configuration_Record_Length) *
2814234868Smav					    vmeta->sectorsize;
2815234868Smav					vmeta->bvdc[bvd] = malloc(size,
2816234868Smav					    M_MD_DDF, M_WAITOK);
2817234868Smav					memset(vmeta->bvdc[bvd], 0xff, size);
2818234868Smav				}
2819234868Smav				memcpy(vmeta->bvdc[bvd], vmeta->vdc,
2820234868Smav				    sizeof(struct ddf_vdc_record));
2821234848Smav				SET8(vmeta, bvdc[bvd]->Secondary_Element_Seq, bvd);
2822234868Smav				SET64(vmeta, bvdc[bvd]->Block_Count,
2823234868Smav				    sd->sd_size / vol->v_sectorsize);
2824234868Smav				SET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos],
2825234868Smav				    GET32(&pd->pd_meta, pdd->PD_Reference));
2826234868Smav				val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
2827234868Smav				    GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
2828234868Smav				SET64P(vmeta, val2 + pos,
2829234868Smav				    sd->sd_offset / vol->v_sectorsize);
2830234848Smav			}
2831234868Smav			if (vmeta->bvdc[bvd] == NULL)
2832234868Smav				continue;
2833234848Smav
2834234848Smav			j = ddf_meta_find_pd(gmeta, NULL,
2835234868Smav			    GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]));
2836234848Smav			if (j < 0)
2837234848Smav				continue;
2838234848Smav			SET32(gmeta, pdr->entry[j].PD_Type,
2839234848Smav			    GET32(gmeta, pdr->entry[j].PD_Type) |
2840234848Smav			    DDF_PDE_PARTICIPATING);
2841234868Smav			if (sd->sd_state == G_RAID_SUBDISK_S_NONE)
2842234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2843234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2844234899Smav				    (DDF_PDE_FAILED | DDF_PDE_MISSING));
2845234868Smav			else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED)
2846234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2847234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2848234899Smav				    (DDF_PDE_FAILED | DDF_PDE_PFA));
2849234868Smav			else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD)
2850234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2851234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2852234899Smav				    DDF_PDE_REBUILD);
2853234848Smav			else
2854234848Smav				SET32(gmeta, pdr->entry[j].PD_State,
2855234848Smav				    GET32(gmeta, pdr->entry[j].PD_State) |
2856234848Smav				    DDF_PDE_ONLINE);
2857234848Smav		}
2858234848Smav	}
2859234848Smav
2860234899Smav	/* Mark spare and failed disks as such. */
2861234899Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2862234899Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2863234899Smav		i = ddf_meta_find_pd(gmeta, NULL,
2864234899Smav		    GET32(&pd->pd_meta, pdd->PD_Reference));
2865234899Smav		if (i < 0)
2866234899Smav			continue;
2867234899Smav		if (disk->d_state == G_RAID_DISK_S_FAILED) {
2868234899Smav			SET32(gmeta, pdr->entry[i].PD_State,
2869234899Smav			    GET32(gmeta, pdr->entry[i].PD_State) |
2870234899Smav			    (DDF_PDE_FAILED | DDF_PDE_PFA));
2871234899Smav		}
2872234899Smav		if (disk->d_state != G_RAID_DISK_S_SPARE)
2873234899Smav			continue;
2874234899Smav		sa = ddf_meta_find_sa(&pd->pd_meta, 0);
2875234899Smav		if (sa == NULL ||
2876234899Smav		    (GET8D(&pd->pd_meta, sa->Spare_Type) &
2877234899Smav		     DDF_SAR_TYPE_DEDICATED) == 0) {
2878234899Smav			SET16(gmeta, pdr->entry[i].PD_Type,
2879234899Smav			    GET16(gmeta, pdr->entry[i].PD_Type) |
2880234899Smav			    DDF_PDE_GLOBAL_SPARE);
2881234899Smav		} else {
2882234899Smav			SET16(gmeta, pdr->entry[i].PD_Type,
2883234899Smav			    GET16(gmeta, pdr->entry[i].PD_Type) |
2884234899Smav			    DDF_PDE_CONFIG_SPARE);
2885234899Smav		}
2886234899Smav		SET32(gmeta, pdr->entry[i].PD_State,
2887234899Smav		    GET32(gmeta, pdr->entry[i].PD_State) |
2888234899Smav		    DDF_PDE_ONLINE);
2889234899Smav	}
2890234899Smav
2891234868Smav	/* Remove disks without "participating" flag (unused). */
2892234868Smav	for (i = 0, j = -1; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
2893234868Smav		if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
2894234868Smav			continue;
2895234899Smav		if ((GET16(gmeta, pdr->entry[i].PD_Type) &
2896234899Smav		    (DDF_PDE_PARTICIPATING |
2897234899Smav		     DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)) != 0 ||
2898234899Smav		    g_raid_md_ddf_get_disk(sc,
2899234899Smav		     NULL, GET32(gmeta, pdr->entry[i].PD_Reference)) != NULL)
2900234868Smav			j = i;
2901234868Smav		else
2902234868Smav			memset(&gmeta->pdr->entry[i], 0xff,
2903234868Smav			    sizeof(struct ddf_pd_entry));
2904234868Smav	}
2905234868Smav	SET16(gmeta, pdr->Populated_PDEs, j + 1);
2906234868Smav
2907234868Smav	/* Update per-disk metadata and write them. */
2908234848Smav	TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2909234848Smav		pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2910234899Smav		if (disk->d_state != G_RAID_DISK_S_ACTIVE &&
2911234899Smav		    disk->d_state != G_RAID_DISK_S_SPARE)
2912234848Smav			continue;
2913234868Smav		/* Update PDR. */
2914234848Smav		memcpy(pd->pd_meta.pdr, gmeta->pdr,
2915234848Smav		    GET32(&pd->pd_meta, hdr->pdr_length) *
2916234848Smav		    pd->pd_meta.sectorsize);
2917234868Smav		/* Update VDR. */
2918234868Smav		SET16(&pd->pd_meta, vdr->Populated_VDEs, 0);
2919234868Smav		TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
2920234868Smav			if (vol->v_stopping)
2921234868Smav				continue;
2922234848Smav			pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2923234848Smav			i = ddf_meta_find_vd(&pd->pd_meta,
2924234848Smav			    pv->pv_meta.vde->VD_GUID);
2925234848Smav			if (i < 0)
2926234848Smav				i = ddf_meta_find_vd(&pd->pd_meta, NULL);
2927234848Smav			if (i >= 0)
2928234848Smav				memcpy(&pd->pd_meta.vdr->entry[i],
2929234848Smav				    pv->pv_meta.vde,
2930234848Smav				    sizeof(struct ddf_vd_entry));
2931234868Smav		}
2932234868Smav		/* Update VDC. */
2933234869Smav		if (mdi->mdio_starting == 0) {
2934234869Smav			/* Remove all VDCs to restore needed later. */
2935234869Smav			j = GETCRNUM(&pd->pd_meta);
2936234869Smav			for (i = 0; i < j; i++) {
2937234869Smav				vdc = GETVDCPTR(&pd->pd_meta, i);
2938234869Smav				if (GET32D(&pd->pd_meta, vdc->Signature) !=
2939234869Smav				    DDF_VDCR_SIGNATURE)
2940234869Smav					continue;
2941234869Smav				SET32D(&pd->pd_meta, vdc->Signature, 0xffffffff);
2942234869Smav			}
2943234869Smav		}
2944234868Smav		TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
2945234868Smav			vol = sd->sd_volume;
2946234868Smav			if (vol->v_stopping)
2947234868Smav				continue;
2948234868Smav			pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
2949234868Smav			vmeta = &pv->pv_meta;
2950234848Smav			vdc = ddf_meta_find_vdc(&pd->pd_meta,
2951234868Smav			    vmeta->vde->VD_GUID);
2952234848Smav			if (vdc == NULL)
2953234848Smav				vdc = ddf_meta_find_vdc(&pd->pd_meta, NULL);
2954234848Smav			if (vdc != NULL) {
2955234848Smav				bvd = sd->sd_pos / GET16(vmeta,
2956234848Smav				    vdc->Primary_Element_Count);
2957234868Smav				memcpy(vdc, vmeta->bvdc[bvd],
2958234848Smav				    GET16(&pd->pd_meta,
2959234848Smav				    hdr->Configuration_Record_Length) *
2960234848Smav				    pd->pd_meta.sectorsize);
2961234848Smav			}
2962234848Smav		}
2963234848Smav		G_RAID_DEBUG(1, "Writing DDF metadata to %s",
2964234848Smav		    g_raid_get_diskname(disk));
2965234848Smav		g_raid_md_ddf_print(&pd->pd_meta);
2966234848Smav		ddf_meta_write(disk->d_consumer, &pd->pd_meta);
2967234848Smav	}
2968234848Smav	return (0);
2969234848Smav}
2970234848Smav
2971234848Smavstatic int
2972234848Smavg_raid_md_fail_disk_ddf(struct g_raid_md_object *md,
2973234848Smav    struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
2974234848Smav{
2975234848Smav	struct g_raid_softc *sc;
2976234848Smav	struct g_raid_md_ddf_perdisk *pd;
2977234848Smav	struct g_raid_subdisk *sd;
2978234848Smav	int i;
2979234848Smav
2980234848Smav	sc = md->mdo_softc;
2981234848Smav	pd = (struct g_raid_md_ddf_perdisk *)tdisk->d_md_data;
2982234848Smav
2983234848Smav	/* We can't fail disk that is not a part of array now. */
2984234848Smav	if (tdisk->d_state != G_RAID_DISK_S_ACTIVE)
2985234848Smav		return (-1);
2986234848Smav
2987234848Smav	/*
2988234848Smav	 * Mark disk as failed in metadata and try to write that metadata
2989234848Smav	 * to the disk itself to prevent it's later resurrection as STALE.
2990234848Smav	 */
2991234848Smav	G_RAID_DEBUG(1, "Writing DDF metadata to %s",
2992234848Smav	    g_raid_get_diskname(tdisk));
2993234848Smav	i = ddf_meta_find_pd(&pd->pd_meta, NULL, GET32(&pd->pd_meta, pdd->PD_Reference));
2994234848Smav	SET16(&pd->pd_meta, pdr->entry[i].PD_State, DDF_PDE_FAILED | DDF_PDE_PFA);
2995234848Smav	if (tdisk->d_consumer != NULL)
2996234848Smav		ddf_meta_write(tdisk->d_consumer, &pd->pd_meta);
2997234848Smav
2998234848Smav	/* Change states. */
2999234848Smav	g_raid_change_disk_state(tdisk, G_RAID_DISK_S_FAILED);
3000234848Smav	TAILQ_FOREACH(sd, &tdisk->d_subdisks, sd_next) {
3001234848Smav		g_raid_change_subdisk_state(sd,
3002234848Smav		    G_RAID_SUBDISK_S_FAILED);
3003234848Smav		g_raid_event_send(sd, G_RAID_SUBDISK_E_FAILED,
3004234848Smav		    G_RAID_EVENT_SUBDISK);
3005234848Smav	}
3006234848Smav
3007234848Smav	/* Write updated metadata to remaining disks. */
3008234848Smav	g_raid_md_write_ddf(md, NULL, NULL, tdisk);
3009234848Smav
3010234848Smav	g_raid_md_ddf_refill(sc);
3011234848Smav	return (0);
3012234848Smav}
3013234848Smav
3014234848Smavstatic int
3015234848Smavg_raid_md_free_disk_ddf(struct g_raid_md_object *md,
3016234848Smav    struct g_raid_disk *disk)
3017234848Smav{
3018234848Smav	struct g_raid_md_ddf_perdisk *pd;
3019234848Smav
3020234848Smav	pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
3021234848Smav	ddf_meta_free(&pd->pd_meta);
3022234848Smav	free(pd, M_MD_DDF);
3023234848Smav	disk->d_md_data = NULL;
3024234848Smav	return (0);
3025234848Smav}
3026234848Smav
3027234848Smavstatic int
3028234848Smavg_raid_md_free_volume_ddf(struct g_raid_md_object *md,
3029234848Smav    struct g_raid_volume *vol)
3030234848Smav{
3031234869Smav	struct g_raid_md_ddf_object *mdi;
3032234848Smav	struct g_raid_md_ddf_pervolume *pv;
3033234848Smav
3034234869Smav	mdi = (struct g_raid_md_ddf_object *)md;
3035234848Smav	pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
3036234848Smav	ddf_vol_meta_free(&pv->pv_meta);
3037234848Smav	if (!pv->pv_started) {
3038234848Smav		pv->pv_started = 1;
3039234869Smav		mdi->mdio_starting--;
3040234848Smav		callout_stop(&pv->pv_start_co);
3041234848Smav	}
3042234848Smav	return (0);
3043234848Smav}
3044234848Smav
3045234848Smavstatic int
3046234848Smavg_raid_md_free_ddf(struct g_raid_md_object *md)
3047234848Smav{
3048234848Smav	struct g_raid_md_ddf_object *mdi;
3049234848Smav
3050234848Smav	mdi = (struct g_raid_md_ddf_object *)md;
3051234848Smav	if (!mdi->mdio_started) {
3052234848Smav		mdi->mdio_started = 0;
3053234848Smav		callout_stop(&mdi->mdio_start_co);
3054234848Smav		G_RAID_DEBUG1(1, md->mdo_softc,
3055234848Smav		    "root_mount_rel %p", mdi->mdio_rootmount);
3056234848Smav		root_mount_rel(mdi->mdio_rootmount);
3057234848Smav		mdi->mdio_rootmount = NULL;
3058234848Smav	}
3059234848Smav	ddf_meta_free(&mdi->mdio_meta);
3060234848Smav	return (0);
3061234848Smav}
3062234848Smav
3063234848SmavG_RAID_MD_DECLARE(g_raid_md_ddf);
3064