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