1 /* $OpenBSD: biosdev.c,v 1.99 2018/12/16 08:33:16 otto 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 #define MAXSECTS 32 345 346 int 347 biosd_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 */ 367 static u_int 368 findopenbsd(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 376 again: 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 438 const char * 439 bios_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 476 int 477 biosopen(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 538 /* Create a fake diskinfo for this softraid volume. */ 539 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 540 if (bv->sbv_unit == unit) 541 break; 542 if (bv == NULL) { 543 printf("Unknown device: sr%d\n", unit); 544 return EADAPT; 545 } 546 547 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 548 if (sr_crypto_unlock_volume(bv) != 0) 549 return EPERM; 550 551 if (bv->sbv_diskinfo == NULL) { 552 dip = alloc(sizeof(struct diskinfo)); 553 bzero(dip, sizeof(*dip)); 554 dip->strategy = biosstrategy; 555 bv->sbv_diskinfo = dip; 556 dip->sr_vol = bv; 557 dip->bios_info.flags |= BDI_BADLABEL; 558 } 559 560 dip = bv->sbv_diskinfo; 561 562 if (dip->bios_info.flags & BDI_BADLABEL) { 563 /* Attempt to read disklabel. */ 564 bv->sbv_part = 'c'; 565 if (sr_getdisklabel(bv, &dip->disklabel)) 566 return ERDLAB; 567 dip->bios_info.flags &= ~BDI_BADLABEL; 568 check_hibernate(dip); 569 } 570 571 bv->sbv_part = part + 'a'; 572 573 bootdev_dip = dip; 574 f->f_devdata = dip; 575 576 return 0; 577 } 578 #endif 579 580 for (maj = 0; maj < nbdevs && 581 strncmp(dev, bdevs[maj], devlen); maj++); 582 if (maj >= nbdevs) { 583 printf("Unknown device: "); 584 for (cp = *file; *cp != ':'; cp++) 585 putchar(*cp); 586 putchar('\n'); 587 return EADAPT; 588 } 589 590 biosdev = unit; 591 switch (maj) { 592 case 0: /* wd */ 593 case 4: /* sd */ 594 case 17: /* hd */ 595 biosdev |= 0x80; 596 break; 597 case 2: /* fd */ 598 break; 599 case 6: /* cd */ 600 biosdev = bios_bootdev & 0xff; 601 break; 602 default: 603 return ENXIO; 604 } 605 606 /* Find device */ 607 bootdev_dip = dip = dklookup(biosdev); 608 609 /* Fix up bootdev */ 610 { dev_t bsd_dev; 611 bsd_dev = dip->bios_info.bsd_dev; 612 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 613 B_CONTROLLER(bsd_dev), unit, part); 614 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 615 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part); 616 } 617 618 #if 0 619 dip->bios_info.bsd_dev = dip->bootdev; 620 bootdev = dip->bootdev; 621 #endif 622 623 #ifdef BIOS_DEBUG 624 if (debug) { 625 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n", 626 dip->bios_info.bios_heads, dip->bios_info.bios_sectors, 627 dip->bios_info.bios_edd); 628 } 629 #endif 630 631 /* Try for disklabel again (might be removable media) */ 632 if (dip->bios_info.flags & BDI_BADLABEL) { 633 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel); 634 #ifdef BIOS_DEBUG 635 if (debug && st) 636 printf("%s\n", st); 637 #endif 638 if (!st) { 639 dip->bios_info.flags &= ~BDI_BADLABEL; 640 dip->bios_info.flags |= BDI_GOODLABEL; 641 } else 642 return ERDLAB; 643 } 644 645 f->f_devdata = dip; 646 647 return 0; 648 } 649 650 const u_char bidos_errs[] = 651 /* ignored "\x00" "successful completion\0" */ 652 "\x01" "invalid function/parameter\0" 653 "\x02" "address mark not found\0" 654 "\x03" "write-protected\0" 655 "\x04" "sector not found\0" 656 "\x05" "reset failed\0" 657 "\x06" "disk changed\0" 658 "\x07" "drive parameter activity failed\0" 659 "\x08" "DMA overrun\0" 660 "\x09" "data boundary error\0" 661 "\x0A" "bad sector detected\0" 662 "\x0B" "bad track detected\0" 663 "\x0C" "invalid media\0" 664 "\x0E" "control data address mark detected\0" 665 "\x0F" "DMA arbitration level out of range\0" 666 "\x10" "uncorrectable CRC or ECC error on read\0" 667 /* ignored "\x11" "data ECC corrected\0" */ 668 "\x20" "controller failure\0" 669 "\x31" "no media in drive\0" 670 "\x32" "incorrect drive type in CMOS\0" 671 "\x40" "seek failed\0" 672 "\x80" "operation timed out\0" 673 "\xAA" "drive not ready\0" 674 "\xB0" "volume not locked in drive\0" 675 "\xB1" "volume locked in drive\0" 676 "\xB2" "volume not removable\0" 677 "\xB3" "volume in use\0" 678 "\xB4" "lock count exceeded\0" 679 "\xB5" "valid eject request failed\0" 680 "\xBB" "undefined error\0" 681 "\xCC" "write fault\0" 682 "\xE0" "status register error\0" 683 "\xFF" "sense operation failed\0" 684 "\x00" "\0"; 685 686 static const char * 687 biosdisk_err(u_int error) 688 { 689 register const u_char *p = bidos_errs; 690 691 while (*p && *p != error) 692 while (*p++); 693 694 return ++p; 695 } 696 697 const struct biosdisk_errors { 698 u_char error; 699 u_char errno; 700 } tab[] = { 701 { 0x01, EINVAL }, 702 { 0x03, EROFS }, 703 { 0x08, EINVAL }, 704 { 0x09, EINVAL }, 705 { 0x0A, EBSE }, 706 { 0x0B, EBSE }, 707 { 0x0C, ENXIO }, 708 { 0x0D, EINVAL }, 709 { 0x10, EECC }, 710 { 0x20, EHER }, 711 { 0x31, ENXIO }, 712 { 0x32, ENXIO }, 713 { 0x00, EIO } 714 }; 715 716 static int 717 biosdisk_errno(u_int error) 718 { 719 register const struct biosdisk_errors *p; 720 721 if (error == 0) 722 return 0; 723 724 for (p = tab; p->error && p->error != error; p++); 725 726 return p->errno; 727 } 728 729 int 730 biosstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, 731 size_t *rsize) 732 { 733 struct diskinfo *dip = (struct diskinfo *)devdata; 734 u_int8_t error = 0; 735 size_t nsect; 736 737 #ifdef SOFTRAID 738 /* Intercept strategy for softraid volumes. */ 739 if (dip->sr_vol) 740 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 741 #endif 742 743 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 744 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; 745 746 /* Read all, sub-functions handle track boundaries */ 747 if (blk < 0) 748 error = EINVAL; 749 else 750 error = biosd_diskio(rw, dip, blk, nsect, buf); 751 752 #ifdef BIOS_DEBUG 753 if (debug) { 754 if (error != 0) 755 printf("=0x%x(%s)", error, biosdisk_err(error)); 756 putchar('\n'); 757 } 758 #endif 759 760 if (rsize != NULL) 761 *rsize = nsect * DEV_BSIZE; 762 763 return (biosdisk_errno(error)); 764 } 765 766 int 767 biosclose(struct open_file *f) 768 { 769 f->f_devdata = NULL; 770 771 return 0; 772 } 773 774 int 775 biosioctl(struct open_file *f, u_long cmd, void *data) 776 { 777 return 0; 778 } 779