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,
+ * ra...@ludd.luth.se
+ *
+ * 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 */

Reply via email to