summaryrefslogtreecommitdiff
path: root/sys/arch/armish/stand/boot/wd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/armish/stand/boot/wd.c')
-rw-r--r--sys/arch/armish/stand/boot/wd.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/sys/arch/armish/stand/boot/wd.c b/sys/arch/armish/stand/boot/wd.c
new file mode 100644
index 00000000000..f907d271e1a
--- /dev/null
+++ b/sys/arch/armish/stand/boot/wd.c
@@ -0,0 +1,279 @@
+/* $OpenBSD: wd.c,v 1.1 2006/07/28 17:12:06 kettenis Exp $ */
+/* $NetBSD: wd.c,v 1.5 2005/12/11 12:17:06 christos Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+
+#include <lib/libsa/stand.h>
+#include <machine/param.h>
+
+#include "boot.h"
+#include "wdvar.h"
+
+static int wd_get_params(struct wd_softc *wd);
+static int wdgetdisklabel(struct wd_softc *wd);
+static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp);
+
+/*
+ * Get drive parameters through 'device identify' command.
+ */
+int
+wd_get_params(wd)
+ struct wd_softc *wd;
+{
+ int error;
+ unsigned char buf[DEV_BSIZE];
+
+ if ((error = wdc_exec_identify(wd, buf)) != 0)
+ return (error);
+
+ wd->sc_params = *(struct ataparams *)buf;
+
+ /* 48-bit LBA addressing */
+ if ((wd->sc_params.atap_cmd2_en & ATAPI_CMD2_48AD) != 0) {
+ DPRINTF(("Drive supports LBA48.\n"));
+#if defined(_ENABLE_LBA48)
+ wd->sc_flags |= WDF_LBA48;
+#endif
+ }
+
+ /* Prior to ATA-4, LBA was optional. */
+ if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) {
+ DPRINTF(("Drive supports LBA.\n"));
+ wd->sc_flags |= WDF_LBA;
+ }
+
+ return (0);
+}
+
+/*
+ * Initialize disk label to the default value.
+ */
+void
+wdgetdefaultlabel(wd, lp)
+ struct wd_softc *wd;
+ struct disklabel *lp;
+{
+ memset(lp, 0, sizeof(struct disklabel));
+
+ lp->d_secsize = DEV_BSIZE;
+ lp->d_ntracks = wd->sc_params.atap_heads;
+ lp->d_nsectors = wd->sc_params.atap_sectors;
+ lp->d_ncylinders = wd->sc_params.atap_cylinders;
+ lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
+
+ if (strcmp(wd->sc_params.atap_model, "ST506") == 0)
+ lp->d_type = DTYPE_ST506;
+ else
+ lp->d_type = DTYPE_ESDI;
+
+ strncpy(lp->d_typename, wd->sc_params.atap_model, 16);
+ strncpy(lp->d_packname, "fictitious", 16);
+ if (wd->sc_capacity > UINT32_MAX)
+ lp->d_secperunit = UINT32_MAX;
+ else
+ lp->d_secperunit = wd->sc_capacity;
+ lp->d_rpm = 3600;
+ lp->d_interleave = 1;
+ lp->d_flags = 0;
+
+ lp->d_partitions[RAW_PART].p_offset = 0;
+ lp->d_partitions[RAW_PART].p_size =
+ lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
+ lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
+ lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */
+
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = dkcksum(lp);
+}
+
+/*
+ * Read disk label from the device.
+ */
+int
+wdgetdisklabel(wd)
+ struct wd_softc *wd;
+{
+ char *msg;
+ int sector;
+ size_t rsize;
+ struct disklabel *lp;
+ unsigned char buf[DEV_BSIZE];
+
+ wdgetdefaultlabel(wd, &wd->sc_label);
+
+ /*
+ * Find OpenBSD Partition in DOS partition table.
+ */
+ sector = 0;
+ if (wdstrategy(wd, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize))
+ return EOFFSET;
+
+ if (*(u_int16_t *)&buf[DOSMAGICOFF] == DOSMAGIC) {
+ int i;
+ struct dos_partition *dp = (struct dos_partition *)buf;
+
+ /*
+ * Lookup OpenBSD slice. If there is none, go ahead
+ * and try to read the disklabel off sector #0.
+ */
+
+ memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp));
+ for (i = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_typ == DOSPTYP_OPENBSD) {
+ sector = letoh32(dp[i].dp_start);
+ break;
+ }
+ }
+ }
+
+ if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE,
+ buf, &rsize))
+ return EOFFSET;
+
+ if ((msg = getdisklabel(buf + LABELOFFSET, &wd->sc_label)))
+ printf("wd%d: getdisklabel: %s\n", wd->sc_unit, msg);
+
+ lp = &wd->sc_label;
+
+ /* check partition */
+ if ((wd->sc_part >= lp->d_npartitions) ||
+ (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) {
+ DPRINTF(("illegal partition\n"));
+ return (EPART);
+ }
+
+ DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d,"
+ "d_ntracks %d, d_secpercyl %d\n",
+ wd->sc_label.d_secsize,
+ wd->sc_label.d_nsectors,
+ wd->sc_label.d_ncylinders,
+ wd->sc_label.d_ntracks,
+ wd->sc_label.d_secpercyl));
+
+ return (0);
+}
+
+/*
+ * Open device (read drive parameters and disklabel)
+ */
+int
+wdopen(struct open_file *f, ...)
+{
+ int error;
+ va_list ap;
+ u_int unit, part;
+ struct wd_softc *wd;
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ DPRINTF(("wdopen: %d:%d\n", unit, part));
+
+ wd = alloc(sizeof(struct wd_softc));
+ if (wd == NULL)
+ return ENOMEM;
+
+ memset(wd, 0, sizeof(struct wd_softc));
+
+ if (wdc_init(wd, &unit) != 0)
+ return (ENXIO);
+
+ wd->sc_part = part;
+ wd->sc_unit = unit;
+
+ if ( (error = wd_get_params(wd)) != 0)
+ return (error);
+
+ if ( (error = wdgetdisklabel(wd)) != 0)
+ return error;
+
+ f->f_devdata = wd;
+ return (0);
+}
+
+/*
+ * Close device.
+ */
+int
+wdclose(struct open_file *f)
+{
+ return 0;
+}
+
+/*
+ * Read some data.
+ */
+int
+wdstrategy(f, rw, dblk, size, buf, rsize)
+ void *f;
+ int rw;
+ daddr_t dblk;
+ size_t size;
+ void *buf;
+ size_t *rsize;
+{
+ int i, nsect;
+ daddr_t blkno;
+ struct wd_softc *wd = f;
+
+ if (size == 0)
+ return (0);
+
+ if (rw != F_READ)
+ return EOPNOTSUPP;
+
+ nsect = howmany(size, wd->sc_label.d_secsize);
+ blkno = dblk + wd->sc_label.d_partitions[wd->sc_part].p_offset;
+
+ for (i = 0; i < nsect; i++, blkno++) {
+ int error;
+
+ if ( (error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0)
+ return (error);
+
+ buf += wd->sc_label.d_secsize;
+ }
+
+ *rsize = size;
+ return (0);
+}