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