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