14a5d661aSToomas Soome /*-
24a5d661aSToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
34a5d661aSToomas Soome * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
44a5d661aSToomas Soome * All rights reserved.
54a5d661aSToomas Soome *
64a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without
74a5d661aSToomas Soome * modification, are permitted provided that the following conditions
84a5d661aSToomas Soome * are met:
94a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright
104a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer.
114a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
124a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the
134a5d661aSToomas Soome * documentation and/or other materials provided with the distribution.
144a5d661aSToomas Soome *
154a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254a5d661aSToomas Soome * SUCH DAMAGE.
264a5d661aSToomas Soome */
274a5d661aSToomas Soome
284a5d661aSToomas Soome #include <sys/cdefs.h>
294a5d661aSToomas Soome
304a5d661aSToomas Soome /*
314a5d661aSToomas Soome * BIOS disk device handling.
324a5d661aSToomas Soome *
334a5d661aSToomas Soome * Ideas and algorithms from:
344a5d661aSToomas Soome *
354a5d661aSToomas Soome * - NetBSD libi386/biosdisk.c
364a5d661aSToomas Soome * - FreeBSD biosboot/disk.c
374a5d661aSToomas Soome *
384a5d661aSToomas Soome */
394a5d661aSToomas Soome
404a5d661aSToomas Soome #include <sys/disk.h>
41a10ef84eSToomas Soome #include <sys/limits.h>
424a5d661aSToomas Soome #include <stand.h>
434a5d661aSToomas Soome #include <machine/bootinfo.h>
444a5d661aSToomas Soome #include <stdarg.h>
454a5d661aSToomas Soome
464a5d661aSToomas Soome #include <bootstrap.h>
474a5d661aSToomas Soome #include <btxv86.h>
484a5d661aSToomas Soome #include <edd.h>
494a5d661aSToomas Soome #include "disk.h"
504a5d661aSToomas Soome #include "libi386.h"
514a5d661aSToomas Soome
524a5d661aSToomas Soome CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
534a5d661aSToomas Soome
544a5d661aSToomas Soome #define BIOS_NUMDRIVES 0x475
554a5d661aSToomas Soome #define BIOSDISK_SECSIZE 512
564a5d661aSToomas Soome #define BUFSIZE (1 * BIOSDISK_SECSIZE)
574a5d661aSToomas Soome
584a5d661aSToomas Soome #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */
594a5d661aSToomas Soome #define WDMAJOR 0 /* major numbers for devices we frontend for */
604a5d661aSToomas Soome #define WFDMAJOR 1
614a5d661aSToomas Soome #define FDMAJOR 2
624a5d661aSToomas Soome #define DAMAJOR 4
634a5d661aSToomas Soome
644a5d661aSToomas Soome #ifdef DISK_DEBUG
654a5d661aSToomas Soome # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
664a5d661aSToomas Soome #else
674a5d661aSToomas Soome # define DEBUG(fmt, args...)
684a5d661aSToomas Soome #endif
694a5d661aSToomas Soome
704a5d661aSToomas Soome /*
714a5d661aSToomas Soome * List of BIOS devices, translation from disk unit number to
724a5d661aSToomas Soome * BIOS unit number.
734a5d661aSToomas Soome */
744a5d661aSToomas Soome static struct bdinfo
754a5d661aSToomas Soome {
764a5d661aSToomas Soome int bd_unit; /* BIOS unit number */
774a5d661aSToomas Soome int bd_cyl; /* BIOS geometry */
784a5d661aSToomas Soome int bd_hds;
794a5d661aSToomas Soome int bd_sec;
804a5d661aSToomas Soome int bd_flags;
814a5d661aSToomas Soome #define BD_MODEINT13 0x0000
824a5d661aSToomas Soome #define BD_MODEEDD1 0x0001
834a5d661aSToomas Soome #define BD_MODEEDD3 0x0002
844a5d661aSToomas Soome #define BD_MODEMASK 0x0003
854a5d661aSToomas Soome #define BD_FLOPPY 0x0004
864a5d661aSToomas Soome int bd_type; /* BIOS 'drive type' (floppy only) */
874a5d661aSToomas Soome uint16_t bd_sectorsize; /* Sector size */
884a5d661aSToomas Soome uint64_t bd_sectors; /* Disk size */
894a5d661aSToomas Soome int bd_open; /* reference counter */
904a5d661aSToomas Soome void *bd_bcache; /* buffer cache data */
914a5d661aSToomas Soome } bdinfo [MAXBDDEV];
924a5d661aSToomas Soome static int nbdinfo = 0;
934a5d661aSToomas Soome
944a5d661aSToomas Soome #define BD(dev) (bdinfo[(dev)->d_unit])
954a5d661aSToomas Soome
962cd691b4SToomas Soome static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int);
974a5d661aSToomas Soome static int bd_int13probe(struct bdinfo *bd);
984a5d661aSToomas Soome
994a5d661aSToomas Soome static int bd_init(void);
100976852c7SToomas Soome static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
101976852c7SToomas Soome char *buf, size_t *rsize);
102976852c7SToomas Soome static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
103976852c7SToomas Soome char *buf, size_t *rsize);
1044a5d661aSToomas Soome static int bd_open(struct open_file *f, ...);
1054a5d661aSToomas Soome static int bd_close(struct open_file *f);
1064a5d661aSToomas Soome static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
1074a5d661aSToomas Soome static int bd_print(int verbose);
1084a5d661aSToomas Soome
1094a5d661aSToomas Soome struct devsw biosdisk = {
1104a5d661aSToomas Soome "disk",
1114a5d661aSToomas Soome DEVT_DISK,
1124a5d661aSToomas Soome bd_init,
1134a5d661aSToomas Soome bd_strategy,
1144a5d661aSToomas Soome bd_open,
1154a5d661aSToomas Soome bd_close,
1164a5d661aSToomas Soome bd_ioctl,
1174a5d661aSToomas Soome bd_print,
1181ec96012SToomas Soome NULL
1194a5d661aSToomas Soome };
1204a5d661aSToomas Soome
1214a5d661aSToomas Soome /*
1224a5d661aSToomas Soome * Translate between BIOS device numbers and our private unit numbers.
1234a5d661aSToomas Soome */
1244a5d661aSToomas Soome int
bd_bios2unit(int biosdev)1254a5d661aSToomas Soome bd_bios2unit(int biosdev)
1264a5d661aSToomas Soome {
1274a5d661aSToomas Soome int i;
1284a5d661aSToomas Soome
1294a5d661aSToomas Soome DEBUG("looking for bios device 0x%x", biosdev);
1304a5d661aSToomas Soome for (i = 0; i < nbdinfo; i++) {
1314a5d661aSToomas Soome DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
1324a5d661aSToomas Soome if (bdinfo[i].bd_unit == biosdev)
1334a5d661aSToomas Soome return (i);
1344a5d661aSToomas Soome }
1354a5d661aSToomas Soome return (-1);
1364a5d661aSToomas Soome }
1374a5d661aSToomas Soome
1384a5d661aSToomas Soome int
bd_unit2bios(int unit)1394a5d661aSToomas Soome bd_unit2bios(int unit)
1404a5d661aSToomas Soome {
1414a5d661aSToomas Soome
1424a5d661aSToomas Soome if ((unit >= 0) && (unit < nbdinfo))
1434a5d661aSToomas Soome return (bdinfo[unit].bd_unit);
1444a5d661aSToomas Soome return (-1);
1454a5d661aSToomas Soome }
1464a5d661aSToomas Soome
1474a5d661aSToomas Soome /*
1484a5d661aSToomas Soome * Quiz the BIOS for disk devices, save a little info about them.
1494a5d661aSToomas Soome */
1504a5d661aSToomas Soome static int
bd_init(void)1514a5d661aSToomas Soome bd_init(void)
1524a5d661aSToomas Soome {
1534a5d661aSToomas Soome int base, unit, nfd = 0;
1544a5d661aSToomas Soome
1554a5d661aSToomas Soome /* sequence 0, 0x80 */
1564a5d661aSToomas Soome for (base = 0; base <= 0x80; base += 0x80) {
1574a5d661aSToomas Soome for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
1584a5d661aSToomas Soome #ifndef VIRTUALBOX
1594a5d661aSToomas Soome /*
1604a5d661aSToomas Soome * Check the BIOS equipment list for number
1614a5d661aSToomas Soome * of fixed disks.
1624a5d661aSToomas Soome */
1634a5d661aSToomas Soome if(base == 0x80 &&
1644a5d661aSToomas Soome (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES)))
1654a5d661aSToomas Soome break;
1664a5d661aSToomas Soome #endif
1674a5d661aSToomas Soome bdinfo[nbdinfo].bd_open = 0;
1684a5d661aSToomas Soome bdinfo[nbdinfo].bd_bcache = NULL;
1694a5d661aSToomas Soome bdinfo[nbdinfo].bd_unit = unit;
1704a5d661aSToomas Soome bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
1714a5d661aSToomas Soome if (!bd_int13probe(&bdinfo[nbdinfo]))
1724a5d661aSToomas Soome break;
1734a5d661aSToomas Soome
1744a5d661aSToomas Soome #ifndef BOOT2
1754a5d661aSToomas Soome /* XXX we need "disk aliases" to make this simpler */
1764a5d661aSToomas Soome printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ?
1774a5d661aSToomas Soome ('A' + unit): ('C' + unit - 0x80), nbdinfo);
1784a5d661aSToomas Soome #endif
1794a5d661aSToomas Soome nbdinfo++;
1804a5d661aSToomas Soome if (base == 0x80)
1814a5d661aSToomas Soome nfd++;
1824a5d661aSToomas Soome }
1834a5d661aSToomas Soome }
1844a5d661aSToomas Soome bcache_add_dev(nbdinfo);
1854a5d661aSToomas Soome return(0);
1864a5d661aSToomas Soome }
1874a5d661aSToomas Soome
1884a5d661aSToomas Soome /*
1894a5d661aSToomas Soome * Try to detect a device supported by the legacy int13 BIOS
1904a5d661aSToomas Soome */
1914a5d661aSToomas Soome static int
bd_int13probe(struct bdinfo * bd)1924a5d661aSToomas Soome bd_int13probe(struct bdinfo *bd)
1934a5d661aSToomas Soome {
1944a5d661aSToomas Soome struct edd_params params;
1954a5d661aSToomas Soome int ret = 1; /* assume success */
1964a5d661aSToomas Soome
1974a5d661aSToomas Soome v86.ctl = V86_FLAGS;
1984a5d661aSToomas Soome v86.addr = 0x13;
1994a5d661aSToomas Soome v86.eax = 0x800;
2004a5d661aSToomas Soome v86.edx = bd->bd_unit;
2014a5d661aSToomas Soome v86int();
2024a5d661aSToomas Soome
2034a5d661aSToomas Soome /* Don't error out if we get bad sector number, try EDD as well */
2044a5d661aSToomas Soome if (V86_CY(v86.efl) || /* carry set */
2054a5d661aSToomas Soome (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f)) /* unit # bad */
2064a5d661aSToomas Soome return (0); /* skip device */
2074a5d661aSToomas Soome
2084a5d661aSToomas Soome if ((v86.ecx & 0x3f) == 0) /* absurd sector number */
2094a5d661aSToomas Soome ret = 0; /* set error */
2104a5d661aSToomas Soome
2114a5d661aSToomas Soome /* Convert max cyl # -> # of cylinders */
2124a5d661aSToomas Soome bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
2134a5d661aSToomas Soome /* Convert max head # -> # of heads */
2144a5d661aSToomas Soome bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
2154a5d661aSToomas Soome bd->bd_sec = v86.ecx & 0x3f;
2164a5d661aSToomas Soome bd->bd_type = v86.ebx & 0xff;
2174a5d661aSToomas Soome bd->bd_flags |= BD_MODEINT13;
2184a5d661aSToomas Soome
2194a5d661aSToomas Soome /* Calculate sectors count from the geometry */
2204a5d661aSToomas Soome bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec;
2214a5d661aSToomas Soome bd->bd_sectorsize = BIOSDISK_SECSIZE;
2224a5d661aSToomas Soome DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
2234a5d661aSToomas Soome bd->bd_hds, bd->bd_sec);
2244a5d661aSToomas Soome
2254a5d661aSToomas Soome /* Determine if we can use EDD with this device. */
2264a5d661aSToomas Soome v86.ctl = V86_FLAGS;
2274a5d661aSToomas Soome v86.addr = 0x13;
2284a5d661aSToomas Soome v86.eax = 0x4100;
2294a5d661aSToomas Soome v86.edx = bd->bd_unit;
2304a5d661aSToomas Soome v86.ebx = 0x55aa;
2314a5d661aSToomas Soome v86int();
2324a5d661aSToomas Soome if (V86_CY(v86.efl) || /* carry set */
2334a5d661aSToomas Soome (v86.ebx & 0xffff) != 0xaa55 || /* signature */
2344a5d661aSToomas Soome (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
2354a5d661aSToomas Soome return (ret); /* return code from int13 AH=08 */
2364a5d661aSToomas Soome
2374a5d661aSToomas Soome /* EDD supported */
2384a5d661aSToomas Soome bd->bd_flags |= BD_MODEEDD1;
2394a5d661aSToomas Soome if ((v86.eax & 0xff00) >= 0x3000)
2404a5d661aSToomas Soome bd->bd_flags |= BD_MODEEDD3;
2414a5d661aSToomas Soome /* Get disk params */
2424a5d661aSToomas Soome params.len = sizeof(struct edd_params);
2434a5d661aSToomas Soome v86.ctl = V86_FLAGS;
2444a5d661aSToomas Soome v86.addr = 0x13;
2454a5d661aSToomas Soome v86.eax = 0x4800;
2464a5d661aSToomas Soome v86.edx = bd->bd_unit;
2474a5d661aSToomas Soome v86.ds = VTOPSEG(¶ms);
2484a5d661aSToomas Soome v86.esi = VTOPOFF(¶ms);
2494a5d661aSToomas Soome v86int();
2504a5d661aSToomas Soome if (!V86_CY(v86.efl)) {
2514a5d661aSToomas Soome uint64_t total;
2524a5d661aSToomas Soome
253a10ef84eSToomas Soome /*
254a10ef84eSToomas Soome * Sector size must be a multiple of 512 bytes.
255a10ef84eSToomas Soome * An alternate test would be to check power of 2,
256a10ef84eSToomas Soome * powerof2(params.sector_size).
257a10ef84eSToomas Soome */
258a10ef84eSToomas Soome if (params.sector_size % BIOSDISK_SECSIZE)
259a10ef84eSToomas Soome bd->bd_sectorsize = BIOSDISK_SECSIZE;
260a10ef84eSToomas Soome else
261a10ef84eSToomas Soome bd->bd_sectorsize = params.sector_size;
262a10ef84eSToomas Soome
263a10ef84eSToomas Soome total = bd->bd_sectorsize * params.sectors;
264a10ef84eSToomas Soome if (params.sectors != 0) {
265a10ef84eSToomas Soome /* Only update if we did not overflow. */
266a10ef84eSToomas Soome if (total > params.sectors)
2674a5d661aSToomas Soome bd->bd_sectors = params.sectors;
268a10ef84eSToomas Soome }
2694a5d661aSToomas Soome
2704a5d661aSToomas Soome total = (uint64_t)params.cylinders *
2714a5d661aSToomas Soome params.heads * params.sectors_per_track;
2724a5d661aSToomas Soome if (bd->bd_sectors < total)
2734a5d661aSToomas Soome bd->bd_sectors = total;
2744a5d661aSToomas Soome
2754a5d661aSToomas Soome ret = 1;
2764a5d661aSToomas Soome }
2774a5d661aSToomas Soome DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u",
2784a5d661aSToomas Soome bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize);
2794a5d661aSToomas Soome return (ret);
2804a5d661aSToomas Soome }
2814a5d661aSToomas Soome
2824a5d661aSToomas Soome /*
2834a5d661aSToomas Soome * Print information about disks
2844a5d661aSToomas Soome */
2854a5d661aSToomas Soome static int
bd_print(int verbose)2864a5d661aSToomas Soome bd_print(int verbose)
2874a5d661aSToomas Soome {
2884a5d661aSToomas Soome static char line[80];
2894a5d661aSToomas Soome struct disk_devdesc dev;
2904a5d661aSToomas Soome int i, ret = 0;
2914a5d661aSToomas Soome
292c3f8f694SToomas Soome if (nbdinfo == 0)
293c3f8f694SToomas Soome return (0);
294c3f8f694SToomas Soome
295c3f8f694SToomas Soome printf("%s devices:", biosdisk.dv_name);
296c3f8f694SToomas Soome if ((ret = pager_output("\n")) != 0)
297c3f8f694SToomas Soome return (ret);
298c3f8f694SToomas Soome
2994a5d661aSToomas Soome for (i = 0; i < nbdinfo; i++) {
3004751ceb8SDan McDonald snprintf(line, sizeof (line),
3014751ceb8SDan McDonald " disk%d: BIOS drive %c (%ju X %u):\n", i,
3024a5d661aSToomas Soome (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
3034751ceb8SDan McDonald ('C' + bdinfo[i].bd_unit - 0x80),
3044751ceb8SDan McDonald (uintmax_t)bdinfo[i].bd_sectors,
3054751ceb8SDan McDonald bdinfo[i].bd_sectorsize);
3064a5d661aSToomas Soome ret = pager_output(line);
3074a5d661aSToomas Soome if (ret != 0)
3084a5d661aSToomas Soome return (ret);
3094a5d661aSToomas Soome
3104a5d661aSToomas Soome dev.d_dev = &biosdisk;
3114a5d661aSToomas Soome dev.d_unit = i;
3124a5d661aSToomas Soome dev.d_slice = -1;
3134a5d661aSToomas Soome dev.d_partition = -1;
3144a5d661aSToomas Soome if (disk_open(&dev,
3154a5d661aSToomas Soome bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
3161ec96012SToomas Soome bdinfo[i].bd_sectorsize) == 0) {
3174a5d661aSToomas Soome sprintf(line, " disk%d", i);
3184a5d661aSToomas Soome ret = disk_print(&dev, line, verbose);
3194a5d661aSToomas Soome disk_close(&dev);
3204a5d661aSToomas Soome if (ret != 0)
3214a5d661aSToomas Soome return (ret);
3224a5d661aSToomas Soome }
3234a5d661aSToomas Soome }
3244a5d661aSToomas Soome return (ret);
3254a5d661aSToomas Soome }
3264a5d661aSToomas Soome
3274a5d661aSToomas Soome /*
3284a5d661aSToomas Soome * Attempt to open the disk described by (dev) for use by (f).
3294a5d661aSToomas Soome *
3304a5d661aSToomas Soome * Note that the philosophy here is "give them exactly what
3314a5d661aSToomas Soome * they ask for". This is necessary because being too "smart"
3324a5d661aSToomas Soome * about what the user might want leads to complications.
3334a5d661aSToomas Soome * (eg. given no slice or partition value, with a disk that is
3344a5d661aSToomas Soome * sliced - are they after the first BSD slice, or the DOS
3354a5d661aSToomas Soome * slice before it?)
3364a5d661aSToomas Soome */
3374a5d661aSToomas Soome static int
bd_open(struct open_file * f,...)3384a5d661aSToomas Soome bd_open(struct open_file *f, ...)
3394a5d661aSToomas Soome {
3404a5d661aSToomas Soome struct disk_devdesc *dev;
341a10ef84eSToomas Soome struct disk_devdesc disk;
3424a5d661aSToomas Soome va_list ap;
343a10ef84eSToomas Soome uint64_t size;
344f6196c38SToomas Soome int rc;
3454a5d661aSToomas Soome
3464a5d661aSToomas Soome va_start(ap, f);
3474a5d661aSToomas Soome dev = va_arg(ap, struct disk_devdesc *);
3484a5d661aSToomas Soome va_end(ap);
3494a5d661aSToomas Soome
3504a5d661aSToomas Soome if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
3514a5d661aSToomas Soome return (EIO);
3524a5d661aSToomas Soome BD(dev).bd_open++;
3534a5d661aSToomas Soome if (BD(dev).bd_bcache == NULL)
3544a5d661aSToomas Soome BD(dev).bd_bcache = bcache_allocate();
355a10ef84eSToomas Soome
356a10ef84eSToomas Soome /*
357a10ef84eSToomas Soome * Read disk size from partition.
358a10ef84eSToomas Soome * This is needed to work around buggy BIOS systems returning
359a10ef84eSToomas Soome * wrong (truncated) disk media size.
360a10ef84eSToomas Soome * During bd_probe() we tested if the mulitplication of bd_sectors
361a10ef84eSToomas Soome * would overflow so it should be safe to perform here.
362a10ef84eSToomas Soome */
363a10ef84eSToomas Soome disk.d_dev = dev->d_dev;
364a10ef84eSToomas Soome disk.d_type = dev->d_type;
365a10ef84eSToomas Soome disk.d_unit = dev->d_unit;
366a10ef84eSToomas Soome disk.d_opendata = NULL;
367a10ef84eSToomas Soome disk.d_slice = -1;
368a10ef84eSToomas Soome disk.d_partition = -1;
369a10ef84eSToomas Soome disk.d_offset = 0;
370a10ef84eSToomas Soome
371a10ef84eSToomas Soome if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
3721ec96012SToomas Soome BD(dev).bd_sectorsize) == 0) {
373a10ef84eSToomas Soome
374a10ef84eSToomas Soome if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) {
375a10ef84eSToomas Soome size /= BD(dev).bd_sectorsize;
376a10ef84eSToomas Soome if (size > BD(dev).bd_sectors)
377a10ef84eSToomas Soome BD(dev).bd_sectors = size;
378a10ef84eSToomas Soome }
379a10ef84eSToomas Soome disk_close(&disk);
380a10ef84eSToomas Soome }
381a10ef84eSToomas Soome
382f6196c38SToomas Soome rc = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
383f6196c38SToomas Soome BD(dev).bd_sectorsize);
384f6196c38SToomas Soome if (rc != 0) {
385f6196c38SToomas Soome BD(dev).bd_open--;
386f6196c38SToomas Soome if (BD(dev).bd_open == 0) {
387f6196c38SToomas Soome bcache_free(BD(dev).bd_bcache);
388f6196c38SToomas Soome BD(dev).bd_bcache = NULL;
389f6196c38SToomas Soome }
390f6196c38SToomas Soome }
391f6196c38SToomas Soome return (rc);
3924a5d661aSToomas Soome }
3934a5d661aSToomas Soome
3944a5d661aSToomas Soome static int
bd_close(struct open_file * f)3954a5d661aSToomas Soome bd_close(struct open_file *f)
3964a5d661aSToomas Soome {
3974a5d661aSToomas Soome struct disk_devdesc *dev;
3984a5d661aSToomas Soome
3994a5d661aSToomas Soome dev = (struct disk_devdesc *)f->f_devdata;
4004a5d661aSToomas Soome BD(dev).bd_open--;
4014a5d661aSToomas Soome if (BD(dev).bd_open == 0) {
4024a5d661aSToomas Soome bcache_free(BD(dev).bd_bcache);
4034a5d661aSToomas Soome BD(dev).bd_bcache = NULL;
4044a5d661aSToomas Soome }
4054a5d661aSToomas Soome return (disk_close(dev));
4064a5d661aSToomas Soome }
4074a5d661aSToomas Soome
4084a5d661aSToomas Soome static int
bd_ioctl(struct open_file * f,u_long cmd,void * data)4094a5d661aSToomas Soome bd_ioctl(struct open_file *f, u_long cmd, void *data)
4104a5d661aSToomas Soome {
4114a5d661aSToomas Soome struct disk_devdesc *dev;
4129ab3b382SToomas Soome int rc;
4134a5d661aSToomas Soome
4144a5d661aSToomas Soome dev = (struct disk_devdesc *)f->f_devdata;
4159ab3b382SToomas Soome
4169ab3b382SToomas Soome rc = disk_ioctl(dev, cmd, data);
4179ab3b382SToomas Soome if (rc != ENOTTY)
4189ab3b382SToomas Soome return (rc);
4199ab3b382SToomas Soome
4204a5d661aSToomas Soome switch (cmd) {
4214a5d661aSToomas Soome case DIOCGSECTORSIZE:
4224a5d661aSToomas Soome *(u_int *)data = BD(dev).bd_sectorsize;
4234a5d661aSToomas Soome break;
4244a5d661aSToomas Soome case DIOCGMEDIASIZE:
425534e2075SToomas Soome *(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize;
4264a5d661aSToomas Soome break;
4274a5d661aSToomas Soome default:
4284a5d661aSToomas Soome return (ENOTTY);
4294a5d661aSToomas Soome }
4304a5d661aSToomas Soome return (0);
4314a5d661aSToomas Soome }
4324a5d661aSToomas Soome
4334a5d661aSToomas Soome static int
bd_strategy(void * devdata,int rw,daddr_t dblk,size_t size,char * buf,size_t * rsize)434976852c7SToomas Soome bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
4354a5d661aSToomas Soome char *buf, size_t *rsize)
4364a5d661aSToomas Soome {
4374a5d661aSToomas Soome struct bcache_devdata bcd;
4384a5d661aSToomas Soome struct disk_devdesc *dev;
4394a5d661aSToomas Soome
4404a5d661aSToomas Soome dev = (struct disk_devdesc *)devdata;
4414a5d661aSToomas Soome bcd.dv_strategy = bd_realstrategy;
4424a5d661aSToomas Soome bcd.dv_devdata = devdata;
4434a5d661aSToomas Soome bcd.dv_cache = BD(dev).bd_bcache;
4444a5d661aSToomas Soome
445976852c7SToomas Soome return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, size,
4464a5d661aSToomas Soome buf, rsize));
4474a5d661aSToomas Soome }
4484a5d661aSToomas Soome
4494a5d661aSToomas Soome static int
bd_realstrategy(void * devdata,int rw,daddr_t dblk,size_t size,char * buf,size_t * rsize)450976852c7SToomas Soome bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
4514a5d661aSToomas Soome char *buf, size_t *rsize)
4524a5d661aSToomas Soome {
4534a5d661aSToomas Soome struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
4542cd691b4SToomas Soome uint64_t disk_blocks, offset;
4552cd691b4SToomas Soome size_t blks, blkoff, bsize, rest;
4562cd691b4SToomas Soome caddr_t bbuf;
4572cd691b4SToomas Soome int rc;
4584a5d661aSToomas Soome
4592cd691b4SToomas Soome /*
460*ccce536fSToomas Soome * First make sure the IO size is a multiple of 512 bytes. While we do
4612cd691b4SToomas Soome * process partial reads below, the strategy mechanism is built
462*ccce536fSToomas Soome * assuming IO is a multiple of 512B blocks. If the request is not
463*ccce536fSToomas Soome * a multiple of 512B blocks, it has to be some sort of bug.
4642cd691b4SToomas Soome */
4652cd691b4SToomas Soome if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) {
4662cd691b4SToomas Soome printf("bd_strategy: %d bytes I/O not multiple of %d\n",
4672cd691b4SToomas Soome size, BIOSDISK_SECSIZE);
4682cd691b4SToomas Soome return (EIO);
4692cd691b4SToomas Soome }
4704a5d661aSToomas Soome
4714a5d661aSToomas Soome DEBUG("open_disk %p", dev);
472a10ef84eSToomas Soome
4732cd691b4SToomas Soome offset = dblk * BIOSDISK_SECSIZE;
4742cd691b4SToomas Soome dblk = offset / BD(dev).bd_sectorsize;
4752cd691b4SToomas Soome blkoff = offset % BD(dev).bd_sectorsize;
4762cd691b4SToomas Soome
477a10ef84eSToomas Soome /*
478a10ef84eSToomas Soome * Check the value of the size argument. We do have quite small
479a10ef84eSToomas Soome * heap (64MB), but we do not know good upper limit, so we check against
480a10ef84eSToomas Soome * INT_MAX here. This will also protect us against possible overflows
481a10ef84eSToomas Soome * while translating block count to bytes.
482a10ef84eSToomas Soome */
483a10ef84eSToomas Soome if (size > INT_MAX) {
484*ccce536fSToomas Soome DEBUG("requested read: %zu too large", size);
485a10ef84eSToomas Soome return (EIO);
486a10ef84eSToomas Soome }
487a10ef84eSToomas Soome
4884a5d661aSToomas Soome blks = size / BD(dev).bd_sectorsize;
4892cd691b4SToomas Soome if (blks == 0 || (size % BD(dev).bd_sectorsize) != 0)
4902cd691b4SToomas Soome blks++;
4912cd691b4SToomas Soome
492a10ef84eSToomas Soome if (dblk > dblk + blks)
493a10ef84eSToomas Soome return (EIO);
494a10ef84eSToomas Soome
4954a5d661aSToomas Soome if (rsize)
4964a5d661aSToomas Soome *rsize = 0;
4974a5d661aSToomas Soome
4982cd691b4SToomas Soome /*
4992cd691b4SToomas Soome * Get disk blocks, this value is either for whole disk or for
5002cd691b4SToomas Soome * partition.
5012cd691b4SToomas Soome */
502a10ef84eSToomas Soome if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
503a10ef84eSToomas Soome /* DIOCGMEDIASIZE does return bytes. */
504a10ef84eSToomas Soome disk_blocks /= BD(dev).bd_sectorsize;
505a10ef84eSToomas Soome } else {
506a10ef84eSToomas Soome /* We should not get here. Just try to survive. */
507a10ef84eSToomas Soome disk_blocks = BD(dev).bd_sectors - dev->d_offset;
508a10ef84eSToomas Soome }
509a10ef84eSToomas Soome
510a10ef84eSToomas Soome /* Validate source block address. */
511a10ef84eSToomas Soome if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks)
512a10ef84eSToomas Soome return (EIO);
513a10ef84eSToomas Soome
5144a5d661aSToomas Soome /*
515a10ef84eSToomas Soome * Truncate if we are crossing disk or partition end.
5164a5d661aSToomas Soome */
517a10ef84eSToomas Soome if (dblk + blks >= dev->d_offset + disk_blocks) {
518a10ef84eSToomas Soome blks = dev->d_offset + disk_blocks - dblk;
5194a5d661aSToomas Soome size = blks * BD(dev).bd_sectorsize;
5204a5d661aSToomas Soome DEBUG("short read %d", blks);
5214a5d661aSToomas Soome }
5224a5d661aSToomas Soome
5232cd691b4SToomas Soome if (V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize == 0)
5242cd691b4SToomas Soome panic("BUG: Real mode buffer is too small\n");
5252cd691b4SToomas Soome
5262cd691b4SToomas Soome bbuf = PTOV(V86_IO_BUFFER);
5272cd691b4SToomas Soome rest = size;
5282cd691b4SToomas Soome
5292cd691b4SToomas Soome while (blks > 0) {
5302cd691b4SToomas Soome int x = min(blks, V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize);
5312cd691b4SToomas Soome
532a5a5c3b7SToomas Soome switch (rw & F_MASK) {
5334a5d661aSToomas Soome case F_READ:
5342cd691b4SToomas Soome DEBUG("read %d from %lld to %p", x, dblk, buf);
5352cd691b4SToomas Soome bsize = BD(dev).bd_sectorsize * x - blkoff;
5362cd691b4SToomas Soome if (rest < bsize)
5372cd691b4SToomas Soome bsize = rest;
5384a5d661aSToomas Soome
5392cd691b4SToomas Soome if ((rc = bd_io(dev, dblk, x, bbuf, 0)) != 0)
5404a5d661aSToomas Soome return (EIO);
5412cd691b4SToomas Soome
5422cd691b4SToomas Soome bcopy(bbuf + blkoff, buf, bsize);
5434a5d661aSToomas Soome break;
5444a5d661aSToomas Soome case F_WRITE :
5452cd691b4SToomas Soome DEBUG("write %d from %lld to %p", x, dblk, buf);
5462cd691b4SToomas Soome if (blkoff != 0) {
5472cd691b4SToomas Soome /*
5482cd691b4SToomas Soome * We got offset to sector, read 1 sector to
5492cd691b4SToomas Soome * bbuf.
5502cd691b4SToomas Soome */
5512cd691b4SToomas Soome x = 1;
5522cd691b4SToomas Soome bsize = BD(dev).bd_sectorsize - blkoff;
5532cd691b4SToomas Soome bsize = min(bsize, rest);
5542cd691b4SToomas Soome rc = bd_io(dev, dblk, x, bbuf, 0);
5552cd691b4SToomas Soome } else if (rest < BD(dev).bd_sectorsize) {
5562cd691b4SToomas Soome /*
5572cd691b4SToomas Soome * The remaining block is not full
5582cd691b4SToomas Soome * sector. Read 1 sector to bbuf.
5592cd691b4SToomas Soome */
5602cd691b4SToomas Soome x = 1;
5612cd691b4SToomas Soome bsize = rest;
5622cd691b4SToomas Soome rc = bd_io(dev, dblk, x, bbuf, 0);
5632cd691b4SToomas Soome } else {
5642cd691b4SToomas Soome /* We can write full sector(s). */
5652cd691b4SToomas Soome bsize = BD(dev).bd_sectorsize * x;
5662cd691b4SToomas Soome }
5672cd691b4SToomas Soome /*
5682cd691b4SToomas Soome * Put your Data In, Put your Data out,
5692cd691b4SToomas Soome * Put your Data In, and shake it all about
5702cd691b4SToomas Soome */
5712cd691b4SToomas Soome bcopy(buf, bbuf + blkoff, bsize);
5722cd691b4SToomas Soome if ((rc = bd_io(dev, dblk, x, bbuf, 1)) != 0)
5732cd691b4SToomas Soome return (EIO);
5744a5d661aSToomas Soome
5754a5d661aSToomas Soome break;
5764a5d661aSToomas Soome default:
5774a5d661aSToomas Soome /* DO NOTHING */
5784a5d661aSToomas Soome return (EROFS);
5794a5d661aSToomas Soome }
5804a5d661aSToomas Soome
5812cd691b4SToomas Soome blkoff = 0;
5822cd691b4SToomas Soome buf += bsize;
5832cd691b4SToomas Soome rest -= bsize;
5842cd691b4SToomas Soome blks -= x;
5852cd691b4SToomas Soome dblk += x;
5862cd691b4SToomas Soome }
5872cd691b4SToomas Soome
5882cd691b4SToomas Soome if (rsize != NULL)
5894a5d661aSToomas Soome *rsize = size;
5904a5d661aSToomas Soome return (0);
5914a5d661aSToomas Soome }
5924a5d661aSToomas Soome
5934a5d661aSToomas Soome static int
bd_edd_io(struct disk_devdesc * dev,daddr_t dblk,int blks,caddr_t dest,int dowrite)5944a5d661aSToomas Soome bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
5954a5d661aSToomas Soome int dowrite)
5964a5d661aSToomas Soome {
5974a5d661aSToomas Soome static struct edd_packet packet;
5984a5d661aSToomas Soome
5994a5d661aSToomas Soome packet.len = sizeof(struct edd_packet);
6004a5d661aSToomas Soome packet.count = blks;
6014a5d661aSToomas Soome packet.off = VTOPOFF(dest);
6024a5d661aSToomas Soome packet.seg = VTOPSEG(dest);
6034a5d661aSToomas Soome packet.lba = dblk;
6044a5d661aSToomas Soome v86.ctl = V86_FLAGS;
6054a5d661aSToomas Soome v86.addr = 0x13;
6064a5d661aSToomas Soome if (dowrite)
6074a5d661aSToomas Soome /* Should we Write with verify ?? 0x4302 ? */
6084a5d661aSToomas Soome v86.eax = 0x4300;
6094a5d661aSToomas Soome else
6104a5d661aSToomas Soome v86.eax = 0x4200;
6114a5d661aSToomas Soome v86.edx = BD(dev).bd_unit;
6124a5d661aSToomas Soome v86.ds = VTOPSEG(&packet);
6134a5d661aSToomas Soome v86.esi = VTOPOFF(&packet);
6144a5d661aSToomas Soome v86int();
615bcf06a16SToomas Soome if (V86_CY(v86.efl))
616bcf06a16SToomas Soome return (v86.eax >> 8);
617bcf06a16SToomas Soome return (0);
6184a5d661aSToomas Soome }
6194a5d661aSToomas Soome
6204a5d661aSToomas Soome static int
bd_chs_io(struct disk_devdesc * dev,daddr_t dblk,int blks,caddr_t dest,int dowrite)6214a5d661aSToomas Soome bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
6224a5d661aSToomas Soome int dowrite)
6234a5d661aSToomas Soome {
6244a5d661aSToomas Soome u_int x, bpc, cyl, hd, sec;
6254a5d661aSToomas Soome
6264a5d661aSToomas Soome bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */
6274a5d661aSToomas Soome x = dblk;
6284a5d661aSToomas Soome cyl = x / bpc; /* block # / blocks per cylinder */
6294a5d661aSToomas Soome x %= bpc; /* block offset into cylinder */
6304a5d661aSToomas Soome hd = x / BD(dev).bd_sec; /* offset / blocks per track */
6314a5d661aSToomas Soome sec = x % BD(dev).bd_sec; /* offset into track */
6324a5d661aSToomas Soome
6334a5d661aSToomas Soome /* correct sector number for 1-based BIOS numbering */
6344a5d661aSToomas Soome sec++;
6354a5d661aSToomas Soome
6364a5d661aSToomas Soome if (cyl > 1023)
6374a5d661aSToomas Soome /* CHS doesn't support cylinders > 1023. */
6384a5d661aSToomas Soome return (1);
6394a5d661aSToomas Soome
6404a5d661aSToomas Soome v86.ctl = V86_FLAGS;
6414a5d661aSToomas Soome v86.addr = 0x13;
6424a5d661aSToomas Soome if (dowrite)
6434a5d661aSToomas Soome v86.eax = 0x300 | blks;
6444a5d661aSToomas Soome else
6454a5d661aSToomas Soome v86.eax = 0x200 | blks;
6464a5d661aSToomas Soome v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec;
6474a5d661aSToomas Soome v86.edx = (hd << 8) | BD(dev).bd_unit;
6484a5d661aSToomas Soome v86.es = VTOPSEG(dest);
6494a5d661aSToomas Soome v86.ebx = VTOPOFF(dest);
6504a5d661aSToomas Soome v86int();
651bcf06a16SToomas Soome if (V86_CY(v86.efl))
652bcf06a16SToomas Soome return (v86.eax >> 8);
653bcf06a16SToomas Soome return (0);
6544a5d661aSToomas Soome }
6554a5d661aSToomas Soome
6564a5d661aSToomas Soome static int
bd_io(struct disk_devdesc * dev,daddr_t dblk,int blks,caddr_t dest,int dowrite)6573fb2d663SToomas Soome bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
6583fb2d663SToomas Soome int dowrite)
6594a5d661aSToomas Soome {
6602cd691b4SToomas Soome u_int result, retry;
6614a5d661aSToomas Soome
6624a5d661aSToomas Soome /* Just in case some idiot actually tries to read/write -1 blocks... */
6634a5d661aSToomas Soome if (blks < 0)
6644a5d661aSToomas Soome return (-1);
6654a5d661aSToomas Soome
6664a5d661aSToomas Soome /*
6674a5d661aSToomas Soome * Loop retrying the operation a couple of times. The BIOS
6684a5d661aSToomas Soome * may also retry.
6694a5d661aSToomas Soome */
6704a5d661aSToomas Soome for (retry = 0; retry < 3; retry++) {
6714a5d661aSToomas Soome /* if retrying, reset the drive */
6724a5d661aSToomas Soome if (retry > 0) {
6734a5d661aSToomas Soome v86.ctl = V86_FLAGS;
6744a5d661aSToomas Soome v86.addr = 0x13;
6754a5d661aSToomas Soome v86.eax = 0;
6764a5d661aSToomas Soome v86.edx = BD(dev).bd_unit;
6774a5d661aSToomas Soome v86int();
6784a5d661aSToomas Soome }
6794a5d661aSToomas Soome
6804a5d661aSToomas Soome if (BD(dev).bd_flags & BD_MODEEDD1)
6812cd691b4SToomas Soome result = bd_edd_io(dev, dblk, blks, dest, dowrite);
6824a5d661aSToomas Soome else
6832cd691b4SToomas Soome result = bd_chs_io(dev, dblk, blks, dest, dowrite);
6842cd691b4SToomas Soome
6854a5d661aSToomas Soome if (result == 0)
6864a5d661aSToomas Soome break;
6874a5d661aSToomas Soome }
6884a5d661aSToomas Soome
6892cd691b4SToomas Soome /*
6902cd691b4SToomas Soome * 0x20 - Controller failure. This is common error when the
6912cd691b4SToomas Soome * media is not present.
6922cd691b4SToomas Soome */
6932cd691b4SToomas Soome if (result != 0 && result != 0x20) {
6942cd691b4SToomas Soome if (dowrite != 0) {
6952cd691b4SToomas Soome printf("%s%d: Write %d sector(s) from %p (0x%x) "
6962cd691b4SToomas Soome "to %lld: 0x%x", dev->d_dev->dv_name, dev->d_unit,
6972cd691b4SToomas Soome blks, dest, VTOP(dest), dblk, result);
6982cd691b4SToomas Soome } else {
6992cd691b4SToomas Soome printf("%s%d: Read %d sector(s) from %lld to %p "
7002cd691b4SToomas Soome "(0x%x): 0x%x", dev->d_dev->dv_name, dev->d_unit,
7012cd691b4SToomas Soome blks, dblk, dest, VTOP(dest), result);
7022cd691b4SToomas Soome }
7032cd691b4SToomas Soome
7042cd691b4SToomas Soome if (result != 0)
705bcf06a16SToomas Soome return (result);
7064a5d661aSToomas Soome }
7074a5d661aSToomas Soome
7084a5d661aSToomas Soome return(0);
7094a5d661aSToomas Soome }
7104a5d661aSToomas Soome
7114a5d661aSToomas Soome /*
7124a5d661aSToomas Soome * Return the BIOS geometry of a given "fixed drive" in a format
7134a5d661aSToomas Soome * suitable for the legacy bootinfo structure. Since the kernel is
7144a5d661aSToomas Soome * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
7154a5d661aSToomas Soome * prefer to get the information directly, rather than rely on being
7164a5d661aSToomas Soome * able to put it together from information already maintained for
7174a5d661aSToomas Soome * different purposes and for a probably different number of drives.
7184a5d661aSToomas Soome *
7194a5d661aSToomas Soome * For valid drives, the geometry is expected in the format (31..0)
7204a5d661aSToomas Soome * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
7214a5d661aSToomas Soome * indicated by returning the geometry of a "1.2M" PC-format floppy
7224a5d661aSToomas Soome * disk. And, incidentally, what is returned is not the geometry as
7234a5d661aSToomas Soome * such but the highest valid cylinder, head, and sector numbers.
7244a5d661aSToomas Soome */
7254a5d661aSToomas Soome u_int32_t
bd_getbigeom(int bunit)7264a5d661aSToomas Soome bd_getbigeom(int bunit)
7274a5d661aSToomas Soome {
7284a5d661aSToomas Soome
7294a5d661aSToomas Soome v86.ctl = V86_FLAGS;
7304a5d661aSToomas Soome v86.addr = 0x13;
7314a5d661aSToomas Soome v86.eax = 0x800;
7324a5d661aSToomas Soome v86.edx = 0x80 + bunit;
7334a5d661aSToomas Soome v86int();
7344a5d661aSToomas Soome if (V86_CY(v86.efl))
7354a5d661aSToomas Soome return 0x4f010f;
7364a5d661aSToomas Soome return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
7374a5d661aSToomas Soome (v86.edx & 0xff00) | (v86.ecx & 0x3f);
7384a5d661aSToomas Soome }
7394a5d661aSToomas Soome
7404a5d661aSToomas Soome /*
7414a5d661aSToomas Soome * Return a suitable dev_t value for (dev).
7424a5d661aSToomas Soome *
7434a5d661aSToomas Soome * In the case where it looks like (dev) is a SCSI disk, we allow the number of
7444a5d661aSToomas Soome * IDE disks to be specified in $num_ide_disks. There should be a Better Way.
7454a5d661aSToomas Soome */
7464a5d661aSToomas Soome int
bd_getdev(struct i386_devdesc * d)7474a5d661aSToomas Soome bd_getdev(struct i386_devdesc *d)
7484a5d661aSToomas Soome {
7494a5d661aSToomas Soome struct disk_devdesc *dev;
7504a5d661aSToomas Soome int biosdev;
7514a5d661aSToomas Soome int major;
7524a5d661aSToomas Soome int rootdev;
7534a5d661aSToomas Soome char *nip, *cp;
7544a5d661aSToomas Soome int i, unit;
7554a5d661aSToomas Soome
7564a5d661aSToomas Soome dev = (struct disk_devdesc *)d;
7574a5d661aSToomas Soome biosdev = bd_unit2bios(dev->d_unit);
7584a5d661aSToomas Soome DEBUG("unit %d BIOS device %d", dev->d_unit, biosdev);
7594a5d661aSToomas Soome if (biosdev == -1) /* not a BIOS device */
7604a5d661aSToomas Soome return(-1);
7614a5d661aSToomas Soome if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
7621ec96012SToomas Soome BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */
7634a5d661aSToomas Soome return (-1);
7644a5d661aSToomas Soome else
7654a5d661aSToomas Soome disk_close(dev);
7664a5d661aSToomas Soome
7674a5d661aSToomas Soome if (biosdev < 0x80) {
7684a5d661aSToomas Soome /* floppy (or emulated floppy) or ATAPI device */
7694a5d661aSToomas Soome if (bdinfo[dev->d_unit].bd_type == DT_ATAPI) {
7704a5d661aSToomas Soome /* is an ATAPI disk */
7714a5d661aSToomas Soome major = WFDMAJOR;
7724a5d661aSToomas Soome } else {
7734a5d661aSToomas Soome /* is a floppy disk */
7744a5d661aSToomas Soome major = FDMAJOR;
7754a5d661aSToomas Soome }
7764a5d661aSToomas Soome } else {
7774a5d661aSToomas Soome /* assume an IDE disk */
7784a5d661aSToomas Soome major = WDMAJOR;
7794a5d661aSToomas Soome }
7804a5d661aSToomas Soome /* default root disk unit number */
7814a5d661aSToomas Soome unit = biosdev & 0x7f;
7824a5d661aSToomas Soome
7834a5d661aSToomas Soome /* XXX a better kludge to set the root disk unit number */
7844a5d661aSToomas Soome if ((nip = getenv("root_disk_unit")) != NULL) {
7854a5d661aSToomas Soome i = strtol(nip, &cp, 0);
7864a5d661aSToomas Soome /* check for parse error */
7874a5d661aSToomas Soome if ((cp != nip) && (*cp == 0))
7884a5d661aSToomas Soome unit = i;
7894a5d661aSToomas Soome }
7904a5d661aSToomas Soome
7914a5d661aSToomas Soome rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition);
7924a5d661aSToomas Soome DEBUG("dev is 0x%x\n", rootdev);
7934a5d661aSToomas Soome return(rootdev);
7944a5d661aSToomas Soome }
795