1 /* $OpenBSD: biosdev.c,v 1.94 2016/09/11 17:52:47 jsing 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 /* 275 * XXX we believe that all the io is buffered 276 * by fs routines, so no big reads anyway 277 */ 278 bb = bb1 = alloc(bbsize); 279 if (rw != F_READ) 280 bcopy(buf, bb, bbsize); 281 } else 282 bb = buf; 283 284 /* Try to do operation up to 5 times */ 285 for (error = 1, j = 5; j-- && error; ) { 286 /* CHS or LBA access? */ 287 if (bd->bios_edd != -1) { 288 error = EDD_rw(rw, dev, off, nsect, bb); 289 } else { 290 int cyl, head, sect; 291 size_t i, n; 292 char *p = bb; 293 294 /* Handle track boundaries */ 295 for (error = i = 0; error == 0 && i < nsect; 296 i += n, off += n, p += n * DEV_BSIZE) { 297 298 btochs(off, cyl, head, sect, bd->bios_heads, 299 bd->bios_sectors); 300 301 if ((sect + (nsect - i)) >= bd->bios_sectors) 302 n = bd->bios_sectors - sect; 303 else 304 n = nsect - i; 305 306 error = CHS_rw(rw, dev, cyl, head, sect, n, p); 307 308 /* ECC corrected */ 309 if (error == 0x11) 310 error = 0; 311 } 312 } 313 switch (error) { 314 case 0x00: /* No errors */ 315 case 0x11: /* ECC corrected */ 316 error = 0; 317 break; 318 319 default: /* All other errors */ 320 #ifdef BIOS_DEBUG 321 if (debug) 322 printf("\nBIOS error 0x%x (%s)\n", 323 error, biosdisk_err(error)); 324 #endif 325 biosdreset(dev); 326 break; 327 } 328 } 329 330 if (bb != buf && rw == F_READ) 331 bcopy(bb, buf, bbsize); 332 free(bb1, bbsize); 333 334 #ifdef BIOS_DEBUG 335 if (debug) { 336 if (error != 0) 337 printf("=0x%x(%s)", error, biosdisk_err(error)); 338 putchar('\n'); 339 } 340 #endif 341 342 return error; 343 } 344 345 int 346 biosd_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) 347 { 348 return biosd_io(rw, &dip->bios_info, off, nsect, buf); 349 } 350 /* 351 * Try to read the bsd label on the given BIOS device. 352 */ 353 static u_int 354 findopenbsd(bios_diskinfo_t *bd, const char **err) 355 { 356 struct dos_mbr mbr; 357 struct dos_partition *dp; 358 u_int mbroff = DOSBBSECTOR; 359 u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ 360 int error, i, maxebr = DOS_MAXEBR, nextebr; 361 362 again: 363 if (!maxebr--) { 364 *err = "too many extended partitions"; 365 return (-1); 366 } 367 368 /* Read MBR */ 369 bzero(&mbr, sizeof(mbr)); 370 error = biosd_io(F_READ, bd, mbroff, 1, &mbr); 371 if (error) { 372 *err = biosdisk_err(error); 373 return (-1); 374 } 375 376 /* check mbr signature */ 377 if (mbr.dmbr_sign != DOSMBR_SIGNATURE) { 378 *err = "bad MBR signature\n"; 379 return (-1); 380 } 381 382 /* Search for OpenBSD partition */ 383 nextebr = 0; 384 for (i = 0; i < NDOSPART; i++) { 385 dp = &mbr.dmbr_parts[i]; 386 if (!dp->dp_size) 387 continue; 388 #ifdef BIOS_DEBUG 389 if (debug) 390 printf("found partition %u: " 391 "type %u (0x%x) offset %u (0x%x)\n", 392 (int)(dp - mbr.dmbr_parts), 393 dp->dp_typ, dp->dp_typ, 394 dp->dp_start, dp->dp_start); 395 #endif 396 if (dp->dp_typ == DOSPTYP_OPENBSD) { 397 if (dp->dp_start > (dp->dp_start + mbroff)) 398 continue; 399 return (dp->dp_start + mbroff); 400 } 401 402 /* 403 * Record location of next ebr if and only if this is the first 404 * extended partition in this boot record! 405 */ 406 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || 407 dp->dp_typ == DOSPTYP_EXTENDL)) { 408 nextebr = dp->dp_start + mbr_eoff; 409 if (nextebr < dp->dp_start) 410 nextebr = (u_int)-1; 411 if (mbr_eoff == DOSBBSECTOR) 412 mbr_eoff = dp->dp_start; 413 } 414 } 415 416 if (nextebr && nextebr != (u_int)-1) { 417 mbroff = nextebr; 418 goto again; 419 } 420 421 return (-1); 422 } 423 424 const char * 425 bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label) 426 { 427 u_int start = 0; 428 char buf[DEV_BSIZE]; 429 const char *err = NULL; 430 int error; 431 432 /* Sanity check */ 433 if (bd->bios_edd == -1 && 434 (bd->bios_heads == 0 || bd->bios_sectors == 0)) 435 return "failed to read disklabel"; 436 437 /* MBR is a harddisk thing */ 438 if (bd->bios_number & 0x80) { 439 start = findopenbsd(bd, &err); 440 if (start == (u_int)-1) { 441 if (err != NULL) 442 return (err); 443 return "no OpenBSD partition\n"; 444 } 445 } 446 447 /* Load BSD disklabel */ 448 #ifdef BIOS_DEBUG 449 if (debug) 450 printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR); 451 #endif 452 /* read disklabel */ 453 error = biosd_io(F_READ, bd, start + DOS_LABELSECTOR, 1, buf); 454 455 if (error) 456 return "failed to read disklabel"; 457 458 /* Fill in disklabel */ 459 return (getdisklabel(buf, label)); 460 } 461 462 int 463 biosopen(struct open_file *f, ...) 464 { 465 #ifdef SOFTRAID 466 struct sr_boot_volume *bv; 467 #endif 468 register char *cp, **file; 469 dev_t maj, unit, part; 470 struct diskinfo *dip; 471 int biosdev, devlen; 472 const char *st; 473 va_list ap; 474 char *dev; 475 476 va_start(ap, f); 477 cp = *(file = va_arg(ap, char **)); 478 va_end(ap); 479 480 #ifdef BIOS_DEBUG 481 if (debug) 482 printf("%s\n", cp); 483 #endif 484 485 f->f_devdata = NULL; 486 487 /* Search for device specification. */ 488 dev = cp; 489 if (cp[4] == ':') 490 devlen = 2; 491 else if (cp[5] == ':') 492 devlen = 3; 493 else 494 return ENOENT; 495 cp += devlen; 496 497 /* Get unit. */ 498 if ('0' <= *cp && *cp <= '9') 499 unit = *cp++ - '0'; 500 else { 501 printf("Bad unit number\n"); 502 return EUNIT; 503 } 504 505 /* Get partition. */ 506 if ('a' <= *cp && *cp <= 'p') 507 part = *cp++ - 'a'; 508 else { 509 printf("Bad partition\n"); 510 return EPART; 511 } 512 513 /* Get filename. */ 514 cp++; /* skip ':' */ 515 if (*cp != 0) 516 *file = cp; 517 else 518 f->f_flags |= F_RAW; 519 520 #ifdef SOFTRAID 521 /* Intercept softraid disks. */ 522 if (strncmp("sr", dev, 2) == 0) { 523 524 /* Create a fake diskinfo for this softraid volume. */ 525 SLIST_FOREACH(bv, &sr_volumes, sbv_link) 526 if (bv->sbv_unit == unit) 527 break; 528 if (bv == NULL) { 529 printf("Unknown device: sr%d\n", unit); 530 return EADAPT; 531 } 532 533 if (bv->sbv_level == 'C' && bv->sbv_keys == NULL) 534 if (sr_crypto_decrypt_keys(bv) != 0) 535 return EPERM; 536 537 if (bv->sbv_diskinfo == NULL) { 538 dip = alloc(sizeof(struct diskinfo)); 539 bzero(dip, sizeof(*dip)); 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 } 554 555 bv->sbv_part = part + 'a'; 556 557 bootdev_dip = dip; 558 f->f_devdata = dip; 559 560 return 0; 561 } 562 #endif 563 564 for (maj = 0; maj < nbdevs && 565 strncmp(dev, bdevs[maj], devlen); maj++); 566 if (maj >= nbdevs) { 567 printf("Unknown device: "); 568 for (cp = *file; *cp != ':'; cp++) 569 putchar(*cp); 570 putchar('\n'); 571 return EADAPT; 572 } 573 574 biosdev = unit; 575 switch (maj) { 576 case 0: /* wd */ 577 case 4: /* sd */ 578 case 17: /* hd */ 579 biosdev |= 0x80; 580 break; 581 case 2: /* fd */ 582 break; 583 case 6: /* cd */ 584 biosdev = bios_bootdev & 0xff; 585 break; 586 default: 587 return ENXIO; 588 } 589 590 /* Find device */ 591 bootdev_dip = dip = dklookup(biosdev); 592 593 /* Fix up bootdev */ 594 { dev_t bsd_dev; 595 bsd_dev = dip->bios_info.bsd_dev; 596 dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 597 B_CONTROLLER(bsd_dev), unit, part); 598 dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev), 599 B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part); 600 } 601 602 #if 0 603 dip->bios_info.bsd_dev = dip->bootdev; 604 bootdev = dip->bootdev; 605 #endif 606 607 #ifdef BIOS_DEBUG 608 if (debug) { 609 printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n", 610 dip->bios_info.bios_heads, dip->bios_info.bios_sectors, 611 dip->bios_info.bios_edd); 612 } 613 #endif 614 615 /* Try for disklabel again (might be removable media) */ 616 if (dip->bios_info.flags & BDI_BADLABEL) { 617 st = bios_getdisklabel(&dip->bios_info, &dip->disklabel); 618 #ifdef BIOS_DEBUG 619 if (debug && st) 620 printf("%s\n", st); 621 #endif 622 if (!st) { 623 dip->bios_info.flags &= ~BDI_BADLABEL; 624 dip->bios_info.flags |= BDI_GOODLABEL; 625 } else 626 return ERDLAB; 627 } 628 629 f->f_devdata = dip; 630 631 return 0; 632 } 633 634 const u_char bidos_errs[] = 635 /* ignored "\x00" "successful completion\0" */ 636 "\x01" "invalid function/parameter\0" 637 "\x02" "address mark not found\0" 638 "\x03" "write-protected\0" 639 "\x04" "sector not found\0" 640 "\x05" "reset failed\0" 641 "\x06" "disk changed\0" 642 "\x07" "drive parameter activity failed\0" 643 "\x08" "DMA overrun\0" 644 "\x09" "data boundary error\0" 645 "\x0A" "bad sector detected\0" 646 "\x0B" "bad track detected\0" 647 "\x0C" "invalid media\0" 648 "\x0E" "control data address mark detected\0" 649 "\x0F" "DMA arbitration level out of range\0" 650 "\x10" "uncorrectable CRC or ECC error on read\0" 651 /* ignored "\x11" "data ECC corrected\0" */ 652 "\x20" "controller failure\0" 653 "\x31" "no media in drive\0" 654 "\x32" "incorrect drive type in CMOS\0" 655 "\x40" "seek failed\0" 656 "\x80" "operation timed out\0" 657 "\xAA" "drive not ready\0" 658 "\xB0" "volume not locked in drive\0" 659 "\xB1" "volume locked in drive\0" 660 "\xB2" "volume not removable\0" 661 "\xB3" "volume in use\0" 662 "\xB4" "lock count exceeded\0" 663 "\xB5" "valid eject request failed\0" 664 "\xBB" "undefined error\0" 665 "\xCC" "write fault\0" 666 "\xE0" "status register error\0" 667 "\xFF" "sense operation failed\0" 668 "\x00" "\0"; 669 670 static const char * 671 biosdisk_err(u_int error) 672 { 673 register const u_char *p = bidos_errs; 674 675 while (*p && *p != error) 676 while (*p++); 677 678 return ++p; 679 } 680 681 const struct biosdisk_errors { 682 u_char error; 683 u_char errno; 684 } tab[] = { 685 { 0x01, EINVAL }, 686 { 0x03, EROFS }, 687 { 0x08, EINVAL }, 688 { 0x09, EINVAL }, 689 { 0x0A, EBSE }, 690 { 0x0B, EBSE }, 691 { 0x0C, ENXIO }, 692 { 0x0D, EINVAL }, 693 { 0x10, EECC }, 694 { 0x20, EHER }, 695 { 0x31, ENXIO }, 696 { 0x32, ENXIO }, 697 { 0x00, EIO } 698 }; 699 700 static int 701 biosdisk_errno(u_int error) 702 { 703 register const struct biosdisk_errors *p; 704 705 if (error == 0) 706 return 0; 707 708 for (p = tab; p->error && p->error != error; p++); 709 710 return p->errno; 711 } 712 713 int 714 biosstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf, 715 size_t *rsize) 716 { 717 struct diskinfo *dip = (struct diskinfo *)devdata; 718 bios_diskinfo_t *bd = &dip->bios_info; 719 u_int8_t error = 0; 720 size_t nsect; 721 722 #ifdef SOFTRAID 723 /* Intercept strategy for softraid volumes. */ 724 if (dip->sr_vol) 725 return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); 726 #endif 727 728 nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; 729 blk += dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset; 730 731 /* Read all, sub-functions handle track boundaries */ 732 if (blk < 0) 733 error = EINVAL; 734 else 735 error = biosd_io(rw, bd, blk, nsect, buf); 736 737 #ifdef BIOS_DEBUG 738 if (debug) { 739 if (error != 0) 740 printf("=0x%x(%s)", error, biosdisk_err(error)); 741 putchar('\n'); 742 } 743 #endif 744 745 if (rsize != NULL) 746 *rsize = nsect * DEV_BSIZE; 747 748 return (biosdisk_errno(error)); 749 } 750 751 int 752 biosclose(struct open_file *f) 753 { 754 f->f_devdata = NULL; 755 756 return 0; 757 } 758 759 int 760 biosioctl(struct open_file *f, u_long cmd, void *data) 761 { 762 return 0; 763 } 764