1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: releng/10.3/sys/boot/i386/libi386/biosdisk.c 241809 2012-10-21 12:14:58Z ae $"); 30 31/* 32 * BIOS disk device handling. 33 * 34 * Ideas and algorithms from: 35 * 36 * - NetBSD libi386/biosdisk.c 37 * - FreeBSD biosboot/disk.c 38 * 39 */ 40 41#include <sys/disk.h> 42#include <stand.h> 43#include <machine/bootinfo.h> 44#include <stdarg.h> 45 46#include <bootstrap.h> 47#include <btxv86.h> 48#include <edd.h> 49#include "disk.h" 50#include "libi386.h" 51 52CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc)); 53 54#define BIOS_NUMDRIVES 0x475 55#define BIOSDISK_SECSIZE 512 56#define BUFSIZE (1 * BIOSDISK_SECSIZE) 57 58#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ 59#define WDMAJOR 0 /* major numbers for devices we frontend for */ 60#define WFDMAJOR 1 61#define FDMAJOR 2 62#define DAMAJOR 4 63 64#ifdef DISK_DEBUG 65# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 66#else 67# define DEBUG(fmt, args...) 68#endif 69 70/* 71 * List of BIOS devices, translation from disk unit number to 72 * BIOS unit number. 73 */ 74static struct bdinfo 75{ 76 int bd_unit; /* BIOS unit number */ 77 int bd_cyl; /* BIOS geometry */ 78 int bd_hds; 79 int bd_sec; 80 int bd_flags; 81#define BD_MODEINT13 0x0000 82#define BD_MODEEDD1 0x0001 83#define BD_MODEEDD3 0x0002 84#define BD_MODEMASK 0x0003 85#define BD_FLOPPY 0x0004 86 int bd_type; /* BIOS 'drive type' (floppy only) */ 87 uint16_t bd_sectorsize; /* Sector size */ 88 uint64_t bd_sectors; /* Disk size */ 89} bdinfo [MAXBDDEV]; 90static int nbdinfo = 0; 91 92#define BD(dev) (bdinfo[(dev)->d_unit]) 93 94static int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, 95 caddr_t dest); 96static int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, 97 caddr_t dest); 98static int bd_int13probe(struct bdinfo *bd); 99 100static int bd_init(void); 101static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 102 char *buf, size_t *rsize); 103static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, 104 size_t size, char *buf, size_t *rsize); 105static int bd_open(struct open_file *f, ...); 106static int bd_close(struct open_file *f); 107static int bd_ioctl(struct open_file *f, u_long cmd, void *data); 108static void bd_print(int verbose); 109static void bd_cleanup(void); 110 111struct devsw biosdisk = { 112 "disk", 113 DEVT_DISK, 114 bd_init, 115 bd_strategy, 116 bd_open, 117 bd_close, 118 bd_ioctl, 119 bd_print, 120 bd_cleanup 121}; 122 123/* 124 * Translate between BIOS device numbers and our private unit numbers. 125 */ 126int 127bd_bios2unit(int biosdev) 128{ 129 int i; 130 131 DEBUG("looking for bios device 0x%x", biosdev); 132 for (i = 0; i < nbdinfo; i++) { 133 DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); 134 if (bdinfo[i].bd_unit == biosdev) 135 return (i); 136 } 137 return (-1); 138} 139 140int 141bd_unit2bios(int unit) 142{ 143 144 if ((unit >= 0) && (unit < nbdinfo)) 145 return (bdinfo[unit].bd_unit); 146 return (-1); 147} 148 149/* 150 * Quiz the BIOS for disk devices, save a little info about them. 151 */ 152static int 153bd_init(void) 154{ 155 int base, unit, nfd = 0; 156 157 /* sequence 0, 0x80 */ 158 for (base = 0; base <= 0x80; base += 0x80) { 159 for (unit = base; (nbdinfo < MAXBDDEV); unit++) { 160#ifndef VIRTUALBOX 161 /* 162 * Check the BIOS equipment list for number 163 * of fixed disks. 164 */ 165 if(base == 0x80 && 166 (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) 167 break; 168#endif 169 bdinfo[nbdinfo].bd_unit = unit; 170 bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0; 171 if (!bd_int13probe(&bdinfo[nbdinfo])) 172 break; 173 174 /* XXX we need "disk aliases" to make this simpler */ 175 printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ? 176 ('A' + unit): ('C' + unit - 0x80), nbdinfo); 177 nbdinfo++; 178 if (base == 0x80) 179 nfd++; 180 } 181 } 182 return(0); 183} 184 185static void 186bd_cleanup(void) 187{ 188 189 disk_cleanup(&biosdisk); 190} 191 192/* 193 * Try to detect a device supported by the legacy int13 BIOS 194 */ 195static int 196bd_int13probe(struct bdinfo *bd) 197{ 198 struct edd_params params; 199 200 v86.ctl = V86_FLAGS; 201 v86.addr = 0x13; 202 v86.eax = 0x800; 203 v86.edx = bd->bd_unit; 204 v86int(); 205 206 if (V86_CY(v86.efl) || /* carry set */ 207 (v86.ecx & 0x3f) == 0 || /* absurd sector number */ 208 (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */ 209 return (0); /* skip device */ 210 211 /* Convert max cyl # -> # of cylinders */ 212 bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 213 /* Convert max head # -> # of heads */ 214 bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; 215 bd->bd_sec = v86.ecx & 0x3f; 216 bd->bd_type = v86.ebx & 0xff; 217 bd->bd_flags |= BD_MODEINT13; 218 219 /* Calculate sectors count from the geometry */ 220 bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec; 221 bd->bd_sectorsize = BIOSDISK_SECSIZE; 222 DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, 223 bd->bd_hds, bd->bd_sec); 224 225 /* Determine if we can use EDD with this device. */ 226 v86.ctl = V86_FLAGS; 227 v86.addr = 0x13; 228 v86.eax = 0x4100; 229 v86.edx = bd->bd_unit; 230 v86.ebx = 0x55aa; 231 v86int(); 232 if (V86_CY(v86.efl) || /* carry set */ 233 (v86.ebx & 0xffff) != 0xaa55 || /* signature */ 234 (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) 235 return (1); 236 /* EDD supported */ 237 bd->bd_flags |= BD_MODEEDD1; 238 if ((v86.eax & 0xff00) >= 0x3000) 239 bd->bd_flags |= BD_MODEEDD3; 240 /* Get disk params */ 241 params.len = sizeof(struct edd_params); 242 v86.ctl = V86_FLAGS; 243 v86.addr = 0x13; 244 v86.eax = 0x4800; 245 v86.edx = bd->bd_unit; 246 v86.ds = VTOPSEG(¶ms); 247 v86.esi = VTOPOFF(¶ms); 248 v86int(); 249 if (!V86_CY(v86.efl)) { 250 bd->bd_sectors = params.sectors; 251 bd->bd_sectorsize = params.sector_size; 252 } 253 DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u", 254 bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize); 255 return (1); 256} 257 258/* 259 * Print information about disks 260 */ 261static void 262bd_print(int verbose) 263{ 264 static char line[80]; 265 struct disk_devdesc dev; 266 int i; 267 268 for (i = 0; i < nbdinfo; i++) { 269 sprintf(line, " disk%d: BIOS drive %c:\n", i, 270 (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): 271 ('C' + bdinfo[i].bd_unit - 0x80)); 272 pager_output(line); 273 dev.d_dev = &biosdisk; 274 dev.d_unit = i; 275 dev.d_slice = -1; 276 dev.d_partition = -1; 277 if (disk_open(&dev, 278 bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, 279 bdinfo[i].bd_sectorsize, 280 (bdinfo[i].bd_flags & BD_FLOPPY) ? 281 DISK_F_NOCACHE: 0) == 0) { 282 sprintf(line, " disk%d", i); 283 disk_print(&dev, line, verbose); 284 disk_close(&dev); 285 } 286 } 287} 288 289/* 290 * Attempt to open the disk described by (dev) for use by (f). 291 * 292 * Note that the philosophy here is "give them exactly what 293 * they ask for". This is necessary because being too "smart" 294 * about what the user might want leads to complications. 295 * (eg. given no slice or partition value, with a disk that is 296 * sliced - are they after the first BSD slice, or the DOS 297 * slice before it?) 298 */ 299static int 300bd_open(struct open_file *f, ...) 301{ 302 struct disk_devdesc *dev; 303 va_list ap; 304 305 va_start(ap, f); 306 dev = va_arg(ap, struct disk_devdesc *); 307 va_end(ap); 308 309 if (dev->d_unit < 0 || dev->d_unit >= nbdinfo) 310 return (EIO); 311 312 return (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, 313 BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ? 314 DISK_F_NOCACHE: 0)); 315} 316 317static int 318bd_close(struct open_file *f) 319{ 320 struct disk_devdesc *dev; 321 322 dev = (struct disk_devdesc *)f->f_devdata; 323 return (disk_close(dev)); 324} 325 326static int 327bd_ioctl(struct open_file *f, u_long cmd, void *data) 328{ 329 struct disk_devdesc *dev; 330 331 dev = (struct disk_devdesc *)f->f_devdata; 332 switch (cmd) { 333 case DIOCGSECTORSIZE: 334 *(u_int *)data = BD(dev).bd_sectorsize; 335 break; 336 case DIOCGMEDIASIZE: 337 *(off_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; 338 break; 339 default: 340 return (ENOTTY); 341 } 342 return (0); 343} 344 345static int 346bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, 347 size_t *rsize) 348{ 349 struct bcache_devdata bcd; 350 struct disk_devdesc *dev; 351 352 dev = (struct disk_devdesc *)devdata; 353 bcd.dv_strategy = bd_realstrategy; 354 bcd.dv_devdata = devdata; 355 return (bcache_strategy(&bcd, BD(dev).bd_unit, rw, dblk + dev->d_offset, 356 size, buf, rsize)); 357} 358 359static int 360bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, 361 size_t *rsize) 362{ 363 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 364 int blks; 365#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ 366 char fragbuf[BIOSDISK_SECSIZE]; 367 size_t fragsize; 368 369 fragsize = size % BIOSDISK_SECSIZE; 370#else 371 if (size % BD(dev).bd_sectorsize) 372 panic("bd_strategy: %d bytes I/O not multiple of block size", size); 373#endif 374 375 DEBUG("open_disk %p", dev); 376 blks = size / BD(dev).bd_sectorsize; 377 if (rsize) 378 *rsize = 0; 379 380 switch(rw){ 381 case F_READ: 382 DEBUG("read %d from %lld to %p", blks, dblk, buf); 383 384 if (blks && bd_read(dev, dblk, blks, buf)) { 385 DEBUG("read error"); 386 return (EIO); 387 } 388#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */ 389 DEBUG("bd_strategy: frag read %d from %d+%d to %p", 390 fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); 391 if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { 392 DEBUG("frag read error"); 393 return(EIO); 394 } 395 bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); 396#endif 397 break; 398 case F_WRITE : 399 DEBUG("write %d from %d to %p", blks, dblk, buf); 400 401 if (blks && bd_write(dev, dblk, blks, buf)) { 402 DEBUG("write error"); 403 return (EIO); 404 } 405#ifdef BD_SUPPORT_FRAGS 406 if(fragsize) { 407 DEBUG("Attempted to write a frag"); 408 return (EIO); 409 } 410#endif 411 break; 412 default: 413 /* DO NOTHING */ 414 return (EROFS); 415 } 416 417 if (rsize) 418 *rsize = size; 419 return (0); 420} 421 422/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ 423#define FLOPPY_BOUNCEBUF 18 424 425static int 426bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, 427 int write) 428{ 429 static struct edd_packet packet; 430 431 packet.len = sizeof(struct edd_packet); 432 packet.count = blks; 433 packet.off = VTOPOFF(dest); 434 packet.seg = VTOPSEG(dest); 435 packet.lba = dblk; 436 v86.ctl = V86_FLAGS; 437 v86.addr = 0x13; 438 if (write) 439 /* Should we Write with verify ?? 0x4302 ? */ 440 v86.eax = 0x4300; 441 else 442 v86.eax = 0x4200; 443 v86.edx = BD(dev).bd_unit; 444 v86.ds = VTOPSEG(&packet); 445 v86.esi = VTOPOFF(&packet); 446 v86int(); 447 return (V86_CY(v86.efl)); 448} 449 450static int 451bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, 452 int write) 453{ 454 u_int x, bpc, cyl, hd, sec; 455 456 bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */ 457 x = dblk; 458 cyl = x / bpc; /* block # / blocks per cylinder */ 459 x %= bpc; /* block offset into cylinder */ 460 hd = x / BD(dev).bd_sec; /* offset / blocks per track */ 461 sec = x % BD(dev).bd_sec; /* offset into track */ 462 463 /* correct sector number for 1-based BIOS numbering */ 464 sec++; 465 466 if (cyl > 1023) 467 /* CHS doesn't support cylinders > 1023. */ 468 return (1); 469 470 v86.ctl = V86_FLAGS; 471 v86.addr = 0x13; 472 if (write) 473 v86.eax = 0x300 | blks; 474 else 475 v86.eax = 0x200 | blks; 476 v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 477 v86.edx = (hd << 8) | BD(dev).bd_unit; 478 v86.es = VTOPSEG(dest); 479 v86.ebx = VTOPOFF(dest); 480 v86int(); 481 return (V86_CY(v86.efl)); 482} 483 484static int 485bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write) 486{ 487 u_int x, sec, result, resid, retry, maxfer; 488 caddr_t p, xp, bbuf, breg; 489 490 /* Just in case some idiot actually tries to read/write -1 blocks... */ 491 if (blks < 0) 492 return (-1); 493 494 resid = blks; 495 p = dest; 496 497 /* Decide whether we have to bounce */ 498 if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 && 499 (VTOP(dest) >> 16) != (VTOP(dest + 500 blks * BD(dev).bd_sectorsize) >> 16))) { 501 502 /* 503 * There is a 64k physical boundary somewhere in the 504 * destination buffer, or the destination buffer is above 505 * first 1MB of physical memory so we have to arrange a 506 * suitable bounce buffer. Allocate a buffer twice as large 507 * as we need to. Use the bottom half unless there is a break 508 * there, in which case we use the top half. 509 */ 510 x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); 511 bbuf = alloca(x * 2 * BD(dev).bd_sectorsize); 512 if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == 513 ((u_int32_t)VTOP(bbuf + x * BD(dev).bd_sectorsize) & 0xffff0000)) { 514 breg = bbuf; 515 } else { 516 breg = bbuf + x * BD(dev).bd_sectorsize; 517 } 518 maxfer = x; /* limit transfers to bounce region size */ 519 } else { 520 breg = bbuf = NULL; 521 maxfer = 0; 522 } 523 524 while (resid > 0) { 525 /* 526 * Play it safe and don't cross track boundaries. 527 * (XXX this is probably unnecessary) 528 */ 529 sec = dblk % BD(dev).bd_sec; /* offset into track */ 530 x = min(BD(dev).bd_sec - sec, resid); 531 if (maxfer > 0) 532 x = min(x, maxfer); /* fit bounce buffer */ 533 534 /* where do we transfer to? */ 535 xp = bbuf == NULL ? p : breg; 536 537 /* 538 * Put your Data In, Put your Data out, 539 * Put your Data In, and shake it all about 540 */ 541 if (write && bbuf != NULL) 542 bcopy(p, breg, x * BD(dev).bd_sectorsize); 543 544 /* 545 * Loop retrying the operation a couple of times. The BIOS 546 * may also retry. 547 */ 548 for (retry = 0; retry < 3; retry++) { 549 /* if retrying, reset the drive */ 550 if (retry > 0) { 551 v86.ctl = V86_FLAGS; 552 v86.addr = 0x13; 553 v86.eax = 0; 554 v86.edx = BD(dev).bd_unit; 555 v86int(); 556 } 557 558 if (BD(dev).bd_flags & BD_MODEEDD1) 559 result = bd_edd_io(dev, dblk, x, xp, write); 560 else 561 result = bd_chs_io(dev, dblk, x, xp, write); 562 if (result == 0) 563 break; 564 } 565 566 if (write) 567 DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x, 568 p, VTOP(p), dblk, result ? "failed" : "ok"); 569 else 570 DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x, 571 dblk, p, VTOP(p), result ? "failed" : "ok"); 572 if (result) { 573 return(-1); 574 } 575 if (!write && bbuf != NULL) 576 bcopy(breg, p, x * BD(dev).bd_sectorsize); 577 p += (x * BD(dev).bd_sectorsize); 578 dblk += x; 579 resid -= x; 580 } 581 582/* hexdump(dest, (blks * BD(dev).bd_sectorsize)); */ 583 return(0); 584} 585 586static int 587bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) 588{ 589 590 return (bd_io(dev, dblk, blks, dest, 0)); 591} 592 593static int 594bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest) 595{ 596 597 return (bd_io(dev, dblk, blks, dest, 1)); 598} 599 600/* 601 * Return the BIOS geometry of a given "fixed drive" in a format 602 * suitable for the legacy bootinfo structure. Since the kernel is 603 * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we 604 * prefer to get the information directly, rather than rely on being 605 * able to put it together from information already maintained for 606 * different purposes and for a probably different number of drives. 607 * 608 * For valid drives, the geometry is expected in the format (31..0) 609 * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are 610 * indicated by returning the geometry of a "1.2M" PC-format floppy 611 * disk. And, incidentally, what is returned is not the geometry as 612 * such but the highest valid cylinder, head, and sector numbers. 613 */ 614u_int32_t 615bd_getbigeom(int bunit) 616{ 617 618 v86.ctl = V86_FLAGS; 619 v86.addr = 0x13; 620 v86.eax = 0x800; 621 v86.edx = 0x80 + bunit; 622 v86int(); 623 if (V86_CY(v86.efl)) 624 return 0x4f010f; 625 return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 626 (v86.edx & 0xff00) | (v86.ecx & 0x3f); 627} 628 629/* 630 * Return a suitable dev_t value for (dev). 631 * 632 * In the case where it looks like (dev) is a SCSI disk, we allow the number of 633 * IDE disks to be specified in $num_ide_disks. There should be a Better Way. 634 */ 635int 636bd_getdev(struct i386_devdesc *d) 637{ 638 struct disk_devdesc *dev; 639 int biosdev; 640 int major; 641 int rootdev; 642 char *nip, *cp; 643 int i, unit; 644 645 dev = (struct disk_devdesc *)d; 646 biosdev = bd_unit2bios(dev->d_unit); 647 DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev); 648 if (biosdev == -1) /* not a BIOS device */ 649 return(-1); 650 if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, 651 BD(dev).bd_sectorsize,(BD(dev).bd_flags & BD_FLOPPY) ? 652 DISK_F_NOCACHE: 0) != 0) /* oops, not a viable device */ 653 return (-1); 654 else 655 disk_close(dev); 656 657 if (biosdev < 0x80) { 658 /* floppy (or emulated floppy) or ATAPI device */ 659 if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) { 660 /* is an ATAPI disk */ 661 major = WFDMAJOR; 662 } else { 663 /* is a floppy disk */ 664 major = FDMAJOR; 665 } 666 } else { 667 /* assume an IDE disk */ 668 major = WDMAJOR; 669 } 670 /* default root disk unit number */ 671 unit = biosdev & 0x7f; 672 673 /* XXX a better kludge to set the root disk unit number */ 674 if ((nip = getenv("root_disk_unit")) != NULL) { 675 i = strtol(nip, &cp, 0); 676 /* check for parse error */ 677 if ((cp != nip) && (*cp == 0)) 678 unit = i; 679 } 680 681 rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition); 682 DEBUG("dev is 0x%x\n", rootdev); 683 return(rootdev); 684} 685