diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 5 | ||||
-rw-r--r-- | sys/arch/i386/i386/conf.c | 44 | ||||
-rw-r--r-- | sys/arch/i386/i386/dkcsum.c | 173 |
3 files changed, 220 insertions, 2 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 8a318f28429..3b0ac979366 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.34 1997/09/29 03:52:21 mickey Exp $ +# $OpenBSD: files.i386,v 1.35 1997/10/27 08:06:31 niklas Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -223,3 +223,6 @@ device apm attach apm at bios file arch/i386/i386/apm.c apm needs-count +pseudo-device dkcsum +file arch/i386/i386/dkcsum.c dkcsum needs-flag +file lib/libz/adler32.c dkcsum & !ppp_deflate diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c index df526ca46bb..4bb121b12dd 100644 --- a/sys/arch/i386/i386/conf.c +++ b/sys/arch/i386/i386/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.38 1997/10/25 08:30:05 mickey Exp $ */ +/* $OpenBSD: conf.c,v 1.39 1997/10/27 08:06:31 niklas Exp $ */ /* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */ /* @@ -33,11 +33,15 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> +#include <sys/device.h> +#include <sys/disklabel.h> #include <sys/ioctl.h> #include <sys/tty.h> #include <sys/vnode.h> + #include <machine/conf.h> +#include "dkcsum.h" #include "wdc.h" #include "wd.h" bdev_decl(wd); @@ -366,6 +370,44 @@ blktochr(dev) return (NODEV); } +#if NDKCSUM > 0 +/* + * In order to map BSD bdev numbers of disks to their BIOS equivalents + * we use several heuristics, one being using checksums of the first + * few blocks of a disk to get a signature we can match with /boot's + * computed signatures. To know where from to read, we must provide a + * disk driver name -> bdev major number table, which follows. + * Note: floppies are not included as those are differentiated by the BIOS. + */ +static struct { + char *name; + int maj; +} disk_maj[] = { + { "wd", 0 }, + { "sd", 4 }, + { "acd", 18 }, + { "cd", 6 }, + { "mcd", 7 }, /* XXX I wonder if any BIOSes support this */ + { "scd", 15 } /* - " - */ +}; + +dev_t dev_rawpart __P((struct device *)); /* XXX */ + +dev_t +dev_rawpart(dv) + struct device *dv; +{ + int i; + + for (i = 0; i < sizeof disk_maj / sizeof disk_maj[0]; i++) + if (strcmp(dv->dv_cfdata->cf_driver->cd_name, + disk_maj[i].name) == 0) + return (MAKEDISKDEV(disk_maj[i].maj, dv->dv_unit, + RAW_PART)); + return (NODEV); +} +#endif + /* * This entire table could be autoconfig()ed but that would mean that * the kernel's idea of the console would be out of sync with that of diff --git a/sys/arch/i386/i386/dkcsum.c b/sys/arch/i386/i386/dkcsum.c new file mode 100644 index 00000000000..4d93d473bc5 --- /dev/null +++ b/sys/arch/i386/i386/dkcsum.c @@ -0,0 +1,173 @@ +/* $OpenBSD: dkcsum.c,v 1.1 1997/10/27 08:06:30 niklas Exp $ */ + +/*- + * Copyright (c) 1997 Niklas Hallqvist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Niklas Hallqvist. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A checksumming pseudo device used to get unique labels of each disk + * that needs to be matched to BIOS disks. + */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/fcntl.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <sys/systm.h> + +#include <machine/biosvar.h> + +#include <lib/libz/zlib.h> + +#define b_cylin b_resid + +dev_t dev_rawpart __P((struct device *)); /* XXX */ + +extern u_int32_t bios_cksumlen; +extern bios_diskinfo_t *bios_diskinfo; + +void dkcsumattach __P((int)); + +void +dkcsumattach(unused) + int unused; +{ + struct device *dv; + struct buf *bp; + struct bdevsw *bdsw; + dev_t dev; + int error; + u_int32_t csum; + bios_diskinfo_t *bdi, *hit; + + /* + * XXX Whatif DEV_BSIZE is changed to something else than the BIOS + * blocksize? Today, /boot doesn't cover that case so neither need + * I care here. + */ + bp = geteblk(bios_cksumlen * DEV_BSIZE); /* XXX error check? */ + + for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) { + if (dv->dv_class != DV_DISK) + continue; + bp->b_dev = dev = dev_rawpart(dv); + if (dev == NODEV) + continue; + bdsw = &bdevsw[major(dev)]; + + /* + * This open operation guarantees a proper initialization + * of the device, for future strategy calls. + */ + error = (*bdsw->d_open)(dev, FREAD, S_IFCHR, curproc); + if (error) { + /* XXX What to do here? */ + printf("dkcsum: open of %s failed (%d)\n", + dv->dv_xname, error); + continue; + } + + /* Read blocks to cksum. XXX maybe a d_read should be used. */ + bp->b_blkno = 0; + bp->b_bcount = bios_cksumlen * DEV_BSIZE; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylin = 0; + (*bdsw->d_strategy)(bp); + if (biowait(bp)) { + /* XXX What to do here? */ + printf("dkcsum: read of %s failed (%d)\n", + dv->dv_xname, error); + error = (*bdsw->d_close)(dev, 0, S_IFCHR, curproc); + if (error) + printf("dkcsum: close of %s failed (%d)\n", + dv->dv_xname, error); + continue; + } + error = (*bdsw->d_close)(dev, FREAD, S_IFCHR, curproc); + if (error) { + /* XXX What to do here? */ + printf("dkcsum: close of %s failed (%d)\n", + dv->dv_xname, error); + continue; + } + + csum = adler32(0, bp->b_data, bios_cksumlen * DEV_BSIZE); +#ifdef DEBUG + printf("dkcsum: checksum of %s is %x\n", dv->dv_xname, csum); +#endif + + /* Find the BIOS device */ + hit = 0; + for (bdi = bios_diskinfo; bdi->bios_number != -1; bdi++) { + /* Skip non-harddrives */ + if (!(bdi->bios_number & 0x80)) + continue; +#ifdef DEBUG + printf( + "dkcsum: attempting to match with BIOS drive %x csum %x\n", + bdi->bios_number, bdi->checksum); +#endif + if (bdi->checksum == csum) + if (!hit && !(bdi->flags & BDI_PICKED)) + hit = bdi; + else { + /* XXX add other heuristics here. */ + printf("dkcsum: warning: " + "dup BSD->BIOS disk mapping\n"); + } + } + + /* + * If we have no hit, that's OK, we can see a lot more devices + * than the BIOS can, so this case is pretty normal. + */ + if (hit) { +#ifdef DIAGNOSTIC + printf("dkcsum: %s matched BIOS disk %x\n", + dv->dv_xname, hit->bios_number); +#endif + } else { +#ifdef DIAGNOSTIC + printf("dkcsum: %s had no matching BIOS disk\n", + dv->dv_xname); +#endif + continue; + } + + /* This will overwrite /boot's guess, just so you remember */ + hit->bsd_dev = MAKEBOOTDEV(major(bp->b_dev), 0, 0, + DISKUNIT(bp->b_dev), 0); /* XXX RAW_PART later? */ + hit->flags |= BDI_PICKED; + } + brelse(bp); +} |