1177692Smarcel/*- 2177692Smarcel * Copyright (c) 2008 Marcel Moolenaar 3177692Smarcel * All rights reserved. 4177692Smarcel * 5177692Smarcel * Redistribution and use in source and binary forms, with or without 6177692Smarcel * modification, are permitted provided that the following conditions 7177692Smarcel * are met: 8177692Smarcel * 9177692Smarcel * 1. Redistributions of source code must retain the above copyright 10177692Smarcel * notice, this list of conditions and the following disclaimer. 11177692Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12177692Smarcel * notice, this list of conditions and the following disclaimer in the 13177692Smarcel * documentation and/or other materials provided with the distribution. 14177692Smarcel * 15177692Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16177692Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17177692Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18177692Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19177692Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20177692Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21177692Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22177692Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23177692Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24177692Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25177692Smarcel */ 26177692Smarcel 27177692Smarcel#include <sys/cdefs.h> 28177692Smarcel__FBSDID("$FreeBSD$"); 29177692Smarcel 30177692Smarcel#include <sys/param.h> 31177692Smarcel#include <sys/bio.h> 32177692Smarcel#include <sys/diskpc98.h> 33177692Smarcel#include <sys/endian.h> 34177692Smarcel#include <sys/kernel.h> 35177692Smarcel#include <sys/kobj.h> 36177692Smarcel#include <sys/limits.h> 37177692Smarcel#include <sys/lock.h> 38177692Smarcel#include <sys/malloc.h> 39177692Smarcel#include <sys/mutex.h> 40177692Smarcel#include <sys/queue.h> 41177692Smarcel#include <sys/sbuf.h> 42177692Smarcel#include <sys/systm.h> 43219029Snetchild#include <sys/sysctl.h> 44177692Smarcel#include <geom/geom.h> 45265910Sae#include <geom/geom_int.h> 46177692Smarcel#include <geom/part/g_part.h> 47177692Smarcel 48177692Smarcel#include "g_part_if.h" 49177692Smarcel 50219029SnetchildFEATURE(geom_part_pc98, "GEOM partitioning class for PC-9800 disk partitions"); 51219029Snetchild 52177692Smarcel#define SECSIZE 512 53218558Snyan#define MENUSIZE 7168 54218558Snyan#define BOOTSIZE 8192 55177692Smarcel 56177692Smarcelstruct g_part_pc98_table { 57177692Smarcel struct g_part_table base; 58177692Smarcel u_char boot[SECSIZE]; 59177692Smarcel u_char table[SECSIZE]; 60218558Snyan u_char menu[MENUSIZE]; 61177692Smarcel}; 62177692Smarcel 63177692Smarcelstruct g_part_pc98_entry { 64177692Smarcel struct g_part_entry base; 65177692Smarcel struct pc98_partition ent; 66177692Smarcel}; 67177692Smarcel 68177692Smarcelstatic int g_part_pc98_add(struct g_part_table *, struct g_part_entry *, 69177692Smarcel struct g_part_parms *); 70178180Smarcelstatic int g_part_pc98_bootcode(struct g_part_table *, struct g_part_parms *); 71177692Smarcelstatic int g_part_pc98_create(struct g_part_table *, struct g_part_parms *); 72177692Smarcelstatic int g_part_pc98_destroy(struct g_part_table *, struct g_part_parms *); 73188429Simpstatic void g_part_pc98_dumpconf(struct g_part_table *, struct g_part_entry *, 74178444Smarcel struct sbuf *, const char *); 75177692Smarcelstatic int g_part_pc98_dumpto(struct g_part_table *, struct g_part_entry *); 76177692Smarcelstatic int g_part_pc98_modify(struct g_part_table *, struct g_part_entry *, 77177692Smarcel struct g_part_parms *); 78188429Simpstatic const char *g_part_pc98_name(struct g_part_table *, struct g_part_entry *, 79177692Smarcel char *, size_t); 80177692Smarcelstatic int g_part_pc98_probe(struct g_part_table *, struct g_consumer *); 81177692Smarcelstatic int g_part_pc98_read(struct g_part_table *, struct g_consumer *); 82184069Smarcelstatic int g_part_pc98_setunset(struct g_part_table *, struct g_part_entry *, 83184069Smarcel const char *, unsigned int); 84184069Smarcelstatic const char *g_part_pc98_type(struct g_part_table *, 85184069Smarcel struct g_part_entry *, char *, size_t); 86177692Smarcelstatic int g_part_pc98_write(struct g_part_table *, struct g_consumer *); 87207094Smarcelstatic int g_part_pc98_resize(struct g_part_table *, struct g_part_entry *, 88207094Smarcel struct g_part_parms *); 89177692Smarcel 90177692Smarcelstatic kobj_method_t g_part_pc98_methods[] = { 91177692Smarcel KOBJMETHOD(g_part_add, g_part_pc98_add), 92178180Smarcel KOBJMETHOD(g_part_bootcode, g_part_pc98_bootcode), 93177692Smarcel KOBJMETHOD(g_part_create, g_part_pc98_create), 94177692Smarcel KOBJMETHOD(g_part_destroy, g_part_pc98_destroy), 95178444Smarcel KOBJMETHOD(g_part_dumpconf, g_part_pc98_dumpconf), 96177692Smarcel KOBJMETHOD(g_part_dumpto, g_part_pc98_dumpto), 97177692Smarcel KOBJMETHOD(g_part_modify, g_part_pc98_modify), 98207094Smarcel KOBJMETHOD(g_part_resize, g_part_pc98_resize), 99177692Smarcel KOBJMETHOD(g_part_name, g_part_pc98_name), 100177692Smarcel KOBJMETHOD(g_part_probe, g_part_pc98_probe), 101177692Smarcel KOBJMETHOD(g_part_read, g_part_pc98_read), 102184069Smarcel KOBJMETHOD(g_part_setunset, g_part_pc98_setunset), 103177692Smarcel KOBJMETHOD(g_part_type, g_part_pc98_type), 104177692Smarcel KOBJMETHOD(g_part_write, g_part_pc98_write), 105177692Smarcel { 0, 0 } 106177692Smarcel}; 107177692Smarcel 108177692Smarcelstatic struct g_part_scheme g_part_pc98_scheme = { 109177692Smarcel "PC98", 110177692Smarcel g_part_pc98_methods, 111177692Smarcel sizeof(struct g_part_pc98_table), 112177692Smarcel .gps_entrysz = sizeof(struct g_part_pc98_entry), 113254015Smarcel .gps_minent = PC98_NPARTS, 114254015Smarcel .gps_maxent = PC98_NPARTS, 115218558Snyan .gps_bootcodesz = BOOTSIZE, 116177692Smarcel}; 117177692SmarcelG_PART_SCHEME_DECLARE(g_part_pc98); 118177692Smarcel 119177692Smarcelstatic int 120177692Smarcelpc98_parse_type(const char *type, u_char *dp_mid, u_char *dp_sid) 121177692Smarcel{ 122177692Smarcel const char *alias; 123177692Smarcel char *endp; 124177692Smarcel long lt; 125177692Smarcel 126177692Smarcel if (type[0] == '!') { 127177692Smarcel lt = strtol(type + 1, &endp, 0); 128177692Smarcel if (type[1] == '\0' || *endp != '\0' || lt <= 0 || 129177692Smarcel lt >= 65536) 130177692Smarcel return (EINVAL); 131184069Smarcel /* Make sure the active and bootable flags aren't set. */ 132184069Smarcel if (lt & ((PC98_SID_ACTIVE << 8) | PC98_MID_BOOTABLE)) 133184069Smarcel return (ENOATTR); 134184069Smarcel *dp_mid = (*dp_mid & PC98_MID_BOOTABLE) | (u_char)lt; 135184069Smarcel *dp_sid = (*dp_sid & PC98_SID_ACTIVE) | (u_char)(lt >> 8); 136177692Smarcel return (0); 137177692Smarcel } 138177692Smarcel alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); 139177692Smarcel if (!strcasecmp(type, alias)) { 140184069Smarcel *dp_mid = (*dp_mid & PC98_MID_BOOTABLE) | PC98_MID_386BSD; 141184069Smarcel *dp_sid = (*dp_sid & PC98_SID_ACTIVE) | PC98_SID_386BSD; 142177692Smarcel return (0); 143177692Smarcel } 144177692Smarcel return (EINVAL); 145177692Smarcel} 146177692Smarcel 147218845Snyanstatic int 148218845Snyanpc98_set_slicename(const char *label, u_char *dp_name) 149218845Snyan{ 150218845Snyan int len; 151218845Snyan 152218845Snyan len = strlen(label); 153218845Snyan if (len > sizeof(((struct pc98_partition *)NULL)->dp_name)) 154218845Snyan return (EINVAL); 155218845Snyan bzero(dp_name, sizeof(((struct pc98_partition *)NULL)->dp_name)); 156218845Snyan strncpy(dp_name, label, len); 157218845Snyan 158218845Snyan return (0); 159218845Snyan} 160218845Snyan 161177692Smarcelstatic void 162177692Smarcelpc98_set_chs(struct g_part_table *table, uint32_t lba, u_short *cylp, 163177692Smarcel u_char *hdp, u_char *secp) 164177692Smarcel{ 165177692Smarcel uint32_t cyl, hd, sec; 166177692Smarcel 167177692Smarcel sec = lba % table->gpt_sectors + 1; 168177692Smarcel lba /= table->gpt_sectors; 169177692Smarcel hd = lba % table->gpt_heads; 170177692Smarcel lba /= table->gpt_heads; 171177692Smarcel cyl = lba; 172177692Smarcel 173177692Smarcel *cylp = htole16(cyl); 174177692Smarcel *hdp = hd; 175177692Smarcel *secp = sec; 176177692Smarcel} 177177692Smarcel 178177692Smarcelstatic int 179265910Saepc98_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) 180265910Sae{ 181265910Sae uint32_t cyl; 182265910Sae 183265910Sae cyl = basetable->gpt_heads * basetable->gpt_sectors; 184265910Sae if (*size < cyl) 185265910Sae return (EINVAL); 186265910Sae if (start != NULL && (*start % cyl)) { 187265910Sae *size += (*start % cyl) - cyl; 188265910Sae *start -= (*start % cyl) - cyl; 189265910Sae } 190265910Sae if (*size % cyl) 191265910Sae *size -= (*size % cyl); 192265910Sae if (*size < cyl) 193265910Sae return (EINVAL); 194265910Sae return (0); 195265910Sae} 196265910Sae 197265910Saestatic int 198177692Smarcelg_part_pc98_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 199177692Smarcel struct g_part_parms *gpp) 200177692Smarcel{ 201177692Smarcel struct g_part_pc98_entry *entry; 202265910Sae uint32_t start, size; 203218845Snyan int error; 204177692Smarcel 205177692Smarcel entry = (struct g_part_pc98_entry *)baseentry; 206177692Smarcel start = gpp->gpp_start; 207177692Smarcel size = gpp->gpp_size; 208265910Sae if (pc98_align(basetable, &start, &size) != 0) 209177692Smarcel return (EINVAL); 210177692Smarcel if (baseentry->gpe_deleted) 211177692Smarcel bzero(&entry->ent, sizeof(entry->ent)); 212184069Smarcel else 213184069Smarcel entry->ent.dp_mid = entry->ent.dp_sid = 0; 214177692Smarcel 215177692Smarcel KASSERT(baseentry->gpe_start <= start, (__func__)); 216177692Smarcel KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); 217177692Smarcel baseentry->gpe_start = start; 218177692Smarcel baseentry->gpe_end = start + size - 1; 219177692Smarcel pc98_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl, 220177692Smarcel &entry->ent.dp_shd, &entry->ent.dp_ssect); 221177692Smarcel pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 222177692Smarcel &entry->ent.dp_ehd, &entry->ent.dp_esect); 223218845Snyan 224218845Snyan error = pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid, 225218845Snyan &entry->ent.dp_sid); 226218845Snyan if (error) 227218845Snyan return (error); 228218845Snyan 229218845Snyan if (gpp->gpp_parms & G_PART_PARM_LABEL) 230218845Snyan return (pc98_set_slicename(gpp->gpp_label, entry->ent.dp_name)); 231218845Snyan 232218845Snyan return (0); 233177692Smarcel} 234177692Smarcel 235177692Smarcelstatic int 236178180Smarcelg_part_pc98_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 237178180Smarcel{ 238178180Smarcel struct g_part_pc98_table *table; 239218558Snyan const u_char *codeptr; 240178180Smarcel 241218558Snyan if (gpp->gpp_codesize != BOOTSIZE) 242218558Snyan return (EINVAL); 243218558Snyan 244178180Smarcel table = (struct g_part_pc98_table *)basetable; 245218558Snyan codeptr = gpp->gpp_codeptr; 246218558Snyan bcopy(codeptr, table->boot, SECSIZE); 247218558Snyan bcopy(codeptr + SECSIZE*2, table->menu, MENUSIZE); 248218558Snyan 249178180Smarcel return (0); 250178180Smarcel} 251178180Smarcel 252178180Smarcelstatic int 253177692Smarcelg_part_pc98_create(struct g_part_table *basetable, struct g_part_parms *gpp) 254177692Smarcel{ 255177692Smarcel struct g_provider *pp; 256177692Smarcel struct g_part_pc98_table *table; 257177692Smarcel 258177692Smarcel pp = gpp->gpp_provider; 259218845Snyan if (pp->sectorsize < SECSIZE || pp->mediasize < BOOTSIZE) 260177692Smarcel return (ENOSPC); 261177692Smarcel if (pp->sectorsize > SECSIZE) 262177692Smarcel return (ENXIO); 263177692Smarcel 264222281Sae basetable->gpt_first = basetable->gpt_heads * basetable->gpt_sectors; 265222281Sae basetable->gpt_last = MIN(pp->mediasize / SECSIZE, UINT32_MAX) - 1; 266177692Smarcel 267177692Smarcel table = (struct g_part_pc98_table *)basetable; 268254015Smarcel le16enc(table->boot + PC98_MAGICOFS, PC98_MAGIC); 269177692Smarcel return (0); 270177692Smarcel} 271177692Smarcel 272177692Smarcelstatic int 273177692Smarcelg_part_pc98_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 274177692Smarcel{ 275177692Smarcel 276177692Smarcel /* Wipe the first two sectors to clear the partitioning. */ 277177692Smarcel basetable->gpt_smhead |= 3; 278177692Smarcel return (0); 279177692Smarcel} 280177692Smarcel 281188429Simpstatic void 282178444Smarcelg_part_pc98_dumpconf(struct g_part_table *table, 283178444Smarcel struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) 284178444Smarcel{ 285178444Smarcel struct g_part_pc98_entry *entry; 286183420Smarcel char name[sizeof(entry->ent.dp_name) + 1]; 287178444Smarcel u_int type; 288178444Smarcel 289178444Smarcel entry = (struct g_part_pc98_entry *)baseentry; 290183420Smarcel if (entry == NULL) { 291183420Smarcel /* confxml: scheme information */ 292189616Snyan return; 293183420Smarcel } 294183420Smarcel 295183420Smarcel type = entry->ent.dp_mid + (entry->ent.dp_sid << 8); 296183420Smarcel strncpy(name, entry->ent.dp_name, sizeof(name) - 1); 297183420Smarcel name[sizeof(name) - 1] = '\0'; 298179755Smarcel if (indent == NULL) { 299179755Smarcel /* conftxt: libdisk compatibility */ 300183420Smarcel sbuf_printf(sb, " xs PC98 xt %u sn %s", type, name); 301183420Smarcel } else { 302179755Smarcel /* confxml: partition entry information */ 303267156Sae sbuf_printf(sb, "%s<label>", indent); 304267156Sae g_conf_printf_escaped(sb, "%s", name); 305267156Sae sbuf_printf(sb, "</label>\n"); 306184069Smarcel if (entry->ent.dp_mid & PC98_MID_BOOTABLE) 307184069Smarcel sbuf_printf(sb, "%s<attrib>bootable</attrib>\n", 308184069Smarcel indent); 309184069Smarcel if (entry->ent.dp_sid & PC98_SID_ACTIVE) 310184069Smarcel sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent); 311184069Smarcel sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 312184069Smarcel type & 0x7f7f); 313179755Smarcel } 314178444Smarcel} 315178444Smarcel 316178444Smarcelstatic int 317177692Smarcelg_part_pc98_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 318177692Smarcel{ 319177692Smarcel struct g_part_pc98_entry *entry; 320177692Smarcel 321177692Smarcel /* Allow dumping to a FreeBSD partition only. */ 322177692Smarcel entry = (struct g_part_pc98_entry *)baseentry; 323184069Smarcel return (((entry->ent.dp_mid & PC98_MID_MASK) == PC98_MID_386BSD && 324184069Smarcel (entry->ent.dp_sid & PC98_SID_MASK) == PC98_SID_386BSD) ? 1 : 0); 325177692Smarcel} 326177692Smarcel 327177692Smarcelstatic int 328177692Smarcelg_part_pc98_modify(struct g_part_table *basetable, 329177692Smarcel struct g_part_entry *baseentry, struct g_part_parms *gpp) 330177692Smarcel{ 331177692Smarcel struct g_part_pc98_entry *entry; 332218845Snyan int error; 333177692Smarcel 334218845Snyan entry = (struct g_part_pc98_entry *)baseentry; 335218845Snyan 336218845Snyan if (gpp->gpp_parms & G_PART_PARM_TYPE) { 337218845Snyan error = pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid, 338218845Snyan &entry->ent.dp_sid); 339218845Snyan if (error) 340218845Snyan return (error); 341218845Snyan } 342218845Snyan 343177692Smarcel if (gpp->gpp_parms & G_PART_PARM_LABEL) 344218845Snyan return (pc98_set_slicename(gpp->gpp_label, entry->ent.dp_name)); 345177692Smarcel 346177692Smarcel return (0); 347177692Smarcel} 348177692Smarcel 349207094Smarcelstatic int 350207094Smarcelg_part_pc98_resize(struct g_part_table *basetable, 351207094Smarcel struct g_part_entry *baseentry, struct g_part_parms *gpp) 352207094Smarcel{ 353207094Smarcel struct g_part_pc98_entry *entry; 354265910Sae struct g_provider *pp; 355265910Sae uint32_t size; 356207094Smarcel 357265912Sae if (baseentry == NULL) { 358265912Sae pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 359265912Sae basetable->gpt_last = MIN(pp->mediasize / SECSIZE, 360265912Sae UINT32_MAX) - 1; 361265912Sae return (0); 362265912Sae } 363207094Smarcel size = gpp->gpp_size; 364265910Sae if (pc98_align(basetable, NULL, &size) != 0) 365207094Smarcel return (EINVAL); 366265910Sae /* XXX: prevent unexpected shrinking. */ 367265910Sae pp = baseentry->gpe_pp; 368265910Sae if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && 369265910Sae pp->mediasize / pp->sectorsize > size) 370265910Sae return (EBUSY); 371207094Smarcel entry = (struct g_part_pc98_entry *)baseentry; 372207094Smarcel baseentry->gpe_end = baseentry->gpe_start + size - 1; 373207094Smarcel pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 374207094Smarcel &entry->ent.dp_ehd, &entry->ent.dp_esect); 375207094Smarcel 376207094Smarcel return (0); 377207094Smarcel} 378207094Smarcel 379188429Simpstatic const char * 380177692Smarcelg_part_pc98_name(struct g_part_table *table, struct g_part_entry *baseentry, 381177692Smarcel char *buf, size_t bufsz) 382177692Smarcel{ 383177692Smarcel 384177692Smarcel snprintf(buf, bufsz, "s%d", baseentry->gpe_index); 385177692Smarcel return (buf); 386177692Smarcel} 387177692Smarcel 388177692Smarcelstatic int 389177692Smarcelg_part_pc98_probe(struct g_part_table *table, struct g_consumer *cp) 390177692Smarcel{ 391177692Smarcel struct g_provider *pp; 392177692Smarcel u_char *buf, *p; 393177692Smarcel int error, index, res, sum; 394186733Smarcel uint16_t magic, ecyl, scyl; 395177692Smarcel 396177692Smarcel pp = cp->provider; 397177692Smarcel 398177692Smarcel /* Sanity-check the provider. */ 399218558Snyan if (pp->sectorsize < SECSIZE || pp->mediasize < BOOTSIZE) 400177692Smarcel return (ENOSPC); 401177692Smarcel if (pp->sectorsize > SECSIZE) 402177692Smarcel return (ENXIO); 403177692Smarcel 404177692Smarcel /* Check that there's a PC98 partition table. */ 405177692Smarcel buf = g_read_data(cp, 0L, 2 * SECSIZE, &error); 406177692Smarcel if (buf == NULL) 407177692Smarcel return (error); 408177692Smarcel 409177692Smarcel /* We goto out on mismatch. */ 410177692Smarcel res = ENXIO; 411177692Smarcel 412254015Smarcel magic = le16dec(buf + PC98_MAGICOFS); 413254015Smarcel if (magic != PC98_MAGIC) 414177692Smarcel goto out; 415177692Smarcel 416177692Smarcel sum = 0; 417177692Smarcel for (index = SECSIZE; index < 2 * SECSIZE; index++) 418177692Smarcel sum += buf[index]; 419177692Smarcel if (sum == 0) { 420177692Smarcel res = G_PART_PROBE_PRI_LOW; 421177692Smarcel goto out; 422177692Smarcel } 423177692Smarcel 424254015Smarcel for (index = 0; index < PC98_NPARTS; index++) { 425254015Smarcel p = buf + SECSIZE + index * PC98_PARTSIZE; 426186733Smarcel if (p[0] == 0 || p[1] == 0) /* !dp_mid || !dp_sid */ 427177692Smarcel continue; 428186733Smarcel scyl = le16dec(p + 10); 429186733Smarcel ecyl = le16dec(p + 14); 430186733Smarcel if (scyl == 0 || ecyl == 0) 431177692Smarcel goto out; 432186733Smarcel if (p[8] == p[12] && /* dp_ssect == dp_esect */ 433186733Smarcel p[9] == p[13] && /* dp_shd == dp_ehd */ 434186733Smarcel scyl == ecyl) 435186733Smarcel goto out; 436177692Smarcel } 437177692Smarcel 438177692Smarcel res = G_PART_PROBE_PRI_HIGH; 439177692Smarcel 440177692Smarcel out: 441177692Smarcel g_free(buf); 442177692Smarcel return (res); 443177692Smarcel} 444177692Smarcel 445177692Smarcelstatic int 446177692Smarcelg_part_pc98_read(struct g_part_table *basetable, struct g_consumer *cp) 447177692Smarcel{ 448177692Smarcel struct pc98_partition ent; 449177692Smarcel struct g_provider *pp; 450177692Smarcel struct g_part_pc98_table *table; 451177692Smarcel struct g_part_pc98_entry *entry; 452177692Smarcel u_char *buf, *p; 453177692Smarcel off_t msize; 454177692Smarcel off_t start, end; 455177692Smarcel u_int cyl; 456177692Smarcel int error, index; 457177692Smarcel 458177692Smarcel pp = cp->provider; 459177692Smarcel table = (struct g_part_pc98_table *)basetable; 460221647Sae msize = MIN(pp->mediasize / SECSIZE, UINT32_MAX); 461177692Smarcel 462218558Snyan buf = g_read_data(cp, 0L, BOOTSIZE, &error); 463177692Smarcel if (buf == NULL) 464177692Smarcel return (error); 465177692Smarcel 466177692Smarcel cyl = basetable->gpt_heads * basetable->gpt_sectors; 467177692Smarcel 468177692Smarcel bcopy(buf, table->boot, sizeof(table->boot)); 469177692Smarcel bcopy(buf + SECSIZE, table->table, sizeof(table->table)); 470218558Snyan bcopy(buf + SECSIZE*2, table->menu, sizeof(table->menu)); 471177692Smarcel 472254015Smarcel for (index = PC98_NPARTS - 1; index >= 0; index--) { 473254015Smarcel p = buf + SECSIZE + index * PC98_PARTSIZE; 474177692Smarcel ent.dp_mid = p[0]; 475177692Smarcel ent.dp_sid = p[1]; 476177692Smarcel ent.dp_dum1 = p[2]; 477177692Smarcel ent.dp_dum2 = p[3]; 478177692Smarcel ent.dp_ipl_sct = p[4]; 479177692Smarcel ent.dp_ipl_head = p[5]; 480177692Smarcel ent.dp_ipl_cyl = le16dec(p + 6); 481177692Smarcel ent.dp_ssect = p[8]; 482177692Smarcel ent.dp_shd = p[9]; 483177692Smarcel ent.dp_scyl = le16dec(p + 10); 484177692Smarcel ent.dp_esect = p[12]; 485177692Smarcel ent.dp_ehd = p[13]; 486177692Smarcel ent.dp_ecyl = le16dec(p + 14); 487177692Smarcel bcopy(p + 16, ent.dp_name, sizeof(ent.dp_name)); 488177692Smarcel if (ent.dp_sid == 0) 489177692Smarcel continue; 490177692Smarcel 491177692Smarcel start = ent.dp_scyl * cyl; 492177692Smarcel end = (ent.dp_ecyl + 1) * cyl - 1; 493177692Smarcel entry = (struct g_part_pc98_entry *)g_part_new_entry(basetable, 494177692Smarcel index + 1, start, end); 495177692Smarcel entry->ent = ent; 496177692Smarcel } 497177692Smarcel 498254015Smarcel basetable->gpt_entries = PC98_NPARTS; 499177692Smarcel basetable->gpt_first = cyl; 500222281Sae basetable->gpt_last = msize - 1; 501177692Smarcel 502213174Sae g_free(buf); 503177692Smarcel return (0); 504177692Smarcel} 505177692Smarcel 506184069Smarcelstatic int 507184069Smarcelg_part_pc98_setunset(struct g_part_table *table, struct g_part_entry *baseentry, 508184069Smarcel const char *attrib, unsigned int set) 509184069Smarcel{ 510184069Smarcel struct g_part_entry *iter; 511184069Smarcel struct g_part_pc98_entry *entry; 512184069Smarcel int changed, mid, sid; 513184069Smarcel 514251588Smarcel if (baseentry == NULL) 515251588Smarcel return (ENODEV); 516251588Smarcel 517184069Smarcel mid = sid = 0; 518184069Smarcel if (strcasecmp(attrib, "active") == 0) 519184069Smarcel sid = 1; 520184069Smarcel else if (strcasecmp(attrib, "bootable") == 0) 521184069Smarcel mid = 1; 522184069Smarcel if (mid == 0 && sid == 0) 523184069Smarcel return (EINVAL); 524184069Smarcel 525184069Smarcel LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { 526184069Smarcel if (iter->gpe_deleted) 527184069Smarcel continue; 528184069Smarcel if (iter != baseentry) 529184069Smarcel continue; 530184069Smarcel changed = 0; 531184069Smarcel entry = (struct g_part_pc98_entry *)iter; 532184069Smarcel if (set) { 533184069Smarcel if (mid && !(entry->ent.dp_mid & PC98_MID_BOOTABLE)) { 534184069Smarcel entry->ent.dp_mid |= PC98_MID_BOOTABLE; 535184069Smarcel changed = 1; 536184069Smarcel } 537184069Smarcel if (sid && !(entry->ent.dp_sid & PC98_SID_ACTIVE)) { 538184069Smarcel entry->ent.dp_sid |= PC98_SID_ACTIVE; 539184069Smarcel changed = 1; 540184069Smarcel } 541184069Smarcel } else { 542184069Smarcel if (mid && (entry->ent.dp_mid & PC98_MID_BOOTABLE)) { 543184069Smarcel entry->ent.dp_mid &= ~PC98_MID_BOOTABLE; 544184069Smarcel changed = 1; 545184069Smarcel } 546184069Smarcel if (sid && (entry->ent.dp_sid & PC98_SID_ACTIVE)) { 547184069Smarcel entry->ent.dp_sid &= ~PC98_SID_ACTIVE; 548184069Smarcel changed = 1; 549184069Smarcel } 550184069Smarcel } 551184069Smarcel if (changed && !iter->gpe_created) 552184069Smarcel iter->gpe_modified = 1; 553184069Smarcel } 554184069Smarcel return (0); 555184069Smarcel} 556184069Smarcel 557177692Smarcelstatic const char * 558177692Smarcelg_part_pc98_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 559177692Smarcel char *buf, size_t bufsz) 560177692Smarcel{ 561177692Smarcel struct g_part_pc98_entry *entry; 562177692Smarcel u_int type; 563177692Smarcel 564177692Smarcel entry = (struct g_part_pc98_entry *)baseentry; 565184069Smarcel type = (entry->ent.dp_mid & PC98_MID_MASK) | 566184069Smarcel ((entry->ent.dp_sid & PC98_SID_MASK) << 8); 567184069Smarcel if (type == (PC98_MID_386BSD | (PC98_SID_386BSD << 8))) 568177692Smarcel return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); 569177692Smarcel snprintf(buf, bufsz, "!%d", type); 570177692Smarcel return (buf); 571177692Smarcel} 572177692Smarcel 573177692Smarcelstatic int 574177692Smarcelg_part_pc98_write(struct g_part_table *basetable, struct g_consumer *cp) 575177692Smarcel{ 576177692Smarcel struct g_part_entry *baseentry; 577177692Smarcel struct g_part_pc98_entry *entry; 578177692Smarcel struct g_part_pc98_table *table; 579177692Smarcel u_char *p; 580177692Smarcel int error, index; 581177692Smarcel 582177692Smarcel table = (struct g_part_pc98_table *)basetable; 583177692Smarcel baseentry = LIST_FIRST(&basetable->gpt_entry); 584177692Smarcel for (index = 1; index <= basetable->gpt_entries; index++) { 585254015Smarcel p = table->table + (index - 1) * PC98_PARTSIZE; 586177692Smarcel entry = (baseentry != NULL && index == baseentry->gpe_index) 587177692Smarcel ? (struct g_part_pc98_entry *)baseentry : NULL; 588177692Smarcel if (entry != NULL && !baseentry->gpe_deleted) { 589177692Smarcel p[0] = entry->ent.dp_mid; 590177692Smarcel p[1] = entry->ent.dp_sid; 591177692Smarcel p[2] = entry->ent.dp_dum1; 592177692Smarcel p[3] = entry->ent.dp_dum2; 593177692Smarcel p[4] = entry->ent.dp_ipl_sct; 594177692Smarcel p[5] = entry->ent.dp_ipl_head; 595177692Smarcel le16enc(p + 6, entry->ent.dp_ipl_cyl); 596177692Smarcel p[8] = entry->ent.dp_ssect; 597177692Smarcel p[9] = entry->ent.dp_shd; 598177692Smarcel le16enc(p + 10, entry->ent.dp_scyl); 599177692Smarcel p[12] = entry->ent.dp_esect; 600177692Smarcel p[13] = entry->ent.dp_ehd; 601177692Smarcel le16enc(p + 14, entry->ent.dp_ecyl); 602177692Smarcel bcopy(entry->ent.dp_name, p + 16, 603177692Smarcel sizeof(entry->ent.dp_name)); 604177692Smarcel } else 605254015Smarcel bzero(p, PC98_PARTSIZE); 606177692Smarcel 607177692Smarcel if (entry != NULL) 608177692Smarcel baseentry = LIST_NEXT(baseentry, gpe_entry); 609177692Smarcel } 610177692Smarcel 611177692Smarcel error = g_write_data(cp, 0, table->boot, SECSIZE); 612177692Smarcel if (!error) 613177692Smarcel error = g_write_data(cp, SECSIZE, table->table, SECSIZE); 614218558Snyan if (!error) 615218558Snyan error = g_write_data(cp, SECSIZE*2, table->menu, MENUSIZE); 616177692Smarcel return (error); 617177692Smarcel} 618