g_part_pc98.c revision 267156
1/*- 2 * Copyright (c) 2008 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/10/sys/geom/part/g_part_pc98.c 267156 2014-06-06 12:37:56Z ae $"); 29 30#include <sys/param.h> 31#include <sys/bio.h> 32#include <sys/diskpc98.h> 33#include <sys/endian.h> 34#include <sys/kernel.h> 35#include <sys/kobj.h> 36#include <sys/limits.h> 37#include <sys/lock.h> 38#include <sys/malloc.h> 39#include <sys/mutex.h> 40#include <sys/queue.h> 41#include <sys/sbuf.h> 42#include <sys/systm.h> 43#include <sys/sysctl.h> 44#include <geom/geom.h> 45#include <geom/geom_int.h> 46#include <geom/part/g_part.h> 47 48#include "g_part_if.h" 49 50FEATURE(geom_part_pc98, "GEOM partitioning class for PC-9800 disk partitions"); 51 52#define SECSIZE 512 53#define MENUSIZE 7168 54#define BOOTSIZE 8192 55 56struct g_part_pc98_table { 57 struct g_part_table base; 58 u_char boot[SECSIZE]; 59 u_char table[SECSIZE]; 60 u_char menu[MENUSIZE]; 61}; 62 63struct g_part_pc98_entry { 64 struct g_part_entry base; 65 struct pc98_partition ent; 66}; 67 68static int g_part_pc98_add(struct g_part_table *, struct g_part_entry *, 69 struct g_part_parms *); 70static int g_part_pc98_bootcode(struct g_part_table *, struct g_part_parms *); 71static int g_part_pc98_create(struct g_part_table *, struct g_part_parms *); 72static int g_part_pc98_destroy(struct g_part_table *, struct g_part_parms *); 73static void g_part_pc98_dumpconf(struct g_part_table *, struct g_part_entry *, 74 struct sbuf *, const char *); 75static int g_part_pc98_dumpto(struct g_part_table *, struct g_part_entry *); 76static int g_part_pc98_modify(struct g_part_table *, struct g_part_entry *, 77 struct g_part_parms *); 78static const char *g_part_pc98_name(struct g_part_table *, struct g_part_entry *, 79 char *, size_t); 80static int g_part_pc98_probe(struct g_part_table *, struct g_consumer *); 81static int g_part_pc98_read(struct g_part_table *, struct g_consumer *); 82static int g_part_pc98_setunset(struct g_part_table *, struct g_part_entry *, 83 const char *, unsigned int); 84static const char *g_part_pc98_type(struct g_part_table *, 85 struct g_part_entry *, char *, size_t); 86static int g_part_pc98_write(struct g_part_table *, struct g_consumer *); 87static int g_part_pc98_resize(struct g_part_table *, struct g_part_entry *, 88 struct g_part_parms *); 89 90static kobj_method_t g_part_pc98_methods[] = { 91 KOBJMETHOD(g_part_add, g_part_pc98_add), 92 KOBJMETHOD(g_part_bootcode, g_part_pc98_bootcode), 93 KOBJMETHOD(g_part_create, g_part_pc98_create), 94 KOBJMETHOD(g_part_destroy, g_part_pc98_destroy), 95 KOBJMETHOD(g_part_dumpconf, g_part_pc98_dumpconf), 96 KOBJMETHOD(g_part_dumpto, g_part_pc98_dumpto), 97 KOBJMETHOD(g_part_modify, g_part_pc98_modify), 98 KOBJMETHOD(g_part_resize, g_part_pc98_resize), 99 KOBJMETHOD(g_part_name, g_part_pc98_name), 100 KOBJMETHOD(g_part_probe, g_part_pc98_probe), 101 KOBJMETHOD(g_part_read, g_part_pc98_read), 102 KOBJMETHOD(g_part_setunset, g_part_pc98_setunset), 103 KOBJMETHOD(g_part_type, g_part_pc98_type), 104 KOBJMETHOD(g_part_write, g_part_pc98_write), 105 { 0, 0 } 106}; 107 108static struct g_part_scheme g_part_pc98_scheme = { 109 "PC98", 110 g_part_pc98_methods, 111 sizeof(struct g_part_pc98_table), 112 .gps_entrysz = sizeof(struct g_part_pc98_entry), 113 .gps_minent = PC98_NPARTS, 114 .gps_maxent = PC98_NPARTS, 115 .gps_bootcodesz = BOOTSIZE, 116}; 117G_PART_SCHEME_DECLARE(g_part_pc98); 118 119static int 120pc98_parse_type(const char *type, u_char *dp_mid, u_char *dp_sid) 121{ 122 const char *alias; 123 char *endp; 124 long lt; 125 126 if (type[0] == '!') { 127 lt = strtol(type + 1, &endp, 0); 128 if (type[1] == '\0' || *endp != '\0' || lt <= 0 || 129 lt >= 65536) 130 return (EINVAL); 131 /* Make sure the active and bootable flags aren't set. */ 132 if (lt & ((PC98_SID_ACTIVE << 8) | PC98_MID_BOOTABLE)) 133 return (ENOATTR); 134 *dp_mid = (*dp_mid & PC98_MID_BOOTABLE) | (u_char)lt; 135 *dp_sid = (*dp_sid & PC98_SID_ACTIVE) | (u_char)(lt >> 8); 136 return (0); 137 } 138 alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); 139 if (!strcasecmp(type, alias)) { 140 *dp_mid = (*dp_mid & PC98_MID_BOOTABLE) | PC98_MID_386BSD; 141 *dp_sid = (*dp_sid & PC98_SID_ACTIVE) | PC98_SID_386BSD; 142 return (0); 143 } 144 return (EINVAL); 145} 146 147static int 148pc98_set_slicename(const char *label, u_char *dp_name) 149{ 150 int len; 151 152 len = strlen(label); 153 if (len > sizeof(((struct pc98_partition *)NULL)->dp_name)) 154 return (EINVAL); 155 bzero(dp_name, sizeof(((struct pc98_partition *)NULL)->dp_name)); 156 strncpy(dp_name, label, len); 157 158 return (0); 159} 160 161static void 162pc98_set_chs(struct g_part_table *table, uint32_t lba, u_short *cylp, 163 u_char *hdp, u_char *secp) 164{ 165 uint32_t cyl, hd, sec; 166 167 sec = lba % table->gpt_sectors + 1; 168 lba /= table->gpt_sectors; 169 hd = lba % table->gpt_heads; 170 lba /= table->gpt_heads; 171 cyl = lba; 172 173 *cylp = htole16(cyl); 174 *hdp = hd; 175 *secp = sec; 176} 177 178static int 179pc98_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) 180{ 181 uint32_t cyl; 182 183 cyl = basetable->gpt_heads * basetable->gpt_sectors; 184 if (*size < cyl) 185 return (EINVAL); 186 if (start != NULL && (*start % cyl)) { 187 *size += (*start % cyl) - cyl; 188 *start -= (*start % cyl) - cyl; 189 } 190 if (*size % cyl) 191 *size -= (*size % cyl); 192 if (*size < cyl) 193 return (EINVAL); 194 return (0); 195} 196 197static int 198g_part_pc98_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 199 struct g_part_parms *gpp) 200{ 201 struct g_part_pc98_entry *entry; 202 uint32_t start, size; 203 int error; 204 205 entry = (struct g_part_pc98_entry *)baseentry; 206 start = gpp->gpp_start; 207 size = gpp->gpp_size; 208 if (pc98_align(basetable, &start, &size) != 0) 209 return (EINVAL); 210 if (baseentry->gpe_deleted) 211 bzero(&entry->ent, sizeof(entry->ent)); 212 else 213 entry->ent.dp_mid = entry->ent.dp_sid = 0; 214 215 KASSERT(baseentry->gpe_start <= start, (__func__)); 216 KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); 217 baseentry->gpe_start = start; 218 baseentry->gpe_end = start + size - 1; 219 pc98_set_chs(basetable, baseentry->gpe_start, &entry->ent.dp_scyl, 220 &entry->ent.dp_shd, &entry->ent.dp_ssect); 221 pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 222 &entry->ent.dp_ehd, &entry->ent.dp_esect); 223 224 error = pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid, 225 &entry->ent.dp_sid); 226 if (error) 227 return (error); 228 229 if (gpp->gpp_parms & G_PART_PARM_LABEL) 230 return (pc98_set_slicename(gpp->gpp_label, entry->ent.dp_name)); 231 232 return (0); 233} 234 235static int 236g_part_pc98_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 237{ 238 struct g_part_pc98_table *table; 239 const u_char *codeptr; 240 241 if (gpp->gpp_codesize != BOOTSIZE) 242 return (EINVAL); 243 244 table = (struct g_part_pc98_table *)basetable; 245 codeptr = gpp->gpp_codeptr; 246 bcopy(codeptr, table->boot, SECSIZE); 247 bcopy(codeptr + SECSIZE*2, table->menu, MENUSIZE); 248 249 return (0); 250} 251 252static int 253g_part_pc98_create(struct g_part_table *basetable, struct g_part_parms *gpp) 254{ 255 struct g_provider *pp; 256 struct g_part_pc98_table *table; 257 258 pp = gpp->gpp_provider; 259 if (pp->sectorsize < SECSIZE || pp->mediasize < BOOTSIZE) 260 return (ENOSPC); 261 if (pp->sectorsize > SECSIZE) 262 return (ENXIO); 263 264 basetable->gpt_first = basetable->gpt_heads * basetable->gpt_sectors; 265 basetable->gpt_last = MIN(pp->mediasize / SECSIZE, UINT32_MAX) - 1; 266 267 table = (struct g_part_pc98_table *)basetable; 268 le16enc(table->boot + PC98_MAGICOFS, PC98_MAGIC); 269 return (0); 270} 271 272static int 273g_part_pc98_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 274{ 275 276 /* Wipe the first two sectors to clear the partitioning. */ 277 basetable->gpt_smhead |= 3; 278 return (0); 279} 280 281static void 282g_part_pc98_dumpconf(struct g_part_table *table, 283 struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) 284{ 285 struct g_part_pc98_entry *entry; 286 char name[sizeof(entry->ent.dp_name) + 1]; 287 u_int type; 288 289 entry = (struct g_part_pc98_entry *)baseentry; 290 if (entry == NULL) { 291 /* confxml: scheme information */ 292 return; 293 } 294 295 type = entry->ent.dp_mid + (entry->ent.dp_sid << 8); 296 strncpy(name, entry->ent.dp_name, sizeof(name) - 1); 297 name[sizeof(name) - 1] = '\0'; 298 if (indent == NULL) { 299 /* conftxt: libdisk compatibility */ 300 sbuf_printf(sb, " xs PC98 xt %u sn %s", type, name); 301 } else { 302 /* confxml: partition entry information */ 303 sbuf_printf(sb, "%s<label>", indent); 304 g_conf_printf_escaped(sb, "%s", name); 305 sbuf_printf(sb, "</label>\n"); 306 if (entry->ent.dp_mid & PC98_MID_BOOTABLE) 307 sbuf_printf(sb, "%s<attrib>bootable</attrib>\n", 308 indent); 309 if (entry->ent.dp_sid & PC98_SID_ACTIVE) 310 sbuf_printf(sb, "%s<attrib>active</attrib>\n", indent); 311 sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 312 type & 0x7f7f); 313 } 314} 315 316static int 317g_part_pc98_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 318{ 319 struct g_part_pc98_entry *entry; 320 321 /* Allow dumping to a FreeBSD partition only. */ 322 entry = (struct g_part_pc98_entry *)baseentry; 323 return (((entry->ent.dp_mid & PC98_MID_MASK) == PC98_MID_386BSD && 324 (entry->ent.dp_sid & PC98_SID_MASK) == PC98_SID_386BSD) ? 1 : 0); 325} 326 327static int 328g_part_pc98_modify(struct g_part_table *basetable, 329 struct g_part_entry *baseentry, struct g_part_parms *gpp) 330{ 331 struct g_part_pc98_entry *entry; 332 int error; 333 334 entry = (struct g_part_pc98_entry *)baseentry; 335 336 if (gpp->gpp_parms & G_PART_PARM_TYPE) { 337 error = pc98_parse_type(gpp->gpp_type, &entry->ent.dp_mid, 338 &entry->ent.dp_sid); 339 if (error) 340 return (error); 341 } 342 343 if (gpp->gpp_parms & G_PART_PARM_LABEL) 344 return (pc98_set_slicename(gpp->gpp_label, entry->ent.dp_name)); 345 346 return (0); 347} 348 349static int 350g_part_pc98_resize(struct g_part_table *basetable, 351 struct g_part_entry *baseentry, struct g_part_parms *gpp) 352{ 353 struct g_part_pc98_entry *entry; 354 struct g_provider *pp; 355 uint32_t size; 356 357 if (baseentry == NULL) { 358 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 359 basetable->gpt_last = MIN(pp->mediasize / SECSIZE, 360 UINT32_MAX) - 1; 361 return (0); 362 } 363 size = gpp->gpp_size; 364 if (pc98_align(basetable, NULL, &size) != 0) 365 return (EINVAL); 366 /* XXX: prevent unexpected shrinking. */ 367 pp = baseentry->gpe_pp; 368 if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && 369 pp->mediasize / pp->sectorsize > size) 370 return (EBUSY); 371 entry = (struct g_part_pc98_entry *)baseentry; 372 baseentry->gpe_end = baseentry->gpe_start + size - 1; 373 pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, 374 &entry->ent.dp_ehd, &entry->ent.dp_esect); 375 376 return (0); 377} 378 379static const char * 380g_part_pc98_name(struct g_part_table *table, struct g_part_entry *baseentry, 381 char *buf, size_t bufsz) 382{ 383 384 snprintf(buf, bufsz, "s%d", baseentry->gpe_index); 385 return (buf); 386} 387 388static int 389g_part_pc98_probe(struct g_part_table *table, struct g_consumer *cp) 390{ 391 struct g_provider *pp; 392 u_char *buf, *p; 393 int error, index, res, sum; 394 uint16_t magic, ecyl, scyl; 395 396 pp = cp->provider; 397 398 /* Sanity-check the provider. */ 399 if (pp->sectorsize < SECSIZE || pp->mediasize < BOOTSIZE) 400 return (ENOSPC); 401 if (pp->sectorsize > SECSIZE) 402 return (ENXIO); 403 404 /* Check that there's a PC98 partition table. */ 405 buf = g_read_data(cp, 0L, 2 * SECSIZE, &error); 406 if (buf == NULL) 407 return (error); 408 409 /* We goto out on mismatch. */ 410 res = ENXIO; 411 412 magic = le16dec(buf + PC98_MAGICOFS); 413 if (magic != PC98_MAGIC) 414 goto out; 415 416 sum = 0; 417 for (index = SECSIZE; index < 2 * SECSIZE; index++) 418 sum += buf[index]; 419 if (sum == 0) { 420 res = G_PART_PROBE_PRI_LOW; 421 goto out; 422 } 423 424 for (index = 0; index < PC98_NPARTS; index++) { 425 p = buf + SECSIZE + index * PC98_PARTSIZE; 426 if (p[0] == 0 || p[1] == 0) /* !dp_mid || !dp_sid */ 427 continue; 428 scyl = le16dec(p + 10); 429 ecyl = le16dec(p + 14); 430 if (scyl == 0 || ecyl == 0) 431 goto out; 432 if (p[8] == p[12] && /* dp_ssect == dp_esect */ 433 p[9] == p[13] && /* dp_shd == dp_ehd */ 434 scyl == ecyl) 435 goto out; 436 } 437 438 res = G_PART_PROBE_PRI_HIGH; 439 440 out: 441 g_free(buf); 442 return (res); 443} 444 445static int 446g_part_pc98_read(struct g_part_table *basetable, struct g_consumer *cp) 447{ 448 struct pc98_partition ent; 449 struct g_provider *pp; 450 struct g_part_pc98_table *table; 451 struct g_part_pc98_entry *entry; 452 u_char *buf, *p; 453 off_t msize; 454 off_t start, end; 455 u_int cyl; 456 int error, index; 457 458 pp = cp->provider; 459 table = (struct g_part_pc98_table *)basetable; 460 msize = MIN(pp->mediasize / SECSIZE, UINT32_MAX); 461 462 buf = g_read_data(cp, 0L, BOOTSIZE, &error); 463 if (buf == NULL) 464 return (error); 465 466 cyl = basetable->gpt_heads * basetable->gpt_sectors; 467 468 bcopy(buf, table->boot, sizeof(table->boot)); 469 bcopy(buf + SECSIZE, table->table, sizeof(table->table)); 470 bcopy(buf + SECSIZE*2, table->menu, sizeof(table->menu)); 471 472 for (index = PC98_NPARTS - 1; index >= 0; index--) { 473 p = buf + SECSIZE + index * PC98_PARTSIZE; 474 ent.dp_mid = p[0]; 475 ent.dp_sid = p[1]; 476 ent.dp_dum1 = p[2]; 477 ent.dp_dum2 = p[3]; 478 ent.dp_ipl_sct = p[4]; 479 ent.dp_ipl_head = p[5]; 480 ent.dp_ipl_cyl = le16dec(p + 6); 481 ent.dp_ssect = p[8]; 482 ent.dp_shd = p[9]; 483 ent.dp_scyl = le16dec(p + 10); 484 ent.dp_esect = p[12]; 485 ent.dp_ehd = p[13]; 486 ent.dp_ecyl = le16dec(p + 14); 487 bcopy(p + 16, ent.dp_name, sizeof(ent.dp_name)); 488 if (ent.dp_sid == 0) 489 continue; 490 491 start = ent.dp_scyl * cyl; 492 end = (ent.dp_ecyl + 1) * cyl - 1; 493 entry = (struct g_part_pc98_entry *)g_part_new_entry(basetable, 494 index + 1, start, end); 495 entry->ent = ent; 496 } 497 498 basetable->gpt_entries = PC98_NPARTS; 499 basetable->gpt_first = cyl; 500 basetable->gpt_last = msize - 1; 501 502 g_free(buf); 503 return (0); 504} 505 506static int 507g_part_pc98_setunset(struct g_part_table *table, struct g_part_entry *baseentry, 508 const char *attrib, unsigned int set) 509{ 510 struct g_part_entry *iter; 511 struct g_part_pc98_entry *entry; 512 int changed, mid, sid; 513 514 if (baseentry == NULL) 515 return (ENODEV); 516 517 mid = sid = 0; 518 if (strcasecmp(attrib, "active") == 0) 519 sid = 1; 520 else if (strcasecmp(attrib, "bootable") == 0) 521 mid = 1; 522 if (mid == 0 && sid == 0) 523 return (EINVAL); 524 525 LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { 526 if (iter->gpe_deleted) 527 continue; 528 if (iter != baseentry) 529 continue; 530 changed = 0; 531 entry = (struct g_part_pc98_entry *)iter; 532 if (set) { 533 if (mid && !(entry->ent.dp_mid & PC98_MID_BOOTABLE)) { 534 entry->ent.dp_mid |= PC98_MID_BOOTABLE; 535 changed = 1; 536 } 537 if (sid && !(entry->ent.dp_sid & PC98_SID_ACTIVE)) { 538 entry->ent.dp_sid |= PC98_SID_ACTIVE; 539 changed = 1; 540 } 541 } else { 542 if (mid && (entry->ent.dp_mid & PC98_MID_BOOTABLE)) { 543 entry->ent.dp_mid &= ~PC98_MID_BOOTABLE; 544 changed = 1; 545 } 546 if (sid && (entry->ent.dp_sid & PC98_SID_ACTIVE)) { 547 entry->ent.dp_sid &= ~PC98_SID_ACTIVE; 548 changed = 1; 549 } 550 } 551 if (changed && !iter->gpe_created) 552 iter->gpe_modified = 1; 553 } 554 return (0); 555} 556 557static const char * 558g_part_pc98_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 559 char *buf, size_t bufsz) 560{ 561 struct g_part_pc98_entry *entry; 562 u_int type; 563 564 entry = (struct g_part_pc98_entry *)baseentry; 565 type = (entry->ent.dp_mid & PC98_MID_MASK) | 566 ((entry->ent.dp_sid & PC98_SID_MASK) << 8); 567 if (type == (PC98_MID_386BSD | (PC98_SID_386BSD << 8))) 568 return (g_part_alias_name(G_PART_ALIAS_FREEBSD)); 569 snprintf(buf, bufsz, "!%d", type); 570 return (buf); 571} 572 573static int 574g_part_pc98_write(struct g_part_table *basetable, struct g_consumer *cp) 575{ 576 struct g_part_entry *baseentry; 577 struct g_part_pc98_entry *entry; 578 struct g_part_pc98_table *table; 579 u_char *p; 580 int error, index; 581 582 table = (struct g_part_pc98_table *)basetable; 583 baseentry = LIST_FIRST(&basetable->gpt_entry); 584 for (index = 1; index <= basetable->gpt_entries; index++) { 585 p = table->table + (index - 1) * PC98_PARTSIZE; 586 entry = (baseentry != NULL && index == baseentry->gpe_index) 587 ? (struct g_part_pc98_entry *)baseentry : NULL; 588 if (entry != NULL && !baseentry->gpe_deleted) { 589 p[0] = entry->ent.dp_mid; 590 p[1] = entry->ent.dp_sid; 591 p[2] = entry->ent.dp_dum1; 592 p[3] = entry->ent.dp_dum2; 593 p[4] = entry->ent.dp_ipl_sct; 594 p[5] = entry->ent.dp_ipl_head; 595 le16enc(p + 6, entry->ent.dp_ipl_cyl); 596 p[8] = entry->ent.dp_ssect; 597 p[9] = entry->ent.dp_shd; 598 le16enc(p + 10, entry->ent.dp_scyl); 599 p[12] = entry->ent.dp_esect; 600 p[13] = entry->ent.dp_ehd; 601 le16enc(p + 14, entry->ent.dp_ecyl); 602 bcopy(entry->ent.dp_name, p + 16, 603 sizeof(entry->ent.dp_name)); 604 } else 605 bzero(p, PC98_PARTSIZE); 606 607 if (entry != NULL) 608 baseentry = LIST_NEXT(baseentry, gpe_entry); 609 } 610 611 error = g_write_data(cp, 0, table->boot, SECSIZE); 612 if (!error) 613 error = g_write_data(cp, SECSIZE, table->table, SECSIZE); 614 if (!error) 615 error = g_write_data(cp, SECSIZE*2, table->menu, MENUSIZE); 616 return (error); 617} 618