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> 44cb08c2ccSAlexander Leidinger #include <sys/sysctl.h> 451d3aed33SMarcel Moolenaar #include <geom/geom.h> 461d3aed33SMarcel Moolenaar #include <geom/part/g_part.h> 471d3aed33SMarcel Moolenaar 481d3aed33SMarcel Moolenaar #include "g_part_if.h" 491d3aed33SMarcel Moolenaar 50cb08c2ccSAlexander Leidinger FEATURE(geom_part_apm, "GEOM partitioning class for Apple-style partitions"); 51cb08c2ccSAlexander Leidinger 521d3aed33SMarcel Moolenaar struct g_part_apm_table { 531d3aed33SMarcel Moolenaar struct g_part_table base; 541d3aed33SMarcel Moolenaar struct apm_ddr ddr; 551d3aed33SMarcel Moolenaar struct apm_ent self; 560952268eSWarner Losh int tivo_series1; 571d3aed33SMarcel Moolenaar }; 581d3aed33SMarcel Moolenaar 591d3aed33SMarcel Moolenaar struct g_part_apm_entry { 601d3aed33SMarcel Moolenaar struct g_part_entry base; 611d3aed33SMarcel Moolenaar struct apm_ent ent; 621d3aed33SMarcel Moolenaar }; 631d3aed33SMarcel Moolenaar 641d3aed33SMarcel Moolenaar static int g_part_apm_add(struct g_part_table *, struct g_part_entry *, 651d3aed33SMarcel Moolenaar struct g_part_parms *); 661d3aed33SMarcel Moolenaar static int g_part_apm_create(struct g_part_table *, struct g_part_parms *); 671d3aed33SMarcel Moolenaar static int g_part_apm_destroy(struct g_part_table *, struct g_part_parms *); 6851f53a08SWarner Losh static void g_part_apm_dumpconf(struct g_part_table *, struct g_part_entry *, 695db67052SMarcel Moolenaar struct sbuf *, const char *); 701d3aed33SMarcel Moolenaar static int g_part_apm_dumpto(struct g_part_table *, struct g_part_entry *); 711d3aed33SMarcel Moolenaar static int g_part_apm_modify(struct g_part_table *, struct g_part_entry *, 721d3aed33SMarcel Moolenaar struct g_part_parms *); 7351f53a08SWarner Losh static const char *g_part_apm_name(struct g_part_table *, struct g_part_entry *, 741d3aed33SMarcel Moolenaar char *, size_t); 751d3aed33SMarcel Moolenaar static int g_part_apm_probe(struct g_part_table *, struct g_consumer *); 761d3aed33SMarcel Moolenaar static int g_part_apm_read(struct g_part_table *, struct g_consumer *); 771d3aed33SMarcel Moolenaar static const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *, 781d3aed33SMarcel Moolenaar char *, size_t); 791d3aed33SMarcel Moolenaar static int g_part_apm_write(struct g_part_table *, struct g_consumer *); 803f71c319SMarcel Moolenaar static int g_part_apm_resize(struct g_part_table *, struct g_part_entry *, 813f71c319SMarcel Moolenaar struct g_part_parms *); 821d3aed33SMarcel Moolenaar 831d3aed33SMarcel Moolenaar static kobj_method_t g_part_apm_methods[] = { 841d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_apm_add), 851d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_apm_create), 861d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_apm_destroy), 875db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_apm_dumpconf), 881d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_apm_dumpto), 891d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_apm_modify), 903f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_apm_resize), 911d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_apm_name), 921d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_apm_probe), 931d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_apm_read), 941d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_apm_type), 951d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_apm_write), 961d3aed33SMarcel Moolenaar { 0, 0 } 971d3aed33SMarcel Moolenaar }; 981d3aed33SMarcel Moolenaar 991d3aed33SMarcel Moolenaar static struct g_part_scheme g_part_apm_scheme = { 1001d3aed33SMarcel Moolenaar "APM", 1011d3aed33SMarcel Moolenaar g_part_apm_methods, 1021d3aed33SMarcel Moolenaar sizeof(struct g_part_apm_table), 1031d3aed33SMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_apm_entry), 1041d3aed33SMarcel Moolenaar .gps_minent = 16, 1051d3aed33SMarcel Moolenaar .gps_maxent = INT_MAX, 1061d3aed33SMarcel Moolenaar }; 1074ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_apm); 1081d3aed33SMarcel Moolenaar 1090952268eSWarner Losh static void 1100952268eSWarner Losh swab(char *buf, size_t bufsz) 1110952268eSWarner Losh { 1120952268eSWarner Losh int i; 1130952268eSWarner Losh char ch; 1140952268eSWarner Losh 1150952268eSWarner Losh for (i = 0; i < bufsz; i += 2) { 1160952268eSWarner Losh ch = buf[i]; 1170952268eSWarner Losh buf[i] = buf[i + 1]; 1180952268eSWarner Losh buf[i + 1] = ch; 1190952268eSWarner Losh } 1200952268eSWarner Losh } 1210952268eSWarner Losh 1221d3aed33SMarcel Moolenaar static int 1231d3aed33SMarcel Moolenaar apm_parse_type(const char *type, char *buf, size_t bufsz) 1241d3aed33SMarcel Moolenaar { 125d287f590SMarcel Moolenaar const char *alias; 1261d3aed33SMarcel Moolenaar 127d287f590SMarcel Moolenaar if (type[0] == '!') { 128d287f590SMarcel Moolenaar type++; 1291d3aed33SMarcel Moolenaar if (strlen(type) > bufsz) 1301d3aed33SMarcel Moolenaar return (EINVAL); 1311d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_SELF) || 1321d3aed33SMarcel Moolenaar !strcmp(type, APM_ENT_TYPE_UNUSED)) 1331d3aed33SMarcel Moolenaar return (EINVAL); 1341d3aed33SMarcel Moolenaar strncpy(buf, type, bufsz); 1351d3aed33SMarcel Moolenaar return (0); 1361d3aed33SMarcel Moolenaar } 1370532c3a5SNathan Whitehorn alias = g_part_alias_name(G_PART_ALIAS_APPLE_BOOT); 1380532c3a5SNathan Whitehorn if (!strcasecmp(type, alias)) { 1390532c3a5SNathan Whitehorn strcpy(buf, APM_ENT_TYPE_APPLE_BOOT); 1400532c3a5SNathan Whitehorn return (0); 1410532c3a5SNathan Whitehorn } 1420532c3a5SNathan Whitehorn alias = g_part_alias_name(G_PART_ALIAS_APPLE_HFS); 1430532c3a5SNathan Whitehorn if (!strcasecmp(type, alias)) { 1440532c3a5SNathan Whitehorn strcpy(buf, APM_ENT_TYPE_APPLE_HFS); 1450532c3a5SNathan Whitehorn return (0); 1460532c3a5SNathan Whitehorn } 1470532c3a5SNathan Whitehorn alias = g_part_alias_name(G_PART_ALIAS_APPLE_UFS); 1480532c3a5SNathan Whitehorn if (!strcasecmp(type, alias)) { 1490532c3a5SNathan Whitehorn strcpy(buf, APM_ENT_TYPE_APPLE_UFS); 1500532c3a5SNathan Whitehorn return (0); 1510532c3a5SNathan Whitehorn } 1520532c3a5SNathan Whitehorn alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_BOOT); 1530532c3a5SNathan Whitehorn if (!strcasecmp(type, alias)) { 1540532c3a5SNathan Whitehorn strcpy(buf, APM_ENT_TYPE_APPLE_BOOT); 1550532c3a5SNathan Whitehorn return (0); 1560532c3a5SNathan Whitehorn } 157d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); 158d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 1591d3aed33SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD); 1601d3aed33SMarcel Moolenaar return (0); 1611d3aed33SMarcel Moolenaar } 162d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP); 163d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 164d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_SWAP); 165d287f590SMarcel Moolenaar return (0); 166d287f590SMarcel Moolenaar } 167d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS); 168d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 169d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_UFS); 170d287f590SMarcel Moolenaar return (0); 171d287f590SMarcel Moolenaar } 172d287f590SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM); 173d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 174d287f590SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_VINUM); 175d287f590SMarcel Moolenaar return (0); 176d287f590SMarcel Moolenaar } 177a1fedf91SMarcel Moolenaar alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS); 178a1fedf91SMarcel Moolenaar if (!strcasecmp(type, alias)) { 179a1fedf91SMarcel Moolenaar strcpy(buf, APM_ENT_TYPE_FREEBSD_ZFS); 180a1fedf91SMarcel Moolenaar return (0); 181a1fedf91SMarcel Moolenaar } 182d287f590SMarcel Moolenaar return (EINVAL); 183d287f590SMarcel Moolenaar } 1841d3aed33SMarcel Moolenaar 1851d3aed33SMarcel Moolenaar static int 1860952268eSWarner Losh apm_read_ent(struct g_consumer *cp, uint32_t blk, struct apm_ent *ent, 1870952268eSWarner Losh int tivo_series1) 1881d3aed33SMarcel Moolenaar { 1891d3aed33SMarcel Moolenaar struct g_provider *pp; 1901d3aed33SMarcel Moolenaar char *buf; 1911d3aed33SMarcel Moolenaar int error; 1921d3aed33SMarcel Moolenaar 1931d3aed33SMarcel Moolenaar pp = cp->provider; 1941d3aed33SMarcel Moolenaar buf = g_read_data(cp, pp->sectorsize * blk, pp->sectorsize, &error); 1951d3aed33SMarcel Moolenaar if (buf == NULL) 1961d3aed33SMarcel Moolenaar return (error); 1970952268eSWarner Losh if (tivo_series1) 1980952268eSWarner Losh swab(buf, pp->sectorsize); 1991d3aed33SMarcel Moolenaar ent->ent_sig = be16dec(buf); 2001d3aed33SMarcel Moolenaar ent->ent_pmblkcnt = be32dec(buf + 4); 2011d3aed33SMarcel Moolenaar ent->ent_start = be32dec(buf + 8); 2021d3aed33SMarcel Moolenaar ent->ent_size = be32dec(buf + 12); 2031d3aed33SMarcel Moolenaar bcopy(buf + 16, ent->ent_name, sizeof(ent->ent_name)); 2041d3aed33SMarcel Moolenaar bcopy(buf + 48, ent->ent_type, sizeof(ent->ent_type)); 2051d3aed33SMarcel Moolenaar g_free(buf); 2061d3aed33SMarcel Moolenaar return (0); 2071d3aed33SMarcel Moolenaar } 2081d3aed33SMarcel Moolenaar 2091d3aed33SMarcel Moolenaar static int 2101d3aed33SMarcel Moolenaar g_part_apm_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 2111d3aed33SMarcel Moolenaar struct g_part_parms *gpp) 2121d3aed33SMarcel Moolenaar { 2131d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 2141d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 2151d3aed33SMarcel Moolenaar int error; 2161d3aed33SMarcel Moolenaar 2171d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 2181d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 2191d3aed33SMarcel Moolenaar entry->ent.ent_sig = APM_ENT_SIG; 2201d3aed33SMarcel Moolenaar entry->ent.ent_pmblkcnt = table->self.ent_pmblkcnt; 2211d3aed33SMarcel Moolenaar entry->ent.ent_start = gpp->gpp_start; 2221d3aed33SMarcel Moolenaar entry->ent.ent_size = gpp->gpp_size; 2231d3aed33SMarcel Moolenaar if (baseentry->gpe_deleted) { 2241d3aed33SMarcel Moolenaar bzero(entry->ent.ent_type, sizeof(entry->ent.ent_type)); 2251d3aed33SMarcel Moolenaar bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name)); 2261d3aed33SMarcel Moolenaar } 2271d3aed33SMarcel Moolenaar error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type, 2281d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 2291d3aed33SMarcel Moolenaar if (error) 2301d3aed33SMarcel Moolenaar return (error); 2311d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 2321d3aed33SMarcel Moolenaar if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name)) 2331d3aed33SMarcel Moolenaar return (EINVAL); 2341d3aed33SMarcel Moolenaar strncpy(entry->ent.ent_name, gpp->gpp_label, 2351d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 2361d3aed33SMarcel Moolenaar } 237*a85a0d46SAndrey V. Elsukov if (baseentry->gpe_index >= table->self.ent_pmblkcnt) 238*a85a0d46SAndrey V. Elsukov table->self.ent_pmblkcnt = baseentry->gpe_index + 1; 239*a85a0d46SAndrey V. Elsukov KASSERT(table->self.ent_size >= table->self.ent_pmblkcnt, 240*a85a0d46SAndrey V. Elsukov ("%s", __func__)); 241*a85a0d46SAndrey V. Elsukov KASSERT(table->self.ent_size > baseentry->gpe_index, 242*a85a0d46SAndrey V. Elsukov ("%s", __func__)); 2431d3aed33SMarcel Moolenaar return (0); 2441d3aed33SMarcel Moolenaar } 2451d3aed33SMarcel Moolenaar 2461d3aed33SMarcel Moolenaar static int 2471d3aed33SMarcel Moolenaar g_part_apm_create(struct g_part_table *basetable, struct g_part_parms *gpp) 2481d3aed33SMarcel Moolenaar { 2491d3aed33SMarcel Moolenaar struct g_provider *pp; 2501d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 251d01a198bSMarcel Moolenaar uint32_t last; 252d01a198bSMarcel Moolenaar 253d01a198bSMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 254d01a198bSMarcel Moolenaar if (basetable->gpt_depth != 0) 255d01a198bSMarcel Moolenaar return (ENXIO); 2561d3aed33SMarcel Moolenaar 2571d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 2581d3aed33SMarcel Moolenaar pp = gpp->gpp_provider; 2591d3aed33SMarcel Moolenaar if (pp->sectorsize != 512 || 2601d3aed33SMarcel Moolenaar pp->mediasize < (2 + 2 * basetable->gpt_entries) * pp->sectorsize) 2611d3aed33SMarcel Moolenaar return (ENOSPC); 2621d3aed33SMarcel Moolenaar 263d01a198bSMarcel Moolenaar /* APM uses 32-bit LBAs. */ 2646017ae3fSAndrey V. Elsukov last = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX) - 1; 265d01a198bSMarcel Moolenaar 2661d3aed33SMarcel Moolenaar basetable->gpt_first = 2 + basetable->gpt_entries; 267d01a198bSMarcel Moolenaar basetable->gpt_last = last; 2681d3aed33SMarcel Moolenaar 2691d3aed33SMarcel Moolenaar table->ddr.ddr_sig = APM_DDR_SIG; 2701d3aed33SMarcel Moolenaar table->ddr.ddr_blksize = pp->sectorsize; 271d01a198bSMarcel Moolenaar table->ddr.ddr_blkcount = last + 1; 2721d3aed33SMarcel Moolenaar 2731d3aed33SMarcel Moolenaar table->self.ent_sig = APM_ENT_SIG; 2741d3aed33SMarcel Moolenaar table->self.ent_pmblkcnt = basetable->gpt_entries + 1; 2751d3aed33SMarcel Moolenaar table->self.ent_start = 1; 2761d3aed33SMarcel Moolenaar table->self.ent_size = table->self.ent_pmblkcnt; 2771d3aed33SMarcel Moolenaar strcpy(table->self.ent_name, "Apple"); 2781d3aed33SMarcel Moolenaar strcpy(table->self.ent_type, APM_ENT_TYPE_SELF); 2791d3aed33SMarcel Moolenaar return (0); 2801d3aed33SMarcel Moolenaar } 2811d3aed33SMarcel Moolenaar 2821d3aed33SMarcel Moolenaar static int 2831d3aed33SMarcel Moolenaar g_part_apm_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 2841d3aed33SMarcel Moolenaar { 2851d3aed33SMarcel Moolenaar 2861d3aed33SMarcel Moolenaar /* Wipe the first 2 sectors to clear the partitioning. */ 2871d3aed33SMarcel Moolenaar basetable->gpt_smhead |= 3; 2881d3aed33SMarcel Moolenaar return (0); 2891d3aed33SMarcel Moolenaar } 2901d3aed33SMarcel Moolenaar 29151f53a08SWarner Losh static void 2925db67052SMarcel Moolenaar g_part_apm_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 2935db67052SMarcel Moolenaar struct sbuf *sb, const char *indent) 2945db67052SMarcel Moolenaar { 295ab1e8f04SMarcel Moolenaar union { 296ab1e8f04SMarcel Moolenaar char name[APM_ENT_NAMELEN + 1]; 297ab1e8f04SMarcel Moolenaar char type[APM_ENT_TYPELEN + 1]; 298ab1e8f04SMarcel Moolenaar } u; 2995db67052SMarcel Moolenaar struct g_part_apm_entry *entry; 3005db67052SMarcel Moolenaar 3015db67052SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 302ab1e8f04SMarcel Moolenaar if (indent == NULL) { 303ab1e8f04SMarcel Moolenaar /* conftxt: libdisk compatibility */ 3045db67052SMarcel Moolenaar sbuf_printf(sb, " xs APPLE xt %s", entry->ent.ent_type); 305ab1e8f04SMarcel Moolenaar } else if (entry != NULL) { 306ab1e8f04SMarcel Moolenaar /* confxml: partition entry information */ 307ab1e8f04SMarcel Moolenaar strncpy(u.name, entry->ent.ent_name, APM_ENT_NAMELEN); 308ab1e8f04SMarcel Moolenaar u.name[APM_ENT_NAMELEN] = '\0'; 309ab1e8f04SMarcel Moolenaar sbuf_printf(sb, "%s<label>%s</label>\n", indent, u.name); 310ab1e8f04SMarcel Moolenaar strncpy(u.type, entry->ent.ent_type, APM_ENT_TYPELEN); 311ab1e8f04SMarcel Moolenaar u.type[APM_ENT_TYPELEN] = '\0'; 312ab1e8f04SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>%s</rawtype>\n", indent, u.type); 313ab1e8f04SMarcel Moolenaar } else { 314ab1e8f04SMarcel Moolenaar /* confxml: scheme information */ 315ab1e8f04SMarcel Moolenaar } 3165db67052SMarcel Moolenaar } 3175db67052SMarcel Moolenaar 3185db67052SMarcel Moolenaar static int 3191d3aed33SMarcel Moolenaar g_part_apm_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 3201d3aed33SMarcel Moolenaar { 3211d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 3221d3aed33SMarcel Moolenaar 3231d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 3241d3aed33SMarcel Moolenaar return ((!strcmp(entry->ent.ent_type, APM_ENT_TYPE_FREEBSD_SWAP)) 3251d3aed33SMarcel Moolenaar ? 1 : 0); 3261d3aed33SMarcel Moolenaar } 3271d3aed33SMarcel Moolenaar 3281d3aed33SMarcel Moolenaar static int 3291d3aed33SMarcel Moolenaar g_part_apm_modify(struct g_part_table *basetable, 3301d3aed33SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3311d3aed33SMarcel Moolenaar { 3321d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 3331d3aed33SMarcel Moolenaar int error; 3341d3aed33SMarcel Moolenaar 3351d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 3361d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 3371d3aed33SMarcel Moolenaar if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name)) 3381d3aed33SMarcel Moolenaar return (EINVAL); 3391d3aed33SMarcel Moolenaar } 3401d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE) { 3411d3aed33SMarcel Moolenaar error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type, 3421d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 3431d3aed33SMarcel Moolenaar if (error) 3441d3aed33SMarcel Moolenaar return (error); 3451d3aed33SMarcel Moolenaar } 3461d3aed33SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) { 3471d3aed33SMarcel Moolenaar strncpy(entry->ent.ent_name, gpp->gpp_label, 3481d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 3491d3aed33SMarcel Moolenaar } 3501d3aed33SMarcel Moolenaar return (0); 3511d3aed33SMarcel Moolenaar } 3521d3aed33SMarcel Moolenaar 3533f71c319SMarcel Moolenaar static int 3543f71c319SMarcel Moolenaar g_part_apm_resize(struct g_part_table *basetable, 3553f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 3563f71c319SMarcel Moolenaar { 3573f71c319SMarcel Moolenaar struct g_part_apm_entry *entry; 3583f71c319SMarcel Moolenaar 3593f71c319SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 3603f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 3613f71c319SMarcel Moolenaar entry->ent.ent_size = gpp->gpp_size; 3623f71c319SMarcel Moolenaar 3633f71c319SMarcel Moolenaar return (0); 3643f71c319SMarcel Moolenaar } 3653f71c319SMarcel Moolenaar 36651f53a08SWarner Losh static const char * 3671d3aed33SMarcel Moolenaar g_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry, 3681d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 3691d3aed33SMarcel Moolenaar { 3701d3aed33SMarcel Moolenaar 3711d3aed33SMarcel Moolenaar snprintf(buf, bufsz, "s%d", baseentry->gpe_index + 1); 3721d3aed33SMarcel Moolenaar return (buf); 3731d3aed33SMarcel Moolenaar } 3741d3aed33SMarcel Moolenaar 3751d3aed33SMarcel Moolenaar static int 3761d3aed33SMarcel Moolenaar g_part_apm_probe(struct g_part_table *basetable, struct g_consumer *cp) 3771d3aed33SMarcel Moolenaar { 3781d3aed33SMarcel Moolenaar struct g_provider *pp; 3791d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 3801d3aed33SMarcel Moolenaar char *buf; 3811d3aed33SMarcel Moolenaar int error; 3821d3aed33SMarcel Moolenaar 3831d3aed33SMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 3841d3aed33SMarcel Moolenaar if (basetable->gpt_depth != 0) 3851d3aed33SMarcel Moolenaar return (ENXIO); 3861d3aed33SMarcel Moolenaar 3871d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 3880952268eSWarner Losh table->tivo_series1 = 0; 3891d3aed33SMarcel Moolenaar pp = cp->provider; 3901d3aed33SMarcel Moolenaar 3911d3aed33SMarcel Moolenaar /* Sanity-check the provider. */ 3921d3aed33SMarcel Moolenaar if (pp->mediasize < 4 * pp->sectorsize) 3931d3aed33SMarcel Moolenaar return (ENOSPC); 3941d3aed33SMarcel Moolenaar 3951d3aed33SMarcel Moolenaar /* Check that there's a Driver Descriptor Record (DDR). */ 3961d3aed33SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 3971d3aed33SMarcel Moolenaar if (buf == NULL) 3981d3aed33SMarcel Moolenaar return (error); 39947bae5fdSGavin Atkinson if (be16dec(buf) == APM_DDR_SIG) { 4000952268eSWarner Losh /* Normal Apple DDR */ 4011d3aed33SMarcel Moolenaar table->ddr.ddr_sig = be16dec(buf); 4021d3aed33SMarcel Moolenaar table->ddr.ddr_blksize = be16dec(buf + 2); 4031d3aed33SMarcel Moolenaar table->ddr.ddr_blkcount = be32dec(buf + 4); 4041d3aed33SMarcel Moolenaar g_free(buf); 4051d3aed33SMarcel Moolenaar if (table->ddr.ddr_blksize != pp->sectorsize) 4061d3aed33SMarcel Moolenaar return (ENXIO); 4076017ae3fSAndrey V. Elsukov if (table->ddr.ddr_blkcount > pp->mediasize / pp->sectorsize) 4086017ae3fSAndrey V. Elsukov return (ENXIO); 4090952268eSWarner Losh } else { 4100952268eSWarner Losh /* 4110952268eSWarner Losh * Check for Tivo drives, which have no DDR and a different 4120952268eSWarner Losh * signature. Those whose first two bytes are 14 92 are 4130952268eSWarner Losh * Series 2 drives, and aren't supported. Those that start 4140952268eSWarner Losh * with 92 14 are series 1 drives and are supported. 4150952268eSWarner Losh */ 4160952268eSWarner Losh if (be16dec(buf) != 0x9214) { 4170952268eSWarner Losh /* If this is 0x1492 it could be a series 2 drive */ 4180952268eSWarner Losh g_free(buf); 4190952268eSWarner Losh return (ENXIO); 4200952268eSWarner Losh } 4210952268eSWarner Losh table->ddr.ddr_sig = APM_DDR_SIG; /* XXX */ 4220952268eSWarner Losh table->ddr.ddr_blksize = pp->sectorsize; /* XXX */ 4236017ae3fSAndrey V. Elsukov table->ddr.ddr_blkcount = 4246017ae3fSAndrey V. Elsukov MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 4250952268eSWarner Losh table->tivo_series1 = 1; 4260952268eSWarner Losh g_free(buf); 4270952268eSWarner Losh } 4281d3aed33SMarcel Moolenaar 4291d3aed33SMarcel Moolenaar /* Check that there's a Partition Map. */ 4300952268eSWarner Losh error = apm_read_ent(cp, 1, &table->self, table->tivo_series1); 4311d3aed33SMarcel Moolenaar if (error) 4321d3aed33SMarcel Moolenaar return (error); 4331d3aed33SMarcel Moolenaar if (table->self.ent_sig != APM_ENT_SIG) 4341d3aed33SMarcel Moolenaar return (ENXIO); 4351d3aed33SMarcel Moolenaar if (strcmp(table->self.ent_type, APM_ENT_TYPE_SELF)) 4361d3aed33SMarcel Moolenaar return (ENXIO); 4371d3aed33SMarcel Moolenaar if (table->self.ent_pmblkcnt >= table->ddr.ddr_blkcount) 4381d3aed33SMarcel Moolenaar return (ENXIO); 4391d3aed33SMarcel Moolenaar return (G_PART_PROBE_PRI_NORM); 4401d3aed33SMarcel Moolenaar } 4411d3aed33SMarcel Moolenaar 4421d3aed33SMarcel Moolenaar static int 4431d3aed33SMarcel Moolenaar g_part_apm_read(struct g_part_table *basetable, struct g_consumer *cp) 4441d3aed33SMarcel Moolenaar { 4451d3aed33SMarcel Moolenaar struct apm_ent ent; 4461d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 4471d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 4481d3aed33SMarcel Moolenaar int error, index; 4491d3aed33SMarcel Moolenaar 4501d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 4511d3aed33SMarcel Moolenaar 45264c4a837SAndrey V. Elsukov basetable->gpt_first = table->self.ent_size + 1; 4531d3aed33SMarcel Moolenaar basetable->gpt_last = table->ddr.ddr_blkcount - 1; 454*a85a0d46SAndrey V. Elsukov basetable->gpt_entries = table->self.ent_size - 1; 4551d3aed33SMarcel Moolenaar 4561d3aed33SMarcel Moolenaar for (index = table->self.ent_pmblkcnt - 1; index > 0; index--) { 4570952268eSWarner Losh error = apm_read_ent(cp, index + 1, &ent, table->tivo_series1); 4581d3aed33SMarcel Moolenaar if (error) 4591d3aed33SMarcel Moolenaar continue; 4601d3aed33SMarcel Moolenaar if (!strcmp(ent.ent_type, APM_ENT_TYPE_UNUSED)) 4611d3aed33SMarcel Moolenaar continue; 4621d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)g_part_new_entry(basetable, 4631d3aed33SMarcel Moolenaar index, ent.ent_start, ent.ent_start + ent.ent_size - 1); 4641d3aed33SMarcel Moolenaar entry->ent = ent; 4651d3aed33SMarcel Moolenaar } 4661d3aed33SMarcel Moolenaar 4671d3aed33SMarcel Moolenaar return (0); 4681d3aed33SMarcel Moolenaar } 4691d3aed33SMarcel Moolenaar 4701d3aed33SMarcel Moolenaar static const char * 4711d3aed33SMarcel Moolenaar g_part_apm_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 4721d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 4731d3aed33SMarcel Moolenaar { 4741d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 4751d3aed33SMarcel Moolenaar const char *type; 4761d3aed33SMarcel Moolenaar size_t len; 4771d3aed33SMarcel Moolenaar 4781d3aed33SMarcel Moolenaar entry = (struct g_part_apm_entry *)baseentry; 4791d3aed33SMarcel Moolenaar type = entry->ent.ent_type; 4800532c3a5SNathan Whitehorn if (!strcmp(type, APM_ENT_TYPE_APPLE_BOOT)) 4810532c3a5SNathan Whitehorn return (g_part_alias_name(G_PART_ALIAS_APPLE_BOOT)); 4820532c3a5SNathan Whitehorn if (!strcmp(type, APM_ENT_TYPE_APPLE_HFS)) 4830532c3a5SNathan Whitehorn return (g_part_alias_name(G_PART_ALIAS_APPLE_HFS)); 4840532c3a5SNathan Whitehorn if (!strcmp(type, APM_ENT_TYPE_APPLE_UFS)) 4850532c3a5SNathan Whitehorn return (g_part_alias_name(G_PART_ALIAS_APPLE_UFS)); 4861d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD)) 4871d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); 4881d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_SWAP)) 4891d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); 4901d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_UFS)) 4911d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); 4921d3aed33SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_VINUM)) 4931d3aed33SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); 494a1fedf91SMarcel Moolenaar if (!strcmp(type, APM_ENT_TYPE_FREEBSD_ZFS)) 495a1fedf91SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); 496cf231470SMarcel Moolenaar buf[0] = '!'; 497cf231470SMarcel Moolenaar len = MIN(sizeof(entry->ent.ent_type), bufsz - 2); 498cf231470SMarcel Moolenaar bcopy(type, buf + 1, len); 499cf231470SMarcel Moolenaar buf[len + 1] = '\0'; 5001d3aed33SMarcel Moolenaar return (buf); 5011d3aed33SMarcel Moolenaar } 5021d3aed33SMarcel Moolenaar 5031d3aed33SMarcel Moolenaar static int 5041d3aed33SMarcel Moolenaar g_part_apm_write(struct g_part_table *basetable, struct g_consumer *cp) 5051d3aed33SMarcel Moolenaar { 506*a85a0d46SAndrey V. Elsukov struct g_provider *pp; 5071d3aed33SMarcel Moolenaar struct g_part_entry *baseentry; 5081d3aed33SMarcel Moolenaar struct g_part_apm_entry *entry; 5091d3aed33SMarcel Moolenaar struct g_part_apm_table *table; 510*a85a0d46SAndrey V. Elsukov char *buf, *ptr; 511*a85a0d46SAndrey V. Elsukov uint32_t index; 512*a85a0d46SAndrey V. Elsukov int error; 513*a85a0d46SAndrey V. Elsukov size_t tblsz; 5141d3aed33SMarcel Moolenaar 515*a85a0d46SAndrey V. Elsukov pp = cp->provider; 5161d3aed33SMarcel Moolenaar table = (struct g_part_apm_table *)basetable; 5170952268eSWarner Losh /* 5180952268eSWarner Losh * Tivo Series 1 disk partitions are currently read-only. 5190952268eSWarner Losh */ 5200952268eSWarner Losh if (table->tivo_series1) 5210952268eSWarner Losh return (EOPNOTSUPP); 5221d3aed33SMarcel Moolenaar 523*a85a0d46SAndrey V. Elsukov /* Write the DDR only when we're newly created. */ 5241d3aed33SMarcel Moolenaar if (basetable->gpt_created) { 525*a85a0d46SAndrey V. Elsukov buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 5261d3aed33SMarcel Moolenaar be16enc(buf, table->ddr.ddr_sig); 5271d3aed33SMarcel Moolenaar be16enc(buf + 2, table->ddr.ddr_blksize); 5281d3aed33SMarcel Moolenaar be32enc(buf + 4, table->ddr.ddr_blkcount); 529*a85a0d46SAndrey V. Elsukov error = g_write_data(cp, 0, buf, pp->sectorsize); 530*a85a0d46SAndrey V. Elsukov g_free(buf); 5311d3aed33SMarcel Moolenaar if (error) 5321d3aed33SMarcel Moolenaar return (error); 5331d3aed33SMarcel Moolenaar } 5341d3aed33SMarcel Moolenaar 535*a85a0d46SAndrey V. Elsukov /* Allocate the buffer for all entries */ 536*a85a0d46SAndrey V. Elsukov tblsz = table->self.ent_pmblkcnt; 537*a85a0d46SAndrey V. Elsukov buf = g_malloc(tblsz * pp->sectorsize, M_WAITOK | M_ZERO); 5381d3aed33SMarcel Moolenaar 539*a85a0d46SAndrey V. Elsukov /* Fill the self entry */ 540*a85a0d46SAndrey V. Elsukov be16enc(buf, APM_ENT_SIG); 541*a85a0d46SAndrey V. Elsukov be32enc(buf + 4, table->self.ent_pmblkcnt); 5421d3aed33SMarcel Moolenaar be32enc(buf + 8, table->self.ent_start); 5431d3aed33SMarcel Moolenaar be32enc(buf + 12, table->self.ent_size); 544*a85a0d46SAndrey V. Elsukov bcopy(table->self.ent_name, buf + 16, sizeof(table->self.ent_name)); 545*a85a0d46SAndrey V. Elsukov bcopy(table->self.ent_type, buf + 48, sizeof(table->self.ent_type)); 5461d3aed33SMarcel Moolenaar 5471d3aed33SMarcel Moolenaar baseentry = LIST_FIRST(&basetable->gpt_entry); 548*a85a0d46SAndrey V. Elsukov for (index = 1; index < tblsz; index++) { 549d287f590SMarcel Moolenaar entry = (baseentry != NULL && index == baseentry->gpe_index) 550d287f590SMarcel Moolenaar ? (struct g_part_apm_entry *)baseentry : NULL; 551*a85a0d46SAndrey V. Elsukov ptr = buf + index * pp->sectorsize; 552*a85a0d46SAndrey V. Elsukov be16enc(ptr, APM_ENT_SIG); 553*a85a0d46SAndrey V. Elsukov be32enc(ptr + 4, table->self.ent_pmblkcnt); 554d287f590SMarcel Moolenaar if (entry != NULL && !baseentry->gpe_deleted) { 555*a85a0d46SAndrey V. Elsukov be32enc(ptr + 8, entry->ent.ent_start); 556*a85a0d46SAndrey V. Elsukov be32enc(ptr + 12, entry->ent.ent_size); 557*a85a0d46SAndrey V. Elsukov bcopy(entry->ent.ent_name, ptr + 16, 5581d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 559*a85a0d46SAndrey V. Elsukov bcopy(entry->ent.ent_type, ptr + 48, 5601d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_type)); 5611d3aed33SMarcel Moolenaar } else { 562*a85a0d46SAndrey V. Elsukov strcpy(ptr + 48, APM_ENT_TYPE_UNUSED); 5631d3aed33SMarcel Moolenaar } 564d287f590SMarcel Moolenaar if (entry != NULL) 565d287f590SMarcel Moolenaar baseentry = LIST_NEXT(baseentry, gpe_entry); 5661d3aed33SMarcel Moolenaar } 5671d3aed33SMarcel Moolenaar 568*a85a0d46SAndrey V. Elsukov for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) { 569*a85a0d46SAndrey V. Elsukov error = g_write_data(cp, (1 + index) * pp->sectorsize, 570*a85a0d46SAndrey V. Elsukov buf + index * pp->sectorsize, 571*a85a0d46SAndrey V. Elsukov (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS: 572*a85a0d46SAndrey V. Elsukov (tblsz - index) * pp->sectorsize); 573*a85a0d46SAndrey V. Elsukov if (error) { 574*a85a0d46SAndrey V. Elsukov g_free(buf); 575*a85a0d46SAndrey V. Elsukov return (error); 576*a85a0d46SAndrey V. Elsukov } 577*a85a0d46SAndrey V. Elsukov } 578*a85a0d46SAndrey V. Elsukov g_free(buf); 5791d3aed33SMarcel Moolenaar return (0); 5801d3aed33SMarcel Moolenaar } 581