1 /* $NetBSD: biosdisk.c,v 1.37 2011/01/26 20:59:48 jakllsch Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1998 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 /* 30 * raw BIOS disk device for libsa. 31 * needs lowlevel parts from bios_disk.S and biosdisk_ll.c 32 * partly from netbsd:sys/arch/i386/boot/disk.c 33 * no bad144 handling! 34 * 35 * A lot of this must match sys/kern/subr_disk_mbr.c 36 */ 37 38 /* 39 * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 40 * 41 * Mach Operating System 42 * Copyright (c) 1992, 1991 Carnegie Mellon University 43 * All Rights Reserved. 44 * 45 * Permission to use, copy, modify and distribute this software and its 46 * documentation is hereby granted, provided that both the copyright 47 * notice and this permission notice appear in all copies of the 48 * software, derivative works or modified versions, and any portions 49 * thereof, and that both notices appear in supporting documentation. 50 * 51 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 52 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 53 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 54 * 55 * Carnegie Mellon requests users of this software to return to 56 * 57 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 58 * School of Computer Science 59 * Carnegie Mellon University 60 * Pittsburgh PA 15213-3890 61 * 62 * any improvements or extensions that they make and grant Carnegie Mellon 63 * the rights to redistribute these changes. 64 */ 65 66 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 67 #define FSTYPENAMES 68 #endif 69 70 #include <lib/libkern/libkern.h> 71 #include <lib/libsa/stand.h> 72 73 #include <sys/types.h> 74 #include <sys/md5.h> 75 #include <sys/param.h> 76 #include <sys/disklabel.h> 77 #include <sys/disklabel_gpt.h> 78 #include <sys/uuid.h> 79 80 #include <fs/cd9660/iso.h> 81 82 #include <lib/libsa/saerrno.h> 83 #include <machine/stdarg.h> 84 #include <machine/cpu.h> 85 86 #include "libi386.h" 87 #include "biosdisk_ll.h" 88 #include "biosdisk.h" 89 #ifdef _STANDALONE 90 #include "bootinfo.h" 91 #endif 92 93 #define BUFSIZE 2048 /* must be large enough for a CD sector */ 94 95 #define BIOSDISKNPART 26 96 97 struct biosdisk { 98 struct biosdisk_ll ll; 99 daddr_t boff; 100 char buf[BUFSIZE]; 101 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 102 struct { 103 daddr_t offset; 104 daddr_t size; 105 int fstype; 106 } part[BIOSDISKNPART]; 107 #endif 108 }; 109 110 #ifndef NO_GPT 111 const struct uuid GET_nbsd_raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME; 112 const struct uuid GET_nbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS; 113 const struct uuid GET_nbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS; 114 const struct uuid GET_nbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP; 115 #endif /* NO_GPT */ 116 117 #ifdef _STANDALONE 118 static struct btinfo_bootdisk bi_disk; 119 static struct btinfo_bootwedge bi_wedge; 120 #endif 121 122 #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */ 123 124 int 125 biosdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 126 void *buf, size_t *rsize) 127 { 128 struct biosdisk *d; 129 int blks, frag; 130 131 if (flag != F_READ) 132 return EROFS; 133 134 d = (struct biosdisk *) devdata; 135 136 if (d->ll.type == BIOSDISK_TYPE_CD) 137 dblk = dblk * DEV_BSIZE / ISO_DEFAULT_BLOCK_SIZE; 138 139 dblk += d->boff; 140 141 blks = size / d->ll.secsize; 142 if (blks && readsects(&d->ll, dblk, blks, buf, 0)) { 143 if (rsize) 144 *rsize = 0; 145 return EIO; 146 } 147 148 /* needed for CD */ 149 frag = size % d->ll.secsize; 150 if (frag) { 151 if (readsects(&d->ll, dblk + blks, 1, d->buf, 0)) { 152 if (rsize) 153 *rsize = blks * d->ll.secsize; 154 return EIO; 155 } 156 memcpy(buf + blks * d->ll.secsize, d->buf, frag); 157 } 158 159 if (rsize) 160 *rsize = size; 161 return 0; 162 } 163 164 static struct biosdisk * 165 alloc_biosdisk(int biosdev) 166 { 167 struct biosdisk *d; 168 169 d = alloc(sizeof(*d)); 170 if (d == NULL) 171 return NULL; 172 memset(d, 0, sizeof(*d)); 173 174 d->ll.dev = biosdev; 175 if (set_geometry(&d->ll, NULL)) { 176 #ifdef DISK_DEBUG 177 printf("no geometry information\n"); 178 #endif 179 dealloc(d, sizeof(*d)); 180 return NULL; 181 } 182 return d; 183 } 184 185 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 186 static void 187 md5(void *hash, const void *data, size_t len) 188 { 189 MD5_CTX ctx; 190 191 MD5Init(&ctx); 192 MD5Update(&ctx, data, len); 193 MD5Final(hash, &ctx); 194 195 return; 196 } 197 #endif 198 199 #ifndef NO_GPT 200 static bool 201 guid_is_nil(const struct uuid *u) 202 { 203 static const struct uuid nil = { .time_low = 0 }; 204 return (memcmp(u, &nil, sizeof(*u)) == 0 ? true : false); 205 } 206 207 static bool 208 guid_is_equal(const struct uuid *a, const struct uuid *b) 209 { 210 return (memcmp(a, b, sizeof(*a)) == 0 ? true : false); 211 } 212 213 static int 214 check_gpt(struct biosdisk *d, daddr_t sector) 215 { 216 struct gpt_hdr gpth; 217 const struct gpt_ent *ep; 218 const struct uuid *u; 219 daddr_t entblk; 220 size_t size; 221 uint32_t crc; 222 int sectors; 223 int entries; 224 int entry; 225 int i, j; 226 227 /* read in gpt_hdr sector */ 228 if (readsects(&d->ll, sector, 1, d->buf, 1)) { 229 #ifdef DISK_DEBUG 230 printf("Error reading GPT header at %"PRId64"\n", sector); 231 #endif 232 return EIO; 233 } 234 235 gpth = *(const struct gpt_hdr *)d->buf; 236 237 if (memcmp(GPT_HDR_SIG, gpth.hdr_sig, sizeof(gpth.hdr_sig))) 238 return -1; 239 240 crc = gpth.hdr_crc_self; 241 gpth.hdr_crc_self = 0; 242 gpth.hdr_crc_self = crc32(0, (const void *)&gpth, GPT_HDR_SIZE); 243 if (gpth.hdr_crc_self != crc) { 244 return -1; 245 } 246 247 if (gpth.hdr_lba_self != sector) 248 return -1; 249 250 #ifdef _STANDALONE 251 bi_wedge.matchblk = sector; 252 bi_wedge.matchnblks = 1; 253 254 md5(bi_wedge.matchhash, d->buf, d->ll.secsize); 255 #endif 256 257 sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */ 258 entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */ 259 entblk = gpth.hdr_lba_table; 260 crc = crc32(0, NULL, 0); 261 262 j = 0; 263 ep = (const struct gpt_ent *)d->buf; 264 265 for (entry = 0; entry < gpth.hdr_entries; entry += entries) { 266 size = MIN(sizeof(d->buf), 267 (gpth.hdr_entries - entry) * gpth.hdr_entsz); 268 entries = size / gpth.hdr_entsz; 269 sectors = roundup(size, d->ll.secsize) / d->ll.secsize; 270 if (readsects(&d->ll, entblk, sectors, d->buf, 1)) 271 return -1; 272 entblk += sectors; 273 crc = crc32(crc, (const void *)d->buf, size); 274 275 for (i = 0; j < BIOSDISKNPART && i < entries; i++, j++) { 276 u = (const struct uuid *)ep[i].ent_type; 277 if (!guid_is_nil(u)) { 278 d->part[j].offset = ep[i].ent_lba_start; 279 d->part[j].size = ep[i].ent_lba_end - 280 ep[i].ent_lba_start + 1; 281 if (guid_is_equal(u, &GET_nbsd_ffs)) 282 d->part[j].fstype = FS_BSDFFS; 283 else if (guid_is_equal(u, &GET_nbsd_lfs)) 284 d->part[j].fstype = FS_BSDLFS; 285 else if (guid_is_equal(u, &GET_nbsd_raid)) 286 d->part[j].fstype = FS_RAID; 287 else if (guid_is_equal(u, &GET_nbsd_swap)) 288 d->part[j].fstype = FS_SWAP; 289 else 290 d->part[j].fstype = FS_OTHER; 291 } 292 } 293 294 } 295 296 if (crc != gpth.hdr_crc_table) { 297 #ifdef DISK_DEBUG 298 printf("GPT table CRC invalid\n"); 299 #endif 300 return -1; 301 } 302 303 return 0; 304 } 305 306 static int 307 read_gpt(struct biosdisk *d) 308 { 309 struct biosdisk_extinfo ed; 310 daddr_t gptsector[2]; 311 int i, error; 312 313 if (d->ll.type != BIOSDISK_TYPE_HD) 314 /* No GPT on floppy and CD */ 315 return -1; 316 317 gptsector[0] = GPT_HDR_BLKNO; 318 if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) { 319 gptsector[1] = ed.totsec - 1; 320 d->ll.secsize = ed.sbytes; 321 } else { 322 #ifdef DISK_DEBUG 323 printf("Unable to determine extended disk geometry - " 324 "using CHS\n"); 325 #endif 326 /* at least try some other reasonable values then */ 327 gptsector[1] = d->ll.chs_sectors - 1; 328 } 329 330 /* 331 * Use any valid GPT available, do not require both GPTs to be valid 332 */ 333 for (i = 0; i < __arraycount(gptsector); i++) { 334 error = check_gpt(d, gptsector[i]); 335 if (error == 0) 336 break; 337 } 338 339 if (i >= __arraycount(gptsector)) { 340 memset(d->part, 0, sizeof(d->part)); 341 return -1; 342 } 343 344 #ifdef DISK_DEBUG 345 printf("using %s GPT\n", (i == 0) ? "primary" : "secondary"); 346 #endif 347 return 0; 348 } 349 #endif /* !NO_GPT */ 350 351 #ifndef NO_DISKLABEL 352 static void 353 ingest_label(struct biosdisk *d, struct disklabel *lp) 354 { 355 int part; 356 357 memset(d->part, 0, sizeof(d->part)); 358 359 for (part = 0; part < lp->d_npartitions; part++) { 360 if (lp->d_partitions[part].p_size == 0) 361 continue; 362 if (lp->d_partitions[part].p_fstype == FS_UNUSED) 363 continue; 364 d->part[part].fstype = lp->d_partitions[part].p_fstype; 365 d->part[part].offset = lp->d_partitions[part].p_offset; 366 d->part[part].size = lp->d_partitions[part].p_size; 367 } 368 } 369 370 static int 371 check_label(struct biosdisk *d, daddr_t sector) 372 { 373 struct disklabel *lp; 374 375 /* find partition in NetBSD disklabel */ 376 if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) { 377 #ifdef DISK_DEBUG 378 printf("Error reading disklabel\n"); 379 #endif 380 return EIO; 381 } 382 lp = (struct disklabel *) (d->buf + LABELOFFSET); 383 if (lp->d_magic != DISKMAGIC || dkcksum(lp)) { 384 #ifdef DISK_DEBUG 385 printf("warning: no disklabel in sector %"PRId64"\n", sector); 386 #endif 387 return -1; 388 } 389 390 ingest_label(d, lp); 391 392 #ifdef _STANDALONE 393 bi_disk.labelsector = d->boff + LABELSECTOR; 394 bi_disk.label.type = lp->d_type; 395 memcpy(bi_disk.label.packname, lp->d_packname, 16); 396 bi_disk.label.checksum = lp->d_checksum; 397 398 bi_wedge.matchblk = d->boff + LABELSECTOR; 399 bi_wedge.matchnblks = 1; 400 401 md5(bi_wedge.matchhash, d->buf, d->ll.secsize); 402 #endif 403 404 return 0; 405 } 406 407 static int 408 read_label(struct biosdisk *d) 409 { 410 struct disklabel dflt_lbl; 411 struct mbr_partition mbr[MBR_PART_COUNT]; 412 struct partition *p; 413 int sector, i; 414 int error; 415 int typ; 416 int ext_base, this_ext, next_ext; 417 #ifdef COMPAT_386BSD_MBRPART 418 int sector_386bsd = -1; 419 #endif 420 421 memset(&dflt_lbl, 0, sizeof(dflt_lbl)); 422 dflt_lbl.d_npartitions = 8; 423 424 d->boff = 0; 425 426 if (d->ll.type != BIOSDISK_TYPE_HD) 427 /* No label on floppy and CD */ 428 return -1; 429 430 /* 431 * find NetBSD Partition in DOS partition table 432 * XXX check magic??? 433 */ 434 ext_base = 0; 435 next_ext = 0; 436 for (;;) { 437 this_ext = ext_base + next_ext; 438 next_ext = 0; 439 if (readsects(&d->ll, this_ext, 1, d->buf, 0)) { 440 #ifdef DISK_DEBUG 441 printf("error reading MBR sector %d\n", this_ext); 442 #endif 443 return EIO; 444 } 445 memcpy(&mbr, ((struct mbr_sector *)d->buf)->mbr_parts, 446 sizeof(mbr)); 447 /* Look for NetBSD partition ID */ 448 for (i = 0; i < MBR_PART_COUNT; i++) { 449 typ = mbr[i].mbrp_type; 450 if (typ == 0) 451 continue; 452 sector = this_ext + mbr[i].mbrp_start; 453 #ifdef DISK_DEBUG 454 printf("ptn type %d in sector %d\n", typ, sector); 455 #endif 456 if (typ == MBR_PTYPE_NETBSD) { 457 error = check_label(d, sector); 458 if (error >= 0) 459 return error; 460 } 461 if (MBR_IS_EXTENDED(typ)) { 462 next_ext = mbr[i].mbrp_start; 463 continue; 464 } 465 #ifdef COMPAT_386BSD_MBRPART 466 if (this_ext == 0 && typ == MBR_PTYPE_386BSD) 467 sector_386bsd = sector; 468 #endif 469 if (this_ext != 0) { 470 if (dflt_lbl.d_npartitions >= MAXPARTITIONS) 471 continue; 472 p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++]; 473 } else 474 p = &dflt_lbl.d_partitions[i]; 475 p->p_offset = sector; 476 p->p_size = mbr[i].mbrp_size; 477 p->p_fstype = xlat_mbr_fstype(typ); 478 } 479 if (next_ext == 0) 480 break; 481 if (ext_base == 0) { 482 ext_base = next_ext; 483 next_ext = 0; 484 } 485 } 486 487 sector = 0; 488 #ifdef COMPAT_386BSD_MBRPART 489 if (sector_386bsd != -1) { 490 printf("old BSD partition ID!\n"); 491 sector = sector_386bsd; 492 } 493 #endif 494 495 /* 496 * One of two things: 497 * 1. no MBR 498 * 2. no NetBSD partition in MBR 499 * 500 * We simply default to "start of disk" in this case and 501 * press on. 502 */ 503 error = check_label(d, sector); 504 if (error >= 0) 505 return error; 506 507 /* 508 * Nothing at start of disk, return info from mbr partitions. 509 */ 510 /* XXX fill it to make checksum match kernel one */ 511 dflt_lbl.d_checksum = dkcksum(&dflt_lbl); 512 ingest_label(d, &dflt_lbl); 513 return 0; 514 } 515 #endif /* NO_DISKLABEL */ 516 517 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 518 static int 519 read_partitions(struct biosdisk *d) 520 { 521 int error; 522 523 error = -1; 524 525 #ifndef NO_GPT 526 error = read_gpt(d); 527 if (error == 0) 528 return 0; 529 530 #endif 531 #ifndef NO_DISKLABEL 532 error = read_label(d); 533 534 #endif 535 return error; 536 } 537 #endif 538 539 void 540 biosdisk_probe(void) 541 { 542 struct biosdisk d; 543 struct biosdisk_extinfo ed; 544 uint64_t size; 545 int first; 546 int i; 547 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 548 int part; 549 #endif 550 551 for (i = 0; i < MAX_BIOSDISKS + 2; i++) { 552 first = 1; 553 memset(&d, 0, sizeof(d)); 554 memset(&ed, 0, sizeof(ed)); 555 if (i >= MAX_BIOSDISKS) 556 d.ll.dev = 0x00 + i - MAX_BIOSDISKS; /* fd */ 557 else 558 d.ll.dev = 0x80 + i; /* hd/cd */ 559 if (set_geometry(&d.ll, &ed)) 560 continue; 561 printf("disk "); 562 switch (d.ll.type) { 563 case BIOSDISK_TYPE_CD: 564 printf("cd0\n cd0a\n"); 565 break; 566 case BIOSDISK_TYPE_FD: 567 printf("fd%d\n", d.ll.dev & 0x7f); 568 printf(" fd%da\n", d.ll.dev & 0x7f); 569 break; 570 case BIOSDISK_TYPE_HD: 571 printf("hd%d", d.ll.dev & 0x7f); 572 if (d.ll.flags & BIOSDISK_INT13EXT) { 573 printf(" size "); 574 size = ed.totsec * ed.sbytes; 575 if (size >= (10ULL * 1024 * 1024 * 1024)) 576 printf("%"PRIu64" GB", 577 size / (1024 * 1024 * 1024)); 578 else 579 printf("%"PRIu64" MB", 580 size / (1024 * 1024)); 581 } 582 printf("\n"); 583 break; 584 } 585 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 586 if (d.ll.type != BIOSDISK_TYPE_HD) 587 continue; 588 589 if (read_partitions(&d) != 0) 590 continue; 591 592 for (part = 0; part < BIOSDISKNPART; part++) { 593 if (d.part[part].size == 0) 594 continue; 595 if (d.part[part].fstype == FS_UNUSED) 596 continue; 597 if (first) { 598 printf(" "); 599 first = 0; 600 } 601 printf(" hd%d%c(", d.ll.dev & 0x7f, part + 'a'); 602 if (d.part[part].fstype < FSMAXTYPES) 603 printf("%s", 604 fstypenames[d.part[part].fstype]); 605 else 606 printf("%d", d.part[part].fstype); 607 printf(")"); 608 } 609 #endif 610 if (first == 0) 611 printf("\n"); 612 } 613 } 614 615 /* Determine likely partition for possible sector number of dos 616 * partition. 617 */ 618 619 int 620 biosdisk_findpartition(int biosdev, daddr_t sector) 621 { 622 #if defined(NO_DISKLABEL) && defined(NO_GPT) 623 return 0; 624 #else 625 struct biosdisk *d; 626 int partition = 0; 627 #ifdef DISK_DEBUG 628 printf("looking for partition device %x, sector %"PRId64"\n", biosdev, sector); 629 #endif 630 631 /* Look for netbsd partition that is the dos boot one */ 632 d = alloc_biosdisk(biosdev); 633 if (d == NULL) 634 return 0; 635 636 if (read_partitions(d) == 0) { 637 for (partition = (BIOSDISKNPART-1); --partition;) { 638 if (d->part[partition].fstype == FS_UNUSED) 639 continue; 640 if (d->part[partition].offset == sector) 641 break; 642 } 643 } 644 645 dealloc(d, sizeof(*d)); 646 return partition; 647 #endif /* NO_DISKLABEL && NO_GPT */ 648 } 649 650 #ifdef _STANDALONE 651 static void 652 add_biosdisk_bootinfo(void) 653 { 654 static bool done; 655 656 if (bootinfo == NULL) { 657 done = false; 658 return; 659 } 660 661 if (done) 662 return; 663 664 BI_ADD(&bi_disk, BTINFO_BOOTDISK, sizeof(bi_disk)); 665 BI_ADD(&bi_wedge, BTINFO_BOOTWEDGE, sizeof(bi_wedge)); 666 667 done = true; 668 669 return; 670 } 671 672 #endif 673 674 int 675 biosdisk_open(struct open_file *f, ...) 676 /* struct open_file *f, int biosdev, int partition */ 677 { 678 va_list ap; 679 struct biosdisk *d; 680 int biosdev; 681 int partition; 682 int error = 0; 683 684 va_start(ap, f); 685 biosdev = va_arg(ap, int); 686 d = alloc_biosdisk(biosdev); 687 if (d == NULL) { 688 error = ENXIO; 689 goto out; 690 } 691 692 partition = va_arg(ap, int); 693 #ifdef _STANDALONE 694 bi_disk.biosdev = d->ll.dev; 695 bi_disk.partition = partition; 696 bi_disk.labelsector = -1; 697 698 bi_wedge.biosdev = d->ll.dev; 699 bi_wedge.matchblk = -1; 700 #endif 701 702 #if !defined(NO_DISKLABEL) || !defined(NO_GPT) 703 error = read_partitions(d); 704 if (error == -1) { 705 error = 0; 706 goto nolabel; 707 } 708 if (error) 709 goto out; 710 711 if (partition >= BIOSDISKNPART || 712 d->part[partition].fstype == FS_UNUSED) { 713 #ifdef DISK_DEBUG 714 printf("illegal partition\n"); 715 #endif 716 error = EPART; 717 goto out; 718 } 719 720 d->boff = d->part[partition].offset; 721 722 if (d->part[partition].fstype == FS_RAID) 723 d->boff += RF_PROTECTED_SECTORS; 724 725 #ifdef _STANDALONE 726 bi_wedge.startblk = d->part[partition].offset; 727 bi_wedge.nblks = d->part[partition].size; 728 #endif 729 730 nolabel: 731 #endif 732 #ifdef DISK_DEBUG 733 printf("partition @%"PRId64"\n", d->boff); 734 #endif 735 736 #ifdef _STANDALONE 737 add_biosdisk_bootinfo(); 738 #endif 739 740 f->f_devdata = d; 741 out: 742 va_end(ap); 743 if (error) 744 dealloc(d, sizeof(*d)); 745 return error; 746 } 747 748 #ifndef LIBSA_NO_FS_CLOSE 749 int 750 biosdisk_close(struct open_file *f) 751 { 752 struct biosdisk *d = f->f_devdata; 753 754 /* let the floppy drive go off */ 755 if (d->ll.type == BIOSDISK_TYPE_FD) 756 wait_sec(3); /* 2s is enough on all PCs I found */ 757 758 dealloc(d, sizeof(*d)); 759 f->f_devdata = NULL; 760 return 0; 761 } 762 #endif 763 764 int 765 biosdisk_ioctl(struct open_file *f, u_long cmd, void *arg) 766 { 767 return EIO; 768 } 769