summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1997-10-27 08:06:32 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1997-10-27 08:06:32 +0000
commitb5464f47493b2abb003205f76e8776597eeb176a (patch)
tree89c336c5467d45d7dd6d516d87f501eafdf30eeb
parent65620acc2871184197dc498b893432ffb3749cbe (diff)
Kernel side of disk signature based BIOS->BSD disk number mapping
(a.k.a checksumming). This is a solution for the otherwise hard problem of knowing what disk a certain BIOS geometry is for. PC BIOSes does not tell anything about where a certain disk is physically attached, and the ordering of drives in the BIOS area is not deterministic. for the moment it is not enabled in any kernel config file, but that will come RSN.
-rw-r--r--sys/arch/i386/conf/files.i3865
-rw-r--r--sys/arch/i386/i386/conf.c44
-rw-r--r--sys/arch/i386/i386/dkcsum.c173
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);
+}