summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2017-06-11 11:20:55 +0300
committerRichard Lowe <richlowe@richlowe.net>2018-12-08 16:54:07 +0000
commit863275a46b877530dd1c728df0b4e9bddb5702e3 (patch)
tree10f6193f9a7c4fad534fa1f12a4d3d1982830b54
parent049ba636fa37a2892809192fc671bff9158a01cd (diff)
downloadillumos-gate-863275a46b877530dd1c728df0b4e9bddb5702e3.tar.gz
9956 loader: create separate lists for fd, cd and hd, merge bioscd with biosdisk
Reviewed by: Norm Jacobs <naj@snapcon.com> Approved by: Richard Lowe <richlowe@richlowe.net>
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c20
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/Makefile4
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/bioscd.c454
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/biosdisk.c666
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/bootinfo32.c7
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/libi386.h8
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/linux.c2
-rw-r--r--usr/src/boot/sys/boot/i386/loader/chain.c2
-rw-r--r--usr/src/boot/sys/boot/i386/loader/conf.c3
-rw-r--r--usr/src/boot/sys/boot/i386/loader/main.c18
11 files changed, 520 insertions, 666 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index 5774ebbc44..143e416056 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -33,4 +33,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2018.8.04.1
+BOOT_VERSION = $(LOADER_VERSION)-2018.11.05.1
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
index 94875500b4..4238afe3e8 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
+++ b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
@@ -115,7 +115,7 @@ struct arch_switch archsw; /* MI/MD interface boundary */
static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */
struct devsw *devsw[] = {
- &biosdisk,
+ &bioshd,
&zfs_dev,
NULL
};
@@ -429,7 +429,7 @@ mount_root(char *arg)
bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type],
bdev->d_kind.biosdisk.slice + 1,
bdev->dd.d_unit, part);
- bootinfo.bi_bios_dev = bd_unit2bios(bdev->dd.d_unit);
+ bootinfo.bi_bios_dev = bd_unit2bios(bdev);
}
setenv("currdev", root, 1);
free(root);
@@ -712,8 +712,10 @@ static void
i386_zfs_probe(void)
{
char devname[32];
- int boot_unit, unit;
+ int boot_unit;
+ struct i386_devdesc dev;
+ dev.dd.d_dev = &bioshd;
/* Translate bios dev to our unit number. */
boot_unit = bd_bios2unit(bootinfo.bi_bios_dev);
@@ -721,15 +723,11 @@ i386_zfs_probe(void)
* Open all the disks we can find and see if we can reconstruct
* ZFS pools from them.
*/
- for (unit = 0; unit < MAXBDDEV; unit++) {
- if (bd_unit2bios(unit) == -1)
- break;
- if (bd_unit2bios(unit) < 0x80)
- continue;
-
- sprintf(devname, "disk%d:", unit);
+ for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) {
+ snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name,
+ dev.dd.d_unit);
/* If this is not boot disk, use generic probe. */
- if (unit != boot_unit)
+ if (dev.dd.d_unit != boot_unit)
zfs_probe_dev(devname, NULL);
else
probe_disk(devname);
diff --git a/usr/src/boot/sys/boot/i386/libi386/Makefile b/usr/src/boot/sys/boot/i386/libi386/Makefile
index 797e3257d0..b2d8cca9ef 100644
--- a/usr/src/boot/sys/boot/i386/libi386/Makefile
+++ b/usr/src/boot/sys/boot/i386/libi386/Makefile
@@ -36,14 +36,14 @@ ASFLAGS=-m32
AS_CPPFLAGS=
COMPILE.s = $(AS) $(AS_FLAGS)
-SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \
+SRCS= biosacpi.c biosdisk.c biosmem.c biospnp.c \
biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \
comconsole.c cpuid.c devicename.c elf32_freebsd.c \
elf64_freebsd.c multiboot.c multiboot_tramp.S \
i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \
smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c linux.c \
relocater_tramp.S
-OBJS= biosacpi.o bioscd.o biosdisk.o biosmem.o biospnp.o \
+OBJS= biosacpi.o biosdisk.o biosmem.o biospnp.o \
biospci.o biossmap.o bootinfo.o bootinfo32.o bootinfo64.o \
comconsole.o cpuid.o devicename.o elf32_freebsd.o \
elf64_freebsd.o multiboot.o multiboot_tramp.o \
diff --git a/usr/src/boot/sys/boot/i386/libi386/bioscd.c b/usr/src/boot/sys/boot/i386/libi386/bioscd.c
deleted file mode 100644
index d4c10c361d..0000000000
--- a/usr/src/boot/sys/boot/i386/libi386/bioscd.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/*-
- * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
- * Copyright (c) 2001 John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-
-/*
- * BIOS CD device handling for CD's that have been booted off of via no
- * emulation booting as defined in the El Torito standard.
- *
- * Ideas and algorithms from:
- *
- * - FreeBSD libi386/biosdisk.c
- *
- */
-
-#include <stand.h>
-
-#include <sys/param.h>
-#include <machine/bootinfo.h>
-
-#include <stdarg.h>
-
-#include <bootstrap.h>
-#include <btxv86.h>
-#include <edd.h>
-#include "libi386.h"
-
-#define BIOSCD_SECSIZE 2048
-#define BUFSIZE (1 * BIOSCD_SECSIZE)
-#define MAXBCDEV 1
-
-/* Major numbers for devices we frontend for. */
-#define ACDMAJOR 117
-#define CDMAJOR 15
-
-#ifdef DISK_DEBUG
-# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
-#else
-# define DEBUG(fmt, args...)
-#endif
-
-struct specification_packet {
- u_char sp_size;
- u_char sp_bootmedia;
- u_char sp_drive;
- u_char sp_controller;
- u_int sp_lba;
- u_short sp_devicespec;
- u_short sp_buffersegment;
- u_short sp_loadsegment;
- u_short sp_sectorcount;
- u_short sp_cylsec;
- u_char sp_head;
-};
-
-/*
- * List of BIOS devices, translation from disk unit number to
- * BIOS unit number.
- */
-static struct bcinfo {
- int bc_unit; /* BIOS unit number */
- struct specification_packet bc_sp;
- int bc_open; /* reference counter */
- void *bc_bcache; /* buffer cache data */
-} bcinfo [MAXBCDEV];
-static int nbcinfo = 0;
-
-#define BC(dev) (bcinfo[(dev)->dd.d_unit])
-
-static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest);
-static int bc_init(void);
-static int bc_strategy(void *devdata, int flag, daddr_t dblk,
- size_t size, char *buf, size_t *rsize);
-static int bc_realstrategy(void *devdata, int flag, daddr_t dblk,
- size_t size, char *buf, size_t *rsize);
-static int bc_open(struct open_file *f, ...);
-static int bc_close(struct open_file *f);
-static int bc_print(int verbose);
-
-struct devsw bioscd = {
- "cd",
- DEVT_CD,
- bc_init,
- bc_strategy,
- bc_open,
- bc_close,
- noioctl,
- bc_print,
- NULL
-};
-
-/*
- * Translate between BIOS device numbers and our private unit numbers.
- */
-int
-bc_bios2unit(int biosdev)
-{
- int i;
-
- DEBUG("looking for bios device 0x%x", biosdev);
- for (i = 0; i < nbcinfo; i++) {
- DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit);
- if (bcinfo[i].bc_unit == biosdev)
- return(i);
- }
- return(-1);
-}
-
-int
-bc_unit2bios(int unit)
-{
- if ((unit >= 0) && (unit < nbcinfo))
- return(bcinfo[unit].bc_unit);
- return(-1);
-}
-
-/*
- * We can't quiz, we have to be told what device to use, so this functoin
- * doesn't do anything. Instead, the loader calls bc_add() with the BIOS
- * device number to add.
- */
-static int
-bc_init(void)
-{
-
- return (0);
-}
-
-int
-bc_add(int biosdev)
-{
-
- if (nbcinfo >= MAXBCDEV)
- return (-1);
- bcinfo[nbcinfo].bc_unit = biosdev;
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0x4b01;
- v86.edx = biosdev;
- v86.ds = VTOPSEG(&bcinfo[nbcinfo].bc_sp);
- v86.esi = VTOPOFF(&bcinfo[nbcinfo].bc_sp);
- v86int();
- if ((v86.eax & 0xff00) != 0)
- return (-1);
-
- printf("BIOS CD is cd%d\n", nbcinfo);
- nbcinfo++;
- bcache_add_dev(nbcinfo); /* register cd device in bcache */
- return(0);
-}
-
-/*
- * Print information about disks
- */
-static int
-bc_print(int verbose)
-{
- char line[80];
- int i, ret = 0;
-
- if (nbcinfo == 0)
- return (0);
-
- printf("%s devices:", bioscd.dv_name);
- if ((ret = pager_output("\n")) != 0)
- return (ret);
-
- for (i = 0; i < nbcinfo; i++) {
- sprintf(line, " cd%d: Device 0x%x\n", i,
- bcinfo[i].bc_sp.sp_devicespec);
- ret = pager_output(line);
- if (ret != 0)
- return (ret);
- }
- return (ret);
-}
-
-/*
- * Attempt to open the disk described by (dev) for use by (f).
- */
-static int
-bc_open(struct open_file *f, ...)
-{
- va_list ap;
- struct i386_devdesc *dev;
-
- va_start(ap, f);
- dev = va_arg(ap, struct i386_devdesc *);
- va_end(ap);
- if (dev->dd.d_unit >= nbcinfo) {
- DEBUG("attempt to open nonexistent disk");
- return(ENXIO);
- }
-
- BC(dev).bc_open++;
- if (BC(dev).bc_bcache == NULL)
- BC(dev).bc_bcache = bcache_allocate();
- return(0);
-}
-
-static int
-bc_close(struct open_file *f)
-{
- struct i386_devdesc *dev;
-
- dev = (struct i386_devdesc *)f->f_devdata;
- BC(dev).bc_open--;
- if (BC(dev).bc_open == 0) {
- bcache_free(BC(dev).bc_bcache);
- BC(dev).bc_bcache = NULL;
- }
- return(0);
-}
-
-static int
-bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
- char *buf, size_t *rsize)
-{
- struct bcache_devdata bcd;
- struct i386_devdesc *dev;
-
- dev = (struct i386_devdesc *)devdata;
- bcd.dv_strategy = bc_realstrategy;
- bcd.dv_devdata = devdata;
- bcd.dv_cache = BC(dev).bc_bcache;
-
- return (bcache_strategy(&bcd, rw, dblk, size, buf, rsize));
-}
-
-static int
-bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
- char *buf, size_t *rsize)
-{
- struct i386_devdesc *dev;
- int unit;
- int blks;
-#ifdef BD_SUPPORT_FRAGS
- char fragbuf[BIOSCD_SECSIZE];
- size_t fragsize;
-
- fragsize = size % BIOSCD_SECSIZE;
-#else
- if (size % BIOSCD_SECSIZE)
- return (EINVAL);
-#endif
-
- if ((rw & F_MASK) != F_READ)
- return(EROFS);
- dev = (struct i386_devdesc *)devdata;
- unit = dev->dd.d_unit;
- blks = size / BIOSCD_SECSIZE;
- if (dblk % (BIOSCD_SECSIZE / DEV_BSIZE) != 0)
- return (EINVAL);
- dblk /= (BIOSCD_SECSIZE / DEV_BSIZE);
- DEBUG("read %d from %lld to %p", blks, dblk, buf);
-
- if (rsize)
- *rsize = 0;
- if ((blks = bc_read(unit, dblk, blks, buf)) < 0) {
- DEBUG("read error");
- return (EIO);
- } else {
- if (size / BIOSCD_SECSIZE > blks) {
- if (rsize)
- *rsize = blks * BIOSCD_SECSIZE;
- return (0);
- }
- }
-#ifdef BD_SUPPORT_FRAGS
- DEBUG("frag read %d from %lld+%d to %p",
- fragsize, dblk, blks, buf + (blks * BIOSCD_SECSIZE));
- if (fragsize && bc_read(unit, dblk + blks, 1, fragbuf) != 1) {
- if (blks) {
- if (rsize)
- *rsize = blks * BIOSCD_SECSIZE;
- return (0);
- }
- DEBUG("frag read error");
- return(EIO);
- }
- bcopy(fragbuf, buf + (blks * BIOSCD_SECSIZE), fragsize);
-#endif
- if (rsize)
- *rsize = size;
- return (0);
-}
-
-/* return negative value for an error, otherwise blocks read */
-static int
-bc_read(int unit, daddr_t dblk, int blks, caddr_t dest)
-{
- u_int maxfer, resid, result, retry, x;
- caddr_t bbuf, p, xp;
- static struct edd_packet packet;
- int biosdev;
-#ifdef DISK_DEBUG
- int error;
-#endif
-
- /* Just in case some idiot actually tries to read -1 blocks... */
- if (blks < 0)
- return (-1);
-
- /* If nothing to do, just return succcess. */
- if (blks == 0)
- return (0);
-
- /* Decide whether we have to bounce */
- if (VTOP(dest) >> 20 != 0) {
- /*
- * The destination buffer is above first 1MB of
- * physical memory so we have to arrange a suitable
- * bounce buffer.
- */
- x = V86_IO_BUFFER_SIZE / BIOSCD_SECSIZE;
- if (x == 0)
- panic("BUG: Real mode buffer is too small\n");
- x = min(x, (unsigned)blks);
- bbuf = PTOV(V86_IO_BUFFER);
- maxfer = x;
- } else {
- bbuf = NULL;
- maxfer = 0;
- }
-
- biosdev = bc_unit2bios(unit);
- resid = blks;
- p = dest;
-
- while (resid > 0) {
- if (bbuf)
- xp = bbuf;
- else
- xp = p;
- x = resid;
- if (maxfer > 0)
- x = min(x, maxfer);
-
- /*
- * Loop retrying the operation a couple of times. The BIOS
- * may also retry.
- */
- for (retry = 0; retry < 3; retry++) {
- /* If retrying, reset the drive */
- if (retry > 0) {
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0;
- v86.edx = biosdev;
- v86int();
- }
-
- packet.len = sizeof(struct edd_packet);
- packet.count = x;
- packet.off = VTOPOFF(xp);
- packet.seg = VTOPSEG(xp);
- packet.lba = dblk;
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0x4200;
- v86.edx = biosdev;
- v86.ds = VTOPSEG(&packet);
- v86.esi = VTOPOFF(&packet);
- v86int();
- result = V86_CY(v86.efl);
- if (result == 0)
- break;
- /* fall back to 1 sector read */
- x = 1;
- }
-
-#ifdef DISK_DEBUG
- error = (v86.eax >> 8) & 0xff;
-#endif
- DEBUG("%d sectors from %lld to %p (0x%x) %s", x, dblk, p,
- VTOP(p), result ? "failed" : "ok");
- DEBUG("unit %d status 0x%x", unit, error);
-
- /* still an error? break off */
- if (result != 0)
- break;
-
- if (bbuf != NULL)
- bcopy(bbuf, p, x * BIOSCD_SECSIZE);
- p += (x * BIOSCD_SECSIZE);
- dblk += x;
- resid -= x;
- }
-
-/* hexdump(dest, (blks * BIOSCD_SECSIZE)); */
-
- if (blks - resid == 0)
- return (-1); /* read failed */
-
- return (blks - resid);
-}
-
-/*
- * Return a suitable dev_t value for (dev).
- */
-int
-bc_getdev(struct i386_devdesc *dev)
-{
- int biosdev, unit;
- int major;
- int rootdev;
-
- unit = dev->dd.d_unit;
- biosdev = bc_unit2bios(unit);
- DEBUG("unit %d BIOS device %d", unit, biosdev);
- if (biosdev == -1) /* not a BIOS device */
- return(-1);
-
- /*
- * XXX: Need to examine device spec here to figure out if SCSI or
- * ATAPI. No idea on how to figure out device number. All we can
- * really pass to the kernel is what bus and device on which bus we
- * were booted from, which dev_t isn't well suited to since those
- * number don't match to unit numbers very well. We may just need
- * to engage in a hack where we pass -C to the boot args if we are
- * the boot device.
- */
- major = ACDMAJOR;
- unit = 0; /* XXX */
-
- /* XXX: Assume partition 'a'. */
- rootdev = MAKEBOOTDEV(major, 0, unit, 0);
- DEBUG("dev is 0x%x\n", rootdev);
- return(rootdev);
-}
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
index 30af54ea53..68378ef2b2 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
+++ b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
@@ -39,9 +39,11 @@
#include <sys/disk.h>
#include <sys/limits.h>
+#include <sys/queue.h>
#include <stand.h>
#include <machine/bootinfo.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <bootstrap.h>
#include <btxv86.h>
@@ -58,6 +60,8 @@
#define WFDMAJOR 1
#define FDMAJOR 2
#define DAMAJOR 4
+#define ACDMAJOR 117
+#define CDMAJOR 15
#ifdef DISK_DEBUG
#define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args)
@@ -65,12 +69,27 @@
#define DEBUG(fmt, args...)
#endif
+struct specification_packet {
+ uint8_t sp_size;
+ uint8_t sp_bootmedia;
+ uint8_t sp_drive;
+ uint8_t sp_controller;
+ uint32_t sp_lba;
+ uint16_t sp_devicespec;
+ uint16_t sp_buffersegment;
+ uint16_t sp_loadsegment;
+ uint16_t sp_sectorcount;
+ uint16_t sp_cylsec;
+ uint8_t sp_head;
+};
+
/*
* List of BIOS devices, translation from disk unit number to
* BIOS unit number.
*/
-static struct bdinfo
+typedef struct bdinfo
{
+ STAILQ_ENTRY(bdinfo) bd_link; /* link in device list */
int bd_unit; /* BIOS unit number */
int bd_cyl; /* BIOS geometry */
int bd_hds;
@@ -82,25 +101,30 @@ static struct bdinfo
#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3)
#define BD_MODEMASK 0x0003
#define BD_FLOPPY 0x0004
-#define BD_NO_MEDIA 0x0008
+#define BD_CDROM 0x0008
+#define BD_NO_MEDIA 0x0010
int bd_type; /* BIOS 'drive type' (floppy only) */
uint16_t bd_sectorsize; /* Sector size */
uint64_t bd_sectors; /* Disk size */
int bd_open; /* reference counter */
void *bd_bcache; /* buffer cache data */
-} bdinfo [MAXBDDEV];
-static int nbdinfo = 0;
+} bdinfo_t;
-#define BD(dev) (bdinfo[(dev)->dd.d_unit])
#define BD_RD 0
#define BD_WR 1
-static void bd_io_workaround(struct disk_devdesc *dev);
+typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t;
+static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
+static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
+static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
-static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int);
-static int bd_int13probe(struct bdinfo *bd);
+static void bd_io_workaround(bdinfo_t *);
+static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int);
+static bool bd_int13probe(bdinfo_t *);
static int bd_init(void);
+static int cd_init(void);
+static int fd_init(void);
static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
char *buf, size_t *rsize);
static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
@@ -109,42 +133,120 @@ static int bd_open(struct open_file *f, ...);
static int bd_close(struct open_file *f);
static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
static int bd_print(int verbose);
+static int cd_print(int verbose);
+static int fd_print(int verbose);
+
+struct devsw biosfd = {
+ .dv_name = "fd",
+ .dv_type = DEVT_FD,
+ .dv_init = fd_init,
+ .dv_strategy = bd_strategy,
+ .dv_open = bd_open,
+ .dv_close = bd_close,
+ .dv_ioctl = bd_ioctl,
+ .dv_print = fd_print,
+ .dv_cleanup = NULL
+};
+
+struct devsw bioscd = {
+ .dv_name = "cd",
+ .dv_type = DEVT_CD,
+ .dv_init = cd_init,
+ .dv_strategy = bd_strategy,
+ .dv_open = bd_open,
+ .dv_close = bd_close,
+ .dv_ioctl = bd_ioctl,
+ .dv_print = cd_print,
+ .dv_cleanup = NULL
+};
-struct devsw biosdisk = {
- "disk",
- DEVT_DISK,
- bd_init,
- bd_strategy,
- bd_open,
- bd_close,
- bd_ioctl,
- bd_print,
- NULL
+struct devsw bioshd = {
+ .dv_name = "disk",
+ .dv_type = DEVT_DISK,
+ .dv_init = bd_init,
+ .dv_strategy = bd_strategy,
+ .dv_open = bd_open,
+ .dv_close = bd_close,
+ .dv_ioctl = bd_ioctl,
+ .dv_print = bd_print,
+ .dv_cleanup = NULL
};
+static bdinfo_list_t *
+bd_get_bdinfo_list(struct devsw *dev)
+{
+ if (dev->dv_type == DEVT_DISK)
+ return (&hdinfo);
+ if (dev->dv_type == DEVT_CD)
+ return (&cdinfo);
+ if (dev->dv_type == DEVT_FD)
+ return (&fdinfo);
+ return (NULL);
+}
+
+/* XXX this gets called way way too often, investigate */
+static bdinfo_t *
+bd_get_bdinfo(struct devdesc *dev)
+{
+ bdinfo_list_t *bdi;
+ bdinfo_t *bd = NULL;
+ int unit;
+
+ bdi = bd_get_bdinfo_list(dev->d_dev);
+ if (bdi == NULL)
+ return (bd);
+
+ unit = 0;
+ STAILQ_FOREACH(bd, bdi, bd_link) {
+ if (unit == dev->d_unit)
+ return (bd);
+ unit++;
+ }
+ return (bd);
+}
+
/*
* Translate between BIOS device numbers and our private unit numbers.
*/
int
bd_bios2unit(int biosdev)
{
- int i;
+ bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL };
+ bdinfo_t *bd;
+ int i, unit;
DEBUG("looking for bios device 0x%x", biosdev);
- for (i = 0; i < nbdinfo; i++) {
- DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
- if (bdinfo[i].bd_unit == biosdev)
- return (i);
+ for (i = 0; bdi[i] != NULL; i++) {
+ unit = 0;
+ STAILQ_FOREACH(bd, bdi[i], bd_link) {
+ if (bd->bd_unit == biosdev) {
+ DEBUG("bd unit %d is BIOS device 0x%x", unit,
+ bd->bd_unit);
+ return (unit);
+ }
+ unit++;
+ }
}
return (-1);
}
int
-bd_unit2bios(int unit)
+bd_unit2bios(struct i386_devdesc *dev)
{
+ bdinfo_list_t *bdi;
+ bdinfo_t *bd;
+ int unit;
+
+ bdi = bd_get_bdinfo_list(dev->dd.d_dev);
+ if (bdi == NULL)
+ return (-1);
- if ((unit >= 0) && (unit < nbdinfo))
- return (bdinfo[unit].bd_unit);
+ unit = 0;
+ STAILQ_FOREACH(bd, bdi, bd_link) {
+ if (unit == dev->dd.d_unit)
+ return (bd->bd_unit);
+ unit++;
+ }
return (-1);
}
@@ -152,44 +254,128 @@ bd_unit2bios(int unit)
* Quiz the BIOS for disk devices, save a little info about them.
*/
static int
-bd_init(void)
+fd_init(void)
{
- int base, unit, nfd = 0;
+ int unit;
+ bdinfo_t *bd;
- /* sequence 0, 0x80 */
- for (base = 0; base <= 0x80; base += 0x80) {
- for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
-#ifndef VIRTUALBOX
- /*
- * Check the BIOS equipment list for number
- * of fixed disks.
- */
- if (base == 0x80 &&
- (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES)))
- break;
+ for (unit = 0; unit < MAXBDDEV; unit++) {
+ if ((bd = calloc(1, sizeof (*bd))) == NULL)
+ break;
+ bd->bd_flags = BD_FLOPPY;
+ bd->bd_unit = unit;
+ if (!bd_int13probe(bd)) {
+ free(bd);
+ break;
+ }
+ if (bd->bd_sectors == 0)
+ bd->bd_flags |= BD_NO_MEDIA;
+#ifndef BOOT2
+ printf("BIOS drive %c: is %s%d\n", ('A' + unit),
+ biosfd.dv_name, unit);
#endif
- bdinfo[nbdinfo].bd_open = 0;
- bdinfo[nbdinfo].bd_bcache = NULL;
- bdinfo[nbdinfo].bd_unit = unit;
- bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
- if (!bd_int13probe(&bdinfo[nbdinfo]))
- break;
+ STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link);
+ }
+
+ bcache_add_dev(unit);
+ return (0);
+}
+static int
+bd_init(void)
+{
+ int base, unit;
+ bdinfo_t *bd;
+
+ base = 0x80;
+ for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) {
+ /*
+ * Check the BIOS equipment list for number of fixed disks.
+ */
+ if ((bd = calloc(1, sizeof (*bd))) == NULL)
+ break;
+ bd->bd_unit = base + unit;
+ if (!bd_int13probe(bd)) {
+ free(bd);
+ break;
+ }
#ifndef BOOT2
- /* XXX we need "disk aliases" to make this simpler */
- printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ?
- ('A' + unit): ('C' + unit - 0x80), nbdinfo);
+ printf("BIOS drive %c: is %s%d\n", ('C' + unit),
+ bioshd.dv_name, unit);
#endif
- nbdinfo++;
- if (base == 0x80)
- nfd++;
- }
+ STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link);
}
- bcache_add_dev(nbdinfo);
+ bcache_add_dev(unit);
return (0);
}
/*
+ * We can't quiz, we have to be told what device to use, so this function
+ * doesn't do anything. Instead, the loader calls bc_add() with the BIOS
+ * device number to add.
+ */
+static int
+cd_init(void)
+{
+
+ return (0);
+}
+
+int
+bc_add(int biosdev)
+{
+ bdinfo_t *bd;
+ struct specification_packet bc_sp;
+ int nbcinfo = 0;
+
+ if (!STAILQ_EMPTY(&cdinfo))
+ return (-1);
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4b01;
+ v86.edx = biosdev;
+ v86.ds = VTOPSEG(&bc_sp);
+ v86.esi = VTOPOFF(&bc_sp);
+ v86int();
+ if ((v86.eax & 0xff00) != 0)
+ return (-1);
+
+ if ((bd = calloc(1, sizeof (*bd))) == NULL)
+ return (-1);
+
+ bd->bd_flags = BD_CDROM;
+ bd->bd_unit = biosdev;
+
+ /*
+ * Ignore result from bd_int13probe(), we will use local
+ * workaround below.
+ */
+ (void)bd_int13probe(bd);
+
+ if (bd->bd_cyl == 0) {
+ bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
+ ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1;
+ }
+ if (bd->bd_hds == 0)
+ bd->bd_hds = bc_sp.sp_head + 1;
+ if (bd->bd_sec == 0)
+ bd->bd_sec = bc_sp.sp_cylsec & 0x3f;
+ if (bd->bd_sectors == 0)
+ bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
+
+ /* Still no size? use 7.961GB */
+ if (bd->bd_sectors == 0)
+ bd->bd_sectors = 4173824;
+
+ STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
+ printf("BIOS CD is cd%d\n", nbcinfo);
+ nbcinfo++;
+ bcache_add_dev(nbcinfo); /* register cd device in bcache */
+ return(0);
+}
+
+/*
* Return EDD version or 0 if EDD is not supported on this drive.
*/
static int
@@ -307,11 +493,10 @@ bd_get_diskinfo_ext(struct bdinfo *bd)
/*
* Try to detect a device supported by the legacy int13 BIOS
*/
-static int
-bd_int13probe(struct bdinfo *bd)
+static bool
+bd_int13probe(bdinfo_t *bd)
{
- int edd;
- int ret;
+ int edd, ret;
bd->bd_flags &= ~BD_NO_MEDIA;
@@ -341,7 +526,7 @@ bd_int13probe(struct bdinfo *bd)
v86.edx = bd->bd_unit;
v86int();
if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0)
- return (0);
+ return (false);
}
ret = 1;
@@ -355,7 +540,6 @@ bd_int13probe(struct bdinfo *bd)
bd->bd_cyl = 80;
bd->bd_hds = 2;
bd->bd_sec = 18;
- bd->bd_type = 4;
bd->bd_sectors = 2880;
/* Since we are there, there most likely is no media */
bd->bd_flags |= BD_NO_MEDIA;
@@ -363,6 +547,10 @@ bd_int13probe(struct bdinfo *bd)
}
if (ret != 0) {
+ /* CD is special case, bc_add() has its own fallback. */
+ if ((bd->bd_flags & BD_CDROM) != 0)
+ return (true);
+
if (bd->bd_sectors != 0 && edd != 0) {
bd->bd_sec = 63;
bd->bd_hds = 255;
@@ -370,9 +558,18 @@ bd_int13probe(struct bdinfo *bd)
(bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) /
bd->bd_sec * bd->bd_hds;
} else {
+ const char *dv_name;
+
+ if ((bd->bd_flags & BD_FLOPPY) != 0)
+ dv_name = biosfd.dv_name;
+ else if ((bd->bd_flags & BD_CDROM) != 0)
+ dv_name = bioscd.dv_name;
+ else
+ dv_name = bioshd.dv_name;
+
printf("Can not get information about %s unit %#x\n",
- biosdisk.dv_name, bd->bd_unit);
- return (0);
+ dv_name, bd->bd_unit);
+ return (false);
}
}
@@ -384,54 +581,86 @@ bd_int13probe(struct bdinfo *bd)
if (bd->bd_sectors == 0)
bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
- DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
+ DEBUG("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl,
bd->bd_hds, bd->bd_sec);
- return (1);
+ return (true);
+}
+
+static int
+bd_count(bdinfo_list_t *bdi)
+{
+ bdinfo_t *bd;
+ int i;
+
+ i = 0;
+ STAILQ_FOREACH(bd, bdi, bd_link)
+ i++;
+ return (i);
}
/*
* Print information about disks
*/
static int
-bd_print(int verbose)
+bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose)
{
- static char line[80];
- struct disk_devdesc dev;
+ char line[80];
+ struct disk_devdesc devd;
+ bdinfo_t *bd;
int i, ret = 0;
+ char drive;
- if (nbdinfo == 0)
+ if (STAILQ_EMPTY(bdi))
return (0);
- printf("%s devices:", biosdisk.dv_name);
+ printf("%s devices:", dev->dv_name);
if ((ret = pager_output("\n")) != 0)
return (ret);
- for (i = 0; i < nbdinfo; i++) {
+ i = -1;
+ STAILQ_FOREACH(bd, bdi, bd_link) {
+ i++;
+
+ switch (dev->dv_type) {
+ case DEVT_FD:
+ drive = 'A';
+ break;
+ case DEVT_CD:
+ drive = 'C' + bd_count(&hdinfo);
+ break;
+ default:
+ drive = 'C';
+ break;
+ }
+
snprintf(line, sizeof (line),
- " disk%d: BIOS drive %c (%s%ju X %u):\n", i,
- (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
- ('C' + bdinfo[i].bd_unit - 0x80),
- (bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
+ " %s%d: BIOS drive %c (%s%ju X %u):\n",
+ dev->dv_name, i, drive + i,
+ (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
"no media, " : "",
- (uintmax_t)bdinfo[i].bd_sectors,
- bdinfo[i].bd_sectorsize);
+ (uintmax_t)bd->bd_sectors,
+ bd->bd_sectorsize);
if ((ret = pager_output(line)) != 0)
break;
- if ((bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
+ if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
continue;
- dev.dd.d_dev = &biosdisk;
- dev.dd.d_unit = i;
- dev.d_slice = -1;
- dev.d_partition = -1;
- if (disk_open(&dev,
- bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
- bdinfo[i].bd_sectorsize) == 0) {
- snprintf(line, sizeof (line), " disk%d", i);
- ret = disk_print(&dev, line, verbose);
- disk_close(&dev);
+ if (dev->dv_type != DEVT_DISK)
+ continue;
+
+ devd.dd.d_dev = dev;
+ devd.dd.d_unit = i;
+ devd.d_slice = -1;
+ devd.d_partition = -1;
+ if (disk_open(&devd,
+ bd->bd_sectorsize * bd->bd_sectors,
+ bd->bd_sectorsize) == 0) {
+ snprintf(line, sizeof (line), " %s%d",
+ dev->dv_name, i);
+ ret = disk_print(&devd, line, verbose);
+ disk_close(&devd);
if (ret != 0)
break;
}
@@ -439,6 +668,24 @@ bd_print(int verbose)
return (ret);
}
+static int
+fd_print(int verbose)
+{
+ return (bd_print_common(&biosfd, &fdinfo, verbose));
+}
+
+static int
+bd_print(int verbose)
+{
+ return (bd_print_common(&bioshd, &hdinfo, verbose));
+}
+
+static int
+cd_print(int verbose)
+{
+ return (bd_print_common(&bioscd, &cdinfo, verbose));
+}
+
/*
* Read disk size from partition.
* This is needed to work around buggy BIOS systems returning
@@ -449,21 +696,26 @@ bd_print(int verbose)
static uint64_t
bd_disk_get_sectors(struct disk_devdesc *dev)
{
+ bdinfo_t *bd;
struct disk_devdesc disk;
uint64_t size;
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
+ return (0);
+
disk.dd.d_dev = dev->dd.d_dev;
disk.dd.d_unit = dev->dd.d_unit;
disk.d_slice = -1;
disk.d_partition = -1;
disk.d_offset = 0;
- size = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
- if (disk_open(&disk, size, BD(dev).bd_sectorsize) == 0) {
+ size = bd->bd_sectors * bd->bd_sectorsize;
+ if (disk_open(&disk, size, bd->bd_sectorsize) == 0) {
(void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size);
disk_close(&disk);
}
- return (size / BD(dev).bd_sectorsize);
+ return (size / bd->bd_sectorsize);
}
/*
@@ -479,6 +731,7 @@ bd_disk_get_sectors(struct disk_devdesc *dev)
static int
bd_open(struct open_file *f, ...)
{
+ bdinfo_t *bd;
struct disk_devdesc *dev;
va_list ap;
int rc;
@@ -487,29 +740,33 @@ bd_open(struct open_file *f, ...)
dev = va_arg(ap, struct disk_devdesc *);
va_end(ap);
- if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo)
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
return (EIO);
- if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
- if (!bd_int13probe(&BD(dev)))
+ if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
+ if (!bd_int13probe(bd))
return (EIO);
- if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
+ if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
return (EIO);
}
- if (BD(dev).bd_bcache == NULL)
- BD(dev).bd_bcache = bcache_allocate();
-
- if (BD(dev).bd_open == 0)
- BD(dev).bd_sectors = bd_disk_get_sectors(dev);
- BD(dev).bd_open++;
-
- rc = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
- BD(dev).bd_sectorsize);
- if (rc != 0) {
- BD(dev).bd_open--;
- if (BD(dev).bd_open == 0) {
- bcache_free(BD(dev).bd_bcache);
- BD(dev).bd_bcache = NULL;
+ if (bd->bd_bcache == NULL)
+ bd->bd_bcache = bcache_allocate();
+
+ if (bd->bd_open == 0)
+ bd->bd_sectors = bd_disk_get_sectors(dev);
+ bd->bd_open++;
+
+ rc = 0;
+ if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+ rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
+ bd->bd_sectorsize);
+ if (rc != 0) {
+ bd->bd_open--;
+ if (bd->bd_open == 0) {
+ bcache_free(bd->bd_bcache);
+ bd->bd_bcache = NULL;
+ }
}
}
return (rc);
@@ -519,34 +776,48 @@ static int
bd_close(struct open_file *f)
{
struct disk_devdesc *dev;
+ bdinfo_t *bd;
+ int rc = 0;
dev = (struct disk_devdesc *)f->f_devdata;
- BD(dev).bd_open--;
- if (BD(dev).bd_open == 0) {
- bcache_free(BD(dev).bd_bcache);
- BD(dev).bd_bcache = NULL;
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
+ return (EIO);
+
+ bd->bd_open--;
+ if (bd->bd_open == 0) {
+ bcache_free(bd->bd_bcache);
+ bd->bd_bcache = NULL;
}
- return (disk_close(dev));
+ if (dev->dd.d_dev->dv_type == DEVT_DISK)
+ rc = disk_close(dev);
+ return (rc);
}
static int
bd_ioctl(struct open_file *f, u_long cmd, void *data)
{
+ bdinfo_t *bd;
struct disk_devdesc *dev;
int rc;
dev = (struct disk_devdesc *)f->f_devdata;
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
+ return (EIO);
- rc = disk_ioctl(dev, cmd, data);
- if (rc != ENOTTY)
- return (rc);
+ if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+ rc = disk_ioctl(dev, cmd, data);
+ if (rc != ENOTTY)
+ return (rc);
+ }
switch (cmd) {
case DIOCGSECTORSIZE:
- *(uint32_t *)data = BD(dev).bd_sectorsize;
+ *(uint32_t *)data = bd->bd_sectorsize;
break;
case DIOCGMEDIASIZE:
- *(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
+ *(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize;
break;
default:
return (ENOTTY);
@@ -558,14 +829,27 @@ static int
bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
char *buf, size_t *rsize)
{
+ bdinfo_t *bd;
struct bcache_devdata bcd;
struct disk_devdesc *dev;
+ daddr_t offset;
dev = (struct disk_devdesc *)devdata;
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
+ return (EINVAL);
+
bcd.dv_strategy = bd_realstrategy;
bcd.dv_devdata = devdata;
- bcd.dv_cache = BD(dev).bd_bcache;
- return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, size,
+ bcd.dv_cache = bd->bd_bcache;
+
+ offset = 0;
+ if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+
+ offset = dev->d_offset * bd->bd_sectorsize;
+ offset /= BIOSDISK_SECSIZE;
+ }
+ return (bcache_strategy(&bcd, rw, dblk + offset, size,
buf, rsize));
}
@@ -574,12 +858,14 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
char *buf, size_t *rsize)
{
struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
- uint64_t disk_blocks, offset;
+ bdinfo_t *bd;
+ uint64_t disk_blocks, offset, d_offset;
size_t blks, blkoff, bsize, rest;
caddr_t bbuf;
int rc;
- if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA)
return (EIO);
/*
@@ -597,8 +883,8 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
DEBUG("open_disk %p", dev);
offset = dblk * BIOSDISK_SECSIZE;
- dblk = offset / BD(dev).bd_sectorsize;
- blkoff = offset % BD(dev).bd_sectorsize;
+ dblk = offset / bd->bd_sectorsize;
+ blkoff = offset % bd->bd_sectorsize;
/*
* Check the value of the size argument. We do have quite small
@@ -611,8 +897,8 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
return (EIO);
}
- blks = size / BD(dev).bd_sectorsize;
- if (blks == 0 || (size % BD(dev).bd_sectorsize) != 0)
+ blks = size / bd->bd_sectorsize;
+ if (blks == 0 || (size % bd->bd_sectorsize) != 0)
blks++;
if (dblk > dblk + blks)
@@ -625,44 +911,48 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
* Get disk blocks, this value is either for whole disk or for
* partition.
*/
- if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
- /* DIOCGMEDIASIZE does return bytes. */
- disk_blocks /= BD(dev).bd_sectorsize;
- } else {
- /* We should not get here. Just try to survive. */
- disk_blocks = BD(dev).bd_sectors - dev->d_offset;
+ d_offset = 0;
+ disk_blocks = 0;
+ if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+ if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
+ /* DIOCGMEDIASIZE does return bytes. */
+ disk_blocks /= bd->bd_sectorsize;
+ }
+ d_offset = dev->d_offset;
}
+ if (disk_blocks == 0)
+ disk_blocks = bd->bd_sectors - d_offset;
/* Validate source block address. */
- if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks)
+ if (dblk < d_offset || dblk >= d_offset + disk_blocks)
return (EIO);
/*
* Truncate if we are crossing disk or partition end.
*/
- if (dblk + blks >= dev->d_offset + disk_blocks) {
- blks = dev->d_offset + disk_blocks - dblk;
- size = blks * BD(dev).bd_sectorsize;
+ if (dblk + blks >= d_offset + disk_blocks) {
+ blks = d_offset + disk_blocks - dblk;
+ size = blks * bd->bd_sectorsize;
DEBUG("short I/O %d", blks);
}
- if (V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize == 0)
+ if (V86_IO_BUFFER_SIZE / bd->bd_sectorsize == 0)
panic("BUG: Real mode buffer is too small\n");
bbuf = PTOV(V86_IO_BUFFER);
rest = size;
while (blks > 0) {
- int x = min(blks, V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize);
+ int x = min(blks, V86_IO_BUFFER_SIZE / bd->bd_sectorsize);
switch (rw & F_MASK) {
case F_READ:
DEBUG("read %d from %lld to %p", x, dblk, buf);
- bsize = BD(dev).bd_sectorsize * x - blkoff;
+ bsize = bd->bd_sectorsize * x - blkoff;
if (rest < bsize)
bsize = rest;
- if ((rc = bd_io(dev, dblk, x, bbuf, BD_RD)) != 0)
+ if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0)
return (EIO);
bcopy(bbuf + blkoff, buf, bsize);
@@ -675,27 +965,27 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
* bbuf.
*/
x = 1;
- bsize = BD(dev).bd_sectorsize - blkoff;
+ bsize = bd->bd_sectorsize - blkoff;
bsize = min(bsize, rest);
- rc = bd_io(dev, dblk, x, bbuf, BD_RD);
- } else if (rest < BD(dev).bd_sectorsize) {
+ rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
+ } else if (rest < bd->bd_sectorsize) {
/*
* The remaining block is not full
* sector. Read 1 sector to bbuf.
*/
x = 1;
bsize = rest;
- rc = bd_io(dev, dblk, x, bbuf, BD_RD);
+ rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD);
} else {
/* We can write full sector(s). */
- bsize = BD(dev).bd_sectorsize * x;
+ bsize = bd->bd_sectorsize * x;
}
/*
* Put your Data In, Put your Data out,
* Put your Data In, and shake it all about
*/
bcopy(buf, bbuf + blkoff, bsize);
- if ((rc = bd_io(dev, dblk, x, bbuf, BD_WR)) != 0)
+ if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0)
return (EIO);
break;
@@ -717,7 +1007,7 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
}
static int
-bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
+bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
int dowrite)
{
static struct edd_packet packet;
@@ -734,7 +1024,7 @@ bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
v86.eax = 0x4300;
else
v86.eax = 0x4200;
- v86.edx = BD(dev).bd_unit;
+ v86.edx = bd->bd_unit;
v86.ds = VTOPSEG(&packet);
v86.esi = VTOPOFF(&packet);
v86int();
@@ -744,17 +1034,17 @@ bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
}
static int
-bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
+bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest,
int dowrite)
{
uint32_t x, bpc, cyl, hd, sec;
- bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */
+ bpc = bd->bd_sec * bd->bd_hds; /* blocks per cylinder */
x = dblk;
cyl = x / bpc; /* block # / blocks per cylinder */
x %= bpc; /* block offset into cylinder */
- hd = x / BD(dev).bd_sec; /* offset / blocks per track */
- sec = x % BD(dev).bd_sec; /* offset into track */
+ hd = x / bd->bd_sec; /* offset / blocks per track */
+ sec = x % bd->bd_sec; /* offset into track */
/* correct sector number for 1-based BIOS numbering */
sec++;
@@ -771,7 +1061,7 @@ bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
else
v86.eax = 0x200 | blks;
v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
- v86.edx = (hd << 8) | BD(dev).bd_unit;
+ v86.edx = (hd << 8) | bd->bd_unit;
v86.es = VTOPSEG(dest);
v86.ebx = VTOPOFF(dest);
v86int();
@@ -781,16 +1071,16 @@ bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
}
static void
-bd_io_workaround(struct disk_devdesc *dev)
+bd_io_workaround(bdinfo_t *bd)
{
uint8_t buf[8 * 1024];
- bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD);
+ bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD);
}
static int
-bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
- int dowrite)
+bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks,
+ caddr_t dest, int dowrite)
{
int result, retry;
@@ -810,20 +1100,20 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
* may also retry.
*/
if (dowrite == BD_RD && dblk >= 0x100000000)
- bd_io_workaround(dev);
+ bd_io_workaround(bd);
for (retry = 0; retry < 3; retry++) {
- if (BD(dev).bd_flags & BD_MODEEDD)
- result = bd_edd_io(dev, dblk, blks, dest, dowrite);
+ if (bd->bd_flags & BD_MODEEDD)
+ result = bd_edd_io(bd, dblk, blks, dest, dowrite);
else
- result = bd_chs_io(dev, dblk, blks, dest, dowrite);
+ result = bd_chs_io(bd, dblk, blks, dest, dowrite);
if (result == 0) {
- if (BD(dev).bd_flags & BD_NO_MEDIA)
- BD(dev).bd_flags &= ~BD_NO_MEDIA;
+ if (bd->bd_flags & BD_NO_MEDIA)
+ bd->bd_flags &= ~BD_NO_MEDIA;
break;
}
- bd_reset_disk(BD(dev).bd_unit);
+ bd_reset_disk(bd->bd_unit);
/*
* Error codes:
@@ -833,12 +1123,12 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
* There is no reason to repeat the IO with errors above.
*/
if (result == 0x20 || result == 0x31 || result == 0x80) {
- BD(dev).bd_flags |= BD_NO_MEDIA;
+ bd->bd_flags |= BD_NO_MEDIA;
break;
}
}
- if (result != 0 && (BD(dev).bd_flags & BD_NO_MEDIA) == 0) {
+ if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) {
if (dowrite == BD_WR) {
printf("%s%d: Write %d sector(s) from %p (0x%x) "
"to %lld: 0x%x\n", dev->dd.d_dev->dv_name,
@@ -894,26 +1184,40 @@ int
bd_getdev(struct i386_devdesc *d)
{
struct disk_devdesc *dev;
+ bdinfo_t *bd;
int biosdev;
int major;
int rootdev;
char *nip, *cp;
- int i, unit;
+ int i, unit, slice, partition;
+
+ /* XXX: Assume partition 'a'. */
+ slice = 0;
+ partition = 0;
dev = (struct disk_devdesc *)d;
- biosdev = bd_unit2bios(dev->dd.d_unit);
+ bd = bd_get_bdinfo(&dev->dd);
+ if (bd == NULL)
+ return (-1);
+
+ biosdev = bd_unit2bios(d);
DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev);
if (biosdev == -1) /* not a BIOS device */
return (-1);
- if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
- BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */
- return (-1);
- else
- disk_close(dev);
+
+ if (dev->dd.d_dev->dv_type == DEVT_DISK) {
+ if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize,
+ bd->bd_sectorsize) != 0) /* oops, not a viable device */
+ return (-1);
+ else
+ disk_close(dev);
+ slice = dev->d_slice + 1;
+ partition = dev->d_partition;
+ }
if (biosdev < 0x80) {
/* floppy (or emulated floppy) or ATAPI device */
- if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) {
+ if (bd->bd_type == DT_ATAPI) {
/* is an ATAPI disk */
major = WFDMAJOR;
} else {
@@ -927,6 +1231,20 @@ bd_getdev(struct i386_devdesc *d)
/* default root disk unit number */
unit = biosdev & 0x7f;
+ if (dev->dd.d_dev->dv_type == DEVT_CD) {
+ /*
+ * XXX: Need to examine device spec here to figure out if
+ * SCSI or ATAPI. No idea on how to figure out device number.
+ * All we can really pass to the kernel is what bus and device
+ * on which bus we were booted from, which dev_t isn't well
+ * suited to since those number don't match to unit numbers
+ * very well. We may just need to engage in a hack where
+ * we pass -C to the boot args if we are the boot device.
+ */
+ major = ACDMAJOR;
+ unit = 0; /* XXX */
+ }
+
/* XXX a better kludge to set the root disk unit number */
if ((nip = getenv("root_disk_unit")) != NULL) {
i = strtol(nip, &cp, 0);
@@ -935,7 +1253,7 @@ bd_getdev(struct i386_devdesc *d)
unit = i;
}
- rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition);
+ rootdev = MAKEBOOTDEV(major, slice, unit, partition);
DEBUG("dev is 0x%x\n", rootdev);
return (rootdev);
}
diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c b/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c
index fd54ac4be5..adf5d514a5 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c
+++ b/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c
@@ -170,14 +170,9 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
switch(rootdev->dd.d_dev->dv_type) {
case DEVT_CD:
- /* Pass in BIOS device number. */
- bi.bi_bios_dev = bc_unit2bios(rootdev->dd.d_unit);
- bootdevnr = bc_getdev(rootdev);
- break;
-
case DEVT_DISK:
/* pass in the BIOS device number of the current disk */
- bi.bi_bios_dev = bd_unit2bios(rootdev->dd.d_unit);
+ bi.bi_bios_dev = bd_unit2bios(rootdev);
bootdevnr = bd_getdev(rootdev);
break;
diff --git a/usr/src/boot/sys/boot/i386/libi386/libi386.h b/usr/src/boot/sys/boot/i386/libi386/libi386.h
index 190ae27d40..9b4defb084 100644
--- a/usr/src/boot/sys/boot/i386/libi386/libi386.h
+++ b/usr/src/boot/sys/boot/i386/libi386/libi386.h
@@ -89,17 +89,15 @@ extern struct devdesc currdev; /* our current device */
/* exported devices XXX rename? */
extern struct devsw bioscd;
-extern struct devsw biosdisk;
+extern struct devsw biosfd;
+extern struct devsw bioshd;
extern struct devsw pxedisk;
extern struct fs_ops pxe_fsops;
int bc_add(int biosdev); /* Register CD booted from. */
-int bc_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */
-int bc_bios2unit(int biosdev); /* xlate BIOS device -> bioscd unit */
-int bc_unit2bios(int unit); /* xlate bioscd unit -> BIOS device */
uint32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */
int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */
-int bd_unit2bios(int unit); /* xlate biosdisk unit -> BIOS device */
+int bd_unit2bios(struct i386_devdesc *); /* xlate biosdisk -> BIOS device */
int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */
ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len);
diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.c b/usr/src/boot/sys/boot/i386/libi386/linux.c
index 4c9910cc16..d69ac26a4e 100644
--- a/usr/src/boot/sys/boot/i386/libi386/linux.c
+++ b/usr/src/boot/sys/boot/i386/libi386/linux.c
@@ -292,7 +292,7 @@ linux_exec(struct preloaded_file *fp)
i386_getdev((void **)(&rootdev), fp->f_name, NULL);
if (rootdev != NULL)
- relocator_edx = bd_unit2bios(rootdev->dd.d_unit);
+ relocator_edx = bd_unit2bios(rootdev);
/*
* command line
diff --git a/usr/src/boot/sys/boot/i386/loader/chain.c b/usr/src/boot/sys/boot/i386/loader/chain.c
index 160f498065..04658076bb 100644
--- a/usr/src/boot/sys/boot/i386/loader/chain.c
+++ b/usr/src/boot/sys/boot/i386/loader/chain.c
@@ -100,7 +100,7 @@ command_chain(int argc, char *argv[])
relocater_data[0].dest = 0x7C00;
relocater_data[0].size = size;
- relocator_edx = bd_unit2bios(rootdev->dd.d_unit);
+ relocator_edx = bd_unit2bios(rootdev);
relocator_esi = relocater_size;
relocator_ds = 0;
relocator_es = 0;
diff --git a/usr/src/boot/sys/boot/i386/loader/conf.c b/usr/src/boot/sys/boot/i386/loader/conf.c
index 2d5ff8e8b1..70d7e44ad2 100644
--- a/usr/src/boot/sys/boot/i386/loader/conf.c
+++ b/usr/src/boot/sys/boot/i386/loader/conf.c
@@ -48,8 +48,9 @@ extern struct devsw fwohci;
/* Exported for libstand */
struct devsw *devsw[] = {
+ &biosfd,
&bioscd,
- &biosdisk,
+ &bioshd,
&pxedisk,
#if defined(LOADER_FIREWIRE_SUPPORT)
&fwohci,
diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/sys/boot/i386/loader/main.c
index abf2fc8832..cd605f1002 100644
--- a/usr/src/boot/sys/boot/i386/loader/main.c
+++ b/usr/src/boot/sys/boot/i386/loader/main.c
@@ -204,14 +204,14 @@ extract_currdev(void)
int biosdev = -1;
/* Assume we are booting from a BIOS disk by default */
- new_currdev.dd.d_dev = &biosdisk;
+ new_currdev.dd.d_dev = &bioshd;
/* new-style boot loaders such as pxeldr and cdldr */
if (kargs->bootinfo == 0) {
if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) {
/* we are booting from a CD with cdboot */
new_currdev.dd.d_dev = &bioscd;
- new_currdev.dd.d_unit = bc_bios2unit(initial_bootdev);
+ new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev);
} else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) {
/* we are booting from pxeldr */
new_currdev.dd.d_dev = &pxedisk;
@@ -263,7 +263,7 @@ extract_currdev(void)
* If we are booting off of a BIOS disk and we didn't succeed in determining
* which one we booted off of, just use disk0: as a reasonable default.
*/
- if ((new_currdev.dd.d_dev->dv_type == biosdisk.dv_type) &&
+ if ((new_currdev.dd.d_dev->dv_type == bioshd.dv_type) &&
((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) {
printf("Can't work out which disk we are booting from.\n"
"Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
@@ -329,18 +329,16 @@ static void
i386_zfs_probe(void)
{
char devname[32];
- int unit;
+ struct i386_devdesc dev;
/*
* Open all the disks we can find and see if we can reconstruct
* ZFS pools from them.
*/
- for (unit = 0; unit < MAXBDDEV; unit++) {
- if (bd_unit2bios(unit) == -1)
- break;
- if (bd_unit2bios(unit) < 0x80)
- continue;
- sprintf(devname, "disk%d:", unit);
+ dev.dd.d_dev = &bioshd;
+ for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) {
+ snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name,
+ dev.dd.d_unit);
zfs_probe_dev(devname, NULL);
}
}