1267359Sae/*-
2267359Sae * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org>
3267359Sae * All rights reserved.
4267359Sae *
5267359Sae * Redistribution and use in source and binary forms, with or without
6267359Sae * modification, are permitted provided that the following conditions
7267359Sae * are met:
8267359Sae *
9267359Sae * 1. Redistributions of source code must retain the above copyright
10267359Sae *    notice, this list of conditions and the following disclaimer.
11267359Sae * 2. Redistributions in binary form must reproduce the above copyright
12267359Sae *    notice, this list of conditions and the following disclaimer in the
13267359Sae *    documentation and/or other materials provided with the distribution.
14267359Sae *
15267359Sae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16267359Sae * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17267359Sae * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18267359Sae * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19267359Sae * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20267359Sae * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21267359Sae * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22267359Sae * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23267359Sae * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24267359Sae * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25267359Sae */
26267359Sae
27267359Sae#include <sys/cdefs.h>
28267359Sae__FBSDID("$FreeBSD: stable/11/sys/geom/part/g_part_bsd64.c 332640 2018-04-17 02:18:04Z kevans $");
29267359Sae
30267359Sae#include <sys/param.h>
31267359Sae#include <sys/bio.h>
32267359Sae#include <sys/disklabel.h>
33267359Sae#include <sys/endian.h>
34267359Sae#include <sys/gpt.h>
35267359Sae#include <sys/kernel.h>
36267359Sae#include <sys/kobj.h>
37267359Sae#include <sys/limits.h>
38267359Sae#include <sys/lock.h>
39267359Sae#include <sys/malloc.h>
40267359Sae#include <sys/mutex.h>
41267359Sae#include <sys/queue.h>
42267359Sae#include <sys/sbuf.h>
43267359Sae#include <sys/systm.h>
44267359Sae#include <sys/sysctl.h>
45267359Sae#include <geom/geom.h>
46267359Sae#include <geom/geom_int.h>
47267359Sae#include <geom/part/g_part.h>
48267359Sae
49267359Sae#include "g_part_if.h"
50267359Sae
51267359SaeFEATURE(geom_part_bsd64, "GEOM partitioning class for 64-bit BSD disklabels");
52267359Sae
53267359Sae/* XXX: move this to sys/disklabel64.h */
54267359Sae#define	DISKMAGIC64     ((uint32_t)0xc4464c59)
55267359Sae#define	MAXPARTITIONS64	16
56267359Sae#define	RESPARTITIONS64	32
57267359Sae
58267359Saestruct disklabel64 {
59267359Sae	char	  d_reserved0[512];	/* reserved or unused */
60267359Sae	u_int32_t d_magic;		/* the magic number */
61298808Spfg	u_int32_t d_crc;		/* crc32() d_magic through last part */
62267359Sae	u_int32_t d_align;		/* partition alignment requirement */
63267359Sae	u_int32_t d_npartitions;	/* number of partitions */
64267359Sae	struct uuid d_stor_uuid;	/* unique uuid for label */
65267359Sae
66267359Sae	u_int64_t d_total_size;		/* total size incl everything (bytes) */
67267359Sae	u_int64_t d_bbase;		/* boot area base offset (bytes) */
68267359Sae					/* boot area is pbase - bbase */
69267359Sae	u_int64_t d_pbase;		/* first allocatable offset (bytes) */
70267359Sae	u_int64_t d_pstop;		/* last allocatable offset+1 (bytes) */
71267359Sae	u_int64_t d_abase;		/* location of backup copy if not 0 */
72267359Sae
73267359Sae	u_char	  d_packname[64];
74267359Sae	u_char    d_reserved[64];
75267359Sae
76267359Sae	/*
77267359Sae	 * Note: offsets are relative to the base of the slice, NOT to
78267359Sae	 * d_pbase.  Unlike 32 bit disklabels the on-disk format for
79267359Sae	 * a 64 bit disklabel remains slice-relative.
80267359Sae	 *
81267359Sae	 * An uninitialized partition has a p_boffset and p_bsize of 0.
82267359Sae	 *
83267359Sae	 * If p_fstype is not supported for a live partition it is set
84267359Sae	 * to FS_OTHER.  This is typically the case when the filesystem
85267359Sae	 * is identified by its uuid.
86267359Sae	 */
87267359Sae	struct partition64 {		/* the partition table */
88267359Sae		u_int64_t p_boffset;	/* slice relative offset, in bytes */
89267359Sae		u_int64_t p_bsize;	/* size of partition, in bytes */
90267359Sae		u_int8_t  p_fstype;
91267359Sae		u_int8_t  p_unused01;	/* reserved, must be 0 */
92267359Sae		u_int8_t  p_unused02;	/* reserved, must be 0 */
93267359Sae		u_int8_t  p_unused03;	/* reserved, must be 0 */
94267359Sae		u_int32_t p_unused04;	/* reserved, must be 0 */
95267359Sae		u_int32_t p_unused05;	/* reserved, must be 0 */
96267359Sae		u_int32_t p_unused06;	/* reserved, must be 0 */
97267359Sae		struct uuid p_type_uuid;/* mount type as UUID */
98267359Sae		struct uuid p_stor_uuid;/* unique uuid for storage */
99267359Sae	} d_partitions[MAXPARTITIONS64];/* actually may be more */
100267359Sae};
101267359Sae
102267359Saestruct g_part_bsd64_table {
103267359Sae	struct g_part_table	base;
104267359Sae
105267359Sae	uint32_t		d_align;
106267359Sae	uint64_t		d_bbase;
107267359Sae	uint64_t		d_abase;
108267359Sae	struct uuid		d_stor_uuid;
109267359Sae	char			d_reserved0[512];
110267359Sae	u_char			d_packname[64];
111267359Sae	u_char			d_reserved[64];
112267359Sae};
113267359Sae
114267359Saestruct g_part_bsd64_entry {
115267359Sae	struct g_part_entry	base;
116267359Sae
117267359Sae	uint8_t			fstype;
118267359Sae	struct uuid		type_uuid;
119267359Sae	struct uuid		stor_uuid;
120267359Sae};
121267359Sae
122267359Saestatic int g_part_bsd64_add(struct g_part_table *, struct g_part_entry *,
123267359Sae    struct g_part_parms *);
124267359Saestatic int g_part_bsd64_bootcode(struct g_part_table *, struct g_part_parms *);
125267359Saestatic int g_part_bsd64_create(struct g_part_table *, struct g_part_parms *);
126267359Saestatic int g_part_bsd64_destroy(struct g_part_table *, struct g_part_parms *);
127267359Saestatic void g_part_bsd64_dumpconf(struct g_part_table *, struct g_part_entry *,
128267359Sae    struct sbuf *, const char *);
129267359Saestatic int g_part_bsd64_dumpto(struct g_part_table *, struct g_part_entry *);
130332521Skevansstatic int g_part_bsd64_modify(struct g_part_table *, struct g_part_entry *,
131267359Sae    struct g_part_parms *);
132267359Saestatic const char *g_part_bsd64_name(struct g_part_table *, struct g_part_entry *,
133267359Sae    char *, size_t);
134267359Saestatic int g_part_bsd64_probe(struct g_part_table *, struct g_consumer *);
135267359Saestatic int g_part_bsd64_read(struct g_part_table *, struct g_consumer *);
136267359Saestatic const char *g_part_bsd64_type(struct g_part_table *, struct g_part_entry *,
137267359Sae    char *, size_t);
138267359Saestatic int g_part_bsd64_write(struct g_part_table *, struct g_consumer *);
139267359Saestatic int g_part_bsd64_resize(struct g_part_table *, struct g_part_entry *,
140267359Sae    struct g_part_parms *);
141267359Sae
142267359Saestatic kobj_method_t g_part_bsd64_methods[] = {
143267359Sae	KOBJMETHOD(g_part_add,		g_part_bsd64_add),
144267359Sae	KOBJMETHOD(g_part_bootcode,	g_part_bsd64_bootcode),
145267359Sae	KOBJMETHOD(g_part_create,	g_part_bsd64_create),
146267359Sae	KOBJMETHOD(g_part_destroy,	g_part_bsd64_destroy),
147267359Sae	KOBJMETHOD(g_part_dumpconf,	g_part_bsd64_dumpconf),
148267359Sae	KOBJMETHOD(g_part_dumpto,	g_part_bsd64_dumpto),
149267359Sae	KOBJMETHOD(g_part_modify,	g_part_bsd64_modify),
150267359Sae	KOBJMETHOD(g_part_resize,	g_part_bsd64_resize),
151267359Sae	KOBJMETHOD(g_part_name,		g_part_bsd64_name),
152267359Sae	KOBJMETHOD(g_part_probe,	g_part_bsd64_probe),
153267359Sae	KOBJMETHOD(g_part_read,		g_part_bsd64_read),
154267359Sae	KOBJMETHOD(g_part_type,		g_part_bsd64_type),
155267359Sae	KOBJMETHOD(g_part_write,	g_part_bsd64_write),
156267359Sae	{ 0, 0 }
157267359Sae};
158267359Sae
159267359Saestatic struct g_part_scheme g_part_bsd64_scheme = {
160267359Sae	"BSD64",
161267359Sae	g_part_bsd64_methods,
162267359Sae	sizeof(struct g_part_bsd64_table),
163267359Sae	.gps_entrysz = sizeof(struct g_part_bsd64_entry),
164267359Sae	.gps_minent = MAXPARTITIONS64,
165267359Sae	.gps_maxent = MAXPARTITIONS64
166267359Sae};
167267359SaeG_PART_SCHEME_DECLARE(g_part_bsd64);
168332640SkevansMODULE_VERSION(geom_part_bsd64, 0);
169267359Sae
170267359Sae#define	EQUUID(a, b)	(memcmp(a, b, sizeof(struct uuid)) == 0)
171267359Saestatic struct uuid bsd64_uuid_unused = GPT_ENT_TYPE_UNUSED;
172267359Saestatic struct uuid bsd64_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP;
173267359Saestatic struct uuid bsd64_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1;
174267359Saestatic struct uuid bsd64_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM;
175267359Saestatic struct uuid bsd64_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD;
176267359Saestatic struct uuid bsd64_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY;
177267359Saestatic struct uuid bsd64_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER;
178267359Saestatic struct uuid bsd64_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2;
179267359Saestatic struct uuid bsd64_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
180267359Saestatic struct uuid bsd64_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
181267359Saestatic struct uuid bsd64_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
182267359Saestatic struct uuid bsd64_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
183267359Saestatic struct uuid bsd64_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
184267359Saestatic struct uuid bsd64_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
185267359Sae
186267359Saestruct bsd64_uuid_alias {
187267359Sae	struct uuid *uuid;
188267359Sae	uint8_t fstype;
189267359Sae	int alias;
190267359Sae};
191267359Saestatic struct bsd64_uuid_alias dfbsd_alias_match[] = {
192267359Sae	{ &bsd64_uuid_dfbsd_swap, FS_SWAP, G_PART_ALIAS_DFBSD_SWAP },
193267359Sae	{ &bsd64_uuid_dfbsd_ufs1, FS_BSDFFS, G_PART_ALIAS_DFBSD_UFS },
194267359Sae	{ &bsd64_uuid_dfbsd_vinum, FS_VINUM, G_PART_ALIAS_DFBSD_VINUM },
195267359Sae	{ &bsd64_uuid_dfbsd_ccd, FS_CCD, G_PART_ALIAS_DFBSD_CCD },
196267359Sae	{ &bsd64_uuid_dfbsd_legacy, FS_OTHER, G_PART_ALIAS_DFBSD_LEGACY },
197267359Sae	{ &bsd64_uuid_dfbsd_hammer, FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER },
198267359Sae	{ &bsd64_uuid_dfbsd_hammer2, FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 },
199267359Sae	{ NULL, 0, 0}
200267359Sae};
201267359Saestatic struct bsd64_uuid_alias fbsd_alias_match[] = {
202267359Sae	{ &bsd64_uuid_freebsd_boot, FS_OTHER, G_PART_ALIAS_FREEBSD_BOOT },
203267359Sae	{ &bsd64_uuid_freebsd_swap, FS_OTHER, G_PART_ALIAS_FREEBSD_SWAP },
204267359Sae	{ &bsd64_uuid_freebsd_ufs, FS_OTHER, G_PART_ALIAS_FREEBSD_UFS },
205267359Sae	{ &bsd64_uuid_freebsd_zfs, FS_OTHER, G_PART_ALIAS_FREEBSD_ZFS },
206267359Sae	{ &bsd64_uuid_freebsd_vinum, FS_OTHER, G_PART_ALIAS_FREEBSD_VINUM },
207267359Sae	{ &bsd64_uuid_freebsd_nandfs, FS_OTHER, G_PART_ALIAS_FREEBSD_NANDFS },
208267359Sae	{ NULL, 0, 0}
209267359Sae};
210267359Sae
211267359Saestatic int
212267359Saebsd64_parse_type(const char *type, struct g_part_bsd64_entry *entry)
213267359Sae{
214267359Sae	struct uuid tmp;
215267359Sae	const struct bsd64_uuid_alias *uap;
216267359Sae	const char *alias;
217267359Sae	char *p;
218267359Sae	long lt;
219267359Sae	int error;
220267359Sae
221267359Sae	if (type[0] == '!') {
222267359Sae		if (type[1] == '\0')
223267359Sae			return (EINVAL);
224267359Sae		lt = strtol(type + 1, &p, 0);
225267359Sae		/* The type specified as number */
226267359Sae		if (*p == '\0') {
227267359Sae			if (lt <= 0 || lt > 255)
228267359Sae				return (EINVAL);
229267359Sae			entry->fstype = lt;
230267359Sae			entry->type_uuid = bsd64_uuid_unused;
231267359Sae			return (0);
232267359Sae		}
233267359Sae		/* The type specified as uuid */
234267359Sae		error = parse_uuid(type + 1, &tmp);
235267359Sae		if (error != 0)
236267359Sae			return (error);
237267359Sae		if (EQUUID(&tmp, &bsd64_uuid_unused))
238267359Sae			return (EINVAL);
239267359Sae		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
240267359Sae			if (EQUUID(&tmp, uap->uuid)) {
241267359Sae				/* Prefer fstype for known uuids */
242267359Sae				entry->type_uuid = bsd64_uuid_unused;
243267359Sae				entry->fstype = uap->fstype;
244267359Sae				return (0);
245267359Sae			}
246267359Sae		}
247267359Sae		entry->type_uuid = tmp;
248267359Sae		entry->fstype = FS_OTHER;
249267359Sae		return (0);
250267359Sae	}
251267359Sae	/* The type specified as symbolic alias name */
252267359Sae	for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++) {
253267359Sae		alias = g_part_alias_name(uap->alias);
254267359Sae		if (!strcasecmp(type, alias)) {
255267359Sae			entry->type_uuid = *uap->uuid;
256267359Sae			entry->fstype = uap->fstype;
257267359Sae			return (0);
258267359Sae		}
259267359Sae	}
260267359Sae	for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++) {
261267359Sae		alias = g_part_alias_name(uap->alias);
262267359Sae		if (!strcasecmp(type, alias)) {
263267359Sae			entry->type_uuid = bsd64_uuid_unused;
264267359Sae			entry->fstype = uap->fstype;
265267359Sae			return (0);
266267359Sae		}
267267359Sae	}
268267359Sae	return (EINVAL);
269267359Sae}
270267359Sae
271267359Saestatic int
272267359Saeg_part_bsd64_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
273267359Sae    struct g_part_parms *gpp)
274267359Sae{
275267359Sae	struct g_part_bsd64_entry *entry;
276267359Sae
277267359Sae	if (gpp->gpp_parms & G_PART_PARM_LABEL)
278267359Sae		return (EINVAL);
279267359Sae
280267359Sae	entry = (struct g_part_bsd64_entry *)baseentry;
281267359Sae	if (bsd64_parse_type(gpp->gpp_type, entry) != 0)
282267359Sae		return (EINVAL);
283267359Sae	kern_uuidgen(&entry->stor_uuid, 1);
284267359Sae	return (0);
285267359Sae}
286267359Sae
287267359Saestatic int
288267359Saeg_part_bsd64_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
289267359Sae{
290267359Sae
291267359Sae	return (EOPNOTSUPP);
292267359Sae}
293267359Sae
294267359Sae#define	PALIGN_SIZE	(1024 * 1024)
295267359Sae#define	PALIGN_MASK	(PALIGN_SIZE - 1)
296267359Sae#define	BLKSIZE		(4 * 1024)
297267359Sae#define	BOOTSIZE	(32 * 1024)
298267359Sae#define	DALIGN_SIZE	(32 * 1024)
299267359Saestatic int
300267359Saeg_part_bsd64_create(struct g_part_table *basetable, struct g_part_parms *gpp)
301267359Sae{
302267359Sae	struct g_part_bsd64_table *table;
303267359Sae	struct g_part_entry *baseentry;
304267359Sae	struct g_provider *pp;
305267359Sae	uint64_t blkmask, pbase;
306267359Sae	uint32_t blksize, ressize;
307267359Sae
308267359Sae	pp = gpp->gpp_provider;
309267359Sae	if (pp->mediasize < 2* PALIGN_SIZE)
310267359Sae		return (ENOSPC);
311267359Sae
312267359Sae	/*
313267359Sae	 * Use at least 4KB block size. Blksize is stored in the d_align.
314267359Sae	 * XXX: Actually it is used just for calculate d_bbase and used
315267359Sae	 * for better alignment in bsdlabel64(8).
316267359Sae	 */
317267359Sae	blksize = pp->sectorsize < BLKSIZE ? BLKSIZE: pp->sectorsize;
318267359Sae	blkmask = blksize - 1;
319267359Sae	/* Reserve enough space for RESPARTITIONS64 partitions. */
320267359Sae	ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]);
321267359Sae	ressize = (ressize + blkmask) & ~blkmask;
322267359Sae	/*
323267359Sae	 * Reserve enough space for bootcode and align first allocatable
324267359Sae	 * offset to PALIGN_SIZE.
325267359Sae	 * XXX: Currently DragonFlyBSD has 32KB bootcode, but the size could
326267359Sae	 * be bigger, because it is possible change it (it is equal pbase-bbase)
327267359Sae	 * in the bsdlabel64(8).
328267359Sae	 */
329267359Sae	pbase = ressize + ((BOOTSIZE + blkmask) & ~blkmask);
330267359Sae	pbase = (pbase + PALIGN_MASK) & ~PALIGN_MASK;
331267359Sae	/*
332267359Sae	 * Take physical offset into account and make first allocatable
333267359Sae	 * offset 32KB aligned to the start of the physical disk.
334267359Sae	 * XXX: Actually there are no such restrictions, this is how
335267359Sae	 * DragonFlyBSD behaves.
336267359Sae	 */
337267359Sae	pbase += DALIGN_SIZE - pp->stripeoffset % DALIGN_SIZE;
338267359Sae
339267359Sae	table = (struct g_part_bsd64_table *)basetable;
340267359Sae	table->d_align = blksize;
341267359Sae	table->d_bbase = ressize / pp->sectorsize;
342267359Sae	table->d_abase = ((pp->mediasize - ressize) &
343267359Sae	    ~blkmask) / pp->sectorsize;
344267359Sae	kern_uuidgen(&table->d_stor_uuid, 1);
345267359Sae	basetable->gpt_first = pbase / pp->sectorsize;
346267359Sae	basetable->gpt_last = table->d_abase - 1; /* XXX */
347267359Sae	/*
348267359Sae	 * Create 'c' partition and make it internal, so user will not be
349267359Sae	 * able use it.
350267359Sae	 */
351267359Sae	baseentry = g_part_new_entry(basetable, RAW_PART + 1, 0, 0);
352267359Sae	baseentry->gpe_internal = 1;
353267359Sae	return (0);
354267359Sae}
355267359Sae
356267359Saestatic int
357267359Saeg_part_bsd64_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
358267359Sae{
359267359Sae	struct g_provider *pp;
360267359Sae
361267359Sae	pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
362267359Sae	if (pp->sectorsize > offsetof(struct disklabel64, d_magic))
363267359Sae		basetable->gpt_smhead |= 1;
364267359Sae	else
365267359Sae		basetable->gpt_smhead |= 3;
366267359Sae	return (0);
367267359Sae}
368267359Sae
369267359Saestatic void
370267359Saeg_part_bsd64_dumpconf(struct g_part_table *basetable,
371267359Sae    struct g_part_entry *baseentry, struct sbuf *sb, const char *indent)
372267359Sae{
373267359Sae	struct g_part_bsd64_table *table;
374267359Sae	struct g_part_bsd64_entry *entry;
375267359Sae	char buf[sizeof(table->d_packname)];
376267359Sae
377267359Sae	entry = (struct g_part_bsd64_entry *)baseentry;
378267359Sae	if (indent == NULL) {
379267359Sae		/* conftxt: libdisk compatibility */
380267359Sae		sbuf_printf(sb, " xs BSD64 xt %u", entry->fstype);
381267359Sae	} else if (entry != NULL) {
382267359Sae		/* confxml: partition entry information */
383267359Sae		sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
384267359Sae		    entry->fstype);
385267359Sae		if (!EQUUID(&bsd64_uuid_unused, &entry->type_uuid)) {
386267359Sae			sbuf_printf(sb, "%s<type_uuid>", indent);
387267359Sae			sbuf_printf_uuid(sb, &entry->type_uuid);
388267359Sae			sbuf_printf(sb, "</type_uuid>\n");
389267359Sae		}
390267359Sae		sbuf_printf(sb, "%s<stor_uuid>", indent);
391267359Sae		sbuf_printf_uuid(sb, &entry->stor_uuid);
392267359Sae		sbuf_printf(sb, "</stor_uuid>\n");
393267359Sae	} else {
394267359Sae		/* confxml: scheme information */
395267359Sae		table = (struct g_part_bsd64_table *)basetable;
396267359Sae		sbuf_printf(sb, "%s<bootbase>%ju</bootbase>\n", indent,
397267359Sae		    (uintmax_t)table->d_bbase);
398267359Sae		if (table->d_abase)
399267359Sae			sbuf_printf(sb, "%s<backupbase>%ju</backupbase>\n",
400267359Sae			    indent, (uintmax_t)table->d_abase);
401267359Sae		sbuf_printf(sb, "%s<stor_uuid>", indent);
402267359Sae		sbuf_printf_uuid(sb, &table->d_stor_uuid);
403267359Sae		sbuf_printf(sb, "</stor_uuid>\n");
404267359Sae		sbuf_printf(sb, "%s<label>", indent);
405267359Sae		strncpy(buf, table->d_packname, sizeof(buf) - 1);
406267359Sae		buf[sizeof(buf) - 1] = '\0';
407267359Sae		g_conf_printf_escaped(sb, "%s", buf);
408267359Sae		sbuf_printf(sb, "</label>\n");
409267359Sae	}
410267359Sae}
411267359Sae
412267359Saestatic int
413332521Skevansg_part_bsd64_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
414267359Sae{
415267359Sae	struct g_part_bsd64_entry *entry;
416267359Sae
417267359Sae	/* Allow dumping to a swap partition. */
418267359Sae	entry = (struct g_part_bsd64_entry *)baseentry;
419267359Sae	if (entry->fstype == FS_SWAP ||
420267359Sae	    EQUUID(&entry->type_uuid, &bsd64_uuid_dfbsd_swap) ||
421267359Sae	    EQUUID(&entry->type_uuid, &bsd64_uuid_freebsd_swap))
422267359Sae		return (1);
423267359Sae	return (0);
424267359Sae}
425267359Sae
426267359Saestatic int
427267359Saeg_part_bsd64_modify(struct g_part_table *basetable,
428267359Sae    struct g_part_entry *baseentry, struct g_part_parms *gpp)
429267359Sae{
430267359Sae	struct g_part_bsd64_entry *entry;
431267359Sae
432267359Sae	if (gpp->gpp_parms & G_PART_PARM_LABEL)
433267359Sae		return (EINVAL);
434267359Sae
435267359Sae	entry = (struct g_part_bsd64_entry *)baseentry;
436267359Sae	if (gpp->gpp_parms & G_PART_PARM_TYPE)
437267359Sae		return (bsd64_parse_type(gpp->gpp_type, entry));
438267359Sae	return (0);
439267359Sae}
440267359Sae
441267359Saestatic int
442267359Saeg_part_bsd64_resize(struct g_part_table *basetable,
443267359Sae    struct g_part_entry *baseentry, struct g_part_parms *gpp)
444267359Sae{
445267359Sae	struct g_part_bsd64_table *table;
446267359Sae	struct g_provider *pp;
447267359Sae
448267359Sae	if (baseentry == NULL) {
449267359Sae		pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
450267359Sae		table = (struct g_part_bsd64_table *)basetable;
451298433Spfg		table->d_abase =
452298433Spfg		    rounddown2(pp->mediasize - table->d_bbase * pp->sectorsize,
453298433Spfg		        table->d_align) / pp->sectorsize;
454267359Sae		basetable->gpt_last = table->d_abase - 1;
455267359Sae		return (0);
456267359Sae	}
457267359Sae	baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
458267359Sae	return (0);
459267359Sae}
460267359Sae
461267359Saestatic const char *
462267359Saeg_part_bsd64_name(struct g_part_table *table, struct g_part_entry *baseentry,
463267359Sae    char *buf, size_t bufsz)
464267359Sae{
465267359Sae
466267359Sae	snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
467267359Sae	return (buf);
468267359Sae}
469267359Sae
470267359Saestatic int
471267359Saeg_part_bsd64_probe(struct g_part_table *table, struct g_consumer *cp)
472267359Sae{
473267359Sae	struct g_provider *pp;
474267359Sae	uint32_t v;
475267359Sae	int error;
476267359Sae	u_char *buf;
477267359Sae
478267359Sae	pp = cp->provider;
479267359Sae	if (pp->mediasize < 2 * PALIGN_SIZE)
480267359Sae		return (ENOSPC);
481298433Spfg	v = rounddown2(pp->sectorsize + offsetof(struct disklabel64, d_magic),
482298433Spfg		       pp->sectorsize);
483267359Sae	buf = g_read_data(cp, 0, v, &error);
484267359Sae	if (buf == NULL)
485267359Sae		return (error);
486267359Sae	v = le32dec(buf + offsetof(struct disklabel64, d_magic));
487267359Sae	g_free(buf);
488267359Sae	return (v == DISKMAGIC64 ? G_PART_PROBE_PRI_HIGH: ENXIO);
489267359Sae}
490267359Sae
491267359Saestatic int
492267359Saeg_part_bsd64_read(struct g_part_table *basetable, struct g_consumer *cp)
493267359Sae{
494267359Sae	struct g_part_bsd64_table *table;
495267359Sae	struct g_part_bsd64_entry *entry;
496267359Sae	struct g_part_entry *baseentry;
497267359Sae	struct g_provider *pp;
498267359Sae	struct disklabel64 *dlp;
499267359Sae	uint64_t v64, sz;
500267359Sae	uint32_t v32;
501267359Sae	int error, index;
502267359Sae	u_char *buf;
503267359Sae
504267359Sae	pp = cp->provider;
505267359Sae	table = (struct g_part_bsd64_table *)basetable;
506298433Spfg	v32 = roundup2(sizeof(struct disklabel64), pp->sectorsize);
507267359Sae	buf = g_read_data(cp, 0, v32, &error);
508267359Sae	if (buf == NULL)
509267359Sae		return (error);
510267359Sae
511267359Sae	dlp = (struct disklabel64 *)buf;
512267359Sae	basetable->gpt_entries = le32toh(dlp->d_npartitions);
513298671Scem	if (basetable->gpt_entries > MAXPARTITIONS64 ||
514298671Scem	    basetable->gpt_entries < 1)
515267359Sae		goto invalid_label;
516267359Sae	v32 = le32toh(dlp->d_crc);
517267359Sae	dlp->d_crc = 0;
518267359Sae	if (crc32(&dlp->d_magic, offsetof(struct disklabel64,
519267359Sae	    d_partitions[basetable->gpt_entries]) -
520267359Sae	    offsetof(struct disklabel64, d_magic)) != v32)
521267359Sae		goto invalid_label;
522267359Sae	table->d_align = le32toh(dlp->d_align);
523267359Sae	if (table->d_align == 0 || (table->d_align & (pp->sectorsize - 1)))
524267359Sae		goto invalid_label;
525267359Sae	if (le64toh(dlp->d_total_size) > pp->mediasize)
526267359Sae		goto invalid_label;
527267359Sae	v64 = le64toh(dlp->d_pbase);
528267359Sae	if (v64 % pp->sectorsize)
529267359Sae		goto invalid_label;
530267359Sae	basetable->gpt_first = v64 / pp->sectorsize;
531267359Sae	v64 = le64toh(dlp->d_pstop);
532267359Sae	if (v64 % pp->sectorsize)
533267359Sae		goto invalid_label;
534267359Sae	basetable->gpt_last = v64 / pp->sectorsize;
535267359Sae	basetable->gpt_isleaf = 1;
536267359Sae	v64 = le64toh(dlp->d_bbase);
537267359Sae	if (v64 % pp->sectorsize)
538267359Sae		goto invalid_label;
539267359Sae	table->d_bbase = v64 / pp->sectorsize;
540267359Sae	v64 = le64toh(dlp->d_abase);
541267359Sae	if (v64 % pp->sectorsize)
542267359Sae		goto invalid_label;
543267359Sae	table->d_abase = v64 / pp->sectorsize;
544267359Sae	le_uuid_dec(&dlp->d_stor_uuid, &table->d_stor_uuid);
545267359Sae	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
546267359Sae		if (index == RAW_PART) {
547267359Sae			/* Skip 'c' partition. */
548267359Sae			baseentry = g_part_new_entry(basetable,
549267359Sae			    index + 1, 0, 0);
550267359Sae			baseentry->gpe_internal = 1;
551267359Sae			continue;
552267359Sae		}
553267359Sae		v64 = le64toh(dlp->d_partitions[index].p_boffset);
554267359Sae		sz = le64toh(dlp->d_partitions[index].p_bsize);
555267359Sae		if (sz == 0 && v64 == 0)
556267359Sae			continue;
557267359Sae		if (sz == 0 || (v64 % pp->sectorsize) || (sz % pp->sectorsize))
558267359Sae			goto invalid_label;
559267359Sae		baseentry = g_part_new_entry(basetable, index + 1,
560267359Sae		    v64 / pp->sectorsize, (v64 + sz) / pp->sectorsize - 1);
561267359Sae		entry = (struct g_part_bsd64_entry *)baseentry;
562267359Sae		le_uuid_dec(&dlp->d_partitions[index].p_type_uuid,
563267359Sae		    &entry->type_uuid);
564267359Sae		le_uuid_dec(&dlp->d_partitions[index].p_stor_uuid,
565267359Sae		    &entry->stor_uuid);
566267359Sae		entry->fstype = dlp->d_partitions[index].p_fstype;
567267359Sae	}
568267359Sae	bcopy(dlp->d_reserved0, table->d_reserved0,
569267359Sae	    sizeof(table->d_reserved0));
570267359Sae	bcopy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
571267359Sae	bcopy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
572267359Sae	g_free(buf);
573267359Sae	return (0);
574267359Sae
575267359Saeinvalid_label:
576267359Sae	g_free(buf);
577267359Sae	return (EINVAL);
578267359Sae}
579267359Sae
580267359Saestatic const char *
581332521Skevansg_part_bsd64_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
582267359Sae    char *buf, size_t bufsz)
583267359Sae{
584267359Sae	struct g_part_bsd64_entry *entry;
585267359Sae	struct bsd64_uuid_alias *uap;
586267359Sae
587267359Sae	entry = (struct g_part_bsd64_entry *)baseentry;
588267359Sae	if (entry->fstype != FS_OTHER) {
589267359Sae		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
590267359Sae			if (uap->fstype == entry->fstype)
591267359Sae				return (g_part_alias_name(uap->alias));
592267359Sae	} else {
593267359Sae		for (uap = &fbsd_alias_match[0]; uap->uuid != NULL; uap++)
594267359Sae			if (EQUUID(uap->uuid, &entry->type_uuid))
595267359Sae				return (g_part_alias_name(uap->alias));
596267359Sae		for (uap = &dfbsd_alias_match[0]; uap->uuid != NULL; uap++)
597267359Sae			if (EQUUID(uap->uuid, &entry->type_uuid))
598267359Sae				return (g_part_alias_name(uap->alias));
599267359Sae	}
600267359Sae	if (EQUUID(&bsd64_uuid_unused, &entry->type_uuid))
601267359Sae		snprintf(buf, bufsz, "!%d", entry->fstype);
602267359Sae	else {
603267359Sae		buf[0] = '!';
604267359Sae		snprintf_uuid(buf + 1, bufsz - 1, &entry->type_uuid);
605267359Sae	}
606267359Sae	return (buf);
607267359Sae}
608267359Sae
609267359Saestatic int
610267359Saeg_part_bsd64_write(struct g_part_table *basetable, struct g_consumer *cp)
611267359Sae{
612267359Sae	struct g_provider *pp;
613267359Sae	struct g_part_entry *baseentry;
614267359Sae	struct g_part_bsd64_entry *entry;
615267359Sae	struct g_part_bsd64_table *table;
616267359Sae	struct disklabel64 *dlp;
617267359Sae	uint32_t v, sz;
618267359Sae	int error, index;
619267359Sae
620267359Sae	pp = cp->provider;
621267359Sae	table = (struct g_part_bsd64_table *)basetable;
622298433Spfg	sz = roundup2(sizeof(struct disklabel64), pp->sectorsize);
623267359Sae	dlp = g_malloc(sz, M_WAITOK | M_ZERO);
624267359Sae
625267359Sae	memcpy(dlp->d_reserved0, table->d_reserved0,
626267359Sae	    sizeof(table->d_reserved0));
627267359Sae	memcpy(dlp->d_packname, table->d_packname, sizeof(table->d_packname));
628267359Sae	memcpy(dlp->d_reserved, table->d_reserved, sizeof(table->d_reserved));
629267359Sae	le32enc(&dlp->d_magic, DISKMAGIC64);
630267359Sae	le32enc(&dlp->d_align, table->d_align);
631267359Sae	le32enc(&dlp->d_npartitions, basetable->gpt_entries);
632267359Sae	le_uuid_enc(&dlp->d_stor_uuid, &table->d_stor_uuid);
633267359Sae	le64enc(&dlp->d_total_size, pp->mediasize);
634267359Sae	le64enc(&dlp->d_bbase, table->d_bbase * pp->sectorsize);
635267359Sae	le64enc(&dlp->d_pbase, basetable->gpt_first * pp->sectorsize);
636267359Sae	le64enc(&dlp->d_pstop, basetable->gpt_last * pp->sectorsize);
637267359Sae	le64enc(&dlp->d_abase, table->d_abase * pp->sectorsize);
638267359Sae
639267359Sae	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
640267359Sae		if (baseentry->gpe_deleted)
641267359Sae			continue;
642267359Sae		index = baseentry->gpe_index - 1;
643267359Sae		entry = (struct g_part_bsd64_entry *)baseentry;
644267359Sae		if (index == RAW_PART)
645267359Sae			continue;
646267359Sae		le64enc(&dlp->d_partitions[index].p_boffset,
647267359Sae		    baseentry->gpe_start * pp->sectorsize);
648267359Sae		le64enc(&dlp->d_partitions[index].p_bsize, pp->sectorsize *
649267359Sae		    (baseentry->gpe_end - baseentry->gpe_start + 1));
650267359Sae		dlp->d_partitions[index].p_fstype = entry->fstype;
651267359Sae		le_uuid_enc(&dlp->d_partitions[index].p_type_uuid,
652267359Sae		    &entry->type_uuid);
653267359Sae		le_uuid_enc(&dlp->d_partitions[index].p_stor_uuid,
654267359Sae		    &entry->stor_uuid);
655267359Sae	}
656267359Sae	/* Calculate checksum. */
657267359Sae	v = offsetof(struct disklabel64,
658267359Sae	    d_partitions[basetable->gpt_entries]) -
659267359Sae	    offsetof(struct disklabel64, d_magic);
660267359Sae	le32enc(&dlp->d_crc, crc32(&dlp->d_magic, v));
661267359Sae	error = g_write_data(cp, 0, dlp, sz);
662267359Sae	g_free(dlp);
663267359Sae	return (error);
664267359Sae}
665267359Sae
666