xref: /freebsd/sys/geom/part/g_part_ebr.c (revision 09c999b1557a8031d2b60435d71a0a5ed4f0f016)
15d68db5bSMarcel Moolenaar /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni  *
45d68db5bSMarcel Moolenaar  * Copyright (c) 2007-2009 Marcel Moolenaar
55d68db5bSMarcel Moolenaar  * All rights reserved.
65d68db5bSMarcel Moolenaar  *
75d68db5bSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
85d68db5bSMarcel Moolenaar  * modification, are permitted provided that the following conditions
95d68db5bSMarcel Moolenaar  * are met:
105d68db5bSMarcel Moolenaar  *
115d68db5bSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
125d68db5bSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
135d68db5bSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
145d68db5bSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
155d68db5bSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
165d68db5bSMarcel Moolenaar  *
175d68db5bSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185d68db5bSMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195d68db5bSMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205d68db5bSMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215d68db5bSMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225d68db5bSMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235d68db5bSMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245d68db5bSMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255d68db5bSMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265d68db5bSMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275d68db5bSMarcel Moolenaar  */
285d68db5bSMarcel Moolenaar 
296ad9a99fSMarcel Moolenaar #include "opt_geom.h"
306ad9a99fSMarcel Moolenaar 
315d68db5bSMarcel Moolenaar #include <sys/param.h>
325d68db5bSMarcel Moolenaar #include <sys/bio.h>
335d68db5bSMarcel Moolenaar #include <sys/diskmbr.h>
345d68db5bSMarcel Moolenaar #include <sys/endian.h>
355d68db5bSMarcel Moolenaar #include <sys/kernel.h>
365d68db5bSMarcel Moolenaar #include <sys/kobj.h>
375d68db5bSMarcel Moolenaar #include <sys/limits.h>
385d68db5bSMarcel Moolenaar #include <sys/lock.h>
395d68db5bSMarcel Moolenaar #include <sys/malloc.h>
405d68db5bSMarcel Moolenaar #include <sys/mutex.h>
415d68db5bSMarcel Moolenaar #include <sys/queue.h>
425d68db5bSMarcel Moolenaar #include <sys/sbuf.h>
435d68db5bSMarcel Moolenaar #include <sys/systm.h>
44cb08c2ccSAlexander Leidinger #include <sys/sysctl.h>
455d68db5bSMarcel Moolenaar #include <geom/geom.h>
465d68db5bSMarcel Moolenaar #include <geom/part/g_part.h>
475d68db5bSMarcel Moolenaar 
485d68db5bSMarcel Moolenaar #include "g_part_if.h"
495d68db5bSMarcel Moolenaar 
50cb08c2ccSAlexander Leidinger FEATURE(geom_part_ebr,
51cb08c2ccSAlexander Leidinger     "GEOM partitioning class for extended boot records support");
52cb08c2ccSAlexander Leidinger FEATURE(geom_part_ebr_compat,
53cb08c2ccSAlexander Leidinger     "GEOM EBR partitioning class: backward-compatible partition names");
54cb08c2ccSAlexander Leidinger 
5564612d4eSConrad Meyer SYSCTL_DECL(_kern_geom_part);
5664612d4eSConrad Meyer static SYSCTL_NODE(_kern_geom_part, OID_AUTO, ebr, CTLFLAG_RW | CTLFLAG_MPSAFE,
5764612d4eSConrad Meyer     0, "GEOM_PART_EBR Extended Boot Record");
5864612d4eSConrad Meyer 
5964612d4eSConrad Meyer #define	EBRNAMFMT	"+%08u"
605d68db5bSMarcel Moolenaar #define	EBRSIZE		512
615d68db5bSMarcel Moolenaar 
625d68db5bSMarcel Moolenaar struct g_part_ebr_table {
635d68db5bSMarcel Moolenaar 	struct g_part_table	base;
6464612d4eSConrad Meyer 	u_char			lba0_ebr[EBRSIZE];
655d68db5bSMarcel Moolenaar };
665d68db5bSMarcel Moolenaar 
675d68db5bSMarcel Moolenaar struct g_part_ebr_entry {
685d68db5bSMarcel Moolenaar 	struct g_part_entry	base;
695d68db5bSMarcel Moolenaar 	struct dos_partition	ent;
7064612d4eSConrad Meyer 	u_char			ebr[EBRSIZE];
7164612d4eSConrad Meyer 	u_int			ebr_compat_idx;
725d68db5bSMarcel Moolenaar };
735d68db5bSMarcel Moolenaar 
745d68db5bSMarcel Moolenaar static int g_part_ebr_add(struct g_part_table *, struct g_part_entry *,
755d68db5bSMarcel Moolenaar     struct g_part_parms *);
7664612d4eSConrad Meyer static void g_part_ebr_add_alias(struct g_part_table *, struct g_provider *,
7764612d4eSConrad Meyer     struct g_part_entry *, const char *);
785d68db5bSMarcel Moolenaar static int g_part_ebr_create(struct g_part_table *, struct g_part_parms *);
795d68db5bSMarcel Moolenaar static int g_part_ebr_destroy(struct g_part_table *, struct g_part_parms *);
805d68db5bSMarcel Moolenaar static void g_part_ebr_dumpconf(struct g_part_table *, struct g_part_entry *,
815d68db5bSMarcel Moolenaar     struct sbuf *, const char *);
825d68db5bSMarcel Moolenaar static int g_part_ebr_dumpto(struct g_part_table *, struct g_part_entry *);
835d68db5bSMarcel Moolenaar static int g_part_ebr_modify(struct g_part_table *, struct g_part_entry *,
845d68db5bSMarcel Moolenaar     struct g_part_parms *);
855d68db5bSMarcel Moolenaar static const char *g_part_ebr_name(struct g_part_table *, struct g_part_entry *,
865d68db5bSMarcel Moolenaar     char *, size_t);
8764612d4eSConrad Meyer static struct g_provider *g_part_ebr_new_provider(struct g_part_table *,
8864612d4eSConrad Meyer     struct g_geom *, struct g_part_entry *, const char *);
89e24c8a3fSMarcel Moolenaar static int g_part_ebr_precheck(struct g_part_table *, enum g_part_ctl,
90e24c8a3fSMarcel Moolenaar     struct g_part_parms *);
915d68db5bSMarcel Moolenaar static int g_part_ebr_probe(struct g_part_table *, struct g_consumer *);
925d68db5bSMarcel Moolenaar static int g_part_ebr_read(struct g_part_table *, struct g_consumer *);
935d68db5bSMarcel Moolenaar static int g_part_ebr_setunset(struct g_part_table *, struct g_part_entry *,
945d68db5bSMarcel Moolenaar     const char *, unsigned int);
955d68db5bSMarcel Moolenaar static const char *g_part_ebr_type(struct g_part_table *, struct g_part_entry *,
965d68db5bSMarcel Moolenaar     char *, size_t);
975d68db5bSMarcel Moolenaar static int g_part_ebr_write(struct g_part_table *, struct g_consumer *);
98884c8e4fSAndrey V. Elsukov static int g_part_ebr_resize(struct g_part_table *, struct g_part_entry *,
99884c8e4fSAndrey V. Elsukov     struct g_part_parms *);
1005d68db5bSMarcel Moolenaar 
1015d68db5bSMarcel Moolenaar static kobj_method_t g_part_ebr_methods[] = {
1025d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_add,		g_part_ebr_add),
10364612d4eSConrad Meyer 	KOBJMETHOD(g_part_add_alias,	g_part_ebr_add_alias),
1045d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_create,	g_part_ebr_create),
1055d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_destroy,	g_part_ebr_destroy),
1065d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_dumpconf,	g_part_ebr_dumpconf),
1075d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_dumpto,	g_part_ebr_dumpto),
1085d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_modify,	g_part_ebr_modify),
1095d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_name,		g_part_ebr_name),
11064612d4eSConrad Meyer 	KOBJMETHOD(g_part_new_provider,	g_part_ebr_new_provider),
111e24c8a3fSMarcel Moolenaar 	KOBJMETHOD(g_part_precheck,	g_part_ebr_precheck),
1125d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_probe,	g_part_ebr_probe),
1135d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_read,		g_part_ebr_read),
114884c8e4fSAndrey V. Elsukov 	KOBJMETHOD(g_part_resize,	g_part_ebr_resize),
1155d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_setunset,	g_part_ebr_setunset),
1165d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_type,		g_part_ebr_type),
1175d68db5bSMarcel Moolenaar 	KOBJMETHOD(g_part_write,	g_part_ebr_write),
1185d68db5bSMarcel Moolenaar 	{ 0, 0 }
1195d68db5bSMarcel Moolenaar };
1205d68db5bSMarcel Moolenaar 
1215d68db5bSMarcel Moolenaar static struct g_part_scheme g_part_ebr_scheme = {
1225d68db5bSMarcel Moolenaar 	"EBR",
1235d68db5bSMarcel Moolenaar 	g_part_ebr_methods,
1245d68db5bSMarcel Moolenaar 	sizeof(struct g_part_ebr_table),
1255d68db5bSMarcel Moolenaar 	.gps_entrysz = sizeof(struct g_part_ebr_entry),
1265d68db5bSMarcel Moolenaar 	.gps_minent = 1,
127*09c999b1SWarner Losh 	.gps_defent = 1,
1285d68db5bSMarcel Moolenaar 	.gps_maxent = INT_MAX,
1295d68db5bSMarcel Moolenaar };
1305d68db5bSMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_ebr);
13174d6c131SKyle Evans MODULE_VERSION(geom_part_ebr, 0);
1325d68db5bSMarcel Moolenaar 
13388007f61SAndrey V. Elsukov static struct g_part_ebr_alias {
13488007f61SAndrey V. Elsukov 	u_char		typ;
13588007f61SAndrey V. Elsukov 	int		alias;
13688007f61SAndrey V. Elsukov } ebr_alias_match[] = {
13788007f61SAndrey V. Elsukov 	{ DOSPTYP_386BSD,	G_PART_ALIAS_FREEBSD },
13876db6c87SEd Maste 	{ DOSPTYP_EFI,		G_PART_ALIAS_EFI },
13988007f61SAndrey V. Elsukov 	{ DOSPTYP_FAT32,	G_PART_ALIAS_MS_FAT32 },
140b525a10aSEd Maste 	{ DOSPTYP_FAT32LBA,	G_PART_ALIAS_MS_FAT32LBA },
14188007f61SAndrey V. Elsukov 	{ DOSPTYP_LINLVM,	G_PART_ALIAS_LINUX_LVM },
14288007f61SAndrey V. Elsukov 	{ DOSPTYP_LINRAID,	G_PART_ALIAS_LINUX_RAID },
143a0a8412bSEd Maste 	{ DOSPTYP_LINSWP,	G_PART_ALIAS_LINUX_SWAP },
144a0a8412bSEd Maste 	{ DOSPTYP_LINUX,	G_PART_ALIAS_LINUX_DATA },
145a0a8412bSEd Maste 	{ DOSPTYP_NTFS,		G_PART_ALIAS_MS_NTFS },
14688007f61SAndrey V. Elsukov };
14788007f61SAndrey V. Elsukov 
148e24c8a3fSMarcel Moolenaar static void ebr_set_chs(struct g_part_table *, uint32_t, u_char *, u_char *,
149e24c8a3fSMarcel Moolenaar     u_char *);
150e24c8a3fSMarcel Moolenaar 
1515d68db5bSMarcel Moolenaar static void
ebr_entry_decode(const char * p,struct dos_partition * ent)1525d68db5bSMarcel Moolenaar ebr_entry_decode(const char *p, struct dos_partition *ent)
1535d68db5bSMarcel Moolenaar {
1545d68db5bSMarcel Moolenaar 	ent->dp_flag = p[0];
1555d68db5bSMarcel Moolenaar 	ent->dp_shd = p[1];
1565d68db5bSMarcel Moolenaar 	ent->dp_ssect = p[2];
1575d68db5bSMarcel Moolenaar 	ent->dp_scyl = p[3];
1585d68db5bSMarcel Moolenaar 	ent->dp_typ = p[4];
1595d68db5bSMarcel Moolenaar 	ent->dp_ehd = p[5];
1605d68db5bSMarcel Moolenaar 	ent->dp_esect = p[6];
1615d68db5bSMarcel Moolenaar 	ent->dp_ecyl = p[7];
1625d68db5bSMarcel Moolenaar 	ent->dp_start = le32dec(p + 8);
1635d68db5bSMarcel Moolenaar 	ent->dp_size = le32dec(p + 12);
1645d68db5bSMarcel Moolenaar }
1655d68db5bSMarcel Moolenaar 
166e24c8a3fSMarcel Moolenaar static void
ebr_entry_link(struct g_part_table * table,uint32_t start,uint32_t end,u_char * buf)167e24c8a3fSMarcel Moolenaar ebr_entry_link(struct g_part_table *table, uint32_t start, uint32_t end,
168e24c8a3fSMarcel Moolenaar    u_char *buf)
169e24c8a3fSMarcel Moolenaar {
170e24c8a3fSMarcel Moolenaar 
171e24c8a3fSMarcel Moolenaar 	buf[0] = 0 /* dp_flag */;
172e24c8a3fSMarcel Moolenaar 	ebr_set_chs(table, start, &buf[3] /* dp_scyl */, &buf[1] /* dp_shd */,
173e24c8a3fSMarcel Moolenaar 	    &buf[2] /* dp_ssect */);
17464612d4eSConrad Meyer 	buf[4] = DOSPTYP_EXT /* dp_typ */;
175e24c8a3fSMarcel Moolenaar 	ebr_set_chs(table, end, &buf[7] /* dp_ecyl */, &buf[5] /* dp_ehd */,
176e24c8a3fSMarcel Moolenaar 	    &buf[6] /* dp_esect */);
177e24c8a3fSMarcel Moolenaar 	le32enc(buf + 8, start);
178e24c8a3fSMarcel Moolenaar 	le32enc(buf + 12, end - start + 1);
179e24c8a3fSMarcel Moolenaar }
180e24c8a3fSMarcel Moolenaar 
181e24c8a3fSMarcel Moolenaar static int
ebr_parse_type(const char * type,u_char * dp_typ)182e24c8a3fSMarcel Moolenaar ebr_parse_type(const char *type, u_char *dp_typ)
183e24c8a3fSMarcel Moolenaar {
184e24c8a3fSMarcel Moolenaar 	const char *alias;
185e24c8a3fSMarcel Moolenaar 	char *endp;
186e24c8a3fSMarcel Moolenaar 	long lt;
18788007f61SAndrey V. Elsukov 	int i;
188e24c8a3fSMarcel Moolenaar 
189e24c8a3fSMarcel Moolenaar 	if (type[0] == '!') {
190e24c8a3fSMarcel Moolenaar 		lt = strtol(type + 1, &endp, 0);
191e24c8a3fSMarcel Moolenaar 		if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256)
192e24c8a3fSMarcel Moolenaar 			return (EINVAL);
193e24c8a3fSMarcel Moolenaar 		*dp_typ = (u_char)lt;
194e24c8a3fSMarcel Moolenaar 		return (0);
195e24c8a3fSMarcel Moolenaar 	}
19663b6b7a7SPedro F. Giffuni 	for (i = 0; i < nitems(ebr_alias_match); i++) {
19788007f61SAndrey V. Elsukov 		alias = g_part_alias_name(ebr_alias_match[i].alias);
19888007f61SAndrey V. Elsukov 		if (strcasecmp(type, alias) == 0) {
19988007f61SAndrey V. Elsukov 			*dp_typ = ebr_alias_match[i].typ;
200e24c8a3fSMarcel Moolenaar 			return (0);
201e24c8a3fSMarcel Moolenaar 		}
20288007f61SAndrey V. Elsukov 	}
203e24c8a3fSMarcel Moolenaar 	return (EINVAL);
204e24c8a3fSMarcel Moolenaar }
205e24c8a3fSMarcel Moolenaar 
206e24c8a3fSMarcel Moolenaar static void
ebr_set_chs(struct g_part_table * table,uint32_t lba,u_char * cylp,u_char * hdp,u_char * secp)207e24c8a3fSMarcel Moolenaar ebr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp,
208e24c8a3fSMarcel Moolenaar     u_char *secp)
209e24c8a3fSMarcel Moolenaar {
210e24c8a3fSMarcel Moolenaar 	uint32_t cyl, hd, sec;
211e24c8a3fSMarcel Moolenaar 
212e24c8a3fSMarcel Moolenaar 	sec = lba % table->gpt_sectors + 1;
213e24c8a3fSMarcel Moolenaar 	lba /= table->gpt_sectors;
214e24c8a3fSMarcel Moolenaar 	hd = lba % table->gpt_heads;
215e24c8a3fSMarcel Moolenaar 	lba /= table->gpt_heads;
216e24c8a3fSMarcel Moolenaar 	cyl = lba;
217e24c8a3fSMarcel Moolenaar 	if (cyl > 1023)
218e24c8a3fSMarcel Moolenaar 		sec = hd = cyl = ~0;
219e24c8a3fSMarcel Moolenaar 
220e24c8a3fSMarcel Moolenaar 	*cylp = cyl & 0xff;
221e24c8a3fSMarcel Moolenaar 	*hdp = hd & 0xff;
222e24c8a3fSMarcel Moolenaar 	*secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0);
223e24c8a3fSMarcel Moolenaar }
224e24c8a3fSMarcel Moolenaar 
2255d68db5bSMarcel Moolenaar static int
ebr_align(struct g_part_table * basetable,uint32_t * start,uint32_t * size)226bc1e8f56SAndrey V. Elsukov ebr_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size)
227bc1e8f56SAndrey V. Elsukov {
228bc1e8f56SAndrey V. Elsukov 	uint32_t sectors;
229bc1e8f56SAndrey V. Elsukov 
230bc1e8f56SAndrey V. Elsukov 	sectors = basetable->gpt_sectors;
231bc1e8f56SAndrey V. Elsukov 	if (*size < 2 * sectors)
232bc1e8f56SAndrey V. Elsukov 		return (EINVAL);
233bc1e8f56SAndrey V. Elsukov 	if (*start % sectors) {
234bc1e8f56SAndrey V. Elsukov 		*size += (*start % sectors) - sectors;
235bc1e8f56SAndrey V. Elsukov 		*start -= (*start % sectors) - sectors;
236bc1e8f56SAndrey V. Elsukov 	}
237bc1e8f56SAndrey V. Elsukov 	if (*size % sectors)
238bc1e8f56SAndrey V. Elsukov 		*size -= (*size % sectors);
239bc1e8f56SAndrey V. Elsukov 	if (*size < 2 * sectors)
240bc1e8f56SAndrey V. Elsukov 		return (EINVAL);
241bc1e8f56SAndrey V. Elsukov 	return (0);
242bc1e8f56SAndrey V. Elsukov }
243bc1e8f56SAndrey V. Elsukov 
244bc1e8f56SAndrey V. Elsukov static int
g_part_ebr_add(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)2455d68db5bSMarcel Moolenaar g_part_ebr_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
2465d68db5bSMarcel Moolenaar     struct g_part_parms *gpp)
2475d68db5bSMarcel Moolenaar {
248e24c8a3fSMarcel Moolenaar 	struct g_provider *pp;
249e24c8a3fSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
25064612d4eSConrad Meyer 	struct g_part_entry *iter;
251bc1e8f56SAndrey V. Elsukov 	uint32_t start, size;
25264612d4eSConrad Meyer 	u_int idx;
2535d68db5bSMarcel Moolenaar 
254e24c8a3fSMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_LABEL)
255e24c8a3fSMarcel Moolenaar 		return (EINVAL);
256e24c8a3fSMarcel Moolenaar 
257bc1e8f56SAndrey V. Elsukov 	pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
258e24c8a3fSMarcel Moolenaar 	entry = (struct g_part_ebr_entry *)baseentry;
259e24c8a3fSMarcel Moolenaar 	start = gpp->gpp_start;
260e24c8a3fSMarcel Moolenaar 	size = gpp->gpp_size;
261bc1e8f56SAndrey V. Elsukov 	if (ebr_align(basetable, &start, &size) != 0)
262e24c8a3fSMarcel Moolenaar 		return (EINVAL);
263e24c8a3fSMarcel Moolenaar 	if (baseentry->gpe_deleted)
264e24c8a3fSMarcel Moolenaar 		bzero(&entry->ent, sizeof(entry->ent));
265e24c8a3fSMarcel Moolenaar 
26642a783c1SRui Paulo 	KASSERT(baseentry->gpe_start <= start, ("%s", __func__));
26742a783c1SRui Paulo 	KASSERT(baseentry->gpe_end >= start + size - 1, ("%s", __func__));
268bc1e8f56SAndrey V. Elsukov 	baseentry->gpe_index = (start / basetable->gpt_sectors) + 1;
269bc1e8f56SAndrey V. Elsukov 	baseentry->gpe_offset =
270bc1e8f56SAndrey V. Elsukov 	    (off_t)(start + basetable->gpt_sectors) * pp->sectorsize;
271e24c8a3fSMarcel Moolenaar 	baseentry->gpe_start = start;
272e24c8a3fSMarcel Moolenaar 	baseentry->gpe_end = start + size - 1;
273bc1e8f56SAndrey V. Elsukov 	entry->ent.dp_start = basetable->gpt_sectors;
274bc1e8f56SAndrey V. Elsukov 	entry->ent.dp_size = size - basetable->gpt_sectors;
275e24c8a3fSMarcel Moolenaar 	ebr_set_chs(basetable, entry->ent.dp_start, &entry->ent.dp_scyl,
276e24c8a3fSMarcel Moolenaar 	    &entry->ent.dp_shd, &entry->ent.dp_ssect);
277e24c8a3fSMarcel Moolenaar 	ebr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl,
278e24c8a3fSMarcel Moolenaar 	    &entry->ent.dp_ehd, &entry->ent.dp_esect);
27964612d4eSConrad Meyer 
28064612d4eSConrad Meyer 	idx = 5;
28164612d4eSConrad Meyer 	LIST_FOREACH(iter, &basetable->gpt_entry, gpe_entry)
28264612d4eSConrad Meyer 		idx++;
28364612d4eSConrad Meyer 	entry->ebr_compat_idx = idx;
284e24c8a3fSMarcel Moolenaar 	return (ebr_parse_type(gpp->gpp_type, &entry->ent.dp_typ));
2855d68db5bSMarcel Moolenaar }
2865d68db5bSMarcel Moolenaar 
28764612d4eSConrad Meyer static void
g_part_ebr_add_alias(struct g_part_table * table,struct g_provider * pp,struct g_part_entry * baseentry,const char * pfx)28864612d4eSConrad Meyer g_part_ebr_add_alias(struct g_part_table *table, struct g_provider *pp,
28964612d4eSConrad Meyer     struct g_part_entry *baseentry, const char *pfx)
29064612d4eSConrad Meyer {
29164612d4eSConrad Meyer 	struct g_part_ebr_entry *entry;
29264612d4eSConrad Meyer 
29364612d4eSConrad Meyer 	g_provider_add_alias(pp, "%s%s" EBRNAMFMT, pfx, g_part_separator,
29464612d4eSConrad Meyer 	    baseentry->gpe_index);
29564612d4eSConrad Meyer 	entry = (struct g_part_ebr_entry *)baseentry;
29664612d4eSConrad Meyer 	g_provider_add_alias(pp, "%.*s%u", (int)strlen(pfx) - 1, pfx,
29764612d4eSConrad Meyer 	    entry->ebr_compat_idx);
29864612d4eSConrad Meyer }
29964612d4eSConrad Meyer 
30064612d4eSConrad Meyer static struct g_provider *
g_part_ebr_new_provider(struct g_part_table * table,struct g_geom * gp,struct g_part_entry * baseentry,const char * pfx)30164612d4eSConrad Meyer g_part_ebr_new_provider(struct g_part_table *table, struct g_geom *gp,
30264612d4eSConrad Meyer     struct g_part_entry *baseentry, const char *pfx)
30364612d4eSConrad Meyer {
30464612d4eSConrad Meyer 	struct g_part_ebr_entry *entry;
30564612d4eSConrad Meyer 	struct g_provider *pp;
30664612d4eSConrad Meyer 
30764612d4eSConrad Meyer 	pp = g_new_providerf(gp, "%s%s" EBRNAMFMT, pfx, g_part_separator,
30864612d4eSConrad Meyer 	    baseentry->gpe_index);
30964612d4eSConrad Meyer 	entry = (struct g_part_ebr_entry *)baseentry;
31064612d4eSConrad Meyer 	g_provider_add_alias(pp, "%.*s%u", (int)strlen(pfx) - 1, pfx,
31164612d4eSConrad Meyer 	    entry->ebr_compat_idx);
31264612d4eSConrad Meyer 	return (pp);
31364612d4eSConrad Meyer }
31464612d4eSConrad Meyer 
3155d68db5bSMarcel Moolenaar static int
g_part_ebr_create(struct g_part_table * basetable,struct g_part_parms * gpp)3165d68db5bSMarcel Moolenaar g_part_ebr_create(struct g_part_table *basetable, struct g_part_parms *gpp)
3175d68db5bSMarcel Moolenaar {
3183bcf7d71SAndrey V. Elsukov 	char type[64];
319e24c8a3fSMarcel Moolenaar 	struct g_consumer *cp;
320e24c8a3fSMarcel Moolenaar 	struct g_provider *pp;
321f5f875edSMarcel Moolenaar 	uint32_t msize;
322e24c8a3fSMarcel Moolenaar 	int error;
3235d68db5bSMarcel Moolenaar 
324e24c8a3fSMarcel Moolenaar 	pp = gpp->gpp_provider;
325e24c8a3fSMarcel Moolenaar 
326e24c8a3fSMarcel Moolenaar 	if (pp->sectorsize < EBRSIZE)
327e24c8a3fSMarcel Moolenaar 		return (ENOSPC);
328e24c8a3fSMarcel Moolenaar 	if (pp->sectorsize > 4096)
329e24c8a3fSMarcel Moolenaar 		return (ENXIO);
330e24c8a3fSMarcel Moolenaar 
331e24c8a3fSMarcel Moolenaar 	/* Check that we have a parent and that it's a MBR. */
332e24c8a3fSMarcel Moolenaar 	if (basetable->gpt_depth == 0)
333e24c8a3fSMarcel Moolenaar 		return (ENXIO);
334e24c8a3fSMarcel Moolenaar 	cp = LIST_FIRST(&pp->consumers);
3353bcf7d71SAndrey V. Elsukov 	error = g_getattr("PART::scheme", cp, &type);
3363bcf7d71SAndrey V. Elsukov 	if (error != 0)
337e24c8a3fSMarcel Moolenaar 		return (error);
3383bcf7d71SAndrey V. Elsukov 	if (strcmp(type, "MBR") != 0)
3393bcf7d71SAndrey V. Elsukov 		return (ENXIO);
3403bcf7d71SAndrey V. Elsukov 	error = g_getattr("PART::type", cp, &type);
3413bcf7d71SAndrey V. Elsukov 	if (error != 0)
3423bcf7d71SAndrey V. Elsukov 		return (error);
3433bcf7d71SAndrey V. Elsukov 	if (strcmp(type, "ebr") != 0)
344e24c8a3fSMarcel Moolenaar 		return (ENXIO);
345e24c8a3fSMarcel Moolenaar 
346284a82d0SAndrey V. Elsukov 	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
347e24c8a3fSMarcel Moolenaar 	basetable->gpt_first = 0;
348f5f875edSMarcel Moolenaar 	basetable->gpt_last = msize - 1;
349f5f875edSMarcel Moolenaar 	basetable->gpt_entries = msize / basetable->gpt_sectors;
350e24c8a3fSMarcel Moolenaar 	return (0);
3515d68db5bSMarcel Moolenaar }
3525d68db5bSMarcel Moolenaar 
3535d68db5bSMarcel Moolenaar static int
g_part_ebr_destroy(struct g_part_table * basetable,struct g_part_parms * gpp)3545d68db5bSMarcel Moolenaar g_part_ebr_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
3555d68db5bSMarcel Moolenaar {
3565d68db5bSMarcel Moolenaar 
3575d68db5bSMarcel Moolenaar 	/* Wipe the first sector to clear the partitioning. */
3585d68db5bSMarcel Moolenaar 	basetable->gpt_smhead |= 1;
3595d68db5bSMarcel Moolenaar 	return (0);
3605d68db5bSMarcel Moolenaar }
3615d68db5bSMarcel Moolenaar 
3625d68db5bSMarcel Moolenaar static void
g_part_ebr_dumpconf(struct g_part_table * table,struct g_part_entry * baseentry,struct sbuf * sb,const char * indent)3635d68db5bSMarcel Moolenaar g_part_ebr_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry,
3645d68db5bSMarcel Moolenaar     struct sbuf *sb, const char *indent)
3655d68db5bSMarcel Moolenaar {
3665d68db5bSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
3675d68db5bSMarcel Moolenaar 
3685d68db5bSMarcel Moolenaar 	entry = (struct g_part_ebr_entry *)baseentry;
3695d68db5bSMarcel Moolenaar 	if (indent == NULL) {
3705d68db5bSMarcel Moolenaar 		/* conftxt: libdisk compatibility */
3715d68db5bSMarcel Moolenaar 		sbuf_printf(sb, " xs MBREXT xt %u", entry->ent.dp_typ);
3725d68db5bSMarcel Moolenaar 	} else if (entry != NULL) {
3735d68db5bSMarcel Moolenaar 		/* confxml: partition entry information */
3745d68db5bSMarcel Moolenaar 		sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
3755d68db5bSMarcel Moolenaar 		    entry->ent.dp_typ);
3765d68db5bSMarcel Moolenaar 		if (entry->ent.dp_flag & 0x80)
3775d68db5bSMarcel Moolenaar 			sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent);
3785d68db5bSMarcel Moolenaar 	} else {
3795d68db5bSMarcel Moolenaar 		/* confxml: scheme information */
3805d68db5bSMarcel Moolenaar 	}
3815d68db5bSMarcel Moolenaar }
3825d68db5bSMarcel Moolenaar 
3835d68db5bSMarcel Moolenaar static int
g_part_ebr_dumpto(struct g_part_table * table,struct g_part_entry * baseentry)3845d68db5bSMarcel Moolenaar g_part_ebr_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
3855d68db5bSMarcel Moolenaar {
3865d68db5bSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
3875d68db5bSMarcel Moolenaar 
388b5bad281SDon Lewis 	/* Allow dumping to a FreeBSD partition or Linux swap partition only. */
3895d68db5bSMarcel Moolenaar 	entry = (struct g_part_ebr_entry *)baseentry;
390b5bad281SDon Lewis 	return ((entry->ent.dp_typ == DOSPTYP_386BSD ||
391b5bad281SDon Lewis 	    entry->ent.dp_typ == DOSPTYP_LINSWP) ? 1 : 0);
3925d68db5bSMarcel Moolenaar }
3935d68db5bSMarcel Moolenaar 
3945d68db5bSMarcel Moolenaar static int
g_part_ebr_modify(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)3955d68db5bSMarcel Moolenaar g_part_ebr_modify(struct g_part_table *basetable,
3965d68db5bSMarcel Moolenaar     struct g_part_entry *baseentry, struct g_part_parms *gpp)
3975d68db5bSMarcel Moolenaar {
398e24c8a3fSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
3995d68db5bSMarcel Moolenaar 
400e24c8a3fSMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_LABEL)
401e24c8a3fSMarcel Moolenaar 		return (EINVAL);
402e24c8a3fSMarcel Moolenaar 
403e24c8a3fSMarcel Moolenaar 	entry = (struct g_part_ebr_entry *)baseentry;
404e24c8a3fSMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_TYPE)
405e24c8a3fSMarcel Moolenaar 		return (ebr_parse_type(gpp->gpp_type, &entry->ent.dp_typ));
406e24c8a3fSMarcel Moolenaar 	return (0);
4075d68db5bSMarcel Moolenaar }
4085d68db5bSMarcel Moolenaar 
409884c8e4fSAndrey V. Elsukov static int
g_part_ebr_resize(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)410884c8e4fSAndrey V. Elsukov g_part_ebr_resize(struct g_part_table *basetable,
411884c8e4fSAndrey V. Elsukov     struct g_part_entry *baseentry, struct g_part_parms *gpp)
412884c8e4fSAndrey V. Elsukov {
413884c8e4fSAndrey V. Elsukov 	struct g_provider *pp;
414884c8e4fSAndrey V. Elsukov 
415884c8e4fSAndrey V. Elsukov 	if (baseentry != NULL)
416884c8e4fSAndrey V. Elsukov 		return (EOPNOTSUPP);
417884c8e4fSAndrey V. Elsukov 	pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
418884c8e4fSAndrey V. Elsukov 	basetable->gpt_last = MIN(pp->mediasize / pp->sectorsize,
419884c8e4fSAndrey V. Elsukov 	    UINT32_MAX) - 1;
420884c8e4fSAndrey V. Elsukov 	return (0);
421884c8e4fSAndrey V. Elsukov }
422884c8e4fSAndrey V. Elsukov 
4235d68db5bSMarcel Moolenaar static const char *
g_part_ebr_name(struct g_part_table * table,struct g_part_entry * entry,char * buf,size_t bufsz)4245d68db5bSMarcel Moolenaar g_part_ebr_name(struct g_part_table *table, struct g_part_entry *entry,
4255d68db5bSMarcel Moolenaar     char *buf, size_t bufsz)
4265d68db5bSMarcel Moolenaar {
42764612d4eSConrad Meyer 	snprintf(buf, bufsz, EBRNAMFMT, entry->gpe_index);
4285d68db5bSMarcel Moolenaar 	return (buf);
4295d68db5bSMarcel Moolenaar }
4305d68db5bSMarcel Moolenaar 
4315d68db5bSMarcel Moolenaar static int
g_part_ebr_precheck(struct g_part_table * table,enum g_part_ctl req,struct g_part_parms * gpp)432e24c8a3fSMarcel Moolenaar g_part_ebr_precheck(struct g_part_table *table, enum g_part_ctl req,
433e24c8a3fSMarcel Moolenaar     struct g_part_parms *gpp)
434e24c8a3fSMarcel Moolenaar {
435e24c8a3fSMarcel Moolenaar 	/*
436e24c8a3fSMarcel Moolenaar 	 * The index is a function of the start of the partition.
437e24c8a3fSMarcel Moolenaar 	 * This is not something the user can override, nor is it
438e24c8a3fSMarcel Moolenaar 	 * something the common code will do right. We can set the
439e24c8a3fSMarcel Moolenaar 	 * index now so that we get what we need.
440e24c8a3fSMarcel Moolenaar 	 */
441e24c8a3fSMarcel Moolenaar 	if (req == G_PART_CTL_ADD)
442e24c8a3fSMarcel Moolenaar 		gpp->gpp_index = (gpp->gpp_start / table->gpt_sectors) + 1;
443e24c8a3fSMarcel Moolenaar 	return (0);
444e24c8a3fSMarcel Moolenaar }
445e24c8a3fSMarcel Moolenaar 
446e24c8a3fSMarcel Moolenaar static int
g_part_ebr_probe(struct g_part_table * table,struct g_consumer * cp)4475d68db5bSMarcel Moolenaar g_part_ebr_probe(struct g_part_table *table, struct g_consumer *cp)
4485d68db5bSMarcel Moolenaar {
4493bcf7d71SAndrey V. Elsukov 	char type[64];
4505d68db5bSMarcel Moolenaar 	struct g_provider *pp;
4515d68db5bSMarcel Moolenaar 	u_char *buf, *p;
452d3507dffSAndrey V. Elsukov 	int error, index, res;
4535d68db5bSMarcel Moolenaar 	uint16_t magic;
4545d68db5bSMarcel Moolenaar 
4555d68db5bSMarcel Moolenaar 	pp = cp->provider;
4565d68db5bSMarcel Moolenaar 
4575d68db5bSMarcel Moolenaar 	/* Sanity-check the provider. */
4585d68db5bSMarcel Moolenaar 	if (pp->sectorsize < EBRSIZE || pp->mediasize < pp->sectorsize)
4595d68db5bSMarcel Moolenaar 		return (ENOSPC);
4605d68db5bSMarcel Moolenaar 	if (pp->sectorsize > 4096)
4615d68db5bSMarcel Moolenaar 		return (ENXIO);
4625d68db5bSMarcel Moolenaar 
4635d68db5bSMarcel Moolenaar 	/* Check that we have a parent and that it's a MBR. */
4645d68db5bSMarcel Moolenaar 	if (table->gpt_depth == 0)
4655d68db5bSMarcel Moolenaar 		return (ENXIO);
4663bcf7d71SAndrey V. Elsukov 	error = g_getattr("PART::scheme", cp, &type);
4673bcf7d71SAndrey V. Elsukov 	if (error != 0)
4685d68db5bSMarcel Moolenaar 		return (error);
4693bcf7d71SAndrey V. Elsukov 	if (strcmp(type, "MBR") != 0)
4703bcf7d71SAndrey V. Elsukov 		return (ENXIO);
4713bcf7d71SAndrey V. Elsukov 	/* Check that partition has type DOSPTYP_EBR. */
4723bcf7d71SAndrey V. Elsukov 	error = g_getattr("PART::type", cp, &type);
4733bcf7d71SAndrey V. Elsukov 	if (error != 0)
4743bcf7d71SAndrey V. Elsukov 		return (error);
4753bcf7d71SAndrey V. Elsukov 	if (strcmp(type, "ebr") != 0)
4765d68db5bSMarcel Moolenaar 		return (ENXIO);
4775d68db5bSMarcel Moolenaar 
4785d68db5bSMarcel Moolenaar 	/* Check that there's a EBR. */
4795d68db5bSMarcel Moolenaar 	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
4805d68db5bSMarcel Moolenaar 	if (buf == NULL)
4815d68db5bSMarcel Moolenaar 		return (error);
4825d68db5bSMarcel Moolenaar 
4835d68db5bSMarcel Moolenaar 	/* We goto out on mismatch. */
4845d68db5bSMarcel Moolenaar 	res = ENXIO;
4855d68db5bSMarcel Moolenaar 
4865d68db5bSMarcel Moolenaar 	magic = le16dec(buf + DOSMAGICOFFSET);
4875d68db5bSMarcel Moolenaar 	if (magic != DOSMAGIC)
4885d68db5bSMarcel Moolenaar 		goto out;
4895d68db5bSMarcel Moolenaar 
490d3507dffSAndrey V. Elsukov 	for (index = 0; index < 2; index++) {
4915d68db5bSMarcel Moolenaar 		p = buf + DOSPARTOFF + index * DOSPARTSIZE;
4925d68db5bSMarcel Moolenaar 		if (p[0] != 0 && p[0] != 0x80)
4935d68db5bSMarcel Moolenaar 			goto out;
4945d68db5bSMarcel Moolenaar 	}
495f3548c02SMarcel Moolenaar 	res = G_PART_PROBE_PRI_NORM;
4965d68db5bSMarcel Moolenaar 
4975d68db5bSMarcel Moolenaar  out:
4985d68db5bSMarcel Moolenaar 	g_free(buf);
4995d68db5bSMarcel Moolenaar 	return (res);
5005d68db5bSMarcel Moolenaar }
5015d68db5bSMarcel Moolenaar 
5025d68db5bSMarcel Moolenaar static int
g_part_ebr_read(struct g_part_table * basetable,struct g_consumer * cp)5035d68db5bSMarcel Moolenaar g_part_ebr_read(struct g_part_table *basetable, struct g_consumer *cp)
5045d68db5bSMarcel Moolenaar {
5055d68db5bSMarcel Moolenaar 	struct dos_partition ent[2];
5065d68db5bSMarcel Moolenaar 	struct g_provider *pp;
5075d68db5bSMarcel Moolenaar 	struct g_part_entry *baseentry;
5085d68db5bSMarcel Moolenaar 	struct g_part_ebr_table *table;
5095d68db5bSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
5105d68db5bSMarcel Moolenaar 	u_char *buf;
5115d68db5bSMarcel Moolenaar 	off_t ofs, msize;
51264612d4eSConrad Meyer 	u_int lba, idx;
513671dfdbfSAndrey V. Elsukov 	int error, index;
5145d68db5bSMarcel Moolenaar 
51564612d4eSConrad Meyer 	idx = 5;
5165d68db5bSMarcel Moolenaar 	pp = cp->provider;
5175d68db5bSMarcel Moolenaar 	table = (struct g_part_ebr_table *)basetable;
518284a82d0SAndrey V. Elsukov 	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
5195d68db5bSMarcel Moolenaar 
5205d68db5bSMarcel Moolenaar 	lba = 0;
5215d68db5bSMarcel Moolenaar 	while (1) {
5225d68db5bSMarcel Moolenaar 		ofs = (off_t)lba * pp->sectorsize;
5235d68db5bSMarcel Moolenaar 		buf = g_read_data(cp, ofs, pp->sectorsize, &error);
5245d68db5bSMarcel Moolenaar 		if (buf == NULL)
5255d68db5bSMarcel Moolenaar 			return (error);
5265d68db5bSMarcel Moolenaar 
5275d68db5bSMarcel Moolenaar 		ebr_entry_decode(buf + DOSPARTOFF + 0 * DOSPARTSIZE, ent + 0);
5285d68db5bSMarcel Moolenaar 		ebr_entry_decode(buf + DOSPARTOFF + 1 * DOSPARTSIZE, ent + 1);
529d3507dffSAndrey V. Elsukov 
530d3507dffSAndrey V. Elsukov 		/* The 3rd & 4th entries should be zeroes. */
531d3507dffSAndrey V. Elsukov 		if (le64dec(buf + DOSPARTOFF + 2 * DOSPARTSIZE) +
532d3507dffSAndrey V. Elsukov 		    le64dec(buf + DOSPARTOFF + 3 * DOSPARTSIZE) != 0) {
533d3507dffSAndrey V. Elsukov 			basetable->gpt_corrupt = 1;
534d3507dffSAndrey V. Elsukov 			printf("GEOM: %s: invalid entries in the EBR ignored.\n",
535d3507dffSAndrey V. Elsukov 			    pp->name);
536d3507dffSAndrey V. Elsukov 		}
53764612d4eSConrad Meyer 		/*
53864612d4eSConrad Meyer 		 * Preserve EBR, it can contain boot code or other metadata we
53964612d4eSConrad Meyer 		 * are ignorant of.
54064612d4eSConrad Meyer 		 */
541671dfdbfSAndrey V. Elsukov 		if (lba == 0)
54264612d4eSConrad Meyer 			memcpy(table->lba0_ebr, buf, sizeof(table->lba0_ebr));
5435d68db5bSMarcel Moolenaar 
54464612d4eSConrad Meyer 		if (ent[0].dp_typ == 0) {
54564612d4eSConrad Meyer 			g_free(buf);
5465d68db5bSMarcel Moolenaar 			break;
54764612d4eSConrad Meyer 		}
5485d68db5bSMarcel Moolenaar 
5495d68db5bSMarcel Moolenaar 		if (ent[0].dp_typ == 5 && ent[1].dp_typ == 0) {
5505d68db5bSMarcel Moolenaar 			lba = ent[0].dp_start;
55164612d4eSConrad Meyer 			g_free(buf);
5525d68db5bSMarcel Moolenaar 			continue;
5535d68db5bSMarcel Moolenaar 		}
5545d68db5bSMarcel Moolenaar 
5555d68db5bSMarcel Moolenaar 		index = (lba / basetable->gpt_sectors) + 1;
5565d68db5bSMarcel Moolenaar 		baseentry = (struct g_part_entry *)g_part_new_entry(basetable,
5575d68db5bSMarcel Moolenaar 		    index, lba, lba + ent[0].dp_start + ent[0].dp_size - 1);
5585d68db5bSMarcel Moolenaar 		baseentry->gpe_offset = (off_t)(lba + ent[0].dp_start) *
5595d68db5bSMarcel Moolenaar 		    pp->sectorsize;
5605d68db5bSMarcel Moolenaar 		entry = (struct g_part_ebr_entry *)baseentry;
5615d68db5bSMarcel Moolenaar 		entry->ent = ent[0];
56264612d4eSConrad Meyer 		memcpy(entry->ebr, buf, sizeof(entry->ebr));
56364612d4eSConrad Meyer 		entry->ebr_compat_idx = idx++;
56464612d4eSConrad Meyer 		g_free(buf);
5655d68db5bSMarcel Moolenaar 
5665d68db5bSMarcel Moolenaar 		if (ent[1].dp_typ == 0)
5675d68db5bSMarcel Moolenaar 			break;
5685d68db5bSMarcel Moolenaar 
5695d68db5bSMarcel Moolenaar 		lba = ent[1].dp_start;
5705d68db5bSMarcel Moolenaar 	}
5715d68db5bSMarcel Moolenaar 
5725d68db5bSMarcel Moolenaar 	basetable->gpt_entries = msize / basetable->gpt_sectors;
5735d68db5bSMarcel Moolenaar 	basetable->gpt_first = 0;
57423a34900SAndrey V. Elsukov 	basetable->gpt_last = msize - 1;
5755d68db5bSMarcel Moolenaar 	return (0);
5765d68db5bSMarcel Moolenaar }
5775d68db5bSMarcel Moolenaar 
5785d68db5bSMarcel Moolenaar static int
g_part_ebr_setunset(struct g_part_table * table,struct g_part_entry * baseentry,const char * attrib,unsigned int set)5795d68db5bSMarcel Moolenaar g_part_ebr_setunset(struct g_part_table *table, struct g_part_entry *baseentry,
5805d68db5bSMarcel Moolenaar     const char *attrib, unsigned int set)
5815d68db5bSMarcel Moolenaar {
582e24c8a3fSMarcel Moolenaar 	struct g_part_entry *iter;
583e24c8a3fSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
584e24c8a3fSMarcel Moolenaar 	int changed;
5855d68db5bSMarcel Moolenaar 
5863bd22a9cSMarcel Moolenaar 	if (baseentry == NULL)
5873bd22a9cSMarcel Moolenaar 		return (ENODEV);
588e24c8a3fSMarcel Moolenaar 	if (strcasecmp(attrib, "active") != 0)
589e24c8a3fSMarcel Moolenaar 		return (EINVAL);
590e24c8a3fSMarcel Moolenaar 
591e24c8a3fSMarcel Moolenaar 	/* Only one entry can have the active attribute. */
592e24c8a3fSMarcel Moolenaar 	LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) {
593e24c8a3fSMarcel Moolenaar 		if (iter->gpe_deleted)
594e24c8a3fSMarcel Moolenaar 			continue;
595e24c8a3fSMarcel Moolenaar 		changed = 0;
596e24c8a3fSMarcel Moolenaar 		entry = (struct g_part_ebr_entry *)iter;
597e24c8a3fSMarcel Moolenaar 		if (iter == baseentry) {
598e24c8a3fSMarcel Moolenaar 			if (set && (entry->ent.dp_flag & 0x80) == 0) {
599e24c8a3fSMarcel Moolenaar 				entry->ent.dp_flag |= 0x80;
600e24c8a3fSMarcel Moolenaar 				changed = 1;
601e24c8a3fSMarcel Moolenaar 			} else if (!set && (entry->ent.dp_flag & 0x80)) {
602e24c8a3fSMarcel Moolenaar 				entry->ent.dp_flag &= ~0x80;
603e24c8a3fSMarcel Moolenaar 				changed = 1;
604e24c8a3fSMarcel Moolenaar 			}
605e24c8a3fSMarcel Moolenaar 		} else {
606e24c8a3fSMarcel Moolenaar 			if (set && (entry->ent.dp_flag & 0x80)) {
607e24c8a3fSMarcel Moolenaar 				entry->ent.dp_flag &= ~0x80;
608e24c8a3fSMarcel Moolenaar 				changed = 1;
609e24c8a3fSMarcel Moolenaar 			}
610e24c8a3fSMarcel Moolenaar 		}
611e24c8a3fSMarcel Moolenaar 		if (changed && !iter->gpe_created)
612e24c8a3fSMarcel Moolenaar 			iter->gpe_modified = 1;
613e24c8a3fSMarcel Moolenaar 	}
614e24c8a3fSMarcel Moolenaar 	return (0);
6155d68db5bSMarcel Moolenaar }
6165d68db5bSMarcel Moolenaar 
6175d68db5bSMarcel Moolenaar static const char *
g_part_ebr_type(struct g_part_table * basetable,struct g_part_entry * baseentry,char * buf,size_t bufsz)6185d68db5bSMarcel Moolenaar g_part_ebr_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
6195d68db5bSMarcel Moolenaar     char *buf, size_t bufsz)
6205d68db5bSMarcel Moolenaar {
6215d68db5bSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
62288007f61SAndrey V. Elsukov 	int i;
6235d68db5bSMarcel Moolenaar 
6245d68db5bSMarcel Moolenaar 	entry = (struct g_part_ebr_entry *)baseentry;
62563b6b7a7SPedro F. Giffuni 	for (i = 0; i < nitems(ebr_alias_match); i++) {
62688007f61SAndrey V. Elsukov 		if (ebr_alias_match[i].typ == entry->ent.dp_typ)
62788007f61SAndrey V. Elsukov 			return (g_part_alias_name(ebr_alias_match[i].alias));
62888007f61SAndrey V. Elsukov 	}
62988007f61SAndrey V. Elsukov 	snprintf(buf, bufsz, "!%d", entry->ent.dp_typ);
6305d68db5bSMarcel Moolenaar 	return (buf);
6315d68db5bSMarcel Moolenaar }
6325d68db5bSMarcel Moolenaar 
6335d68db5bSMarcel Moolenaar static int
g_part_ebr_write(struct g_part_table * basetable,struct g_consumer * cp)6345d68db5bSMarcel Moolenaar g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp)
6355d68db5bSMarcel Moolenaar {
636671dfdbfSAndrey V. Elsukov 	struct g_part_ebr_table *table;
637e24c8a3fSMarcel Moolenaar 	struct g_provider *pp;
638e24c8a3fSMarcel Moolenaar 	struct g_part_entry *baseentry, *next;
639e24c8a3fSMarcel Moolenaar 	struct g_part_ebr_entry *entry;
640e24c8a3fSMarcel Moolenaar 	u_char *buf;
641e24c8a3fSMarcel Moolenaar 	u_char *p;
642e24c8a3fSMarcel Moolenaar 	int error;
6435d68db5bSMarcel Moolenaar 
644e24c8a3fSMarcel Moolenaar 	pp = cp->provider;
645e24c8a3fSMarcel Moolenaar 	buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
646671dfdbfSAndrey V. Elsukov 	table = (struct g_part_ebr_table *)basetable;
64764612d4eSConrad Meyer 
64864612d4eSConrad Meyer 	_Static_assert(DOSPARTOFF <= sizeof(table->lba0_ebr), "");
64964612d4eSConrad Meyer 	memcpy(buf, table->lba0_ebr, DOSPARTOFF);
650e24c8a3fSMarcel Moolenaar 	le16enc(buf + DOSMAGICOFFSET, DOSMAGIC);
651e24c8a3fSMarcel Moolenaar 
652e24c8a3fSMarcel Moolenaar 	baseentry = LIST_FIRST(&basetable->gpt_entry);
653e24c8a3fSMarcel Moolenaar 	while (baseentry != NULL && baseentry->gpe_deleted)
654e24c8a3fSMarcel Moolenaar 		baseentry = LIST_NEXT(baseentry, gpe_entry);
655e24c8a3fSMarcel Moolenaar 
6566bccea7cSRebecca Cran 	/* Wipe-out the first EBR when there are no slices. */
657e24c8a3fSMarcel Moolenaar 	if (baseentry == NULL) {
658e24c8a3fSMarcel Moolenaar 		error = g_write_data(cp, 0, buf, pp->sectorsize);
659e24c8a3fSMarcel Moolenaar 		goto out;
660e24c8a3fSMarcel Moolenaar 	}
661e24c8a3fSMarcel Moolenaar 
662e24c8a3fSMarcel Moolenaar 	/*
663e24c8a3fSMarcel Moolenaar 	 * If the first partition is not in LBA 0, we need to
664e24c8a3fSMarcel Moolenaar 	 * put a "link" EBR in LBA 0.
665e24c8a3fSMarcel Moolenaar 	 */
666e24c8a3fSMarcel Moolenaar 	if (baseentry->gpe_start != 0) {
667e24c8a3fSMarcel Moolenaar 		ebr_entry_link(basetable, (uint32_t)baseentry->gpe_start,
668e24c8a3fSMarcel Moolenaar 		    (uint32_t)baseentry->gpe_end, buf + DOSPARTOFF);
669e24c8a3fSMarcel Moolenaar 		error = g_write_data(cp, 0, buf, pp->sectorsize);
670e24c8a3fSMarcel Moolenaar 		if (error)
671e24c8a3fSMarcel Moolenaar 			goto out;
672e24c8a3fSMarcel Moolenaar 	}
673e24c8a3fSMarcel Moolenaar 
674e24c8a3fSMarcel Moolenaar 	do {
675e24c8a3fSMarcel Moolenaar 		entry = (struct g_part_ebr_entry *)baseentry;
676e24c8a3fSMarcel Moolenaar 
67764612d4eSConrad Meyer 		_Static_assert(DOSPARTOFF <= sizeof(entry->ebr), "");
67864612d4eSConrad Meyer 		memcpy(buf, entry->ebr, DOSPARTOFF);
67964612d4eSConrad Meyer 
680e24c8a3fSMarcel Moolenaar 		p = buf + DOSPARTOFF;
681e24c8a3fSMarcel Moolenaar 		p[0] = entry->ent.dp_flag;
682e24c8a3fSMarcel Moolenaar 		p[1] = entry->ent.dp_shd;
683e24c8a3fSMarcel Moolenaar 		p[2] = entry->ent.dp_ssect;
684e24c8a3fSMarcel Moolenaar 		p[3] = entry->ent.dp_scyl;
685e24c8a3fSMarcel Moolenaar 		p[4] = entry->ent.dp_typ;
686e24c8a3fSMarcel Moolenaar 		p[5] = entry->ent.dp_ehd;
687e24c8a3fSMarcel Moolenaar 		p[6] = entry->ent.dp_esect;
688e24c8a3fSMarcel Moolenaar 		p[7] = entry->ent.dp_ecyl;
689e24c8a3fSMarcel Moolenaar 		le32enc(p + 8, entry->ent.dp_start);
690e24c8a3fSMarcel Moolenaar 		le32enc(p + 12, entry->ent.dp_size);
691e24c8a3fSMarcel Moolenaar 
692e24c8a3fSMarcel Moolenaar 		next = LIST_NEXT(baseentry, gpe_entry);
693507a0d4aSMarcel Moolenaar 		while (next != NULL && next->gpe_deleted)
694507a0d4aSMarcel Moolenaar 			next = LIST_NEXT(next, gpe_entry);
695e24c8a3fSMarcel Moolenaar 
696e24c8a3fSMarcel Moolenaar 		p += DOSPARTSIZE;
697e24c8a3fSMarcel Moolenaar 		if (next != NULL)
698e24c8a3fSMarcel Moolenaar 			ebr_entry_link(basetable, (uint32_t)next->gpe_start,
699e24c8a3fSMarcel Moolenaar 			    (uint32_t)next->gpe_end, p);
700e24c8a3fSMarcel Moolenaar 		else
701e24c8a3fSMarcel Moolenaar 			bzero(p, DOSPARTSIZE);
702e24c8a3fSMarcel Moolenaar 
703e24c8a3fSMarcel Moolenaar 		error = g_write_data(cp, baseentry->gpe_start * pp->sectorsize,
704e24c8a3fSMarcel Moolenaar 		    buf, pp->sectorsize);
705e24c8a3fSMarcel Moolenaar 		baseentry = next;
706e24c8a3fSMarcel Moolenaar 	} while (!error && baseentry != NULL);
707e24c8a3fSMarcel Moolenaar 
708e24c8a3fSMarcel Moolenaar  out:
709e24c8a3fSMarcel Moolenaar 	g_free(buf);
710e24c8a3fSMarcel Moolenaar 	return (error);
7115d68db5bSMarcel Moolenaar }
712