xref: /freebsd/sys/geom/part/g_part_apm.c (revision cf23147053bcf3b07f0282aebfc0189db00946d9)
11d3aed33SMarcel Moolenaar /*-
21d3aed33SMarcel Moolenaar  * Copyright (c) 2006, 2007 Marcel Moolenaar
31d3aed33SMarcel Moolenaar  * All rights reserved.
41d3aed33SMarcel Moolenaar  *
51d3aed33SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
61d3aed33SMarcel Moolenaar  * modification, are permitted provided that the following conditions
71d3aed33SMarcel Moolenaar  * are met:
81d3aed33SMarcel Moolenaar  *
91d3aed33SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
101d3aed33SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
111d3aed33SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
121d3aed33SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
131d3aed33SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
141d3aed33SMarcel Moolenaar  *
151d3aed33SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161d3aed33SMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171d3aed33SMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181d3aed33SMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191d3aed33SMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201d3aed33SMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211d3aed33SMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221d3aed33SMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231d3aed33SMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241d3aed33SMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251d3aed33SMarcel Moolenaar  */
261d3aed33SMarcel Moolenaar 
271d3aed33SMarcel Moolenaar #include <sys/cdefs.h>
281d3aed33SMarcel Moolenaar __FBSDID("$FreeBSD$");
291d3aed33SMarcel Moolenaar 
301d3aed33SMarcel Moolenaar #include <sys/param.h>
311d3aed33SMarcel Moolenaar #include <sys/apm.h>
321d3aed33SMarcel Moolenaar #include <sys/bio.h>
331d3aed33SMarcel Moolenaar #include <sys/diskmbr.h>
341d3aed33SMarcel Moolenaar #include <sys/endian.h>
351d3aed33SMarcel Moolenaar #include <sys/kernel.h>
361d3aed33SMarcel Moolenaar #include <sys/kobj.h>
371d3aed33SMarcel Moolenaar #include <sys/limits.h>
381d3aed33SMarcel Moolenaar #include <sys/lock.h>
391d3aed33SMarcel Moolenaar #include <sys/malloc.h>
401d3aed33SMarcel Moolenaar #include <sys/mutex.h>
411d3aed33SMarcel Moolenaar #include <sys/queue.h>
421d3aed33SMarcel Moolenaar #include <sys/sbuf.h>
431d3aed33SMarcel Moolenaar #include <sys/systm.h>
441d3aed33SMarcel Moolenaar #include <geom/geom.h>
451d3aed33SMarcel Moolenaar #include <geom/part/g_part.h>
461d3aed33SMarcel Moolenaar 
471d3aed33SMarcel Moolenaar #include "g_part_if.h"
481d3aed33SMarcel Moolenaar 
491d3aed33SMarcel Moolenaar struct g_part_apm_table {
501d3aed33SMarcel Moolenaar 	struct g_part_table	base;
511d3aed33SMarcel Moolenaar 	struct apm_ddr		ddr;
521d3aed33SMarcel Moolenaar 	struct apm_ent		self;
531d3aed33SMarcel Moolenaar };
541d3aed33SMarcel Moolenaar 
551d3aed33SMarcel Moolenaar struct g_part_apm_entry {
561d3aed33SMarcel Moolenaar 	struct g_part_entry	base;
571d3aed33SMarcel Moolenaar 	struct apm_ent		ent;
581d3aed33SMarcel Moolenaar };
591d3aed33SMarcel Moolenaar 
601d3aed33SMarcel Moolenaar static int g_part_apm_add(struct g_part_table *, struct g_part_entry *,
611d3aed33SMarcel Moolenaar     struct g_part_parms *);
621d3aed33SMarcel Moolenaar static int g_part_apm_create(struct g_part_table *, struct g_part_parms *);
631d3aed33SMarcel Moolenaar static int g_part_apm_destroy(struct g_part_table *, struct g_part_parms *);
641d3aed33SMarcel Moolenaar static int g_part_apm_dumpto(struct g_part_table *, struct g_part_entry *);
651d3aed33SMarcel Moolenaar static int g_part_apm_modify(struct g_part_table *, struct g_part_entry *,
661d3aed33SMarcel Moolenaar     struct g_part_parms *);
671d3aed33SMarcel Moolenaar static char *g_part_apm_name(struct g_part_table *, struct g_part_entry *,
681d3aed33SMarcel Moolenaar     char *, size_t);
691d3aed33SMarcel Moolenaar static int g_part_apm_probe(struct g_part_table *, struct g_consumer *);
701d3aed33SMarcel Moolenaar static int g_part_apm_read(struct g_part_table *, struct g_consumer *);
711d3aed33SMarcel Moolenaar static const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *,
721d3aed33SMarcel Moolenaar     char *, size_t);
731d3aed33SMarcel Moolenaar static int g_part_apm_write(struct g_part_table *, struct g_consumer *);
741d3aed33SMarcel Moolenaar 
751d3aed33SMarcel Moolenaar static kobj_method_t g_part_apm_methods[] = {
761d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_add,		g_part_apm_add),
771d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_create,	g_part_apm_create),
781d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_destroy,	g_part_apm_destroy),
791d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_dumpto,	g_part_apm_dumpto),
801d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_modify,	g_part_apm_modify),
811d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_name,		g_part_apm_name),
821d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_probe,	g_part_apm_probe),
831d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_read,		g_part_apm_read),
841d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_type,		g_part_apm_type),
851d3aed33SMarcel Moolenaar 	KOBJMETHOD(g_part_write,	g_part_apm_write),
861d3aed33SMarcel Moolenaar 	{ 0, 0 }
871d3aed33SMarcel Moolenaar };
881d3aed33SMarcel Moolenaar 
891d3aed33SMarcel Moolenaar static struct g_part_scheme g_part_apm_scheme = {
901d3aed33SMarcel Moolenaar 	"APM",
911d3aed33SMarcel Moolenaar 	g_part_apm_methods,
921d3aed33SMarcel Moolenaar 	sizeof(struct g_part_apm_table),
931d3aed33SMarcel Moolenaar 	.gps_entrysz = sizeof(struct g_part_apm_entry),
941d3aed33SMarcel Moolenaar 	.gps_minent = 16,
951d3aed33SMarcel Moolenaar 	.gps_maxent = INT_MAX,
961d3aed33SMarcel Moolenaar };
971d3aed33SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_apm_scheme);
981d3aed33SMarcel Moolenaar 
991d3aed33SMarcel Moolenaar static int
1001d3aed33SMarcel Moolenaar apm_parse_type(const char *type, char *buf, size_t bufsz)
1011d3aed33SMarcel Moolenaar {
102d287f590SMarcel Moolenaar 	const char *alias;
1031d3aed33SMarcel Moolenaar 
104d287f590SMarcel Moolenaar 	if (type[0] == '!') {
105d287f590SMarcel Moolenaar 		type++;
1061d3aed33SMarcel Moolenaar 		if (strlen(type) > bufsz)
1071d3aed33SMarcel Moolenaar 			return (EINVAL);
1081d3aed33SMarcel Moolenaar 		if (!strcmp(type, APM_ENT_TYPE_SELF) ||
1091d3aed33SMarcel Moolenaar 		    !strcmp(type, APM_ENT_TYPE_UNUSED))
1101d3aed33SMarcel Moolenaar 			return (EINVAL);
1111d3aed33SMarcel Moolenaar 		strncpy(buf, type, bufsz);
1121d3aed33SMarcel Moolenaar 		return (0);
1131d3aed33SMarcel Moolenaar 	}
114d287f590SMarcel Moolenaar 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
115d287f590SMarcel Moolenaar 	if (!strcasecmp(type, alias)) {
1161d3aed33SMarcel Moolenaar 		strcpy(buf, APM_ENT_TYPE_FREEBSD);
1171d3aed33SMarcel Moolenaar 		return (0);
1181d3aed33SMarcel Moolenaar 	}
119d287f590SMarcel Moolenaar 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
120d287f590SMarcel Moolenaar 	if (!strcasecmp(type, alias)) {
121d287f590SMarcel Moolenaar 		strcpy(buf, APM_ENT_TYPE_FREEBSD_SWAP);
122d287f590SMarcel Moolenaar 		return (0);
123d287f590SMarcel Moolenaar 	}
124d287f590SMarcel Moolenaar 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
125d287f590SMarcel Moolenaar 	if (!strcasecmp(type, alias)) {
126d287f590SMarcel Moolenaar 		strcpy(buf, APM_ENT_TYPE_FREEBSD_UFS);
127d287f590SMarcel Moolenaar 		return (0);
128d287f590SMarcel Moolenaar 	}
129d287f590SMarcel Moolenaar 	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
130d287f590SMarcel Moolenaar 	if (!strcasecmp(type, alias)) {
131d287f590SMarcel Moolenaar 		strcpy(buf, APM_ENT_TYPE_FREEBSD_VINUM);
132d287f590SMarcel Moolenaar 		return (0);
133d287f590SMarcel Moolenaar 	}
134d287f590SMarcel Moolenaar 	return (EINVAL);
135d287f590SMarcel Moolenaar }
1361d3aed33SMarcel Moolenaar 
1371d3aed33SMarcel Moolenaar static int
1381d3aed33SMarcel Moolenaar apm_read_ent(struct g_consumer *cp, uint32_t blk, struct apm_ent *ent)
1391d3aed33SMarcel Moolenaar {
1401d3aed33SMarcel Moolenaar 	struct g_provider *pp;
1411d3aed33SMarcel Moolenaar 	char *buf;
1421d3aed33SMarcel Moolenaar 	int error;
1431d3aed33SMarcel Moolenaar 
1441d3aed33SMarcel Moolenaar 	pp = cp->provider;
1451d3aed33SMarcel Moolenaar 	buf = g_read_data(cp, pp->sectorsize * blk, pp->sectorsize, &error);
1461d3aed33SMarcel Moolenaar 	if (buf == NULL)
1471d3aed33SMarcel Moolenaar 		return (error);
1481d3aed33SMarcel Moolenaar 	ent->ent_sig = be16dec(buf);
1491d3aed33SMarcel Moolenaar 	ent->ent_pmblkcnt = be32dec(buf + 4);
1501d3aed33SMarcel Moolenaar 	ent->ent_start = be32dec(buf + 8);
1511d3aed33SMarcel Moolenaar 	ent->ent_size = be32dec(buf + 12);
1521d3aed33SMarcel Moolenaar 	bcopy(buf + 16, ent->ent_name, sizeof(ent->ent_name));
1531d3aed33SMarcel Moolenaar 	bcopy(buf + 48, ent->ent_type, sizeof(ent->ent_type));
1541d3aed33SMarcel Moolenaar 	g_free(buf);
1551d3aed33SMarcel Moolenaar 	return (0);
1561d3aed33SMarcel Moolenaar }
1571d3aed33SMarcel Moolenaar 
1581d3aed33SMarcel Moolenaar static int
1591d3aed33SMarcel Moolenaar g_part_apm_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
1601d3aed33SMarcel Moolenaar     struct g_part_parms *gpp)
1611d3aed33SMarcel Moolenaar {
1621d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
1631d3aed33SMarcel Moolenaar 	struct g_part_apm_table *table;
1641d3aed33SMarcel Moolenaar 	int error;
1651d3aed33SMarcel Moolenaar 
1661d3aed33SMarcel Moolenaar 	entry = (struct g_part_apm_entry *)baseentry;
1671d3aed33SMarcel Moolenaar 	table = (struct g_part_apm_table *)basetable;
1681d3aed33SMarcel Moolenaar 	entry->ent.ent_sig = APM_ENT_SIG;
1691d3aed33SMarcel Moolenaar 	entry->ent.ent_pmblkcnt = table->self.ent_pmblkcnt;
1701d3aed33SMarcel Moolenaar 	entry->ent.ent_start = gpp->gpp_start;
1711d3aed33SMarcel Moolenaar 	entry->ent.ent_size = gpp->gpp_size;
1721d3aed33SMarcel Moolenaar 	if (baseentry->gpe_deleted) {
1731d3aed33SMarcel Moolenaar 		bzero(entry->ent.ent_type, sizeof(entry->ent.ent_type));
1741d3aed33SMarcel Moolenaar 		bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
1751d3aed33SMarcel Moolenaar 	}
1761d3aed33SMarcel Moolenaar 	error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
1771d3aed33SMarcel Moolenaar 	    sizeof(entry->ent.ent_type));
1781d3aed33SMarcel Moolenaar 	if (error)
1791d3aed33SMarcel Moolenaar 		return (error);
1801d3aed33SMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
1811d3aed33SMarcel Moolenaar 		if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
1821d3aed33SMarcel Moolenaar 			return (EINVAL);
1831d3aed33SMarcel Moolenaar 		strncpy(entry->ent.ent_name, gpp->gpp_label,
1841d3aed33SMarcel Moolenaar 		    sizeof(entry->ent.ent_name));
1851d3aed33SMarcel Moolenaar 	}
1861d3aed33SMarcel Moolenaar 	return (0);
1871d3aed33SMarcel Moolenaar }
1881d3aed33SMarcel Moolenaar 
1891d3aed33SMarcel Moolenaar static int
1901d3aed33SMarcel Moolenaar g_part_apm_create(struct g_part_table *basetable, struct g_part_parms *gpp)
1911d3aed33SMarcel Moolenaar {
1921d3aed33SMarcel Moolenaar 	struct g_provider *pp;
1931d3aed33SMarcel Moolenaar 	struct g_part_apm_table *table;
1941d3aed33SMarcel Moolenaar 
1951d3aed33SMarcel Moolenaar 	table = (struct g_part_apm_table *)basetable;
1961d3aed33SMarcel Moolenaar 	pp = gpp->gpp_provider;
1971d3aed33SMarcel Moolenaar 	if (pp->sectorsize != 512 ||
1981d3aed33SMarcel Moolenaar 	    pp->mediasize < (2 + 2 * basetable->gpt_entries) * pp->sectorsize)
1991d3aed33SMarcel Moolenaar 		return (ENOSPC);
2001d3aed33SMarcel Moolenaar 
2011d3aed33SMarcel Moolenaar 	basetable->gpt_first = 2 + basetable->gpt_entries;
2021d3aed33SMarcel Moolenaar 	basetable->gpt_last = (pp->mediasize / pp->sectorsize) - 1;
2031d3aed33SMarcel Moolenaar 
2041d3aed33SMarcel Moolenaar 	table->ddr.ddr_sig = APM_DDR_SIG;
2051d3aed33SMarcel Moolenaar 	table->ddr.ddr_blksize = pp->sectorsize;
2061d3aed33SMarcel Moolenaar 	table->ddr.ddr_blkcount = basetable->gpt_last + 1;
2071d3aed33SMarcel Moolenaar 
2081d3aed33SMarcel Moolenaar 	table->self.ent_sig = APM_ENT_SIG;
2091d3aed33SMarcel Moolenaar 	table->self.ent_pmblkcnt = basetable->gpt_entries + 1;
2101d3aed33SMarcel Moolenaar 	table->self.ent_start = 1;
2111d3aed33SMarcel Moolenaar 	table->self.ent_size = table->self.ent_pmblkcnt;
2121d3aed33SMarcel Moolenaar 	strcpy(table->self.ent_name, "Apple");
2131d3aed33SMarcel Moolenaar 	strcpy(table->self.ent_type, APM_ENT_TYPE_SELF);
2141d3aed33SMarcel Moolenaar 	return (0);
2151d3aed33SMarcel Moolenaar }
2161d3aed33SMarcel Moolenaar 
2171d3aed33SMarcel Moolenaar static int
2181d3aed33SMarcel Moolenaar g_part_apm_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
2191d3aed33SMarcel Moolenaar {
2201d3aed33SMarcel Moolenaar 
2211d3aed33SMarcel Moolenaar 	/* Wipe the first 2 sectors to clear the partitioning. */
2221d3aed33SMarcel Moolenaar 	basetable->gpt_smhead |= 3;
2231d3aed33SMarcel Moolenaar 	return (0);
2241d3aed33SMarcel Moolenaar }
2251d3aed33SMarcel Moolenaar 
2261d3aed33SMarcel Moolenaar static int
2271d3aed33SMarcel Moolenaar g_part_apm_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
2281d3aed33SMarcel Moolenaar {
2291d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
2301d3aed33SMarcel Moolenaar 
2311d3aed33SMarcel Moolenaar 	entry = (struct g_part_apm_entry *)baseentry;
2321d3aed33SMarcel Moolenaar 	return ((!strcmp(entry->ent.ent_type, APM_ENT_TYPE_FREEBSD_SWAP))
2331d3aed33SMarcel Moolenaar 	    ? 1 : 0);
2341d3aed33SMarcel Moolenaar }
2351d3aed33SMarcel Moolenaar 
2361d3aed33SMarcel Moolenaar static int
2371d3aed33SMarcel Moolenaar g_part_apm_modify(struct g_part_table *basetable,
2381d3aed33SMarcel Moolenaar     struct g_part_entry *baseentry, struct g_part_parms *gpp)
2391d3aed33SMarcel Moolenaar {
2401d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
2411d3aed33SMarcel Moolenaar 	int error;
2421d3aed33SMarcel Moolenaar 
2431d3aed33SMarcel Moolenaar 	entry = (struct g_part_apm_entry *)baseentry;
2441d3aed33SMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
2451d3aed33SMarcel Moolenaar 		if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
2461d3aed33SMarcel Moolenaar 			return (EINVAL);
2471d3aed33SMarcel Moolenaar 	}
2481d3aed33SMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_TYPE) {
2491d3aed33SMarcel Moolenaar 		error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
2501d3aed33SMarcel Moolenaar 		    sizeof(entry->ent.ent_type));
2511d3aed33SMarcel Moolenaar 		if (error)
2521d3aed33SMarcel Moolenaar 			return (error);
2531d3aed33SMarcel Moolenaar 	}
2541d3aed33SMarcel Moolenaar 	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
2551d3aed33SMarcel Moolenaar 		strncpy(entry->ent.ent_name, gpp->gpp_label,
2561d3aed33SMarcel Moolenaar 		    sizeof(entry->ent.ent_name));
2571d3aed33SMarcel Moolenaar 	}
2581d3aed33SMarcel Moolenaar 	return (0);
2591d3aed33SMarcel Moolenaar }
2601d3aed33SMarcel Moolenaar 
2611d3aed33SMarcel Moolenaar static char *
2621d3aed33SMarcel Moolenaar g_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry,
2631d3aed33SMarcel Moolenaar     char *buf, size_t bufsz)
2641d3aed33SMarcel Moolenaar {
2651d3aed33SMarcel Moolenaar 
2661d3aed33SMarcel Moolenaar 	snprintf(buf, bufsz, "s%d", baseentry->gpe_index + 1);
2671d3aed33SMarcel Moolenaar 	return (buf);
2681d3aed33SMarcel Moolenaar }
2691d3aed33SMarcel Moolenaar 
2701d3aed33SMarcel Moolenaar static int
2711d3aed33SMarcel Moolenaar g_part_apm_probe(struct g_part_table *basetable, struct g_consumer *cp)
2721d3aed33SMarcel Moolenaar {
2731d3aed33SMarcel Moolenaar 	struct g_provider *pp;
2741d3aed33SMarcel Moolenaar 	struct g_part_apm_table *table;
2751d3aed33SMarcel Moolenaar 	char *buf;
2761d3aed33SMarcel Moolenaar 	int error;
2771d3aed33SMarcel Moolenaar 
2781d3aed33SMarcel Moolenaar 	/* We don't nest, which means that our depth should be 0. */
2791d3aed33SMarcel Moolenaar 	if (basetable->gpt_depth != 0)
2801d3aed33SMarcel Moolenaar 		return (ENXIO);
2811d3aed33SMarcel Moolenaar 
2821d3aed33SMarcel Moolenaar 	table = (struct g_part_apm_table *)basetable;
2831d3aed33SMarcel Moolenaar 	pp = cp->provider;
2841d3aed33SMarcel Moolenaar 
2851d3aed33SMarcel Moolenaar 	/* Sanity-check the provider. */
2861d3aed33SMarcel Moolenaar 	if (pp->mediasize < 4 * pp->sectorsize)
2871d3aed33SMarcel Moolenaar 		return (ENOSPC);
2881d3aed33SMarcel Moolenaar 
2891d3aed33SMarcel Moolenaar 	/* Check that there's a Driver Descriptor Record (DDR). */
2901d3aed33SMarcel Moolenaar 	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
2911d3aed33SMarcel Moolenaar 	if (buf == NULL)
2921d3aed33SMarcel Moolenaar 		return (error);
2931d3aed33SMarcel Moolenaar 	table->ddr.ddr_sig = be16dec(buf);
2941d3aed33SMarcel Moolenaar 	table->ddr.ddr_blksize = be16dec(buf + 2);
2951d3aed33SMarcel Moolenaar 	table->ddr.ddr_blkcount = be32dec(buf + 4);
2961d3aed33SMarcel Moolenaar 	g_free(buf);
2971d3aed33SMarcel Moolenaar 	if (table->ddr.ddr_sig != APM_DDR_SIG)
2981d3aed33SMarcel Moolenaar 		return (ENXIO);
2991d3aed33SMarcel Moolenaar 	if (table->ddr.ddr_blksize != pp->sectorsize)
3001d3aed33SMarcel Moolenaar 		return (ENXIO);
3011d3aed33SMarcel Moolenaar 
3021d3aed33SMarcel Moolenaar 	/* Check that there's a Partition Map. */
3031d3aed33SMarcel Moolenaar 	error = apm_read_ent(cp, 1, &table->self);
3041d3aed33SMarcel Moolenaar 	if (error)
3051d3aed33SMarcel Moolenaar 		return (error);
3061d3aed33SMarcel Moolenaar 	if (table->self.ent_sig != APM_ENT_SIG)
3071d3aed33SMarcel Moolenaar 		return (ENXIO);
3081d3aed33SMarcel Moolenaar 	if (strcmp(table->self.ent_type, APM_ENT_TYPE_SELF))
3091d3aed33SMarcel Moolenaar 		return (ENXIO);
3101d3aed33SMarcel Moolenaar 	if (table->self.ent_pmblkcnt >= table->ddr.ddr_blkcount)
3111d3aed33SMarcel Moolenaar 		return (ENXIO);
3121d3aed33SMarcel Moolenaar 	return (G_PART_PROBE_PRI_NORM);
3131d3aed33SMarcel Moolenaar }
3141d3aed33SMarcel Moolenaar 
3151d3aed33SMarcel Moolenaar static int
3161d3aed33SMarcel Moolenaar g_part_apm_read(struct g_part_table *basetable, struct g_consumer *cp)
3171d3aed33SMarcel Moolenaar {
3181d3aed33SMarcel Moolenaar 	struct apm_ent ent;
3191d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
3201d3aed33SMarcel Moolenaar 	struct g_part_apm_table *table;
3211d3aed33SMarcel Moolenaar 	int error, index;
3221d3aed33SMarcel Moolenaar 
3231d3aed33SMarcel Moolenaar 	table = (struct g_part_apm_table *)basetable;
3241d3aed33SMarcel Moolenaar 
3251d3aed33SMarcel Moolenaar 	basetable->gpt_first = table->self.ent_pmblkcnt + 1;
3261d3aed33SMarcel Moolenaar 	basetable->gpt_last = table->ddr.ddr_blkcount - 1;
3271d3aed33SMarcel Moolenaar 	basetable->gpt_entries = table->self.ent_pmblkcnt - 1;
3281d3aed33SMarcel Moolenaar 
3291d3aed33SMarcel Moolenaar 	for (index = table->self.ent_pmblkcnt - 1; index > 0; index--) {
3301d3aed33SMarcel Moolenaar 		error = apm_read_ent(cp, index + 1, &ent);
3311d3aed33SMarcel Moolenaar 		if (error)
3321d3aed33SMarcel Moolenaar 			continue;
3331d3aed33SMarcel Moolenaar 		if (!strcmp(ent.ent_type, APM_ENT_TYPE_UNUSED))
3341d3aed33SMarcel Moolenaar 			continue;
3351d3aed33SMarcel Moolenaar 		entry = (struct g_part_apm_entry *)g_part_new_entry(basetable,
3361d3aed33SMarcel Moolenaar 		    index, ent.ent_start, ent.ent_start + ent.ent_size - 1);
3371d3aed33SMarcel Moolenaar 		entry->ent = ent;
3381d3aed33SMarcel Moolenaar 	}
3391d3aed33SMarcel Moolenaar 
3401d3aed33SMarcel Moolenaar 	return (0);
3411d3aed33SMarcel Moolenaar }
3421d3aed33SMarcel Moolenaar 
3431d3aed33SMarcel Moolenaar static const char *
3441d3aed33SMarcel Moolenaar g_part_apm_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
3451d3aed33SMarcel Moolenaar     char *buf, size_t bufsz)
3461d3aed33SMarcel Moolenaar {
3471d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
3481d3aed33SMarcel Moolenaar 	const char *type;
3491d3aed33SMarcel Moolenaar 	size_t len;
3501d3aed33SMarcel Moolenaar 
3511d3aed33SMarcel Moolenaar 	entry = (struct g_part_apm_entry *)baseentry;
3521d3aed33SMarcel Moolenaar 	type = entry->ent.ent_type;
3531d3aed33SMarcel Moolenaar 	if (!strcmp(type, APM_ENT_TYPE_FREEBSD))
3541d3aed33SMarcel Moolenaar 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
3551d3aed33SMarcel Moolenaar 	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_SWAP))
3561d3aed33SMarcel Moolenaar 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
3571d3aed33SMarcel Moolenaar 	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_UFS))
3581d3aed33SMarcel Moolenaar 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
3591d3aed33SMarcel Moolenaar 	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_VINUM))
3601d3aed33SMarcel Moolenaar 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
361cf231470SMarcel Moolenaar 	buf[0] = '!';
362cf231470SMarcel Moolenaar 	len = MIN(sizeof(entry->ent.ent_type), bufsz - 2);
363cf231470SMarcel Moolenaar 	bcopy(type, buf + 1, len);
364cf231470SMarcel Moolenaar 	buf[len + 1] = '\0';
3651d3aed33SMarcel Moolenaar 	return (buf);
3661d3aed33SMarcel Moolenaar }
3671d3aed33SMarcel Moolenaar 
3681d3aed33SMarcel Moolenaar static int
3691d3aed33SMarcel Moolenaar g_part_apm_write(struct g_part_table *basetable, struct g_consumer *cp)
3701d3aed33SMarcel Moolenaar {
3711d3aed33SMarcel Moolenaar 	char buf[512];
3721d3aed33SMarcel Moolenaar 	struct g_part_entry *baseentry;
3731d3aed33SMarcel Moolenaar 	struct g_part_apm_entry *entry;
3741d3aed33SMarcel Moolenaar 	struct g_part_apm_table *table;
3751d3aed33SMarcel Moolenaar 	int error, index;
3761d3aed33SMarcel Moolenaar 
3771d3aed33SMarcel Moolenaar 	table = (struct g_part_apm_table *)basetable;
3781d3aed33SMarcel Moolenaar 	bzero(buf, sizeof(buf));
3791d3aed33SMarcel Moolenaar 
3801d3aed33SMarcel Moolenaar 	/* Write the DDR and 'self' entry only when we're newly created. */
3811d3aed33SMarcel Moolenaar 	if (basetable->gpt_created) {
3821d3aed33SMarcel Moolenaar 		be16enc(buf, table->ddr.ddr_sig);
3831d3aed33SMarcel Moolenaar 		be16enc(buf + 2, table->ddr.ddr_blksize);
3841d3aed33SMarcel Moolenaar 		be32enc(buf + 4, table->ddr.ddr_blkcount);
3851d3aed33SMarcel Moolenaar 		error = g_write_data(cp, 0, buf, sizeof(buf));
3861d3aed33SMarcel Moolenaar 		if (error)
3871d3aed33SMarcel Moolenaar 			return (error);
3881d3aed33SMarcel Moolenaar 	}
3891d3aed33SMarcel Moolenaar 
3901d3aed33SMarcel Moolenaar 	be16enc(buf, table->self.ent_sig);
3911d3aed33SMarcel Moolenaar 	be16enc(buf + 2, 0);
3921d3aed33SMarcel Moolenaar 	be32enc(buf + 4, table->self.ent_pmblkcnt);
3931d3aed33SMarcel Moolenaar 
3941d3aed33SMarcel Moolenaar 	if (basetable->gpt_created) {
3951d3aed33SMarcel Moolenaar 		be32enc(buf + 8, table->self.ent_start);
3961d3aed33SMarcel Moolenaar 		be32enc(buf + 12, table->self.ent_size);
3971d3aed33SMarcel Moolenaar 		bcopy(table->self.ent_name, buf + 16,
3981d3aed33SMarcel Moolenaar 		    sizeof(table->self.ent_name));
3991d3aed33SMarcel Moolenaar 		bcopy(table->self.ent_type, buf + 48,
4001d3aed33SMarcel Moolenaar 		    sizeof(table->self.ent_type));
4011d3aed33SMarcel Moolenaar 		error = g_write_data(cp, 512, buf, sizeof(buf));
4021d3aed33SMarcel Moolenaar 		if (error)
4031d3aed33SMarcel Moolenaar 			return (error);
4041d3aed33SMarcel Moolenaar 	}
4051d3aed33SMarcel Moolenaar 
4061d3aed33SMarcel Moolenaar 	baseentry = LIST_FIRST(&basetable->gpt_entry);
4071d3aed33SMarcel Moolenaar 	for (index = 1; index <= basetable->gpt_entries; index++) {
408d287f590SMarcel Moolenaar 		entry = (baseentry != NULL && index == baseentry->gpe_index)
409d287f590SMarcel Moolenaar 		    ? (struct g_part_apm_entry *)baseentry : NULL;
410d287f590SMarcel Moolenaar 		if (entry != NULL && !baseentry->gpe_deleted) {
4111d3aed33SMarcel Moolenaar 			be32enc(buf + 8, entry->ent.ent_start);
4121d3aed33SMarcel Moolenaar 			be32enc(buf + 12, entry->ent.ent_size);
4131d3aed33SMarcel Moolenaar 			bcopy(entry->ent.ent_name, buf + 16,
4141d3aed33SMarcel Moolenaar 			    sizeof(entry->ent.ent_name));
4151d3aed33SMarcel Moolenaar 			bcopy(entry->ent.ent_type, buf + 48,
4161d3aed33SMarcel Moolenaar 			    sizeof(entry->ent.ent_type));
4171d3aed33SMarcel Moolenaar 		} else {
4181d3aed33SMarcel Moolenaar 			bzero(buf + 8, 4 + 4 + 32 + 32);
4191d3aed33SMarcel Moolenaar 			strcpy(buf + 48, APM_ENT_TYPE_UNUSED);
4201d3aed33SMarcel Moolenaar 		}
4211d3aed33SMarcel Moolenaar 		error = g_write_data(cp, (index + 1) * 512, buf, sizeof(buf));
4221d3aed33SMarcel Moolenaar 		if (error)
4231d3aed33SMarcel Moolenaar 			return (error);
424d287f590SMarcel Moolenaar 		if (entry != NULL)
425d287f590SMarcel Moolenaar 			baseentry = LIST_NEXT(baseentry, gpe_entry);
4261d3aed33SMarcel Moolenaar 	}
4271d3aed33SMarcel Moolenaar 
4281d3aed33SMarcel Moolenaar 	return (0);
4291d3aed33SMarcel Moolenaar }
430