bioscd.c revision 199767f8919635c4928607450d9e0abb932109ce
/*-
* 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
*
* 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.
*/
__FBSDID("$FreeBSD$");
/*
* 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 <machine/bootinfo.h>
#include <stdarg.h>
#include <bootstrap.h>
#include <btxv86.h>
#include <edd.h>
#include "libi386.h"
#define BIOSCD_SECSIZE 2048
#define MAXBCDEV 1
/* Major numbers for devices we frontend for. */
#define ACDMAJOR 117
#define CDMAJOR 15
#ifdef DISK_DEBUG
#else
#endif
struct specification_packet {
};
/*
* 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 */
static int nbcinfo = 0;
static int bc_init(void);
"cd",
};
/*
* Translate between BIOS device numbers and our private unit numbers.
*/
int
bc_bios2unit(int biosdev)
{
int i;
for (i = 0; i < nbcinfo; i++) {
return(i);
}
return(-1);
}
int
bc_unit2bios(int 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
{
return (-1);
v86int();
return (-1);
nbcinfo++;
return(0);
}
/*
* Print information about disks
*/
static int
{
char line[80];
int i, ret = 0;
for (i = 0; i < nbcinfo; i++) {
if (ret != 0)
return (ret);
}
return (ret);
}
/*
* Attempt to open the disk described by (dev) for use by (f).
*/
static int
{
struct i386_devdesc *dev;
DEBUG("attempt to open nonexistent disk");
return(ENXIO);
}
return(0);
}
static int
{
struct i386_devdesc *dev;
}
return(0);
}
static int
{
struct bcache_devdata bcd;
struct i386_devdesc *dev;
}
static int
{
struct i386_devdesc *dev;
int unit;
int blks;
#ifdef BD_SUPPORT_FRAGS
char fragbuf[BIOSCD_SECSIZE];
#else
if (size % BIOSCD_SECSIZE)
return (EINVAL);
#endif
return(EROFS);
return (EINVAL);
if (rsize)
*rsize = 0;
DEBUG("read error");
return (EIO);
} else {
if (rsize)
return (0);
}
}
#ifdef BD_SUPPORT_FRAGS
DEBUG("frag read %d from %lld+%d to %p",
if (blks) {
if (rsize)
return (0);
}
DEBUG("frag read error");
return(EIO);
}
#endif
if (rsize)
return (0);
}
/* Max number of sectors to bounce-buffer at a time. */
#define CD_BOUNCEBUF 8
/* return negative value for an error, otherwise blocks read */
static int
{
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 */
/*
* The destination buffer is above first 1MB of
* physical memory so we have to arrange a suitable
* bounce buffer.
*/
maxfer = x;
} else {
maxfer = 0;
}
p = dest;
while (resid > 0) {
if (bbuf)
else
xp = p;
x = resid;
if (maxfer > 0)
/*
* Loop retrying the operation a couple of times. The BIOS
* may also retry.
*/
/* If retrying, reset the drive */
if (retry > 0) {
v86int();
}
v86int();
if (result == 0)
break;
/* fall back to 1 sector read */
x = 1;
}
#ifdef DISK_DEBUG
#endif
/* still an error? break off */
if (result != 0)
break;
p += (x * BIOSCD_SECSIZE);
dblk += x;
resid -= x;
}
/* hexdump(dest, (blks * BIOSCD_SECSIZE)); */
return (-1); /* read failed */
}
/*
* Return a suitable dev_t value for (dev).
*/
int
{
int major;
int rootdev;
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.
*/
unit = 0; /* XXX */
/* XXX: Assume partition 'a'. */
return(rootdev);
}