biosdisk.c revision 346473
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/11/stand/i386/libi386/biosdisk.c 346473 2019-04-21 03:22:57Z kevans $"); 30 31/* 32 * BIOS disk device handling. 33 * 34 * Ideas and algorithms from: 35 * 36 * - NetBSD libi386/biosdisk.c 37 * - FreeBSD biosboot/disk.c 38 * 39 */ 40 41#include <sys/disk.h> 42#include <sys/limits.h> 43#include <stand.h> 44#include <machine/bootinfo.h> 45#include <stdarg.h> 46 47#include <bootstrap.h> 48#include <btxv86.h> 49#include <edd.h> 50#include "disk.h" 51#include "libi386.h" 52 53#define BIOS_NUMDRIVES 0x475 54#define BIOSDISK_SECSIZE 512 55#define BUFSIZE (1 * BIOSDISK_SECSIZE) 56 57#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ 58#define WDMAJOR 0 /* major numbers for devices we frontend for */ 59#define WFDMAJOR 1 60#define FDMAJOR 2 61#define DAMAJOR 4 62 63#ifdef DISK_DEBUG 64# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 65#else 66# define DEBUG(fmt, args...) 67#endif 68 69/* 70 * List of BIOS devices, translation from disk unit number to 71 * BIOS unit number. 72 */ 73static struct bdinfo 74{ 75 int bd_unit; /* BIOS unit number */ 76 int bd_cyl; /* BIOS geometry */ 77 int bd_hds; 78 int bd_sec; 79 int bd_flags; 80#define BD_MODEINT13 0x0000 81#define BD_MODEEDD1 0x0001 82#define BD_MODEEDD3 0x0002 83#define BD_MODEMASK 0x0003 84#define BD_FLOPPY 0x0004 85 int bd_type; /* BIOS 'drive type' (floppy only) */ 86 uint16_t bd_sectorsize; /* Sector size */ 87 uint64_t bd_sectors; /* Disk size */ 88 int bd_open; /* reference counter */ 89 void *bd_bcache; /* buffer cache data */ 90} bdinfo [MAXBDDEV]; 91static int nbdinfo = 0; 92 93#define BD(dev) (bdinfo[(dev)->dd.d_unit]) 94 95static void bd_io_workaround(struct disk_devdesc *dev); 96 97static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, 98 caddr_t dest); 99static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, 100 caddr_t dest); 101static int bd_int13probe(struct bdinfo *bd); 102 103static int bd_init(void); 104static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 105 char *buf, size_t *rsize); 106static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, 107 char *buf, size_t *rsize); 108static int bd_open(struct open_file *f, ...); 109static int bd_close(struct open_file *f); 110static int bd_ioctl(struct open_file *f, u_long cmd, void *data); 111static int bd_print(int verbose); 112 113struct devsw biosdisk = { 114 "disk", 115 DEVT_DISK, 116 bd_init, 117 bd_strategy, 118 bd_open, 119 bd_close, 120 bd_ioctl, 121 bd_print, 122 NULL 123}; 124 125/* 126 * Translate between BIOS device numbers and our private unit numbers. 127 */ 128int 129bd_bios2unit(int biosdev) 130{ 131 int i; 132 133 DEBUG("looking for bios device 0x%x", biosdev); 134 for (i = 0; i < nbdinfo; i++) { 135 DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); 136 if (bdinfo[i].bd_unit == biosdev) 137 return (i); 138 } 139 return (-1); 140} 141 142int 143bd_unit2bios(int unit) 144{ 145 146 if ((unit >= 0) && (unit < nbdinfo)) 147 return (bdinfo[unit].bd_unit); 148 return (-1); 149} 150 151/* 152 * Quiz the BIOS for disk devices, save a little info about them. 153 */ 154static int 155bd_init(void) 156{ 157 int base, unit, nfd = 0; 158 159 /* sequence 0, 0x80 */ 160 for (base = 0; base <= 0x80; base += 0x80) { 161 for (unit = base; (nbdinfo < MAXBDDEV); unit++) { 162#ifndef VIRTUALBOX 163 /* 164 * Check the BIOS equipment list for number 165 * of fixed disks. 166 */ 167 if(base == 0x80 && 168 (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) 169 break; 170#endif 171 bdinfo[nbdinfo].bd_open = 0; 172 bdinfo[nbdinfo].bd_bcache = NULL; 173 bdinfo[nbdinfo].bd_unit = unit; 174 bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0; 175 if (!bd_int13probe(&bdinfo[nbdinfo])) 176 break; 177 178 /* XXX we need "disk aliases" to make this simpler */ 179 printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ? 180 ('A' + unit): ('C' + unit - 0x80), nbdinfo); 181 nbdinfo++; 182 if (base == 0x80) 183 nfd++; 184 } 185 } 186 bcache_add_dev(nbdinfo); 187 return(0); 188} 189 190/* 191 * Try to detect a device supported by the legacy int13 BIOS 192 */ 193static int 194bd_int13probe(struct bdinfo *bd) 195{ 196 struct edd_params params; 197 int ret = 1; /* assume success */ 198 199 v86.ctl = V86_FLAGS; 200 v86.addr = 0x13; 201 v86.eax = 0x800; 202 v86.edx = bd->bd_unit; 203 v86int(); 204 205 /* Don't error out if we get bad sector number, try EDD as well */ 206 if (V86_CY(v86.efl) || /* carry set */ 207 (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */ 208 return (0); /* skip device */ 209 210 if ((v86.ecx & 0x3f) == 0) /* absurd sector number */ 211 ret = 0; /* set error */ 212 213 /* Convert max cyl # -> # of cylinders */ 214 bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 215 /* Convert max head # -> # of heads */ 216 bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; 217 bd->bd_sec = v86.ecx & 0x3f; 218 bd->bd_type = v86.ebx & 0xff; 219 bd->bd_flags |= BD_MODEINT13; 220 221 /* Calculate sectors count from the geometry */ 222 bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec; 223 bd->bd_sectorsize = BIOSDISK_SECSIZE; 224 DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, 225 bd->bd_hds, bd->bd_sec); 226 227 /* Determine if we can use EDD with this device. */ 228 v86.ctl = V86_FLAGS; 229 v86.addr = 0x13; 230 v86.eax = 0x4100; 231 v86.edx = bd->bd_unit; 232 v86.ebx = 0x55aa; 233 v86int(); 234 if (V86_CY(v86.efl) || /* carry set */ 235 (v86.ebx & 0xffff) != 0xaa55 || /* signature */ 236 (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) 237 return (ret); /* return code from int13 AH=08 */ 238 239 /* EDD supported */ 240 bd->bd_flags |= BD_MODEEDD1; 241 if ((v86.eax & 0xff00) >= 0x3000) 242 bd->bd_flags |= BD_MODEEDD3; 243 /* Get disk params */ 244 params.len = sizeof(struct edd_params); 245 v86.ctl = V86_FLAGS; 246 v86.addr = 0x13; 247 v86.eax = 0x4800; 248 v86.edx = bd->bd_unit; 249 v86.ds = VTOPSEG(¶ms); 250 v86.esi = VTOPOFF(¶ms); 251 v86int(); 252 if (!V86_CY(v86.efl)) { 253 uint64_t total; 254 255 /* 256 * Sector size must be a multiple of 512 bytes. 257 * An alternate test would be to check power of 2, 258 * powerof2(params.sector_size). 259 */ 260 if (params.sector_size % BIOSDISK_SECSIZE) 261 bd->bd_sectorsize = BIOSDISK_SECSIZE; 262 else 263 bd->bd_sectorsize = params.sector_size; 264 265 total = bd->bd_sectorsize * params.sectors; 266 if (params.sectors != 0) { 267 /* Only update if we did not overflow. */ 268 if (total > params.sectors) 269 bd->bd_sectors = params.sectors; 270 } 271 272 total = (uint64_t)params.cylinders * 273 params.heads * params.sectors_per_track; 274 if (total > 0 && bd->bd_sectors > total) 275 bd->bd_sectors = total; 276 277 ret = 1; 278 } 279 DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u", 280 bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize); 281 return (ret); 282} 283 284/* 285 * Print information about disks 286 */ 287static int 288bd_print(int verbose) 289{ 290 static char line[80]; 291 struct disk_devdesc dev; 292 int i, ret = 0; 293 294 if (nbdinfo == 0) 295 return (0); 296 297 printf("%s devices:", biosdisk.dv_name); 298 if ((ret = pager_output("\n")) != 0) 299 return (ret); 300 301 for (i = 0; i < nbdinfo; i++) { 302 snprintf(line, sizeof(line), 303 " disk%d: BIOS drive %c (%ju X %u):\n", i, 304 (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): 305 ('C' + bdinfo[i].bd_unit - 0x80), 306 (uintmax_t)bdinfo[i].bd_sectors, 307 bdinfo[i].bd_sectorsize); 308 if ((ret = pager_output(line)) != 0) 309 break; 310 dev.dd.d_dev = &biosdisk; 311 dev.dd.d_unit = i; 312 dev.d_slice = -1; 313 dev.d_partition = -1; 314 if (disk_open(&dev, 315 bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, 316 bdinfo[i].bd_sectorsize) == 0) { 317 snprintf(line, sizeof(line), " disk%d", i); 318 ret = disk_print(&dev, line, verbose); 319 disk_close(&dev); 320 if (ret != 0) 321 return (ret); 322 } 323 } 324 return (ret); 325} 326 327/* 328 * Attempt to open the disk described by (dev) for use by (f). 329 * 330 * Note that the philosophy here is "give them exactly what 331 * they ask for". This is necessary because being too "smart" 332 * about what the user might want leads to complications. 333 * (eg. given no slice or partition value, with a disk that is 334 * sliced - are they after the first BSD slice, or the DOS 335 * slice before it?) 336 */ 337static int 338bd_open(struct open_file *f, ...) 339{ 340 struct disk_devdesc *dev, rdev; 341 struct disk_devdesc disk; 342 int err, g_err; 343 va_list ap; 344 uint64_t size; 345 346 va_start(ap, f); 347 dev = va_arg(ap, struct disk_devdesc *); 348 va_end(ap); 349 350 if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo) 351 return (EIO); 352 BD(dev).bd_open++; 353 if (BD(dev).bd_bcache == NULL) 354 BD(dev).bd_bcache = bcache_allocate(); 355 356 /* 357 * Read disk size from partition. 358 * This is needed to work around buggy BIOS systems returning 359 * wrong (truncated) disk media size. 360 * During bd_probe() we tested if the mulitplication of bd_sectors 361 * would overflow so it should be safe to perform here. 362 */ 363 disk.dd.d_dev = dev->dd.d_dev; 364 disk.dd.d_unit = dev->dd.d_unit; 365 disk.d_slice = -1; 366 disk.d_partition = -1; 367 disk.d_offset = 0; 368 if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, 369 BD(dev).bd_sectorsize) == 0) { 370 371 if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { 372 size /= BD(dev).bd_sectorsize; 373 if (size > BD(dev).bd_sectors) 374 BD(dev).bd_sectors = size; 375 } 376 disk_close(&disk); 377 } 378 379 err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, 380 BD(dev).bd_sectorsize); 381 382 return (err); 383} 384 385static int 386bd_close(struct open_file *f) 387{ 388 struct disk_devdesc *dev; 389 390 dev = (struct disk_devdesc *)f->f_devdata; 391 BD(dev).bd_open--; 392 if (BD(dev).bd_open == 0) { 393 bcache_free(BD(dev).bd_bcache); 394 BD(dev).bd_bcache = NULL; 395 } 396 return (disk_close(dev)); 397} 398 399static int 400bd_ioctl(struct open_file *f, u_long cmd, void *data) 401{ 402 struct disk_devdesc *dev; 403 int rc; 404 405 dev = (struct disk_devdesc *)f->f_devdata; 406 407 rc = disk_ioctl(dev, cmd, data); 408 if (rc != ENOTTY) 409 return (rc); 410 411 switch (cmd) { 412 case DIOCGSECTORSIZE: 413 *(u_int *)data = BD(dev).bd_sectorsize; 414 break; 415 case DIOCGMEDIASIZE: 416 *(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; 417 break; 418 default: 419 return (ENOTTY); 420 } 421 return (0); 422} 423 424static int 425bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 426 char *buf, size_t *rsize) 427{ 428 struct bcache_devdata bcd; 429 struct disk_devdesc *dev; 430 431 dev = (struct disk_devdesc *)devdata; 432 bcd.dv_strategy = bd_realstrategy; 433 bcd.dv_devdata = devdata; 434 bcd.dv_cache = BD(dev).bd_bcache; 435 return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, 436 size, buf, rsize)); 437} 438 439static int 440bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, 441 char *buf, size_t *rsize) 442{ 443 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 444 uint64_t disk_blocks; 445 int blks, rc; 446#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ 447 char fragbuf[BIOSDISK_SECSIZE]; 448 size_t fragsize; 449 450 fragsize = size % BIOSDISK_SECSIZE; 451#else 452 if (size % BD(dev).bd_sectorsize) 453 panic("bd_strategy: %d bytes I/O not multiple of block size", size); 454#endif 455 456 DEBUG("open_disk %p", dev); 457 458 /* 459 * Check the value of the size argument. We do have quite small 460 * heap (64MB), but we do not know good upper limit, so we check against 461 * INT_MAX here. This will also protect us against possible overflows 462 * while translating block count to bytes. 463 */ 464 if (size > INT_MAX) { 465 DEBUG("too large read: %zu bytes", size); 466 return (EIO); 467 } 468 469 blks = size / BD(dev).bd_sectorsize; 470 if (dblk > dblk + blks) 471 return (EIO); 472 473 if (rsize) 474 *rsize = 0; 475 476 /* Get disk blocks, this value is either for whole disk or for partition */ 477 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { 478 /* DIOCGMEDIASIZE returns bytes. */ 479 disk_blocks /= BD(dev).bd_sectorsize; 480 } else { 481 /* We should not get here. Just try to survive. */ 482 disk_blocks = BD(dev).bd_sectors - dev->d_offset; 483 } 484 485 /* Validate source block address. */ 486 if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks) 487 return (EIO); 488 489 /* 490 * Truncate if we are crossing disk or partition end. 491 */ 492 if (dblk + blks >= dev->d_offset + disk_blocks) { 493 blks = dev->d_offset + disk_blocks - dblk; 494 size = blks * BD(dev).bd_sectorsize; 495 DEBUG("short read %d", blks); 496 } 497 498 switch (rw & F_MASK) { 499 case F_READ: 500 DEBUG("read %d from %lld to %p", blks, dblk, buf); 501 502 if (blks && (rc = bd_read(dev, dblk, blks, buf))) { 503 /* Filter out floppy controller errors */ 504 if (BD(dev).bd_flags != BD_FLOPPY || rc != 0x20) { 505 printf("read %d from %lld to %p, error: 0x%x\n", blks, dblk, 506 buf, rc); 507 } 508 return (EIO); 509 } 510#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ 511 DEBUG("bd_strategy: frag read %d from %d+%d to %p", 512 fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); 513 if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { 514 DEBUG("frag read error"); 515 return(EIO); 516 } 517 bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); 518#endif 519 break; 520 case F_WRITE : 521 DEBUG("write %d from %lld to %p", blks, dblk, buf); 522 523 if (blks && bd_write(dev, dblk, blks, buf)) { 524 DEBUG("write error"); 525 return (EIO); 526 } 527#ifdef BD_SUPPORT_FRAGS 528 if(fragsize) { 529 DEBUG("Attempted to write a frag"); 530 return (EIO); 531 } 532#endif 533 break; 534 default: 535 /* DO NOTHING */ 536 return (EROFS); 537 } 538 539 if (rsize) 540 *rsize = size; 541 return (0); 542} 543 544static int 545bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, 546 int write) 547{ 548 static struct edd_packet packet; 549 550 packet.len = sizeof(struct edd_packet); 551 packet.count = blks; 552 packet.off = VTOPOFF(dest); 553 packet.seg = VTOPSEG(dest); 554 packet.lba = dblk; 555 v86.ctl = V86_FLAGS; 556 v86.addr = 0x13; 557 if (write) 558 /* Should we Write with verify ?? 0x4302 ? */ 559 v86.eax = 0x4300; 560 else 561 v86.eax = 0x4200; 562 v86.edx = BD(dev).bd_unit; 563 v86.ds = VTOPSEG(&packet); 564 v86.esi = VTOPOFF(&packet); 565 v86int(); 566 if (V86_CY(v86.efl)) 567 return (v86.eax >> 8); 568 return (0); 569} 570 571static int 572bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, 573 int write) 574{ 575 u_int x, bpc, cyl, hd, sec; 576 577 bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */ 578 x = dblk; 579 cyl = x / bpc; /* block # / blocks per cylinder */ 580 x %= bpc; /* block offset into cylinder */ 581 hd = x / BD(dev).bd_sec; /* offset / blocks per track */ 582 sec = x % BD(dev).bd_sec; /* offset into track */ 583 584 /* correct sector number for 1-based BIOS numbering */ 585 sec++; 586 587 if (cyl > 1023) 588 /* CHS doesn't support cylinders > 1023. */ 589 return (1); 590 591 v86.ctl = V86_FLAGS; 592 v86.addr = 0x13; 593 if (write) 594 v86.eax = 0x300 | blks; 595 else 596 v86.eax = 0x200 | blks; 597 v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 598 v86.edx = (hd << 8) | BD(dev).bd_unit; 599 v86.es = VTOPSEG(dest); 600 v86.ebx = VTOPOFF(dest); 601 v86int(); 602 if (V86_CY(v86.efl)) 603 return (v86.eax >> 8); 604 return (0); 605} 606 607static void 608bd_io_workaround(struct disk_devdesc *dev) 609{ 610 uint8_t buf[8 * 1024]; 611 612 bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, 0); 613} 614 615 616static int 617bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) 618{ 619 u_int x, sec, result, resid, retry, maxfer; 620 caddr_t p, xp, bbuf; 621 622 /* Just in case some idiot actually tries to read/write -1 blocks... */ 623 if (blks < 0) 624 return (-1); 625 626 resid = blks; 627 p = dest; 628 629 /* 630 * Workaround for a problem with some HP ProLiant BIOS failing to work out 631 * the boot disk after installation. hrs and kuriyama discovered this 632 * problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and discovered 633 * that an int13h call seems to cause a buffer overrun in the bios. The 634 * problem is alleviated by doing an extra read before the buggy read. It 635 * is not immediately known whether other models are similarly affected. 636 */ 637 if (dblk >= 0x100000000) 638 bd_io_workaround(dev); 639 640 /* Decide whether we have to bounce */ 641 if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 && 642 (VTOP(dest) >> 16) != (VTOP(dest + 643 blks * BD(dev).bd_sectorsize) >> 16))) { 644 645 /* 646 * There is a 64k physical boundary somewhere in the 647 * destination buffer, or the destination buffer is above 648 * first 1MB of physical memory so we have to arrange a 649 * suitable bounce buffer. Allocate a buffer twice as large 650 * as we need to. Use the bottom half unless there is a break 651 * there, in which case we use the top half. 652 */ 653 x = V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize; 654 x = min(x, (unsigned)blks); 655 bbuf = PTOV(V86_IO_BUFFER); 656 maxfer = x; /* limit transfers to bounce region size */ 657 } else { 658 bbuf = NULL; 659 maxfer = 0; 660 } 661 662 while (resid > 0) { 663 /* 664 * Play it safe and don't cross track boundaries. 665 * (XXX this is probably unnecessary) 666 */ 667 sec = dblk % BD(dev).bd_sec; /* offset into track */ 668 x = min(BD(dev).bd_sec - sec, resid); 669 if (maxfer > 0) 670 x = min(x, maxfer); /* fit bounce buffer */ 671 672 /* where do we transfer to? */ 673 xp = bbuf == NULL ? p : bbuf; 674 675 /* 676 * Put your Data In, Put your Data out, 677 * Put your Data In, and shake it all about 678 */ 679 if (write && bbuf != NULL) 680 bcopy(p, bbuf, x * BD(dev).bd_sectorsize); 681 682 /* 683 * Loop retrying the operation a couple of times. The BIOS 684 * may also retry. 685 */ 686 for (retry = 0; retry < 3; retry++) { 687 /* if retrying, reset the drive */ 688 if (retry > 0) { 689 v86.ctl = V86_FLAGS; 690 v86.addr = 0x13; 691 v86.eax = 0; 692 v86.edx = BD(dev).bd_unit; 693 v86int(); 694 } 695 696 if (BD(dev).bd_flags & BD_MODEEDD1) 697 result = bd_edd_io(dev, dblk, x, xp, write); 698 else 699 result = bd_chs_io(dev, dblk, x, xp, write); 700 if (result == 0) 701 break; 702 } 703 704 if (write) 705 DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x, 706 p, VTOP(p), dblk, result ? "failed" : "ok"); 707 else 708 DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, 709 dblk, p, VTOP(p), result ? "failed" : "ok"); 710 if (result) { 711 return (result); 712 } 713 if (!write && bbuf != NULL) 714 bcopy(bbuf, p, x * BD(dev).bd_sectorsize); 715 p += (x * BD(dev).bd_sectorsize); 716 dblk += x; 717 resid -= x; 718 } 719 720/* hexdump(dest, (blks * BD(dev).bd_sectorsize)); */ 721 return(0); 722} 723 724static int 725bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) 726{ 727 728 return (bd_io(dev, dblk, blks, dest, 0)); 729} 730 731static int 732bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) 733{ 734 735 return (bd_io(dev, dblk, blks, dest, 1)); 736} 737 738/* 739 * Return the BIOS geometry of a given "fixed drive" in a format 740 * suitable for the legacy bootinfo structure. Since the kernel is 741 * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we 742 * prefer to get the information directly, rather than rely on being 743 * able to put it together from information already maintained for 744 * different purposes and for a probably different number of drives. 745 * 746 * For valid drives, the geometry is expected in the format (31..0) 747 * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are 748 * indicated by returning the geometry of a "1.2M" PC-format floppy 749 * disk. And, incidentally, what is returned is not the geometry as 750 * such but the highest valid cylinder, head, and sector numbers. 751 */ 752uint32_t 753bd_getbigeom(int bunit) 754{ 755 756 v86.ctl = V86_FLAGS; 757 v86.addr = 0x13; 758 v86.eax = 0x800; 759 v86.edx = 0x80 + bunit; 760 v86int(); 761 if (V86_CY(v86.efl)) 762 return 0x4f010f; 763 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 764 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 765} 766 767/* 768 * Return a suitable dev_t value for (dev). 769 * 770 * In the case where it looks like (dev) is a SCSI disk, we allow the number of 771 * IDE disks to be specified in $num_ide_disks. There should be a Better Way. 772 */ 773int 774bd_getdev(struct i386_devdesc *d) 775{ 776 struct disk_devdesc *dev; 777 int biosdev; 778 int major; 779 int rootdev; 780 char *nip, *cp; 781 int i, unit; 782 783 dev = (struct disk_devdesc *)d; 784 biosdev = bd_unit2bios(dev->dd.d_unit); 785 DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev); 786 if (biosdev == -1) /* not a BIOS device */ 787 return(-1); 788 if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, 789 BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */ 790 return (-1); 791 else 792 disk_close(dev); 793 794 if (biosdev < 0x80) { 795 /* floppy (or emulated floppy) or ATAPI device */ 796 if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) { 797 /* is an ATAPI disk */ 798 major = WFDMAJOR; 799 } else { 800 /* is a floppy disk */ 801 major = FDMAJOR; 802 } 803 } else { 804 /* assume an IDE disk */ 805 major = WDMAJOR; 806 } 807 /* default root disk unit number */ 808 unit = biosdev & 0x7f; 809 810 /* XXX a better kludge to set the root disk unit number */ 811 if ((nip = getenv("root_disk_unit")) != NULL) { 812 i = strtol(nip, &cp, 0); 813 /* check for parse error */ 814 if ((cp != nip) && (*cp == 0)) 815 unit = i; 816 } 817 818 rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition); 819 DEBUG("dev is 0x%x\n", rootdev); 820 return(rootdev); 821} 822