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