biosdisk.c revision 130603
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 */ 2643561Skato 27119880Sobrien#include <sys/cdefs.h> 28119880Sobrien__FBSDID("$FreeBSD: head/sys/boot/pc98/libpc98/biosdisk.c 130603 2004-06-16 18:21:22Z phk $"); 29119880Sobrien 3043561Skato/* 3143561Skato * BIOS disk device handling. 3243561Skato * 3343561Skato * Ideas and algorithms from: 3443561Skato * 3543561Skato * - NetBSD libi386/biosdisk.c 3643561Skato * - FreeBSD biosboot/disk.c 3743561Skato * 3843561Skato */ 3943561Skato 4043561Skato#include <stand.h> 4143561Skato 4243561Skato#include <sys/disklabel.h> 43104621Snyan#include <sys/diskpc98.h> 44113083Sphk#include <machine/bootinfo.h> 4543561Skato 4643561Skato#include <stdarg.h> 4743561Skato 4843561Skato#include <bootstrap.h> 4943561Skato#include <btxv86.h> 5043561Skato#include "libi386.h" 5143561Skato 5263101Snyan#define BIOS_NUMDRIVES 0x475 5343561Skato#define BIOSDISK_SECSIZE 512 5443561Skato#define BUFSIZE (1 * BIOSDISK_SECSIZE) 5543561Skato#define MAXBDDEV MAXDEV 5643561Skato 5743561Skato#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ 5843561Skato#define WDMAJOR 0 /* major numbers for devices we frontend for */ 5943561Skato#define WFDMAJOR 1 6043561Skato#define FDMAJOR 2 6143561Skato#define DAMAJOR 4 6243561Skato 6343561Skato#ifdef DISK_DEBUG 6487599Sobrien# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 6543561Skato#else 6643561Skato# define DEBUG(fmt, args...) 6743561Skato#endif 6843561Skato 6943561Skatostruct open_disk { 7043561Skato int od_dkunit; /* disk unit number */ 7143561Skato int od_unit; /* BIOS unit number */ 7243561Skato int od_cyl; /* BIOS geometry */ 7343561Skato int od_hds; 7443561Skato int od_sec; 7543561Skato int od_boff; /* block offset from beginning of BIOS disk */ 7643561Skato int od_flags; 7759777Snyan#define BD_MODEINT13 0x0000 7859777Snyan#define BD_MODEEDD1 0x0001 7959777Snyan#define BD_MODEEDD3 0x0002 8063101Snyan#define BD_MODEMASK 0x0003 8159777Snyan#define BD_FLOPPY 0x0004 8259777Snyan#define BD_LABELOK 0x0008 8359777Snyan#define BD_PARTTABOK 0x0010 84108791Snyan#ifdef PC98 85108791Snyan#define BD_OPTICAL 0x0020 86108791Snyan#endif 8743561Skato struct disklabel od_disklabel; 8859777Snyan int od_nslices; /* slice count */ 89109638Snyan struct pc98_partition od_slicetab[NDOSPART]; 9043561Skato}; 9143561Skato 9243561Skato/* 9343561Skato * List of BIOS devices, translation from disk unit number to 9443561Skato * BIOS unit number. 9543561Skato */ 9643561Skatostatic struct bdinfo 9743561Skato{ 9843561Skato int bd_unit; /* BIOS unit number */ 9943561Skato int bd_flags; 10043561Skato int bd_type; /* BIOS 'drive type' (floppy only) */ 10143561Skato#ifdef PC98 10253207Snyan int bd_da_unit; /* kernel unit number for da */ 10343561Skato#endif 10443561Skato} bdinfo [MAXBDDEV]; 10543561Skatostatic int nbdinfo = 0; 10643561Skato 10743561Skatostatic int bd_getgeom(struct open_disk *od); 10859777Snyanstatic int bd_read(struct open_disk *od, daddr_t dblk, int blks, 10959777Snyan caddr_t dest); 11087734Snyanstatic int bd_write(struct open_disk *od, daddr_t dblk, int blks, 11187734Snyan caddr_t dest); 11243561Skato 11343561Skatostatic int bd_int13probe(struct bdinfo *bd); 11443561Skato 115108650Snyanstatic void bd_printslice(struct open_disk *od, struct pc98_partition *dp, 11668358Snyan char *prefix, int verbose); 11768358Snyanstatic void bd_printbsdslice(struct open_disk *od, daddr_t offset, 11868358Snyan char *prefix, int verbose); 11943561Skato 12043561Skatostatic int bd_init(void); 12159777Snyanstatic int bd_strategy(void *devdata, int flag, daddr_t dblk, 12268358Snyan size_t size, char *buf, size_t *rsize); 12359777Snyanstatic int bd_realstrategy(void *devdata, int flag, daddr_t dblk, 12468358Snyan size_t size, char *buf, size_t *rsize); 12543561Skatostatic int bd_open(struct open_file *f, ...); 12643561Skatostatic int bd_close(struct open_file *f); 12743561Skatostatic void bd_print(int verbose); 12843561Skato 12943561Skatostruct devsw biosdisk = { 13043561Skato "disk", 13143561Skato DEVT_DISK, 13243561Skato bd_init, 13343561Skato bd_strategy, 13443561Skato bd_open, 13543561Skato bd_close, 13643561Skato noioctl, 13768358Snyan bd_print, 13868358Snyan NULL 13943561Skato}; 14043561Skato 14143561Skatostatic int bd_opendisk(struct open_disk **odp, struct i386_devdesc *dev); 14243561Skatostatic void bd_closedisk(struct open_disk *od); 14359777Snyanstatic int bd_bestslice(struct open_disk *od); 14459777Snyanstatic void bd_checkextended(struct open_disk *od, int slicenum); 14543561Skato 14643561Skato/* 14743561Skato * Translate between BIOS device numbers and our private unit numbers. 14843561Skato */ 14943561Skatoint 15043561Skatobd_bios2unit(int biosdev) 15143561Skato{ 15243561Skato int i; 15343561Skato 15443561Skato DEBUG("looking for bios device 0x%x", biosdev); 15543561Skato for (i = 0; i < nbdinfo; i++) { 15643561Skato DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); 15743561Skato if (bdinfo[i].bd_unit == biosdev) 15843561Skato return(i); 15943561Skato } 16043561Skato return(-1); 16143561Skato} 16243561Skato 16343561Skatoint 16443561Skatobd_unit2bios(int unit) 16543561Skato{ 16643561Skato if ((unit >= 0) && (unit < nbdinfo)) 16743561Skato return(bdinfo[unit].bd_unit); 16843561Skato return(-1); 16943561Skato} 17043561Skato 17143561Skato/* 17243561Skato * Quiz the BIOS for disk devices, save a little info about them. 17343561Skato */ 17443561Skatostatic int 17543561Skatobd_init(void) 17643561Skato{ 17763101Snyan#ifdef PC98 17843561Skato int base, unit; 17963101Snyan int da_drive=0, n=-0x10; 18043561Skato 18143561Skato /* sequence 0x90, 0x80, 0xa0 */ 18243561Skato for (base = 0x90; base <= 0xa0; base += n, n += 0x30) { 18343561Skato for (unit = base; (nbdinfo < MAXBDDEV) || ((unit & 0x0f) < 4); unit++) { 18443561Skato bdinfo[nbdinfo].bd_unit = unit; 18543561Skato bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0; 18643561Skato 18744463Skato if (!bd_int13probe(&bdinfo[nbdinfo])){ 18849425Skato if (((unit & 0xf0) == 0x90 && (unit & 0x0f) < 4) || 18949425Skato ((unit & 0xf0) == 0xa0 && (unit & 0x0f) < 6)) 19044463Skato continue; /* Target IDs are not contiguous. */ 19144463Skato else 19244463Skato break; 19344463Skato } 19443561Skato 19543561Skato if (bdinfo[nbdinfo].bd_flags & BD_FLOPPY){ 19644467Skato /* available 1.44MB access? */ 19759777Snyan if (*(u_char *)PTOV(0xA15AE) & (1<<(unit & 0xf))) { 19844467Skato /* boot media 1.2MB FD? */ 19944467Skato if ((*(u_char *)PTOV(0xA1584) & 0xf0) != 0x90) 20044467Skato bdinfo[nbdinfo].bd_unit = 0x30 + (unit & 0xf); 20144467Skato } 20243561Skato } 20349426Skato else { 204108791Snyan if ((unit & 0xF0) == 0xA0) /* SCSI HD or MO */ 20549426Skato bdinfo[nbdinfo].bd_da_unit = da_drive++; 20649426Skato } 20743561Skato /* XXX we need "disk aliases" to make this simpler */ 20843561Skato printf("BIOS drive %c: is disk%d\n", 20949426Skato 'A' + nbdinfo, nbdinfo); 21043561Skato nbdinfo++; 21143561Skato } 21243561Skato } 21343561Skato#else 21463101Snyan int base, unit, nfd = 0; 21563101Snyan 21643561Skato /* sequence 0, 0x80 */ 21743561Skato for (base = 0; base <= 0x80; base += 0x80) { 21843561Skato for (unit = base; (nbdinfo < MAXBDDEV); unit++) { 21963101Snyan /* check the BIOS equipment list for number of fixed disks */ 22063101Snyan if((base == 0x80) && 22168358Snyan (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) 22263101Snyan break; 22363101Snyan 22443561Skato bdinfo[nbdinfo].bd_unit = unit; 22543561Skato bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0; 22643561Skato 22743561Skato if (!bd_int13probe(&bdinfo[nbdinfo])) 22843561Skato break; 22943561Skato 23043561Skato /* XXX we need "disk aliases" to make this simpler */ 23143561Skato printf("BIOS drive %c: is disk%d\n", 23243561Skato (unit < 0x80) ? ('A' + unit) : ('C' + unit - 0x80), nbdinfo); 23343561Skato nbdinfo++; 23463101Snyan if (base == 0x80) 23563101Snyan nfd++; 23643561Skato } 23743561Skato } 23843561Skato#endif 23943561Skato return(0); 24043561Skato} 24143561Skato 24243561Skato/* 24343561Skato * Try to detect a device supported by the legacy int13 BIOS 24443561Skato */ 24543561Skatostatic int 24643561Skatobd_int13probe(struct bdinfo *bd) 24743561Skato{ 24843561Skato#ifdef PC98 24943561Skato int addr; 25063101Snyan 25159777Snyan if (bd->bd_flags & BD_FLOPPY) { 25243561Skato addr = 0xa155c; 25359777Snyan } else { 25443561Skato if ((bd->bd_unit & 0xf0) == 0x80) 25543561Skato addr = 0xa155d; 25643561Skato else 25743561Skato addr = 0xa1482; 25843561Skato } 25943561Skato if ( *(u_char *)PTOV(addr) & (1<<(bd->bd_unit & 0x0f))) { 26043561Skato bd->bd_flags |= BD_MODEINT13; 26143561Skato return(1); 26243561Skato } 263108791Snyan if ((bd->bd_unit & 0xF0) == 0xA0) { 264108791Snyan int media = ((unsigned *)PTOV(0xA1460))[bd->bd_unit & 0x0F] & 0x1F; 265108791Snyan 266108791Snyan if (media == 7) { /* MO */ 267108791Snyan bd->bd_flags |= BD_MODEINT13 | BD_OPTICAL; 268108791Snyan return(1); 269108791Snyan } 270108791Snyan } 27143561Skato return(0); 27243561Skato#else 27343561Skato v86.ctl = V86_FLAGS; 27443561Skato v86.addr = 0x13; 27543561Skato v86.eax = 0x800; 27643561Skato v86.edx = bd->bd_unit; 27743561Skato v86int(); 27843561Skato 27943561Skato if (!(v86.efl & 0x1) && /* carry clear */ 28068358Snyan ((v86.edx & 0xff) > ((unsigned)bd->bd_unit & 0x7f))) { /* unit # OK */ 28143561Skato bd->bd_flags |= BD_MODEINT13; 28243561Skato bd->bd_type = v86.ebx & 0xff; 28363101Snyan 28463101Snyan /* Determine if we can use EDD with this device. */ 28563101Snyan v86.eax = 0x4100; 28663101Snyan v86.edx = bd->bd_unit; 28763101Snyan v86.ebx = 0x55aa; 28863101Snyan v86int(); 28963101Snyan if (!(v86.efl & 0x1) && /* carry clear */ 29063101Snyan ((v86.ebx & 0xffff) == 0xaa55) && /* signature */ 29163101Snyan (v86.ecx & 0x1)) { /* packets mode ok */ 29263101Snyan bd->bd_flags |= BD_MODEEDD1; 29368358Snyan if((v86.eax & 0xff00) > 0x300) 29463101Snyan bd->bd_flags |= BD_MODEEDD3; 29563101Snyan } 29643561Skato return(1); 29743561Skato } 29863101Snyan return(0); 29943561Skato#endif 30043561Skato} 30143561Skato 30243561Skato/* 30343561Skato * Print information about disks 30443561Skato */ 30543561Skatostatic void 30643561Skatobd_print(int verbose) 30743561Skato{ 30843561Skato int i, j; 30943561Skato char line[80]; 31043561Skato struct i386_devdesc dev; 31143561Skato struct open_disk *od; 312108650Snyan struct pc98_partition *dptr; 31343561Skato 31443561Skato for (i = 0; i < nbdinfo; i++) { 31543561Skato#ifdef PC98 31649426Skato sprintf(line, " disk%d: BIOS drive %c:\n", i, 'A' + i); 31743561Skato#else 31843561Skato sprintf(line, " disk%d: BIOS drive %c:\n", i, 31943561Skato (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit) : ('C' + bdinfo[i].bd_unit - 0x80)); 32043561Skato#endif 32143561Skato pager_output(line); 32243561Skato 32343561Skato /* try to open the whole disk */ 32443561Skato dev.d_kind.biosdisk.unit = i; 32543561Skato dev.d_kind.biosdisk.slice = -1; 32643561Skato dev.d_kind.biosdisk.partition = -1; 32743561Skato 32843561Skato if (!bd_opendisk(&od, &dev)) { 32943561Skato 33043561Skato /* Do we have a partition table? */ 33143561Skato if (od->od_flags & BD_PARTTABOK) { 33259777Snyan dptr = &od->od_slicetab[0]; 33343561Skato 33468358Snyan /* Check for a "dedicated" disk */ 33543561Skato#ifdef PC98 33659777Snyan for (j = 0; j < od->od_nslices; j++) { 33743561Skato switch(dptr[j].dp_mid) { 33843561Skato case DOSMID_386BSD: 33943561Skato sprintf(line, " disk%ds%d", i, j + 1); 34059777Snyan bd_printbsdslice(od, 34159777Snyan dptr[j].dp_scyl * od->od_hds * od->od_sec + 34259777Snyan dptr[j].dp_shd * od->od_sec + dptr[j].dp_ssect, 34368358Snyan line, verbose); 34443561Skato break; 34543561Skato default: 346130601Sphk break; 34743561Skato } 34843561Skato } 34943561Skato#else 35043561Skato if ((dptr[3].dp_typ == DOSPTYP_386BSD) && 35143561Skato (dptr[3].dp_start == 0) && 35243561Skato (dptr[3].dp_size == 50000)) { 35343561Skato sprintf(line, " disk%d", i); 35468358Snyan bd_printbsdslice(od, 0, line, verbose); 35543561Skato } else { 35659777Snyan for (j = 0; j < od->od_nslices; j++) { 35759777Snyan sprintf(line, " disk%ds%d", i, j + 1); 35868358Snyan bd_printslice(od, &dptr[j], line, verbose); 35959777Snyan } 36059777Snyan } 36143561Skato#endif 36243561Skato } 36343561Skato bd_closedisk(od); 36443561Skato } 36543561Skato } 36643561Skato} 36743561Skato 36868358Snyan#ifndef PC98 36959777Snyan/* 37068358Snyan * Print information about slices on a disk. For the size calculations we 37168358Snyan * assume a 512 byte sector. 37259777Snyan */ 37343561Skatostatic void 37468358Snyanbd_printslice(struct open_disk *od, struct dos_partition *dp, char *prefix, 37568358Snyan int verbose) 37643561Skato{ 37759777Snyan char line[80]; 37859777Snyan 37959777Snyan switch (dp->dp_typ) { 38059777Snyan case DOSPTYP_386BSD: 38168358Snyan bd_printbsdslice(od, (daddr_t)dp->dp_start, prefix, verbose); 38259777Snyan return; 38359777Snyan case DOSPTYP_LINSWP: 38468358Snyan if (verbose) 38568358Snyan sprintf(line, "%s: Linux swap %.6dMB (%d - %d)\n", 38668358Snyan prefix, dp->dp_size / 2048, 38768358Snyan dp->dp_start, dp->dp_start + dp->dp_size); 38868358Snyan else 38968358Snyan sprintf(line, "%s: Linux swap\n", prefix); 39059777Snyan break; 39159777Snyan case DOSPTYP_LINUX: 39259777Snyan /* 39359777Snyan * XXX 39459777Snyan * read the superblock to confirm this is an ext2fs partition? 39559777Snyan */ 39668358Snyan if (verbose) 39768358Snyan sprintf(line, "%s: ext2fs %.6dMB (%d - %d)\n", prefix, 39868358Snyan dp->dp_size / 2048, dp->dp_start, 39968358Snyan dp->dp_start + dp->dp_size); 40068358Snyan else 40168358Snyan sprintf(line, "%s: ext2fs\n", prefix); 40259777Snyan break; 40359777Snyan case 0x00: /* unused partition */ 40459777Snyan case DOSPTYP_EXT: 40559777Snyan return; 40659777Snyan case 0x01: 40768358Snyan if (verbose) 40868358Snyan sprintf(line, "%s: FAT-12 %.6dMB (%d - %d)\n", prefix, 40968358Snyan dp->dp_size / 2048, dp->dp_start, 41068358Snyan dp->dp_start + dp->dp_size); 41168358Snyan else 41268358Snyan sprintf(line, "%s: FAT-12\n", prefix); 41359777Snyan break; 41459777Snyan case 0x04: 41559777Snyan case 0x06: 41659777Snyan case 0x0e: 41768358Snyan if (verbose) 41868358Snyan sprintf(line, "%s: FAT-16 %.6dMB (%d - %d)\n", prefix, 41968358Snyan dp->dp_size / 2048, dp->dp_start, 42068358Snyan dp->dp_start + dp->dp_size); 42168358Snyan else 42268358Snyan sprintf(line, "%s: FAT-16\n", prefix); 42359777Snyan break; 42459777Snyan case 0x0b: 42559777Snyan case 0x0c: 42668358Snyan if (verbose) 42768358Snyan sprintf(line, "%s: FAT-32 %.6dMB (%d - %d)\n", prefix, 42868358Snyan dp->dp_size / 2048, dp->dp_start, 42968358Snyan dp->dp_start + dp->dp_size); 43068358Snyan else 43168358Snyan sprintf(line, "%s: FAT-32\n", prefix); 43259777Snyan break; 43359777Snyan default: 43468358Snyan if (verbose) 43568358Snyan sprintf(line, "%s: Unknown fs: 0x%x %.6dMB (%d - %d)\n", 43668358Snyan prefix, dp->dp_typ, dp->dp_size / 2048, 43768358Snyan dp->dp_start, dp->dp_start + dp->dp_size); 43868358Snyan else 43968358Snyan sprintf(line, "%s: Unknown fs: 0x%x\n", prefix, 44068358Snyan dp->dp_typ); 44159777Snyan } 44259777Snyan pager_output(line); 44359777Snyan} 44459777Snyan#endif 44559777Snyan 44668358Snyan/* 44768358Snyan * Print out each valid partition in the disklabel of a FreeBSD slice. 44868358Snyan * For size calculations, we assume a 512 byte sector size. 44968358Snyan */ 45059777Snyanstatic void 45168358Snyanbd_printbsdslice(struct open_disk *od, daddr_t offset, char *prefix, 45268358Snyan int verbose) 45359777Snyan{ 45443561Skato char line[80]; 45568358Snyan char buf[BIOSDISK_SECSIZE]; 45643561Skato struct disklabel *lp; 45743561Skato int i; 45843561Skato 45943561Skato /* read disklabel */ 46043561Skato if (bd_read(od, offset + LABELSECTOR, 1, buf)) 46143561Skato return; 46243561Skato lp =(struct disklabel *)(&buf[0]); 46343561Skato if (lp->d_magic != DISKMAGIC) { 46463101Snyan sprintf(line, "%s: FFS bad disklabel\n", prefix); 46543561Skato pager_output(line); 46643561Skato return; 46743561Skato } 46843561Skato 46943561Skato /* Print partitions */ 47043561Skato for (i = 0; i < lp->d_npartitions; i++) { 47168358Snyan /* 47268358Snyan * For each partition, make sure we know what type of fs it is. If 47368358Snyan * not, then skip it. However, since floppies often have bogus 47468358Snyan * fstypes, print the 'a' partition on a floppy even if it is marked 47568358Snyan * unused. 47668358Snyan */ 47763101Snyan if ((lp->d_partitions[i].p_fstype == FS_BSDFFS) || 47863101Snyan (lp->d_partitions[i].p_fstype == FS_SWAP) || 47963101Snyan (lp->d_partitions[i].p_fstype == FS_VINUM) || 48043561Skato ((lp->d_partitions[i].p_fstype == FS_UNUSED) && 48168358Snyan (od->od_flags & BD_FLOPPY) && (i == 0))) { 48268358Snyan 48368358Snyan /* Only print out statistics in verbose mode */ 48468358Snyan if (verbose) 48568358Snyan sprintf(line, " %s%c: %s %.6dMB (%d - %d)\n", prefix, 'a' + i, 48663101Snyan (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : 48768358Snyan (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : 48868358Snyan "FFS", 48968358Snyan lp->d_partitions[i].p_size / 2048, 49068358Snyan lp->d_partitions[i].p_offset, 49168358Snyan lp->d_partitions[i].p_offset + lp->d_partitions[i].p_size); 49268358Snyan else 49368358Snyan sprintf(line, " %s%c: %s\n", prefix, 'a' + i, 49468358Snyan (lp->d_partitions[i].p_fstype == FS_SWAP) ? "swap" : 49568358Snyan (lp->d_partitions[i].p_fstype == FS_VINUM) ? "vinum" : 49668358Snyan "FFS"); 49743561Skato pager_output(line); 49843561Skato } 49943561Skato } 50043561Skato} 50143561Skato 50243561Skato 50343561Skato/* 50443561Skato * Attempt to open the disk described by (dev) for use by (f). 50543561Skato * 50643561Skato * Note that the philosophy here is "give them exactly what 50743561Skato * they ask for". This is necessary because being too "smart" 50843561Skato * about what the user might want leads to complications. 50943561Skato * (eg. given no slice or partition value, with a disk that is 51043561Skato * sliced - are they after the first BSD slice, or the DOS 51143561Skato * slice before it?) 51243561Skato */ 51343561Skatostatic int 51443561Skatobd_open(struct open_file *f, ...) 51543561Skato{ 51643561Skato va_list ap; 51743561Skato struct i386_devdesc *dev; 51843561Skato struct open_disk *od; 51943561Skato int error; 52043561Skato 52143561Skato va_start(ap, f); 52243561Skato dev = va_arg(ap, struct i386_devdesc *); 52343561Skato va_end(ap); 52443561Skato if ((error = bd_opendisk(&od, dev))) 52543561Skato return(error); 52643561Skato 52743561Skato /* 52843561Skato * Save our context 52943561Skato */ 53043561Skato ((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data = od; 53143561Skato DEBUG("open_disk %p, partition at 0x%x", od, od->od_boff); 53243561Skato return(0); 53343561Skato} 53443561Skato 53543561Skatostatic int 53643561Skatobd_opendisk(struct open_disk **odp, struct i386_devdesc *dev) 53743561Skato{ 538108650Snyan struct pc98_partition *dptr; 53943561Skato struct disklabel *lp; 54043561Skato struct open_disk *od; 54143561Skato int sector, slice, i; 54243561Skato int error; 54368358Snyan char buf[BUFSIZE]; 54443561Skato 54543561Skato if (dev->d_kind.biosdisk.unit >= nbdinfo) { 54643561Skato DEBUG("attempt to open nonexistent disk"); 54743561Skato return(ENXIO); 54843561Skato } 54943561Skato 55043561Skato od = (struct open_disk *)malloc(sizeof(struct open_disk)); 55143561Skato if (!od) { 55243561Skato DEBUG("no memory"); 55343561Skato return (ENOMEM); 55443561Skato } 55543561Skato 55643561Skato /* Look up BIOS unit number, intialise open_disk structure */ 55743561Skato od->od_dkunit = dev->d_kind.biosdisk.unit; 55843561Skato od->od_unit = bdinfo[od->od_dkunit].bd_unit; 55943561Skato od->od_flags = bdinfo[od->od_dkunit].bd_flags; 56043561Skato od->od_boff = 0; 56159777Snyan od->od_nslices = 0; 56243561Skato error = 0; 56343561Skato DEBUG("open '%s', unit 0x%x slice %d partition %c", 56443561Skato i386_fmtdev(dev), dev->d_kind.biosdisk.unit, 56543561Skato dev->d_kind.biosdisk.slice, dev->d_kind.biosdisk.partition + 'a'); 56643561Skato 56743561Skato /* Get geometry for this open (removable device may have changed) */ 56843561Skato if (bd_getgeom(od)) { 56943561Skato DEBUG("can't get geometry"); 57043561Skato error = ENXIO; 57143561Skato goto out; 57243561Skato } 57343561Skato 57443561Skato /* 57543561Skato * Following calculations attempt to determine the correct value 57643561Skato * for d->od_boff by looking for the slice and partition specified, 57743561Skato * or searching for reasonable defaults. 57843561Skato */ 57943561Skato 58043561Skato /* 58143561Skato * Find the slice in the DOS slice table. 58243561Skato */ 58343561Skato#ifdef PC98 58443561Skato if (od->od_flags & BD_FLOPPY) { 58543561Skato sector = 0; 58643561Skato goto unsliced; 58743561Skato } 58843561Skato#endif 58943561Skato if (bd_read(od, 0, 1, buf)) { 59043561Skato DEBUG("error reading MBR"); 59143561Skato error = EIO; 59243561Skato goto out; 59343561Skato } 59443561Skato 59543561Skato /* 59643561Skato * Check the slice table magic. 59743561Skato */ 59868358Snyan if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { 59943561Skato /* If a slice number was explicitly supplied, this is an error */ 60043561Skato if (dev->d_kind.biosdisk.slice > 0) { 60143561Skato DEBUG("no slice table/MBR (no magic)"); 60243561Skato error = ENOENT; 60343561Skato goto out; 60443561Skato } 60543561Skato sector = 0; 60643561Skato goto unsliced; /* may be a floppy */ 60743561Skato } 60843561Skato#ifdef PC98 60943561Skato if (bd_read(od, 1, 1, buf)) { 61043561Skato DEBUG("error reading MBR"); 61143561Skato error = EIO; 61243561Skato goto out; 61343561Skato } 61443561Skato#endif 61559777Snyan 61659777Snyan /* 61759777Snyan * copy the partition table, then pick up any extended partitions. 61859777Snyan */ 61959777Snyan bcopy(buf + DOSPARTOFF, &od->od_slicetab, 620108650Snyan sizeof(struct pc98_partition) * NDOSPART); 62163101Snyan#ifdef PC98 62259777Snyan od->od_nslices = NDOSPART; /* extended slices start here */ 62363101Snyan#else 62463101Snyan od->od_nslices = 4; /* extended slices start here */ 62559777Snyan for (i = 0; i < NDOSPART; i++) 62659777Snyan bd_checkextended(od, i); 62759777Snyan#endif 62843561Skato od->od_flags |= BD_PARTTABOK; 62959777Snyan dptr = &od->od_slicetab[0]; 63043561Skato 63143561Skato /* Is this a request for the whole disk? */ 63243561Skato if (dev->d_kind.biosdisk.slice == -1) { 63343561Skato sector = 0; 63443561Skato goto unsliced; 63543561Skato } 63643561Skato 63759777Snyan /* 63859777Snyan * if a slice number was supplied but not found, this is an error. 63959777Snyan */ 64059777Snyan if (dev->d_kind.biosdisk.slice > 0) { 64159777Snyan slice = dev->d_kind.biosdisk.slice - 1; 64259777Snyan if (slice >= od->od_nslices) { 64359777Snyan DEBUG("slice %d not found", slice); 64459777Snyan error = ENOENT; 64559777Snyan goto out; 64659777Snyan } 64759777Snyan } 64843561Skato 64959777Snyan#ifndef PC98 65059777Snyan /* 65159777Snyan * Check for the historically bogus MBR found on true dedicated disks 65259777Snyan */ 65359777Snyan if ((dptr[3].dp_typ == DOSPTYP_386BSD) && 65459777Snyan (dptr[3].dp_start == 0) && 65559777Snyan (dptr[3].dp_size == 50000)) { 65659777Snyan sector = 0; 65759777Snyan goto unsliced; 65843561Skato } 65959777Snyan#endif 66043561Skato 66159777Snyan /* Try to auto-detect the best slice; this should always give a slice number */ 66259777Snyan if (dev->d_kind.biosdisk.slice == 0) { 66359777Snyan slice = bd_bestslice(od); 66459777Snyan if (slice == -1) { 66559777Snyan error = ENOENT; 66659777Snyan goto out; 66759777Snyan } 66859777Snyan dev->d_kind.biosdisk.slice = slice; 66959777Snyan } 67059777Snyan 67159777Snyan dptr = &od->od_slicetab[0]; 67243561Skato /* 67343561Skato * Accept the supplied slice number unequivocally (we may be looking 67443561Skato * at a DOS partition). 67543561Skato */ 67643561Skato dptr += (dev->d_kind.biosdisk.slice - 1); /* we number 1-4, offsets are 0-3 */ 67743561Skato#ifdef PC98 67859777Snyan sector = dptr->dp_scyl * od->od_hds * od->od_sec + 67959777Snyan dptr->dp_shd * od->od_sec + dptr->dp_ssect; 68043561Skato { 68159777Snyan int end = dptr->dp_ecyl * od->od_hds * od->od_sec + 68259777Snyan dptr->dp_ehd * od->od_sec + dptr->dp_esect; 68359777Snyan DEBUG("slice entry %d at %d, %d sectors", 68459777Snyan dev->d_kind.biosdisk.slice - 1, sector, end-sector); 68543561Skato } 68643561Skato#else 68743561Skato sector = dptr->dp_start; 68843561Skato DEBUG("slice entry %d at %d, %d sectors", dev->d_kind.biosdisk.slice - 1, sector, dptr->dp_size); 68943561Skato#endif 69043561Skato 69143561Skato /* 69243561Skato * If we are looking at a BSD slice, and the partition is < 0, assume the 'a' partition 69343561Skato */ 69443561Skato#ifdef PC98 69543561Skato if ((dptr->dp_mid == DOSMID_386BSD) && (dev->d_kind.biosdisk.partition < 0)) 69643561Skato#else 69743561Skato if ((dptr->dp_typ == DOSPTYP_386BSD) && (dev->d_kind.biosdisk.partition < 0)) 69843561Skato#endif 69943561Skato dev->d_kind.biosdisk.partition = 0; 70043561Skato 70143561Skato unsliced: 70243561Skato /* 70343561Skato * Now we have the slice offset, look for the partition in the disklabel if we have 70443561Skato * a partition to start with. 70543561Skato * 70643561Skato * XXX we might want to check the label checksum. 70743561Skato */ 70843561Skato if (dev->d_kind.biosdisk.partition < 0) { 70943561Skato od->od_boff = sector; /* no partition, must be after the slice */ 71043561Skato DEBUG("opening raw slice"); 71143561Skato } else { 71253207Snyan 71343561Skato if (bd_read(od, sector + LABELSECTOR, 1, buf)) { 71443561Skato DEBUG("error reading disklabel"); 71543561Skato error = EIO; 71643561Skato goto out; 71743561Skato } 71843561Skato DEBUG("copy %d bytes of label from %p to %p", sizeof(struct disklabel), buf + LABELOFFSET, &od->od_disklabel); 71943561Skato bcopy(buf + LABELOFFSET, &od->od_disklabel, sizeof(struct disklabel)); 72043561Skato lp = &od->od_disklabel; 72143561Skato od->od_flags |= BD_LABELOK; 72243561Skato 72343561Skato if (lp->d_magic != DISKMAGIC) { 72443561Skato DEBUG("no disklabel"); 72543561Skato error = ENOENT; 72643561Skato goto out; 72743561Skato } 72843561Skato if (dev->d_kind.biosdisk.partition >= lp->d_npartitions) { 72943561Skato DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 73043561Skato 'a' + dev->d_kind.biosdisk.partition, 'a' + lp->d_npartitions); 73143561Skato error = EPART; 73243561Skato goto out; 73343561Skato 73443561Skato } 73543561Skato 73668358Snyan#ifdef DISK_DEBUG 73768358Snyan /* Complain if the partition is unused unless this is a floppy. */ 73843561Skato if ((lp->d_partitions[dev->d_kind.biosdisk.partition].p_fstype == FS_UNUSED) && 73968358Snyan !(od->od_flags & BD_FLOPPY)) 74043561Skato DEBUG("warning, partition marked as unused"); 74168358Snyan#endif 74243561Skato 74343561Skato od->od_boff = lp->d_partitions[dev->d_kind.biosdisk.partition].p_offset; 74443561Skato } 74543561Skato 74643561Skato out: 74743561Skato if (error) { 74843561Skato free(od); 74943561Skato } else { 75043561Skato *odp = od; /* return the open disk */ 75143561Skato } 75243561Skato return(error); 75343561Skato} 75443561Skato 75559777Snyan#ifndef PC98 75659777Snyanstatic void 75759777Snyanbd_checkextended(struct open_disk *od, int slicenum) 75859777Snyan{ 75968358Snyan char buf[BIOSDISK_SECSIZE]; 76059777Snyan struct dos_partition *dp; 76159777Snyan u_int base; 76259777Snyan int i, start, end; 76343561Skato 76459777Snyan dp = &od->od_slicetab[slicenum]; 76559777Snyan start = od->od_nslices; 76659777Snyan 76759777Snyan if (dp->dp_size == 0) 76859777Snyan goto done; 76959777Snyan if (dp->dp_typ != DOSPTYP_EXT) 77059777Snyan goto done; 77168358Snyan if (bd_read(od, (daddr_t)dp->dp_start, 1, buf)) 77259777Snyan goto done; 77368358Snyan if (((u_char)buf[0x1fe] != 0x55) || ((u_char)buf[0x1ff] != 0xaa)) { 77459777Snyan DEBUG("no magic in extended table"); 77559777Snyan goto done; 77659777Snyan } 77759777Snyan base = dp->dp_start; 77859777Snyan dp = (struct dos_partition *)(&buf[DOSPARTOFF]); 77959777Snyan for (i = 0; i < NDOSPART; i++, dp++) { 78059777Snyan if (dp->dp_size == 0) 78159777Snyan continue; 782109638Snyan if (od->od_nslices == NDOSPART) 78359777Snyan goto done; 78459777Snyan dp->dp_start += base; 78559777Snyan bcopy(dp, &od->od_slicetab[od->od_nslices], sizeof(*dp)); 78659777Snyan od->od_nslices++; 78759777Snyan } 78859777Snyan end = od->od_nslices; 78959777Snyan 79059777Snyan /* 79159777Snyan * now, recursively check the slices we just added 79259777Snyan */ 79359777Snyan for (i = start; i < end; i++) 79459777Snyan bd_checkextended(od, i); 79559777Snyandone: 79659777Snyan return; 79759777Snyan} 79859777Snyan#endif 79959777Snyan 80043561Skato/* 80143561Skato * Search for a slice with the following preferences: 80243561Skato * 80343561Skato * 1: Active FreeBSD slice 80443561Skato * 2: Non-active FreeBSD slice 80559777Snyan * 3: Active Linux slice 80659777Snyan * 4: non-active Linux slice 80759777Snyan * 5: Active FAT/FAT32 slice 80859777Snyan * 6: non-active FAT/FAT32 slice 80943561Skato */ 81059777Snyan#define PREF_RAWDISK 0 81159777Snyan#define PREF_FBSD_ACT 1 81259777Snyan#define PREF_FBSD 2 81359777Snyan#define PREF_LINUX_ACT 3 81459777Snyan#define PREF_LINUX 4 81559777Snyan#define PREF_DOS_ACT 5 81659777Snyan#define PREF_DOS 6 81759777Snyan#define PREF_NONE 7 81843561Skato 81959777Snyan/* 82059777Snyan * slicelimit is in the range 0 .. NDOSPART 82159777Snyan */ 82243561Skatostatic int 82359777Snyanbd_bestslice(struct open_disk *od) 82443561Skato{ 825108650Snyan struct pc98_partition *dp; 82659777Snyan int pref, preflevel; 82759777Snyan int i, prefslice; 82853207Snyan 82959777Snyan prefslice = 0; 83059777Snyan preflevel = PREF_NONE; 83143561Skato 83259777Snyan dp = &od->od_slicetab[0]; 83359777Snyan for (i = 0; i < od->od_nslices; i++, dp++) { 83487734Snyan 83543561Skato#ifdef PC98 83659777Snyan switch(dp->dp_mid & 0x7f) { 83759777Snyan case DOSMID_386BSD & 0x7f: /* FreeBSD */ 83859777Snyan if ((dp->dp_mid & 0x80) && 83959777Snyan (preflevel > PREF_FBSD_ACT)) { 84059777Snyan pref = i; 84159777Snyan preflevel = PREF_FBSD_ACT; 84259777Snyan } else if (preflevel > PREF_FBSD) { 84359777Snyan pref = i; 84459777Snyan preflevel = PREF_FBSD; 84559777Snyan } 84659777Snyan break; 84759777Snyan 84859777Snyan case 0x11: /* DOS/Windows */ 84959777Snyan case 0x20: 85059777Snyan case 0x21: 85159777Snyan case 0x22: 85259777Snyan case 0x23: 85359777Snyan case 0x63: 85459777Snyan if ((dp->dp_mid & 0x80) && 85559777Snyan (preflevel > PREF_DOS_ACT)) { 85659777Snyan pref = i; 85759777Snyan preflevel = PREF_DOS_ACT; 85859777Snyan } else if (preflevel > PREF_DOS) { 85959777Snyan pref = i; 86059777Snyan preflevel = PREF_DOS; 86159777Snyan } 86259777Snyan break; 86359777Snyan } 86443561Skato#else 86559777Snyan switch (dp->dp_typ) { 86659777Snyan case DOSPTYP_386BSD: /* FreeBSD */ 86759777Snyan pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD; 86859777Snyan break; 86959777Snyan 87059777Snyan case DOSPTYP_LINUX: 87159777Snyan pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX; 87259777Snyan break; 87359777Snyan 87459777Snyan case 0x01: /* DOS/Windows */ 87559777Snyan case 0x04: 87659777Snyan case 0x06: 87759777Snyan case 0x0b: 87859777Snyan case 0x0c: 87959777Snyan case 0x0e: 88059777Snyan pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS; 88159777Snyan break; 88259777Snyan 88359777Snyan default: 88459777Snyan pref = PREF_NONE; 88559777Snyan } 88659777Snyan if (pref < preflevel) { 88759777Snyan preflevel = pref; 88859777Snyan prefslice = i + 1; 88959777Snyan } 89059777Snyan#endif 89143561Skato } 89259777Snyan return (prefslice); 89343561Skato} 89487734Snyan 89543561Skatostatic int 89643561Skatobd_close(struct open_file *f) 89743561Skato{ 89843561Skato struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data); 89943561Skato 90043561Skato bd_closedisk(od); 90143561Skato return(0); 90243561Skato} 90343561Skato 90443561Skatostatic void 90543561Skatobd_closedisk(struct open_disk *od) 90643561Skato{ 90743561Skato DEBUG("open_disk %p", od); 90843561Skato#if 0 90943561Skato /* XXX is this required? (especially if disk already open...) */ 91043561Skato if (od->od_flags & BD_FLOPPY) 91143561Skato delay(3000000); 91243561Skato#endif 91343561Skato free(od); 91443561Skato} 91543561Skato 91643561Skatostatic int 91768358Snyanbd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 91843561Skato{ 91943561Skato struct bcache_devdata bcd; 92058165Snyan struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); 92158165Snyan 92243561Skato bcd.dv_strategy = bd_realstrategy; 92343561Skato bcd.dv_devdata = devdata; 92458165Snyan return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, size, buf, rsize)); 92543561Skato} 92643561Skato 92743561Skatostatic int 92868358Snyanbd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 92943561Skato{ 93043561Skato struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); 93143561Skato int blks; 93243561Skato#ifdef BD_SUPPORT_FRAGS 93343561Skato char fragbuf[BIOSDISK_SECSIZE]; 93443561Skato size_t fragsize; 93543561Skato 93643561Skato fragsize = size % BIOSDISK_SECSIZE; 93743561Skato#else 93843561Skato if (size % BIOSDISK_SECSIZE) 93943561Skato panic("bd_strategy: %d bytes I/O not multiple of block size", size); 94043561Skato#endif 94143561Skato 94243561Skato DEBUG("open_disk %p", od); 94343561Skato 94443561Skato 94587734Snyan switch(rw){ 94687734Snyan case F_READ: 94743561Skato blks = size / BIOSDISK_SECSIZE; 94858165Snyan DEBUG("read %d from %d to %p", blks, dblk, buf); 94943561Skato 95043561Skato if (rsize) 95143561Skato *rsize = 0; 95258165Snyan if (blks && bd_read(od, dblk, blks, buf)) { 95343561Skato DEBUG("read error"); 95443561Skato return (EIO); 95543561Skato } 95643561Skato#ifdef BD_SUPPORT_FRAGS 95758165Snyan DEBUG("bd_strategy: frag read %d from %d+%d to %p", 95858165Snyan fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE)); 95958165Snyan if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) { 96043561Skato DEBUG("frag read error"); 96143561Skato return(EIO); 96243561Skato } 96343561Skato bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize); 96443561Skato#endif 96543561Skato if (rsize) 96643561Skato *rsize = size; 96743561Skato return (0); 96887734Snyan break; 96987734Snyan 97087734Snyan case F_WRITE : 97187734Snyan blks = size / BIOSDISK_SECSIZE; 97287734Snyan DEBUG("write %d from %d to %p", blks, dblk, buf); 97387734Snyan 97487734Snyan if (rsize) 97587734Snyan *rsize = 0; 97687734Snyan if (blks && bd_write(od, dblk, blks, buf)) { 97787734Snyan DEBUG("write error"); 97887734Snyan return (EIO); 97987734Snyan } 98087734Snyan#ifdef BD_SUPPORT_FRAGS 98187734Snyan if(fragsize) { 98287734Snyan DEBUG("Attempted to write a frag"); 98387734Snyan return (EIO); 98487734Snyan } 98587734Snyan#endif 98687734Snyan 98787734Snyan if (rsize) 98887734Snyan *rsize = size; 98987734Snyan return (0); 99087734Snyan default: 99187734Snyan /* DO NOTHING */ 992130579Sphk beak; 99387734Snyan } 99487734Snyan 99587734Snyan return EROFS; 99643561Skato} 99743561Skato 99843561Skato/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ 99943561Skato#define FLOPPY_BOUNCEBUF 18 100043561Skato 100143561Skatostatic int 100243561Skatobd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) 100343561Skato{ 100468358Snyan u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; 100543561Skato caddr_t p, xp, bbuf, breg; 100643561Skato 100768358Snyan /* Just in case some idiot actually tries to read -1 blocks... */ 100868358Snyan if (blks < 0) 100968358Snyan return (-1); 101068358Snyan 101143561Skato bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ 101243561Skato resid = blks; 101343561Skato p = dest; 101443561Skato 101543561Skato /* Decide whether we have to bounce */ 101643561Skato#ifdef PC98 101751586Skato if ( 101843561Skato#else 101943561Skato if ((od->od_unit < 0x80) && 102043561Skato#endif 102143561Skato ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) { 102243561Skato 102343561Skato /* 102443561Skato * There is a 64k physical boundary somewhere in the destination buffer, so we have 102543561Skato * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we 102643561Skato * need to. Use the bottom half unless there is a break there, in which case we 102743561Skato * use the top half. 102843561Skato */ 102951586Skato#ifdef PC98 103068358Snyan x = min(od->od_sec, (unsigned)blks); 103151586Skato#else 103268358Snyan x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); 103351586Skato#endif 103443561Skato bbuf = malloc(x * 2 * BIOSDISK_SECSIZE); 103543561Skato if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) { 103643561Skato breg = bbuf; 103743561Skato } else { 103843561Skato breg = bbuf + x * BIOSDISK_SECSIZE; 103943561Skato } 104043561Skato maxfer = x; /* limit transfers to bounce region size */ 104143561Skato } else { 104268358Snyan breg = bbuf = NULL; 104343561Skato maxfer = 0; 104443561Skato } 104543561Skato 104643561Skato while (resid > 0) { 104743561Skato x = dblk; 104843561Skato cyl = x / bpc; /* block # / blocks per cylinder */ 104943561Skato x %= bpc; /* block offset into cylinder */ 105043561Skato hd = x / od->od_sec; /* offset / blocks per track */ 105143561Skato sec = x % od->od_sec; /* offset into track */ 105243561Skato 105343561Skato /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ 105443561Skato x = min(od->od_sec - sec, resid); 105543561Skato if (maxfer > 0) 105643561Skato x = min(x, maxfer); /* fit bounce buffer */ 105743561Skato 105843561Skato /* where do we transfer to? */ 105943561Skato xp = bbuf == NULL ? p : breg; 106043561Skato 106143561Skato /* correct sector number for 1-based BIOS numbering */ 106243561Skato#ifdef PC98 106343561Skato if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90) 106443561Skato sec++; 106543561Skato#else 106643561Skato sec++; 106743561Skato#endif 106843561Skato 106943561Skato /* Loop retrying the operation a couple of times. The BIOS may also retry. */ 107043561Skato for (retry = 0; retry < 3; retry++) { 107143561Skato /* if retrying, reset the drive */ 107243561Skato if (retry > 0) { 107343561Skato#ifdef PC98 107451586Skato v86.ctl = V86_FLAGS; 107551586Skato v86.addr = 0x1b; 107651586Skato v86.eax = 0x0300 | od->od_unit; 107743561Skato#else 107843561Skato v86.ctl = V86_FLAGS; 107943561Skato v86.addr = 0x13; 108043561Skato v86.eax = 0; 108143561Skato v86.edx = od->od_unit; 108251586Skato#endif 108343561Skato v86int(); 108443561Skato } 108543561Skato 108663101Snyan#ifdef PC98 108751586Skato v86.ctl = V86_FLAGS; 108843561Skato v86.addr = 0x1b; 108943561Skato if (od->od_flags & BD_FLOPPY) { 109043561Skato v86.eax = 0xd600 | od->od_unit; 109143561Skato v86.ecx = 0x0200 | (cyl & 0xff); 109243561Skato } 109343561Skato else { 109443561Skato v86.eax = 0x0600 | od->od_unit; 109543561Skato v86.ecx = cyl; 109643561Skato } 1097108791Snyan if (od->od_flags & BD_OPTICAL) { 1098108791Snyan v86.eax &= 0xFF7F; 1099108791Snyan v86.ecx = dblk & 0xFFFF; 1100108791Snyan v86.edx = dblk >> 16; 1101108791Snyan } else { 1102108791Snyan v86.edx = (hd << 8) | sec; 1103108791Snyan } 110443561Skato v86.ebx = x * BIOSDISK_SECSIZE; 110543561Skato v86.es = VTOPSEG(xp); 110643561Skato v86.ebp = VTOPOFF(xp); 110743561Skato v86int(); 110843561Skato result = (v86.efl & 0x1); 110943561Skato if (result == 0) 111043561Skato break; 111163101Snyan#else 111263101Snyan if(cyl > 1023) { 111363101Snyan /* use EDD if the disk supports it, otherwise, return error */ 111463101Snyan if(od->od_flags & BD_MODEEDD1) { 111563101Snyan static unsigned short packet[8]; 111663101Snyan 111763101Snyan packet[0] = 0x10; 111863101Snyan packet[1] = x; 111963101Snyan packet[2] = VTOPOFF(xp); 112063101Snyan packet[3] = VTOPSEG(xp); 112163101Snyan packet[4] = dblk & 0xffff; 112263101Snyan packet[5] = dblk >> 16; 112363101Snyan packet[6] = 0; 112463101Snyan packet[7] = 0; 112563101Snyan v86.ctl = V86_FLAGS; 112663101Snyan v86.addr = 0x13; 112763101Snyan v86.eax = 0x4200; 112863101Snyan v86.edx = od->od_unit; 112963101Snyan v86.ds = VTOPSEG(packet); 113063101Snyan v86.esi = VTOPOFF(packet); 113163101Snyan v86int(); 113263101Snyan result = (v86.efl & 0x1); 113363101Snyan if(result == 0) 113463101Snyan break; 113563101Snyan } else { 113663101Snyan result = 1; 113763101Snyan break; 113863101Snyan } 113963101Snyan } else { 114063101Snyan /* Use normal CHS addressing */ 114163101Snyan v86.ctl = V86_FLAGS; 114263101Snyan v86.addr = 0x13; 114363101Snyan v86.eax = 0x200 | x; 114463101Snyan v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 114563101Snyan v86.edx = (hd << 8) | od->od_unit; 114663101Snyan v86.es = VTOPSEG(xp); 114763101Snyan v86.ebx = VTOPOFF(xp); 114863101Snyan v86int(); 114963101Snyan result = (v86.efl & 0x1); 115063101Snyan if (result == 0) 115163101Snyan break; 115263101Snyan } 115363101Snyan#endif 115443561Skato } 115543561Skato 115643561Skato#ifdef PC98 115743561Skato 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"); 115843561Skato /* BUG here, cannot use v86 in printf because putchar uses it too */ 115943561Skato DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 116043561Skato od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit, 116143561Skato od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec, 116243561Skato (v86.eax >> 8) & 0xff); 116343561Skato#else 116443561Skato DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); 116543561Skato /* BUG here, cannot use v86 in printf because putchar uses it too */ 116643561Skato DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 116743561Skato 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); 116843561Skato#endif 116943561Skato if (result) { 117043561Skato if (bbuf != NULL) 117143561Skato free(bbuf); 117243561Skato return(-1); 117343561Skato } 117443561Skato if (bbuf != NULL) 117543561Skato bcopy(breg, p, x * BIOSDISK_SECSIZE); 117643561Skato p += (x * BIOSDISK_SECSIZE); 117743561Skato dblk += x; 117843561Skato resid -= x; 117943561Skato } 118043561Skato 118143561Skato/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ 118243561Skato if (bbuf != NULL) 118343561Skato free(bbuf); 118443561Skato return(0); 118543561Skato} 118643561Skato 118787734Snyan 118843561Skatostatic int 118987734Snyanbd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) 119087734Snyan{ 119187734Snyan u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; 119287734Snyan caddr_t p, xp, bbuf, breg; 119387734Snyan 119487734Snyan /* Just in case some idiot actually tries to read -1 blocks... */ 119587734Snyan if (blks < 0) 119687734Snyan return (-1); 119787734Snyan 119887734Snyan bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ 119987734Snyan resid = blks; 120087734Snyan p = dest; 120187734Snyan 120287734Snyan /* Decide whether we have to bounce */ 120387734Snyan#ifdef PC98 120487734Snyan if ( 120587734Snyan#else 120687734Snyan if ((od->od_unit < 0x80) && 120787734Snyan#endif 120887734Snyan ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) { 120987734Snyan 121087734Snyan /* 121187734Snyan * There is a 64k physical boundary somewhere in the destination buffer, so we have 121287734Snyan * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we 121387734Snyan * need to. Use the bottom half unless there is a break there, in which case we 121487734Snyan * use the top half. 121587734Snyan */ 121687734Snyan 121787734Snyan#ifdef PC98 121887734Snyan x = min(od->od_sec, (unsigned)blks); 121987734Snyan#else 122087734Snyan x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); 122187734Snyan#endif 122287734Snyan bbuf = malloc(x * 2 * BIOSDISK_SECSIZE); 122387734Snyan if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) { 122487734Snyan breg = bbuf; 122587734Snyan } else { 122687734Snyan breg = bbuf + x * BIOSDISK_SECSIZE; 122787734Snyan } 122887734Snyan maxfer = x; /* limit transfers to bounce region size */ 122987734Snyan } else { 123087734Snyan breg = bbuf = NULL; 123187734Snyan maxfer = 0; 123287734Snyan } 123387734Snyan 123487734Snyan while (resid > 0) { 123587734Snyan x = dblk; 123687734Snyan cyl = x / bpc; /* block # / blocks per cylinder */ 123787734Snyan x %= bpc; /* block offset into cylinder */ 123887734Snyan hd = x / od->od_sec; /* offset / blocks per track */ 123987734Snyan sec = x % od->od_sec; /* offset into track */ 124087734Snyan 124187734Snyan /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ 124287734Snyan x = min(od->od_sec - sec, resid); 124387734Snyan if (maxfer > 0) 124487734Snyan x = min(x, maxfer); /* fit bounce buffer */ 124587734Snyan 124687734Snyan /* where do we transfer to? */ 124787734Snyan xp = bbuf == NULL ? p : breg; 124887734Snyan 124987734Snyan /* correct sector number for 1-based BIOS numbering */ 125087734Snyan#ifdef PC98 125187734Snyan if ((od->od_unit & 0xf0) == 0x30 || (od->od_unit & 0xf0) == 0x90) 125287734Snyan sec++; 125387734Snyan#else 125487734Snyan sec++; 125587734Snyan#endif 125687734Snyan 125787734Snyan 125887734Snyan /* Put your Data In, Put your Data out, 125987734Snyan Put your Data In, and shake it all about 126087734Snyan */ 126187734Snyan if (bbuf != NULL) 126287734Snyan bcopy(p, breg, x * BIOSDISK_SECSIZE); 126387734Snyan p += (x * BIOSDISK_SECSIZE); 126487734Snyan dblk += x; 126587734Snyan resid -= x; 126687734Snyan 126787734Snyan /* Loop retrying the operation a couple of times. The BIOS may also retry. */ 126887734Snyan for (retry = 0; retry < 3; retry++) { 126987734Snyan /* if retrying, reset the drive */ 127087734Snyan if (retry > 0) { 127187734Snyan#ifdef PC98 127287734Snyan v86.ctl = V86_FLAGS; 127387734Snyan v86.addr = 0x1b; 127487734Snyan v86.eax = 0x0300 | od->od_unit; 127587734Snyan#else 127687734Snyan v86.ctl = V86_FLAGS; 127787734Snyan v86.addr = 0x13; 127887734Snyan v86.eax = 0; 127987734Snyan v86.edx = od->od_unit; 128087734Snyan#endif 128187734Snyan v86int(); 128287734Snyan } 128387734Snyan 128487734Snyan#ifdef PC98 128587734Snyan v86.ctl = V86_FLAGS; 128687734Snyan v86.addr = 0x1b; 128787734Snyan if (od->od_flags & BD_FLOPPY) { 128887734Snyan v86.eax = 0xd500 | od->od_unit; 128987734Snyan v86.ecx = 0x0200 | (cyl & 0xff); 129087734Snyan } else { 129187734Snyan v86.eax = 0x0500 | od->od_unit; 129287734Snyan v86.ecx = cyl; 129387734Snyan } 129487734Snyan v86.edx = (hd << 8) | sec; 129587734Snyan v86.ebx = x * BIOSDISK_SECSIZE; 129687734Snyan v86.es = VTOPSEG(xp); 129787734Snyan v86.ebp = VTOPOFF(xp); 129887734Snyan v86int(); 129987734Snyan result = (v86.efl & 0x1); 130087734Snyan if (result == 0) 130187734Snyan break; 130287734Snyan#else 130387734Snyan if(cyl > 1023) { 130487734Snyan /* use EDD if the disk supports it, otherwise, return error */ 130587734Snyan if(od->od_flags & BD_MODEEDD1) { 130687734Snyan static unsigned short packet[8]; 130787734Snyan 130887734Snyan packet[0] = 0x10; 130987734Snyan packet[1] = x; 131087734Snyan packet[2] = VTOPOFF(xp); 131187734Snyan packet[3] = VTOPSEG(xp); 131287734Snyan packet[4] = dblk & 0xffff; 131387734Snyan packet[5] = dblk >> 16; 131487734Snyan packet[6] = 0; 131587734Snyan packet[7] = 0; 131687734Snyan v86.ctl = V86_FLAGS; 131787734Snyan v86.addr = 0x13; 131887734Snyan /* Should we Write with verify ?? 0x4302 ? */ 131987734Snyan v86.eax = 0x4300; 132087734Snyan v86.edx = od->od_unit; 132187734Snyan v86.ds = VTOPSEG(packet); 132287734Snyan v86.esi = VTOPOFF(packet); 132387734Snyan v86int(); 132487734Snyan result = (v86.efl & 0x1); 132587734Snyan if(result == 0) 132687734Snyan break; 132787734Snyan } else { 132887734Snyan result = 1; 132987734Snyan break; 133087734Snyan } 133187734Snyan } else { 133287734Snyan /* Use normal CHS addressing */ 133387734Snyan v86.ctl = V86_FLAGS; 133487734Snyan v86.addr = 0x13; 133587734Snyan v86.eax = 0x300 | x; 133687734Snyan v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 133787734Snyan v86.edx = (hd << 8) | od->od_unit; 133887734Snyan v86.es = VTOPSEG(xp); 133987734Snyan v86.ebx = VTOPOFF(xp); 134087734Snyan v86int(); 134187734Snyan result = (v86.efl & 0x1); 134287734Snyan if (result == 0) 134387734Snyan break; 134487734Snyan } 134587734Snyan#endif 134687734Snyan } 134787734Snyan 134887734Snyan#ifdef PC98 134987734Snyan DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, 135087734Snyan od->od_flags & BD_FLOPPY ? sec - 1 : sec, p, VTOP(p), 135187734Snyan result ? "failed" : "ok"); 135287734Snyan /* BUG here, cannot use v86 in printf because putchar uses it too */ 135387734Snyan DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 135487734Snyan od->od_flags & BD_FLOPPY ? 0xd600 | od->od_unit : 0x0600 | od->od_unit, 135587734Snyan od->od_flags & BD_FLOPPY ? 0x0200 | cyl : cyl, (hd << 8) | sec, 135687734Snyan (v86.eax >> 8) & 0xff); 135787734Snyan#else 135887734Snyan DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); 135987734Snyan /* BUG here, cannot use v86 in printf because putchar uses it too */ 136087734Snyan DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", 136187734Snyan 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); 136287734Snyan#endif 136387734Snyan if (result) { 136487734Snyan if (bbuf != NULL) 136587734Snyan free(bbuf); 136687734Snyan return(-1); 136787734Snyan } 136887734Snyan } 136987734Snyan 137087734Snyan/* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ 137187734Snyan if (bbuf != NULL) 137287734Snyan free(bbuf); 137387734Snyan return(0); 137487734Snyan} 137587734Snyanstatic int 137643561Skatobd_getgeom(struct open_disk *od) 137743561Skato{ 137843561Skato 137943561Skato#ifdef PC98 138043561Skato if (od->od_flags & BD_FLOPPY) { 138154819Snyan od->od_cyl = 79; 138243561Skato od->od_hds = 2; 138343561Skato od->od_sec = (od->od_unit & 0xf0) == 0x30 ? 18 : 15; 1384108791Snyan } else if (od->od_flags & BD_OPTICAL) { 1385108791Snyan od->od_cyl = 0xFFFE; 1386108791Snyan od->od_hds = 8; 1387108791Snyan od->od_sec = 32; 138859777Snyan } else { 138954819Snyan v86.ctl = V86_FLAGS; 139043561Skato v86.addr = 0x1b; 139143561Skato v86.eax = 0x8400 | od->od_unit; 139243561Skato v86int(); 139343561Skato 139443561Skato od->od_cyl = v86.ecx; 139543561Skato od->od_hds = (v86.edx >> 8) & 0xff; 139643561Skato od->od_sec = v86.edx & 0xff; 139751586Skato if (v86.efl & 0x1) 139851586Skato return(1); 139943561Skato } 140043561Skato#else 140143561Skato v86.ctl = V86_FLAGS; 140243561Skato v86.addr = 0x13; 140343561Skato v86.eax = 0x800; 140443561Skato v86.edx = od->od_unit; 140543561Skato v86int(); 140643561Skato 140743561Skato if ((v86.efl & 0x1) || /* carry set */ 140868358Snyan ((v86.edx & 0xff) <= (unsigned)(od->od_unit & 0x7f))) /* unit # bad */ 140943561Skato return(1); 141043561Skato 141143561Skato /* convert max cyl # -> # of cylinders */ 141243561Skato od->od_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 141343561Skato /* convert max head # -> # of heads */ 141443561Skato od->od_hds = ((v86.edx & 0xff00) >> 8) + 1; 141543561Skato od->od_sec = v86.ecx & 0x3f; 141643561Skato#endif 141743561Skato 141843561Skato DEBUG("unit 0x%x geometry %d/%d/%d", od->od_unit, od->od_cyl, od->od_hds, od->od_sec); 141943561Skato return(0); 142043561Skato} 142143561Skato 142243561Skato/* 142353207Snyan * Return the BIOS geometry of a given "fixed drive" in a format 142453207Snyan * suitable for the legacy bootinfo structure. Since the kernel is 142553207Snyan * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we 142653207Snyan * prefer to get the information directly, rather than rely on being 142753207Snyan * able to put it together from information already maintained for 142853207Snyan * different purposes and for a probably different number of drives. 142953207Snyan * 143053207Snyan * For valid drives, the geometry is expected in the format (31..0) 143153207Snyan * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are 143253207Snyan * indicated by returning the geometry of a "1.2M" PC-format floppy 143353207Snyan * disk. And, incidentally, what is returned is not the geometry as 143453207Snyan * such but the highest valid cylinder, head, and sector numbers. 143553207Snyan */ 143653207Snyanu_int32_t 143753207Snyanbd_getbigeom(int bunit) 143853207Snyan{ 143953207Snyan 144054819Snyan#ifdef PC98 144154819Snyan int hds = 0; 144255339Snyan int unit = 0x80; /* IDE HDD */ 144354819Snyan u_int addr = 0xA155d; 144455339Snyan 144554819Snyan while (unit < 0xa7) { 144655339Snyan if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) 144755339Snyan if (hds++ == bunit) 144854819Snyan break; 1449108791Snyan 1450108791Snyan if (unit >= 0xA0) { 1451108791Snyan int media = ((unsigned *)PTOV(0xA1460))[unit & 0x0F] & 0x1F; 1452108791Snyan 1453108791Snyan if (media == 7 && hds++ == bunit) /* SCSI MO */ 1454108791Snyan return(0xFFFE0820); /* C:65535 H:8 S:32 */ 1455108791Snyan } 145654819Snyan if (++unit == 0x84) { 1457108791Snyan unit = 0xA0; /* SCSI HDD */ 145854819Snyan addr = 0xA1482; 145954819Snyan } 146054819Snyan } 146154819Snyan if (unit == 0xa7) 1462108791Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 146353207Snyan v86.ctl = V86_FLAGS; 146454819Snyan v86.addr = 0x1b; 146554819Snyan v86.eax = 0x8400 | unit; 146654819Snyan v86int(); 146754819Snyan if (v86.efl & 0x1) 1468108791Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 146954819Snyan return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); 147054819Snyan#else 147154819Snyan v86.ctl = V86_FLAGS; 147253207Snyan v86.addr = 0x13; 147353207Snyan v86.eax = 0x800; 147453207Snyan v86.edx = 0x80 + bunit; 147553207Snyan v86int(); 147653207Snyan if (v86.efl & 0x1) 147753207Snyan return 0x4f010f; 147853207Snyan return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 147953207Snyan (v86.edx & 0xff00) | (v86.ecx & 0x3f); 148054819Snyan#endif 148153207Snyan} 148253207Snyan 148353207Snyan/* 1484130603Sphk * Return a suitable dev_t value for (dev). 148543561Skato * 148643561Skato * In the case where it looks like (dev) is a SCSI disk, we allow the number of 148743561Skato * IDE disks to be specified in $num_ide_disks. There should be a Better Way. 148843561Skato */ 148943561Skatoint 149043561Skatobd_getdev(struct i386_devdesc *dev) 149143561Skato{ 149243561Skato struct open_disk *od; 149343561Skato int biosdev; 149443561Skato int major; 149543561Skato int rootdev; 149643561Skato char *nip, *cp; 149743561Skato int unitofs = 0, i, unit; 149843561Skato 149943561Skato biosdev = bd_unit2bios(dev->d_kind.biosdisk.unit); 150043561Skato DEBUG("unit %d BIOS device %d", dev->d_kind.biosdisk.unit, biosdev); 150143561Skato if (biosdev == -1) /* not a BIOS device */ 150243561Skato return(-1); 150343561Skato if (bd_opendisk(&od, dev) != 0) /* oops, not a viable device */ 150443561Skato return(-1); 150543561Skato 150643561Skato#ifdef PC98 150743561Skato if ((biosdev & 0xf0) == 0x90 || (biosdev & 0xf0) == 0x30) { 150843561Skato#else 150943561Skato if (biosdev < 0x80) { 151043561Skato#endif 151143561Skato /* floppy (or emulated floppy) or ATAPI device */ 151243561Skato if (bdinfo[dev->d_kind.biosdisk.unit].bd_type == DT_ATAPI) { 151343561Skato /* is an ATAPI disk */ 151443561Skato major = WFDMAJOR; 151543561Skato } else { 151643561Skato /* is a floppy disk */ 151743561Skato major = FDMAJOR; 151843561Skato } 151943561Skato } else { 152043561Skato /* harddisk */ 152143561Skato if ((od->od_flags & BD_LABELOK) && (od->od_disklabel.d_type == DTYPE_SCSI)) { 152243561Skato /* label OK, disk labelled as SCSI */ 152343561Skato major = DAMAJOR; 152443561Skato /* check for unit number correction hint, now deprecated */ 152543561Skato if ((nip = getenv("num_ide_disks")) != NULL) { 152643561Skato i = strtol(nip, &cp, 0); 152743561Skato /* check for parse error */ 152843561Skato if ((cp != nip) && (*cp == 0)) 152943561Skato unitofs = i; 153043561Skato } 153143561Skato } else { 153243561Skato /* assume an IDE disk */ 153343561Skato major = WDMAJOR; 153443561Skato } 153543561Skato } 153668358Snyan /* default root disk unit number */ 153768358Snyan#ifdef PC98 153868358Snyan if ((biosdev & 0xf0) == 0xa0) 153968358Snyan unit = bdinfo[dev->d_kind.biosdisk.unit].bd_da_unit; 154068358Snyan else 154168358Snyan unit = biosdev & 0xf; 154268358Snyan#else 154368358Snyan unit = (biosdev & 0x7f) - unitofs; 154468358Snyan#endif 154568358Snyan 154643561Skato /* XXX a better kludge to set the root disk unit number */ 154743561Skato if ((nip = getenv("root_disk_unit")) != NULL) { 154843561Skato i = strtol(nip, &cp, 0); 154943561Skato /* check for parse error */ 155043561Skato if ((cp != nip) && (*cp == 0)) 155143561Skato unit = i; 155243561Skato } 155343561Skato 155443561Skato rootdev = MAKEBOOTDEV(major, 155543561Skato (dev->d_kind.biosdisk.slice + 1) >> 4, /* XXX slices may be wrong here */ 155643561Skato (dev->d_kind.biosdisk.slice + 1) & 0xf, 155743561Skato unit, 155843561Skato dev->d_kind.biosdisk.partition); 155943561Skato DEBUG("dev is 0x%x\n", rootdev); 156043561Skato return(rootdev); 156143561Skato} 1562