1/* $OpenBSD: biosdev.c,v 1.102 2024/04/14 03:26:25 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 50static const char *biosdisk_err(u_int); 51static int biosdisk_errno(u_int); 52 53int CHS_rw (int, int, int, int, int, int, void *); 54static int EDD_rw (int, int, u_int32_t, u_int32_t, void *); 55 56static int biosd_io(int, bios_diskinfo_t *, u_int, int, void *); 57static u_int findopenbsd(bios_diskinfo_t *, const char **); 58 59extern int debug; 60int bios_bootdev; 61int bios_cddev = -1; /* Set by srt0 if coming from CD */ 62 63struct 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 */ 76static int 77biosdreset(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 */ 92int 93bios_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 */ 188int 189CHS_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 214static __inline int 215EDD_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 */ 246int 247biosd_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#define MAXSECTS 32 345 346int 347biosd_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 348{ 349 char *dest = buf; 350 int n, ret; 351 352 /* 353 * Avoid doing too large reads, the bounce buffer used by biosd_io() 354 * might run us out-of-mem. 355 */ 356 for (ret = 0; ret == 0 && nsect > 0; 357 off += MAXSECTS, dest += MAXSECTS * DEV_BSIZE, nsect -= MAXSECTS) { 358 n = nsect >= MAXSECTS ? MAXSECTS : nsect; 359 ret = biosd_io(rw, &dip->bios_info, off, n, dest); 360 } 361 return ret; 362} 363 364/* 365 * Try to read the bsd label on the given BIOS device. 366 */ 367static u_int 368findopenbsd(bios_diskinfo_t *bd, const char **err) 369{ 370 struct dos_mbr mbr; 371 struct dos_partition *dp; 372 u_int mbroff = DOSBBSECTOR; 373 u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ 374 int error, i, maxebr = DOS_MAXEBR, nextebr; 375 376again: 377 if (!maxebr--) { 378 *err = "too many extended partitions"; 379 return (-1); 380 } 381 382 /* Read MBR */ 383 bzero(&mbr, sizeof(mbr)); 384 error = biosd_io(F_READ, bd, mbroff, 1, &mbr); 385 if (error) { 386 *err = biosdisk_err(error); 387 return (-1); 388 } 389 390 /* check mbr signature */ 391 if (mbr.dmbr_sign != DOSMBR_SIGNATURE) { 392 *err = "bad MBR signature\n"; 393 return (-1); 394 } 395 396 /* Search for OpenBSD partition */ 397 nextebr = 0; 398 for (i = 0; i < NDOSPART; i++) { 399 dp = &mbr.dmbr_parts[i]; 400 if (!dp->dp_size) 401 continue; 402#ifdef BIOS_DEBUG 403 if (debug) 404 printf("found partition %u: " 405 "type %u (0x%x) offset %u (0x%x)\n", 406 (int)(dp - mbr.dmbr_parts), 407 dp->dp_typ, dp->dp_typ, 408 dp->dp_start, dp->dp_start); 409#endif 410 if (dp->dp_typ == DOSPTYP_OPENBSD) { 411 if (dp->dp_start > (dp->dp_start + mbroff)) 412 continue; 413 return (dp->dp_start + mbroff); 414 } 415 416 /* 417 * Record location of next ebr if and only if this is the first 418 * extended partition in this boot record! 419 */ 420 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || 421 dp->dp_typ == DOSPTYP_EXTENDL)) { 422 nextebr = dp->dp_start + mbr_eoff; 423 if (nextebr < dp->dp_start) 424 nextebr = (u_int)-1; 425 if (mbr_eoff == DOSBBSECTOR) 426 mbr_eoff = dp->dp_start; 427 } 428 } 429 430 if (nextebr && nextebr != (u_int)-1) { 431 mbroff = nextebr; 432 goto again; 433 } 434 435 return (-1); 436} 437 438const char * 439bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) 440{ 441 u_int start = 0; 442 char buf[DEV_BSIZE]; 443 const char *err = NULL; 444 int error; 445 446 /* Sanity check */ 447 if (bd->bios_edd == -1 && 448 (bd->bios_heads == 0 || bd->bios_sectors == 0)) 449 return "failed to read disklabel"; 450 451 /* MBR is a harddisk thing */ 452 if (bd->bios_number & 0x80) { 453 start = findopenbsd(bd, &err); 454 if (start == (u_int)-1) { 455 if (err != NULL) 456 return (err); 457 return "no OpenBSD partition\n"; 458 } 459 } 460 461 /* Load BSD disklabel */ 462#ifdef BIOS_DEBUG 463 if (debug) 464 printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR); 465#endif 466 /* read disklabel */ 467 error = biosd_io(F_READ, bd, start + DOS_LABELSECTOR, 1, buf); 468 469 if (error) 470 return "failed to read disklabel"; 471 472 /* Fill in disklabel */ 473 return (getdisklabel(buf, label)); 474} 475 476int 477biosopen(struct open_file *f, ...) 478{ 479#ifdef SOFTRAID 480 struct sr_boot_volume *bv; 481#endif 482 register char *cp, **file; 483 dev_t maj, unit, part; 484 struct diskinfo *dip; 485 int biosdev, devlen; 486 const char *st; 487 va_list ap; 488 char *dev; 489 490 va_start(ap, f); 491 cp = *(file = va_arg(ap, char **)); 492 va_end(ap); 493 494#ifdef BIOS_DEBUG 495 if (debug) 496 printf("%s\n", cp); 497#endif 498 499 f->f_devdata = NULL; 500 501 /* Search for device specification. */ 502 dev = cp; 503 if (cp[4] == ':') 504 devlen = 2; 505 else if (cp[5] == ':') 506 devlen = 3; 507 else 508 return ENOENT; 509 cp += devlen; 510 511 /* Get unit. */ 512 if ('0' <= *cp && *cp <= '9') 513 unit = *cp++ - '0'; 514 else { 515 printf("Bad unit number\n"); 516 return EUNIT; 517 } 518 519 /* Get partition. */ 520 if ('a' <= *cp && *cp <= 'p') 521 part = *cp++ - 'a'; 522 else { 523 printf("Bad partition\n"); 524 return EPART; 525 } 526 527 /* Get filename. */ 528 cp++; /* skip ':' */ 529 if (*cp != 0) 530 *file = cp; 531 else 532 f->f_flags |= F_RAW; 533 534#ifdef SOFTRAID 535 /* Intercept softraid disks. */ 536 if (strncmp("sr", dev, 2) == 0) { 537 /* We only support read-only softraid. */ 538 f->f_flags |= F_NOWRITE; 539 540 /* Create a fake diskinfo for this softraid volume. */ 541 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 542 if (bv->sbv_unit == unit) 543 break; 544 if (bv == NULL) { 545 printf("Unknown device: sr%d\n", unit); 546 return EADAPT; 547 } 548 549 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 550 if (sr_crypto_unlock_volume(bv) != 0) 551 return EPERM; 552 553 if (bv->sbv_diskinfo == NULL) { 554 dip = alloc(sizeof(struct diskinfo)); 555 bzero(dip, sizeof(*dip)); 556 dip->strategy = biosstrategy; 557 bv->sbv_diskinfo = dip; 558 dip->sr_vol = bv; 559 dip->bios_info.flags |= BDI_BADLABEL; 560 } 561 562 dip = bv->sbv_diskinfo; 563 564 if (dip->bios_info.flags & BDI_BADLABEL) { 565 /* Attempt to read disklabel. */ 566 bv->sbv_part = 'c'; 567 if (sr_getdisklabel(bv, &dip->disklabel)) 568 return ERDLAB; 569 dip->bios_info.flags &= ~BDI_BADLABEL; 570 check_hibernate(dip); 571 } 572 573 bv->sbv_part = part + 'a'; 574 575 bootdev_dip = dip; 576 f->f_devdata = dip; 577 578 return 0; 579 } 580#endif 581 582 for (maj = 0; maj < nbdevs && 583 strncmp(dev, bdevs[maj], devlen); maj++); 584 if (maj >= nbdevs) { 585 printf("Unknown device: "); 586 for (cp = *file; *cp != ':'; cp++) 587 putchar(*cp); 588 putchar('\n'); 589 return EADAPT; 590 } 591 592 biosdev = unit; 593 switch (maj) { 594 case 0: /* wd */ 595 case 4: /* sd */ 596 case 17: /* hd */ 597 biosdev |= 0x80; 598 break; 599 case 2: /* fd */ 600 break; 601 case 6: /* cd */ 602 biosdev = bios_bootdev & 0xff; 603 break; 604 default: 605 return ENXIO; 606 } 607 608 /* Find device */ 609 bootdev_dip = dip = dklookup(biosdev); 610 611 /* Fix up bootdev */ 612 { dev_t bsd_dev; 613 bsd_dev = dip->bios_info.bsd_dev; 614 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 615 B_CONTROLLER(bsd_dev), unit, part); 616 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 617 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part); 618 } 619 620#if 0 621 dip->bios_info.bsd_dev = dip->bootdev; 622 bootdev = dip->bootdev; 623#endif 624 625#ifdef BIOS_DEBUG 626 if (debug) { 627 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n", 628 dip->bios_info.bios_heads, dip->bios_info.bios_sectors, 629 dip->bios_info.bios_edd); 630 } 631#endif 632 633 /* Try for disklabel again (might be removable media) */ 634 if (dip->bios_info.flags & BDI_BADLABEL) { 635 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel); 636#ifdef BIOS_DEBUG 637 if (debug && st) 638 printf("%s\n", st); 639#endif 640 if (!st) { 641 dip->bios_info.flags &= ~BDI_BADLABEL; 642 dip->bios_info.flags |= BDI_GOODLABEL; 643 } else 644 return ERDLAB; 645 } 646 647 f->f_devdata = dip; 648 649 return 0; 650} 651 652const u_char bidos_errs[] = 653/* ignored "\x00" "successful completion\0" */ 654 "\x01" "invalid function/parameter\0" 655 "\x02" "address mark not found\0" 656 "\x03" "write-protected\0" 657 "\x04" "sector not found\0" 658 "\x05" "reset failed\0" 659 "\x06" "disk changed\0" 660 "\x07" "drive parameter activity failed\0" 661 "\x08" "DMA overrun\0" 662 "\x09" "data boundary error\0" 663 "\x0A" "bad sector detected\0" 664 "\x0B" "bad track detected\0" 665 "\x0C" "invalid media\0" 666 "\x0E" "control data address mark detected\0" 667 "\x0F" "DMA arbitration level out of range\0" 668 "\x10" "uncorrectable CRC or ECC error on read\0" 669/* ignored "\x11" "data ECC corrected\0" */ 670 "\x20" "controller failure\0" 671 "\x31" "no media in drive\0" 672 "\x32" "incorrect drive type in CMOS\0" 673 "\x40" "seek failed\0" 674 "\x80" "operation timed out\0" 675 "\xAA" "drive not ready\0" 676 "\xB0" "volume not locked in drive\0" 677 "\xB1" "volume locked in drive\0" 678 "\xB2" "volume not removable\0" 679 "\xB3" "volume in use\0" 680 "\xB4" "lock count exceeded\0" 681 "\xB5" "valid eject request failed\0" 682 "\xBB" "undefined error\0" 683 "\xCC" "write fault\0" 684 "\xE0" "status register error\0" 685 "\xFF" "sense operation failed\0" 686 "\x00" "\0"; 687 688static const char * 689biosdisk_err(u_int error) 690{ 691 register const u_char *p = bidos_errs; 692 693 while (*p && *p != error) 694 while (*p++); 695 696 return ++p; 697} 698 699const struct biosdisk_errors { 700 u_char error; 701 u_char errno; 702} tab[] = { 703 { 0x01, EINVAL }, 704 { 0x03, EROFS }, 705 { 0x08, EINVAL }, 706 { 0x09, EINVAL }, 707 { 0x0A, EBSE }, 708 { 0x0B, EBSE }, 709 { 0x0C, ENXIO }, 710 { 0x0D, EINVAL }, 711 { 0x10, EECC }, 712 { 0x20, EHER }, 713 { 0x31, ENXIO }, 714 { 0x32, ENXIO }, 715 { 0x00, EIO } 716}; 717 718static int 719biosdisk_errno(u_int error) 720{ 721 register const struct biosdisk_errors *p; 722 723 if (error == 0) 724 return 0; 725 726 for (p = tab; p->error && p->error != error; p++) 727 ; 728 729 return p->errno; 730} 731 732int 733biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 734 size_t *rsize) 735{ 736 struct diskinfo *dip = (struct diskinfo *)devdata; 737 u_int8_t error = 0; 738 size_t nsect; 739 740#ifdef SOFTRAID 741 /* Intercept strategy for softraid volumes. */ 742 if (dip->sr_vol) 743 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 744#endif 745 746 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 747 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; 748 749 /* Read all, sub-functions handle track boundaries */ 750 if (blk < 0) 751 error = EINVAL; 752 else 753 error = biosd_diskio(rw, dip, blk, nsect, buf); 754 755#ifdef BIOS_DEBUG 756 if (debug) { 757 if (error != 0) 758 printf("=0x%x(%s)", error, biosdisk_err(error)); 759 putchar('\n'); 760 } 761#endif 762 763 if (rsize != NULL) 764 *rsize = nsect * DEV_BSIZE; 765 766 return (biosdisk_errno(error)); 767} 768 769int 770biosclose(struct open_file *f) 771{ 772 f->f_devdata = NULL; 773 774 return 0; 775} 776 777int 778biosioctl(struct open_file *f, u_long cmd, void *data) 779{ 780 return 0; 781} 782