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