biosdisk.c revision 51586
143561Skato/*-
243561Skato * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
343561Skato * All rights reserved.
443561Skato *
543561Skato * Redistribution and use in source and binary forms, with or without
643561Skato * modification, are permitted provided that the following conditions
743561Skato * are met:
843561Skato * 1. Redistributions of source code must retain the above copyright
943561Skato *    notice, this list of conditions and the following disclaimer.
1043561Skato * 2. Redistributions in binary form must reproduce the above copyright
1143561Skato *    notice, this list of conditions and the following disclaimer in the
1243561Skato *    documentation and/or other materials provided with the distribution.
1343561Skato *
1443561Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1543561Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1643561Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1743561Skato * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1843561Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1943561Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2043561Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2143561Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2243561Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2343561Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2443561Skato * SUCH DAMAGE.
2543561Skato *
2650477Speter * $FreeBSD: head/sys/boot/pc98/libpc98/biosdisk.c 51586 1999-09-23 03:57:16Z kato $
2743561Skato */
2843561Skato
2943561Skato/*
3043561Skato * BIOS disk device handling.
3143561Skato *
3243561Skato * Ideas and algorithms from:
3343561Skato *
3443561Skato * - NetBSD libi386/biosdisk.c
3543561Skato * - FreeBSD biosboot/disk.c
3643561Skato *
3743561Skato * XXX Todo: add bad144 support.
3843561Skato */
3943561Skato
4043561Skato#include <stand.h>
4143561Skato
4243561Skato#include <sys/disklabel.h>
4343561Skato#include <sys/diskslice.h>
4443561Skato#include <sys/reboot.h>
4543561Skato
4643561Skato#include <stdarg.h>
4743561Skato
4843561Skato#include <bootstrap.h>
4943561Skato#include <btxv86.h>
5043561Skato#include "libi386.h"
5143561Skato
5243561Skato#define BIOSDISK_SECSIZE	512
5343561Skato#define BUFSIZE			(1 * BIOSDISK_SECSIZE)
5443561Skato#define	MAXBDDEV		MAXDEV
5543561Skato
5643561Skato#define DT_ATAPI		0x10		/* disk type for ATAPI floppies */
5743561Skato#define WDMAJOR			0		/* major numbers for devices we frontend for */
5843561Skato#define WFDMAJOR		1
5943561Skato#define FDMAJOR			2
6043561Skato#define DAMAJOR			4
6143561Skato
6243561Skato#ifdef DISK_DEBUG
6343561Skato# define DEBUG(fmt, args...)	printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
6443561Skato#else
6543561Skato# define DEBUG(fmt, args...)
6643561Skato#endif
6743561Skato
6843561Skatostruct open_disk {
6943561Skato    int			od_dkunit;		/* disk unit number */
7043561Skato    int			od_unit;		/* BIOS unit number */
7143561Skato    int			od_cyl;			/* BIOS geometry */
7243561Skato    int			od_hds;
7343561Skato    int			od_sec;
7443561Skato    int			od_boff;		/* block offset from beginning of BIOS disk */
7543561Skato    int			od_flags;
7643561Skato#define	BD_MODEMASK	0x3
7743561Skato#define BD_MODEINT13	0x0
7843561Skato#define BD_MODEEDD1	0x1
7943561Skato#define BD_MODEEDD3	0x2
8043561Skato#define BD_FLOPPY	(1<<2)
8143561Skato    struct disklabel		od_disklabel;
8243561Skato    struct dos_partition	od_parttab[NDOSPART];	/* XXX needs to grow for extended partitions */
8343561Skato#define BD_LABELOK	(1<<3)
8443561Skato#define BD_PARTTABOK	(1<<4)
8543561Skato};
8643561Skato
8743561Skato/*
8843561Skato * List of BIOS devices, translation from disk unit number to
8943561Skato * BIOS unit number.
9043561Skato */
9143561Skatostatic struct bdinfo
9243561Skato{
9343561Skato    int		bd_unit;		/* BIOS unit number */
9443561Skato    int		bd_flags;
9543561Skato    int		bd_type;		/* BIOS 'drive type' (floppy only) */
9643561Skato#ifdef PC98
9749426Skato    int         bd_da_unit;		/* kernel unit number for da */
9843561Skato#endif
9943561Skato} bdinfo [MAXBDDEV];
10043561Skatostatic int nbdinfo = 0;
10143561Skato
10243561Skatostatic int	bd_getgeom(struct open_disk *od);
10343561Skatostatic int	bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest);
10443561Skato
10543561Skatostatic int	bd_int13probe(struct bdinfo *bd);
10643561Skato
10743561Skatostatic void	bd_printslice(struct open_disk *od, int offset, char *prefix);
10843561Skato
10943561Skatostatic int	bd_init(void);
11043561Skatostatic int	bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
11143561Skatostatic int	bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
11243561Skatostatic int	bd_open(struct open_file *f, ...);
11343561Skatostatic int	bd_close(struct open_file *f);
11443561Skatostatic void	bd_print(int verbose);
11543561Skato
11643561Skatostruct devsw biosdisk = {
11743561Skato    "disk",
11843561Skato    DEVT_DISK,
11943561Skato    bd_init,
12043561Skato    bd_strategy,
12143561Skato    bd_open,
12243561Skato    bd_close,
12343561Skato    noioctl,
12443561Skato    bd_print
12543561Skato};
12643561Skato
12743561Skatostatic int	bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev);
12843561Skatostatic void	bd_closedisk(struct open_disk *od);
12943561Skatostatic int	bd_bestslice(struct dos_partition *dptr);
13043561Skato
13143561Skato/*
13243561Skato * Translate between BIOS device numbers and our private unit numbers.
13343561Skato */
13443561Skatoint
13543561Skatobd_bios2unit(int biosdev)
13643561Skato{
13743561Skato    int		i;
13843561Skato
13943561Skato    DEBUG("looking for bios device 0x%x", biosdev);
14043561Skato    for (i = 0; i < nbdinfo; i++) {
14143561Skato	DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
14243561Skato	if (bdinfo[i].bd_unit == biosdev)
14343561Skato	    return(i);
14443561Skato    }
14543561Skato    return(-1);
14643561Skato}
14743561Skato
14843561Skatoint
14943561Skatobd_unit2bios(int unit)
15043561Skato{
15143561Skato    if ((unit >= 0) && (unit < nbdinfo))
15243561Skato	return(bdinfo[unit].bd_unit);
15343561Skato    return(-1);
15443561Skato}
15543561Skato
15643561Skato/*
15743561Skato * Quiz the BIOS for disk devices, save a little info about them.
15843561Skato *
15943561Skato * XXX should we be consulting the BIOS equipment list, specifically
16043561Skato *     the value at 0x475?
16143561Skato */
16243561Skatostatic int
16343561Skatobd_init(void)
16443561Skato{
16543561Skato    int		base, unit;
16643561Skato
16743561Skato#ifdef PC98
16849426Skato    int         da_drive=0, n=-0x10;
16943561Skato    /* sequence 0x90, 0x80, 0xa0 */
17043561Skato    for (base = 0x90; base <= 0xa0; base += n, n += 0x30) {
17143561Skato	for (unit = base; (nbdinfo < MAXBDDEV) || ((unit & 0x0f) < 4); unit++) {
17243561Skato	    bdinfo[nbdinfo].bd_unit = unit;
17343561Skato	    bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0;
17443561Skato
17543561Skato	    /* XXX add EDD probes */
17644463Skato	    if (!bd_int13probe(&bdinfo[nbdinfo])){
17749425Skato		if (((unit & 0xf0) == 0x90 && (unit & 0x0f) < 4) ||
17849425Skato		    ((unit & 0xf0) == 0xa0 && (unit & 0x0f) < 6))
17944463Skato		    continue;	/* Target IDs are not contiguous. */
18044463Skato		else
18144463Skato		    break;
18244463Skato	    }
18343561Skato
18443561Skato	    if (bdinfo[nbdinfo].bd_flags & BD_FLOPPY){
18544467Skato		/* available 1.44MB access? */
18644467Skato		if (*(u_char *)PTOV(0xA15AE) & (1<<(unit & 0xf))){
18744467Skato		    /* boot media 1.2MB FD? */
18844467Skato		    if ((*(u_char *)PTOV(0xA1584) & 0xf0) != 0x90)
18944467Skato		        bdinfo[nbdinfo].bd_unit = 0x30 + (unit & 0xf);
19044467Skato		}
19143561Skato	    }
19249426Skato	    else {
19349426Skato		if ((unit & 0xa0) == 0xa0)
19449426Skato		    bdinfo[nbdinfo].bd_da_unit = da_drive++;
19549426Skato	    }
19643561Skato	    /* XXX we need "disk aliases" to make this simpler */
19743561Skato	    printf("BIOS drive %c: is disk%d\n",
19849426Skato		   'A' + nbdinfo, nbdinfo);
19943561Skato	    nbdinfo++;
20043561Skato	}
20143561Skato    }
20243561Skato#else
20343561Skato    /* sequence 0, 0x80 */
20443561Skato    for (base = 0; base <= 0x80; base += 0x80) {
20543561Skato	for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
20643561Skato	    bdinfo[nbdinfo].bd_unit = unit;
20743561Skato	    bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0;
20843561Skato
20943561Skato	    /* XXX add EDD probes */
21043561Skato	    if (!bd_int13probe(&bdinfo[nbdinfo]))
21143561Skato		break;
21243561Skato
21343561Skato	    /* XXX we need "disk aliases" to make this simpler */
21443561Skato	    printf("BIOS drive %c: is disk%d\n",
21543561Skato		   (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo);
21643561Skato	    nbdinfo++;
21743561Skato	}
21843561Skato    }
21943561Skato#endif
22043561Skato    return(0);
22143561Skato}
22243561Skato
22343561Skato/*
22443561Skato * Try to detect a device supported by the legacy int13 BIOS
22543561Skato */
22643561Skato
22743561Skatostatic int
22843561Skatobd_int13probe(struct bdinfo *bd)
22943561Skato{
23043561Skato#ifdef PC98
23143561Skato    int addr;
23243561Skato    if (bd->bd_flags & BD_FLOPPY){
23343561Skato	addr = 0xa155c;
23443561Skato    }
23543561Skato    else {
23643561Skato	if ((bd->bd_unit & 0xf0) == 0x80)
23743561Skato	    addr = 0xa155d;
23843561Skato	else
23943561Skato	    addr = 0xa1482;
24043561Skato    }
24143561Skato    if ( *(u_char *)PTOV(addr) & (1<<(bd->bd_unit & 0x0f))) {
24243561Skato	bd->bd_flags |= BD_MODEINT13;
24343561Skato	return(1);
24443561Skato    }
24543561Skato    return(0);
24643561Skato#else
24743561Skato    v86.ctl = V86_FLAGS;
24843561Skato    v86.addr = 0x13;
24943561Skato    v86.eax = 0x800;
25043561Skato    v86.edx = bd->bd_unit;
25143561Skato    v86int();
25243561Skato
25343561Skato    if (!(v86.efl & 0x1) &&				/* carry clear */
25443561Skato	((v86.edx & 0xff) > (bd->bd_unit & 0x7f))) {	/* unit # OK */
25543561Skato	bd->bd_flags |= BD_MODEINT13;
25643561Skato	bd->bd_type = v86.ebx & 0xff;
25743561Skato	return(1);
25843561Skato    }
25943561Skato#endif
26043561Skato    return(0);
26143561Skato}
26243561Skato
26343561Skato/*
26443561Skato * Print information about disks
26543561Skato */
26643561Skatostatic void
26743561Skatobd_print(int verbose)
26843561Skato{
26943561Skato    int				i, j;
27043561Skato    char			line[80];
27143561Skato    struct i386_devdesc		dev;
27243561Skato    struct open_disk		*od;
27343561Skato    struct dos_partition	*dptr;
27443561Skato
27543561Skato    for (i = 0; i < nbdinfo; i++) {
27643561Skato#ifdef PC98
27749426Skato	sprintf(line, "    disk%d:   BIOS drive %c:\n", i, 'A' + i);
27843561Skato#else
27943561Skato	sprintf(line, "    disk%d:   BIOS drive %c:\n", i,
28043561Skato		(bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80));
28143561Skato#endif
28243561Skato	pager_output(line);
28343561Skato
28443561Skato	/* try to open the whole disk */
28543561Skato	dev.d_kind.biosdisk.unit = i;
28643561Skato	dev.d_kind.biosdisk.slice = -1;
28743561Skato	dev.d_kind.biosdisk.partition = -1;
28843561Skato
28943561Skato	if (!bd_opendisk(&od, &dev)) {
29043561Skato
29143561Skato	    /* Do we have a partition table? */
29243561Skato	    if (od->od_flags & BD_PARTTABOK) {
29343561Skato		dptr = &od->od_parttab[0];
29443561Skato
29543561Skato		/* Check for a "truly dedicated" disk */
29643561Skato#ifdef PC98
29743561Skato		for (j = 0; j < NDOSPART; j++) {
29843561Skato		    switch(dptr[j].dp_mid) {
29943561Skato		    case DOSMID_386BSD:
30043561Skato		        sprintf(line, "      disk%ds%d", i, j + 1);
30143561Skato			bd_printslice(od, dptr[j].dp_scyl * od->od_hds * od->od_sec + dptr[j].dp_shd * od->od_sec + dptr[j].dp_ssect, line);
30243561Skato			break;
30343561Skato		    default:
30443561Skato		    }
30543561Skato		}
30643561Skato#else
30743561Skato		if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
30843561Skato		    (dptr[3].dp_start == 0) &&
30943561Skato		    (dptr[3].dp_size == 50000)) {
31043561Skato		    sprintf(line, "      disk%d", i);
31143561Skato		    bd_printslice(od, 0, line);
31243561Skato		} else {
31343561Skato		    for (j = 0; j < NDOSPART; j++) {
31443561Skato			switch(dptr[j].dp_typ) {
31543561Skato			case DOSPTYP_386BSD:
31643561Skato			    sprintf(line, "      disk%ds%d", i, j + 1);
31743561Skato			    bd_printslice(od, dptr[j].dp_start, line);
31843561Skato			    break;
31943561Skato			default:
32043561Skato			}
32143561Skato		    }
32243561Skato
32343561Skato		}
32443561Skato#endif
32543561Skato	    }
32643561Skato	    bd_closedisk(od);
32743561Skato	}
32843561Skato    }
32943561Skato}
33043561Skato
33143561Skatostatic void
33243561Skatobd_printslice(struct open_disk *od, int offset, char *prefix)
33343561Skato{
33443561Skato    char		line[80];
33543561Skato    u_char		buf[BIOSDISK_SECSIZE];
33643561Skato    struct disklabel	*lp;
33743561Skato    int			i;
33843561Skato
33943561Skato    /* read disklabel */
34043561Skato    if (bd_read(od, offset + LABELSECTOR, 1, buf))
34143561Skato	return;
34243561Skato    lp =(struct disklabel *)(&buf[0]);
34343561Skato    if (lp->d_magic != DISKMAGIC) {
34443561Skato	sprintf(line, "bad disklabel\n");
34543561Skato	pager_output(line);
34643561Skato	return;
34743561Skato    }
34843561Skato
34943561Skato    /* Print partitions */
35043561Skato    for (i = 0; i < lp->d_npartitions; i++) {
35143561Skato	if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || (lp->d_partitions[i].p_fstype == FS_SWAP) ||
35243561Skato	    ((lp->d_partitions[i].p_fstype == FS_UNUSED) &&
35343561Skato	     (od->od_flags & BD_FLOPPY) && (i == 0))) {	/* Floppies often have bogus fstype, print 'a' */
35443561Skato	    sprintf(line, "  %s%c: %s  %.6dMB (%d - %d)\n", prefix, 'a' + i,
35543561Skato		    (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : "FFS",
35643561Skato		    lp->d_partitions[i].p_size / 2048,	/* 512-byte sector assumption */
35743561Skato		    lp->d_partitions[i].p_offset, lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size);
35843561Skato	    pager_output(line);
35943561Skato	}
36043561Skato    }
36143561Skato}
36243561Skato
36343561Skato
36443561Skato/*
36543561Skato * Attempt to open the disk described by (dev) for use by (f).
36643561Skato *
36743561Skato * Note that the philosophy here is "give them exactly what
36843561Skato * they ask for".  This is necessary because being too "smart"
36943561Skato * about what the user might want leads to complications.
37043561Skato * (eg. given no slice or partition value, with a disk that is
37143561Skato *  sliced - are they after the first BSD slice, or the DOS
37243561Skato *  slice before it?)
37343561Skato */
37443561Skatostatic int
37543561Skatobd_open(struct open_file *f, ...)
37643561Skato{
37743561Skato    va_list			ap;
37843561Skato    struct i386_devdesc		*dev;
37943561Skato    struct open_disk		*od;
38043561Skato    int				error;
38143561Skato
38243561Skato    va_start(ap, f);
38343561Skato    dev = va_arg(ap, struct i386_devdesc *);
38443561Skato    va_end(ap);
38543561Skato    if ((error = bd_opendisk(&od, dev)))
38643561Skato	return(error);
38743561Skato
38843561Skato    /*
38943561Skato     * Save our context
39043561Skato     */
39143561Skato    ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od;
39243561Skato    DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff);
39343561Skato    return(0);
39443561Skato}
39543561Skato
39643561Skatostatic int
39743561Skatobd_opendisk(struct open_disk **odp, struct i386_devdesc *dev)
39843561Skato{
39943561Skato    struct dos_partition	*dptr;
40043561Skato    struct disklabel		*lp;
40143561Skato    struct open_disk		*od;
40243561Skato    int				sector, slice, i;
40343561Skato    int				error;
40443561Skato    u_char			buf[BUFSIZE];
40543561Skato    daddr_t			pref_slice[4];
40643561Skato
40743561Skato    if (dev->d_kind.biosdisk.unit >= nbdinfo) {
40843561Skato	DEBUG("attempt to open nonexistent disk");
40943561Skato	return(ENXIO);
41043561Skato    }
41143561Skato
41243561Skato    od = (struct open_disk *)malloc(sizeof(struct open_disk));
41343561Skato    if (!od) {
41443561Skato	DEBUG("no memory");
41543561Skato	return (ENOMEM);
41643561Skato    }
41743561Skato
41843561Skato    /* Look up BIOS unit number, intialise open_disk structure */
41943561Skato    od->od_dkunit = dev->d_kind.biosdisk.unit;
42043561Skato    od->od_unit = bdinfo[od->od_dkunit].bd_unit;
42143561Skato    od->od_flags = bdinfo[od->od_dkunit].bd_flags;
42243561Skato    od->od_boff = 0;
42343561Skato    error = 0;
42443561Skato    DEBUG("open '%s', unit 0x%x slice %d partition %c",
42543561Skato	     i386_fmtdev(dev), dev->d_kind.biosdisk.unit,
42643561Skato	     dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a');
42743561Skato
42843561Skato    /* Get geometry for this open (removable device may have changed) */
42943561Skato    if (bd_getgeom(od)) {
43043561Skato	DEBUG("can't get geometry");
43143561Skato	error = ENXIO;
43243561Skato	goto out;
43343561Skato    }
43443561Skato
43543561Skato    /*
43643561Skato     * Following calculations attempt to determine the correct value
43743561Skato     * for d->od_boff by looking for the slice and partition specified,
43843561Skato     * or searching for reasonable defaults.
43943561Skato     */
44043561Skato
44143561Skato    /*
44243561Skato     * Find the slice in the DOS slice table.
44343561Skato     */
44443561Skato#ifdef PC98
44543561Skato    if (od->od_flags & BD_FLOPPY) {
44643561Skato	sector = 0;
44743561Skato	goto unsliced;
44843561Skato    }
44943561Skato#endif
45043561Skato    if (bd_read(od, 0, 1, buf)) {
45143561Skato	DEBUG("error reading MBR");
45243561Skato	error = EIO;
45343561Skato	goto out;
45443561Skato    }
45543561Skato
45643561Skato    /*
45743561Skato     * Check the slice table magic.
45843561Skato     */
45943561Skato    if ((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) {
46043561Skato	/* If a slice number was explicitly supplied, this is an error */
46143561Skato	if (dev->d_kind.biosdisk.slice > 0) {
46243561Skato	    DEBUG("no slice table/MBR (no magic)");
46343561Skato	    error = ENOENT;
46443561Skato	    goto out;
46543561Skato	}
46643561Skato	sector = 0;
46743561Skato	goto unsliced;		/* may be a floppy */
46843561Skato    }
46943561Skato#ifdef PC98
47043561Skato    if (bd_read(od, 1, 1, buf)) {
47143561Skato	DEBUG("error reading MBR");
47243561Skato	error = EIO;
47343561Skato	goto out;
47443561Skato    }
47543561Skato#endif
47643561Skato    bcopy(buf + DOSPARTOFF, &od->od_parttab, sizeof(struct dos_partition) * NDOSPART);
47743561Skato    dptr = &od->od_parttab[0];
47843561Skato    od->od_flags |= BD_PARTTABOK;
47943561Skato
48043561Skato    /* Is this a request for the whole disk? */
48143561Skato    if (dev->d_kind.biosdisk.slice == -1) {
48243561Skato	sector = 0;
48343561Skato	goto unsliced;
48443561Skato    }
48543561Skato
48643561Skato    /* Try to auto-detect the best slice; this should always give a slice number */
48743561Skato    if (dev->d_kind.biosdisk.slice == 0)
48843561Skato	dev->d_kind.biosdisk.slice = bd_bestslice(dptr);
48943561Skato
49043561Skato    switch (dev->d_kind.biosdisk.slice) {
49143561Skato    case -1:
49243561Skato	error = ENOENT;
49343561Skato	goto out;
49443561Skato    case 0:
49543561Skato	sector = 0;
49643561Skato	goto unsliced;
49743561Skato    default:
49843561Skato	break;
49943561Skato    }
50043561Skato
50143561Skato    /*
50243561Skato     * Accept the supplied slice number unequivocally (we may be looking
50343561Skato     * at a DOS partition).
50443561Skato     */
50543561Skato    dptr += (dev->d_kind.biosdisk.slice - 1);	/* we number 1-4, offsets are 0-3 */
50643561Skato#ifdef PC98
50743561Skato    sector = dptr->dp_scyl * od->od_hds * od->od_sec + dptr->dp_shd * od->od_sec + dptr->dp_ssect;
50843561Skato    {
50943561Skato	int end = dptr->dp_ecyl * od->od_hds * od->od_sec + dptr->dp_ehd * od->od_sec + dptr->dp_esect;
51043561Skato	DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, end-sector);
51143561Skato    }
51243561Skato#else
51343561Skato    sector = dptr->dp_start;
51443561Skato    DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size);
51543561Skato#endif
51643561Skato
51743561Skato    /*
51843561Skato     * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition
51943561Skato     */
52043561Skato#ifdef PC98
52143561Skato    if ((dptr->dp_mid == DOSMID_386BSD) && (dev->d_kind.biosdisk.partition < 0))
52243561Skato#else
52343561Skato    if ((dptr->dp_typ == DOSPTYP_386BSD) && (dev->d_kind.biosdisk.partition < 0))
52443561Skato#endif
52543561Skato	dev->d_kind.biosdisk.partition = 0;
52643561Skato
52743561Skato unsliced:
52843561Skato    /*
52943561Skato     * Now we have the slice offset, look for the partition in the disklabel if we have
53043561Skato     * a partition to start with.
53143561Skato     *
53243561Skato     * XXX we might want to check the label checksum.
53343561Skato     */
53443561Skato    if (dev->d_kind.biosdisk.partition < 0) {
53543561Skato	od->od_boff = sector;		/* no partition, must be after the slice */
53643561Skato	DEBUG("opening raw slice");
53743561Skato    } else {
53843561Skato	if (bd_read(od, sector + LABELSECTOR, 1, buf)) {
53943561Skato	    DEBUG("error reading disklabel");
54043561Skato	    error = EIO;
54143561Skato	    goto out;
54243561Skato	}
54343561Skato	DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel);
54443561Skato	bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel));
54543561Skato	lp = &od->od_disklabel;
54643561Skato	od->od_flags |= BD_LABELOK;
54743561Skato
54843561Skato	if (lp->d_magic != DISKMAGIC) {
54943561Skato	    DEBUG("no disklabel");
55043561Skato	    error = ENOENT;
55143561Skato	    goto out;
55243561Skato	}
55343561Skato	if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) {
55443561Skato	    DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
55543561Skato		  'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions);
55643561Skato	    error = EPART;
55743561Skato	    goto out;
55843561Skato
55943561Skato	}
56043561Skato
56143561Skato	/* Complain if the partition type is wrong */
56243561Skato	if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) &&
56343561Skato	    !(od->od_flags & BD_FLOPPY))	    /* Floppies often have bogus fstype */
56443561Skato	    DEBUG("warning, partition marked as unused");
56543561Skato
56643561Skato	od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset;
56743561Skato    }
56843561Skato
56943561Skato out:
57043561Skato    if (error) {
57143561Skato	free(od);
57243561Skato    } else {
57343561Skato	*odp = od;	/* return the open disk */
57443561Skato    }
57543561Skato    return(error);
57643561Skato}
57743561Skato
57843561Skato
57943561Skato/*
58043561Skato * Search for a slice with the following preferences:
58143561Skato *
58243561Skato * 1: Active FreeBSD slice
58343561Skato * 2: Non-active FreeBSD slice
58443561Skato * 3: Active FAT/FAT32 slice
58543561Skato * 4: non-active FAT/FAT32 slice
58643561Skato */
58743561Skato#define PREF_FBSD_ACT	0
58843561Skato#define PREF_FBSD	1
58943561Skato#define PREF_DOS_ACT	2
59043561Skato#define PREF_DOS	3
59143561Skato#define PREF_NONE	4
59243561Skato
59343561Skatostatic int
59443561Skatobd_bestslice(struct dos_partition *dptr)
59543561Skato{
59643561Skato    int		i;
59743561Skato    int		preflevel, pref;
59843561Skato
59943561Skato
60043561Skato#ifndef PC98
60143561Skato    /*
60243561Skato     * Check for the historically bogus MBR found on true dedicated disks
60343561Skato     */
60443561Skato    if ((dptr[3].dp_typ == DOSPTYP_386BSD) &&
60543561Skato	(dptr[3].dp_start == 0) &&
60643561Skato	(dptr[3].dp_size == 50000))
60743561Skato	return(0);
60843561Skato#endif
60943561Skato
61043561Skato    preflevel = PREF_NONE;
61143561Skato    pref = -1;
61243561Skato
61343561Skato    /*
61443561Skato     * XXX No support here for 'extended' slices
61543561Skato     */
61643561Skato    for (i = 0; i < NDOSPART; i++) {
61743561Skato#ifdef PC98
61843561Skato	switch(dptr[i].dp_mid & 0x7f) {
61943561Skato	case DOSMID_386BSD & 0x7f:		/* FreeBSD */
62043561Skato	    if ((dptr[i].dp_mid & 0x80) && (preflevel > PREF_FBSD_ACT)) {
62143561Skato		pref = i;
62243561Skato		preflevel = PREF_FBSD_ACT;
62343561Skato	    } else if (preflevel > PREF_FBSD) {
62443561Skato		pref = i;
62543561Skato		preflevel = PREF_FBSD;
62643561Skato	    }
62743561Skato	    break;
62843561Skato
62943561Skato	    case 0x11:				/* DOS/Windows */
63043561Skato	    case 0x20:
63143561Skato	    case 0x21:
63243561Skato	    case 0x22:
63343561Skato	    case 0x23:
63443561Skato	    case 0x63:
63543561Skato	    if ((dptr[i].dp_mid & 0x80) && (preflevel > PREF_DOS_ACT)) {
63643561Skato		pref = i;
63743561Skato		preflevel = PREF_DOS_ACT;
63843561Skato	    } else if (preflevel > PREF_DOS) {
63943561Skato		pref = i;
64043561Skato		preflevel = PREF_DOS;
64143561Skato	    }
64243561Skato	    break;
64343561Skato	}
64443561Skato#else
64543561Skato	switch(dptr[i].dp_typ) {
64643561Skato	case DOSPTYP_386BSD:			/* FreeBSD */
64743561Skato	    if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_FBSD_ACT)) {
64843561Skato		pref = i;
64943561Skato		preflevel = PREF_FBSD_ACT;
65043561Skato	    } else if (preflevel > PREF_FBSD) {
65143561Skato		pref = i;
65243561Skato		preflevel = PREF_FBSD;
65343561Skato	    }
65443561Skato	    break;
65543561Skato
65643561Skato	    case 0x04:				/* DOS/Windows */
65743561Skato	    case 0x06:
65843561Skato	    case 0x0b:
65943561Skato	    case 0x0c:
66043561Skato	    case 0x0e:
66143561Skato	    case 0x63:
66243561Skato	    if ((dptr[i].dp_flag & 0x80) && (preflevel > PREF_DOS_ACT)) {
66343561Skato		pref = i;
66443561Skato		preflevel = PREF_DOS_ACT;
66543561Skato	    } else if (preflevel > PREF_DOS) {
66643561Skato		pref = i;
66743561Skato		preflevel = PREF_DOS;
66843561Skato	    }
66943561Skato	    break;
67043561Skato	}
67143561Skato#endif
67243561Skato    }
67343561Skato    return(pref + 1);	/* slices numbered 1-4 */
67443561Skato}
67543561Skato
67643561Skato
67743561Skatostatic int
67843561Skatobd_close(struct open_file *f)
67943561Skato{
68043561Skato    struct open_disk	*od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data);
68143561Skato
68243561Skato    bd_closedisk(od);
68343561Skato    return(0);
68443561Skato}
68543561Skato
68643561Skatostatic void
68743561Skatobd_closedisk(struct open_disk *od)
68843561Skato{
68943561Skato    DEBUG("open_disk %p", od);
69043561Skato#if 0
69143561Skato    /* XXX is this required? (especially if disk already open...) */
69243561Skato    if (od->od_flags & BD_FLOPPY)
69343561Skato	delay(3000000);
69443561Skato#endif
69543561Skato    free(od);
69643561Skato}
69743561Skato
69843561Skatostatic int
69943561Skatobd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
70043561Skato{
70143561Skato    struct bcache_devdata	bcd;
70243561Skato
70343561Skato    bcd.dv_strategy = bd_realstrategy;
70443561Skato    bcd.dv_devdata = devdata;
70543561Skato    return(bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
70643561Skato}
70743561Skato
70843561Skatostatic int
70943561Skatobd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
71043561Skato{
71143561Skato    struct open_disk	*od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data);
71243561Skato    int			blks;
71343561Skato#ifdef BD_SUPPORT_FRAGS
71443561Skato    char		fragbuf[BIOSDISK_SECSIZE];
71543561Skato    size_t		fragsize;
71643561Skato
71743561Skato    fragsize = size % BIOSDISK_SECSIZE;
71843561Skato#else
71943561Skato    if (size % BIOSDISK_SECSIZE)
72043561Skato	panic("bd_strategy: %d bytes I/O not multiple of block size", size);
72143561Skato#endif
72243561Skato
72343561Skato    DEBUG("open_disk %p", od);
72443561Skato
72543561Skato    if (rw != F_READ)
72643561Skato	return(EROFS);
72743561Skato
72843561Skato
72943561Skato    blks = size / BIOSDISK_SECSIZE;
73043561Skato    DEBUG("read %d from %d+%d to %p", blks, od->od_boff, dblk, buf);
73143561Skato
73243561Skato    if (rsize)
73343561Skato	*rsize = 0;
73443561Skato    if (blks && bd_read(od, dblk + od->od_boff, blks, buf)) {
73543561Skato	DEBUG("read error");
73643561Skato	return (EIO);
73743561Skato    }
73843561Skato#ifdef BD_SUPPORT_FRAGS
73943561Skato    DEBUG("bd_strategy: frag read %d from %d+%d+d to %p",
74043561Skato	     fragsize, od->od_boff, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
74143561Skato    if (fragsize && bd_read(od, dblk + od->od_boff + blks, 1, fragsize)) {
74243561Skato	DEBUG("frag read error");
74343561Skato	return(EIO);
74443561Skato    }
74543561Skato    bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
74643561Skato#endif
74743561Skato    if (rsize)
74843561Skato	*rsize = size;
74943561Skato    return (0);
75043561Skato}
75143561Skato
75243561Skato/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
75343561Skato#define FLOPPY_BOUNCEBUF	18
75443561Skato
75543561Skatostatic int
75643561Skatobd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest)
75743561Skato{
75843561Skato    int		x, bpc, cyl, hd, sec, result, resid, cnt, retry, maxfer;
75943561Skato    caddr_t	p, xp, bbuf, breg;
76043561Skato
76143561Skato    bpc = (od->od_sec * od->od_hds);		/* blocks per cylinder */
76243561Skato    resid = blks;
76343561Skato    p = dest;
76443561Skato
76543561Skato    /* Decide whether we have to bounce */
76643561Skato#ifdef PC98
76751586Skato    if (
76843561Skato#else
76943561Skato    if ((od->od_unit < 0x80) &&
77043561Skato#endif
77143561Skato	((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) {
77243561Skato
77343561Skato	/*
77443561Skato	 * There is a 64k physical boundary somewhere in the destination buffer, so we have
77543561Skato	 * to arrange a suitable bounce buffer.  Allocate a buffer twice as large as we
77643561Skato	 * need to.  Use the bottom half unless there is a break there, in which case we
77743561Skato	 * use the top half.
77843561Skato	 */
77951586Skato#ifdef PC98
78051586Skato	x = min(od->od_sec, blks);
78151586Skato#else
78243561Skato	x = min(FLOPPY_BOUNCEBUF, blks);
78351586Skato#endif
78443561Skato	bbuf = malloc(x * 2 * BIOSDISK_SECSIZE);
78543561Skato	if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) {
78643561Skato	    breg = bbuf;
78743561Skato	} else {
78843561Skato	    breg = bbuf + x * BIOSDISK_SECSIZE;
78943561Skato	}
79043561Skato	maxfer = x;			/* limit transfers to bounce region size */
79143561Skato    } else {
79243561Skato	bbuf = NULL;
79343561Skato	maxfer = 0;
79443561Skato    }
79543561Skato
79643561Skato    while (resid > 0) {
79743561Skato	x = dblk;
79843561Skato	cyl = x / bpc;			/* block # / blocks per cylinder */
79943561Skato	x %= bpc;			/* block offset into cylinder */
80043561Skato	hd = x / od->od_sec;		/* offset / blocks per track */
80143561Skato	sec = x % od->od_sec;		/* offset into track */
80243561Skato
80343561Skato	/* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */
80443561Skato	x = min(od->od_sec - sec, resid);
80543561Skato	if (maxfer > 0)
80643561Skato	    x = min(x, maxfer);		/* fit bounce buffer */
80743561Skato
80843561Skato	/* where do we transfer to? */
80943561Skato	xp = bbuf == NULL ? p : breg;
81043561Skato
81143561Skato	/* correct sector number for 1-based BIOS numbering */
81243561Skato#ifdef PC98
81343561Skato	if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90)
81443561Skato	    sec++;
81543561Skato#else
81643561Skato	sec++;
81743561Skato#endif
81843561Skato
81943561Skato	/* Loop retrying the operation a couple of times.  The BIOS may also retry. */
82043561Skato	for (retry = 0; retry < 3; retry++) {
82143561Skato	    /* if retrying, reset the drive */
82243561Skato	    if (retry > 0) {
82343561Skato#ifdef PC98
82451586Skato		v86.ctl = V86_FLAGS;
82551586Skato		v86.addr = 0x1b;
82651586Skato		v86.eax = 0x0300 | od->od_unit;
82743561Skato#else
82843561Skato		v86.ctl = V86_FLAGS;
82943561Skato		v86.addr = 0x13;
83043561Skato		v86.eax = 0;
83143561Skato		v86.edx = od->od_unit;
83251586Skato#endif
83343561Skato		v86int();
83443561Skato	    }
83543561Skato
83643561Skato	    /* build request  XXX support EDD requests too */
83751586Skato	    v86.ctl = V86_FLAGS;
83843561Skato#ifdef PC98
83943561Skato	    v86.addr = 0x1b;
84043561Skato	    if (od->od_flags & BD_FLOPPY) {
84143561Skato	        v86.eax = 0xd600 | od->od_unit;
84243561Skato		v86.ecx = 0x0200 | (cyl & 0xff);
84343561Skato	    }
84443561Skato	    else {
84543561Skato	        v86.eax = 0x0600 | od->od_unit;
84643561Skato		v86.ecx = cyl;
84743561Skato	    }
84843561Skato	    v86.edx = (hd << 8) | sec;
84943561Skato	    v86.ebx = x * BIOSDISK_SECSIZE;
85043561Skato	    v86.es = VTOPSEG(xp);
85143561Skato	    v86.ebp = VTOPOFF(xp);
85243561Skato#else
85343561Skato	    v86.addr = 0x13;
85443561Skato	    v86.eax = 0x200 | x;
85543561Skato	    v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
85643561Skato	    v86.edx = (hd << 8) | od->od_unit;
85743561Skato	    v86.es = VTOPSEG(xp);
85843561Skato	    v86.ebx = VTOPOFF(xp);
85951586Skato#endif
86043561Skato	    v86int();
86143561Skato	    result = (v86.efl & 0x1);
86243561Skato	    if (result == 0)
86343561Skato		break;
86443561Skato	}
86543561Skato
86643561Skato#ifdef PC98
86743561Skato 	DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), result ? "failed" : "ok");
86843561Skato	/* BUG here, cannot use v86 in printf because putchar uses it too */
86943561Skato	DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
87043561Skato	      od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit,
87143561Skato	      od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec,
87243561Skato	      (v86.eax >> 8) & 0xff);
87343561Skato#else
87443561Skato 	DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok");
87543561Skato	/* BUG here, cannot use v86 in printf because putchar uses it too */
87643561Skato	DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x",
87743561Skato	      0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff);
87843561Skato#endif
87943561Skato	if (result) {
88043561Skato	    if (bbuf != NULL)
88143561Skato		free(bbuf);
88243561Skato	    return(-1);
88343561Skato	}
88443561Skato	if (bbuf != NULL)
88543561Skato	    bcopy(breg, p, x * BIOSDISK_SECSIZE);
88643561Skato	p += (x * BIOSDISK_SECSIZE);
88743561Skato	dblk += x;
88843561Skato	resid -= x;
88943561Skato    }
89043561Skato
89143561Skato/*    hexdump(dest, (blks * BIOSDISK_SECSIZE)); */
89243561Skato    if (bbuf != NULL)
89343561Skato	free(bbuf);
89443561Skato    return(0);
89543561Skato}
89643561Skato
89743561Skatostatic int
89843561Skatobd_getgeom(struct open_disk *od)
89943561Skato{
90043561Skato
90143561Skato#ifdef PC98
90243561Skato    if (od->od_flags & BD_FLOPPY) {
90343561Skato        od->od_cyl = 79;
90443561Skato	od->od_hds = 2;
90543561Skato	od->od_sec = (od->od_unit & 0xf0) == 0x30 ? 18 : 15;
90643561Skato    }
90743561Skato    else {
90851586Skato        v86.ctl = V86_FLAGS;
90943561Skato	v86.addr = 0x1b;
91043561Skato	v86.eax = 0x8400 | od->od_unit;
91143561Skato	v86int();
91243561Skato
91343561Skato	od->od_cyl = v86.ecx;
91443561Skato	od->od_hds = (v86.edx >> 8) & 0xff;
91543561Skato	od->od_sec = v86.edx & 0xff;
91651586Skato	if (v86.efl & 0x1)
91751586Skato	    return(1);
91843561Skato    }
91943561Skato#else
92043561Skato    v86.ctl = V86_FLAGS;
92143561Skato    v86.addr = 0x13;
92243561Skato    v86.eax = 0x800;
92343561Skato    v86.edx = od->od_unit;
92443561Skato    v86int();
92543561Skato
92643561Skato    if ((v86.efl & 0x1) ||				/* carry set */
92743561Skato	((v86.edx & 0xff) <= (od->od_unit & 0x7f)))	/* unit # bad */
92843561Skato	return(1);
92943561Skato
93043561Skato    /* convert max cyl # -> # of cylinders */
93143561Skato    od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
93243561Skato    /* convert max head # -> # of heads */
93343561Skato    od->od_hds = ((v86.edx & 0xff00) >> 8) + 1;
93443561Skato    od->od_sec = v86.ecx & 0x3f;
93543561Skato#endif
93643561Skato
93743561Skato    DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec);
93843561Skato    return(0);
93943561Skato}
94043561Skato
94143561Skato/*
94243561Skato * Return a suitable dev_t value for (dev).
94343561Skato *
94443561Skato * In the case where it looks like (dev) is a SCSI disk, we allow the number of
94543561Skato * IDE disks to be specified in $num_ide_disks.  There should be a Better Way.
94643561Skato */
94743561Skatoint
94843561Skatobd_getdev(struct i386_devdesc *dev)
94943561Skato{
95043561Skato    struct open_disk		*od;
95143561Skato    int				biosdev;
95243561Skato    int 			major;
95343561Skato    int				rootdev;
95443561Skato    char			*nip, *cp;
95543561Skato    int				unitofs = 0, i, unit;
95643561Skato
95743561Skato    biosdev = bd_unit2bios(dev->d_kind.biosdisk.unit);
95843561Skato    DEBUG("unit %d BIOS device %d", dev->d_kind.biosdisk.unit, biosdev);
95943561Skato    if (biosdev == -1)				/* not a BIOS device */
96043561Skato	return(-1);
96143561Skato    if (bd_opendisk(&od, dev) != 0)		/* oops, not a viable device */
96243561Skato	return(-1);
96343561Skato
96443561Skato#ifdef PC98
96543561Skato    if ((biosdev & 0xf0) == 0x90 || (biosdev & 0xf0) == 0x30) {
96643561Skato#else
96743561Skato    if (biosdev < 0x80) {
96843561Skato#endif
96943561Skato	/* floppy (or emulated floppy) or ATAPI device */
97043561Skato	if (bdinfo[dev->d_kind.biosdisk.unit].bd_type == DT_ATAPI) {
97143561Skato	    /* is an ATAPI disk */
97243561Skato	    major = WFDMAJOR;
97343561Skato	} else {
97443561Skato	    /* is a floppy disk */
97543561Skato	    major = FDMAJOR;
97643561Skato	}
97743561Skato    } else {
97843561Skato	/* harddisk */
97943561Skato	if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) {
98043561Skato	    /* label OK, disk labelled as SCSI */
98143561Skato	    major = DAMAJOR;
98243561Skato	    /* check for unit number correction hint, now deprecated */
98343561Skato	    if ((nip = getenv("num_ide_disks")) != NULL) {
98443561Skato		i = strtol(nip, &cp, 0);
98543561Skato		/* check for parse error */
98643561Skato		if ((cp != nip) && (*cp == 0))
98743561Skato		    unitofs = i;
98843561Skato	    }
98943561Skato	} else {
99043561Skato	    /* assume an IDE disk */
99143561Skato	    major = WDMAJOR;
99243561Skato	}
99343561Skato    }
99443561Skato    /* XXX a better kludge to set the root disk unit number */
99543561Skato    if ((nip = getenv("root_disk_unit")) != NULL) {
99643561Skato	i = strtol(nip, &cp, 0);
99743561Skato	/* check for parse error */
99843561Skato	if ((cp != nip) && (*cp == 0))
99943561Skato	    unit = i;
100043561Skato    } else {
100143561Skato#ifdef PC98
100249426Skato	if ((biosdev & 0xf0) == 0xa0)
100349426Skato	    unit = bdinfo[dev->d_kind.biosdisk.unit].bd_da_unit;
100449426Skato	else
100549426Skato            unit = biosdev & 0xf;
100643561Skato#else
100743561Skato	unit = (biosdev & 0x7f) - unitofs;					/* allow for #wd compenstation in da case */
100843561Skato#endif
100943561Skato    }
101043561Skato
101143561Skato    rootdev = MAKEBOOTDEV(major,
101243561Skato			  (dev->d_kind.biosdisk.slice + 1) >> 4, 	/* XXX slices may be wrong here */
101343561Skato			  (dev->d_kind.biosdisk.slice + 1) & 0xf,
101443561Skato			  unit,
101543561Skato			  dev->d_kind.biosdisk.partition);
101643561Skato    DEBUG("dev is 0x%x\n", rootdev);
101743561Skato    return(rootdev);
101843561Skato}
101943561Skato
102043561Skato/*
102143561Skato * Fix (dev) so that it refers to the 'real' disk/slice/partition that it implies.
102243561Skato */
102343561Skatoint
102443561Skatobd_fixupdev(struct i386_devdesc *dev)
102543561Skato{
102643561Skato    struct open_disk *od;
102743561Skato
102843561Skato    /*
102943561Skato     * Open the disk.  This will fix up the slice and partition fields.
103043561Skato     */
103143561Skato    if (bd_opendisk(&od, dev) != 0)
103243561Skato	return(ENOENT);
103343561Skato
103443561Skato    bd_closedisk(od);
103543561Skato}
1036