199767f8919635c4928607450d9e0abb932109ceToomas Soome/*-
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 *
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 * are met:
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 *
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/cdefs.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome__FBSDID("$FreeBSD$");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * BIOS disk device handling.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Ideas and algorithms from:
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * - NetBSD libi386/biosdisk.c
199767f8919635c4928607450d9e0abb932109ceToomas Soome * - FreeBSD biosboot/disk.c
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/disk.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stand.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <machine/bootinfo.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stdarg.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <bootstrap.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <btxv86.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <edd.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "disk.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "libi386.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas SoomeCTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BIOS_NUMDRIVES 0x475
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BIOSDISK_SECSIZE 512
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BUFSIZE (1 * BIOSDISK_SECSIZE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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 WFDMAJOR 1
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define FDMAJOR 2
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define DAMAJOR 4
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef DISK_DEBUG
199767f8919635c4928607450d9e0abb932109ceToomas Soome# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#else
199767f8919635c4928607450d9e0abb932109ceToomas Soome# define DEBUG(fmt, args...)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * List of BIOS devices, translation from disk unit number to
199767f8919635c4928607450d9e0abb932109ceToomas Soome * BIOS unit number.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic struct bdinfo
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_unit; /* BIOS unit number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_cyl; /* BIOS geometry */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_hds;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_flags;
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD_MODEINT13 0x0000
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD_MODEEDD1 0x0001
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD_MODEEDD3 0x0002
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD_MODEMASK 0x0003
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD_FLOPPY 0x0004
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_type; /* BIOS 'drive type' (floppy only) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint16_t bd_sectorsize; /* Sector size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint64_t bd_sectors; /* Disk size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bd_open; /* reference counter */
199767f8919635c4928607450d9e0abb932109ceToomas Soome void *bd_bcache; /* buffer cache data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome} bdinfo [MAXBDDEV];
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int nbdinfo = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BD(dev) (bdinfo[(dev)->d_unit])
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks,
199767f8919635c4928607450d9e0abb932109ceToomas Soome caddr_t dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_write(struct disk_devdesc *dev, daddr_t dblk, int blks,
199767f8919635c4928607450d9e0abb932109ceToomas Soome caddr_t dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_int13probe(struct bdinfo *bd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_init(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t offset,
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t size, char *buf, size_t *rsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t offset,
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t size, char *buf, size_t *rsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_open(struct open_file *f, ...);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_close(struct open_file *f);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_ioctl(struct open_file *f, u_long cmd, void *data);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bd_print(int verbose);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void bd_cleanup(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct devsw biosdisk = {
199767f8919635c4928607450d9e0abb932109ceToomas Soome "disk",
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEVT_DISK,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_init,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_strategy,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_open,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_close,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_ioctl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_print,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd_cleanup
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Translate between BIOS device numbers and our private unit numbers.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_bios2unit(int biosdev)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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 if (bdinfo[i].bd_unit == biosdev)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (i);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_unit2bios(int unit)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((unit >= 0) && (unit < nbdinfo))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (bdinfo[unit].bd_unit);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Quiz the BIOS for disk devices, save a little info about them.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_init(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int base, unit, nfd = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* sequence 0, 0x80 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (base = 0; base <= 0x80; base += 0x80) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifndef VIRTUALBOX
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check the BIOS equipment list for number
199767f8919635c4928607450d9e0abb932109ceToomas Soome * of fixed disks.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if(base == 0x80 &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES)))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[nbdinfo].bd_open = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[nbdinfo].bd_bcache = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[nbdinfo].bd_unit = unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!bd_int13probe(&bdinfo[nbdinfo]))
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifndef BOOT2
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 ('A' + unit): ('C' + unit - 0x80), nbdinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome nbdinfo++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (base == 0x80)
199767f8919635c4928607450d9e0abb932109ceToomas Soome nfd++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcache_add_dev(nbdinfo);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_cleanup(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_cleanup(&biosdisk);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Try to detect a device supported by the legacy int13 BIOS
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_int13probe(struct bdinfo *bd)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct edd_params params;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int ret = 1; /* assume success */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x800;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = bd->bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Don't error out if we get bad sector number, try EDD as well */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (V86_CY(v86.efl) || /* carry set */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0); /* skip device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((v86.ecx & 0x3f) == 0) /* absurd sector number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = 0; /* set error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
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 bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sec = v86.ecx & 0x3f;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_type = v86.ebx & 0xff;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_flags |= BD_MODEINT13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Calculate sectors count from the geometry */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectorsize = BIOSDISK_SECSIZE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_hds, bd->bd_sec);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Determine if we can use EDD with this device. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x4100;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = bd->bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ebx = 0x55aa;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (V86_CY(v86.efl) || /* carry set */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.ebx & 0xffff) != 0xaa55 || /* signature */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ret); /* return code from int13 AH=08 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* EDD supported */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_flags |= BD_MODEEDD1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((v86.eax & 0xff00) >= 0x3000)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_flags |= BD_MODEEDD3;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Get disk params */
199767f8919635c4928607450d9e0abb932109ceToomas Soome params.len = sizeof(struct edd_params);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x4800;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = bd->bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ds = VTOPSEG(&params);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.esi = VTOPOFF(&params);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!V86_CY(v86.efl)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint64_t total;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (params.sectors != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectors = params.sectors;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome total = (uint64_t)params.cylinders *
199767f8919635c4928607450d9e0abb932109ceToomas Soome params.heads * params.sectors_per_track;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bd->bd_sectors < total)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectors = total;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome bd->bd_sectorsize = params.sector_size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
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 return (ret);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Print information about disks
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_print(int verbose)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome static char line[80];
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int i, ret = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < nbdinfo; i++) {
9c02c7edf62c061c8b4d3134fb190ea51af6f69fDan McDonald snprintf(line, sizeof (line),
9c02c7edf62c061c8b4d3134fb190ea51af6f69fDan McDonald " disk%d: BIOS drive %c (%ju X %u):\n", i,
199767f8919635c4928607450d9e0abb932109ceToomas Soome (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
9c02c7edf62c061c8b4d3134fb190ea51af6f69fDan McDonald ('C' + bdinfo[i].bd_unit - 0x80),
9c02c7edf62c061c8b4d3134fb190ea51af6f69fDan McDonald (uintmax_t)bdinfo[i].bd_sectors,
9c02c7edf62c061c8b4d3134fb190ea51af6f69fDan McDonald bdinfo[i].bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = pager_output(line);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ret != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ret);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_dev = &biosdisk;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_unit = i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_slice = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_partition = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (disk_open(&dev,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bdinfo[i].bd_sectorsize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome (bdinfo[i].bd_flags & BD_FLOPPY) ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome DISK_F_NOCACHE: 0) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, " disk%d", i);
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = disk_print(&dev, line, verbose);
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_close(&dev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (ret != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ret);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ret);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Attempt to open the disk described by (dev) for use by (f).
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_open(struct open_file *f, ...)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_list ap;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_start(ap, f);
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = va_arg(ap, struct disk_devdesc *);
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_end(ap);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_open++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (BD(dev).bd_bcache == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_bcache = bcache_allocate();
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 Soome DISK_F_NOCACHE: 0));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_close(struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = (struct disk_devdesc *)f->f_devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_open--;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (BD(dev).bd_open == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcache_free(BD(dev).bd_bcache);
199767f8919635c4928607450d9e0abb932109ceToomas Soome BD(dev).bd_bcache = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (disk_close(dev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_ioctl(struct open_file *f, u_long cmd, void *data)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = (struct disk_devdesc *)f->f_devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch (cmd) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case DIOCGSECTORSIZE:
199767f8919635c4928607450d9e0abb932109ceToomas Soome *(u_int *)data = BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case DIOCGMEDIASIZE:
199767f8919635c4928607450d9e0abb932109ceToomas Soome *(off_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENOTTY);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *buf, size_t *rsize)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bcache_devdata bcd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = (struct disk_devdesc *)devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcd.dv_strategy = bd_realstrategy;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcd.dv_devdata = devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcd.dv_cache = BD(dev).bd_bcache;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, offset, size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome buf, rsize));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *buf, size_t *rsize)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int blks, remaining;
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome char fragbuf[BIOSDISK_SECSIZE];
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t fragsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome fragsize = size % BIOSDISK_SECSIZE;
199767f8919635c4928607450d9e0abb932109ceToomas Soome#else
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (size % BD(dev).bd_sectorsize)
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("bd_strategy: %d bytes I/O not multiple of block size", size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("open_disk %p", dev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome blks = size / BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rsize)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *rsize = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (remaining > 0 && remaining < blks) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome blks = remaining;
199767f8919635c4928607450d9e0abb932109ceToomas Soome size = blks * BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("short read %d", blks);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch(rw){
199767f8919635c4928607450d9e0abb932109ceToomas Soome case F_READ:
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("read %d from %lld to %p", blks, dblk, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (blks && bd_read(dev, dblk, blks, buf)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("read error");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
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 DEBUG("frag read error");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(fragbuf, buf + (blks * BIOSDISK_SECSIZE), fragsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case F_WRITE :
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("write %d from %d to %p", blks, dblk, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (blks && bd_write(dev, dblk, blks, buf)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("write error");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef BD_SUPPORT_FRAGS
199767f8919635c4928607450d9e0abb932109ceToomas Soome if(fragsize) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("Attempted to write a frag");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* DO NOTHING */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EROFS);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rsize)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *rsize = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define FLOPPY_BOUNCEBUF 18
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome int dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome static struct edd_packet packet;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome packet.len = sizeof(struct edd_packet);
199767f8919635c4928607450d9e0abb932109ceToomas Soome packet.count = blks;
199767f8919635c4928607450d9e0abb932109ceToomas Soome packet.off = VTOPOFF(dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soome packet.seg = VTOPSEG(dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soome packet.lba = dblk;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Should we Write with verify ?? 0x4302 ? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x4300;
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x4200;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = BD(dev).bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ds = VTOPSEG(&packet);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.esi = VTOPOFF(&packet);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (V86_CY(v86.efl));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
199767f8919635c4928607450d9e0abb932109ceToomas Soome int dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_int x, bpc, cyl, hd, sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */
199767f8919635c4928607450d9e0abb932109ceToomas Soome x = dblk;
199767f8919635c4928607450d9e0abb932109ceToomas Soome cyl = x / bpc; /* block # / blocks per cylinder */
199767f8919635c4928607450d9e0abb932109ceToomas Soome x %= bpc; /* block offset into 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
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* correct sector number for 1-based BIOS numbering */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sec++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cyl > 1023)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* CHS doesn't support cylinders > 1023. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x300 | blks;
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x200 | blks;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = (hd << 8) | BD(dev).bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.es = VTOPSEG(dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ebx = VTOPOFF(dest);
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (V86_CY(v86.efl));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome u_int x, sec, result, resid, retry, maxfer;
199767f8919635c4928607450d9e0abb932109ceToomas Soome caddr_t p, xp, bbuf, breg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Just in case some idiot actually tries to read/write -1 blocks... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (blks < 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome resid = blks;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p = dest;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Decide whether we have to bounce */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (VTOP(dest) >> 20 != 0 || (BD(dev).bd_unit < 0x80 &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome (VTOP(dest) >> 16) != (VTOP(dest +
199767f8919635c4928607450d9e0abb932109ceToomas Soome blks * BD(dev).bd_sectorsize) >> 16))) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome x = min(FLOPPY_BOUNCEBUF, (unsigned)blks);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bbuf = alloca(x * 2 * BD(dev).bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (((u_int32_t)VTOP(bbuf) & 0xffff0000) ==
199767f8919635c4928607450d9e0abb932109ceToomas Soome ((u_int32_t)VTOP(bbuf + x * BD(dev).bd_sectorsize) & 0xffff0000)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome breg = bbuf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome breg = bbuf + x * BD(dev).bd_sectorsize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome maxfer = x; /* limit transfers to bounce region size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome breg = bbuf = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome maxfer = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (resid > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Play it safe and don't cross track boundaries.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * (XXX this is probably unnecessary)
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sec = dblk % BD(dev).bd_sec; /* offset into track */
199767f8919635c4928607450d9e0abb932109ceToomas Soome x = min(BD(dev).bd_sec - sec, resid);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (maxfer > 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome x = min(x, maxfer); /* fit bounce buffer */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* where do we transfer to? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome xp = bbuf == NULL ? p : breg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Put your Data In, Put your Data out,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Put your Data In, and shake it all about
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dowrite && bbuf != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(p, breg, x * BD(dev).bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Loop retrying the operation a couple of times. The BIOS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * may also retry.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (retry = 0; retry < 3; retry++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if retrying, reset the drive */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (retry > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = BD(dev).bd_unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (BD(dev).bd_flags & BD_MODEEDD1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = bd_edd_io(dev, dblk, x, xp, dowrite);
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = bd_chs_io(dev, dblk, x, xp, dowrite);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dowrite)
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("Write %d sector(s) from %p (0x%x) to %lld %s", x,
199767f8919635c4928607450d9e0abb932109ceToomas Soome p, VTOP(p), dblk, result ? "failed" : "ok");
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("Read %d sector(s) from %lld to %p (0x%x) %s", x,
199767f8919635c4928607450d9e0abb932109ceToomas Soome dblk, p, VTOP(p), result ? "failed" : "ok");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!dowrite && bbuf != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(breg, p, x * BD(dev).bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome p += (x * BD(dev).bd_sectorsize);
199767f8919635c4928607450d9e0abb932109ceToomas Soome dblk += x;
199767f8919635c4928607450d9e0abb932109ceToomas Soome resid -= x;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* hexdump(dest, (blks * BD(dev).bd_sectorsize)); */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (bd_io(dev, dblk, blks, dest, 0));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_write(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (bd_io(dev, dblk, blks, dest, 1));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
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 *
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeu_int32_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_getbigeom(int bunit)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.ctl = V86_FLAGS;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.addr = 0x13;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.eax = 0x800;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86.edx = 0x80 + bunit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome v86int();
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (V86_CY(v86.efl))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return 0x4f010f;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
199767f8919635c4928607450d9e0abb932109ceToomas Soome (v86.edx & 0xff00) | (v86.ecx & 0x3f);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Return a suitable dev_t value for (dev).
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
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 */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomebd_getdev(struct i386_devdesc *d)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int biosdev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int major;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int rootdev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *nip, *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int i, unit;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = (struct disk_devdesc *)d;
199767f8919635c4928607450d9e0abb932109ceToomas Soome biosdev = bd_unit2bios(dev->d_unit);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (biosdev == -1) /* not a BIOS device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
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 else
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_close(dev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (biosdev < 0x80) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* floppy (or emulated floppy) or ATAPI device */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is an ATAPI disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome major = WFDMAJOR;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* is a floppy disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome major = FDMAJOR;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* assume an IDE disk */
199767f8919635c4928607450d9e0abb932109ceToomas Soome major = WDMAJOR;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* default root disk unit number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome unit = biosdev & 0x7f;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* XXX a better kludge to set the root disk unit number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((nip = getenv("root_disk_unit")) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome i = strtol(nip, &cp, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check for parse error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((cp != nip) && (*cp == 0))
199767f8919635c4928607450d9e0abb932109ceToomas Soome unit = i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition);
199767f8919635c4928607450d9e0abb932109ceToomas Soome DEBUG("dev is 0x%x\n", rootdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(rootdev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}