biosdisk.c revision 199767f8919635c4928607450d9e0abb932109ce
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * BIOS disk device handling.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Ideas and algorithms from:
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define WDMAJOR 0 /* major numbers for devices we frontend for */
199767f8919635c4928607450d9e0abb932109ceToomas Soome# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * List of BIOS devices, translation from disk unit number to
199767f8919635c4928607450d9e0abb932109ceToomas Soome * BIOS unit number.
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_type; /* BIOS 'drive type' (floppy only) */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int nbdinfo = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks,
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks,
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_init(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t offset,
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t offset,
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_ioctl(struct open_file *f, u_long cmd, void *data);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void bd_cleanup(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Translate between BIOS device numbers and our private unit numbers.
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("looking for bios device 0x%x", biosdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < nbdinfo; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Quiz the BIOS for disk devices, save a little info about them.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* sequence 0, 0x80 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check the BIOS equipment list for number
199767f8919635c4928607450d9e0abb932109ceToomas Soome * of fixed disks.
199767f8919635c4928607450d9e0abb932109ceToomas Soome (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* XXX we need "disk aliases" to make this simpler */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Try to detect a device supported by the legacy int13 BIOS
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Don't error out if we get bad sector number, try EDD as well */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0); /* skip device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((v86.ecx & 0x3f) == 0) /* absurd sector number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Convert max cyl # -> # of cylinders */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Convert max head # -> # of heads */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Calculate sectors count from the geometry */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Determine if we can use EDD with this device. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.ebx & 0xffff) != 0xaa55 || /* signature */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ret); /* return code from int13 AH=08 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* EDD supported */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Get disk params */
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u",
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Print information about disks
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < nbdinfo; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Attempt to open the disk described by (dev) for use by (f).
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Note that the philosophy here is "give them exactly what
199767f8919635c4928607450d9e0abb932109ceToomas Soome * they ask for". This is necessary because being too "smart"
199767f8919635c4928607450d9e0abb932109ceToomas Soome * about what the user might want leads to complications.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * (eg. given no slice or partition value, with a disk that is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * sliced - are they after the first BSD slice, or the DOS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * slice before it?)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ?
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_ioctl(struct open_file *f, u_long cmd, void *data)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *(off_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, offset, size,
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("bd_strategy: %d bytes I/O not multiple of block size", size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Perform partial read to prevent read-ahead crossing
199767f8919635c4928607450d9e0abb932109ceToomas Soome * the end of disk - or any 32 bit aliases of the end.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Signed arithmetic is used to handle wrap-around cases
199767f8919635c4928607450d9e0abb932109ceToomas Soome * like we do for TCP sequence numbers.
199767f8919635c4928607450d9e0abb932109ceToomas Soome remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("read %d from %lld to %p", blks, dblk, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("bd_strategy: frag read %d from %d+%d to %p",
199767f8919635c4928607450d9e0abb932109ceToomas Soome fragsize, dblk, blks, buf + (blks * BIOSDISK_SECSIZE));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fragsize && bd_read(od, dblk + blks, 1, fragsize)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("write %d from %d to %p", blks, dblk, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* DO NOTHING */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Should we Write with verify ?? 0x4302 ? */
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */
199767f8919635c4928607450d9e0abb932109ceToomas Soome cyl = x / bpc; /* block # / blocks per cylinder */
199767f8919635c4928607450d9e0abb932109ceToomas Soome hd = x / BD(dev).bd_sec; /* offset / blocks per track */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sec = x % BD(dev).bd_sec; /* offset into track */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* correct sector number for 1-based BIOS numbering */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* CHS doesn't support cylinders > 1023. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Just in case some idiot actually tries to read/write -1 blocks... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Decide whether we have to bounce */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome * There is a 64k physical boundary somewhere in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * destination buffer, or the destination buffer is above
199767f8919635c4928607450d9e0abb932109ceToomas Soome * first 1MB of physical memory so we have to arrange a
199767f8919635c4928607450d9e0abb932109ceToomas Soome * suitable bounce buffer. Allocate a buffer twice as large
199767f8919635c4928607450d9e0abb932109ceToomas Soome * as we need to. Use the bottom half unless there is a break
199767f8919635c4928607450d9e0abb932109ceToomas Soome * there, in which case we use the top half.
199767f8919635c4928607450d9e0abb932109ceToomas Soome ((u_int32_t)VTOP(bbuf + x * BD(dev).bd_sectorsize) & 0xffff0000)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome maxfer = x; /* limit transfers to bounce region size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (resid > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Play it safe and don't cross track boundaries.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * (XXX this is probably unnecessary)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sec = dblk % BD(dev).bd_sec; /* offset into track */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* where do we transfer to? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Put your Data In, Put your Data out,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Put your Data In, and shake it all about
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Loop retrying the operation a couple of times. The BIOS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * may also retry.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if retrying, reset the drive */
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* hexdump(dest, (blks * BD(dev).bd_sectorsize)); */
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Return the BIOS geometry of a given "fixed drive" in a format
199767f8919635c4928607450d9e0abb932109ceToomas Soome * suitable for the legacy bootinfo structure. Since the kernel is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
199767f8919635c4928607450d9e0abb932109ceToomas Soome * prefer to get the information directly, rather than rely on being
199767f8919635c4928607450d9e0abb932109ceToomas Soome * able to put it together from information already maintained for
199767f8919635c4928607450d9e0abb932109ceToomas Soome * different purposes and for a probably different number of drives.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * For valid drives, the geometry is expected in the format (31..0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
199767f8919635c4928607450d9e0abb932109ceToomas Soome * indicated by returning the geometry of a "1.2M" PC-format floppy
199767f8919635c4928607450d9e0abb932109ceToomas Soome * disk. And, incidentally, what is returned is not the geometry as
199767f8919635c4928607450d9e0abb932109ceToomas Soome * such but the highest valid cylinder, head, and sector numbers.
199767f8919635c4928607450d9e0abb932109ceToomas Soome return 0x4f010f;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Return a suitable dev_t value for (dev).
199767f8919635c4928607450d9e0abb932109ceToomas Soome * In the case where it looks like (dev) is a SCSI disk, we allow the number of
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IDE disks to be specified in $num_ide_disks. There should be a Better Way.
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_sectorsize,(BD(dev).bd_flags & BD_FLOPPY) ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome DISK_F_NOCACHE: 0) != 0) /* oops, not a viable device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* floppy (or emulated floppy) or ATAPI device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is an ATAPI disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is a floppy disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* assume an IDE disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* default root disk unit number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* XXX a better kludge to set the root disk unit number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((nip = getenv("root_disk_unit")) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check for parse error */