1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/boot/i386/libi386/biosdisk.c,v 1.45 2004/09/21 06:46:44 wes Exp $ 27 */ 28 29 /* 30 * BIOS disk device handling. 31 * 32 * Ideas and algorithms from: 33 * 34 * - NetBSD libi386/biosdisk.c 35 * - FreeBSD biosboot/disk.c 36 * 37 */ 38 39 #include <stand.h> 40 41 #include <sys/disklabel32.h> 42 #include <sys/disklabel64.h> 43 #include <sys/diskmbr.h> 44 #include <sys/dtype.h> 45 #include <machine/bootinfo.h> 46 #include <machine/psl.h> 47 48 #include <stdarg.h> 49 50 #include <bootstrap.h> 51 #include <btxv86.h> 52 #include "libi386.h" 53 54 #define BIOS_NUMDRIVES 0x475 55 #define BIOSDISK_SECSIZE 512 56 #define BUFSIZE (4 * BIOSDISK_SECSIZE) 57 #define MAXBDDEV MAXDEV 58 59 #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ 60 #define WDMAJOR 0 /* major numbers for devices we frontend for */ 61 #define WFDMAJOR 1 62 #define FDMAJOR 2 63 #define DAMAJOR 4 64 65 #ifdef DISK_DEBUG 66 # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 67 #else 68 # define DEBUG(fmt, args...) 69 #endif 70 71 struct open_disk { 72 int od_dkunit; /* disk unit number */ 73 int od_unit; /* BIOS unit number */ 74 int od_cyl; /* BIOS geometry */ 75 int od_hds; 76 int od_sec; 77 int od_boff; /* block offset from beginning of BIOS disk */ 78 int od_flags; 79 #define BD_MODEINT13 0x0000 80 #define BD_MODEEDD1 0x0001 81 #define BD_MODEEDD3 0x0002 82 #define BD_MODEMASK 0x0003 83 #define BD_FLOPPY 0x0004 84 #define BD_LABELOK 0x0008 85 #define BD_PARTTABOK 0x0010 86 union { 87 struct disklabel32 od_disklabel; 88 struct disklabel64 od_disklabel64; 89 }; 90 int od_nslices; /* slice count */ 91 struct dos_partition od_slicetab[NEXTDOSPART]; 92 }; 93 94 /* 95 * List of BIOS devices, translation from disk unit number to 96 * BIOS unit number. 97 */ 98 static struct bdinfo 99 { 100 int bd_unit; /* BIOS unit number */ 101 int bd_flags; 102 int bd_type; /* BIOS 'drive type' (floppy only) */ 103 } bdinfo [MAXBDDEV]; 104 static int nbdinfo = 0; 105 106 static int bd_getgeom(struct open_disk *od); 107 static int bd_read(struct open_disk *od, daddr_t dblk, int blks, 108 caddr_t dest); 109 static int bd_write(struct open_disk *od, daddr_t dblk, int blks, 110 caddr_t dest); 111 112 static int bd_int13probe(struct bdinfo *bd); 113 114 static void bd_printslice(struct open_disk *od, struct dos_partition *dp, 115 char *prefix, int verbose); 116 static void bd_printbsdslice(struct open_disk *od, daddr_t offset, 117 char *prefix, int verbose); 118 119 static int bd_init(void); 120 static int bd_strategy(void *devdata, int flag, daddr_t dblk, 121 size_t size, char *buf, size_t *rsize); 122 static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, 123 size_t size, char *buf, size_t *rsize); 124 static int bd_open(struct open_file *f, ...); 125 static int bd_close(struct open_file *f); 126 static void bd_print(int verbose); 127 128 struct devsw biosdisk = { 129 "disk", 130 DEVT_DISK, 131 bd_init, 132 bd_strategy, 133 bd_open, 134 bd_close, 135 noioctl, 136 bd_print, 137 NULL 138 }; 139 140 static int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev); 141 static void bd_closedisk(struct open_disk *od); 142 static int bd_bestslice(struct open_disk *od); 143 static void bd_chainextended(struct open_disk *od, u_int32_t base, 144 u_int32_t offset); 145 146 /* also used by CD code */ 147 char __aligned(16) bounce_base[BOUNCEBUF_SIZE]; 148 149 150 /* 151 * Translate between BIOS device numbers and our private unit numbers. 152 */ 153 int 154 bd_bios2unit(int biosdev) 155 { 156 int i; 157 158 DEBUG("looking for bios device 0x%x", biosdev); 159 for (i = 0; i < nbdinfo; i++) { 160 DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); 161 if (bdinfo[i].bd_unit == biosdev) 162 return(i); 163 } 164 return(-1); 165 } 166 167 int 168 bd_unit2bios(int unit) 169 { 170 if ((unit >= 0) && (unit < nbdinfo)) 171 return(bdinfo[unit].bd_unit); 172 return(-1); 173 } 174 175 /* 176 * Quiz the BIOS for disk devices, save a little info about them. 177 */ 178 static int 179 bd_init(void) 180 { 181 int base, unit, nfd = 0; 182 183 /* sequence 0, 0x80 */ 184 for (base = 0; base <= 0x80; base += 0x80) { 185 for (unit = base; (nbdinfo < MAXBDDEV); unit++) { 186 /* check the BIOS equipment list for number of fixed disks */ 187 if((base == 0x80) && 188 (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) 189 break; 190 191 bdinfo[nbdinfo].bd_unit = unit; 192 bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0; 193 194 if (!bd_int13probe(&bdinfo[nbdinfo])) 195 break; 196 197 /* XXX we need "disk aliases" to make this simpler */ 198 printf("BIOS drive %c: is disk%d\n", 199 (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo); 200 nbdinfo++; 201 if (base == 0x80) 202 nfd++; 203 } 204 } 205 return(0); 206 } 207 208 /* 209 * Try to detect a device supported by the legacy int13 BIOS 210 */ 211 static int 212 bd_int13probe(struct bdinfo *bd) 213 { 214 v86.ctl = V86_FLAGS; 215 v86.addr = 0x13; 216 v86.eax = 0x800; 217 v86.edx = bd->bd_unit; 218 v86int(); 219 220 if (!(v86.efl & PSL_C) && /* carry clear */ 221 ((v86.edx & 0xff) > ((unsigned)bd->bd_unit & 0x7f))) { /* unit # OK */ 222 223 /* 224 * Ignore devices with an absurd sector size. 225 */ 226 if ((v86.ecx & 0x3f) == 0) { 227 DEBUG("Invalid geometry for unit %d", bd->bd_unit); 228 return(0); 229 } 230 bd->bd_flags |= BD_MODEINT13; 231 bd->bd_type = v86.ebx & 0xff; 232 233 /* Determine if we can use EDD with this device. */ 234 v86.ctl = V86_FLAGS; 235 v86.addr = 0x13; 236 v86.eax = 0x4100; 237 v86.edx = bd->bd_unit; 238 v86.ebx = 0x55aa; 239 v86int(); 240 if (!(v86.efl & PSL_C) && /* carry clear */ 241 ((v86.ebx & 0xffff) == 0xaa55) && /* signature */ 242 (v86.ecx & 0x1)) { /* packets mode ok */ 243 bd->bd_flags |= BD_MODEEDD1; 244 if((v86.eax & 0xff00) > 0x300) 245 bd->bd_flags |= BD_MODEEDD3; 246 } 247 return(1); 248 } 249 return(0); 250 } 251 252 /* 253 * Print information about disks 254 */ 255 static void 256 bd_print(int verbose) 257 { 258 int i, j; 259 char line[80]; 260 struct i386_devdesc dev; 261 struct open_disk *od; 262 struct dos_partition *dptr; 263 264 for (i = 0; i < nbdinfo; i++) { 265 sprintf(line, " disk%d: BIOS drive %c:\n", i, 266 (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80)); 267 pager_output(line); 268 269 /* try to open the whole disk */ 270 dev.d_kind.biosdisk.unit = i; 271 dev.d_kind.biosdisk.slice = -1; 272 dev.d_kind.biosdisk.partition = -1; 273 274 if (!bd_opendisk(&od, &dev)) { 275 276 /* Do we have a partition table? */ 277 if (od->od_flags & BD_PARTTABOK) { 278 dptr = &od->od_slicetab[0]; 279 280 /* Check for a "dedicated" disk */ 281 if ((dptr[3].dp_typ == DOSPTYP_386BSD || 282 dptr[3].dp_typ == DOSPTYP_NETBSD || 283 dptr[3].dp_typ == DOSPTYP_DFLYBSD) && 284 (dptr[3].dp_start == 0) && 285 (dptr[3].dp_size == 50000)) { 286 sprintf(line, " disk%d", i); 287 bd_printbsdslice(od, 0, line, verbose); 288 } else { 289 for (j = 0; j < od->od_nslices; j++) { 290 sprintf(line, " disk%ds%d", i, j + 1); 291 bd_printslice(od, &dptr[j], line, verbose); 292 } 293 } 294 } 295 bd_closedisk(od); 296 } 297 } 298 } 299 300 /* 301 * Print information about slices on a disk. For the size calculations we 302 * assume a 512 byte sector. 303 */ 304 static void 305 bd_printslice(struct open_disk *od, struct dos_partition *dp, char *prefix, 306 int verbose) 307 { 308 char line[80]; 309 310 switch (dp->dp_typ) { 311 case DOSPTYP_DFLYBSD: 312 case DOSPTYP_386BSD: 313 case DOSPTYP_NETBSD: 314 /* XXX: possibly add types 0 and 1, as in subr_disk, for gpt magic */ 315 bd_printbsdslice(od, (daddr_t)dp->dp_start, prefix, verbose); 316 return; 317 case DOSPTYP_LINSWP: 318 if (verbose) 319 sprintf(line, "%s: Linux swap %.6dMB (%d - %d)\n", 320 prefix, dp->dp_size / 2048, 321 dp->dp_start, dp->dp_start + dp->dp_size); 322 else 323 sprintf(line, "%s: Linux swap\n", prefix); 324 break; 325 case DOSPTYP_LINUX: 326 /* 327 * XXX 328 * read the superblock to confirm this is an ext2fs partition? 329 */ 330 if (verbose) 331 sprintf(line, "%s: ext2fs %.6dMB (%d - %d)\n", prefix, 332 dp->dp_size / 2048, dp->dp_start, 333 dp->dp_start + dp->dp_size); 334 else 335 sprintf(line, "%s: ext2fs\n", prefix); 336 break; 337 case 0x00: /* unused partition */ 338 case DOSPTYP_EXT: 339 return; 340 case 0x01: 341 if (verbose) 342 sprintf(line, "%s: FAT-12 %.6dMB (%d - %d)\n", prefix, 343 dp->dp_size / 2048, dp->dp_start, 344 dp->dp_start + dp->dp_size); 345 else 346 sprintf(line, "%s: FAT-12\n", prefix); 347 break; 348 case 0x04: 349 case 0x06: 350 case 0x0e: 351 if (verbose) 352 sprintf(line, "%s: FAT-16 %.6dMB (%d - %d)\n", prefix, 353 dp->dp_size / 2048, dp->dp_start, 354 dp->dp_start + dp->dp_size); 355 else 356 sprintf(line, "%s: FAT-16\n", prefix); 357 break; 358 case 0x0b: 359 case 0x0c: 360 if (verbose) 361 sprintf(line, "%s: FAT-32 %.6dMB (%d - %d)\n", prefix, 362 dp->dp_size / 2048, dp->dp_start, 363 dp->dp_start + dp->dp_size); 364 else 365 sprintf(line, "%s: FAT-32\n", prefix); 366 break; 367 default: 368 if (verbose) 369 sprintf(line, "%s: Unknown fs: 0x%x %.6dMB (%d - %d)\n", 370 prefix, dp->dp_typ, dp->dp_size / 2048, 371 dp->dp_start, dp->dp_start + dp->dp_size); 372 else 373 sprintf(line, "%s: Unknown fs: 0x%x\n", prefix, 374 dp->dp_typ); 375 } 376 pager_output(line); 377 } 378 379 static void 380 print_partition(u_int8_t fstype, unsigned long long offset, 381 unsigned long long size, int i, int od_flags, 382 char *prefix, int verbose, int type) 383 { 384 char line[80]; 385 386 /* 387 * For each partition, make sure we know what type of fs it is. If 388 * not, then skip it. However, since floppies often have bogus 389 * fstypes, print the 'a' partition on a floppy even if it is marked 390 * unused. 391 */ 392 if ((fstype == FS_SWAP) || 393 (fstype == FS_VINUM) || 394 (fstype == FS_HAMMER) || 395 (fstype == FS_HAMMER2) || 396 (fstype == FS_BSDFFS) || 397 (fstype == FS_ZFS) || 398 (fstype == FS_JFS2) || 399 ((fstype == FS_UNUSED) && 400 (od_flags & BD_FLOPPY) && (i == 0))) { 401 402 /* Only print out statistics in verbose mode */ 403 if (verbose) { 404 sprintf(line, "%c %s%c: %s %.6lluMB (%llu - %llu)\n", 405 /* prefix disks that can be used to load modules with '*' */ 406 ((fstype == FS_BSDFFS) || (fstype == FS_UNUSED) || 407 (fstype == FS_VINUM)) ? '*' : ' ', 408 prefix, 'a' + i, 409 (fstype == FS_SWAP) ? "swap" : 410 (fstype == FS_VINUM) ? "vinum" : 411 (fstype == FS_HAMMER) ? "HAMMER" : 412 (fstype == FS_HAMMER2) ? "HAMMER2" : 413 (fstype == FS_JFS2) ? "JFS2" : 414 (fstype == FS_ZFS) ? "ZFS" : 415 (fstype == FS_BSDFFS) ? "FFS" : 416 "(unknown)", 417 (type==32)?(size / 2048):(size/1024/1024), 418 offset, 419 offset + size); 420 } else { 421 sprintf(line, "%c %s%c: %s\n", 422 /* prefix disks that can be used to load modules with '*' */ 423 ((fstype == FS_BSDFFS) || (fstype == FS_UNUSED) || 424 (fstype == FS_VINUM)) ? '*' : ' ', 425 prefix, 'a' + i, 426 (fstype == FS_SWAP) ? "swap" : 427 (fstype == FS_VINUM) ? "vinum" : 428 (fstype == FS_HAMMER) ? "HAMMER" : 429 (fstype == FS_HAMMER2) ? "HAMMER2" : 430 (fstype == FS_JFS2) ? "JFS2" : 431 (fstype == FS_ZFS) ? "ZFS" : 432 (fstype == FS_BSDFFS) ? "FFS" : 433 "(unknown)"); 434 } 435 436 pager_output(line); 437 } 438 } 439 440 /* 441 * Print out each valid partition in the disklabel of a FreeBSD slice. 442 * For size calculations, we assume a 512 byte sector size. 443 */ 444 static void 445 bd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, 446 int verbose) 447 { 448 char line[80]; 449 char buf[BIOSDISK_SECSIZE*2]; 450 struct disklabel32 *lp = NULL; 451 struct disklabel64 *lp64 = NULL; 452 int i; 453 454 /* read disklabel */ 455 if (bd_read(od, offset + LABELSECTOR32, 1, buf)) 456 return; 457 lp =(struct disklabel32 *)(&buf[0]); 458 if (lp->d_magic != DISKMAGIC32) { 459 if (bd_read(od, offset, 2, buf)) 460 return; 461 462 lp64 =(struct disklabel64 *)(&buf[0]); 463 if (lp64->d_magic != DISKMAGIC64) { 464 sprintf(line, "%s: bad disklabel\n", prefix); 465 pager_output(line); 466 return; 467 } 468 lp = NULL; /* PARANOID */ 469 } 470 if (lp64) { 471 /* We got ourselves a disklabel64 here */ 472 for (i = 0; i < lp64->d_npartitions; i++) { 473 if (lp64->d_partitions[i].p_bsize == 0) 474 continue; 475 476 print_partition(lp64->d_partitions[i].p_fstype, 477 lp64->d_partitions[i].p_boffset, 478 lp64->d_partitions[i].p_bsize, 479 i, od->od_flags, prefix, verbose, 64); 480 } 481 } else if (lp) { 482 /* Print partitions */ 483 for (i = 0; i < lp->d_npartitions; i++) { 484 print_partition(lp->d_partitions[i].p_fstype, 485 lp->d_partitions[i].p_offset, 486 lp->d_partitions[i].p_size, 487 i, od->od_flags, prefix, verbose, 32); 488 } 489 } 490 } 491 492 493 /* 494 * Attempt to open the disk described by (dev) for use by (f). 495 * 496 * Note that the philosophy here is "give them exactly what 497 * they ask for". This is necessary because being too "smart" 498 * about what the user might want leads to complications. 499 * (eg. given no slice or partition value, with a disk that is 500 * sliced - are they after the first BSD slice, or the DOS 501 * slice before it?) 502 */ 503 static int 504 bd_open(struct open_file *f, ...) 505 { 506 va_list ap; 507 struct i386_devdesc *dev; 508 struct open_disk *od; 509 int error; 510 511 va_start(ap, f); 512 dev = va_arg(ap, struct i386_devdesc *); 513 va_end(ap); 514 if ((error = bd_opendisk(&od, dev))) 515 return(error); 516 517 /* 518 * Save our context 519 */ 520 ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od; 521 DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff); 522 return(0); 523 } 524 525 static int 526 bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev) 527 { 528 struct dos_partition *dptr; 529 struct disklabel32 *lp; 530 struct disklabel64 *lp64; 531 struct open_disk *od; 532 int sector, slice, i; 533 int error; 534 static char buf[BUFSIZE]; 535 536 if (dev->d_kind.biosdisk.unit >= nbdinfo) { 537 DEBUG("attempt to open nonexistent disk"); 538 return(ENXIO); 539 } 540 541 od = (struct open_disk *)malloc(sizeof(struct open_disk)); 542 if (!od) { 543 DEBUG("no memory"); 544 return (ENOMEM); 545 } 546 547 /* Look up BIOS unit number, intialise open_disk structure */ 548 od->od_dkunit = dev->d_kind.biosdisk.unit; 549 od->od_unit = bdinfo[od->od_dkunit].bd_unit; 550 od->od_flags = bdinfo[od->od_dkunit].bd_flags; 551 od->od_boff = 0; 552 od->od_nslices = 0; 553 error = 0; 554 DEBUG("open '%s', unit 0x%x slice %d partition %c", 555 i386_fmtdev(dev), dev->d_kind.biosdisk.unit, 556 dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a'); 557 558 /* Get geometry for this open (removable device may have changed) */ 559 if (bd_getgeom(od)) { 560 DEBUG("can't get geometry"); 561 error = ENXIO; 562 goto out; 563 } 564 565 /* 566 * Following calculations attempt to determine the correct value 567 * for d->od_boff by looking for the slice and partition specified, 568 * or searching for reasonable defaults. 569 */ 570 571 /* 572 * Find the slice in the DOS slice table. 573 */ 574 if (bd_read(od, 0, 1, buf)) { 575 DEBUG("error reading MBR"); 576 error = EIO; 577 goto out; 578 } 579 580 /* 581 * Check the slice table magic. 582 */ 583 if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { 584 /* If a slice number was explicitly supplied, this is an error */ 585 if (dev->d_kind.biosdisk.slice > 0) { 586 DEBUG("no slice table/MBR (no magic)"); 587 error = ENOENT; 588 goto out; 589 } 590 sector = 0; 591 goto unsliced; /* may be a floppy */ 592 } 593 594 /* 595 * copy the partition table, then pick up any extended partitions. The 596 * base partition table always has four entries, even if some of them 597 * represented extended partitions. However, any additional sub-extended 598 * partitions will be silently recursed and not included in the slice 599 * table. 600 */ 601 bcopy(buf + DOSPARTOFF, &od->od_slicetab, 602 sizeof(struct dos_partition) * NDOSPART); 603 od->od_nslices = NDOSPART; 604 605 dptr = &od->od_slicetab[0]; 606 for (i = 0; i < NDOSPART; i++, dptr++) { 607 if ((dptr->dp_typ == DOSPTYP_EXT) || (dptr->dp_typ == DOSPTYP_EXTLBA)) 608 bd_chainextended(od, dptr->dp_start, 0); /* 1st offset is zero */ 609 } 610 od->od_flags |= BD_PARTTABOK; 611 dptr = &od->od_slicetab[0]; 612 613 /* 614 * Overflow entries are not loaded into memory but we still keep 615 * track of the count. Fix it up now. 616 */ 617 if (od->od_nslices > NEXTDOSPART) 618 od->od_nslices = NEXTDOSPART; 619 620 /* 621 * Is this a request for the whole disk? 622 */ 623 if (dev->d_kind.biosdisk.slice == -1) { 624 sector = 0; 625 goto unsliced; 626 } 627 628 /* 629 * if a slice number was supplied but not found, this is an error. 630 */ 631 if (dev->d_kind.biosdisk.slice > 0) { 632 slice = dev->d_kind.biosdisk.slice - 1; 633 if (slice >= od->od_nslices) { 634 DEBUG("slice %d not found", slice); 635 error = ENOENT; 636 goto out; 637 } 638 } 639 640 /* 641 * Check for the historically bogus MBR found on true dedicated disks 642 */ 643 if ((dptr[3].dp_typ == DOSPTYP_386BSD || 644 dptr[3].dp_typ == DOSPTYP_DFLYBSD) && 645 (dptr[3].dp_start == 0) && 646 (dptr[3].dp_size == 50000)) { 647 sector = 0; 648 goto unsliced; 649 } 650 651 /* Try to auto-detect the best slice; this should always give a slice number */ 652 if (dev->d_kind.biosdisk.slice == 0) { 653 slice = bd_bestslice(od); 654 if (slice == -1) { 655 error = ENOENT; 656 goto out; 657 } 658 dev->d_kind.biosdisk.slice = slice; 659 } 660 661 dptr = &od->od_slicetab[0]; 662 /* 663 * Accept the supplied slice number unequivocally (we may be looking 664 * at a DOS partition). 665 */ 666 dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */ 667 sector = dptr->dp_start; 668 DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size); 669 670 /* 671 * If we are looking at a BSD slice, and the partition is < 0, 672 * assume the 'a' partition 673 */ 674 if ((dptr->dp_typ == DOSPTYP_386BSD || 675 dptr->dp_typ == DOSPTYP_DFLYBSD) && 676 dev->d_kind.biosdisk.partition < 0) { 677 dev->d_kind.biosdisk.partition = 0; 678 } 679 680 unsliced: 681 /* 682 * Now we have the slice offset, look for the partition in the disklabel if we have 683 * a partition to start with. 684 * 685 * XXX we might want to check the label checksum. 686 */ 687 if (dev->d_kind.biosdisk.partition < 0) { 688 od->od_boff = sector; /* no partition, must be after the slice */ 689 DEBUG("opening raw slice"); 690 } else { 691 692 if (bd_read(od, sector + LABELSECTOR32, 1, buf)) { 693 DEBUG("error reading disklabel"); 694 error = EIO; 695 goto out; 696 } 697 DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel32), buf + LABELOFFSET32, &od->od_disklabel); 698 bcopy(buf + LABELOFFSET32, &od->od_disklabel, sizeof(struct disklabel32)); 699 lp = &od->od_disklabel; 700 701 if (lp->d_magic == DISKMAGIC32) { 702 od->od_flags |= BD_LABELOK; 703 704 if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) { 705 DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 706 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions); 707 error = EPART; 708 goto out; 709 710 } 711 712 #ifdef DISK_DEBUG 713 /* Complain if the partition is unused unless this is a floppy. */ 714 if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) && 715 !(od->od_flags & BD_FLOPPY)) 716 DEBUG("warning, partition marked as unused"); 717 #endif 718 719 od->od_boff = 720 lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset - 721 lp->d_partitions[RAW_PART].p_offset + 722 sector; 723 724 goto out; 725 } 726 727 /* else maybe DISKLABEL64? */ 728 729 if (bd_read(od, sector, (sizeof(od->od_disklabel64) + 511) / 512, buf)) { 730 DEBUG("error reading disklabel"); 731 error = EIO; 732 goto out; 733 } 734 DEBUG("copy %d bytes of label from %p to %p", sizeof(od->od_disklabel64), buf, &od->od_disklabel64); 735 bcopy(buf, &od->od_disklabel64, sizeof(od->od_disklabel64)); 736 lp64 = &od->od_disklabel64; 737 738 if (lp64->d_magic == DISKMAGIC64) { 739 od->od_flags |= BD_LABELOK; 740 741 if (dev->d_kind.biosdisk.partition >= lp64->d_npartitions || 742 lp64->d_partitions[dev->d_kind.biosdisk.partition].p_bsize == 0) { 743 DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 744 'a' + dev->d_kind.biosdisk.partition, 'a' + lp64->d_npartitions); 745 error = EPART; 746 goto out; 747 748 } 749 750 od->od_boff = 751 lp64->d_partitions[dev->d_kind.biosdisk.partition].p_boffset / 512 + 752 sector; 753 754 DEBUG("disklabel64 slice at %d", od->od_boff); 755 756 } else { 757 DEBUG("no disklabel"); 758 error = ENOENT; 759 } 760 } 761 762 out: 763 if (error) { 764 free(od); 765 } else { 766 *odp = od; /* return the open disk */ 767 } 768 return(error); 769 } 770 771 772 static void 773 bd_chainextended(struct open_disk *od, u_int32_t base, u_int32_t offset) 774 { 775 char buf[BIOSDISK_SECSIZE]; 776 struct dos_partition *dp1, *dp2; 777 int i; 778 779 if (bd_read(od, (daddr_t)(base + offset), 1, buf)) { 780 printf("\nerror reading extended partition table"); 781 return; 782 } 783 784 /* 785 * dp1 points to the first record in the on-disk XPT, 786 * dp2 points to the next entry in the in-memory parition table. 787 * 788 * NOTE: dp2 may be out of bounds if od_nslices >= NEXTDOSPART. 789 * 790 * NOTE: unlike the extended partitions in our primary dos partition 791 * table, we do not record recursed extended partitions themselves 792 * in our in-memory partition table. 793 * 794 * NOTE: recording within our in-memory table must be breadth first 795 * ot match what the kernel does. Thus, two passes are required. 796 * 797 * NOTE: partitioning programs which support extended partitions seem 798 * to always use the first entry for the user partition and the 799 * second entry to chain, and also appear to disallow more then one 800 * extended partition at each level. Nevertheless we make our code 801 * somewhat more generic (and the same as the kernel's own slice 802 * scan). 803 */ 804 dp1 = (struct dos_partition *)(&buf[DOSPARTOFF]); 805 dp2 = &od->od_slicetab[od->od_nslices]; 806 807 for (i = 0; i < NDOSPART; ++i, ++dp1) { 808 if (dp1->dp_scyl == 0 && dp1->dp_shd == 0 && 809 dp1->dp_ssect == 0 && dp1->dp_start == 0 && 810 dp1->dp_size == 0) { 811 continue; 812 } 813 if ((dp1->dp_typ == DOSPTYP_EXT) || 814 (dp1->dp_typ == DOSPTYP_EXTLBA)) { 815 /* 816 * breadth first traversal, must skip in the 817 * first pass 818 */ 819 continue; 820 } 821 822 /* 823 * Only load up the in-memory data if we haven't overflowed 824 * our in-memory array. 825 */ 826 if (od->od_nslices < NEXTDOSPART) { 827 dp2->dp_typ = dp1->dp_typ; 828 dp2->dp_start = base + offset + dp1->dp_start; 829 dp2->dp_size = dp1->dp_size; 830 } 831 ++od->od_nslices; 832 ++dp2; 833 } 834 835 /* 836 * Pass 2 - handle extended partitions. Note that the extended 837 * slice itself is not stored in the slice array when we recurse, 838 * but any 'original' top-level extended slices are. This is to 839 * match what the kernel does. 840 */ 841 dp1 -= NDOSPART; 842 for (i = 0; i < NDOSPART; ++i, ++dp1) { 843 if (dp1->dp_scyl == 0 && dp1->dp_shd == 0 && 844 dp1->dp_ssect == 0 && dp1->dp_start == 0 && 845 dp1->dp_size == 0) { 846 continue; 847 } 848 if ((dp1->dp_typ == DOSPTYP_EXT) || 849 (dp1->dp_typ == DOSPTYP_EXTLBA)) 850 bd_chainextended(od, base, dp1->dp_start); 851 } 852 } 853 854 /* 855 * Search for a slice with the following preferences: 856 * 857 * 1: Active FreeBSD slice 858 * 2: Non-active FreeBSD slice 859 * 3: Active Linux slice 860 * 4: non-active Linux slice 861 * 5: Active FAT/FAT32 slice 862 * 6: non-active FAT/FAT32 slice 863 */ 864 #define PREF_RAWDISK 0 865 #define PREF_FBSD_ACT 1 866 #define PREF_FBSD 2 867 #define PREF_LINUX_ACT 3 868 #define PREF_LINUX 4 869 #define PREF_DOS_ACT 5 870 #define PREF_DOS 6 871 #define PREF_NONE 7 872 873 /* 874 * slicelimit is in the range 0 .. NDOSPART 875 */ 876 static int 877 bd_bestslice(struct open_disk *od) 878 { 879 struct dos_partition *dp; 880 int pref, preflevel; 881 int i, prefslice; 882 883 prefslice = 0; 884 preflevel = PREF_NONE; 885 886 dp = &od->od_slicetab[0]; 887 for (i = 0; i < od->od_nslices; i++, dp++) { 888 switch (dp->dp_typ) { 889 case DOSPTYP_DFLYBSD: /* DragonFlyBSD */ 890 case DOSPTYP_386BSD: /* FreeBSD and old DFlyBSD */ 891 pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD; 892 break; 893 894 case DOSPTYP_LINUX: 895 pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX; 896 break; 897 898 case 0x01: /* DOS/Windows */ 899 case 0x04: 900 case 0x06: 901 case 0x0b: 902 case 0x0c: 903 case 0x0e: 904 pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS; 905 break; 906 907 default: 908 pref = PREF_NONE; 909 } 910 if (pref < preflevel) { 911 preflevel = pref; 912 prefslice = i + 1; 913 } 914 } 915 return (prefslice); 916 } 917 918 static int 919 bd_close(struct open_file *f) 920 { 921 struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data); 922 923 bd_closedisk(od); 924 return(0); 925 } 926 927 static void 928 bd_closedisk(struct open_disk *od) 929 { 930 DEBUG("open_disk %p", od); 931 #if 0 932 /* XXX is this required? (especially if disk already open...) */ 933 if (od->od_flags & BD_FLOPPY) 934 delay(3000000); 935 #endif 936 free(od); 937 } 938 939 static int 940 bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 941 { 942 struct bcache_devdata bcd; 943 struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); 944 945 bcd.dv_strategy = bd_realstrategy; 946 bcd.dv_devdata = devdata; 947 return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, size, buf, rsize)); 948 } 949 950 static int 951 bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 952 { 953 struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); 954 int blks; 955 #ifdef BD_SUPPORT_FRAGS 956 char fragbuf[BIOSDISK_SECSIZE]; 957 size_t fragsize; 958 959 fragsize = size % BIOSDISK_SECSIZE; 960 #else 961 if (size % BIOSDISK_SECSIZE) 962 panic("bd_strategy: %d bytes I/O not multiple of block size", size); 963 #endif 964 965 DEBUG("open_disk %p", od); 966 967 switch(rw){ 968 case F_READ: 969 blks = size / BIOSDISK_SECSIZE; 970 DEBUG("read %d from %d to %p", blks, dblk, buf); 971 972 if (rsize) 973 *rsize = 0; 974 if (blks && bd_read(od, dblk, blks, buf)) { 975 DEBUG("read error"); 976 return (EIO); 977 } 978 #ifdef BD_SUPPORT_FRAGS 979 DEBUG("bd_strategy: frag read %d from %d+%d to %p", 980 fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); 981 if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { 982 DEBUG("frag read error"); 983 return(EIO); 984 } 985 bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); 986 #endif 987 if (rsize) 988 *rsize = size; 989 return (0); 990 case F_WRITE : 991 blks = size / BIOSDISK_SECSIZE; 992 DEBUG("write %d from %d to %p", blks, dblk, buf); 993 994 if (rsize) 995 *rsize = 0; 996 if (blks && bd_write(od, dblk, blks, buf)) { 997 DEBUG("write error"); 998 return (EIO); 999 } 1000 #ifdef BD_SUPPORT_FRAGS 1001 if(fragsize) { 1002 DEBUG("Attempted to write a frag"); 1003 return (EIO); 1004 } 1005 #endif 1006 if (rsize) 1007 *rsize = size; 1008 return (0); 1009 default: 1010 break; /* DO NOTHING */ 1011 } 1012 return EROFS; 1013 } 1014 1015 static int 1016 bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) 1017 { 1018 u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; 1019 caddr_t p, xp, bbuf, breg; 1020 1021 /* Just in case some idiot actually tries to read -1 blocks... */ 1022 if (blks < 0) 1023 return (-1); 1024 1025 bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ 1026 resid = blks; 1027 p = dest; 1028 1029 /* 1030 * Always bounce. Our buffer is probably not segment-addressable. 1031 */ 1032 if (1) { 1033 /* 1034 * There is a 64k physical boundary somewhere in the destination 1035 * buffer, so we have to arrange a suitable bounce buffer. Allocate 1036 * a buffer twice as large as we need to. Use the bottom half unless 1037 * there is a break there, in which case we use the top half. 1038 */ 1039 bbuf = bounce_base; 1040 x = min(BOUNCEBUF_SECTS / 2, (unsigned)blks); 1041 1042 if (((u_int32_t)VTOP(bbuf) & 0xffff8000) == 1043 ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE - 1) & 0xffff8000)) { 1044 breg = bbuf; 1045 } else { 1046 breg = bbuf + x * BIOSDISK_SECSIZE; 1047 } 1048 maxfer = x; /* limit transfers to bounce region size */ 1049 } else { 1050 breg = bbuf = NULL; 1051 maxfer = 0; 1052 } 1053 1054 while (resid > 0) { 1055 x = dblk; 1056 cyl = x / bpc; /* block # / blocks per cylinder */ 1057 x %= bpc; /* block offset into cylinder */ 1058 hd = x / od->od_sec; /* offset / blocks per track */ 1059 sec = x % od->od_sec; /* offset into track */ 1060 1061 /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ 1062 x = szmin(od->od_sec - sec, resid); 1063 if (maxfer > 0) 1064 x = min(x, maxfer); /* fit bounce buffer */ 1065 1066 /* where do we transfer to? */ 1067 xp = (bbuf == NULL ? p : breg); 1068 1069 /* correct sector number for 1-based BIOS numbering */ 1070 sec++; 1071 1072 /* 1073 * Loop retrying the operation a couple of times. The BIOS may also 1074 * retry. 1075 */ 1076 for (retry = 0; retry < 3; retry++) { 1077 /* 1078 * If retrying, reset the drive. 1079 */ 1080 if (retry > 0) { 1081 v86.ctl = V86_FLAGS; 1082 v86.addr = 0x13; 1083 v86.eax = 0; 1084 v86.edx = od->od_unit; 1085 v86int(); 1086 } 1087 1088 /* 1089 * Always use EDD if the disk supports it, otherwise fall back 1090 * to CHS mode (returning an error if the cylinder number is 1091 * too large). 1092 */ 1093 if (od->od_flags & BD_MODEEDD1) { 1094 static unsigned short packet[8]; 1095 1096 packet[0] = 0x10; 1097 packet[1] = x; 1098 packet[2] = VTOPOFF(xp); 1099 packet[3] = VTOPSEG(xp); 1100 packet[4] = dblk & 0xffff; 1101 packet[5] = dblk >> 16; 1102 packet[6] = 0; 1103 packet[7] = 0; 1104 v86.ctl = V86_FLAGS; 1105 v86.addr = 0x13; 1106 v86.eax = 0x4200; 1107 v86.edx = od->od_unit; 1108 v86.ds = VTOPSEG(packet); 1109 v86.esi = VTOPOFF(packet); 1110 v86int(); 1111 result = (v86.efl & PSL_C); 1112 if (result == 0) 1113 break; 1114 } else if (cyl < 1024) { 1115 /* Use normal CHS addressing */ 1116 v86.ctl = V86_FLAGS; 1117 v86.addr = 0x13; 1118 v86.eax = 0x200 | x; 1119 v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 1120 v86.edx = (hd << 8) | od->od_unit; 1121 v86.es = VTOPSEG(xp); 1122 v86.ebx = VTOPOFF(xp); 1123 v86int(); 1124 result = (v86.efl & PSL_C); 1125 if (result == 0) 1126 break; 1127 } else { 1128 result = 1; 1129 break; 1130 } 1131 } 1132 1133 DEBUG("%u sectors from %u/%u/%d to %p (0x%x) %s", 1134 x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); 1135 /* BUG here, cannot use v86 in printf because putchar uses it too */ 1136 DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 1137 0x200 | x, 1138 ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, 1139 (hd << 8) | od->od_unit, 1140 (v86.eax >> 8) & 0xff); 1141 if (result) 1142 return(-1); 1143 if (bbuf != NULL) 1144 bcopy(breg, p, x * BIOSDISK_SECSIZE); 1145 p += (x * BIOSDISK_SECSIZE); 1146 dblk += x; 1147 resid -= x; 1148 } 1149 1150 /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ 1151 return(0); 1152 } 1153 1154 1155 static int 1156 bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) 1157 { 1158 u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; 1159 caddr_t p, xp, bbuf, breg; 1160 1161 /* Just in case some idiot actually tries to read -1 blocks... */ 1162 if (blks < 0) 1163 return (-1); 1164 1165 bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ 1166 resid = blks; 1167 p = dest; 1168 1169 /* 1170 * Always bounce. Our buffer is probably not segment-addressable. 1171 */ 1172 if (1) { 1173 /* 1174 * There is a 64k physical boundary somewhere in the destination 1175 * buffer, so we have to arrange a suitable bounce buffer. Allocate 1176 * a buffer twice as large as we need to. Use the bottom half 1177 * unless there is a break there, in which case we use the top half. 1178 */ 1179 bbuf = bounce_base; 1180 x = min(BOUNCEBUF_SECTS / 2, (unsigned)blks); 1181 1182 if (((u_int32_t)VTOP(bbuf) & 0xffff8000) == 1183 ((u_int32_t)VTOP(bbuf + x * BIOSDISK_SECSIZE - 1) & 0xffff8000)) { 1184 breg = bbuf; 1185 } else { 1186 breg = bbuf + x * BIOSDISK_SECSIZE; 1187 } 1188 maxfer = x; /* limit transfers to bounce region size */ 1189 } else { 1190 breg = bbuf = NULL; 1191 maxfer = 0; 1192 } 1193 1194 while (resid > 0) { 1195 x = dblk; 1196 cyl = x / bpc; /* block # / blocks per cylinder */ 1197 x %= bpc; /* block offset into cylinder */ 1198 hd = x / od->od_sec; /* offset / blocks per track */ 1199 sec = x % od->od_sec; /* offset into track */ 1200 1201 /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ 1202 x = szmin(od->od_sec - sec, resid); 1203 if (maxfer > 0) 1204 x = szmin(x, maxfer); /* fit bounce buffer */ 1205 1206 /* where do we transfer to? */ 1207 xp = (bbuf == NULL ? p : breg); 1208 1209 /* correct sector number for 1-based BIOS numbering */ 1210 sec++; 1211 1212 1213 /* Put your Data In, Put your Data out, 1214 Put your Data In, and shake it all about 1215 */ 1216 if (bbuf != NULL) 1217 bcopy(p, breg, x * BIOSDISK_SECSIZE); 1218 p += (x * BIOSDISK_SECSIZE); 1219 dblk += x; 1220 resid -= x; 1221 1222 /* 1223 * Loop retrying the operation a couple of times. The BIOS may also 1224 * retry. 1225 */ 1226 for (retry = 0; retry < 3; retry++) { 1227 /* 1228 * If retrying, reset the drive. 1229 */ 1230 if (retry > 0) { 1231 v86.ctl = V86_FLAGS; 1232 v86.addr = 0x13; 1233 v86.eax = 0; 1234 v86.edx = od->od_unit; 1235 v86int(); 1236 } 1237 1238 /* 1239 * Always use EDD if the disk supports it, otherwise fall back 1240 * to CHS mode (returning an error if the cylinder number is 1241 * too large). 1242 */ 1243 if (od->od_flags & BD_MODEEDD1) { 1244 static unsigned short packet[8]; 1245 1246 packet[0] = 0x10; 1247 packet[1] = x; 1248 packet[2] = VTOPOFF(xp); 1249 packet[3] = VTOPSEG(xp); 1250 packet[4] = dblk & 0xffff; 1251 packet[5] = dblk >> 16; 1252 packet[6] = 0; 1253 packet[7] = 0; 1254 v86.ctl = V86_FLAGS; 1255 v86.addr = 0x13; 1256 /* Should we Write with verify ?? 0x4302 ? */ 1257 v86.eax = 0x4300; 1258 v86.edx = od->od_unit; 1259 v86.ds = VTOPSEG(packet); 1260 v86.esi = VTOPOFF(packet); 1261 v86int(); 1262 result = (v86.efl & PSL_C); 1263 if (result == 0) 1264 break; 1265 } else if (cyl < 1024) { 1266 /* Use normal CHS addressing */ 1267 v86.ctl = V86_FLAGS; 1268 v86.addr = 0x13; 1269 v86.eax = 0x300 | x; 1270 v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 1271 v86.edx = (hd << 8) | od->od_unit; 1272 v86.es = VTOPSEG(xp); 1273 v86.ebx = VTOPOFF(xp); 1274 v86int(); 1275 result = (v86.efl & PSL_C); 1276 if (result == 0) 1277 break; 1278 } else { 1279 result = 1; 1280 break; 1281 } 1282 } 1283 1284 DEBUG("%u sectors from %u/%u/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); 1285 /* BUG here, cannot use v86 in printf because putchar uses it too */ 1286 DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 1287 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); 1288 if (result) 1289 return(-1); 1290 } 1291 1292 /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ 1293 return(0); 1294 } 1295 static int 1296 bd_getgeom(struct open_disk *od) 1297 { 1298 1299 v86.ctl = V86_FLAGS; 1300 v86.addr = 0x13; 1301 v86.eax = 0x800; 1302 v86.edx = od->od_unit; 1303 v86int(); 1304 1305 if ((v86.efl & PSL_C) || /* carry set */ 1306 ((v86.edx & 0xff) <= (unsigned)(od->od_unit & 0x7f))) /* unit # bad */ 1307 return(1); 1308 1309 /* convert max cyl # -> # of cylinders */ 1310 od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 1311 /* convert max head # -> # of heads */ 1312 od->od_hds = ((v86.edx & 0xff00) >> 8) + 1; 1313 od->od_sec = v86.ecx & 0x3f; 1314 1315 DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec); 1316 return(0); 1317 } 1318 1319 /* 1320 * Return the BIOS geometry of a given "fixed drive" in a format 1321 * suitable for the legacy bootinfo structure. Since the kernel is 1322 * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we 1323 * prefer to get the information directly, rather than rely on being 1324 * able to put it together from information already maintained for 1325 * different purposes and for a probably different number of drives. 1326 * 1327 * For valid drives, the geometry is expected in the format (31..0) 1328 * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are 1329 * indicated by returning the geometry of a "1.2M" PC-format floppy 1330 * disk. And, incidentally, what is returned is not the geometry as 1331 * such but the highest valid cylinder, head, and sector numbers. 1332 */ 1333 u_int32_t 1334 bd_getbigeom(int bunit) 1335 { 1336 1337 v86.ctl = V86_FLAGS; 1338 v86.addr = 0x13; 1339 v86.eax = 0x800; 1340 v86.edx = 0x80 + bunit; 1341 v86int(); 1342 if (v86.efl & PSL_C) 1343 return 0x4f010f; 1344 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 1345 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 1346 } 1347 1348 /* 1349 * Return a suitable cdev_t value for (dev). 1350 * 1351 * In the case where it looks like (dev) is a SCSI disk, we allow the number of 1352 * IDE disks to be specified in $num_ide_disks. There should be a Better Way. 1353 */ 1354 int 1355 bd_getdev(struct i386_devdesc *dev) 1356 { 1357 struct open_disk *od; 1358 int biosdev; 1359 int major; 1360 int rootdev; 1361 char *nip, *cp; 1362 int unitofs = 0, i, unit; 1363 1364 biosdev = bd_unit2bios(dev->d_kind.biosdisk.unit); 1365 DEBUG("unit %d BIOS device %d", dev->d_kind.biosdisk.unit, biosdev); 1366 if (biosdev == -1) /* not a BIOS device */ 1367 return(-1); 1368 if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */ 1369 return(-1); 1370 1371 if (biosdev < 0x80) { 1372 /* floppy (or emulated floppy) or ATAPI device */ 1373 if (bdinfo[dev->d_kind.biosdisk.unit].bd_type == DT_ATAPI) { 1374 /* is an ATAPI disk */ 1375 major = WFDMAJOR; 1376 } else { 1377 /* is a floppy disk */ 1378 major = FDMAJOR; 1379 } 1380 } else { 1381 /* harddisk */ 1382 if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) { 1383 /* label OK, disk labelled as SCSI */ 1384 major = DAMAJOR; 1385 /* check for unit number correction hint, now deprecated */ 1386 if ((nip = getenv("num_ide_disks")) != NULL) { 1387 i = strtol(nip, &cp, 0); 1388 /* check for parse error */ 1389 if ((cp != nip) && (*cp == 0)) 1390 unitofs = i; 1391 } 1392 } else { 1393 /* assume an IDE disk */ 1394 major = WDMAJOR; 1395 } 1396 } 1397 /* default root disk unit number */ 1398 unit = (biosdev & 0x7f) - unitofs; 1399 1400 /* XXX a better kludge to set the root disk unit number */ 1401 if ((nip = getenv("root_disk_unit")) != NULL) { 1402 i = strtol(nip, &cp, 0); 1403 /* check for parse error */ 1404 if ((cp != nip) && (*cp == 0)) 1405 unit = i; 1406 } 1407 1408 rootdev = MAKEBOOTDEV(major, dev->d_kind.biosdisk.slice + 1, unit, 1409 dev->d_kind.biosdisk.partition); 1410 DEBUG("dev is 0x%x\n", rootdev); 1411 return(rootdev); 1412 } 1413