11d3aed33SMarcel Moolenaar /*- 2ab1e8f04SMarcel Moolenaar * Copyright (c) 2006-2008 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; 530952268eSWarner Losh int tivo_series1; 541d3aed33SMarcel Moolenaar }; 551d3aed33SMarcel Moolenaar 561d3aed33SMarcel Moolenaar struct g_part_apm_entry { 571d3aed33SMarcel Moolenaar struct g_part_entry base; 581d3aed33SMarcel Moolenaar struct apm_ent ent; 591d3aed33SMarcel Moolenaar }; 601d3aed33SMarcel Moolenaar 611d3aed33SMarcel Moolenaar static int g_part_apm_add(struct g_part_table *, struct g_part_entry *, 621d3aed33SMarcel Moolenaar struct g_part_parms *); 631d3aed33SMarcel Moolenaar static int g_part_apm_create(struct g_part_table *, struct g_part_parms *); 641d3aed33SMarcel Moolenaar static int g_part_apm_destroy(struct g_part_table *, struct g_part_parms *); 6551f53a08SWarner Losh static void g_part_apm_dumpconf(struct g_part_table *, struct g_part_entry *, 665db67052SMarcel Moolenaar struct sbuf *, const char *); 671d3aed33SMarcel Moolenaar static int g_part_apm_dumpto(struct g_part_table *, struct g_part_entry *); 681d3aed33SMarcel Moolenaar static int g_part_apm_modify(struct g_part_table *, struct g_part_entry *, 691d3aed33SMarcel Moolenaar struct g_part_parms *); 7051f53a08SWarner Losh static const char *g_part_apm_name(struct g_part_table *, struct g_part_entry *, 711d3aed33SMarcel Moolenaar char *, size_t); 721d3aed33SMarcel Moolenaar static int g_part_apm_probe(struct g_part_table *, struct g_consumer *); 731d3aed33SMarcel Moolenaar static int g_part_apm_read(struct g_part_table *, struct g_consumer *); 741d3aed33SMarcel Moolenaar static const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *, 751d3aed33SMarcel Moolenaar char *, size_t); 761d3aed33SMarcel Moolenaar static int g_part_apm_write(struct g_part_table *, struct g_consumer *); 77*3f71c319SMarcel Moolenaar static int g_part_apm_resize(struct g_part_table *, struct g_part_entry *, 78*3f71c319SMarcel Moolenaar struct g_part_parms *); 791d3aed33SMarcel Moolenaar 801d3aed33SMarcel Moolenaar static kobj_method_t g_part_apm_methods[] = { 811d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_apm_add), 821d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_apm_create), 831d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_apm_destroy), 845db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_apm_dumpconf), 851d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_apm_dumpto), 861d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_apm_modify), 87*3f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_apm_resize), 881d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_apm_name), 891d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_apm_probe), 901d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_apm_read), 911d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_apm_type), 921d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_apm_write), 931d3aed33SMarcel Moolenaar { 0, 0 } 941d3aed33SMarcel Moolenaar }; 951d3aed33SMarcel Moolenaar 961d3aed33SMarcel Moolenaar static struct g_part_scheme g_part_apm_scheme = { 971d3aed33SMarcel Moolenaar "APM", 981d3aed33SMarcel Moolenaar g_part_apm_methods, 991d3aed33SMarcel Moolenaar sizeof(struct g_part_apm_table), 1001d3aed33SMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_apm_entry), 1011d3aed33SMarcel Moolenaar .gps_minent = 16, 1021d3aed33SMarcel Moolenaar .gps_maxent = INT_MAX, 1031d3aed33SMarcel Moolenaar }; 1044ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_apm); 1051d3aed33SMarcel Moolenaar 1060952268eSWarner Losh static void 1070952268eSWarner Losh swab(char *buf, size_t bufsz) 1080952268eSWarner Losh { 1090952268eSWarner Losh int i; 1100952268eSWarner Losh char ch; 1110952268eSWarner Losh 1120952268eSWarner Losh for (i = 0; i < bufsz; i += 2) { 1130952268eSWarner Losh ch = buf[i]; 1140952268eSWarner Losh buf[i] = buf[i + 1]; 1150952268eSWarner Losh buf[i + 1] = ch; 1160952268eSWarner Losh } 1170952268eSWarner Losh } 1180952268eSWarner Losh 1191d3aed33SMarcel Moolenaar static int 1201d3aed33SMarcel Moolenaar apm_parse_type(const char *type, char *buf, size_t bufsz) 1211d3aed33SMarcel Moolenaar { 122d287f590SMarcel Moolenaar const char *alias; 1231d3aed33SMarcel Moolenaar 124d287f590SMarcel Moolenaar if (type[0] == '!') { 125d287f590SMarcel Moolenaar type++; 1261d3aed33SMarcel Moolenaar if (strlen(type) > bufsz) 1271d3aed33SMarcel Moolenaar return (EINVAL); 1281d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_SELF) || 1291d3aed33SMarcel Moolenaar !strcmp(type, APM_ENT_TYPE_UNUSED)) 1301d3aed33SMarcel Moolenaar return (EINVAL); 1311d3aed33SMarcel Moolenaar strncpy(buf, type, bufsz); 1321d3aed33SMarcel Moolenaar return (0); 1331d3aed33SMarcel Moolenaar } 134d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); 135d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 1361d3aed33SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD); 1371d3aed33SMarcel Moolenaar return (0); 1381d3aed33SMarcel Moolenaar } 139d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP); 140d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 141d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_SWAP); 142d287f590SMarcel Moolenaar return (0); 143d287f590SMarcel Moolenaar } 144d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS); 145d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 146d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_UFS); 147d287f590SMarcel Moolenaar return (0); 148d287f590SMarcel Moolenaar } 149d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM); 150d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 151d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_VINUM); 152d287f590SMarcel Moolenaar return (0); 153d287f590SMarcel Moolenaar } 154a1fedf91SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS); 155a1fedf91SMarcel Moolenaar if (!strcasecmp(type, alias)) { 156a1fedf91SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_ZFS); 157a1fedf91SMarcel Moolenaar return (0); 158a1fedf91SMarcel Moolenaar } 159d287f590SMarcel Moolenaar return (EINVAL); 160d287f590SMarcel Moolenaar } 1611d3aed33SMarcel Moolenaar 1621d3aed33SMarcel Moolenaar static int 1630952268eSWarner Losh apm_read_ent(struct g_consumer *cp, uint32_t blk, struct apm_ent *ent, 1640952268eSWarner Losh int tivo_series1) 1651d3aed33SMarcel Moolenaar { 1661d3aed33SMarcel Moolenaar struct g_provider *pp; 1671d3aed33SMarcel Moolenaar char *buf; 1681d3aed33SMarcel Moolenaar int error; 1691d3aed33SMarcel Moolenaar 1701d3aed33SMarcel Moolenaar pp = cp->provider; 1711d3aed33SMarcel Moolenaar buf = g_read_data(cp, pp->sectorsize * blk, pp->sectorsize, &error); 1721d3aed33SMarcel Moolenaar if (buf == NULL) 1731d3aed33SMarcel Moolenaar return (error); 1740952268eSWarner Losh if (tivo_series1) 1750952268eSWarner Losh swab(buf, pp->sectorsize); 1761d3aed33SMarcel Moolenaar ent->ent_sig = be16dec(buf); 1771d3aed33SMarcel Moolenaar ent->ent_pmblkcnt = be32dec(buf + 4); 1781d3aed33SMarcel Moolenaar ent->ent_start = be32dec(buf + 8); 1791d3aed33SMarcel Moolenaar ent->ent_size = be32dec(buf + 12); 1801d3aed33SMarcel Moolenaar bcopy(buf + 16, ent->ent_name, sizeof(ent->ent_name)); 1811d3aed33SMarcel Moolenaar bcopy(buf + 48, ent->ent_type, sizeof(ent->ent_type)); 1821d3aed33SMarcel Moolenaar g_free(buf); 1831d3aed33SMarcel Moolenaar return (0); 1841d3aed33SMarcel Moolenaar } 1851d3aed33SMarcel Moolenaar 1861d3aed33SMarcel Moolenaar static int 1871d3aed33SMarcel Moolenaar g_part_apm_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 1881d3aed33SMarcel Moolenaar struct g_part_parms *gpp) 1891d3aed33SMarcel Moolenaar { 1901d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 1911d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 1921d3aed33SMarcel Moolenaar int error; 1931d3aed33SMarcel Moolenaar 1941d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 1951d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 1961d3aed33SMarcel Moolenaar entry->ent.ent_sig = APM_ENT_SIG; 1971d3aed33SMarcel Moolenaar entry->ent.ent_pmblkcnt = table->self.ent_pmblkcnt; 1981d3aed33SMarcel Moolenaar entry->ent.ent_start = gpp->gpp_start; 1991d3aed33SMarcel Moolenaar entry->ent.ent_size = gpp->gpp_size; 2001d3aed33SMarcel Moolenaar if (baseentry->gpe_deleted) { 2011d3aed33SMarcel Moolenaar bzero(entry->ent.ent_type, sizeof(entry->ent.ent_type)); 2021d3aed33SMarcel Moolenaar bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name)); 2031d3aed33SMarcel Moolenaar } 2041d3aed33SMarcel Moolenaar error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type, 2051d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 2061d3aed33SMarcel Moolenaar if (error) 2071d3aed33SMarcel Moolenaar return (error); 2081d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 2091d3aed33SMarcel Moolenaar if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name)) 2101d3aed33SMarcel Moolenaar return (EINVAL); 2111d3aed33SMarcel Moolenaar strncpy(entry->ent.ent_name, gpp->gpp_label, 2121d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 2131d3aed33SMarcel Moolenaar } 2141d3aed33SMarcel Moolenaar return (0); 2151d3aed33SMarcel Moolenaar } 2161d3aed33SMarcel Moolenaar 2171d3aed33SMarcel Moolenaar static int 2181d3aed33SMarcel Moolenaar g_part_apm_create(struct g_part_table *basetable, struct g_part_parms *gpp) 2191d3aed33SMarcel Moolenaar { 2201d3aed33SMarcel Moolenaar struct g_provider *pp; 2211d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 222d01a198bSMarcel Moolenaar uint32_t last; 223d01a198bSMarcel Moolenaar 224d01a198bSMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 225d01a198bSMarcel Moolenaar if (basetable->gpt_depth != 0) 226d01a198bSMarcel Moolenaar return (ENXIO); 2271d3aed33SMarcel Moolenaar 2281d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 2291d3aed33SMarcel Moolenaar pp = gpp->gpp_provider; 2301d3aed33SMarcel Moolenaar if (pp->sectorsize != 512 || 2311d3aed33SMarcel Moolenaar pp->mediasize < (2 + 2 * basetable->gpt_entries) * pp->sectorsize) 2321d3aed33SMarcel Moolenaar return (ENOSPC); 2331d3aed33SMarcel Moolenaar 234d01a198bSMarcel Moolenaar /* APM uses 32-bit LBAs. */ 235d01a198bSMarcel Moolenaar last = MIN(pp->mediasize / pp->sectorsize, 0xffffffff) - 1; 236d01a198bSMarcel Moolenaar 2371d3aed33SMarcel Moolenaar basetable->gpt_first = 2 + basetable->gpt_entries; 238d01a198bSMarcel Moolenaar basetable->gpt_last = last; 2391d3aed33SMarcel Moolenaar 2401d3aed33SMarcel Moolenaar table->ddr.ddr_sig = APM_DDR_SIG; 2411d3aed33SMarcel Moolenaar table->ddr.ddr_blksize = pp->sectorsize; 242d01a198bSMarcel Moolenaar table->ddr.ddr_blkcount = last + 1; 2431d3aed33SMarcel Moolenaar 2441d3aed33SMarcel Moolenaar table->self.ent_sig = APM_ENT_SIG; 2451d3aed33SMarcel Moolenaar table->self.ent_pmblkcnt = basetable->gpt_entries + 1; 2461d3aed33SMarcel Moolenaar table->self.ent_start = 1; 2471d3aed33SMarcel Moolenaar table->self.ent_size = table->self.ent_pmblkcnt; 2481d3aed33SMarcel Moolenaar strcpy(table->self.ent_name, "Apple"); 2491d3aed33SMarcel Moolenaar strcpy(table->self.ent_type, APM_ENT_TYPE_SELF); 2501d3aed33SMarcel Moolenaar return (0); 2511d3aed33SMarcel Moolenaar } 2521d3aed33SMarcel Moolenaar 2531d3aed33SMarcel Moolenaar static int 2541d3aed33SMarcel Moolenaar g_part_apm_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 2551d3aed33SMarcel Moolenaar { 2561d3aed33SMarcel Moolenaar 2571d3aed33SMarcel Moolenaar /* Wipe the first 2 sectors to clear the partitioning. */ 2581d3aed33SMarcel Moolenaar basetable->gpt_smhead |= 3; 2591d3aed33SMarcel Moolenaar return (0); 2601d3aed33SMarcel Moolenaar } 2611d3aed33SMarcel Moolenaar 26251f53a08SWarner Losh static void 2635db67052SMarcel Moolenaar g_part_apm_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 2645db67052SMarcel Moolenaar struct sbuf *sb, const char *indent) 2655db67052SMarcel Moolenaar { 266ab1e8f04SMarcel Moolenaar union { 267ab1e8f04SMarcel Moolenaar char name[APM_ENT_NAMELEN + 1]; 268ab1e8f04SMarcel Moolenaar char type[APM_ENT_TYPELEN + 1]; 269ab1e8f04SMarcel Moolenaar } u; 2705db67052SMarcel Moolenaar struct g_part_apm_entry *entry; 2715db67052SMarcel Moolenaar 2725db67052SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 273ab1e8f04SMarcel Moolenaar if (indent == NULL) { 274ab1e8f04SMarcel Moolenaar /* conftxt: libdisk compatibility */ 2755db67052SMarcel Moolenaar sbuf_printf(sb, " xs APPLE xt %s", entry->ent.ent_type); 276ab1e8f04SMarcel Moolenaar } else if (entry != NULL) { 277ab1e8f04SMarcel Moolenaar /* confxml: partition entry information */ 278ab1e8f04SMarcel Moolenaar strncpy(u.name, entry->ent.ent_name, APM_ENT_NAMELEN); 279ab1e8f04SMarcel Moolenaar u.name[APM_ENT_NAMELEN] = '\0'; 280ab1e8f04SMarcel Moolenaar sbuf_printf(sb, "%s<label>%s</label>\n", indent, u.name); 281ab1e8f04SMarcel Moolenaar strncpy(u.type, entry->ent.ent_type, APM_ENT_TYPELEN); 282ab1e8f04SMarcel Moolenaar u.type[APM_ENT_TYPELEN] = '\0'; 283ab1e8f04SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>%s</rawtype>\n", indent, u.type); 284ab1e8f04SMarcel Moolenaar } else { 285ab1e8f04SMarcel Moolenaar /* confxml: scheme information */ 286ab1e8f04SMarcel Moolenaar } 2875db67052SMarcel Moolenaar } 2885db67052SMarcel Moolenaar 2895db67052SMarcel Moolenaar static int 2901d3aed33SMarcel Moolenaar g_part_apm_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 2911d3aed33SMarcel Moolenaar { 2921d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 2931d3aed33SMarcel Moolenaar 2941d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 2951d3aed33SMarcel Moolenaar return ((!strcmp(entry->ent.ent_type, APM_ENT_TYPE_FREEBSD_SWAP)) 2961d3aed33SMarcel Moolenaar ? 1 : 0); 2971d3aed33SMarcel Moolenaar } 2981d3aed33SMarcel Moolenaar 2991d3aed33SMarcel Moolenaar static int 3001d3aed33SMarcel Moolenaar g_part_apm_modify(struct g_part_table *basetable, 3011d3aed33SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3021d3aed33SMarcel Moolenaar { 3031d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 3041d3aed33SMarcel Moolenaar int error; 3051d3aed33SMarcel Moolenaar 3061d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 3071d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 3081d3aed33SMarcel Moolenaar if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name)) 3091d3aed33SMarcel Moolenaar return (EINVAL); 3101d3aed33SMarcel Moolenaar } 3111d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE) { 3121d3aed33SMarcel Moolenaar error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type, 3131d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 3141d3aed33SMarcel Moolenaar if (error) 3151d3aed33SMarcel Moolenaar return (error); 3161d3aed33SMarcel Moolenaar } 3171d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 3181d3aed33SMarcel Moolenaar strncpy(entry->ent.ent_name, gpp->gpp_label, 3191d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 3201d3aed33SMarcel Moolenaar } 3211d3aed33SMarcel Moolenaar return (0); 3221d3aed33SMarcel Moolenaar } 3231d3aed33SMarcel Moolenaar 324*3f71c319SMarcel Moolenaar static int 325*3f71c319SMarcel Moolenaar g_part_apm_resize(struct g_part_table *basetable, 326*3f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 327*3f71c319SMarcel Moolenaar { 328*3f71c319SMarcel Moolenaar struct g_part_apm_entry *entry; 329*3f71c319SMarcel Moolenaar 330*3f71c319SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 331*3f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 332*3f71c319SMarcel Moolenaar entry->ent.ent_size = gpp->gpp_size; 333*3f71c319SMarcel Moolenaar 334*3f71c319SMarcel Moolenaar return (0); 335*3f71c319SMarcel Moolenaar } 336*3f71c319SMarcel Moolenaar 33751f53a08SWarner Losh static const char * 3381d3aed33SMarcel Moolenaar g_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry, 3391d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 3401d3aed33SMarcel Moolenaar { 3411d3aed33SMarcel Moolenaar 3421d3aed33SMarcel Moolenaar snprintf(buf, bufsz, "s%d", baseentry->gpe_index + 1); 3431d3aed33SMarcel Moolenaar return (buf); 3441d3aed33SMarcel Moolenaar } 3451d3aed33SMarcel Moolenaar 3461d3aed33SMarcel Moolenaar static int 3471d3aed33SMarcel Moolenaar g_part_apm_probe(struct g_part_table *basetable, struct g_consumer *cp) 3481d3aed33SMarcel Moolenaar { 3491d3aed33SMarcel Moolenaar struct g_provider *pp; 3501d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 3511d3aed33SMarcel Moolenaar char *buf; 3521d3aed33SMarcel Moolenaar int error; 3531d3aed33SMarcel Moolenaar 3541d3aed33SMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 3551d3aed33SMarcel Moolenaar if (basetable->gpt_depth != 0) 3561d3aed33SMarcel Moolenaar return (ENXIO); 3571d3aed33SMarcel Moolenaar 3581d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 3590952268eSWarner Losh table->tivo_series1 = 0; 3601d3aed33SMarcel Moolenaar pp = cp->provider; 3611d3aed33SMarcel Moolenaar 3621d3aed33SMarcel Moolenaar /* Sanity-check the provider. */ 3631d3aed33SMarcel Moolenaar if (pp->mediasize < 4 * pp->sectorsize) 3641d3aed33SMarcel Moolenaar return (ENOSPC); 3651d3aed33SMarcel Moolenaar 3661d3aed33SMarcel Moolenaar /* Check that there's a Driver Descriptor Record (DDR). */ 3671d3aed33SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 3681d3aed33SMarcel Moolenaar if (buf == NULL) 3691d3aed33SMarcel Moolenaar return (error); 3700952268eSWarner Losh if (be16dec(buf) == be16toh(APM_DDR_SIG)) { 3710952268eSWarner Losh /* Normal Apple DDR */ 3721d3aed33SMarcel Moolenaar table->ddr.ddr_sig = be16dec(buf); 3731d3aed33SMarcel Moolenaar table->ddr.ddr_blksize = be16dec(buf + 2); 3741d3aed33SMarcel Moolenaar table->ddr.ddr_blkcount = be32dec(buf + 4); 3751d3aed33SMarcel Moolenaar g_free(buf); 3761d3aed33SMarcel Moolenaar if (table->ddr.ddr_blksize != pp->sectorsize) 3771d3aed33SMarcel Moolenaar return (ENXIO); 3780952268eSWarner Losh } else { 3790952268eSWarner Losh /* 3800952268eSWarner Losh * Check for Tivo drives, which have no DDR and a different 3810952268eSWarner Losh * signature. Those whose first two bytes are 14 92 are 3820952268eSWarner Losh * Series 2 drives, and aren't supported. Those that start 3830952268eSWarner Losh * with 92 14 are series 1 drives and are supported. 3840952268eSWarner Losh */ 3850952268eSWarner Losh if (be16dec(buf) != 0x9214) { 3860952268eSWarner Losh /* If this is 0x1492 it could be a series 2 drive */ 3870952268eSWarner Losh g_free(buf); 3880952268eSWarner Losh return (ENXIO); 3890952268eSWarner Losh } 3900952268eSWarner Losh table->ddr.ddr_sig = APM_DDR_SIG; /* XXX */ 3910952268eSWarner Losh table->ddr.ddr_blksize = pp->sectorsize; /* XXX */ 3920952268eSWarner Losh table->ddr.ddr_blkcount = pp->mediasize / pp->sectorsize;/* XXX */ 3930952268eSWarner Losh table->tivo_series1 = 1; 3940952268eSWarner Losh g_free(buf); 3950952268eSWarner Losh } 3961d3aed33SMarcel Moolenaar 3971d3aed33SMarcel Moolenaar /* Check that there's a Partition Map. */ 3980952268eSWarner Losh error = apm_read_ent(cp, 1, &table->self, table->tivo_series1); 3991d3aed33SMarcel Moolenaar if (error) 4001d3aed33SMarcel Moolenaar return (error); 4011d3aed33SMarcel Moolenaar if (table->self.ent_sig != APM_ENT_SIG) 4021d3aed33SMarcel Moolenaar return (ENXIO); 4031d3aed33SMarcel Moolenaar if (strcmp(table->self.ent_type, APM_ENT_TYPE_SELF)) 4041d3aed33SMarcel Moolenaar return (ENXIO); 4051d3aed33SMarcel Moolenaar if (table->self.ent_pmblkcnt >= table->ddr.ddr_blkcount) 4061d3aed33SMarcel Moolenaar return (ENXIO); 4071d3aed33SMarcel Moolenaar return (G_PART_PROBE_PRI_NORM); 4081d3aed33SMarcel Moolenaar } 4091d3aed33SMarcel Moolenaar 4101d3aed33SMarcel Moolenaar static int 4111d3aed33SMarcel Moolenaar g_part_apm_read(struct g_part_table *basetable, struct g_consumer *cp) 4121d3aed33SMarcel Moolenaar { 4131d3aed33SMarcel Moolenaar struct apm_ent ent; 4141d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 4151d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 4161d3aed33SMarcel Moolenaar int error, index; 4171d3aed33SMarcel Moolenaar 4181d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 4191d3aed33SMarcel Moolenaar 4201d3aed33SMarcel Moolenaar basetable->gpt_first = table->self.ent_pmblkcnt + 1; 4211d3aed33SMarcel Moolenaar basetable->gpt_last = table->ddr.ddr_blkcount - 1; 4221d3aed33SMarcel Moolenaar basetable->gpt_entries = table->self.ent_pmblkcnt - 1; 4231d3aed33SMarcel Moolenaar 4241d3aed33SMarcel Moolenaar for (index = table->self.ent_pmblkcnt - 1; index > 0; index--) { 4250952268eSWarner Losh error = apm_read_ent(cp, index + 1, &ent, table->tivo_series1); 4261d3aed33SMarcel Moolenaar if (error) 4271d3aed33SMarcel Moolenaar continue; 4281d3aed33SMarcel Moolenaar if (!strcmp(ent.ent_type, APM_ENT_TYPE_UNUSED)) 4291d3aed33SMarcel Moolenaar continue; 4301d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)g_part_new_entry(basetable, 4311d3aed33SMarcel Moolenaar index, ent.ent_start, ent.ent_start + ent.ent_size - 1); 4321d3aed33SMarcel Moolenaar entry->ent = ent; 4331d3aed33SMarcel Moolenaar } 4341d3aed33SMarcel Moolenaar 4351d3aed33SMarcel Moolenaar return (0); 4361d3aed33SMarcel Moolenaar } 4371d3aed33SMarcel Moolenaar 4381d3aed33SMarcel Moolenaar static const char * 4391d3aed33SMarcel Moolenaar g_part_apm_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 4401d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 4411d3aed33SMarcel Moolenaar { 4421d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 4431d3aed33SMarcel Moolenaar const char *type; 4441d3aed33SMarcel Moolenaar size_t len; 4451d3aed33SMarcel Moolenaar 4461d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 4471d3aed33SMarcel Moolenaar type = entry->ent.ent_type; 4481d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD)) 4491d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); 4501d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_SWAP)) 4511d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); 4521d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_UFS)) 4531d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); 4541d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_VINUM)) 4551d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); 456a1fedf91SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_ZFS)) 457a1fedf91SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); 458cf231470SMarcel Moolenaar buf[0] = '!'; 459cf231470SMarcel Moolenaar len = MIN(sizeof(entry->ent.ent_type), bufsz - 2); 460cf231470SMarcel Moolenaar bcopy(type, buf + 1, len); 461cf231470SMarcel Moolenaar buf[len + 1] = '\0'; 4621d3aed33SMarcel Moolenaar return (buf); 4631d3aed33SMarcel Moolenaar } 4641d3aed33SMarcel Moolenaar 4651d3aed33SMarcel Moolenaar static int 4661d3aed33SMarcel Moolenaar g_part_apm_write(struct g_part_table *basetable, struct g_consumer *cp) 4671d3aed33SMarcel Moolenaar { 4681d3aed33SMarcel Moolenaar char buf[512]; 4691d3aed33SMarcel Moolenaar struct g_part_entry *baseentry; 4701d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 4711d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 4721d3aed33SMarcel Moolenaar int error, index; 4731d3aed33SMarcel Moolenaar 4741d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 4750952268eSWarner Losh /* 4760952268eSWarner Losh * Tivo Series 1 disk partitions are currently read-only. 4770952268eSWarner Losh */ 4780952268eSWarner Losh if (table->tivo_series1) 4790952268eSWarner Losh return (EOPNOTSUPP); 4801d3aed33SMarcel Moolenaar bzero(buf, sizeof(buf)); 4811d3aed33SMarcel Moolenaar 4821d3aed33SMarcel Moolenaar /* Write the DDR and 'self' entry only when we're newly created. */ 4831d3aed33SMarcel Moolenaar if (basetable->gpt_created) { 4841d3aed33SMarcel Moolenaar be16enc(buf, table->ddr.ddr_sig); 4851d3aed33SMarcel Moolenaar be16enc(buf + 2, table->ddr.ddr_blksize); 4861d3aed33SMarcel Moolenaar be32enc(buf + 4, table->ddr.ddr_blkcount); 4871d3aed33SMarcel Moolenaar error = g_write_data(cp, 0, buf, sizeof(buf)); 4881d3aed33SMarcel Moolenaar if (error) 4891d3aed33SMarcel Moolenaar return (error); 4901d3aed33SMarcel Moolenaar } 4911d3aed33SMarcel Moolenaar 4921d3aed33SMarcel Moolenaar be16enc(buf, table->self.ent_sig); 4931d3aed33SMarcel Moolenaar be16enc(buf + 2, 0); 4941d3aed33SMarcel Moolenaar be32enc(buf + 4, table->self.ent_pmblkcnt); 4951d3aed33SMarcel Moolenaar 4961d3aed33SMarcel Moolenaar if (basetable->gpt_created) { 4971d3aed33SMarcel Moolenaar be32enc(buf + 8, table->self.ent_start); 4981d3aed33SMarcel Moolenaar be32enc(buf + 12, table->self.ent_size); 4991d3aed33SMarcel Moolenaar bcopy(table->self.ent_name, buf + 16, 5001d3aed33SMarcel Moolenaar sizeof(table->self.ent_name)); 5011d3aed33SMarcel Moolenaar bcopy(table->self.ent_type, buf + 48, 5021d3aed33SMarcel Moolenaar sizeof(table->self.ent_type)); 5031d3aed33SMarcel Moolenaar error = g_write_data(cp, 512, buf, sizeof(buf)); 5041d3aed33SMarcel Moolenaar if (error) 5051d3aed33SMarcel Moolenaar return (error); 5061d3aed33SMarcel Moolenaar } 5071d3aed33SMarcel Moolenaar 5081d3aed33SMarcel Moolenaar baseentry = LIST_FIRST(&basetable->gpt_entry); 5091d3aed33SMarcel Moolenaar for (index = 1; index <= basetable->gpt_entries; index++) { 510d287f590SMarcel Moolenaar entry = (baseentry != NULL && index == baseentry->gpe_index) 511d287f590SMarcel Moolenaar ? (struct g_part_apm_entry *)baseentry : NULL; 512d287f590SMarcel Moolenaar if (entry != NULL && !baseentry->gpe_deleted) { 5131d3aed33SMarcel Moolenaar be32enc(buf + 8, entry->ent.ent_start); 5141d3aed33SMarcel Moolenaar be32enc(buf + 12, entry->ent.ent_size); 5151d3aed33SMarcel Moolenaar bcopy(entry->ent.ent_name, buf + 16, 5161d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 5171d3aed33SMarcel Moolenaar bcopy(entry->ent.ent_type, buf + 48, 5181d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 5191d3aed33SMarcel Moolenaar } else { 5201d3aed33SMarcel Moolenaar bzero(buf + 8, 4 + 4 + 32 + 32); 5211d3aed33SMarcel Moolenaar strcpy(buf + 48, APM_ENT_TYPE_UNUSED); 5221d3aed33SMarcel Moolenaar } 5231d3aed33SMarcel Moolenaar error = g_write_data(cp, (index + 1) * 512, buf, sizeof(buf)); 5241d3aed33SMarcel Moolenaar if (error) 5251d3aed33SMarcel Moolenaar return (error); 526d287f590SMarcel Moolenaar if (entry != NULL) 527d287f590SMarcel Moolenaar baseentry = LIST_NEXT(baseentry, gpe_entry); 5281d3aed33SMarcel Moolenaar } 5291d3aed33SMarcel Moolenaar 5301d3aed33SMarcel Moolenaar return (0); 5311d3aed33SMarcel Moolenaar } 532