1/*-
2 * Copyright (c) 2008 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/geom/part/g_part_vtoc8.c 332640 2018-04-17 02:18:04Z kevans $");
29
30#include <sys/param.h>
31#include <sys/bio.h>
32#include <sys/endian.h>
33#include <sys/kernel.h>
34#include <sys/kobj.h>
35#include <sys/limits.h>
36#include <sys/lock.h>
37#include <sys/malloc.h>
38#include <sys/mutex.h>
39#include <sys/queue.h>
40#include <sys/sbuf.h>
41#include <sys/systm.h>
42#include <sys/sysctl.h>
43#include <sys/vtoc.h>
44#include <geom/geom.h>
45#include <geom/geom_int.h>
46#include <geom/part/g_part.h>
47
48#include "g_part_if.h"
49
50FEATURE(geom_part_vtoc8, "GEOM partitioning class for SMI VTOC8 disk labels");
51
52struct g_part_vtoc8_table {
53	struct g_part_table	base;
54	struct vtoc8		vtoc;
55	uint32_t		secpercyl;
56};
57
58static int g_part_vtoc8_add(struct g_part_table *, struct g_part_entry *,
59    struct g_part_parms *);
60static int g_part_vtoc8_create(struct g_part_table *, struct g_part_parms *);
61static int g_part_vtoc8_destroy(struct g_part_table *, struct g_part_parms *);
62static void g_part_vtoc8_dumpconf(struct g_part_table *,
63    struct g_part_entry *, struct sbuf *, const char *);
64static int g_part_vtoc8_dumpto(struct g_part_table *, struct g_part_entry *);
65static int g_part_vtoc8_modify(struct g_part_table *, struct g_part_entry *,
66    struct g_part_parms *);
67static const char *g_part_vtoc8_name(struct g_part_table *,
68    struct g_part_entry *, char *, size_t);
69static int g_part_vtoc8_probe(struct g_part_table *, struct g_consumer *);
70static int g_part_vtoc8_read(struct g_part_table *, struct g_consumer *);
71static const char *g_part_vtoc8_type(struct g_part_table *,
72    struct g_part_entry *, char *, size_t);
73static int g_part_vtoc8_write(struct g_part_table *, struct g_consumer *);
74static int g_part_vtoc8_resize(struct g_part_table *, struct g_part_entry *,
75    struct g_part_parms *);
76
77static kobj_method_t g_part_vtoc8_methods[] = {
78	KOBJMETHOD(g_part_add,		g_part_vtoc8_add),
79	KOBJMETHOD(g_part_create,	g_part_vtoc8_create),
80	KOBJMETHOD(g_part_destroy,	g_part_vtoc8_destroy),
81	KOBJMETHOD(g_part_dumpconf,	g_part_vtoc8_dumpconf),
82	KOBJMETHOD(g_part_dumpto,	g_part_vtoc8_dumpto),
83	KOBJMETHOD(g_part_modify,	g_part_vtoc8_modify),
84	KOBJMETHOD(g_part_resize,	g_part_vtoc8_resize),
85	KOBJMETHOD(g_part_name,		g_part_vtoc8_name),
86	KOBJMETHOD(g_part_probe,	g_part_vtoc8_probe),
87	KOBJMETHOD(g_part_read,		g_part_vtoc8_read),
88	KOBJMETHOD(g_part_type,		g_part_vtoc8_type),
89	KOBJMETHOD(g_part_write,	g_part_vtoc8_write),
90	{ 0, 0 }
91};
92
93static struct g_part_scheme g_part_vtoc8_scheme = {
94	"VTOC8",
95	g_part_vtoc8_methods,
96	sizeof(struct g_part_vtoc8_table),
97	.gps_entrysz = sizeof(struct g_part_entry),
98	.gps_minent = VTOC8_NPARTS,
99	.gps_maxent = VTOC8_NPARTS,
100};
101G_PART_SCHEME_DECLARE(g_part_vtoc8);
102MODULE_VERSION(geom_part_vtoc8, 0);
103
104static int
105vtoc8_parse_type(const char *type, uint16_t *tag)
106{
107	const char *alias;
108	char *endp;
109	long lt;
110
111	if (type[0] == '!') {
112		lt = strtol(type + 1, &endp, 0);
113		if (type[1] == '\0' || *endp != '\0' || lt <= 0 ||
114		    lt >= 65536)
115			return (EINVAL);
116		*tag = (uint16_t)lt;
117		return (0);
118	}
119	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS);
120	if (!strcasecmp(type, alias)) {
121		*tag = VTOC_TAG_FREEBSD_NANDFS;
122		return (0);
123	}
124	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
125	if (!strcasecmp(type, alias)) {
126		*tag = VTOC_TAG_FREEBSD_SWAP;
127		return (0);
128	}
129	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
130	if (!strcasecmp(type, alias)) {
131		*tag = VTOC_TAG_FREEBSD_UFS;
132		return (0);
133	}
134	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
135	if (!strcasecmp(type, alias)) {
136		*tag = VTOC_TAG_FREEBSD_VINUM;
137		return (0);
138	}
139	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS);
140	if (!strcasecmp(type, alias)) {
141		*tag = VTOC_TAG_FREEBSD_ZFS;
142		return (0);
143	}
144	return (EINVAL);
145}
146
147static int
148vtoc8_align(struct g_part_vtoc8_table *table, uint64_t *start, uint64_t *size)
149{
150
151	if (*size < table->secpercyl)
152		return (EINVAL);
153	if (start != NULL && (*start % table->secpercyl)) {
154		*size += (*start % table->secpercyl) - table->secpercyl;
155		*start -= (*start % table->secpercyl) - table->secpercyl;
156	}
157	if (*size % table->secpercyl)
158		*size -= (*size % table->secpercyl);
159	if (*size < table->secpercyl)
160		return (EINVAL);
161	return (0);
162}
163
164static int
165g_part_vtoc8_add(struct g_part_table *basetable, struct g_part_entry *entry,
166    struct g_part_parms *gpp)
167{
168	struct g_part_vtoc8_table *table;
169	int error, index;
170	uint64_t start, size;
171	uint16_t tag;
172
173	if (gpp->gpp_parms & G_PART_PARM_LABEL)
174		return (EINVAL);
175
176	error = vtoc8_parse_type(gpp->gpp_type, &tag);
177	if (error)
178		return (error);
179
180	table = (struct g_part_vtoc8_table *)basetable;
181	index = entry->gpe_index - 1;
182	start = gpp->gpp_start;
183	size = gpp->gpp_size;
184	if (vtoc8_align(table, &start, &size) != 0)
185		return (EINVAL);
186
187	KASSERT(entry->gpe_start <= start, (__func__));
188	KASSERT(entry->gpe_end >= start + size - 1, (__func__));
189	entry->gpe_start = start;
190	entry->gpe_end = start + size - 1;
191
192	be16enc(&table->vtoc.part[index].tag, tag);
193	be16enc(&table->vtoc.part[index].flag, 0);
194	be32enc(&table->vtoc.timestamp[index], 0);
195	be32enc(&table->vtoc.map[index].cyl, start / table->secpercyl);
196	be32enc(&table->vtoc.map[index].nblks, size);
197	return (0);
198}
199
200static int
201g_part_vtoc8_create(struct g_part_table *basetable, struct g_part_parms *gpp)
202{
203	struct g_provider *pp;
204	struct g_part_entry *entry;
205	struct g_part_vtoc8_table *table;
206	uint64_t msize;
207	uint32_t acyls, ncyls, pcyls;
208
209	pp = gpp->gpp_provider;
210
211	if (pp->sectorsize < sizeof(struct vtoc8))
212		return (ENOSPC);
213	if (pp->sectorsize > sizeof(struct vtoc8))
214		return (ENXIO);
215
216	table = (struct g_part_vtoc8_table *)basetable;
217
218	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
219	table->secpercyl = basetable->gpt_sectors * basetable->gpt_heads;
220	pcyls = msize / table->secpercyl;
221	acyls = 2;
222	ncyls = pcyls - acyls;
223	msize = ncyls * table->secpercyl;
224
225	sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u",
226	    (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads,
227	    basetable->gpt_sectors);
228	be32enc(&table->vtoc.version, VTOC_VERSION);
229	be16enc(&table->vtoc.nparts, VTOC8_NPARTS);
230	be32enc(&table->vtoc.sanity, VTOC_SANITY);
231	be16enc(&table->vtoc.rpm, 3600);
232	be16enc(&table->vtoc.physcyls, pcyls);
233	be16enc(&table->vtoc.ncyls, ncyls);
234	be16enc(&table->vtoc.altcyls, acyls);
235	be16enc(&table->vtoc.nheads, basetable->gpt_heads);
236	be16enc(&table->vtoc.nsecs, basetable->gpt_sectors);
237	be16enc(&table->vtoc.magic, VTOC_MAGIC);
238
239	basetable->gpt_first = 0;
240	basetable->gpt_last = msize - 1;
241	basetable->gpt_isleaf = 1;
242
243	entry = g_part_new_entry(basetable, VTOC_RAW_PART + 1,
244	    basetable->gpt_first, basetable->gpt_last);
245	entry->gpe_internal = 1;
246	be16enc(&table->vtoc.part[VTOC_RAW_PART].tag, VTOC_TAG_BACKUP);
247	be32enc(&table->vtoc.map[VTOC_RAW_PART].nblks, msize);
248	return (0);
249}
250
251static int
252g_part_vtoc8_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
253{
254
255	/* Wipe the first sector to clear the partitioning. */
256	basetable->gpt_smhead |= 1;
257	return (0);
258}
259
260static void
261g_part_vtoc8_dumpconf(struct g_part_table *basetable,
262    struct g_part_entry *entry, struct sbuf *sb, const char *indent)
263{
264	struct g_part_vtoc8_table *table;
265
266	table = (struct g_part_vtoc8_table *)basetable;
267	if (indent == NULL) {
268		/* conftxt: libdisk compatibility */
269		sbuf_printf(sb, " xs SUN sc %u hd %u alt %u",
270		    be16dec(&table->vtoc.nsecs), be16dec(&table->vtoc.nheads),
271		    be16dec(&table->vtoc.altcyls));
272	} else if (entry != NULL) {
273		/* confxml: partition entry information */
274		sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
275		    be16dec(&table->vtoc.part[entry->gpe_index - 1].tag));
276	} else {
277		/* confxml: scheme information */
278	}
279}
280
281static int
282g_part_vtoc8_dumpto(struct g_part_table *basetable,
283    struct g_part_entry *entry)
284{
285	struct g_part_vtoc8_table *table;
286	uint16_t tag;
287
288	/*
289	 * Allow dumping to a swap partition or a partition that
290	 * has no type.
291	 */
292	table = (struct g_part_vtoc8_table *)basetable;
293	tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag);
294	return ((tag == 0 || tag == VTOC_TAG_FREEBSD_SWAP ||
295	    tag == VTOC_TAG_SWAP) ? 1 : 0);
296}
297
298static int
299g_part_vtoc8_modify(struct g_part_table *basetable,
300    struct g_part_entry *entry, struct g_part_parms *gpp)
301{
302	struct g_part_vtoc8_table *table;
303	int error;
304	uint16_t tag;
305
306	if (gpp->gpp_parms & G_PART_PARM_LABEL)
307		return (EINVAL);
308
309	table = (struct g_part_vtoc8_table *)basetable;
310	if (gpp->gpp_parms & G_PART_PARM_TYPE) {
311		error = vtoc8_parse_type(gpp->gpp_type, &tag);
312		if (error)
313			return(error);
314
315		be16enc(&table->vtoc.part[entry->gpe_index - 1].tag, tag);
316	}
317	return (0);
318}
319
320static int
321vtoc8_set_rawsize(struct g_part_table *basetable, struct g_provider *pp)
322{
323	struct g_part_vtoc8_table *table;
324	struct g_part_entry *baseentry;
325	off_t msize;
326	uint32_t acyls, ncyls, pcyls;
327
328	table = (struct g_part_vtoc8_table *)basetable;
329	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
330	pcyls = msize / table->secpercyl;
331	if (pcyls > UINT16_MAX)
332		return (ERANGE);
333	acyls = be16dec(&table->vtoc.altcyls);
334	ncyls = pcyls - acyls;
335	msize = ncyls * table->secpercyl;
336	basetable->gpt_last = msize - 1;
337
338	bzero(table->vtoc.ascii, sizeof(table->vtoc.ascii));
339	sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u",
340	    (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads,
341	    basetable->gpt_sectors);
342	be16enc(&table->vtoc.physcyls, pcyls);
343	be16enc(&table->vtoc.ncyls, ncyls);
344	be32enc(&table->vtoc.map[VTOC_RAW_PART].nblks, msize);
345	if (be32dec(&table->vtoc.sanity) == VTOC_SANITY)
346		be16enc(&table->vtoc.part[VTOC_RAW_PART].tag, VTOC_TAG_BACKUP);
347	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
348		if (baseentry->gpe_index == VTOC_RAW_PART + 1) {
349			baseentry->gpe_end = basetable->gpt_last;
350			return (0);
351		}
352	}
353	return (ENXIO);
354}
355
356static int
357g_part_vtoc8_resize(struct g_part_table *basetable,
358    struct g_part_entry *entry, struct g_part_parms *gpp)
359{
360	struct g_part_vtoc8_table *table;
361	struct g_provider *pp;
362	uint64_t size;
363
364	if (entry == NULL) {
365		pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
366		return (vtoc8_set_rawsize(basetable, pp));
367	}
368	table = (struct g_part_vtoc8_table *)basetable;
369	size = gpp->gpp_size;
370	if (vtoc8_align(table, NULL, &size) != 0)
371		return (EINVAL);
372	/* XXX: prevent unexpected shrinking. */
373	pp = entry->gpe_pp;
374	if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size &&
375	    pp->mediasize / pp->sectorsize > size)
376		return (EBUSY);
377	entry->gpe_end = entry->gpe_start + size - 1;
378	be32enc(&table->vtoc.map[entry->gpe_index - 1].nblks, size);
379
380	return (0);
381}
382
383static const char *
384g_part_vtoc8_name(struct g_part_table *table, struct g_part_entry *baseentry,
385    char *buf, size_t bufsz)
386{
387
388	snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
389	return (buf);
390}
391
392static int
393g_part_vtoc8_probe(struct g_part_table *table, struct g_consumer *cp)
394{
395	struct g_provider *pp;
396	u_char *buf;
397	int error, ofs, res;
398	uint16_t cksum, magic;
399
400	pp = cp->provider;
401
402	/* Sanity-check the provider. */
403	if (pp->sectorsize != sizeof(struct vtoc8))
404		return (ENOSPC);
405
406	/* Check that there's a disklabel. */
407	buf = g_read_data(cp, 0, pp->sectorsize, &error);
408	if (buf == NULL)
409		return (error);
410
411	res = ENXIO;	/* Assume mismatch */
412
413	/* Check the magic */
414	magic = be16dec(buf + offsetof(struct vtoc8, magic));
415	if (magic != VTOC_MAGIC)
416		goto out;
417
418	/* Check the sum */
419	cksum = 0;
420	for (ofs = 0; ofs < sizeof(struct vtoc8); ofs += 2)
421		cksum ^= be16dec(buf + ofs);
422	if (cksum != 0)
423		goto out;
424
425	res = G_PART_PROBE_PRI_NORM;
426
427 out:
428	g_free(buf);
429	return (res);
430}
431
432static int
433g_part_vtoc8_read(struct g_part_table *basetable, struct g_consumer *cp)
434{
435	struct g_provider *pp;
436	struct g_part_vtoc8_table *table;
437	struct g_part_entry *entry;
438	u_char *buf;
439	off_t chs, msize;
440	uint64_t offset, size;
441	u_int cyls, heads, sectors;
442	int error, index, withtags;
443	uint16_t tag;
444
445	pp = cp->provider;
446	buf = g_read_data(cp, 0, pp->sectorsize, &error);
447	if (buf == NULL)
448		return (error);
449
450	table = (struct g_part_vtoc8_table *)basetable;
451	bcopy(buf, &table->vtoc, sizeof(table->vtoc));
452	g_free(buf);
453
454	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
455	sectors = be16dec(&table->vtoc.nsecs);
456	if (sectors < 1)
457		goto invalid_label;
458	if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) {
459		g_part_geometry_heads(msize, sectors, &chs, &heads);
460		if (chs != 0) {
461			basetable->gpt_sectors = sectors;
462			basetable->gpt_heads = heads;
463		}
464	}
465
466	heads = be16dec(&table->vtoc.nheads);
467	if (heads < 1)
468		goto invalid_label;
469	if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom)
470		basetable->gpt_heads = heads;
471	/*
472	 * Except for ATA disks > 32GB, Solaris uses the native geometry
473	 * as reported by the target for the labels while da(4) typically
474	 * uses a synthetic one so we don't complain too loudly if these
475	 * geometries don't match.
476	 */
477	if (bootverbose && (sectors != basetable->gpt_sectors ||
478	    heads != basetable->gpt_heads))
479		printf("GEOM: %s: geometry does not match VTOC8 label "
480		    "(label: %uh,%us GEOM: %uh,%us).\n", pp->name, heads,
481		    sectors, basetable->gpt_heads, basetable->gpt_sectors);
482
483	table->secpercyl = heads * sectors;
484	cyls = be16dec(&table->vtoc.ncyls);
485	chs = cyls * table->secpercyl;
486	if (chs < 1 || chs > msize)
487		goto invalid_label;
488
489	basetable->gpt_first = 0;
490	basetable->gpt_last = chs - 1;
491	basetable->gpt_isleaf = 1;
492
493	withtags = (be32dec(&table->vtoc.sanity) == VTOC_SANITY) ? 1 : 0;
494	if (!withtags) {
495		printf("GEOM: %s: adding VTOC8 information.\n", pp->name);
496		be32enc(&table->vtoc.version, VTOC_VERSION);
497		bzero(&table->vtoc.volume, VTOC_VOLUME_LEN);
498		be16enc(&table->vtoc.nparts, VTOC8_NPARTS);
499		bzero(&table->vtoc.part, sizeof(table->vtoc.part));
500		be32enc(&table->vtoc.sanity, VTOC_SANITY);
501	}
502
503	basetable->gpt_entries = be16dec(&table->vtoc.nparts);
504	if (basetable->gpt_entries < g_part_vtoc8_scheme.gps_minent ||
505	    basetable->gpt_entries > g_part_vtoc8_scheme.gps_maxent)
506		goto invalid_label;
507
508	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
509		offset = be32dec(&table->vtoc.map[index].cyl) *
510		    table->secpercyl;
511		size = be32dec(&table->vtoc.map[index].nblks);
512		if (size == 0)
513			continue;
514		if (withtags)
515			tag = be16dec(&table->vtoc.part[index].tag);
516		else
517			tag = (index == VTOC_RAW_PART)
518			    ? VTOC_TAG_BACKUP
519			    : VTOC_TAG_UNASSIGNED;
520
521		if (index == VTOC_RAW_PART && tag != VTOC_TAG_BACKUP)
522			continue;
523		if (index != VTOC_RAW_PART && tag == VTOC_TAG_BACKUP)
524			continue;
525		entry = g_part_new_entry(basetable, index + 1, offset,
526		    offset + size - 1);
527		if (tag == VTOC_TAG_BACKUP)
528			entry->gpe_internal = 1;
529
530		if (!withtags)
531			be16enc(&table->vtoc.part[index].tag, tag);
532	}
533
534	return (0);
535
536 invalid_label:
537	printf("GEOM: %s: invalid VTOC8 label.\n", pp->name);
538	return (EINVAL);
539}
540
541static const char *
542g_part_vtoc8_type(struct g_part_table *basetable, struct g_part_entry *entry,
543    char *buf, size_t bufsz)
544{
545	struct g_part_vtoc8_table *table;
546	uint16_t tag;
547
548	table = (struct g_part_vtoc8_table *)basetable;
549	tag = be16dec(&table->vtoc.part[entry->gpe_index - 1].tag);
550	if (tag == VTOC_TAG_FREEBSD_NANDFS)
551		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS));
552	if (tag == VTOC_TAG_FREEBSD_SWAP)
553		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
554	if (tag == VTOC_TAG_FREEBSD_UFS)
555		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
556	if (tag == VTOC_TAG_FREEBSD_VINUM)
557		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
558	if (tag == VTOC_TAG_FREEBSD_ZFS)
559		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS));
560	snprintf(buf, bufsz, "!%d", tag);
561	return (buf);
562}
563
564static int
565g_part_vtoc8_write(struct g_part_table *basetable, struct g_consumer *cp)
566{
567	struct g_provider *pp;
568	struct g_part_entry *entry;
569	struct g_part_vtoc8_table *table;
570	uint16_t sum;
571	u_char *p;
572	int error, index, match, offset;
573
574	pp = cp->provider;
575	table = (struct g_part_vtoc8_table *)basetable;
576	entry = LIST_FIRST(&basetable->gpt_entry);
577	for (index = 0; index < basetable->gpt_entries; index++) {
578		match = (entry != NULL && index == entry->gpe_index - 1)
579		    ? 1 : 0;
580		if (match) {
581			if (entry->gpe_deleted) {
582				be16enc(&table->vtoc.part[index].tag, 0);
583				be16enc(&table->vtoc.part[index].flag, 0);
584				be32enc(&table->vtoc.map[index].cyl, 0);
585				be32enc(&table->vtoc.map[index].nblks, 0);
586			}
587			entry = LIST_NEXT(entry, gpe_entry);
588		}
589	}
590
591	/* Calculate checksum. */
592	sum = 0;
593	p = (void *)&table->vtoc;
594	for (offset = 0; offset < sizeof(table->vtoc) - 2; offset += 2)
595		sum ^= be16dec(p + offset);
596	be16enc(&table->vtoc.cksum, sum);
597
598	error = g_write_data(cp, 0, p, pp->sectorsize);
599	return (error);
600}
601