1 /* $OpenBSD: biosdev.c,v 1.98 2018/09/06 11:50:54 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Michael Shalayeff 5 * Copyright (c) 2003 Tobias Weingartner 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/disklabel.h> 34 #include <isofs/cd9660/iso.h> 35 #include <lib/libsa/saerrno.h> 36 #include <machine/biosvar.h> 37 #include <machine/tss.h> 38 39 #include "biosdev.h" 40 #include "debug.h" 41 #include "disk.h" 42 #include "libsa.h" 43 44 #ifdef SOFTRAID 45 #include <dev/softraidvar.h> 46 #include <lib/libsa/softraid.h> 47 #include "softraid_i386.h" 48 #endif 49 50 static const char *biosdisk_err(u_int); 51 static int biosdisk_errno(u_int); 52 53 int CHS_rw (int, int, int, int, int, int, void *); 54 static int EDD_rw (int, int, u_int32_t, u_int32_t, void *); 55 56 static int biosd_io(int, bios_diskinfo_t *, u_int, int, void *); 57 static u_int findopenbsd(bios_diskinfo_t *, const char **); 58 59 extern int debug; 60 int bios_bootdev; 61 int bios_cddev = -1; /* Set by srt0 if coming from CD */ 62 63 struct EDD_CB { 64 u_int8_t edd_len; /* size of packet */ 65 u_int8_t edd_res1; /* reserved */ 66 u_int8_t edd_nblk; /* # of blocks to transfer */ 67 u_int8_t edd_res2; /* reserved */ 68 u_int16_t edd_off; /* address of buffer (offset) */ 69 u_int16_t edd_seg; /* address of buffer (segment) */ 70 u_int64_t edd_daddr; /* starting block */ 71 }; 72 73 /* 74 * reset disk system 75 */ 76 static int 77 biosdreset(int dev) 78 { 79 int rv; 80 81 __asm volatile (DOINT(0x13) "; setc %b0" : "=a" (rv) 82 : "0" (0), "d" (dev) : "%ecx", "cc"); 83 84 return ((rv & 0xff)? rv >> 8 : 0); 85 } 86 87 /* 88 * Fill out a bios_diskinfo_t for this device. 89 * Return 0 if all ok. 90 * Return 1 if not ok. 91 */ 92 int 93 bios_getdiskinfo(int dev, bios_diskinfo_t *pdi) 94 { 95 u_int rv; 96 97 /* Just reset, don't check return code */ 98 rv = biosdreset(dev); 99 100 #ifdef BIOS_DEBUG 101 if (debug) 102 printf("getinfo: try #8, 0x%x, %p\n", dev, pdi); 103 #endif 104 __asm volatile (DOINT(0x13) "\n\t" 105 "setc %b0; movzbl %h1, %1\n\t" 106 "movzbl %%cl, %3; andb $0x3f, %b3\n\t" 107 "xchgb %%cl, %%ch; rolb $2, %%ch" 108 : "=a" (rv), "=d" (pdi->bios_heads), 109 "=c" (pdi->bios_cylinders), 110 "=b" (pdi->bios_sectors) 111 : "0" (0x0800), "1" (dev) : "cc"); 112 113 #ifdef BIOS_DEBUG 114 if (debug) { 115 printf("getinfo: got #8\n"); 116 printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders, 117 pdi->bios_heads, pdi->bios_sectors); 118 } 119 #endif 120 if (rv & 0xff) 121 return 1; 122 123 /* Fix up info */ 124 pdi->bios_number = dev; 125 pdi->bios_heads++; 126 pdi->bios_cylinders &= 0x3ff; 127 pdi->bios_cylinders++; 128 129 /* NOTE: 130 * This currently hangs/reboots some machines 131 * The IBM ThinkPad 750ED for one. 132 * 133 * Funny that an IBM/MS extension would not be 134 * implemented by an IBM system... 135 * 136 * Future hangs (when reported) can be "fixed" 137 * with getSYSCONFaddr() and an exceptions list. 138 */ 139 if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev == bios_bootdev)) { 140 int bm; 141 142 #ifdef BIOS_DEBUG 143 if (debug) 144 printf("getinfo: try #41, 0x%x\n", dev); 145 #endif 146 /* EDD support check */ 147 __asm volatile(DOINT(0x13) "; setc %b0" 148 : "=a" (rv), "=c" (bm) 149 : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc"); 150 if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55) 151 pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16); 152 else 153 pdi->bios_edd = -1; 154 155 #ifdef BIOS_DEBUG 156 if (debug) { 157 printf("getinfo: got #41\n"); 158 printf("disk 0x%x: 0x%x\n", dev, bm); 159 } 160 #endif 161 /* 162 * If extended disk access functions are not supported 163 * there is not much point on doing EDD. 164 */ 165 if (!(pdi->bios_edd & EXT_BM_EDA)) 166 pdi->bios_edd = -1; 167 } else 168 pdi->bios_edd = -1; 169 170 /* Skip sanity check for CHS options in EDD mode. */ 171 if (pdi->bios_edd != -1) 172 return 0; 173 174 /* Sanity check */ 175 if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors) 176 return 1; 177 178 /* CD-ROMs sometimes return heads == 1 */ 179 if (pdi->bios_heads < 2) 180 return 1; 181 182 return 0; 183 } 184 185 /* 186 * Read/Write a block from given place using the BIOS. 187 */ 188 int 189 CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf) 190 { 191 int rv; 192 193 rw = rw == F_READ ? 2 : 3; 194 BIOS_regs.biosr_es = (u_int32_t)buf >> 4; 195 __asm volatile ("movb %b7, %h1\n\t" 196 "movb %b6, %%dh\n\t" 197 "andl $0xf, %4\n\t" 198 /* cylinder; the highest 2 bits of cyl is in %cl */ 199 "xchgb %%ch, %%cl\n\t" 200 "rorb $2, %%cl\n\t" 201 "orb %b5, %%cl\n\t" 202 "inc %%cx\n\t" 203 DOINT(0x13) "\n\t" 204 "setc %b0" 205 : "=a" (rv) 206 : "0" (nsect), "d" (dev), "c" (cyl), 207 "b" (buf), "m" (sect), "m" (head), 208 "m" (rw) 209 : "cc", "memory"); 210 211 return ((rv & 0xff)? rv >> 8 : 0); 212 } 213 214 static __inline int 215 EDD_rw(int rw, int dev, u_int32_t daddr, u_int32_t nblk, void *buf) 216 { 217 int rv; 218 volatile static struct EDD_CB cb; 219 220 /* Zero out reserved stuff */ 221 cb.edd_res1 = 0; 222 cb.edd_res2 = 0; 223 224 /* Fill in parameters */ 225 cb.edd_len = sizeof(cb); 226 cb.edd_nblk = nblk; 227 cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff; 228 cb.edd_off = (u_int32_t)buf & 0xf; 229 cb.edd_daddr = daddr; 230 231 /* if offset/segment are zero, punt */ 232 if (!cb.edd_seg && !cb.edd_off) 233 return 1; 234 235 /* Call extended read/write (with disk packet) */ 236 BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4; 237 __asm volatile (DOINT(0x13) "; setc %b0" : "=a" (rv) 238 : "0" ((rw == F_READ)? 0x4200: 0x4300), 239 "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc"); 240 return ((rv & 0xff)? rv >> 8 : 0); 241 } 242 243 /* 244 * Read given sector, handling retry/errors/etc. 245 */ 246 int 247 biosd_io(int rw, bios_diskinfo_t *bd, u_int off, int nsect, void *buf) 248 { 249 int dev = bd->bios_number; 250 int j, error; 251 void *bb, *bb1 = NULL; 252 int bbsize = nsect * DEV_BSIZE; 253 254 if (bd->flags & BDI_EL_TORITO) { /* It's a CD device */ 255 dev &= 0xff; /* Mask out this flag bit */ 256 257 /* 258 * sys/lib/libsa/cd9600.c converts 2,048-byte CD sectors 259 * to DEV_BSIZE blocks before calling the device strategy 260 * routine. However, the El Torito spec says that the 261 * BIOS will work in 2,048-byte sectors. So shift back. 262 */ 263 off /= (ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE); 264 nsect /= (ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE); 265 } 266 267 /* 268 * Use a bounce buffer to not cross 64k DMA boundary, and to 269 * not access 1 MB or above. 270 */ 271 if (((((u_int32_t)buf) & ~0xffff) != 272 (((u_int32_t)buf + bbsize) & ~0xffff)) || 273 (((u_int32_t)buf) >= 0x100000)) { 274 bb = bb1 = alloc(bbsize * 2); 275 if ((((u_int32_t)bb) & ~0xffff) != 276 (((u_int32_t)bb + bbsize - 1) & ~0xffff)) 277 bb = (void *)(((u_int32_t)bb + bbsize - 1) & ~0xffff); 278 if (rw != F_READ) 279 bcopy(buf, bb, bbsize); 280 } else 281 bb = buf; 282 283 /* Try to do operation up to 5 times */ 284 for (error = 1, j = 5; j-- && error; ) { 285 /* CHS or LBA access? */ 286 if (bd->bios_edd != -1) { 287 error = EDD_rw(rw, dev, off, nsect, bb); 288 } else { 289 int cyl, head, sect; 290 size_t i, n; 291 char *p = bb; 292 293 /* Handle track boundaries */ 294 for (error = i = 0; error == 0 && i < nsect; 295 i += n, off += n, p += n * DEV_BSIZE) { 296 297 btochs(off, cyl, head, sect, bd->bios_heads, 298 bd->bios_sectors); 299 300 if ((sect + (nsect - i)) >= bd->bios_sectors) 301 n = bd->bios_sectors - sect; 302 else 303 n = nsect - i; 304 305 error = CHS_rw(rw, dev, cyl, head, sect, n, p); 306 307 /* ECC corrected */ 308 if (error == 0x11) 309 error = 0; 310 } 311 } 312 switch (error) { 313 case 0x00: /* No errors */ 314 case 0x11: /* ECC corrected */ 315 error = 0; 316 break; 317 318 default: /* All other errors */ 319 #ifdef BIOS_DEBUG 320 if (debug) 321 printf("\nBIOS error 0x%x (%s)\n", 322 error, biosdisk_err(error)); 323 #endif 324 biosdreset(dev); 325 break; 326 } 327 } 328 329 if (bb != buf && rw == F_READ) 330 bcopy(bb, buf, bbsize); 331 free(bb1, bbsize * 2); 332 333 #ifdef BIOS_DEBUG 334 if (debug) { 335 if (error != 0) 336 printf("=0x%x(%s)", error, biosdisk_err(error)); 337 putchar('\n'); 338 } 339 #endif 340 341 return error; 342 } 343 344 int 345 biosd_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 346 { 347 return biosd_io(rw, &dip->bios_info, off, nsect, buf); 348 } 349 /* 350 * Try to read the bsd label on the given BIOS device. 351 */ 352 static u_int 353 findopenbsd(bios_diskinfo_t *bd, const char **err) 354 { 355 struct dos_mbr mbr; 356 struct dos_partition *dp; 357 u_int mbroff = DOSBBSECTOR; 358 u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ 359 int error, i, maxebr = DOS_MAXEBR, nextebr; 360 361 again: 362 if (!maxebr--) { 363 *err = "too many extended partitions"; 364 return (-1); 365 } 366 367 /* Read MBR */ 368 bzero(&mbr, sizeof(mbr)); 369 error = biosd_io(F_READ, bd, mbroff, 1, &mbr); 370 if (error) { 371 *err = biosdisk_err(error); 372 return (-1); 373 } 374 375 /* check mbr signature */ 376 if (mbr.dmbr_sign != DOSMBR_SIGNATURE) { 377 *err = "bad MBR signature\n"; 378 return (-1); 379 } 380 381 /* Search for OpenBSD partition */ 382 nextebr = 0; 383 for (i = 0; i < NDOSPART; i++) { 384 dp = &mbr.dmbr_parts[i]; 385 if (!dp->dp_size) 386 continue; 387 #ifdef BIOS_DEBUG 388 if (debug) 389 printf("found partition %u: " 390 "type %u (0x%x) offset %u (0x%x)\n", 391 (int)(dp - mbr.dmbr_parts), 392 dp->dp_typ, dp->dp_typ, 393 dp->dp_start, dp->dp_start); 394 #endif 395 if (dp->dp_typ == DOSPTYP_OPENBSD) { 396 if (dp->dp_start > (dp->dp_start + mbroff)) 397 continue; 398 return (dp->dp_start + mbroff); 399 } 400 401 /* 402 * Record location of next ebr if and only if this is the first 403 * extended partition in this boot record! 404 */ 405 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || 406 dp->dp_typ == DOSPTYP_EXTENDL)) { 407 nextebr = dp->dp_start + mbr_eoff; 408 if (nextebr < dp->dp_start) 409 nextebr = (u_int)-1; 410 if (mbr_eoff == DOSBBSECTOR) 411 mbr_eoff = dp->dp_start; 412 } 413 } 414 415 if (nextebr && nextebr != (u_int)-1) { 416 mbroff = nextebr; 417 goto again; 418 } 419 420 return (-1); 421 } 422 423 const char * 424 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) 425 { 426 u_int start = 0; 427 char buf[DEV_BSIZE]; 428 const char *err = NULL; 429 int error; 430 431 /* Sanity check */ 432 if (bd->bios_edd == -1 && 433 (bd->bios_heads == 0 || bd->bios_sectors == 0)) 434 return "failed to read disklabel"; 435 436 /* MBR is a harddisk thing */ 437 if (bd->bios_number & 0x80) { 438 start = findopenbsd(bd, &err); 439 if (start == (u_int)-1) { 440 if (err != NULL) 441 return (err); 442 return "no OpenBSD partition\n"; 443 } 444 } 445 446 /* Load BSD disklabel */ 447 #ifdef BIOS_DEBUG 448 if (debug) 449 printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR); 450 #endif 451 /* read disklabel */ 452 error = biosd_io(F_READ, bd, start + DOS_LABELSECTOR, 1, buf); 453 454 if (error) 455 return "failed to read disklabel"; 456 457 /* Fill in disklabel */ 458 return (getdisklabel(buf, label)); 459 } 460 461 int 462 biosopen(struct open_file *f, ...) 463 { 464 #ifdef SOFTRAID 465 struct sr_boot_volume *bv; 466 #endif 467 register char *cp, **file; 468 dev_t maj, unit, part; 469 struct diskinfo *dip; 470 int biosdev, devlen; 471 const char *st; 472 va_list ap; 473 char *dev; 474 475 va_start(ap, f); 476 cp = *(file = va_arg(ap, char **)); 477 va_end(ap); 478 479 #ifdef BIOS_DEBUG 480 if (debug) 481 printf("%s\n", cp); 482 #endif 483 484 f->f_devdata = NULL; 485 486 /* Search for device specification. */ 487 dev = cp; 488 if (cp[4] == ':') 489 devlen = 2; 490 else if (cp[5] == ':') 491 devlen = 3; 492 else 493 return ENOENT; 494 cp += devlen; 495 496 /* Get unit. */ 497 if ('0' <= *cp && *cp <= '9') 498 unit = *cp++ - '0'; 499 else { 500 printf("Bad unit number\n"); 501 return EUNIT; 502 } 503 504 /* Get partition. */ 505 if ('a' <= *cp && *cp <= 'p') 506 part = *cp++ - 'a'; 507 else { 508 printf("Bad partition\n"); 509 return EPART; 510 } 511 512 /* Get filename. */ 513 cp++; /* skip ':' */ 514 if (*cp != 0) 515 *file = cp; 516 else 517 f->f_flags |= F_RAW; 518 519 #ifdef SOFTRAID 520 /* Intercept softraid disks. */ 521 if (strncmp("sr", dev, 2) == 0) { 522 523 /* Create a fake diskinfo for this softraid volume. */ 524 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 525 if (bv->sbv_unit == unit) 526 break; 527 if (bv == NULL) { 528 printf("Unknown device: sr%d\n", unit); 529 return EADAPT; 530 } 531 532 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 533 if (sr_crypto_unlock_volume(bv) != 0) 534 return EPERM; 535 536 if (bv->sbv_diskinfo == NULL) { 537 dip = alloc(sizeof(struct diskinfo)); 538 bzero(dip, sizeof(*dip)); 539 dip->strategy = biosstrategy; 540 bv->sbv_diskinfo = dip; 541 dip->sr_vol = bv; 542 dip->bios_info.flags |= BDI_BADLABEL; 543 } 544 545 dip = bv->sbv_diskinfo; 546 547 if (dip->bios_info.flags & BDI_BADLABEL) { 548 /* Attempt to read disklabel. */ 549 bv->sbv_part = 'c'; 550 if (sr_getdisklabel(bv, &dip->disklabel)) 551 return ERDLAB; 552 dip->bios_info.flags &= ~BDI_BADLABEL; 553 check_hibernate(dip); 554 } 555 556 bv->sbv_part = part + 'a'; 557 558 bootdev_dip = dip; 559 f->f_devdata = dip; 560 561 return 0; 562 } 563 #endif 564 565 for (maj = 0; maj < nbdevs && 566 strncmp(dev, bdevs[maj], devlen); maj++); 567 if (maj >= nbdevs) { 568 printf("Unknown device: "); 569 for (cp = *file; *cp != ':'; cp++) 570 putchar(*cp); 571 putchar('\n'); 572 return EADAPT; 573 } 574 575 biosdev = unit; 576 switch (maj) { 577 case 0: /* wd */ 578 case 4: /* sd */ 579 case 17: /* hd */ 580 biosdev |= 0x80; 581 break; 582 case 2: /* fd */ 583 break; 584 case 6: /* cd */ 585 biosdev = bios_bootdev & 0xff; 586 break; 587 default: 588 return ENXIO; 589 } 590 591 /* Find device */ 592 bootdev_dip = dip = dklookup(biosdev); 593 594 /* Fix up bootdev */ 595 { dev_t bsd_dev; 596 bsd_dev = dip->bios_info.bsd_dev; 597 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 598 B_CONTROLLER(bsd_dev), unit, part); 599 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 600 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part); 601 } 602 603 #if 0 604 dip->bios_info.bsd_dev = dip->bootdev; 605 bootdev = dip->bootdev; 606 #endif 607 608 #ifdef BIOS_DEBUG 609 if (debug) { 610 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n", 611 dip->bios_info.bios_heads, dip->bios_info.bios_sectors, 612 dip->bios_info.bios_edd); 613 } 614 #endif 615 616 /* Try for disklabel again (might be removable media) */ 617 if (dip->bios_info.flags & BDI_BADLABEL) { 618 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel); 619 #ifdef BIOS_DEBUG 620 if (debug && st) 621 printf("%s\n", st); 622 #endif 623 if (!st) { 624 dip->bios_info.flags &= ~BDI_BADLABEL; 625 dip->bios_info.flags |= BDI_GOODLABEL; 626 } else 627 return ERDLAB; 628 } 629 630 f->f_devdata = dip; 631 632 return 0; 633 } 634 635 const u_char bidos_errs[] = 636 /* ignored "\x00" "successful completion\0" */ 637 "\x01" "invalid function/parameter\0" 638 "\x02" "address mark not found\0" 639 "\x03" "write-protected\0" 640 "\x04" "sector not found\0" 641 "\x05" "reset failed\0" 642 "\x06" "disk changed\0" 643 "\x07" "drive parameter activity failed\0" 644 "\x08" "DMA overrun\0" 645 "\x09" "data boundary error\0" 646 "\x0A" "bad sector detected\0" 647 "\x0B" "bad track detected\0" 648 "\x0C" "invalid media\0" 649 "\x0E" "control data address mark detected\0" 650 "\x0F" "DMA arbitration level out of range\0" 651 "\x10" "uncorrectable CRC or ECC error on read\0" 652 /* ignored "\x11" "data ECC corrected\0" */ 653 "\x20" "controller failure\0" 654 "\x31" "no media in drive\0" 655 "\x32" "incorrect drive type in CMOS\0" 656 "\x40" "seek failed\0" 657 "\x80" "operation timed out\0" 658 "\xAA" "drive not ready\0" 659 "\xB0" "volume not locked in drive\0" 660 "\xB1" "volume locked in drive\0" 661 "\xB2" "volume not removable\0" 662 "\xB3" "volume in use\0" 663 "\xB4" "lock count exceeded\0" 664 "\xB5" "valid eject request failed\0" 665 "\xBB" "undefined error\0" 666 "\xCC" "write fault\0" 667 "\xE0" "status register error\0" 668 "\xFF" "sense operation failed\0" 669 "\x00" "\0"; 670 671 static const char * 672 biosdisk_err(u_int error) 673 { 674 register const u_char *p = bidos_errs; 675 676 while (*p && *p != error) 677 while (*p++); 678 679 return ++p; 680 } 681 682 const struct biosdisk_errors { 683 u_char error; 684 u_char errno; 685 } tab[] = { 686 { 0x01, EINVAL }, 687 { 0x03, EROFS }, 688 { 0x08, EINVAL }, 689 { 0x09, EINVAL }, 690 { 0x0A, EBSE }, 691 { 0x0B, EBSE }, 692 { 0x0C, ENXIO }, 693 { 0x0D, EINVAL }, 694 { 0x10, EECC }, 695 { 0x20, EHER }, 696 { 0x31, ENXIO }, 697 { 0x32, ENXIO }, 698 { 0x00, EIO } 699 }; 700 701 static int 702 biosdisk_errno(u_int error) 703 { 704 register const struct biosdisk_errors *p; 705 706 if (error == 0) 707 return 0; 708 709 for (p = tab; p->error && p->error != error; p++); 710 711 return p->errno; 712 } 713 714 int 715 biosstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, 716 size_t *rsize) 717 { 718 struct diskinfo *dip = (struct diskinfo *)devdata; 719 bios_diskinfo_t *bd = &dip->bios_info; 720 u_int8_t error = 0; 721 size_t nsect; 722 723 #ifdef SOFTRAID 724 /* Intercept strategy for softraid volumes. */ 725 if (dip->sr_vol) 726 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 727 #endif 728 729 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 730 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; 731 732 /* Read all, sub-functions handle track boundaries */ 733 if (blk < 0) 734 error = EINVAL; 735 else 736 error = biosd_io(rw, bd, blk, nsect, buf); 737 738 #ifdef BIOS_DEBUG 739 if (debug) { 740 if (error != 0) 741 printf("=0x%x(%s)", error, biosdisk_err(error)); 742 putchar('\n'); 743 } 744 #endif 745 746 if (rsize != NULL) 747 *rsize = nsect * DEV_BSIZE; 748 749 return (biosdisk_errno(error)); 750 } 751 752 int 753 biosclose(struct open_file *f) 754 { 755 f->f_devdata = NULL; 756 757 return 0; 758 } 759 760 int 761 biosioctl(struct open_file *f, u_long cmd, void *data) 762 { 763 return 0; 764 } 765