Module Name: src
Committed By: kiyohara
Date: Thu Oct 14 06:50:44 UTC 2010
Modified Files:
src/sys/arch/bebox/stand/boot: Makefile boot.c conf.c filesystem.c
version
Added Files:
src/sys/arch/bebox/stand/boot: wd.c wdc.c wdvar.h
Log Message:
Support kernel load from IDE HDD with onboard wdc. like cobalt, sandpoint.
To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/bebox/stand/boot/Makefile
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/bebox/stand/boot/boot.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/bebox/stand/boot/conf.c \
src/sys/arch/bebox/stand/boot/filesystem.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/bebox/stand/boot/version
cvs rdiff -u -r0 -r1.1 src/sys/arch/bebox/stand/boot/wd.c \
src/sys/arch/bebox/stand/boot/wdc.c src/sys/arch/bebox/stand/boot/wdvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/bebox/stand/boot/Makefile
diff -u src/sys/arch/bebox/stand/boot/Makefile:1.27 src/sys/arch/bebox/stand/boot/Makefile:1.28
--- src/sys/arch/bebox/stand/boot/Makefile:1.27 Thu Oct 14 06:17:29 2010
+++ src/sys/arch/bebox/stand/boot/Makefile Thu Oct 14 06:50:43 2010
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.27 2010/10/14 06:17:29 kiyohara Exp $
+# $NetBSD: Makefile,v 1.28 2010/10/14 06:50:43 kiyohara Exp $
NOMAN= # defined
@@ -23,7 +23,7 @@
SRCS= srt0.s
SRCS+= boot.c clock.c com.c conf.c cons.c cpu.c devopen.c
SRCS+= fd.c filesystem.c inkernel.c io.c kbd.c monitor.c ns16550.c
-SRCS+= pci.c prf.c tgets.c vers.c vga.c video.c vreset.c
+SRCS+= pci.c prf.c tgets.c vers.c vga.c video.c vreset.c wdc.c wd.c
SRCS+= setjmp.S
CFLAGS= -Wno-main -ffreestanding
Index: src/sys/arch/bebox/stand/boot/boot.c
diff -u src/sys/arch/bebox/stand/boot/boot.c:1.21 src/sys/arch/bebox/stand/boot/boot.c:1.22
--- src/sys/arch/bebox/stand/boot/boot.c:1.21 Thu Oct 14 06:39:52 2010
+++ src/sys/arch/bebox/stand/boot/boot.c Thu Oct 14 06:50:44 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: boot.c,v 1.21 2010/10/14 06:39:52 kiyohara Exp $ */
+/* $NetBSD: boot.c,v 1.22 2010/10/14 06:50:44 kiyohara Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -40,9 +40,12 @@
#include <machine/cpu.h>
#include "boot.h"
+#include "wdvar.h"
char *names[] = {
+ "/dev/disk/ide/0/master/0_0:/netbsd",
"/dev/disk/floppy:netbsd", "/dev/disk/floppy:netbsd.gz",
+ "/dev/disk/ide/0/master/0_0:/onetbsd",
"/dev/disk/floppy:onetbsd", "/dev/disk/floppy:onetbsd.gz"
"in",
};
@@ -115,11 +118,6 @@
p += sizeof (btinfo_console);
memcpy(p, (void *)&btinfo_clock, sizeof (btinfo_clock));
- /*
- * attached kernel check
- */
- init_in();
-
runCPU1((void *)start_CPU1);
wait_for(&CPU1_alive);
@@ -127,6 +125,16 @@
printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
printf(">> Memory: %d k\n", btinfo_memory.memsize / 1024);
+ /*
+ * attached kernel check and copy.
+ */
+ init_in();
+
+ printf("\n");
+
+ /* Initialize w...@isa port 0x1f0 */
+ wdc_init(0x1f0);
+
for (;;) {
name = names[n++];
if (n >= NUMNAMES)
Index: src/sys/arch/bebox/stand/boot/conf.c
diff -u src/sys/arch/bebox/stand/boot/conf.c:1.7 src/sys/arch/bebox/stand/boot/conf.c:1.8
--- src/sys/arch/bebox/stand/boot/conf.c:1.7 Thu Oct 14 06:39:52 2010
+++ src/sys/arch/bebox/stand/boot/conf.c Thu Oct 14 06:50:44 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.7 2010/10/14 06:39:52 kiyohara Exp $ */
+/* $NetBSD: conf.c,v 1.8 2010/10/14 06:50:44 kiyohara Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@@ -42,8 +42,13 @@
extern int inopen(struct open_file *, ...);
extern int inclose(struct open_file *);
+extern int wdstrategy(void *, int, daddr_t, size_t, void *, size_t *);
+extern int wdopen(struct open_file *, ...);
+extern int wdclose(struct open_file *);
+
struct devsw devsw[] = {
{ "fd", fdstrategy, fdopen, fdclose, noioctl },
+ { "wd", wdstrategy, wdopen, wdclose, noioctl },
{ NULL, NULL, NULL, NULL, NULL },
};
Index: src/sys/arch/bebox/stand/boot/filesystem.c
diff -u src/sys/arch/bebox/stand/boot/filesystem.c:1.7 src/sys/arch/bebox/stand/boot/filesystem.c:1.8
--- src/sys/arch/bebox/stand/boot/filesystem.c:1.7 Mon May 26 16:28:39 2008
+++ src/sys/arch/bebox/stand/boot/filesystem.c Thu Oct 14 06:50:44 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: filesystem.c,v 1.7 2008/05/26 16:28:39 kiyohara Exp $ */
+/* $NetBSD: filesystem.c,v 1.8 2010/10/14 06:50:44 kiyohara Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -30,8 +30,11 @@
*/
#include <lib/libsa/stand.h>
+#include <ufs.h>
struct fs_ops file_system[] = {
+ FS_OPS(ffsv1),
+ FS_OPS(ffsv2),
FS_OPS(null),
};
Index: src/sys/arch/bebox/stand/boot/version
diff -u src/sys/arch/bebox/stand/boot/version:1.8 src/sys/arch/bebox/stand/boot/version:1.9
--- src/sys/arch/bebox/stand/boot/version:1.8 Thu Oct 14 06:23:27 2010
+++ src/sys/arch/bebox/stand/boot/version Thu Oct 14 06:50:44 2010
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.8 2010/10/14 06:23:27 kiyohara Exp $
+$NetBSD: version,v 1.9 2010/10/14 06:50:44 kiyohara Exp $
1.1: Boot program for BeBox; initial revision
1.2: check BUS FREQ, add clock information
@@ -8,3 +8,4 @@
Headers.
1.6: Support framebuffer and vga.
Split boot{,_com0,_vga}.
+1.7: Support kernel load from IDE HDD with onboard wdc.
Added files:
Index: src/sys/arch/bebox/stand/boot/wd.c
diff -u /dev/null src/sys/arch/bebox/stand/boot/wd.c:1.1
--- /dev/null Thu Oct 14 06:50:44 2010
+++ src/sys/arch/bebox/stand/boot/wd.c Thu Oct 14 06:50:43 2010
@@ -0,0 +1,320 @@
+/* $NetBSD: wd.c,v 1.1 2010/10/14 06:50:43 kiyohara 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.
+ *
+ * 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/param.h>
+#include <sys/types.h>
+#include <sys/stdint.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libkern/libkern.h>
+
+#include <machine/param.h>
+#include <machine/stdarg.h>
+#include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */
+
+#include "boot.h"
+#include "wdvar.h"
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+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);
+
+int wdopen(struct open_file *, ...);
+int wdclose(struct open_file *);
+int wdstrategy(void *, int, daddr_t, size_t, void *, size_t *);
+
+/*
+ * Get drive parameters through 'device identify' command.
+ */
+int
+wd_get_params(struct wd_softc *wd)
+{
+ int error;
+ uint8_t 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 & ATA_CMD2_LBA48) != 0)
+ wd->sc_flags |= WDF_LBA48;
+
+ /* Prior to ATA-4, LBA was optional. */
+ if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0)
+ wd->sc_flags |= WDF_LBA;
+
+ if ((wd->sc_flags & WDF_LBA48) != 0) {
+ DPRINTF(("Drive supports LBA48.\n"));
+ wd->sc_capacity =
+ ((uint64_t)wd->sc_params.atap_max_lba[3] << 48) |
+ ((uint64_t)wd->sc_params.atap_max_lba[2] << 32) |
+ ((uint64_t)wd->sc_params.atap_max_lba[1] << 16) |
+ ((uint64_t)wd->sc_params.atap_max_lba[0] << 0);
+ DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n",
+ wd->sc_params.atap_max_lba[3],
+ wd->sc_params.atap_max_lba[2],
+ wd->sc_params.atap_max_lba[1],
+ wd->sc_params.atap_max_lba[0]));
+ wd->sc_capacity28 =
+ ((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
+ ((uint32_t)wd->sc_params.atap_capacity[0] << 0);
+ DPRINTF(("atap_capacity = (0x%x, 0x%x)\n",
+ wd->sc_params.atap_capacity[1],
+ wd->sc_params.atap_capacity[0]));
+ } else if ((wd->sc_flags & WDF_LBA) != 0) {
+ DPRINTF(("Drive supports LBA.\n"));
+ wd->sc_capacity =
+ ((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
+ ((uint32_t)wd->sc_params.atap_capacity[0] << 0);
+ wd->sc_capacity28 =
+ ((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
+ ((uint32_t)wd->sc_params.atap_capacity[0] << 0);
+ } else {
+ DPRINTF(("Drive doesn't support LBA; using CHS.\n"));
+ wd->sc_capacity = wd->sc_capacity28 =
+ wd->sc_params.atap_cylinders *
+ wd->sc_params.atap_heads *
+ wd->sc_params.atap_sectors;
+ }
+ DPRINTF(("wd->sc_capacity = %" PRId64 ", wd->sc_capacity28 = %d.\n",
+ wd->sc_capacity, wd->sc_capacity28));
+
+ return 0;
+}
+
+/*
+ * Initialize disk label to the default value.
+ */
+void
+wdgetdefaultlabel(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((const char *)wd->sc_params.atap_model, "ST506") == 0)
+ lp->d_type = DTYPE_ST506;
+ else
+ lp->d_type = DTYPE_ESDI;
+
+ strncpy(lp->d_typename, (const char *)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(struct wd_softc *wd)
+{
+ struct mbr_sector *mbr;
+ struct mbr_partition *mp;
+ struct disklabel *lp;
+ size_t rsize;
+ int sector, i;
+ char *msg;
+ uint8_t buf[DEV_BSIZE];
+
+ wdgetdefaultlabel(wd, &wd->sc_label);
+
+ /*
+ * Find NetBSD Partition in DOS partition table.
+ */
+ sector = 0;
+ if (wdstrategy(wd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf, &rsize))
+ return EOFFSET;
+
+ mbr = (struct mbr_sector *)buf;
+ if (mbr->mbr_magic == htole16(MBR_MAGIC)) {
+ /*
+ * Lookup NetBSD slice. If there is none, go ahead
+ * and try to read the disklabel off sector #0.
+ */
+ mp = mbr->mbr_parts;
+ for (i = 0; i < MBR_PART_COUNT; i++) {
+ if (mp[i].mbrp_type == MBR_PTYPE_NETBSD) {
+ sector = le32toh(mp[i].mbrp_start);
+ break;
+ }
+ }
+ }
+
+ if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE,
+ buf, &rsize))
+ return EOFFSET;
+
+ msg = getdisklabel((const char *)buf + LABELOFFSET, &wd->sc_label);
+ if (msg)
+ printf("ide/0/%s/0: getdisklabel: %s\n",
+ (wd->sc_unit == 0) ? "master" : "slave", 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 ctlr, unit, lunit, part;
+ struct wd_softc *wd;
+
+ va_start(ap, f);
+ ctlr = va_arg(ap, u_int);
+ unit = va_arg(ap, u_int);
+ lunit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ DPRINTF(("wdopen: ide/%d/%s/%d_%d\n",
+ ctlr, (unit == 0) ? "master" : "slave", lunit, part));
+ if (lunit != 0)
+ return ENOENT;
+
+ wd = alloc(sizeof(struct wd_softc));
+ if (wd == NULL)
+ return ENOMEM;
+
+ memset(wd, 0, sizeof(struct wd_softc));
+
+ wd->sc_part = part;
+ wd->sc_unit = unit;
+ wd->sc_ctlr = ctlr;
+
+ 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(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize)
+{
+ int i, nsect;
+ daddr_t blkno;
+ struct wd_softc *wd;
+ struct partition *pp;
+ uint8_t *buf;
+
+ if (size == 0)
+ return 0;
+
+ if (rw != F_READ)
+ return EOPNOTSUPP;
+
+ buf = p;
+ wd = f;
+ pp = &wd->sc_label.d_partitions[wd->sc_part];
+
+ nsect = howmany(size, wd->sc_label.d_secsize);
+ blkno = dblk + pp->p_offset;
+ if (pp->p_fstype == FS_RAID)
+ blkno += RF_PROTECTED_SECTORS;
+
+ 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;
+}
Index: src/sys/arch/bebox/stand/boot/wdc.c
diff -u /dev/null src/sys/arch/bebox/stand/boot/wdc.c:1.1
--- /dev/null Thu Oct 14 06:50:44 2010
+++ src/sys/arch/bebox/stand/boot/wdc.c Thu Oct 14 06:50:43 2010
@@ -0,0 +1,479 @@
+/* $NetBSD: wdc.c,v 1.1 2010/10/14 06:50:43 kiyohara 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.
+ *
+ * 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/disklabel.h>
+#include <sys/bootblock.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libkern/libkern.h>
+#include <machine/param.h>
+
+#include "boot.h"
+#include "wdvar.h"
+
+#define WDCDELAY 100
+#define WDCNDELAY_RST 31000 * 10
+
+static int __wdcwait_reset(struct wdc_channel *, int);
+static char *mkident(uint8_t *, int);
+static int wdcprobe(struct wdc_channel *);
+static int wdc_wait_for_ready(struct wdc_channel *);
+static int wdc_read_block(struct wdc_channel *, struct wdc_command *);
+static int wdccommand(struct wdc_channel *, struct wdc_command *);
+static int wdccommandext(struct wdc_channel *, struct wdc_command *);
+static int _wdc_exec_identify(struct wdc_channel *, int, void *);
+
+static struct wdc_channel ch;
+
+/*
+ * Reset the controller.
+ */
+static int
+__wdcwait_reset(struct wdc_channel *chp, int drv_mask)
+{
+ int timeout;
+ uint8_t st0, st1;
+
+ /* wait for BSY to deassert */
+ for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) {
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM); /* master */
+ delay(10);
+ st0 = WDC_READ_REG(chp, wd_status);
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10); /* slave */
+ delay(10);
+ st1 = WDC_READ_REG(chp, wd_status);
+
+ if ((drv_mask & 0x01) == 0) {
+ /* no master */
+ if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) {
+ /* No master, slave is ready, it's done */
+ goto end;
+ }
+ } else if ((drv_mask & 0x02) == 0) {
+ /* no slave */
+ if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) {
+ /* No slave, master is ready, it's done */
+ goto end;
+ }
+ } else {
+ /* Wait for both master and slave to be ready */
+ if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) {
+ goto end;
+ }
+ }
+
+ delay(WDCDELAY);
+ }
+
+ /* Reset timed out. Maybe it's because drv_mask was not right */
+ if (st0 & WDCS_BSY)
+ drv_mask &= ~0x01;
+ if (st1 & WDCS_BSY)
+ drv_mask &= ~0x02;
+
+ end:
+ return drv_mask;
+}
+
+static char *
+mkident(uint8_t *src, int len)
+{
+ static char local[40];
+ uint8_t *end;
+ char *dst, *last;
+
+ if (len > sizeof(local))
+ len = sizeof(local);
+ dst = last = local;
+ end = src + len - 1;
+
+ /* reserve space for '\0' */
+ if (len < 2)
+ goto out;
+ /* skip leading white space */
+ while (*src != '\0' && src < end && *src == ' ')
+ ++src;
+ /* copy string, omitting trailing white space */
+ while (*src != '\0' && src < end) {
+ *dst++ = *src;
+ if (*src++ != ' ')
+ last = dst;
+ }
+ out:
+ *last = '\0';
+ return local;
+}
+
+/* Test to see controller with at last one attached drive is there.
+ * Returns a bit for each possible drive found (0x01 for drive 0,
+ * 0x02 for drive 1).
+ * Logic:
+ * - If a status register is at 0xff, assume there is no drive here
+ * (ISA has pull-up resistors). Similarly if the status register has
+ * the value we last wrote to the bus (for IDE interfaces without pullups).
+ * If no drive at all -> return.
+ * - reset the controller, wait for it to complete (may take up to 31s !).
+ * If timeout -> return.
+ */
+static int
+wdcprobe(struct wdc_channel *chp)
+{
+ uint8_t st0, st1;
+ uint8_t drives = 0x03;
+ uint8_t drive, cl, ch;
+ uint8_t ident[DEV_BSIZE];
+
+ /*
+ * Sanity check to see if the wdc channel responds at all.
+ */
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
+ delay(10);
+ st0 = WDC_READ_REG(chp, wd_status);
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | 0x10);
+ delay(10);
+ st1 = WDC_READ_REG(chp, wd_status);
+
+ if (st0 == 0xff || st0 == WDSD_IBM)
+ drives &= ~0x01;
+ if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
+ drives &= ~0x02;
+ if (drives == 0)
+ return 0;
+
+ if (!(st0 & WDCS_DRDY))
+ drives &= ~0x01;
+ if (!(st1 & WDCS_DRDY))
+ drives &= ~0x02;
+ if (drives == 0)
+ return 0;
+
+ /* assert SRST, wait for reset to complete */
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM);
+ delay(10);
+ WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_RST | WDCTL_IDS);
+ delay(1000);
+ WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_IDS);
+ delay(1000);
+ (void) WDC_READ_REG(chp, wd_error);
+ WDC_WRITE_CTLREG(chp, wd_aux_ctlr, WDCTL_4BIT);
+ delay(10);
+
+ drives = __wdcwait_reset(chp, drives);
+
+ /* if reset failed, there's nothing here */
+ if (drives == 0)
+ return 0;
+
+ /*
+ * Test presence of drives. First test register signatures looking for
+ * ATAPI devices. If it's not an ATAPI and reset said there may be
+ * something here assume it's ATA or OLD. Ghost will be killed later in
+ * attach routine.
+ */
+ for (drive = 0; drive < 2; drive++) {
+ if ((drives & (1 << drive)) == 0)
+ continue;
+
+ /*
+ * ATAPI device not support...
+ */
+ WDC_WRITE_REG(chp, wd_sdh, WDSD_IBM | (drive << 4));
+ cl = WDC_READ_REG(chp, wd_cyl_lo);
+ ch = WDC_READ_REG(chp, wd_cyl_hi);
+ if (cl == 0x14 && ch == 0xeb) {
+ drives &= ~(1 << drive);
+ continue;
+ }
+
+ if (_wdc_exec_identify(chp, drive, ident) == 0) {
+ struct ataparams *prms = (struct ataparams *)ident;
+ char *model;
+
+ model =
+ mkident(prms->atap_model, sizeof(prms->atap_model));
+ printf("/dev/disk/ide/0/%s/0: <%s>\n",
+ (drive == 0) ? "master" : "slave", model);
+ } else
+ printf("/dev/disk/ide/0/%s/0: identify failed\n",
+ (drive == 0) ? "master" : "slave");
+ }
+ return drives;
+}
+
+/*
+ * Wait until the device is ready.
+ */
+int
+wdc_wait_for_ready(struct wdc_channel *chp)
+{
+ u_int timeout;
+
+ for (timeout = WDC_TIMEOUT; timeout > 0; --timeout) {
+ if ((WDC_READ_REG(chp, wd_status) & (WDCS_BSY | WDCS_DRDY))
+ == WDCS_DRDY)
+ return 0;
+ }
+ return ENXIO;
+}
+
+/*
+ * Read one block off the device.
+ */
+int
+wdc_read_block(struct wdc_channel *chp, struct wdc_command *wd_c)
+{
+ int i;
+ uint16_t *ptr = (uint16_t *)wd_c->data;
+
+ if (ptr == NULL)
+ return EIO;
+
+ if (wd_c->r_command == WDCC_IDENTIFY)
+ for (i = wd_c->bcount; i > 0; i -= sizeof(uint16_t))
+ *ptr++ = WDC_READ_DATA(chp);
+ else
+ for (i = wd_c->bcount; i > 0; i -= sizeof(uint16_t))
+ *ptr++ = WDC_READ_DATA_STREAM(chp);
+
+ return 0;
+}
+
+/*
+ * Send a command to the device (CHS and LBA addressing).
+ */
+int
+wdccommand(struct wdc_channel *chp, struct wdc_command *wd_c)
+{
+
+#if 0
+ DPRINTF(("wdccommand(%d, %d, %d, %d, %d, %d)\n",
+ wd_c->drive, wd_c->r_command, wd_c->r_cyl,
+ wd_c->r_head, wd_c->r_sector, wd_c->bcount));
+#endif
+
+ WDC_WRITE_REG(chp, wd_features, wd_c->r_features);
+ WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
+ WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector);
+ WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl);
+ WDC_WRITE_REG(chp, wd_cyl_hi, wd_c->r_cyl >> 8);
+ WDC_WRITE_REG(chp, wd_sdh,
+ WDSD_IBM | (wd_c->drive << 4) | wd_c->r_head);
+ WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
+
+ if (wdc_wait_for_ready(chp) != 0)
+ return ENXIO;
+
+ if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
+ printf("/dev/disk/ide/0/%s/0: error %x\n",
+ (wd_c->drive == 0) ? "master" : "slave",
+ WDC_READ_REG(chp, wd_error));
+ return ENXIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Send a command to the device (LBA48 addressing).
+ */
+int
+wdccommandext(struct wdc_channel *chp, struct wdc_command *wd_c)
+{
+
+#if 0
+ DPRINTF(("%s(%d, %x, %" PRId64 ", %d)\n", __func__,
+ wd_c->drive, wd_c->r_command,
+ wd_c->r_blkno, wd_c->r_count));
+#endif
+
+ /* Select drive, head, and addressing mode. */
+ WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA);
+
+ /* previous */
+ WDC_WRITE_REG(chp, wd_features, 0);
+ WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count >> 8);
+ WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 40);
+ WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 32);
+ WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno >> 24);
+
+ /* current */
+ WDC_WRITE_REG(chp, wd_features, 0);
+ WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
+ WDC_WRITE_REG(chp, wd_lba_hi, wd_c->r_blkno >> 16);
+ WDC_WRITE_REG(chp, wd_lba_mi, wd_c->r_blkno >> 8);
+ WDC_WRITE_REG(chp, wd_lba_lo, wd_c->r_blkno);
+
+ /* Send command. */
+ WDC_WRITE_REG(chp, wd_command, wd_c->r_command);
+
+ if (wdc_wait_for_ready(chp) != 0)
+ return ENXIO;
+
+ if (WDC_READ_REG(chp, wd_status) & WDCS_ERR) {
+ printf("/dev/disk/ide/0/%s/0: error %x\n",
+ (wd_c->drive == 0) ? "master" : "slave",
+ WDC_READ_REG(chp, wd_error));
+ return ENXIO;
+ }
+
+ return 0;
+}
+
+static int
+_wdc_exec_identify(struct wdc_channel *chp, int drive, void *data)
+{
+ struct wdc_command wd_c;
+ int error;
+
+ memset(&wd_c, 0, sizeof(wd_c));
+
+ wd_c.drive = drive;
+ wd_c.r_command = WDCC_IDENTIFY;
+ wd_c.bcount = DEV_BSIZE;
+ wd_c.data = data;
+
+ if ((error = wdccommand(chp, &wd_c)) != 0)
+ return error;
+
+ return wdc_read_block(chp, &wd_c);
+}
+
+/*
+ * Initialize the device.
+ */
+int
+wdc_init(int addr)
+{
+ struct wdc_channel tmp;
+ int i;
+
+ memset(&ch, 0, sizeof(ch));
+
+ /* set up cmd/ctl regsiters */
+ tmp.c_cmdbase = addr;
+#define WDC_ISA_AUXREG_OFFSET 0x206
+ tmp.c_ctlbase = addr + WDC_ISA_AUXREG_OFFSET;
+ tmp.c_data = addr + wd_data;
+ for (i = 0; i < WDC_NPORTS; i++)
+ tmp.c_cmdreg[i] = tmp.c_cmdbase + i;
+ /* set up shadow registers */
+ tmp.c_cmdreg[wd_status] = tmp.c_cmdreg[wd_command];
+ tmp.c_cmdreg[wd_features] = tmp.c_cmdreg[wd_precomp];
+
+ if (wdcprobe(&tmp) == 0)
+ return ENXIO;
+ ch = tmp;
+ return 0;
+}
+
+/*
+ * Issue 'device identify' command.
+ */
+int
+wdc_exec_identify(struct wd_softc *wd, void *data)
+{
+ struct wdc_channel *chp;
+
+ if (wd->sc_ctlr != 0)
+ return ENOTSUP;
+ if (ch.c_cmdbase == 0)
+ return ENOENT;
+ chp = &ch;
+
+ return _wdc_exec_identify(chp, wd->sc_unit, data);
+}
+
+/*
+ * Issue 'read' command.
+ */
+int
+wdc_exec_read(struct wd_softc *wd, uint8_t cmd, daddr_t blkno, void *data)
+{
+ struct wdc_command wd_c;
+ struct wdc_channel *chp;
+ int error;
+ bool lba, lba48;
+
+ if (wd->sc_ctlr != 0)
+ return ENOTSUP;
+ if (ch.c_cmdbase == 0)
+ return ENOENT;
+ chp = &ch;
+
+ memset(&wd_c, 0, sizeof(wd_c));
+ lba = false;
+ lba48 = false;
+
+ wd_c.data = data;
+ wd_c.r_count = 1;
+ wd_c.r_features = 0;
+ wd_c.drive = wd->sc_unit;
+ wd_c.bcount = wd->sc_label.d_secsize;
+
+ if ((wd->sc_flags & WDF_LBA48) != 0 && blkno > wd->sc_capacity28)
+ lba48 = true;
+ else if ((wd->sc_flags & WDF_LBA) != 0)
+ lba = true;
+
+ if (lba48) {
+ /* LBA48 */
+ wd_c.r_command = atacmd_to48(cmd);
+ wd_c.r_blkno = blkno;
+ } else if (lba) {
+ /* LBA */
+ wd_c.r_command = cmd;
+ wd_c.r_sector = (blkno >> 0) & 0xff;
+ wd_c.r_cyl = (blkno >> 8) & 0xffff;
+ wd_c.r_head = (blkno >> 24) & 0x0f;
+ wd_c.r_head |= WDSD_LBA;
+ } else {
+ /* CHS */
+ wd_c.r_command = cmd;
+ wd_c.r_sector = blkno % wd->sc_label.d_nsectors;
+ wd_c.r_sector++; /* Sectors begin with 1, not 0. */
+ blkno /= wd->sc_label.d_nsectors;
+ wd_c.r_head = blkno % wd->sc_label.d_ntracks;
+ blkno /= wd->sc_label.d_ntracks;
+ wd_c.r_cyl = blkno;
+ wd_c.r_head |= WDSD_CHS;
+ }
+
+ if (lba48)
+ error = wdccommandext(chp, &wd_c);
+ else
+ error = wdccommand(chp, &wd_c);
+
+ if (error != 0)
+ return error;
+
+ return wdc_read_block(chp, &wd_c);
+}
Index: src/sys/arch/bebox/stand/boot/wdvar.h
diff -u /dev/null src/sys/arch/bebox/stand/boot/wdvar.h:1.1
--- /dev/null Thu Oct 14 06:50:44 2010
+++ src/sys/arch/bebox/stand/boot/wdvar.h Thu Oct 14 06:50:43 2010
@@ -0,0 +1,96 @@
+/* $NetBSD: wdvar.h,v 1.1 2010/10/14 06:50:43 kiyohara Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001 Dynarc AB, Sweden. All rights reserved.
+ *
+ * This code is derived from software written by Anders Magnusson,
+ * [email protected]
+ *
+ * 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. 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.
+ */
+
+#ifndef _STAND_WDVAR_H
+#define _STAND_WDVAR_H
+
+#include <dev/ic/wdcreg.h>
+#include <dev/ata/atareg.h>
+
+#include <sys/disklabel.h>
+#include <sys/bootblock.h>
+
+#define WDC_TIMEOUT 2000000
+#define WDC_NPORTS 8 /* XXX */
+#define WDC_NSHADOWREG 2 /* XXX */
+
+struct wdc_channel {
+ int c_cmdbase;
+ int c_ctlbase;
+ int c_data;
+ int c_cmdreg[WDC_NPORTS + WDC_NSHADOWREG];
+};
+
+#define WDC_READ_REG(chp, reg) inb((chp)->c_cmdreg[(reg)])
+#define WDC_WRITE_REG(chp, reg, val) outb((chp)->c_cmdreg[(reg)], (val))
+#define WDC_READ_CTLREG(chp, reg) inb((chp)->c_ctlbase)
+#define WDC_WRITE_CTLREG(chp, reg, val) outb((chp)->c_ctlbase, (val))
+#define WDC_READ_DATA_STREAM(chp) inw((chp)->c_data)
+#define WDC_READ_DATA(chp) inwrb((chp)->c_data)
+
+struct wd_softc {
+#define WDF_LBA 0x0001
+#define WDF_LBA48 0x0002
+ uint16_t sc_flags;
+
+ u_int sc_part;
+ u_int sc_unit;
+ u_int sc_ctlr;
+
+ uint64_t sc_capacity;
+ uint32_t sc_capacity28;
+
+ struct ataparams sc_params;
+ struct disklabel sc_label;
+};
+
+struct wdc_command {
+ uint8_t drive; /* drive id */
+
+ uint8_t r_command; /* Parameters to upload to registers */
+ uint8_t r_head;
+ uint16_t r_cyl;
+ uint8_t r_sector;
+ uint8_t r_count;
+ uint8_t r_features;
+
+ uint16_t bcount;
+ void *data;
+
+ uint64_t r_blkno;
+};
+
+int wdc_init(int);
+int wdc_exec_identify(struct wd_softc *, void *);
+int wdc_exec_read(struct wd_softc *, uint8_t, daddr_t, void *);
+
+#endif /* _STAND_WDVAR_H */