summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>1998-08-20 08:27:11 +0000
committerdfr <dfr@FreeBSD.org>1998-08-20 08:27:11 +0000
commit0c47a30d50ae5d445fee4feb919e88eda179d382 (patch)
treecde46d8a51d81e31d13f1e73a54bb01155ebd499
parentf2844ad92f0c852e677d839b7a4c4a0ca78fca1b (diff)
downloadFreeBSD-src-0c47a30d50ae5d445fee4feb919e88eda179d382.zip
FreeBSD-src-0c47a30d50ae5d445fee4feb919e88eda179d382.tar.gz
Add support for TurboChannel alphas (DEC 3000/300 and 3000/500).
Obtained from: NetBSD Submitted by: Andrew Gallatin <gallatin@cs.duke.edu>
-rw-r--r--sys/alpha/alpha/autoconf.c17
-rw-r--r--sys/alpha/alpha/dec_3000_300.c82
-rw-r--r--sys/alpha/alpha/dec_3000_500.c102
-rw-r--r--sys/alpha/conf/GENERIC23
-rw-r--r--sys/alpha/conf/NOTES23
-rw-r--r--sys/alpha/conf/files.alpha15
-rw-r--r--sys/alpha/conf/options.alpha5
-rw-r--r--sys/alpha/tc/am7990.c1473
-rw-r--r--sys/alpha/tc/am7990reg.h216
-rw-r--r--sys/alpha/tc/am7990var.h208
-rw-r--r--sys/alpha/tc/ascvar.h92
-rw-r--r--sys/alpha/tc/esp.c1898
-rw-r--r--sys/alpha/tc/espreg.h149
-rw-r--r--sys/alpha/tc/espvar.h330
-rw-r--r--sys/alpha/tc/if_le_dec.c170
-rw-r--r--sys/alpha/tc/if_le_ioasic.c398
-rw-r--r--sys/alpha/tc/if_levar.h69
-rw-r--r--sys/alpha/tc/ioasic.c381
-rw-r--r--sys/alpha/tc/ioasicreg.h227
-rw-r--r--sys/alpha/tc/ioasicvar.h59
-rw-r--r--sys/alpha/tc/mcclock_ioasic.c130
-rw-r--r--sys/alpha/tc/sticreg.h101
-rw-r--r--sys/alpha/tc/sticvar.h53
-rw-r--r--sys/alpha/tc/tc.c704
-rw-r--r--sys/alpha/tc/tcasic.c115
-rw-r--r--sys/alpha/tc/tcdevs.h118
-rw-r--r--sys/alpha/tc/tcdevs_data.h174
-rw-r--r--sys/alpha/tc/tcds.c459
-rw-r--r--sys/alpha/tc/tcds_dma.c286
-rw-r--r--sys/alpha/tc/tcdsreg.h215
-rw-r--r--sys/alpha/tc/tcdsvar.h111
-rw-r--r--sys/alpha/tc/tcreg.h162
-rw-r--r--sys/alpha/tc/tcvar.h200
-rw-r--r--sys/conf/files.alpha15
-rw-r--r--sys/conf/options.alpha5
35 files changed, 8772 insertions, 13 deletions
diff --git a/sys/alpha/alpha/autoconf.c b/sys/alpha/alpha/autoconf.c
index 35372c3..48f4761 100644
--- a/sys/alpha/alpha/autoconf.c
+++ b/sys/alpha/alpha/autoconf.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: autoconf.c,v 1.5 1998/07/22 08:34:19 dfr Exp $
+ * $Id: autoconf.c,v 1.6 1998/08/10 07:53:58 dfr Exp $
*/
#include <sys/param.h>
@@ -41,6 +41,7 @@
#include <machine/ipl.h>
#include <machine/md_var.h>
#include <machine/cpuconf.h>
+#include <machine/rpb.h>
#include "scbus.h"
#if NSCBUS > 0
@@ -84,13 +85,15 @@ configure(void *dummy)
root_bus_configure();
- pci_configure();
-
- /*
- * Probe ISA devices after everything.
- */
- bus_generic_attach(isa_bus_device);
+ if((hwrpb->rpb_type != ST_DEC_3000_300) &&
+ (hwrpb->rpb_type != ST_DEC_3000_500)){
+ pci_configure();
+ /*
+ * Probe ISA devices after everything.
+ */
+ bus_generic_attach(isa_bus_device);
+ }
configure_finish();
cninit_finish();
diff --git a/sys/alpha/alpha/dec_3000_300.c b/sys/alpha/alpha/dec_3000_300.c
new file mode 100644
index 0000000..1c465dc
--- /dev/null
+++ b/sys/alpha/alpha/dec_3000_300.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1997 by Matthew Jacob
+ * NASA AMES Research Center.
+ * 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 immediately at the beginning of the file, without modification,
+ * 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 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 AUTHOR 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 "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/termios.h>
+
+#include <machine/rpb.h>
+#include <machine/cpuconf.h>
+
+#include <alpha/tlsb/tlsbreg.h>
+#include <alpha/tlsb/gbusreg.h>
+#include <alpha/tlsb/zsvar.h>
+
+void dec_3000_300_init(int);
+static void dec_3000_300_cons_init(void);
+
+static const struct alpha_variation_table dec_3000_300_variations[] = {
+ { SV_ST_PELICAN, "DEC 3000/300 (\"Pelican\")" },
+ { SV_ST_PELICA, "DEC 3000/300L (\"Pelica\")" },
+ { SV_ST_PELICANPLUS, "DEC 3000/300X (\"Pelican+\")" },
+ { SV_ST_PELICAPLUS, "DEC 3000/300LX (\"Pelica+\")" },
+ { 0, NULL },
+};
+
+void
+dec_3000_300_init(int cputype)
+{
+ u_int64_t variation;
+
+ platform.family = "DEC 3000/300 (\"Pelican\")";
+
+ if ((platform.model = alpha_dsr_sysname()) == NULL) {
+ variation = hwrpb->rpb_variation & SV_ST_MASK;
+ if ((platform.model = alpha_variation_name(variation,
+ dec_3000_300_variations)) == NULL)
+ platform.model = alpha_unknown_sysname();
+ }
+
+ platform.iobus = "tcasic";
+ platform.cons_init = dec_3000_300_cons_init;
+}
+
+/*
+ * dec_3000_300_cons_init- not needed right now.
+ *
+ */
+static void
+dec_3000_300_cons_init(void)
+{
+ return;
+}
diff --git a/sys/alpha/alpha/dec_3000_500.c b/sys/alpha/alpha/dec_3000_500.c
new file mode 100644
index 0000000..f9b6770
--- /dev/null
+++ b/sys/alpha/alpha/dec_3000_500.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1997 by Matthew Jacob
+ * NASA AMES Research Center.
+ * 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 immediately at the beginning of the file, without modification,
+ * 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 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 AUTHOR 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 "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/termios.h>
+
+#include <machine/rpb.h>
+#include <machine/cpuconf.h>
+
+#include <alpha/tlsb/tlsbreg.h>
+#include <alpha/tlsb/gbusreg.h>
+#include <alpha/tlsb/zsvar.h>
+
+void dec_3000_500_init(int);
+static void dec_3000_500_cons_init(void);
+
+static const char dec_3000_500_sp[] = "DEC 3000/400 (\"Sandpiper\")";
+static const char dec_3000_500_sf[] = "DEC 3000/500 (\"Flamingo\")";
+
+const struct alpha_variation_table dec_3000_500_variations[] = {
+ { SV_ST_SANDPIPER, dec_3000_500_sp },
+ { SV_ST_FLAMINGO, dec_3000_500_sf },
+ { SV_ST_HOTPINK, "DEC 3000/500X (\"Hot Pink\")" },
+ { SV_ST_FLAMINGOPLUS, "DEC 3000/800 (\"Flamingo+\")" },
+ { SV_ST_SANDPLUS, "DEC 3000/600 (\"Sandpiper+\")" },
+ { SV_ST_SANDPIPER45, "DEC 3000/700 (\"Sandpiper45\")" },
+ { SV_ST_FLAMINGO45, "DEC 3000/900 (\"Flamingo45\")" },
+ { 0, NULL },
+};
+
+void
+dec_3000_500_init(int cputype)
+{
+ u_int64_t variation;
+
+ platform.family = "DEC 3000/500 (\"Flamingo\")";
+
+ if ((platform.model = alpha_dsr_sysname()) == NULL) {
+ variation = hwrpb->rpb_variation & SV_ST_MASK;
+ if (variation == SV_ST_ULTRA) {
+ /* These are really the same. */
+ variation = SV_ST_FLAMINGOPLUS;
+ }
+ if ((platform.model = alpha_variation_name(variation,
+ dec_3000_500_variations)) == NULL) {
+ /*
+ * This is how things used to be done.
+ */
+ if (variation == SV_ST_RESERVED) {
+ if (hwrpb->rpb_variation & SV_GRAPHICS)
+ platform.model = dec_3000_500_sf;
+ else
+ platform.model = dec_3000_500_sp;
+ } else
+ platform.model = alpha_unknown_sysname();
+ }
+ }
+
+ platform.iobus = "tcasic";
+ platform.cons_init = dec_3000_500_cons_init;
+}
+
+/*
+ * dec_3000_500_cons_init- not needed right now.
+ *
+ */
+static void
+dec_3000_500_cons_init(void)
+{
+ return;
+}
diff --git a/sys/alpha/conf/GENERIC b/sys/alpha/conf/GENERIC
index 3265a1b..c966b63 100644
--- a/sys/alpha/conf/GENERIC
+++ b/sys/alpha/conf/GENERIC
@@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
-# $Id: GENERIC,v 1.2 1998/08/07 08:16:31 dfr Exp $
+# $Id: GENERIC,v 1.3 1998/08/10 07:53:58 dfr Exp $
machine "alpha"
cpu "EV4"
@@ -25,6 +25,8 @@ options "DEC_EB164" # EB164, PC164, PC164LX, PC164SX
options "DEC_2100_A50" # AlphaStation 200, 250, 255, 400
options "DEC_KN20AA" # AlphaStation 500, 600
options "DEC_ST550" # Personal Workstation 433, 500, 600
+options "DEC_3000_300" # DEC3000/300* Pelic* family
+options "DEC_3000_500" # DEC3000/[4-9]00 Flamingo/Sandpiper family
options INET #InterNETworking
options FFS #Berkeley Fast Filesystem
@@ -47,14 +49,32 @@ controller cia0
controller apecs0
controller lca0
+# TurboChannel
+controller tcasic0
+controller tc0
+controller ioasic0
+
+# TurboChannel devices
+controller tcds0
+controller esp0
+
+# TC IO Asic devices
+device le0
+
# Standard busses
controller pci0
controller isa0
+# TurboChannel host bus support
+controller tcasic0
+controller tc0
+controller tcds0
+
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.
controller ncr0
controller isp0
+controller esp0
controller scbus0
@@ -77,6 +97,7 @@ device sio1 at isa0 port "IO_COM2" irq 3 flags 0x50
# Right now it appears that the ie0 must be probed before ep0. See
# revision 1.20 of this file.
device de0
+device le0
pseudo-device loop
pseudo-device ether
diff --git a/sys/alpha/conf/NOTES b/sys/alpha/conf/NOTES
index 3265a1b..c966b63 100644
--- a/sys/alpha/conf/NOTES
+++ b/sys/alpha/conf/NOTES
@@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
-# $Id: GENERIC,v 1.2 1998/08/07 08:16:31 dfr Exp $
+# $Id: GENERIC,v 1.3 1998/08/10 07:53:58 dfr Exp $
machine "alpha"
cpu "EV4"
@@ -25,6 +25,8 @@ options "DEC_EB164" # EB164, PC164, PC164LX, PC164SX
options "DEC_2100_A50" # AlphaStation 200, 250, 255, 400
options "DEC_KN20AA" # AlphaStation 500, 600
options "DEC_ST550" # Personal Workstation 433, 500, 600
+options "DEC_3000_300" # DEC3000/300* Pelic* family
+options "DEC_3000_500" # DEC3000/[4-9]00 Flamingo/Sandpiper family
options INET #InterNETworking
options FFS #Berkeley Fast Filesystem
@@ -47,14 +49,32 @@ controller cia0
controller apecs0
controller lca0
+# TurboChannel
+controller tcasic0
+controller tc0
+controller ioasic0
+
+# TurboChannel devices
+controller tcds0
+controller esp0
+
+# TC IO Asic devices
+device le0
+
# Standard busses
controller pci0
controller isa0
+# TurboChannel host bus support
+controller tcasic0
+controller tc0
+controller tcds0
+
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.
controller ncr0
controller isp0
+controller esp0
controller scbus0
@@ -77,6 +97,7 @@ device sio1 at isa0 port "IO_COM2" irq 3 flags 0x50
# Right now it appears that the ie0 must be probed before ep0. See
# revision 1.20 of this file.
device de0
+device le0
pseudo-device loop
pseudo-device ether
diff --git a/sys/alpha/conf/files.alpha b/sys/alpha/conf/files.alpha
index 5e28c2c..68888d5 100644
--- a/sys/alpha/conf/files.alpha
+++ b/sys/alpha/conf/files.alpha
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.alpha,v 1.4 1998/07/22 08:24:39 dfr Exp $
+# $Id: files.alpha,v 1.5 1998/08/10 07:53:58 dfr Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@@ -22,6 +22,8 @@ alpha/alpha/dec_kn20aa.c optional dec_kn20aa
alpha/alpha/dec_2100_a50.c optional dec_2100_a50
alpha/alpha/dec_st550.c optional dec_st550
alpha/alpha/dec_axppci_33.c optional dec_axppci_33
+alpha/alpha/dec_3000_300.c optional dec_3000_300
+alpha/alpha/dec_3000_500.c optional dec_3000_500
alpha/alpha/mountroot.c optional slice
alpha/alpha/ipl_funcs.c standard
alpha/alpha/pal.s standard
@@ -70,6 +72,16 @@ alpha/tlsb/kftxx.c optional kft
alpha/tlsb/mcclock_tlsb.c optional gbus
alpha/tlsb/zs_tlsb.c optional gbus
alpha/tlsb/dwlpx.c optional dwlpx
+alpha/tc/tcasic.c optional tcasic
+alpha/tc/tc.c optional tc
+alpha/tc/ioasic.c optional tc
+alpha/tc/mcclock_ioasic.c optional tc
+alpha/tc/if_le_ioasic.c optional le device-driver
+alpha/tc/if_le_dec.c optional le device-driver
+alpha/tc/am7990.c optional le device-driver
+alpha/tc/tcds.c optional tcds device-driver
+alpha/tc/tcds_dma.c optional tcds device-driver
+alpha/tc/esp.c optional esp device-driver
dev/dec/mcclock.c standard
dev/dec/mcclock_if.m standard \
dependency "$S/kern/makedevops.sh" \
@@ -126,5 +138,6 @@ libkern/alpha/ntohl.S standard
libkern/alpha/ntohs.S standard
isa/sio.c optional sio device-driver
isa/kbdio.c optional psm device-driver
+isa/psm.c optional psm device-driver
isa/kbdio.c optional sc device-driver
isa/syscons.c optional sc device-driver
diff --git a/sys/alpha/conf/options.alpha b/sys/alpha/conf/options.alpha
index 3132f9a..de3aee2 100644
--- a/sys/alpha/conf/options.alpha
+++ b/sys/alpha/conf/options.alpha
@@ -1,12 +1,15 @@
-# $Id: options.alpha,v 1.3 1998/07/22 08:24:39 dfr Exp $
+# $Id: options.alpha,v 1.4 1998/08/10 07:53:58 dfr Exp $
EV5 opt_global.h
+EV4 opt_global.h
DEC_KN8AE opt_cpu.h
DEC_EB164 opt_cpu.h
DEC_KN20AA opt_cpu.h
DEC_2100_A50 opt_cpu.h
DEC_ST550 opt_cpu.h
DEC_AXPPCI_33 opt_cpu.h
+DEC_3000_300 opt_cpu.h
+DEC_3000_500 opt_cpu.h
ATAPI opt_atapi.h
ATAPI_STATIC opt_atapi.h
diff --git a/sys/alpha/tc/am7990.c b/sys/alpha/tc/am7990.c
new file mode 100644
index 0000000..6c65f82
--- /dev/null
+++ b/sys/alpha/tc/am7990.c
@@ -0,0 +1,1473 @@
+/* $Id$ */
+/* $NetBSD: am7990.c,v 1.43 1998/03/29 22:36:42 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)if_le.c 8.2 (Berkeley) 11/16/93
+ */
+
+#include "opt_inet.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#endif
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+
+#include <machine/clock.h>
+
+#include <alpha/tc/am7990reg.h>
+#include <alpha/tc/am7990var.h>
+
+#ifdef LEDEBUG
+void am7990_recv_print __P((struct am7990_softc *, int));
+void am7990_xmit_print __P((struct am7990_softc *, int));
+#endif
+
+integrate void am7990_rint __P((struct am7990_softc *));
+integrate void am7990_tint __P((struct am7990_softc *));
+
+integrate int am7990_put __P((struct am7990_softc *, int, struct mbuf *));
+integrate struct mbuf *am7990_get __P((struct am7990_softc *, int, int));
+integrate void am7990_read __P((struct am7990_softc *, int, int));
+
+hide void am7990_shutdown __P((void *));
+
+int am7990_mediachange __P((struct ifnet *));
+void am7990_mediastatus __P((struct ifnet *, struct ifmediareq *));
+
+#define ifp (&sc->sc_ethercom.ac_if)
+
+static __inline u_int16_t ether_cmp __P((void *, void *));
+ char * ether_sprintf(u_char *ap);
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed. Use this like bcmp().
+ *
+ * XXX: Add <machine/inlines.h> for stuff like this?
+ * XXX: or maybe add it to libkern.h instead?
+ *
+ * "I'd love to have an inline assembler version of this."
+ * XXX: Who wanted that? mycroft? I wrote one, but this
+ * version in C is as good as hand-coded assembly. -gwr
+ *
+ * Please do NOT tweak this without looking at the actual
+ * assembly code generated before and after your tweaks!
+ */
+static __inline u_int16_t
+ether_cmp(one, two)
+ void *one, *two;
+{
+ register u_int16_t *a = (u_short *) one;
+ register u_int16_t *b = (u_short *) two;
+ register u_int16_t diff;
+
+#ifdef m68k
+ /*
+ * The post-increment-pointer form produces the best
+ * machine code for m68k. This was carefully tuned
+ * so it compiles to just 8 short (2-byte) op-codes!
+ */
+ diff = *a++ - *b++;
+ diff |= *a++ - *b++;
+ diff |= *a++ - *b++;
+#else
+ /*
+ * Most modern CPUs do better with a single expresion.
+ * Note that short-cut evaluation is NOT helpful here,
+ * because it just makes the code longer, not faster!
+ */
+ diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
+#endif
+
+ return (diff);
+}
+
+#define ETHER_CMP ether_cmp
+
+#ifdef LANCE_REVC_BUG
+/* Make sure this is short-aligned, for ether_cmp(). */
+static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
+#endif
+
+void
+am7990_config(sc)
+ struct am7990_softc *sc;
+{
+ int mem, i;
+
+ /* Make sure the chip is stopped. */
+ am7990_stop(sc);
+ /* Initialize ifnet structure. */
+ sprintf(sc->sc_dev.dv_xname, "le%d", sc->unit);
+ ifp->if_unit = sc->unit;
+ ifp->if_name = "le";
+ ifp->if_softc = sc;
+ ifp->if_start = am7990_start;
+ ifp->if_ioctl = am7990_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_watchdog = am7990_watchdog;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef LANCE_REVC_BUG
+ ifp->if_flags &= ~IFF_MULTICAST;
+#endif
+
+ /* Initialize ifmedia structures. */
+ ifmedia_init(&sc->sc_media, 0, am7990_mediachange, am7990_mediastatus);
+ if (sc->sc_supmedia != NULL) {
+ for (i = 0; i < sc->sc_nsupmedia; i++)
+ ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
+ 0, NULL);
+ ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
+ } else {
+ ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
+ ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
+ }
+
+ /* Attach the interface. */
+ bcopy(sc->sc_enaddr,((struct arpcom *)ifp)->ac_enaddr, 6);
+ printf("%s: address %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_enaddr));
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ switch (sc->sc_memsize) {
+ case 8192:
+ sc->sc_nrbuf = 4;
+ sc->sc_ntbuf = 1;
+ break;
+ case 16384:
+ sc->sc_nrbuf = 8;
+ sc->sc_ntbuf = 2;
+ break;
+ case 32768:
+ sc->sc_nrbuf = 16;
+ sc->sc_ntbuf = 4;
+ break;
+ case 65536:
+ sc->sc_nrbuf = 32;
+ sc->sc_ntbuf = 8;
+ break;
+ case 131072:
+ sc->sc_nrbuf = 64;
+ sc->sc_ntbuf = 16;
+ break;
+ default:
+ panic("am7990_config: weird memory size");
+ }
+
+ printf("%s: %d receive buffers, %d transmit buffers\n",
+ sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
+
+/*
+ sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc);
+ if (sc->sc_sh == NULL)
+ panic("am7990_config: can't establish shutdownhook");
+*/
+ sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
+ M_WAITOK);
+ sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
+ M_WAITOK);
+
+ mem = 0;
+ sc->sc_initaddr = mem;
+ mem += sizeof(struct leinit);
+ sc->sc_rmdaddr = mem;
+ mem += sizeof(struct lermd) * sc->sc_nrbuf;
+ sc->sc_tmdaddr = mem;
+ mem += sizeof(struct letmd) * sc->sc_ntbuf;
+ for (i = 0; i < sc->sc_nrbuf; i++, mem += LEBLEN)
+ sc->sc_rbufaddr[i] = mem;
+ for (i = 0; i < sc->sc_ntbuf; i++, mem += LEBLEN)
+ sc->sc_tbufaddr[i] = mem;
+#ifdef notyet
+ if (mem > ...)
+ panic(...);
+#endif
+
+#if NRND > 0
+ rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
+ RND_TYPE_NET);
+#endif
+}
+
+void
+am7990_reset(sc)
+ struct am7990_softc *sc;
+{
+ int s;
+
+ s = splimp();
+ am7990_init(sc);
+ splx(s);
+}
+
+/*
+ * Set up the initialization block and the descriptor rings.
+ */
+void
+am7990_meminit(sc)
+ register struct am7990_softc *sc;
+{
+ u_long a;
+ int bix;
+ struct leinit init;
+ struct lermd rmd;
+ struct letmd tmd;
+ u_int8_t *myaddr;
+
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC)
+ init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
+ else
+#endif
+ init.init_mode = LE_MODE_NORMAL;
+ if (sc->sc_initmodemedia == 1)
+ init.init_mode |= LE_MODE_PSEL0;
+
+ /*
+ * Update our private copy of the Ethernet address.
+ * We NEED the copy so we can ensure its alignment!
+ */
+ bcopy(((struct arpcom *)ifp)->ac_enaddr, sc->sc_enaddr, 6);
+ myaddr = sc->sc_enaddr;
+
+ init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
+ init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
+ init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
+ am7990_setladrf(&sc->sc_ethercom, init.init_ladrf);
+
+ sc->sc_last_rd = 0;
+ sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
+
+ a = sc->sc_addr + LE_RMDADDR(sc, 0);
+ init.init_rdra = a;
+ init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
+
+ a = sc->sc_addr + LE_TMDADDR(sc, 0);
+ init.init_tdra = a;
+ init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
+
+ (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
+
+ /*
+ * Set up receive ring descriptors.
+ */
+ for (bix = 0; bix < sc->sc_nrbuf; bix++) {
+ a = sc->sc_addr + LE_RBUFADDR(sc, bix);
+ rmd.rmd0 = a;
+ rmd.rmd1_hadr = a >> 16;
+ rmd.rmd1_bits = LE_R1_OWN;
+ rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
+ rmd.rmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
+ sizeof(rmd));
+ }
+
+ /*
+ * Set up transmit ring descriptors.
+ */
+ for (bix = 0; bix < sc->sc_ntbuf; bix++) {
+ a = sc->sc_addr + LE_TBUFADDR(sc, bix);
+ tmd.tmd0 = a;
+ tmd.tmd1_hadr = a >> 16;
+ tmd.tmd1_bits = 0;
+ tmd.tmd2 = 0 | LE_XMD2_ONES;
+ tmd.tmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
+ sizeof(tmd));
+ }
+}
+
+void
+am7990_stop(sc)
+ struct am7990_softc *sc;
+{
+
+ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
+}
+
+/*
+ * Initialization of interface; set up initialization block
+ * and transmit/receive descriptor rings.
+ */
+void
+am7990_init(sc)
+ register struct am7990_softc *sc;
+{
+ register int timo;
+ u_long a;
+
+ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
+ DELAY(100);
+
+ /* Newer LANCE chips have a reset register */
+ if (sc->sc_hwreset)
+ (*sc->sc_hwreset)(sc);
+
+ /* Set the correct byte swapping mode, etc. */
+ (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
+
+ /* Set up LANCE init block. */
+ am7990_meminit(sc);
+
+ /* Give LANCE the physical address of its init block. */
+ a = sc->sc_addr + LE_INITADDR(sc);
+ (*sc->sc_wrcsr)(sc, LE_CSR1, a);
+ (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
+
+ /* Try to initialize the LANCE. */
+ DELAY(100);
+ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
+
+ /* Wait for initialization to finish. */
+ for (timo = 100000; timo; timo--)
+ if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
+ break;
+
+ if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
+ /* Start the LANCE. */
+ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
+ LE_C0_IDON);
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_timer = 0;
+ am7990_start(ifp);
+ } else
+ printf("%s: card failed to initialize\n", sc->sc_dev.dv_xname);
+ if (sc->sc_hwinit)
+ (*sc->sc_hwinit)(sc);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmit buffer in
+ * network buffer memory.
+ */
+integrate int
+am7990_put(sc, boff, m)
+ struct am7990_softc *sc;
+ int boff;
+ register struct mbuf *m;
+{
+ register struct mbuf *n;
+ register int len, tlen = 0;
+
+ for (; m; m = n) {
+ len = m->m_len;
+ if (len == 0) {
+ MFREE(m, n);
+ continue;
+ }
+ (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
+ boff += len;
+ tlen += len;
+ MFREE(m, n);
+ }
+ if (tlen < LEMINSIZE) {
+ (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
+ tlen = LEMINSIZE;
+ }
+ return (tlen);
+}
+
+/*
+ * Pull data off an interface.
+ * Len is length of data, with local net header stripped.
+ * We copy the data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+integrate struct mbuf *
+am7990_get(sc, boff, totlen)
+ struct am7990_softc *sc;
+ int boff, totlen;
+{
+ register struct mbuf *m;
+ struct mbuf *top, **mp;
+ int len;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ len = MHLEN;
+ top = 0;
+ mp = &top;
+
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return 0;
+ }
+ len = MLEN;
+ }
+ if (totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m_freem(top);
+ return 0;
+ }
+ len = MCLBYTES;
+ }
+ if (!top) {
+ register int pad =
+ ALIGN(sizeof(struct ether_header)) -
+ sizeof(struct ether_header);
+ m->m_data += pad;
+ len -= pad;
+ }
+ m->m_len = len = min(totlen, len);
+ (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
+ boff += len;
+ totlen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}
+
+/*
+ * Pass a packet to the higher levels.
+ */
+integrate void
+am7990_read(sc, boff, len)
+ register struct am7990_softc *sc;
+ int boff, len;
+{
+ struct mbuf *m;
+ struct ether_header *eh;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+#ifdef LEDEBUG
+ printf("%s: invalid packet size %d; dropping\n",
+ sc->sc_dev.dv_xname, len);
+#endif
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /* Pull packet off interface. */
+ m = am7990_get(sc, boff, len);
+ if (m == 0) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ ifp->if_ipackets++;
+
+ /* We assume that the header fit entirely in one mbuf. */
+ eh = mtod(m, struct ether_header *);
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to BPF.
+ */
+ if (ifp->if_bpf) {
+ bpf_mtap(ifp->if_bpf, m);
+
+#ifndef LANCE_REVC_BUG
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ */
+ if ((ifp->if_flags & IFF_PROMISC) != 0 &&
+ (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
+ ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
+ m_freem(m);
+ return;
+ }
+#endif
+ }
+#endif
+
+#ifdef LANCE_REVC_BUG
+ /*
+ * The old LANCE (Rev. C) chips have a bug which causes
+ * garbage to be inserted in front of the received packet.
+ * The work-around is to ignore packets with an invalid
+ * destination address (garbage will usually not match).
+ * Of course, this precludes multicast support...
+ */
+ if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
+ ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
+ m_freem(m);
+ return;
+ }
+#endif
+
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+}
+
+integrate void
+am7990_rint(sc)
+ struct am7990_softc *sc;
+{
+ register int bix;
+ int rp;
+ struct lermd rmd;
+
+ bix = sc->sc_last_rd;
+
+ /* Process all buffers with valid data. */
+ for (;;) {
+ rp = LE_RMDADDR(sc, bix);
+ (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
+
+ if (rmd.rmd1_bits & LE_R1_OWN)
+ break;
+
+ if (rmd.rmd1_bits & LE_R1_ERR) {
+ if (rmd.rmd1_bits & LE_R1_ENP) {
+#ifdef LEDEBUG
+ if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
+ if (rmd.rmd1_bits & LE_R1_FRAM)
+ printf("%s: framing error\n",
+ sc->sc_dev.dv_xname);
+ if (rmd.rmd1_bits & LE_R1_CRC)
+ printf("%s: crc mismatch\n",
+ sc->sc_dev.dv_xname);
+ }
+#endif
+ } else {
+ if (rmd.rmd1_bits & LE_R1_OFLO)
+ printf("%s: overflow\n",
+ sc->sc_dev.dv_xname);
+ }
+ if (rmd.rmd1_bits & LE_R1_BUFF)
+ printf("%s: receive buffer error\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_ierrors++;
+ } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
+ (LE_R1_STP | LE_R1_ENP)) {
+ printf("%s: dropping chained buffer\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_ierrors++;
+ } else {
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ am7990_recv_print(sc, sc->sc_last_rd);
+#endif
+ am7990_read(sc, LE_RBUFADDR(sc, bix),
+ (int)rmd.rmd3 - 4);
+ }
+
+ rmd.rmd1_bits = LE_R1_OWN;
+ rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
+ rmd.rmd3 = 0;
+ (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("sc->sc_last_rd = %x, rmd: "
+ "ladr %04x, hadr %02x, flags %02x, "
+ "bcnt %04x, mcnt %04x\n",
+ sc->sc_last_rd,
+ rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
+ rmd.rmd2, rmd.rmd3);
+#endif
+
+ if (++bix == sc->sc_nrbuf)
+ bix = 0;
+ }
+
+ sc->sc_last_rd = bix;
+}
+
+integrate void
+am7990_tint(sc)
+ register struct am7990_softc *sc;
+{
+ register int bix;
+ struct letmd tmd;
+
+ bix = sc->sc_first_td;
+
+ for (;;) {
+ if (sc->sc_no_td <= 0)
+ break;
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("trans tmd: "
+ "ladr %04x, hadr %02x, flags %02x, "
+ "bcnt %04x, mcnt %04x\n",
+ tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
+ tmd.tmd2, tmd.tmd3);
+#endif
+
+ (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
+ sizeof(tmd));
+
+ if (tmd.tmd1_bits & LE_T1_OWN)
+ break;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (tmd.tmd1_bits & LE_T1_ERR) {
+ if (tmd.tmd3 & LE_T3_BUFF)
+ printf("%s: transmit buffer error\n",
+ sc->sc_dev.dv_xname);
+ else if (tmd.tmd3 & LE_T3_UFLO)
+ printf("%s: underflow\n", sc->sc_dev.dv_xname);
+ if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
+ am7990_reset(sc);
+ return;
+ }
+ if (tmd.tmd3 & LE_T3_LCAR) {
+ sc->sc_havecarrier = 0;
+ if (sc->sc_nocarrier)
+ (*sc->sc_nocarrier)(sc);
+ else
+ printf("%s: lost carrier\n",
+ sc->sc_dev.dv_xname);
+ }
+ if (tmd.tmd3 & LE_T3_LCOL)
+ ifp->if_collisions++;
+ if (tmd.tmd3 & LE_T3_RTRY) {
+ printf("%s: excessive collisions, tdr %d\n",
+ sc->sc_dev.dv_xname,
+ tmd.tmd3 & LE_T3_TDR_MASK);
+ ifp->if_collisions += 16;
+ }
+ ifp->if_oerrors++;
+ } else {
+ if (tmd.tmd1_bits & LE_T1_ONE)
+ ifp->if_collisions++;
+ else if (tmd.tmd1_bits & LE_T1_MORE)
+ /* Real number is unknown. */
+ ifp->if_collisions += 2;
+ ifp->if_opackets++;
+ }
+
+ if (++bix == sc->sc_ntbuf)
+ bix = 0;
+
+ --sc->sc_no_td;
+ }
+
+ sc->sc_first_td = bix;
+
+ am7990_start(ifp);
+
+ if (sc->sc_no_td == 0)
+ ifp->if_timer = 0;
+}
+
+/*
+ * Controller interrupt.
+ */
+void
+am7990_intr(arg)
+ register void *arg;
+{
+ register struct am7990_softc *sc = arg;
+ register u_int16_t isr;
+
+ isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
+ sc->sc_saved_csr0 = 0;
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ printf("%s: am7990_intr entering with isr=%04x\n",
+ sc->sc_dev.dv_xname, isr);
+#endif
+ if ((isr & LE_C0_INTR) == 0)
+ return;
+
+ (*sc->sc_wrcsr)(sc, LE_CSR0,
+ isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
+ LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
+ if (isr & LE_C0_ERR) {
+ if (isr & LE_C0_BABL) {
+#ifdef LEDEBUG
+ printf("%s: babble\n", sc->sc_dev.dv_xname);
+#endif
+ ifp->if_oerrors++;
+ }
+#if 0
+ if (isr & LE_C0_CERR) {
+ printf("%s: collision error\n", sc->sc_dev.dv_xname);
+ ifp->if_collisions++;
+ }
+#endif
+ if (isr & LE_C0_MISS) {
+#ifdef LEDEBUG
+ printf("%s: missed packet\n", sc->sc_dev.dv_xname);
+#endif
+ ifp->if_ierrors++;
+ }
+ if (isr & LE_C0_MERR) {
+ printf("%s: memory error\n", sc->sc_dev.dv_xname);
+ am7990_reset(sc);
+ return;
+ }
+ }
+
+ if ((isr & LE_C0_RXON) == 0) {
+ printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
+ ifp->if_ierrors++;
+ am7990_reset(sc);
+ return;
+ }
+ if ((isr & LE_C0_TXON) == 0) {
+ printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+ am7990_reset(sc);
+ return;
+ }
+
+ /*
+ * Pretend we have carrier; if we don't this will be cleared
+ * shortly.
+ */
+ sc->sc_havecarrier = 1;
+
+ if (isr & LE_C0_RINT)
+ am7990_rint(sc);
+ if (isr & LE_C0_TINT)
+ am7990_tint(sc);
+
+#if NRND > 0
+ rnd_add_uint32(&sc->rnd_source, isr);
+#endif
+
+ return;
+}
+
+#undef ifp
+
+void
+am7990_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct am7990_softc *sc = ifp->if_softc;
+
+ log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+ ++ifp->if_oerrors;
+
+ am7990_reset(sc);
+}
+
+int
+am7990_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ struct am7990_softc *sc = ifp->if_softc;
+
+ if (sc->sc_mediachange)
+ return ((*sc->sc_mediachange)(sc));
+ return (EINVAL);
+}
+
+void
+am7990_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct am7990_softc *sc = ifp->if_softc;
+
+ if ((ifp->if_flags & IFF_UP) == 0)
+ return;
+
+ ifmr->ifm_status = IFM_AVALID;
+ if (sc->sc_havecarrier)
+ ifmr->ifm_status |= IFM_ACTIVE;
+
+ if (sc->sc_mediastatus)
+ (*sc->sc_mediastatus)(sc, ifmr);
+}
+
+/*
+ * Setup output on interface.
+ * Get another datagram to send off of the interface queue, and map it to the
+ * interface before starting the output.
+ * Called only at splimp or interrupt level.
+ */
+void
+am7990_start(ifp)
+ register struct ifnet *ifp;
+{
+ register struct am7990_softc *sc = ifp->if_softc;
+ register int bix;
+ register struct mbuf *m;
+ struct letmd tmd;
+ int rp;
+ int len;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ bix = sc->sc_last_td;
+
+ for (;;) {
+ rp = LE_TMDADDR(sc, bix);
+ (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
+
+ if (tmd.tmd1_bits & LE_T1_OWN) {
+ ifp->if_flags |= IFF_OACTIVE;
+ printf("missing buffer, no_td = %d, last_td = %d\n",
+ sc->sc_no_td, sc->sc_last_td);
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ break;
+
+#if NBPFILTER > 0
+ /*
+ * If BPF is listening on this interface, let it see the packet
+ * before we commit it to the wire.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /*
+ * Copy the mbuf chain into the transmit buffer.
+ */
+ len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);
+
+#ifdef LEDEBUG
+ if (len > ETHERMTU + sizeof(struct ether_header))
+ printf("packet length %d\n", len);
+#endif
+
+ ifp->if_timer = 5;
+
+ /*
+ * Init transmit registers, and set transmit start flag.
+ */
+ tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
+ tmd.tmd2 = -len | LE_XMD2_ONES;
+ tmd.tmd3 = 0;
+
+ (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
+
+#ifdef LEDEBUG
+ if (sc->sc_debug)
+ am7990_xmit_print(sc, sc->sc_last_td);
+#endif
+
+ (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
+
+ if (++bix == sc->sc_ntbuf)
+ bix = 0;
+
+ if (++sc->sc_no_td == sc->sc_ntbuf) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ }
+
+ sc->sc_last_td = bix;
+}
+
+/*
+ * Process an ioctl request.
+ */
+int
+am7990_ioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ register struct am7990_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ am7990_init(sc);
+ arp_ifinit((struct arpcom *)ifp, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)LLADDR(ifp->if_sadl);
+ else {
+ bcopy(ina->x_host.c_host,
+ LLADDR(ifp->if_sadl),
+ sizeof(sc->sc_enaddr));
+ }
+ /* Set new address. */
+ am7990_init(sc);
+ break;
+ }
+#endif
+ default:
+ am7990_init(sc);
+ break;
+ }
+ break;
+
+#if defined(CCITT) && defined(LLC)
+ case SIOCSIFCONF_X25:
+ ifp->if_flags |= IFF_UP;
+ ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
+ error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
+ if (error == 0)
+ am7990_init(sc);
+ break;
+#endif /* CCITT && LLC */
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ am7990_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ am7990_init(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect hardware registers.
+ */
+ /*am7990_stop(sc);*/
+ am7990_init(sc);
+ }
+#ifdef LEDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ sc->sc_debug = 1;
+ else
+ sc->sc_debug = 0;
+#endif
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ am7990_reset(sc);
+ error = 0;
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+ return (error);
+}
+
+hide void
+am7990_shutdown(arg)
+ void *arg;
+{
+
+ am7990_stop((struct am7990_softc *)arg);
+}
+
+#ifdef LEDEBUG
+void
+am7990_recv_print(sc, no)
+ struct am7990_softc *sc;
+ int no;
+{
+ struct lermd rmd;
+ u_int16_t len;
+ struct ether_header eh;
+
+ (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
+ len = rmd.rmd3;
+ printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
+ len);
+ printf("%s: status %04x\n", sc->sc_dev.dv_xname,
+ (*sc->sc_rdcsr)(sc, LE_CSR0));
+ printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
+ sc->sc_dev.dv_xname,
+ rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
+ if (len >= sizeof(eh)) {
+ (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
+ printf("%s: dst %s", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_dhost));
+ printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
+ ntohs(eh.ether_type));
+ }
+}
+
+void
+am7990_xmit_print(sc, no)
+ struct am7990_softc *sc;
+ int no;
+{
+ struct letmd tmd;
+ u_int16_t len;
+ struct ether_header eh;
+
+ (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
+ len = -tmd.tmd2;
+ printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
+ len);
+ printf("%s: status %04x\n", sc->sc_dev.dv_xname,
+ (*sc->sc_rdcsr)(sc, LE_CSR0));
+ printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
+ sc->sc_dev.dv_xname,
+ tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
+ if (len >= sizeof(eh)) {
+ (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
+ printf("%s: dst %s", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_dhost));
+ printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
+ ntohs(eh.ether_type));
+ }
+}
+#endif /* LEDEBUG */
+
+/*
+ * Set up the logical address filter.
+ */
+void
+am7990_setladrf(ac, af)
+ struct arpcom *ac;
+ u_int16_t *af;
+{
+#if 0
+ struct ifnet *ifp = &ac->ac_if;
+ struct ether_multi *enm;
+ register u_char *cp;
+ register u_int32_t crc;
+ static const u_int32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ register int len;
+ struct ether_multistep step;
+
+ /*
+ * Set up multicast address filter by passing all multicast addresses
+ * through a crc generator, and then using the high order 6 bits as an
+ * index into the 64 bit logical address filter. The high order bit
+ * selects the word, while the rest of the bits select the bit within
+ * the word.
+ */
+
+ if (ifp->if_flags & IFF_PROMISC)
+ goto allmulti;
+
+ af[0] = af[1] = af[2] = af[3] = 0x0000;
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
+ /*
+ * We must listen to a range of multicast addresses.
+ * For now, just accept all multicasts, rather than
+ * trying to set only those filter bits needed to match
+ * the range. (At this time, the only use of address
+ * ranges is for IP multicast routing, for which the
+ * range is big enough to require all bits set.)
+ */
+ goto allmulti;
+ }
+
+ cp = enm->enm_addrlo;
+ crc = 0xffffffff;
+ for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
+ crc ^= *cp++;
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+ /* Just want the 6 most significant bits. */
+ crc >>= 26;
+
+ /* Set the corresponding bit in the filter. */
+ af[crc >> 4] |= 1 << (crc & 0xf);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ return;
+
+allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ af[0] = af[1] = af[2] = af[3] = 0xffff;
+#endif
+}
+
+
+/*
+ * Routines for accessing the transmit and receive buffers.
+ * The various CPU and adapter configurations supported by this
+ * driver require three different access methods for buffers
+ * and descriptors:
+ * (1) contig (contiguous data; no padding),
+ * (2) gap2 (two bytes of data followed by two bytes of padding),
+ * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
+ */
+
+/*
+ * contig: contiguous data with no padding.
+ *
+ * Buffers may have any alignment.
+ */
+
+void
+am7990_copytobuf_contig(sc, from, boff, len)
+ struct am7990_softc *sc;
+ void *from;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(from, buf + boff, len);
+}
+
+void
+am7990_copyfrombuf_contig(sc, to, boff, len)
+ struct am7990_softc *sc;
+ void *to;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just call bcopy() to do the work.
+ */
+ bcopy(buf + boff, to, len);
+}
+
+void
+am7990_zerobuf_contig(sc, boff, len)
+ struct am7990_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+
+ /*
+ * Just let bzero() do the work
+ */
+ bzero(buf + boff, len);
+}
+
+#if 0
+/*
+ * Examples only; duplicate these and tweak (if necessary) in
+ * machine-specific front-ends.
+ */
+
+/*
+ * gap2: two bytes of data followed by two bytes of pad.
+ *
+ * Buffers must be 4-byte aligned. The code doesn't worry about
+ * doing an extra byte.
+ */
+
+void
+am7990_copytobuf_gap2(sc, fromv, boff, len)
+ struct am7990_softc *sc;
+ void *fromv;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t from = fromv;
+ register volatile u_int16_t *bptr;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_int16_t *)buf) + (boff - 1);
+ *bptr = (*from++ << 8) | (*bptr & 0xff);
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_int16_t *)buf) + boff;
+ while (len > 1) {
+ *bptr = (from[1] << 8) | (from[0] & 0xff);
+ bptr += 2;
+ from += 2;
+ len -= 2;
+ }
+ if (len == 1)
+ *bptr = (u_int16_t)*from;
+}
+
+void
+am7990_copyfrombuf_gap2(sc, tov, boff, len)
+ struct am7990_softc *sc;
+ void *tov;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t to = tov;
+ register volatile u_int16_t *bptr;
+ register u_int16_t tmp;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_int16_t *)buf) + (boff - 1);
+ *to++ = (*bptr >> 8) & 0xff;
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_int16_t *)buf) + boff;
+ while (len > 1) {
+ tmp = *bptr;
+ *to++ = tmp & 0xff;
+ *to++ = (tmp >> 8) & 0xff;
+ bptr += 2;
+ len -= 2;
+ }
+ if (len == 1)
+ *to = *bptr & 0xff;
+}
+
+void
+am7990_zerobuf_gap2(sc, boff, len)
+ struct am7990_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register volatile u_int16_t *bptr;
+
+ if ((unsigned)boff & 0x1) {
+ bptr = ((volatile u_int16_t *)buf) + (boff - 1);
+ *bptr &= 0xff;
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_int16_t *)buf) + boff;
+ while (len > 0) {
+ *bptr = 0;
+ bptr += 2;
+ len -= 2;
+ }
+}
+
+/*
+ * gap16: 16 bytes of data followed by 16 bytes of pad.
+ *
+ * Buffers must be 32-byte aligned.
+ */
+
+void
+am7990_copytobuf_gap16(sc, fromv, boff, len)
+ struct am7990_softc *sc;
+ void *fromv;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t from = fromv;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bcopy(from, bptr + boff, xfer);
+ from += xfer;
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+
+void
+am7990_copyfrombuf_gap16(sc, tov, boff, len)
+ struct am7990_softc *sc;
+ void *tov;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t to = tov;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bcopy(bptr + boff, to, xfer);
+ to += xfer;
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+
+void
+am7990_zerobuf_gap16(sc, boff, len)
+ struct am7990_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bzero(bptr + boff, xfer);
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+#endif /* Example only */
+char *
+ether_sprintf(ap)
+ register u_char *ap;
+{
+ register i;
+ static char etherbuf[18];
+ register char *cp = etherbuf;
+ static char digits[] = "0123456789abcdef";
+
+ for (i = 0; i < 6; i++) {
+ *cp++ = digits[*ap >> 4];
+ *cp++ = digits[*ap++ & 0xf];
+ *cp++ = ':';
+ }
+ *--cp = 0;
+ return (etherbuf);
+}
diff --git a/sys/alpha/tc/am7990reg.h b/sys/alpha/tc/am7990reg.h
new file mode 100644
index 0000000..71d92d9
--- /dev/null
+++ b/sys/alpha/tc/am7990reg.h
@@ -0,0 +1,216 @@
+/* $Id$ */
+/* $NetBSD: am7990reg.h,v 1.4 1997/03/27 21:01:49 veego Exp $ */
+
+/*-
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)if_lereg.h 8.1 (Berkeley) 6/10/93
+ */
+
+#define LEBLEN 1536 /* ETHERMTU + header + CRC */
+#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */
+
+/*
+ * Receive message descriptor
+ */
+struct lermd {
+ u_int16_t rmd0;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t rmd1_bits;
+ u_int8_t rmd1_hadr;
+#else
+ u_int8_t rmd1_hadr;
+ u_int8_t rmd1_bits;
+#endif
+ int16_t rmd2;
+ u_int16_t rmd3;
+};
+
+/*
+ * Transmit message descriptor
+ */
+struct letmd {
+ u_int16_t tmd0;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t tmd1_bits;
+ u_int8_t tmd1_hadr;
+#else
+ u_int8_t tmd1_hadr;
+ u_int8_t tmd1_bits;
+#endif
+ int16_t tmd2;
+ u_int16_t tmd3;
+};
+
+/*
+ * Initialization block
+ */
+struct leinit {
+ u_int16_t init_mode; /* +0x0000 */
+ u_int16_t init_padr[3]; /* +0x0002 */
+ u_int16_t init_ladrf[4]; /* +0x0008 */
+ u_int16_t init_rdra; /* +0x0010 */
+ u_int16_t init_rlen; /* +0x0012 */
+ u_int16_t init_tdra; /* +0x0014 */
+ u_int16_t init_tlen; /* +0x0016 */
+ int16_t pad0[4]; /* Pad to 16 shorts */
+};
+
+#define LE_INITADDR(sc) (sc->sc_initaddr)
+#define LE_RMDADDR(sc, bix) (sc->sc_rmdaddr + sizeof(struct lermd) * (bix))
+#define LE_TMDADDR(sc, bix) (sc->sc_tmdaddr + sizeof(struct letmd) * (bix))
+#define LE_RBUFADDR(sc, bix) (sc->sc_rbufaddr[bix])
+#define LE_TBUFADDR(sc, bix) (sc->sc_tbufaddr[bix])
+
+/* register addresses */
+#define LE_CSR0 0x0000 /* Control and status register */
+#define LE_CSR1 0x0001 /* low address of init block */
+#define LE_CSR2 0x0002 /* high address of init block */
+#define LE_CSR3 0x0003 /* Bus master and control */
+
+/* Control and status register 0 (csr0) */
+#define LE_C0_ERR 0x8000 /* error summary */
+#define LE_C0_BABL 0x4000 /* transmitter timeout error */
+#define LE_C0_CERR 0x2000 /* collision */
+#define LE_C0_MISS 0x1000 /* missed a packet */
+#define LE_C0_MERR 0x0800 /* memory error */
+#define LE_C0_RINT 0x0400 /* receiver interrupt */
+#define LE_C0_TINT 0x0200 /* transmitter interrupt */
+#define LE_C0_IDON 0x0100 /* initalization done */
+#define LE_C0_INTR 0x0080 /* interrupt condition */
+#define LE_C0_INEA 0x0040 /* interrupt enable */
+#define LE_C0_RXON 0x0020 /* receiver on */
+#define LE_C0_TXON 0x0010 /* transmitter on */
+#define LE_C0_TDMD 0x0008 /* transmit demand */
+#define LE_C0_STOP 0x0004 /* disable all external activity */
+#define LE_C0_STRT 0x0002 /* enable external activity */
+#define LE_C0_INIT 0x0001 /* begin initalization */
+
+#define LE_C0_BITS \
+ "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\
+\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"
+
+/* Control and status register 3 (csr3) */
+#define LE_C3_BSWP 0x0004 /* byte swap */
+#define LE_C3_ACON 0x0002 /* ALE control, eh? */
+#define LE_C3_BCON 0x0001 /* byte control */
+
+/* Initialzation block (mode) */
+#define LE_MODE_PROM 0x8000 /* promiscuous mode */
+/* 0x7f80 reserved, must be zero */
+/* 0x4000 - 0x0080 are not available on LANCE 7990 */
+#define LE_MODE_DRCVBC 0x4000 /* disable receive brodcast */
+#define LE_MODE_DRCVPA 0x2000 /* disable physical address detection */
+#define LE_MODE_DLNKTST 0x1000 /* disable link status */
+#define LE_MODE_DAPC 0x0800 /* disable automatic polarity correction */
+#define LE_MODE_MENDECL 0x0400 /* MENDEC loopback mode */
+#define LE_MODE_LRTTSEL 0x0200 /* lower receice threshold /
+ transmit mode selection */
+#define LE_MODE_PSEL1 0x0100 /* port selection bit1 */
+#define LE_MODE_PSEL0 0x0080 /* port selection bit0 */
+#define LE_MODE_INTL 0x0040 /* internal loopback */
+#define LE_MODE_DRTY 0x0020 /* disable retry */
+#define LE_MODE_COLL 0x0010 /* force a collision */
+#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */
+#define LE_MODE_LOOP 0x0004 /* loopback mode */
+#define LE_MODE_DTX 0x0002 /* disable transmitter */
+#define LE_MODE_DRX 0x0001 /* disable receiver */
+#define LE_MODE_NORMAL 0 /* none of the above */
+
+/* Receive message descriptor 1 (rmd1_bits) */
+#define LE_R1_OWN 0x80 /* LANCE owns the packet */
+#define LE_R1_ERR 0x40 /* error summary */
+#define LE_R1_FRAM 0x20 /* framing error */
+#define LE_R1_OFLO 0x10 /* overflow error */
+#define LE_R1_CRC 0x08 /* CRC error */
+#define LE_R1_BUFF 0x04 /* buffer error */
+#define LE_R1_STP 0x02 /* start of packet */
+#define LE_R1_ENP 0x01 /* end of packet */
+
+#define LE_R1_BITS \
+ "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP"
+
+/* Transmit message descriptor 1 (tmd1_bits) */
+#define LE_T1_OWN 0x80 /* LANCE owns the packet */
+#define LE_T1_ERR 0x40 /* error summary */
+#define LE_T1_MORE 0x10 /* multiple collisions */
+#define LE_T1_ONE 0x08 /* single collision */
+#define LE_T1_DEF 0x04 /* defferred transmit */
+#define LE_T1_STP 0x02 /* start of packet */
+#define LE_T1_ENP 0x01 /* end of packet */
+
+#define LE_T1_BITS \
+ "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP"
+
+/* Transmit message descriptor 3 (tmd3) */
+#define LE_T3_BUFF 0x8000 /* buffer error */
+#define LE_T3_UFLO 0x4000 /* underflow error */
+#define LE_T3_LCOL 0x1000 /* late collision */
+#define LE_T3_LCAR 0x0800 /* loss of carrier */
+#define LE_T3_RTRY 0x0400 /* retry error */
+#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */
+
+#define LE_XMD2_ONES 0xf000
+
+#define LE_T3_BITS \
+ "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"
+
+/*
+ * PCnet-ISA defines which are not available on LANCE 7990
+ */
+
+/* (ISA) Bus Configuration Registers */
+#define LE_BCR_MSRDA 0x0000
+#define LE_BCR_MSWRA 0x0001
+#define LE_BCR_MC 0x0002
+#define LE_BCR_LED1 0x0005
+#define LE_BCR_LED2 0x0006
+#define LE_BCR_LED3 0x0007
+
+/* Bus configurations bits (MC) */
+#define LE_MC_EADISEL 0x0008 /* EADI selection */
+#define LE_MC_AWAKE 0x0004 /* auto-wake */
+#define LE_MC_ASEL 0x0002 /* auto selection */
+#define LE_MC_XMAUSEL 0x0001 /* external MAU selection */
+
+/* LED bis (LED[123]) */
+#define LE_LED_LEDOUT 0x8000
+#define LE_LED_PSE 0x0080
+#define LE_LED_XMTE 0x0010
+#define LE_LED_PVPE 0x0008
+#define LE_LED_PCVE 0x0004
+#define LE_LED_JABE 0x0002
+#define LE_LED_COLE 0x0001
diff --git a/sys/alpha/tc/am7990var.h b/sys/alpha/tc/am7990var.h
new file mode 100644
index 0000000..cce6c25
--- /dev/null
+++ b/sys/alpha/tc/am7990var.h
@@ -0,0 +1,208 @@
+/* $Id$ */
+/* $NetBSD: am7990var.h,v 1.18 1998/01/12 09:23:16 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1995 Charles M. Hannum. 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 Charles M. Hannum.
+ * 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.
+ */
+
+#ifdef DDB
+#define integrate
+#define hide
+#else
+#define integrate static __inline
+#define hide static
+#endif
+
+/*
+ * Ethernet software status per device.
+ *
+ * Each interface is referenced by a network interface structure,
+ * ethercom.ec_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ *
+ * NOTE: this structure MUST be the first element in machine-dependent
+ * le_softc structures! This is designed SPECIFICALLY to make it possible
+ * to simply cast a "void *" to "struct le_softc *" or to
+ * "struct am7990_softc *". Among other things, this saves a lot of hair
+ * in the interrupt handlers.
+ */
+struct am7990_softc {
+ struct device sc_dev; /* base device glue */
+ struct arpcom sc_ethercom; /* Ethernet common part */
+ struct ifmedia sc_media; /* our supported media */
+
+ /*
+ * Memory functions:
+ *
+ * copy to/from descriptor
+ * copy to/from buffer
+ * zero bytes in buffer
+ */
+ void (*sc_copytodesc)
+ __P((struct am7990_softc *, void *, int, int));
+ void (*sc_copyfromdesc)
+ __P((struct am7990_softc *, void *, int, int));
+ void (*sc_copytobuf)
+ __P((struct am7990_softc *, void *, int, int));
+ void (*sc_copyfrombuf)
+ __P((struct am7990_softc *, void *, int, int));
+ void (*sc_zerobuf)
+ __P((struct am7990_softc *, int, int));
+
+ /*
+ * Machine-dependent functions:
+ *
+ * read/write CSR
+ * hardware reset hook - may be NULL
+ * hardware init hook - may be NULL
+ * no carrier hook - may be NULL
+ * media change hook - may be NULL
+ */
+ u_int16_t (*sc_rdcsr)
+ __P((struct am7990_softc *, u_int16_t));
+ void (*sc_wrcsr)
+ __P((struct am7990_softc *, u_int16_t, u_int16_t));
+ void (*sc_hwreset) __P((struct am7990_softc *));
+ void (*sc_hwinit) __P((struct am7990_softc *));
+ void (*sc_nocarrier) __P((struct am7990_softc *));
+ int (*sc_mediachange) __P((struct am7990_softc *));
+ void (*sc_mediastatus) __P((struct am7990_softc *,
+ struct ifmediareq *));
+
+ /*
+ * Media-supported by this interface. If this is NULL,
+ * the only supported media is assumed to be "manual".
+ */
+ int *sc_supmedia;
+ int sc_nsupmedia;
+ int sc_defaultmedia;
+
+ /* PCnet bit to use software selection of a port */
+ int sc_initmodemedia;
+
+ int sc_havecarrier; /* carrier status */
+
+ void *sc_sh; /* shutdownhook cookie */
+
+ u_int16_t sc_conf3; /* CSR3 value */
+ u_int16_t sc_saved_csr0;/* Value of csr0 at time of interrupt */
+
+ void *sc_mem; /* base address of RAM -- CPU's view */
+ u_long sc_addr; /* base address of RAM -- LANCE's view */
+
+ u_long sc_memsize; /* size of RAM */
+
+ int sc_nrbuf; /* number of receive buffers */
+ int sc_ntbuf; /* number of transmit buffers */
+ int sc_last_rd;
+ int sc_first_td, sc_last_td, sc_no_td;
+
+ int sc_initaddr;
+ int sc_rmdaddr;
+ int sc_tmdaddr;
+ int *sc_rbufaddr;
+ int *sc_tbufaddr;
+
+#ifdef LEDEBUG
+ int sc_debug;
+#endif
+ u_int8_t sc_enaddr[6];
+ u_int8_t sc_pad[2];
+ int unit;
+#if NRND > 0
+ rndsource_element_t rnd_source;
+#endif
+};
+
+void am7990_config __P((struct am7990_softc *));
+void am7990_init __P((struct am7990_softc *));
+int am7990_ioctl __P((struct ifnet *, u_long, caddr_t));
+void am7990_meminit __P((struct am7990_softc *));
+void am7990_reset __P((struct am7990_softc *));
+void am7990_setladrf __P((struct arpcom *, u_int16_t *));
+void am7990_start __P((struct ifnet *));
+void am7990_stop __P((struct am7990_softc *));
+void am7990_watchdog __P((struct ifnet *));
+void am7990_intr __P((void *));
+
+/*
+ * The following functions are only useful on certain cpu/bus
+ * combinations. They should be written in assembly language for
+ * maximum efficiency, but machine-independent versions are provided
+ * for drivers that have not yet been optimized.
+ */
+void am7990_copytobuf_contig __P((struct am7990_softc *, void *, int, int));
+void am7990_copyfrombuf_contig __P((struct am7990_softc *, void *, int, int));
+void am7990_zerobuf_contig __P((struct am7990_softc *, int, int));
+
+#if 0 /* Example only - see am7990.c */
+void am7990_copytobuf_gap2 __P((struct am7990_softc *, void *, int, int));
+void am7990_copyfrombuf_gap2 __P((struct am7990_softc *, void *, int, int));
+void am7990_zerobuf_gap2 __P((struct am7990_softc *, int, int));
+
+void am7990_copytobuf_gap16 __P((struct am7990_softc *, void *, int, int));
+void am7990_copyfrombuf_gap16 __P((struct am7990_softc *, void *, int, int));
+void am7990_zerobuf_gap16 __P((struct am7990_softc *, int, int));
+#endif /* Example only */
diff --git a/sys/alpha/tc/ascvar.h b/sys/alpha/tc/ascvar.h
new file mode 100644
index 0000000..7132925
--- /dev/null
+++ b/sys/alpha/tc/ascvar.h
@@ -0,0 +1,92 @@
+/* $Id$ */
+/* $NetBSD: ascvar.h,v 1.4 1997/11/28 18:23:40 mhitch Exp $ */
+
+
+/*
+ * State kept for each active SCSI device.
+ */
+struct script;
+
+typedef struct scsi_state {
+ struct script *script; /* saved script while processing error */
+ int statusByte; /* status byte returned during STATUS_PHASE */
+ int error; /* errno to pass back to device driver */
+ u_char *dmaBufAddr; /* DMA buffer address */
+ int dmalen; /* amount to transfer in this chunk */
+ int dmaresid; /* amount not transfered if chunk suspended */
+ int buflen; /* total remaining amount of data to transfer */
+ char *buf; /* current pointer within scsicmd->buf */
+ int flags; /* see below */
+ int msglen; /* number of message bytes to read */
+ int msgcnt; /* number of message bytes received */
+ u_char sync_period; /* DMA synchronous period */
+ u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */
+ u_char msg_out; /* next MSG_OUT byte to send */
+ u_char msg_in[16]; /* buffer for multibyte messages */
+} State;
+
+/* state flags */
+#define DISCONN 0x001 /* true if currently disconnected from bus */
+#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
+#define DMA_IN 0x004 /* true if reading from SCSI device */
+#define DMA_RESUME 0x08 /* true if DMA was interrupted by disc. */
+#define DMA_OUT 0x010 /* true if writing to SCSI device */
+#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
+#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
+#define PARITY_ERR 0x080 /* true if parity error seen */
+#define CHECK_SENSE 0x100 /* true if doing sense command */
+
+
+/*
+ * State kept for each active SCSI host interface (53C94).
+ */
+
+struct asc_softc {
+ struct device sc_dev; /* us as a device */
+ asc_regmap_t *regs; /* chip address */
+ volatile int *dmar; /* DMA address register address */
+ int sc_id; /* SCSI ID of this interface */
+ int myidmask; /* ~(1 << myid) */
+ int state; /* current SCSI connection state */
+ int target; /* target SCSI ID if busy */
+ struct script *script; /* next expected interrupt & action */
+ ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */
+ State st[ASC_NCMD]; /* state info for each active command */
+ /* Start dma routine */
+ int (*dma_start) __P((struct asc_softc *asc,
+ struct scsi_state *state,
+ caddr_t cp, int flag, int len, int off));
+ /* End dma routine */
+ void (*dma_end) __P((struct asc_softc *asc,
+ struct scsi_state *state, int flag));
+
+ u_char *dma_next;
+ int dma_xfer; /* Dma len still to go */
+ int min_period; /* Min transfer period clk/byte */
+ int max_period; /* Max transfer period clk/byte */
+ int ccf; /* CCF, whatever that really is? */
+ int timeout_250; /* 250ms timeout */
+ int tb_ticks; /* 4ns. ticks/tb channel ticks */
+#ifdef USE_NEW_SCSI
+ struct scsipi_link sc_link; /* scsipi link struct */
+#endif
+};
+typedef struct asc_softc *asc_softc_t;
+
+#define ASC_STATE_IDLE 0 /* idle state */
+#define ASC_STATE_BUSY 1 /* selecting or currently connected */
+#define ASC_STATE_TARGET 2 /* currently selected as target */
+#define ASC_STATE_RESEL 3 /* currently waiting for reselect */
+
+
+#define ASC_SPEED_25_MHZ 250
+#define ASC_SPEED_12_5_MHZ 125
+
+void ascattach __P((struct asc_softc *asc, int bus_speed));
+int asc_intr __P ((void *asc));
+
+/*
+ * Dma operations.
+ */
+#define ASCDMA_READ 1
+#define ASCDMA_WRITE 2
diff --git a/sys/alpha/tc/esp.c b/sys/alpha/tc/esp.c
new file mode 100644
index 0000000..1a860c2
--- /dev/null
+++ b/sys/alpha/tc/esp.c
@@ -0,0 +1,1898 @@
+/* $Id$ */
+/* $NetBSD: esp.c,v 1.8.4.2 1996/09/10 17:28:16 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Peter Galbavy
+ * Copyright (c) 1995 Paul Kranenburg
+ * 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 Peter Galbavy
+ * 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.
+ */
+
+/*
+ * Based on aic6360 by Jarle Greipsland
+ *
+ * Acknowledgements: Many of the algorithms used in this driver are
+ * inspired by the work of Julian Elischer (julian@tfs.com) and
+ * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+
+#include <sys/errno.h>
+/*#include <sys/ioctl.h>*/
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+/*#include <sys/user.h>*/
+#include <sys/queue.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
+
+#include <machine/cpu.h>
+#include <machine/clock.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdsreg.h>
+#include <alpha/tc/tcdsvar.h>
+#include <alpha/tc/espreg.h>
+#include <alpha/tc/espvar.h>
+
+int esp_debug = 0; /*ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS;*/
+
+/*static*/ void espattach __P((struct device *, struct device *, void *));
+/*static*/ int espmatch __P((struct device *, void *, void *));
+/*static*/ int espprint __P((void *, char *));
+/*static*/ u_int esp_adapter_info __P((struct esp_softc *));
+/*static*/ void espreadregs __P((struct esp_softc *));
+/*static*/ void espselect __P((struct esp_softc *,
+ u_char, u_char, u_char *, u_char));
+/*static*/ void esp_scsi_reset __P((struct esp_softc *));
+/*static*/ void esp_reset __P((struct esp_softc *));
+/*static*/ void esp_init __P((struct esp_softc *, int));
+/*static*/ int esp_scsi_cmd __P((struct scsi_xfer *));
+/*static*/ int esp_poll __P((struct esp_softc *, struct ecb *));
+/*static*/ void esp_sched __P((struct esp_softc *));
+/*static*/ void esp_done __P((struct ecb *));
+/*static*/ void esp_msgin __P((struct esp_softc *));
+/*static*/ void esp_msgout __P((struct esp_softc *));
+/*static*/ int espintr __P((struct esp_softc *));
+/*static*/ void esp_timeout __P((void *arg));
+/*static*/ void esp_abort __P((struct esp_softc *, struct ecb *));
+static u_int32_t esp_info __P((int));
+int esp_stp2cpb __P((struct esp_softc *, int));
+int esp_cpb2stp __P((struct esp_softc *, int));
+
+static void esp_min_phys (struct buf *);
+static int esp_probe(device_t dev);
+static int esp_attach(device_t dev);
+static device_method_t esp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, esp_probe),
+ DEVMETHOD(device_attach, esp_attach),
+ {0, 0}
+};
+#define ESP_SOFTC(dev) (struct esp_softc*) device_get_softc(dev)
+static driver_t esp_driver = {
+ "esp",
+ esp_methods,
+ DRIVER_TYPE_BIO,
+ sizeof(struct esp_softc),
+};
+
+
+struct scsi_adapter esp_switch = {
+ esp_scsi_cmd,
+ esp_min_phys, /* no max at this level; handled by DMA code */
+ NULL,
+ NULL,
+ esp_info,
+ "esp",
+};
+
+struct scsi_device esp_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+static devclass_t esp_devclass;
+DRIVER_MODULE(esp, tcds, esp_driver, esp_devclass, 0, 0);
+
+static int
+esp_probe(device_t dev)
+{
+ if(strcmp(device_get_name(device_get_parent(dev)),"tcds")){
+ return ENXIO;
+ } else {
+ device_set_desc(dev,"NCR53C94");
+ return(0);
+ }
+}
+
+/*
+ * Attach this instance, and then all the sub-devices
+ */
+int
+esp_attach(device_t dev)
+{
+ struct esp_softc *sc = device_get_softc(dev);
+ struct tcdsdev_attach_args *tcdsdev = device_get_ivars(dev);
+ struct scsibus_data *scbus;
+
+ sc->sc_reg = (volatile u_int32_t *)tcdsdev->tcdsda_addr;
+ sc->sc_cookie = tcdsdev->tcdsda_cookie;
+ sc->sc_dma = tcdsdev->tcdsda_sc;
+
+ tcds_intr_establish(device_get_parent(dev), sc->sc_cookie, 0,(int (*)(void *))espintr, sc);
+
+/* if (parent->dv_cfdata->cf_driver == &tcds_cd) {
+ sc->sc_id = tcdsdev->tcdsda_id;
+ sc->sc_freq = tcdsdev->tcdsda_freq;
+ } else*/ {
+ /* XXX */
+ sc->sc_id = 7;
+ sc->sc_freq = 25000000;
+ }
+
+ /* gimme Mhz */
+ sc->sc_freq /= 1000000;
+ sc->sc_dma->sc_esp = sc; /* XXX */
+
+ /*
+ * It is necessary to try to load the 2nd config register here,
+ * to find out what rev the esp chip is, else the esp_reset
+ * will not set up the defaults correctly.
+ */
+ sc->sc_cfg1 = sc->sc_id | ESPCFG1_PARENB;
+ sc->sc_cfg2 = ESPCFG2_SCSI2;
+ sc->sc_cfg3 = 0x4; /* Save residual byte. XXX??? */
+ sc->sc_rev = NCR53C94;
+
+ /*
+ * This is the value used to start sync negotiations
+ * Note that the ESP register "SYNCTP" is programmed
+ * in "clocks per byte", and has a minimum value of 4.
+ * The SCSI period used in negotiation is one-fourth
+ * of the time (in nanoseconds) needed to transfer one byte.
+ * Since the chip's clock is given in MHz, we have the following
+ * formula: 4 * period = (1000 / freq) * 4
+ */
+ sc->sc_minsync = 1000 / sc->sc_freq;
+
+ sc->sc_maxxfer = 64 * 1024;
+ sc->sc_ccf = FREQTOCCF(sc->sc_freq);
+
+ /* The value *must not* be == 1. Make it 2 */
+ if (sc->sc_ccf == 1)
+ sc->sc_ccf = 2;
+
+ /*
+ * The recommended timeout is 250ms. This register is loaded
+ * with a value calculated as follows, from the docs:
+ *
+ * (timout period) x (CLK frequency)
+ * reg = -------------------------------------
+ * 8192 x (Clock Conversion Factor)
+ *
+ * Since CCF has a linear relation to CLK, this generally computes
+ * to the constant of 153.
+ */
+ sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf);
+
+ /* CCF register only has 3 bits; 0 is actually 8 */
+ sc->sc_ccf &= 7;
+
+ /* Reset state & bus */
+ sc->sc_state = 0;
+ esp_init(sc, 1);
+
+ printf("esp%d: %dMhz, target %d\n", device_get_unit(dev),sc->sc_freq, sc->sc_id);
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_targ = sc->sc_id;
+ sc->sc_link.adapter = &esp_switch;
+ sc->sc_link.device = &esp_dev;
+/* sc->sc_link.openings = 2;*/
+ sc->sc_link.fordriver = 0;
+
+ /*
+ * If the boot path is "esp" at the moment and it's me, then
+ * walk our pointer to the sub-device, ready for the config
+ * below.
+ */
+ /*
+ * Now try to attach all the sub-devices
+ */
+/* config_found(self, &sc->sc_link, espprint);*/
+ scbus = scsi_alloc_bus();
+ if(!scbus)
+ return ENXIO;
+ scbus->adapter_link = &sc->sc_link;
+
+ scbus->maxtarg = 7;
+
+ if (bootverbose) {
+ unsigned t_from = 0;
+ unsigned t_to = scbus->maxtarg;
+ unsigned myaddr = sc->sc_id;
+
+ char *txt_and = "";
+ printf ("esp%d scanning for targets ", device_get_unit(dev));
+ if (t_from < myaddr) {
+ printf ("%d..%d ", t_from, myaddr -1);
+ txt_and = "and ";
+ }
+ if (myaddr < t_to)
+ printf ("%s%d..%d ", txt_and, myaddr +1, t_to);
+ }
+
+ scsi_attachdevs (scbus);
+ scbus = NULL; /* Upper-level SCSI code owns this now */
+
+
+ return 0;
+}
+
+/*
+ * This is the generic esp reset function. It does not reset the SCSI bus,
+ * only this controllers, but kills any on-going commands, and also stops
+ * and resets the DMA.
+ *
+ * After reset, registers are loaded with the defaults from the attach
+ * routine above.
+ */
+void
+esp_reset(sc)
+ struct esp_softc *sc;
+{
+
+ /* reset DMA first */
+ DMA_RESET(sc->sc_dma);
+
+ /* reset SCSI chip */
+ ESPCMD(sc, ESPCMD_RSTCHIP);
+ ESPCMD(sc, ESPCMD_NOP);
+ DELAY(500);
+
+ /* do these backwards, and fall through */
+ switch (sc->sc_rev) {
+ case NCR53C94:
+ case ESP200:
+ ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3);
+ case ESP100A:
+ ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2);
+ case ESP100:
+ ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1);
+ ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf);
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout);
+ break;
+ default:
+ printf("%s: unknown revision code, assuming ESP100\n",
+ sc->sc_dev.dv_xname);
+ ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1);
+ ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf);
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout);
+ }
+}
+
+/*
+ * Reset the SCSI bus, but not the chip
+ */
+void
+esp_scsi_reset(sc)
+ struct esp_softc *sc;
+{
+ /*
+ * XXX STOP DMA FIRST
+ */
+
+ printf("esp: resetting SCSI bus\n");
+ ESPCMD(sc, ESPCMD_RSTSCSI);
+}
+
+u_int32_t esp_info (int unit)
+{
+ return (1); /* may be changed later */
+}
+
+
+
+/*
+ * Initialize esp state machine
+ */
+void
+esp_init(sc, doreset)
+ struct esp_softc *sc;
+ int doreset;
+{
+ struct ecb *ecb;
+ int r;
+
+ ESP_TRACE(("[ESP_INIT(%d)] ", doreset));
+
+ if (sc->sc_state == 0) { /* First time through */
+ TAILQ_INIT(&sc->ready_list);
+ TAILQ_INIT(&sc->nexus_list);
+ TAILQ_INIT(&sc->free_list);
+ sc->sc_nexus = NULL;
+ ecb = sc->sc_ecb;
+ bzero(ecb, sizeof(sc->sc_ecb));
+ for (r = 0; r < sizeof(sc->sc_ecb) / sizeof(*ecb); r++) {
+ TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QFREE);
+ ecb++;
+ }
+ bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ } else {
+ sc->sc_flags |= ESP_ABORTING;
+ sc->sc_state = ESP_IDLE;
+ ecb = sc->sc_nexus;
+ if (ecb != NULL) {
+ ecb->xs->error = XS_TIMEOUT;
+ esp_done(ecb);
+ sc->sc_nexus = NULL;
+ }
+ while ((ecb = sc->nexus_list.tqh_first) != NULL) {
+ ecb->xs->error = XS_TIMEOUT;
+ esp_done(ecb);
+ }
+ }
+
+ /*
+ * reset the chip to a known state
+ */
+ esp_reset(sc);
+
+ sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
+ for (r = 0; r < 8; r++) {
+ struct esp_tinfo *tp = &sc->sc_tinfo[r];
+/* XXX - config flags per target: low bits: no reselect; high bits: no synch */
+/* int fl = sc->sc_dev.dv_cfdata->cf_flags;*/
+int fl=0;
+ tp->flags = ((sc->sc_minsync && !(fl & (1<<(r+8))))
+ ? T_NEGOTIATE : 0) |
+ ((fl & (1<<r)) ? T_RSELECTOFF : 0) |
+ T_NEED_TO_RESET;
+ tp->period = sc->sc_minsync;
+ tp->offset = 0;
+ }
+ sc->sc_flags &= ~ESP_ABORTING;
+
+ if (doreset) {
+ sc->sc_state = ESP_SBR;
+ ESPCMD(sc, ESPCMD_RSTSCSI);
+ return;
+ }
+
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ return;
+}
+
+/*
+ * Read the ESP registers, and save their contents for later use.
+ * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading
+ * ESP_INTR - so make sure it is the last read.
+ *
+ * I think that (from reading the docs) most bits in these registers
+ * only make sense when he DMA CSR has an interrupt showing. Call only
+ * if an interrupt is pending.
+ */
+void
+espreadregs(sc)
+ struct esp_softc *sc;
+{
+
+ sc->sc_espstat = ESP_READ_REG(sc, ESP_STAT);
+ /* Only the stepo bits are of interest */
+ sc->sc_espstep = ESP_READ_REG(sc, ESP_STEP) & ESPSTEP_MASK;
+ sc->sc_espintr = ESP_READ_REG(sc, ESP_INTR);
+
+ /* Clear the TCDS interrupt bit. */
+ (void)tcds_scsi_isintr(sc->sc_dma, 1);
+
+ /*
+ * Determine the SCSI bus phase, return either a real SCSI bus phase
+ * or some pseudo phase we use to detect certain exceptions.
+ */
+
+ sc->sc_phase = (sc->sc_espintr & ESPINTR_DIS)
+ ? /* Disconnected */ BUSFREE_PHASE
+ : sc->sc_espstat & ESPSTAT_PHASE;
+
+ ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ",
+ sc->sc_espintr, sc->sc_espstat, sc->sc_espstep));
+}
+
+/*
+ * Convert Synchronous Transfer Period to chip register Clock Per Byte value.
+ */
+int
+esp_stp2cpb(sc, period)
+ struct esp_softc *sc;
+ int period;
+{
+ int v;
+ v = (sc->sc_freq * period) / 250;
+ if (esp_cpb2stp(sc, v) < period)
+ /* Correct round-down error */
+ v++;
+ return v;
+}
+
+/*
+ * Convert chip register Clock Per Byte value to Synchronous Transfer Period.
+ */
+int
+esp_cpb2stp(sc, cpb)
+ struct esp_softc *sc;
+ int cpb;
+{
+ return ((250 * cpb) / sc->sc_freq);
+}
+
+/*
+ * Send a command to a target, set the driver state to ESP_SELECTING
+ * and let the caller take care of the rest.
+ *
+ * Keeping this as a function allows me to say that this may be done
+ * by DMA instead of programmed I/O soon.
+ */
+void
+espselect(sc, target, lun, cmd, clen)
+ struct esp_softc *sc;
+ u_char target, lun;
+ u_char *cmd;
+ u_char clen;
+{
+ struct esp_tinfo *ti = &sc->sc_tinfo[target];
+ int i;
+
+ ESP_TRACE(("[espselect(t%d,l%d,cmd:%x)] ", target, lun, *(u_char *)cmd));
+
+ /* new state ESP_SELECTING */
+ sc->sc_state = ESP_SELECTING;
+
+ ESPCMD(sc, ESPCMD_FLUSH);
+
+ /*
+ * The docs say the target register is never reset, and I
+ * can't think of a better place to set it
+ */
+ ESP_WRITE_REG(sc, ESP_SELID, target);
+ if (ti->flags & T_SYNCMODE) {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, esp_stp2cpb(sc, ti->period));
+ } else {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, 0);
+ }
+
+ /*
+ * Who am I. This is where we tell the target that we are
+ * happy for it to disconnect etc.
+ */
+ ESP_WRITE_REG(sc, ESP_FIFO,
+ MSG_IDENTIFY(lun, (ti->flags & T_RSELECTOFF)?0:1));
+
+ if (ti->flags & T_NEGOTIATE) {
+ /* Arbitrate, select and stop after IDENTIFY message */
+ ESPCMD(sc, ESPCMD_SELATNS);
+ return;
+ }
+
+ /* Now the command into the FIFO */
+ for (i = 0; i < clen; i++)
+ ESP_WRITE_REG(sc, ESP_FIFO, *cmd++);
+
+ /* And get the targets attention */
+ ESPCMD(sc, ESPCMD_SELATN);
+}
+
+/*
+ * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
+ */
+
+/*
+ * Start a SCSI-command
+ * This function is called by the higher level SCSI-driver to queue/run
+ * SCSI-commands.
+ */
+int
+esp_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct esp_softc *sc = sc_link->adapter_softc;
+ struct ecb *ecb;
+ int s, flags;
+
+ ESP_TRACE(("[esp_scsi_cmd] "));
+ ESP_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
+ sc_link->target));
+
+ flags = xs->flags;
+
+ /* Get a esp command block */
+ s = splbio();
+ ecb = sc->free_list.tqh_first;
+ if (ecb) {
+ TAILQ_REMOVE(&sc->free_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNONE);
+ }
+ splx(s);
+
+ if (ecb == NULL) {
+ ESP_MISC(("TRY_AGAIN_LATER"));
+ return TRY_AGAIN_LATER;
+ }
+
+ /* Initialize ecb */
+ ecb->xs = xs;
+ bcopy(xs->cmd, &ecb->cmd, xs->cmdlen);
+ ecb->clen = xs->cmdlen;
+ ecb->daddr = xs->data;
+ ecb->dleft = xs->datalen;
+ ecb->stat = 0;
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QREADY);
+ ecb->timeout_ch = timeout(esp_timeout, ecb, (xs->timeout*hz)/1000);
+
+ if (sc->sc_state == ESP_IDLE)
+ esp_sched(sc);
+
+ splx(s);
+
+ if (flags & SCSI_NOMASK) {
+ /* Not allowed to use interrupts, use polling instead */
+ return esp_poll(sc, ecb);
+ }
+
+ ESP_MISC(("SUCCESSFULLY_QUEUED"));
+ return SUCCESSFULLY_QUEUED;
+}
+
+/*
+ * Used when interrupt driven I/O isn't allowed, e.g. during boot.
+ */
+int
+esp_poll(sc, ecb)
+ struct esp_softc *sc;
+ struct ecb *ecb;
+{
+ struct scsi_xfer *xs = ecb->xs;
+ int count = xs->timeout * 100;
+
+ ESP_TRACE(("[esp_poll] "));
+ while (count) {
+ if (DMA_ISINTR(sc->sc_dma)) {
+ espintr(sc);
+ }
+#if alternatively
+ if (ESP_READ_REG(sc, ESP_STAT) & ESPSTAT_INT)
+ espintr(sc);
+#endif
+ if (xs->flags & ITSDONE)
+ break;
+ DELAY(10);
+ if (sc->sc_state == ESP_IDLE) {
+ ESP_TRACE(("[esp_poll: rescheduling] "));
+ esp_sched(sc);
+ }
+ count--;
+ }
+
+ if (count == 0) {
+ ESP_MISC(("esp_poll: timeout"));
+ esp_timeout((caddr_t)ecb);
+ }
+
+ return COMPLETE;
+}
+
+
+/*
+ * LOW LEVEL SCSI UTILITIES
+ */
+
+/*
+ * Schedule a scsi operation. This has now been pulled out of the interrupt
+ * handler so that we may call it from esp_scsi_cmd and esp_done. This may
+ * save us an unecessary interrupt just to get things going. Should only be
+ * called when state == ESP_IDLE and at bio pl.
+ */
+void
+esp_sched(sc)
+ struct esp_softc *sc;
+{
+ struct scsi_link *sc_link;
+ struct ecb *ecb;
+ int t;
+
+ ESP_TRACE(("[esp_sched] "));
+ if (sc->sc_state != ESP_IDLE)
+ panic("esp_sched: not IDLE (state=%d)", sc->sc_state);
+
+ if (sc->sc_flags & ESP_ABORTING)
+ return;
+
+ /*
+ * Find first ecb in ready queue that is for a target/lunit
+ * combinations that is not busy.
+ */
+ for (ecb = sc->ready_list.tqh_first; ecb; ecb = ecb->chain.tqe_next) {
+ sc_link = ecb->xs->sc_link;
+ t = sc_link->target;
+ if (!(sc->sc_tinfo[t].lubusy & (1 << sc_link->lun))) {
+ struct esp_tinfo *ti = &sc->sc_tinfo[t];
+
+ if ((ecb->flags & ECB_QBITS) != ECB_QREADY)
+ panic("esp: busy entry on ready list");
+ TAILQ_REMOVE(&sc->ready_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNONE);
+ sc->sc_nexus = ecb;
+ sc->sc_flags = 0;
+ sc->sc_prevphase = INVALID_PHASE;
+ sc->sc_dp = ecb->daddr;
+ sc->sc_dleft = ecb->dleft;
+ ti->lubusy |= (1<<sc_link->lun);
+/*XXX*/if (sc->sc_msgpriq) {
+ printf("esp: message queue not empty: %x!\n", sc->sc_msgpriq);
+}
+/*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0;
+ espselect(sc, t, sc_link->lun,
+ (u_char *)&ecb->cmd, ecb->clen);
+ break;
+ } else
+ ESP_MISC(("%d:%d busy\n", t, sc_link->lun));
+ }
+}
+
+/*
+ * POST PROCESSING OF SCSI_CMD (usually current)
+ */
+void
+esp_done(ecb)
+ struct ecb *ecb;
+{
+ struct scsi_xfer *xs = ecb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct esp_softc *sc = sc_link->adapter_softc;
+ struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target];
+
+ ESP_TRACE(("[esp_done(error:%x)] ", xs->error));
+
+ untimeout(esp_timeout, ecb, ecb->timeout_ch);
+
+ /*
+ * Now, if we've come here with no error code, i.e. we've kept the
+ * initial XS_NOERROR, and the status code signals that we should
+ * check sense, we'll need to set up a request sense cmd block and
+ * push the command back into the ready queue *before* any other
+ * commands for this target/lunit, else we lose the sense info.
+ * We don't support chk sense conditions for the request sense cmd.
+ */
+ if (xs->error == XS_NOERROR) {
+ if ((ecb->flags & ECB_ABORTED) != 0) {
+ xs->error = XS_TIMEOUT;
+ } else if ((ecb->flags & ECB_CHKSENSE) != 0) {
+ xs->error = XS_SENSE;
+ } else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
+ struct scsi_sense *ss = (void *)&ecb->cmd;
+ ESP_MISC(("requesting sense "));
+ /* First, save the return values */
+ xs->resid = ecb->dleft;
+ xs->status = ecb->stat;
+ /* Next, setup a request sense command block */
+ bzero(ss, sizeof(*ss));
+ ss->op_code = REQUEST_SENSE;
+ /*ss->byte2 = sc_link->lun << 5;*/
+ ss->length = sizeof(struct scsi_sense_data);
+ ecb->clen = sizeof(*ss);
+ ecb->daddr = (char *)&xs->sense;
+ ecb->dleft = sizeof(struct scsi_sense_data);
+ ecb->flags |= ECB_CHKSENSE;
+/*XXX - must take off queue here */
+ if (ecb != sc->sc_nexus) {
+ panic("%s: esp_sched: floating ecb %p",
+ sc->sc_dev.dv_xname, ecb);
+ }
+ TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QREADY);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ ti->senses++;
+ timeout(esp_timeout, ecb, (xs->timeout*hz)/1000);
+ if (sc->sc_nexus == ecb) {
+ sc->sc_nexus = NULL;
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ }
+ return;
+ } else {
+ xs->resid = ecb->dleft;
+ }
+ }
+
+ xs->flags |= ITSDONE;
+
+#ifdef ESP_DEBUG
+ if (esp_debug & ESP_SHOWMISC) {
+ printf("err=0x%02x ",xs->error);
+ if (xs->error == XS_SENSE) {
+ printf("sense=%2x; ", xs->sense.error_code);
+ }
+ }
+ if ((xs->resid || xs->error > XS_SENSE) && esp_debug & ESP_SHOWMISC) {
+ if (xs->resid)
+ printf("esp_done: resid=%d\n", xs->resid);
+ if (xs->error)
+ printf("esp_done: error=%d\n", xs->error);
+ }
+#endif
+
+ /*
+ * Remove the ECB from whatever queue it's on.
+ */
+ switch (ecb->flags & ECB_QBITS) {
+ case ECB_QNONE:
+ if (ecb != sc->sc_nexus) {
+ panic("%s: floating ecb", sc->sc_dev.dv_xname);
+ }
+ sc->sc_nexus = NULL;
+ sc->sc_state = ESP_IDLE;
+ ti->lubusy &= ~(1<<sc_link->lun);
+ esp_sched(sc);
+ break;
+ case ECB_QREADY:
+ TAILQ_REMOVE(&sc->ready_list, ecb, chain);
+ break;
+ case ECB_QNEXUS:
+ TAILQ_REMOVE(&sc->nexus_list, ecb, chain);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ break;
+ case ECB_QFREE:
+ panic("%s: dequeue: busy ecb on free list",
+ sc->sc_dev.dv_xname);
+ break;
+ default:
+ panic("%s: dequeue: unknown queue %d",
+ sc->sc_dev.dv_xname, ecb->flags & ECB_QBITS);
+ }
+
+ /* Put it on the free list, and clear flags. */
+ TAILQ_INSERT_HEAD(&sc->free_list, ecb, chain);
+ ecb->flags = ECB_QFREE;
+
+ ti->cmds++;
+ scsi_done(xs);
+ return;
+}
+
+/*
+ * INTERRUPT/PROTOCOL ENGINE
+ */
+
+/*
+ * Schedule an outgoing message by prioritizing it, and asserting
+ * attention on the bus. We can only do this when we are the initiator
+ * else there will be an illegal command interrupt.
+ */
+#define esp_sched_msgout(m) \
+ do { \
+ ESP_MISC(("esp_sched_msgout %d ", m)); \
+ ESPCMD(sc, ESPCMD_SETATN); \
+ sc->sc_msgpriq |= (m); \
+ } while (0)
+
+#define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80)
+#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
+#define ISEXTMSG(m) ((m) == 1)
+
+/*
+ * Get an incoming message as initiator.
+ *
+ * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a
+ * byte in the FIFO
+ */
+void
+esp_msgin(sc)
+ register struct esp_softc *sc;
+{
+ register int v;
+
+ ESP_TRACE(("[esp_msgin(curmsglen:%d)] ", sc->sc_imlen));
+
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) == 0) {
+ printf("%s: msgin: no msg byte available\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /*
+ * Prepare for a new message. A message should (according
+ * to the SCSI standard) be transmitted in one single
+ * MESSAGE_IN_PHASE. If we have been in some other phase,
+ * then this is a new message.
+ */
+ if (sc->sc_prevphase != MESSAGE_IN_PHASE) {
+ sc->sc_flags &= ~ESP_DROP_MSGI;
+ sc->sc_imlen = 0;
+ }
+
+ v = ESP_READ_REG(sc, ESP_FIFO);
+ ESP_MISC(("<msgbyte:0x%02x>", v));
+
+#if 0
+ if (sc->sc_state == ESP_RESELECTED && sc->sc_imlen == 0) {
+ /*
+ * Which target is reselecting us? (The ID bit really)
+ */
+ sc->sc_selid = v;
+ sc->sc_selid &= ~(1<<sc->sc_id);
+ ESP_MISC(("selid=0x%2x ", sc->sc_selid));
+ return;
+ }
+#endif
+
+ sc->sc_imess[sc->sc_imlen] = v;
+
+ /*
+ * If we're going to reject the message, don't bother storing
+ * the incoming bytes. But still, we need to ACK them.
+ */
+
+ if ((sc->sc_flags & ESP_DROP_MSGI)) {
+ ESPCMD(sc, ESPCMD_SETATN);
+ ESPCMD(sc, ESPCMD_MSGOK);
+ printf("<dropping msg byte %x>",
+ sc->sc_imess[sc->sc_imlen]);
+ return;
+ }
+
+ if (sc->sc_imlen >= ESP_MAX_MSG_LEN) {
+ esp_sched_msgout(SEND_REJECT);
+ sc->sc_flags |= ESP_DROP_MSGI;
+ } else {
+ sc->sc_imlen++;
+ /*
+ * This testing is suboptimal, but most
+ * messages will be of the one byte variety, so
+ * it should not effect performance
+ * significantly.
+ */
+ if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
+ sc->sc_imlen == sc->sc_imess[1] + 2)
+ goto gotit;
+ }
+ /* Ack what we have so far */
+ ESPCMD(sc, ESPCMD_MSGOK);
+ return;
+
+gotit:
+ ESP_MSGS(("gotmsg(%x)", sc->sc_imess[0]));
+ /*
+ * Now we should have a complete message (1 byte, 2 byte
+ * and moderately long extended messages). We only handle
+ * extended messages which total length is shorter than
+ * ESP_MAX_MSG_LEN. Longer messages will be amputated.
+ */
+ if (sc->sc_state == ESP_HASNEXUS) {
+ struct ecb *ecb = sc->sc_nexus;
+ struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+
+ switch (sc->sc_imess[0]) {
+ case MSG_CMDCOMPLETE:
+ ESP_MSGS(("cmdcomplete "));
+ if (sc->sc_dleft < 0) {
+ struct scsi_link *sc_link = ecb->xs->sc_link;
+ printf("esp: %d extra bytes from %d:%d\n",
+ -sc->sc_dleft,
+ sc_link->target, sc_link->lun);
+ sc->sc_dleft = 0;
+ }
+ ecb->xs->resid = ecb->dleft = sc->sc_dleft;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ break;
+
+ case MSG_MESSAGE_REJECT:
+ if (esp_debug & ESP_SHOWMSGS)
+ printf("%s: our msg rejected by target\n",
+ sc->sc_dev.dv_xname);
+#if 1 /* XXX - must remember last message */
+sc_print_addr(ecb->xs->sc_link); printf("MSG_MESSAGE_REJECT>>");
+#endif
+ if (sc->sc_flags & ESP_SYNCHNEGO) {
+ ti->period = ti->offset = 0;
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ ti->flags &= ~T_NEGOTIATE;
+ }
+ /* Not all targets understand INITIATOR_DETECTED_ERR */
+ if (sc->sc_msgout == SEND_INIT_DET_ERR)
+ esp_sched_msgout(SEND_ABORT);
+ break;
+ case MSG_NOOP:
+ ESP_MSGS(("noop "));
+ break;
+ case MSG_DISCONNECT:
+ ESP_MSGS(("disconnect "));
+ ti->dconns++;
+ sc->sc_flags |= ESP_DISCON;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+#define SDEV_AUTOSAVE (0x01)
+ if ((ecb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
+ break;
+ /*FALLTHROUGH*/
+ case MSG_SAVEDATAPOINTER:
+ ESP_MSGS(("save datapointer "));
+ ecb->dleft = sc->sc_dleft;
+ ecb->daddr = sc->sc_dp;
+ break;
+ case MSG_RESTOREPOINTERS:
+ ESP_MSGS(("restore datapointer "));
+ if (!ecb) {
+ esp_sched_msgout(SEND_ABORT);
+ printf("%s: no DATAPOINTERs to restore\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ sc->sc_dp = ecb->daddr;
+ sc->sc_dleft = ecb->dleft;
+ break;
+ case MSG_PARITY_ERROR:
+ printf("%s:target%d: MSG_PARITY_ERROR\n",
+ sc->sc_dev.dv_xname,
+ ecb->xs->sc_link->target);
+ break;
+ case MSG_EXTENDED:
+ ESP_MSGS(("extended(%x) ", sc->sc_imess[2]));
+ switch (sc->sc_imess[2]) {
+ case MSG_EXT_SDTR:
+ ESP_MSGS(("SDTR period %d, offset %d ",
+ sc->sc_imess[3], sc->sc_imess[4]));
+ ti->period = sc->sc_imess[3];
+ ti->offset = sc->sc_imess[4];
+ if (sc->sc_minsync == 0) {
+ /* We won't do synch */
+ ti->offset = 0;
+ esp_sched_msgout(SEND_SDTR);
+ } else if (ti->offset == 0) {
+ printf("%s:%d: async\n", "esp",
+ ecb->xs->sc_link->target);
+ ti->offset = 0;
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ } else if (ti->period > 124) {
+ printf("%s:%d: async\n", "esp",
+ ecb->xs->sc_link->target);
+ ti->offset = 0;
+ esp_sched_msgout(SEND_SDTR);
+ } else {
+ int r = 250/ti->period;
+ int s = (100*250)/ti->period - 100*r;
+ int p;
+ p = esp_stp2cpb(sc, ti->period);
+ ti->period = esp_cpb2stp(sc, p);
+#ifdef ESP_DEBUG
+ sc_print_addr(ecb->xs->sc_link);
+#endif
+ if ((sc->sc_flags&ESP_SYNCHNEGO) == 0) {
+ /* Target initiated negotiation */
+ if (ti->flags & T_SYNCMODE) {
+ ti->flags &= ~T_SYNCMODE;
+#ifdef ESP_DEBUG
+ printf("renegotiated ");
+#endif
+ }
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ 0);
+ /* Clamp to our maxima */
+ if (ti->period < sc->sc_minsync)
+ ti->period = sc->sc_minsync;
+ if (ti->offset > 15)
+ ti->offset = 15;
+ esp_sched_msgout(SEND_SDTR);
+ } else {
+ /* we are sync */
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ p);
+ ti->flags |= T_SYNCMODE;
+ }
+#ifdef ESP_DEBUG
+ printf("max sync rate %d.%02dMb/s\n",
+ r, s);
+#endif
+ }
+ ti->flags &= ~T_NEGOTIATE;
+ break;
+ default: /* Extended messages we don't handle */
+ ESPCMD(sc, ESPCMD_SETATN);
+ break;
+ }
+ break;
+ default:
+ ESP_MSGS(("ident "));
+ /* thanks for that ident... */
+ if (!MSG_ISIDENTIFY(sc->sc_imess[0])) {
+ ESP_MISC(("unknown "));
+printf("%s: unimplemented message: %d\n", sc->sc_dev.dv_xname, sc->sc_imess[0]);
+ ESPCMD(sc, ESPCMD_SETATN);
+ }
+ break;
+ }
+ } else if (sc->sc_state == ESP_RESELECTED) {
+ struct scsi_link *sc_link = NULL;
+ struct ecb *ecb;
+ struct esp_tinfo *ti;
+ u_char lunit;
+
+ if (MSG_ISIDENTIFY(sc->sc_imess[0])) { /* Identify? */
+ ESP_MISC(("searching "));
+ /*
+ * Search wait queue for disconnected cmd
+ * The list should be short, so I haven't bothered with
+ * any more sophisticated structures than a simple
+ * singly linked list.
+ */
+ lunit = sc->sc_imess[0] & 0x07;
+ for (ecb = sc->nexus_list.tqh_first; ecb;
+ ecb = ecb->chain.tqe_next) {
+ sc_link = ecb->xs->sc_link;
+ if (sc_link->lun == lunit &&
+ sc->sc_selid == (1<<sc_link->target)) {
+ TAILQ_REMOVE(&sc->nexus_list, ecb,
+ chain);
+ ECB_SETQ(ecb, ECB_QNONE);
+ break;
+ }
+ }
+
+ if (!ecb) { /* Invalid reselection! */
+ esp_sched_msgout(SEND_ABORT);
+ printf("esp: invalid reselect (idbit=0x%2x)\n",
+ sc->sc_selid);
+ } else { /* Reestablish nexus */
+ /*
+ * Setup driver data structures and
+ * do an implicit RESTORE POINTERS
+ */
+ ti = &sc->sc_tinfo[sc_link->target];
+ sc->sc_nexus = ecb;
+ sc->sc_dp = ecb->daddr;
+ sc->sc_dleft = ecb->dleft;
+ sc->sc_tinfo[sc_link->target].lubusy
+ |= (1<<sc_link->lun);
+ if (ti->flags & T_SYNCMODE) {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ esp_stp2cpb(sc, ti->period));
+ } else {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, 0);
+ }
+ ESP_MISC(("... found ecb"));
+ sc->sc_state = ESP_HASNEXUS;
+ }
+ } else {
+ printf("%s: bogus reselect (no IDENTIFY) %0x2x\n",
+ sc->sc_dev.dv_xname, sc->sc_selid);
+ esp_sched_msgout(SEND_DEV_RESET);
+ }
+ } else { /* Neither ESP_HASNEXUS nor ESP_RESELECTED! */
+ printf("%s: unexpected message in; will send DEV_RESET\n",
+ sc->sc_dev.dv_xname);
+ esp_sched_msgout(SEND_DEV_RESET);
+ }
+
+ /* Ack last message byte */
+ ESPCMD(sc, ESPCMD_MSGOK);
+
+ /* Done, reset message pointer. */
+ sc->sc_flags &= ~ESP_DROP_MSGI;
+ sc->sc_imlen = 0;
+}
+
+
+/*
+ * Send the highest priority, scheduled message
+ */
+void
+esp_msgout(sc)
+ register struct esp_softc *sc;
+{
+ struct esp_tinfo *ti;
+ struct ecb *ecb;
+ size_t size;
+
+ ESP_TRACE(("[esp_msgout(priq:%x, prevphase:%x)]", sc->sc_msgpriq, sc->sc_prevphase));
+
+ if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
+ /* Pick up highest priority message */
+ sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
+ sc->sc_omlen = 1; /* "Default" message len */
+ switch (sc->sc_msgout) {
+ case SEND_SDTR:
+ ecb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ sc->sc_omess[0] = MSG_EXTENDED;
+ sc->sc_omess[1] = 3;
+ sc->sc_omess[2] = MSG_EXT_SDTR;
+ sc->sc_omess[3] = ti->period;
+ sc->sc_omess[4] = ti->offset;
+ sc->sc_omlen = 5;
+ break;
+ case SEND_IDENTIFY:
+ if (sc->sc_state != ESP_HASNEXUS) {
+ printf("esp at line %d: no nexus", __LINE__);
+ }
+ ecb = sc->sc_nexus;
+ sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,0);
+ break;
+ case SEND_DEV_RESET:
+ sc->sc_omess[0] = MSG_BUS_DEV_RESET;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ ecb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ ti->flags &= ~T_SYNCMODE;
+ ti->flags |= T_NEGOTIATE;
+ break;
+ case SEND_PARITY_ERROR:
+ sc->sc_omess[0] = MSG_PARITY_ERROR;
+ break;
+ case SEND_ABORT:
+ sc->sc_omess[0] = MSG_ABORT;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ break;
+ case SEND_INIT_DET_ERR:
+ sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
+ break;
+ case SEND_REJECT:
+ sc->sc_omess[0] = MSG_MESSAGE_REJECT;
+ break;
+ default:
+ sc->sc_omess[0] = MSG_NOOP;
+ break;
+ }
+ sc->sc_omp = sc->sc_omess;
+ }
+
+#if 1
+ /* (re)send the message */
+ size = min(sc->sc_omlen, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_omp, &sc->sc_omlen, 0, &size);
+ /* Program the SCSI counter */
+ ESP_WRITE_REG(sc, ESP_TCL, size);
+ ESP_WRITE_REG(sc, ESP_TCM, size >> 8);
+ if (sc->sc_cfg2 & ESPCFG2_FE) {
+ ESP_WRITE_REG(sc, ESP_TCH, size >> 16);
+ }
+ /* load the count in */
+ ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA);
+ ESPCMD(sc, (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA);
+ DMA_GO(sc->sc_dma);
+#else
+ { int i;
+ ESPCMD(sc, ESPCMD_FLUSH);
+ for (i = 0; i < sc->sc_omlen; i++)
+ ESP_WRITE_REG(sc, FIFO, sc->sc_omess[i]);
+ ESPCMD(sc, ESPCMD_TRANS);
+#if test_stuck_on_msgout
+printf("<<XXXmsgoutdoneXXX>>");
+#endif
+ }
+#endif
+}
+
+/*
+ * This is the most critical part of the driver, and has to know
+ * how to deal with *all* error conditions and phases from the SCSI
+ * bus. If there are no errors and the DMA was active, then call the
+ * DMA pseudo-interrupt handler. If this returns 1, then that was it
+ * and we can return from here without further processing.
+ *
+ * Most of this needs verifying.
+ */
+int
+espintr(sc)
+ register struct esp_softc *sc;
+{
+ register struct ecb *ecb;
+ register struct scsi_link *sc_link;
+ struct esp_tinfo *ti;
+ int loop;
+ size_t size;
+
+ ESP_TRACE(("[espintr]"));
+
+ /*
+ * I have made some (maybe seriously flawed) assumptions here,
+ * but basic testing (uncomment the printf() below), show that
+ * certainly something happens when this loop is here.
+ *
+ * The idea is that many of the SCSI operations take very little
+ * time, and going away and getting interrupted is too high an
+ * overhead to pay. For example, selecting, sending a message
+ * and command and then doing some work can be done in one "pass".
+ *
+ * The DELAY is not variable because I do not understand that the
+ * DELAY loop should be fixed-time regardless of CPU speed, but
+ * I am *assuming* that the faster SCSI processors get things done
+ * quicker (sending a command byte etc), and so there is no
+ * need to be too slow.
+ *
+ * This is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1
+ * at 40Mhz. This needs testing.
+ */
+ for (loop = 0; 1;loop++, DELAY(50/sc->sc_freq)) {
+ /* a feeling of deja-vu */
+ if (!DMA_ISINTR(sc->sc_dma))
+ return (loop != 0);
+#if 0
+ if (loop)
+ printf("*");
+#endif
+
+ /* and what do the registers say... */
+ espreadregs(sc);
+
+ sc->sc_intrcnt.ev_count++;
+
+ /*
+ * At the moment, only a SCSI Bus Reset or Illegal
+ * Command are classed as errors. A disconnect is a
+ * valid condition, and we let the code check is the
+ * "ESP_BUSFREE_OK" flag was set before declaring it
+ * and error.
+ *
+ * Also, the status register tells us about "Gross
+ * Errors" and "Parity errors". Only the Gross Error
+ * is really bad, and the parity errors are dealt
+ * with later
+ *
+ * TODO
+ * If there are too many parity error, go to slow
+ * cable mode ?
+ */
+
+ /* SCSI Reset */
+ if (sc->sc_espintr & ESPINTR_SBR) {
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ if (sc->sc_state != ESP_SBR) {
+ printf("%s: SCSI bus reset\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 0); /* Restart everything */
+ return 1;
+ }
+#if 0
+ /*XXX*/ printf("<expected bus reset: "
+ "[intr %x, stat %x, step %d]>\n",
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+#endif
+ if (sc->sc_nexus)
+ panic("%s: nexus in reset state",
+ sc->sc_dev.dv_xname);
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ return 1;
+ }
+
+ ecb = sc->sc_nexus;
+
+#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL)
+ if (sc->sc_espintr & ESPINTR_ERR ||
+ sc->sc_espstat & ESPSTAT_GE) {
+
+ if (sc->sc_espstat & ESPSTAT_GE) {
+ /* no target ? */
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ if (sc->sc_state == ESP_HASNEXUS ||
+ sc->sc_state == ESP_SELECTING) {
+ ecb->xs->error = XS_DRIVER_STUFFUP;
+ esp_done(ecb);
+ }
+ return 1;
+ }
+
+ if (sc->sc_espintr & ESPINTR_ILL) {
+ /* illegal command, out of sync ? */
+ printf("%s: illegal command: 0x%x (state %d, phase %x, prevphase %x)\n",
+ sc->sc_dev.dv_xname, sc->sc_lastcmd,
+ sc->sc_state, sc->sc_phase,
+ sc->sc_prevphase);
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ esp_init(sc, 0); /* Restart everything */
+ return 1;
+ }
+ }
+
+ /*
+ * Call if DMA is active.
+ *
+ * If DMA_INTR returns true, then maybe go 'round the loop
+ * again in case there is no more DMA queued, but a phase
+ * change is expected.
+ */
+ if (DMA_ISACTIVE(sc->sc_dma)) {
+ DMA_INTR(sc->sc_dma);
+ /* If DMA active here, then go back to work... */
+ if (DMA_ISACTIVE(sc->sc_dma))
+ return 1;
+
+ if (sc->sc_dleft == 0 &&
+ (sc->sc_espstat & ESPSTAT_TC) == 0)
+ printf("%s: !TC [intr %x, stat %x, step %d]"
+ " prevphase %x, resid %x\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr,
+ sc->sc_espstat,
+ sc->sc_espstep,
+ sc->sc_prevphase,
+ ecb?ecb->dleft:-1);
+ }
+
+#if 0 /* Unreliable on some ESP revisions? */
+ if ((sc->sc_espstat & ESPSTAT_INT) == 0) {
+ printf("%s: spurious interrupt\n", sc->sc_dev.dv_xname);
+ return 1;
+ }
+#endif
+
+ /*
+ * check for less serious errors
+ */
+ if (sc->sc_espstat & ESPSTAT_PE) {
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ if (sc->sc_prevphase == MESSAGE_IN_PHASE)
+ esp_sched_msgout(SEND_PARITY_ERROR);
+ else
+ esp_sched_msgout(SEND_INIT_DET_ERR);
+ }
+
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ ESP_MISC(("<DISC [intr %x, stat %x, step %d]>",
+ sc->sc_espintr,sc->sc_espstat,sc->sc_espstep));
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ /*
+ * This command must (apparently) be issued within
+ * 250mS of a disconnect. So here you are...
+ */
+ ESPCMD(sc, ESPCMD_ENSEL);
+ if (sc->sc_state != ESP_IDLE) {
+ if ((sc->sc_flags & ESP_SYNCHNEGO)) {
+#ifdef ESP_DEBUG
+ if (ecb)
+ sc_print_addr(ecb->xs->sc_link);
+ printf("sync nego not completed!\n");
+#endif
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ sc->sc_tinfo[ecb->xs->sc_link->target].offset = 0;
+ sc->sc_tinfo[ecb->xs->sc_link->target].flags &= ~T_NEGOTIATE;
+ }
+ /*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0;
+
+ /* it may be OK to disconnect */
+ if (!(sc->sc_flags & ESP_BUSFREE_OK)) {
+ if (sc->sc_state == ESP_HASNEXUS) {
+ sc_print_addr(ecb->xs->sc_link);
+ printf("disconnect without"
+ "warning\n");
+ }
+ ecb->xs->error = XS_TIMEOUT;
+ } else if (sc->sc_flags & ESP_DISCON) {
+ TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNEXUS);
+ sc->sc_nexus = NULL;
+ sc->sc_flags &= ~ESP_DISCON;
+ sc->sc_state = ESP_IDLE;
+#if ESP_DEBUG
+if ((esp_debug & 0x10000) && ecb->dleft == 0) {
+ printf("%s: silly disconnect (ecb %p [stat %x])\n",
+ sc->sc_dev.dv_xname, ecb, ecb->stat);
+}
+#endif
+ esp_sched(sc);
+ return 1;
+ }
+
+ esp_done(ecb);
+ return 1;
+ }
+ printf("%s: DISCONNECT in IDLE state!\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ /* did a message go out OK ? This must be broken */
+ if (sc->sc_prevphase == MESSAGE_OUT_PHASE &&
+ sc->sc_phase != MESSAGE_OUT_PHASE) {
+ /* we have sent it */
+ if (sc->sc_msgout == SEND_SDTR &&
+ (sc->sc_flags & ESP_SYNCHNEGO) == 0) {
+ /* We've just accepted new sync parameters */
+ sc->sc_tinfo[ecb->xs->sc_link->target].flags |=
+ T_SYNCMODE;
+if (ecb) sc_print_addr(ecb->xs->sc_link);else printf("NO nexus: ");
+printf("target put in SYNC mode\n");
+ }
+ sc->sc_msgpriq &= ~sc->sc_msgout;
+ sc->sc_msgout = 0;
+ }
+
+ switch (sc->sc_state) {
+
+ case ESP_SBR:
+ printf("%s: waiting for SCSI Bus Reset to happen\n",
+ sc->sc_dev.dv_xname);
+ return 1;
+
+ case ESP_RESELECTED:
+ /*
+ * we must be continuing a message ?
+ */
+ if (sc->sc_phase != MESSAGE_IN_PHASE) {
+ printf("%s: target didn't identify\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+printf("<<RESELECT CONT'd>>");
+#if XXXX
+ esp_msgin(sc);
+ if (sc->sc_state != ESP_HASNEXUS) {
+ /* IDENTIFY fail?! */
+ printf("%s: identify failed\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+#endif
+ break;
+
+ case ESP_IDLE:
+if (sc->sc_flags & ESP_ICCS) printf("[[esp: BUMMER]]");
+ case ESP_SELECTING:
+
+ if (sc->sc_espintr & ESPINTR_RESEL) {
+ /*
+ * If we're trying to select a
+ * target ourselves, push our command
+ * back into the ready list.
+ */
+ if (sc->sc_state == ESP_SELECTING) {
+ ESP_MISC(("backoff selector "));
+ sc_link = sc->sc_nexus->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+ TAILQ_INSERT_HEAD(&sc->ready_list,
+ sc->sc_nexus, chain);
+ ECB_SETQ(sc->sc_nexus, ECB_QREADY);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ ecb = sc->sc_nexus = NULL;
+ }
+ sc->sc_state = ESP_RESELECTED;
+ if (sc->sc_phase != MESSAGE_IN_PHASE) {
+ /*
+ * Things are seriously fucked up.
+ * Pull the brakes, i.e. reset
+ */
+ printf("%s: target didn't identify\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) {
+ printf("%s: RESELECT: %d bytes in FIFO!\n",
+ sc->sc_dev.dv_xname,
+ ESP_READ_REG(sc, ESP_FFLAG) &
+ ESPFIFO_FF);
+ esp_init(sc, 1);
+ return 1;
+ }
+ sc->sc_selid = ESP_READ_REG(sc, ESP_FIFO);
+ sc->sc_selid &= ~(1<<sc->sc_id);
+ ESP_MISC(("selid=0x%2x ", sc->sc_selid));
+ esp_msgin(sc); /* Handle identify message */
+ if (sc->sc_state != ESP_HASNEXUS) {
+ /* IDENTIFY fail?! */
+ printf("%s: identify failed\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+ continue; /* ie. next phase expected soon */
+ }
+
+#define ESPINTR_DONE (ESPINTR_FC|ESPINTR_BS)
+ if ((sc->sc_espintr & ESPINTR_DONE) == ESPINTR_DONE) {
+ ecb = sc->sc_nexus;
+ if (!ecb)
+ panic("esp: not nexus at sc->sc_nexus");
+
+ sc_link = ecb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+
+ switch (sc->sc_espstep) {
+ case 0:
+ printf("%s: select timeout/no disconnect\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ case 1:
+ if ((ti->flags & T_NEGOTIATE) == 0) {
+ printf("%s: step 1 & !NEG\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ if (sc->sc_phase != MESSAGE_OUT_PHASE) {
+ printf("%s: !MSGOUT\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ /* Start negotiating */
+ ti->period = sc->sc_minsync;
+ ti->offset = 15;
+ sc->sc_msgpriq = SEND_SDTR;
+ sc->sc_flags |= ESP_SYNCHNEGO;
+ break;
+ case 3:
+ /*
+ * Grr, this is supposed to mean
+ * "target left command phase
+ * prematurely". It seems to happen
+ * regularly when sync mode is on.
+ * Look at FIFO to see if command
+ * went out.
+ * (Timing problems?)
+ */
+ if ((ESP_READ_REG(sc, ESP_FFLAG)&ESPFIFO_FF) == 0) {
+ /* Hope for the best.. */
+ break;
+ }
+ printf("(%s:%d:%d): selection failed;"
+ " %d left in FIFO "
+ "[intr %x, stat %x, step %d]\n",
+ sc->sc_dev.dv_xname,
+ sc_link->target,
+ sc_link->lun,
+ ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ sc->sc_flags |= ESP_ABORTING;
+ esp_sched_msgout(SEND_ABORT);
+ return 1;
+ case 2:
+ /* Select stuck at Command Phase */
+ ESPCMD(sc, ESPCMD_FLUSH);
+ case 4:
+ /* So far, everything went fine */
+ sc->sc_msgpriq = 0;
+ break;
+ }
+#if 0
+/* Why set msgpriq? (and not raise ATN) */
+ if (ecb->xs->flags & SCSI_RESET)
+ sc->sc_msgpriq = SEND_DEV_RESET;
+ else if (ti->flags & T_NEGOTIATE)
+ sc->sc_msgpriq =
+ SEND_IDENTIFY | SEND_SDTR;
+ else
+ sc->sc_msgpriq = SEND_IDENTIFY;
+#endif
+ sc->sc_state = ESP_HASNEXUS;
+ /*???sc->sc_flags = 0; */
+ sc->sc_prevphase = INVALID_PHASE; /* ?? */
+ sc->sc_dp = ecb->daddr;
+ sc->sc_dleft = ecb->dleft;
+ ti->lubusy |= (1<<sc_link->lun);
+ break;
+ } else {
+ printf("%s: unexpected status after select"
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ esp_abort(sc, ecb);
+ }
+ if (sc->sc_state == ESP_IDLE) {
+ printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);
+ return 0;
+ }
+ break;
+
+ case ESP_HASNEXUS:
+ if (sc->sc_flags & ESP_ICCS) {
+ unsigned char msg;
+
+ sc->sc_flags &= ~ESP_ICCS;
+
+ if (!(sc->sc_espintr & ESPINTR_DONE)) {
+ printf("%s: ICCS: "
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) {
+ printf("%s: ICCS: expected 2, got %d "
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ ecb->stat = ESP_READ_REG(sc, ESP_FIFO);
+ msg = ESP_READ_REG(sc, ESP_FIFO);
+ ESP_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
+ if (msg == MSG_CMDCOMPLETE) {
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ ecb->xs->resid = ecb->dleft = sc->sc_dleft;
+ } else
+ printf("%s: STATUS_PHASE: msg %d\n",
+ sc->sc_dev.dv_xname, msg);
+ ESPCMD(sc, ESPCMD_MSGOK);
+ continue; /* ie. wait for disconnect */
+ }
+ break;
+ default:
+ panic("%s: invalid state: %d",
+ sc->sc_dev.dv_xname,
+ sc->sc_state);
+ }
+
+ /*
+ * Driver is now in state ESP_HASNEXUS, i.e. we
+ * have a current command working the SCSI bus.
+ */
+ if (sc->sc_state != ESP_HASNEXUS || ecb == NULL) {
+ panic("esp no nexus");
+ }
+
+ switch (sc->sc_phase) {
+ case MESSAGE_OUT_PHASE:
+ ESP_PHASE(("MESSAGE_OUT_PHASE "));
+ esp_msgout(sc);
+ sc->sc_prevphase = MESSAGE_OUT_PHASE;
+ break;
+ case MESSAGE_IN_PHASE:
+ ESP_PHASE(("MESSAGE_IN_PHASE "));
+ if (sc->sc_espintr & ESPINTR_BS) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ sc->sc_flags |= ESP_WAITI;
+ ESPCMD(sc, ESPCMD_TRANS);
+ } else if (sc->sc_espintr & ESPINTR_FC) {
+ if ((sc->sc_flags & ESP_WAITI) == 0) {
+ printf("%s: MSGIN: unexpected FC bit: "
+ "[intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ sc->sc_flags &= ~ESP_WAITI;
+ esp_msgin(sc);
+ } else {
+ printf("%s: MSGIN: weird bits: "
+ "[intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ sc->sc_prevphase = MESSAGE_IN_PHASE;
+ break;
+ case COMMAND_PHASE: {
+ /* well, this means send the command again */
+ u_char *cmd = (u_char *)&ecb->cmd;
+ int i;
+
+ ESP_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
+ ecb->cmd.opcode, ecb->clen));
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ /* Now the command into the FIFO */
+ for (i = 0; i < ecb->clen; i++)
+ ESP_WRITE_REG(sc, ESP_FIFO, *cmd++);
+ ESPCMD(sc, ESPCMD_TRANS);
+ sc->sc_prevphase = COMMAND_PHASE;
+ }
+ break;
+ case DATA_OUT_PHASE:
+ ESP_PHASE(("DATA_OUT_PHASE [%d] ", sc->sc_dleft));
+ ESPCMD(sc, ESPCMD_FLUSH);
+ size = min(sc->sc_dleft, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft,
+ 0, &size);
+ sc->sc_prevphase = DATA_OUT_PHASE;
+ goto setup_xfer;
+ case DATA_IN_PHASE:
+ ESP_PHASE(("DATA_IN_PHASE "));
+ if (sc->sc_rev == ESP100)
+ ESPCMD(sc, ESPCMD_FLUSH);
+ size = min(sc->sc_dleft, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft,
+ 1, &size);
+ sc->sc_prevphase = DATA_IN_PHASE;
+ setup_xfer:
+ /* Program the SCSI counter */
+ ESP_WRITE_REG(sc, ESP_TCL, size);
+ ESP_WRITE_REG(sc, ESP_TCM, size >> 8);
+ if (sc->sc_cfg2 & ESPCFG2_FE) {
+ ESP_WRITE_REG(sc, ESP_TCH, size >> 16);
+ }
+ /* load the count in */
+ ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA);
+
+ /*
+ * Note that if `size' is 0, we've already transceived
+ * all the bytes we want but we're still in DATA PHASE.
+ * Apparently, the device needs padding. Also, a
+ * transfer size of 0 means "maximum" to the chip
+ * DMA logic.
+ */
+ ESPCMD(sc,
+ (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA);
+ DMA_GO(sc->sc_dma);
+ return 1;
+ case STATUS_PHASE:
+ ESP_PHASE(("STATUS_PHASE "));
+ sc->sc_flags |= ESP_ICCS;
+ ESPCMD(sc, ESPCMD_ICCS);
+ sc->sc_prevphase = STATUS_PHASE;
+ break;
+ case INVALID_PHASE:
+ break;
+ case BUSFREE_PHASE:
+ if (sc->sc_flags & ESP_BUSFREE_OK) {
+ /*It's fun the 1st time.. */
+ sc->sc_flags &= ~ESP_BUSFREE_OK;
+ }
+ break;
+ default:
+ panic("esp: bogus bus phase\n");
+ }
+ }
+ panic("esp: should not get here..");
+}
+
+void
+esp_abort(sc, ecb)
+ struct esp_softc *sc;
+ struct ecb *ecb;
+{
+ if (ecb == sc->sc_nexus) {
+ if (sc->sc_state == ESP_HASNEXUS) {
+ sc->sc_flags |= ESP_ABORTING;
+ esp_sched_msgout(SEND_ABORT);
+ }
+ } else {
+ if (sc->sc_state == ESP_IDLE)
+ esp_sched(sc);
+ }
+}
+
+void
+esp_timeout(arg)
+ void *arg;
+{
+ int s = splbio();
+ struct ecb *ecb = (struct ecb *)arg;
+ struct esp_softc *sc;
+ struct scsi_xfer *xs = ecb->xs;
+
+ sc = xs->sc_link->adapter_softc;
+ sc_print_addr(xs->sc_link);
+again:
+ printf("%s: timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], "
+ "<state %d, nexus %p, phase(c %x, p %x), resid %x, msg(q %x,o %x) %s>",
+ sc->sc_dev.dv_xname,
+ ecb, ecb->flags, ecb->dleft, ecb->stat,
+ sc->sc_state, sc->sc_nexus, sc->sc_phase, sc->sc_prevphase,
+ sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
+ DMA_ISACTIVE(sc->sc_dma) ? "DMA active" : "");
+#if ESP_DEBUG > 0
+ printf("TRACE: %s.", ecb->trace);
+#endif
+
+ if (ecb->flags & ECB_ABORTED) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ esp_init(sc, 1);
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ xs->error = XS_TIMEOUT;
+ ecb->flags |= ECB_ABORTED;
+ esp_abort(sc, ecb);
+ /* 2 secs for the abort */
+ if ((xs->flags & SCSI_NOMASK) == 0)
+ timeout(esp_timeout, ecb, 2 * hz);
+ else {
+ int count = 200000;
+ while (count) {
+ if (DMA_ISINTR(sc->sc_dma)) {
+ espintr(sc);
+ }
+ if (xs->flags & ITSDONE)
+ break;
+ DELAY(10);
+ --count;
+ }
+ if (count == 0)
+ goto again;
+ }
+ }
+ splx(s);
+}
+
+static void
+esp_min_phys (struct buf *bp)
+{
+
+}
diff --git a/sys/alpha/tc/espreg.h b/sys/alpha/tc/espreg.h
new file mode 100644
index 0000000..4f30d1c
--- /dev/null
+++ b/sys/alpha/tc/espreg.h
@@ -0,0 +1,149 @@
+/* $Id$ */
+/* $NetBSD: espreg.h,v 1.2.4.1 1996/09/10 17:28:17 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Peter Galbavy. 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 Peter Galbavy.
+ * 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.
+ */
+
+/*
+ * Register addresses, relative to some base address
+ */
+
+#define ESP_TCL 0x00 /* RW - Transfer Count Low */
+#define ESP_TCM 0x01 /* RW - Transfer Count Mid */
+#define ESP_TCH 0x0e /* RW - Transfer Count High */
+ /* NOT on 53C90 */
+
+#define ESP_FIFO 0x02 /* RW - FIFO data */
+
+#define ESP_CMD 0x03 /* RW - Command (2 deep) */
+#define ESPCMD_DMA 0x80 /* DMA Bit */
+#define ESPCMD_NOP 0x00 /* No Operation */
+#define ESPCMD_FLUSH 0x01 /* Flush FIFO */
+#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */
+#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */
+#define ESPCMD_RESEL 0x40 /* Reselect Sequence */
+#define ESPCMD_SELNATN 0x41 /* Select without ATN */
+#define ESPCMD_SELATN 0x42 /* Select with ATN */
+#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */
+#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */
+#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */
+#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */
+#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */
+#define ESPCMD_SNDMSG 0x20 /* Send Message */
+#define ESPCMD_SNDSTAT 0x21 /* Send Status */
+#define ESPCMD_SNDDATA 0x22 /* Send Data */
+#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */
+#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */
+#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */
+#define ESPCMD_DISC 0x27 /* Disconnect */
+#define ESPCMD_RECMSG 0x28 /* Receive Message */
+#define ESPCMD_RECCMD 0x29 /* Receive Command */
+#define ESPCMD_RECDATA 0x2a /* Receive Data */
+#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/
+#define ESPCMD_ABORT 0x04 /* Target Abort DMA */
+#define ESPCMD_TRANS 0x10 /* Transfer Information */
+#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */
+#define ESPCMD_MSGOK 0x12 /* Message Accepted */
+#define ESPCMD_TRPAD 0x18 /* Transfer Pad */
+#define ESPCMD_SETATN 0x1a /* Set ATN */
+#define ESPCMD_RSTATN 0x1b /* Reset ATN */
+
+#define ESP_STAT 0x04 /* RO - Status */
+#define ESPSTAT_INT 0x80 /* Interrupt */
+#define ESPSTAT_GE 0x40 /* Gross Error */
+#define ESPSTAT_PE 0x20 /* Parity Error */
+#define ESPSTAT_TC 0x10 /* Terminal Count */
+#define ESPSTAT_VGC 0x08 /* Valid Group Code */
+#define ESPSTAT_PHASE 0x07 /* Phase bits */
+
+#define ESP_SELID 0x04 /* WO - Select/Reselect Bus ID */
+
+#define ESP_INTR 0x05 /* RO - Interrupt */
+#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */
+#define ESPINTR_ILL 0x40 /* Illegal Command */
+#define ESPINTR_DIS 0x20 /* Disconnect */
+#define ESPINTR_BS 0x10 /* Bus Service */
+#define ESPINTR_FC 0x08 /* Function Complete */
+#define ESPINTR_RESEL 0x04 /* Reselected */
+#define ESPINTR_SELATN 0x02 /* Select with ATN */
+#define ESPINTR_SEL 0x01 /* Selected */
+
+#define ESP_TIMEOUT 0x05 /* WO - Select/Reselect Timeout */
+
+#define ESP_STEP 0x06 /* RO - Sequence Step */
+#define ESPSTEP_MASK 0x07 /* the last 3 bits */
+#define ESPSTEP_DONE 0x04 /* command went out */
+
+#define ESP_SYNCTP 0x06 /* WO - Synch Transfer Period */
+ /* Default 5 (53C9X) */
+
+#define ESP_FFLAG 0x07 /* RO - FIFO Flags */
+#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */
+#define ESPFIFO_FF 0x1f /* Bytes in FIFO */
+
+#define ESP_SYNCOFF 0x07 /* WO - Synch Offset */
+ /* 0 = ASYNC */
+ /* 1 - 15 = SYNC bytes */
+
+#define ESP_CFG1 0x08 /* RW - Configuration #1 */
+#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */
+#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */
+#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */
+#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */
+#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */
+#define ESPCFG1_BUSID 0x07 /* Bus ID */
+
+#define ESP_CCF 0x09 /* WO - Clock Conversion Factor */
+ /* 0 = 35.01 - 40Mhz */
+ /* NEVER SET TO 1 */
+ /* 2 = 10Mhz */
+ /* 3 = 10.01 - 15Mhz */
+ /* 4 = 15.01 - 20Mhz */
+ /* 5 = 20.01 - 25Mhz */
+ /* 6 = 25.01 - 30Mhz */
+ /* 7 = 30.01 - 35Mhz */
+
+#define ESP_TEST 0x0a /* WO - Test (Chip Test Only) */
+
+#define ESP_CFG2 0x0b /* RW - Configuration #2 */
+#define ESPCFG2_RSVD 0xa0 /* reserved */
+#define ESPCFG2_FE 0x40 /* Features Enable */
+#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */
+#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */
+#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */
+#define ESPCFG2_RPE 0x02 /* Register Parity Error */
+#define ESPCFG2_DPE 0x01 /* DMA Parity Error */
+
+/* Config #3 only on 53C9X */
+#define ESP_CFG3 0x0c /* RW - Configuration #3 */
+#define ESPCFG3_RSVD 0xe0 /* reserved */
+#define ESPCFG3_IDM 0x10 /* ID Message Res Check */
+#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */
+#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */
+#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */
+#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
diff --git a/sys/alpha/tc/espvar.h b/sys/alpha/tc/espvar.h
new file mode 100644
index 0000000..ad5d139
--- /dev/null
+++ b/sys/alpha/tc/espvar.h
@@ -0,0 +1,330 @@
+/* $Id$ */
+/* $NetBSD: espvar.h,v 1.3.4.1 1996/09/10 17:28:18 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Peter Galbavy. 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 Peter Galbavy.
+ * 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.
+ */
+
+/*#define ESP_DEBUG 0*/
+
+#define FREQTOCCF(freq) (((freq + 4) / 5))
+
+/* esp revisions */
+#define ESP100 0x01
+#define ESP100A 0x02
+#define ESP200 0x03
+#define NCR53C94 0x04
+
+/*
+ * ECB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basicly, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
+ */
+struct ecb {
+ TAILQ_ENTRY(ecb) chain;
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
+#define ECB_QNONE 0
+#define ECB_QFREE 1
+#define ECB_QREADY 2
+#define ECB_QNEXUS 3
+#define ECB_QBITS 0x07
+#define ECB_CHKSENSE 0x08
+#define ECB_ABORTED 0x10
+#define ECB_SETQ(e, q) do (e)->flags = ((e)->flags&~ECB_QBITS)|(q); while(0)
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ char *daddr; /* Saved data pointer */
+ int dleft; /* Residue */
+ struct callout_handle timeout_ch;
+ u_char stat; /* SCSI status byte */
+#if ESP_DEBUG > 0
+ char trace[1000];
+#endif
+};
+#if ESP_DEBUG > 0
+#define ECB_TRACE(ecb, msg, a, b) do { \
+ const char *f = "[" msg "]"; \
+ int n = strlen((ecb)->trace); \
+ if (n < (sizeof((ecb)->trace)-100)) \
+ sprintf((ecb)->trace + n, f, a, b); \
+} while(0)
+#else
+#define ECB_TRACE(ecb, msg, a, b)
+#endif
+
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
+ * this for now. Is there a way to reliably hook it up to sc->fordriver??
+ */
+struct esp_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+#define T_NEED_TO_RESET 0x01 /* Should send a BUS_DEV_RESET */
+#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */
+#define T_BUSY 0x04 /* Target is busy, i.e. cmd in progress */
+#define T_SYNCMODE 0x08 /* sync mode has been negotiated */
+#define T_SYNCHOFF 0x10 /* .. */
+#define T_RSELECTOFF 0x20 /* .. */
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
+
+/* Register a linenumber (for debugging) */
+#define LOGLINE(p)
+
+#define ESP_SHOWECBS 0x01
+#define ESP_SHOWINTS 0x02
+#define ESP_SHOWCMDS 0x04
+#define ESP_SHOWMISC 0x08
+#define ESP_SHOWTRAC 0x10
+#define ESP_SHOWSTART 0x20
+#define ESP_SHOWPHASE 0x40
+#define ESP_SHOWDMA 0x80
+#define ESP_SHOWCCMDS 0x100
+#define ESP_SHOWMSGS 0x200
+
+#ifdef ESP_DEBUG
+extern int esp_debug;
+#define ESP_ECBS(str) do {if (esp_debug & ESP_SHOWECBS) printf str;} while (0)
+#define ESP_MISC(str) do {if (esp_debug & ESP_SHOWMISC) printf str;} while (0)
+#define ESP_INTS(str) do {if (esp_debug & ESP_SHOWINTS) printf str;} while (0)
+#define ESP_TRACE(str) do {if (esp_debug & ESP_SHOWTRAC) printf str;} while (0)
+#define ESP_CMDS(str) do {if (esp_debug & ESP_SHOWCMDS) printf str;} while (0)
+#define ESP_START(str) do {if (esp_debug & ESP_SHOWSTART) printf str;}while (0)
+#define ESP_PHASE(str) do {if (esp_debug & ESP_SHOWPHASE) printf str;}while (0)
+#define ESP_DMA(str) do {if (esp_debug & ESP_SHOWDMA) printf str;}while (0)
+#define ESP_MSGS(str) do {if (esp_debug & ESP_SHOWMSGS) printf str;}while (0)
+#else
+#define ESP_ECBS(str)
+#define ESP_MISC(str)
+#define ESP_INTS(str)
+#define ESP_TRACE(str)
+#define ESP_CMDS(str)
+#define ESP_START(str)
+#define ESP_PHASE(str)
+#define ESP_DMA(str)
+#define ESP_MSGS(str)
+#endif
+
+#define ESP_MAX_MSG_LEN 8
+
+struct esp_softc {
+ struct device sc_dev; /* us as a device */
+#ifdef SPARC_DRIVER
+ struct sbusdev sc_sd; /* sbus device */
+ struct intrhand sc_ih; /* intr handler */
+#endif
+ struct evcnt sc_intrcnt; /* intr count */
+ struct scsi_link sc_link; /* scsi lint struct */
+#ifdef SPARC_DRIVER
+ volatile u_char *sc_reg; /* the registers */
+ struct dma_softc *sc_dma; /* pointer to my dma */
+#else
+ volatile u_int32_t *sc_reg; /* the registers */
+ struct tcds_slotconfig *sc_dma; /* DMA/slot info lives here. */
+ void *sc_cookie; /* intr. handling cookie */
+#endif
+
+ /* register defaults */
+ u_char sc_cfg1; /* Config 1 */
+ u_char sc_cfg2; /* Config 2, not ESP100 */
+ u_char sc_cfg3; /* Config 3, only ESP200 */
+ u_char sc_ccf; /* Clock Conversion */
+ u_char sc_timeout;
+
+ /* register copies, see espreadregs() */
+ u_char sc_espintr;
+ u_char sc_espstat;
+ u_char sc_espstep;
+ u_char sc_espfflags;
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(ecb_list, ecb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct ecb *sc_nexus; /* current command */
+ struct ecb sc_ecb[8]; /* one per target */
+ struct esp_tinfo sc_tinfo[8];
+
+ /* Data about the current nexus (updated for every cmd switch) */
+ caddr_t sc_dp; /* Current data pointer */
+ ssize_t sc_dleft; /* Data left to transfer */
+
+ /* Adapter state */
+ int sc_phase; /* Copy of what bus phase we are in */
+ int sc_prevphase; /* Copy of what bus phase we were in */
+ u_char sc_state; /* State applicable to the adapter */
+ u_char sc_flags;
+ u_char sc_selid;
+ u_char sc_lastcmd;
+
+ /* Message stuff */
+ u_char sc_msgpriq; /* One or more messages to send (encoded) */
+ u_char sc_msgout; /* What message is on its way out? */
+ u_char sc_omess[ESP_MAX_MSG_LEN];
+ caddr_t sc_omp; /* Message pointer (for multibyte messages) */
+ size_t sc_omlen;
+ u_char sc_imess[ESP_MAX_MSG_LEN + 1];
+ caddr_t sc_imp; /* Message pointer (for multibyte messages) */
+ size_t sc_imlen;
+
+ /* hardware/openprom stuff */
+ int sc_node; /* PROM node ID */
+ int sc_freq; /* Freq in HZ */
+#ifdef SPARC_DRIVER
+ int sc_pri; /* SBUS priority */
+#endif
+ int sc_id; /* our scsi id */
+ int sc_rev; /* esp revision */
+ int sc_minsync; /* minimum sync period / 4 */
+ int sc_maxxfer; /* maximum transfer size */
+};
+
+/* values for sc_state */
+#define ESP_IDLE 0x01 /* waiting for something to do */
+#define ESP_TMP_UNAVAIL 0x02 /* Don't accept SCSI commands */
+#define ESP_SELECTING 0x03 /* SCSI command is arbiting */
+#define ESP_RESELECTED 0x04 /* Has been reselected */
+#define ESP_HASNEXUS 0x05 /* Actively using the SCSI bus */
+#define ESP_CLEANING 0x06
+#define ESP_SBR 0x07 /* Expect a SCSI RST because we commanded it */
+
+/* values for sc_flags */
+#define ESP_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */
+#define ESP_DOINGDMA 0x02 /* The FIFO data path is active! */
+#define ESP_BUSFREE_OK 0x04 /* Bus free phase is OK. */
+#define ESP_SYNCHNEGO 0x08 /* Synch negotiation in progress. */
+/*#define ESP_BLOCKED 0x10 * Don't schedule new scsi bus operations */
+#define ESP_DISCON 0x10 /* Target sent DISCONNECT msg */
+#define ESP_ABORTING 0x20 /* Bailing out */
+#define ESP_ICCS 0x40 /* Expect status phase results */
+#define ESP_WAITI 0x80 /* Waiting for non-DMA data to arrive */
+
+/* values for sc_msgout */
+#define SEND_DEV_RESET 0x01
+#define SEND_PARITY_ERROR 0x02
+#define SEND_ABORT 0x04
+#define SEND_REJECT 0x08
+#define SEND_INIT_DET_ERR 0x10
+#define SEND_IDENTIFY 0x20
+#define SEND_SDTR 0x40
+
+/* SCSI Status codes */
+#define ST_GOOD 0x00
+#define ST_CHKCOND 0x02
+#define ST_CONDMET 0x04
+#define ST_BUSY 0x08
+#define ST_INTERMED 0x10
+#define ST_INTERMED_CONDMET 0x14
+#define ST_RESERVATION_CONFLICT 0x18
+#define ST_CMD_TERM 0x22
+#define ST_QUEUE_FULL 0x28
+
+#define ST_MASK 0x3e /* bit 0,6,7 is reserved */
+
+/* phase bits */
+#define IOI 0x01
+#define CDI 0x02
+#define MSGI 0x04
+
+/* Information transfer phases */
+#define DATA_OUT_PHASE (0)
+#define DATA_IN_PHASE (IOI)
+#define COMMAND_PHASE (CDI)
+#define STATUS_PHASE (CDI|IOI)
+#define MESSAGE_OUT_PHASE (MSGI|CDI)
+#define MESSAGE_IN_PHASE (MSGI|CDI|IOI)
+
+#define PHASE_MASK (MSGI|CDI|IOI)
+
+/* Some pseudo phases for getphase()*/
+#define BUSFREE_PHASE 0x100 /* Re/Selection no longer valid */
+#define INVALID_PHASE 0x101 /* Re/Selection valid, but no REQ yet */
+#define PSEUDO_PHASE 0x100 /* "pseudo" bit */
+
+static u_char ESP_READ_REG(struct esp_softc *, int);
+
+#if 1
+static __inline u_char
+ESP_READ_REG(sc, reg)
+ struct esp_softc *sc;
+ int reg;
+{
+ u_char v;
+
+ v = sc->sc_reg[reg * 2] & 0xff;
+ alpha_mb();
+ return v;
+}
+#else
+#define ESP_READ_REG(sc, reg) \
+ ((u_char)((sc)->sc_reg[(reg) * 2] & 0xff))
+#endif
+#define ESP_WRITE_REG(sc, reg, val) \
+ do { \
+ u_char v = (val); \
+ (sc)->sc_reg[(reg) * 2] = v; \
+ alpha_mb(); \
+ } while (0)
+
+#ifdef ESP_DEBUG
+#define ESPCMD(sc, cmd) do { \
+ if (esp_debug & ESP_SHOWCCMDS) \
+ printf("<cmd:0x%x>", (unsigned)cmd); \
+ sc->sc_lastcmd = cmd; \
+ ESP_WRITE_REG(sc, ESP_CMD, cmd); \
+} while (0)
+#else
+#define ESPCMD(sc, cmd) ESP_WRITE_REG(sc, ESP_CMD, cmd)
+#endif
+
+#define SAME_ESP(sc, bp, ca) \
+ ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \
+ (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))
+
+#ifndef SPARC_DRIVER
+/* DMA macros for ESP */
+#define DMA_ISINTR(sc) tcds_dma_isintr(sc)
+#define DMA_RESET(sc) tcds_dma_reset(sc)
+#define DMA_INTR(sc) tcds_dma_intr(sc)
+#define DMA_SETUP(sc, addr, len, datain, dmasize) \
+ tcds_dma_setup(sc, addr, len, datain, dmasize)
+#define DMA_GO(sc) tcds_dma_go(sc)
+#define DMA_ISACTIVE(sc) tcds_dma_isactive(sc)
+#endif
diff --git a/sys/alpha/tc/if_le_dec.c b/sys/alpha/tc/if_le_dec.c
new file mode 100644
index 0000000..6e1206b
--- /dev/null
+++ b/sys/alpha/tc/if_le_dec.c
@@ -0,0 +1,170 @@
+/* $Id$ */
+/* $NetBSD: if_le_dec.c,v 1.8 1997/07/22 04:32:21 jonathan Exp $ */
+
+/*-
+ * Copyright (c) 1997 Jonathan Stone. All rights reserved.
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)if_le.c 8.2 (Berkeley) 11/16/93
+ */
+
+#include "bpfilter.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#endif
+
+#include <alpha/tc/am7990reg.h>
+#include <alpha/tc/am7990var.h>
+
+#include <alpha/tc/if_levar.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/ioasicvar.h>
+#include <machine/clock.h>
+
+
+/* access LANCE registers */
+void le_dec_writereg __P((volatile u_short *regptr, u_short val));
+#define LERDWR(cntl, src, dst) { (dst) = (src); tc_mb(); }
+#define LEWREG(src, dst) le_dec_writereg(&(dst), (src))
+
+hide void le_dec_wrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
+hide u_int16_t le_dec_rdcsr __P((struct am7990_softc *, u_int16_t));
+char *ether_sprintf(char *);
+void
+dec_le_common_attach(sc, eap)
+ struct am7990_softc *sc;
+ u_char *eap;
+{
+ int i;
+
+ sc->sc_rdcsr = le_dec_rdcsr;
+ sc->sc_wrcsr = le_dec_wrcsr;
+ sc->sc_hwinit = NULL;
+
+ sc->sc_conf3 = 0;
+ sc->sc_addr = 0;
+ sc->sc_memsize = 65536;
+
+ /*
+ * Get the ethernet address out of rom
+ */
+ for (i = 0; i < sizeof(sc->sc_enaddr); i++) {
+ sc->sc_enaddr[i] = *eap;
+ eap += 4;
+ }
+ am7990_config(sc);
+}
+
+hide void
+le_dec_wrcsr(sc, port, val)
+ struct am7990_softc *sc;
+ u_int16_t port, val;
+{
+ struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+ LEWREG(port, ler1->ler1_rap);
+ LERDWR(port, val, ler1->ler1_rdp);
+}
+
+hide u_int16_t
+le_dec_rdcsr(sc, port)
+ struct am7990_softc *sc;
+ u_int16_t port;
+{
+ struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+ u_int16_t val;
+ LEWREG(port, ler1->ler1_rap);
+ LERDWR(0, ler1->ler1_rdp, val);
+ return (val);
+}
+
+/*
+ * Write a lance register port, reading it back to ensure success. This seems
+ * to be necessary during initialization, since the chip appears to be a bit
+ * pokey sometimes.
+ */
+void
+le_dec_writereg(regptr, val)
+ register volatile u_short *regptr;
+ register u_short val;
+{
+ register int i = 0;
+ while (*regptr != val) {
+ *regptr = val;
+ tc_mb();
+ if (++i > 10000) {
+ printf("le: Reg did not settle (to x%x): x%x\n", val,
+ *regptr);
+ return;
+ }
+ DELAY(100);
+ }
+}
+
+/*
+ * Routines for accessing the transmit and receive buffers are provided
+ * by am7990.c, because of the LE_NEED_BUF_* macros defined above.
+ * Unfortunately, CPU addressing of these buffers is done in one of
+ * 3 ways:
+ * - contiguous (for the 3max and turbochannel option card)
+ * - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
+ * spaces (for the pmax, vax 3400, and ioasic LANCE descriptors)
+ * - gap16, which means 16bytes interspersed with 16byte spaces
+ * for buffers which must begin on a 32byte boundary (for 3min, maxine,
+ * and alpha)
+ * The buffer offset is the logical byte offset, assuming contiguous storage.
+ */
diff --git a/sys/alpha/tc/if_le_ioasic.c b/sys/alpha/tc/if_le_ioasic.c
new file mode 100644
index 0000000..fe3eacc
--- /dev/null
+++ b/sys/alpha/tc/if_le_ioasic.c
@@ -0,0 +1,398 @@
+/* $Id$ */
+/* $NetBSD: if_le_ioasic.c,v 1.10 1998/01/19 02:49:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * LANCE on DEC IOCTL ASIC.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#endif
+
+#include <alpha/tc/am7990reg.h>
+#include <alpha/tc/am7990var.h>
+
+#include <alpha/tc/if_levar.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/ioasicvar.h>
+
+extern caddr_t le_iomem;
+
+static int le_ioasic_probe(device_t dev);
+static int le_ioasic_attach(device_t dev);
+static device_method_t le_ioasic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, le_ioasic_probe),
+ DEVMETHOD(device_attach, le_ioasic_attach),
+ {0, 0}
+};
+#define LE_IOASIC_SOFTC(dev) (struct le_softc*) device_get_softc(dev)
+static driver_t le_ioasic_driver = {
+ "le",
+ le_ioasic_methods,
+ DRIVER_TYPE_NET,
+ sizeof(struct le_softc),
+};
+
+static devclass_t le_ioasic_devclass;
+
+hide void le_ioasic_copytobuf_gap2 __P((struct am7990_softc *, void *,
+ int, int));
+hide void le_ioasic_copyfrombuf_gap2 __P((struct am7990_softc *, void *,
+ int, int));
+
+hide void le_ioasic_copytobuf_gap16 __P((struct am7990_softc *, void *,
+ int, int));
+hide void le_ioasic_copyfrombuf_gap16 __P((struct am7990_softc *, void *,
+ int, int));
+hide void le_ioasic_zerobuf_gap16 __P((struct am7990_softc *, int, int));
+
+
+static int
+le_ioasic_probe(device_t dev)
+{
+ if(strcmp(device_get_name(device_get_parent(dev)),"ioasic")){
+ return ENXIO;
+ } else {
+ return(0);
+ }
+
+}
+
+static int
+le_ioasic_attach(device_t dev)
+{
+ register struct le_softc *lesc = LE_IOASIC_SOFTC(dev);
+ register struct am7990_softc *sc = &lesc->sc_am7990;
+ struct ioasic_dev *d = device_get_ivars(dev);
+ lesc->sc_r1 = (struct lereg1 *)
+ TC_DENSE_TO_SPARSE(TC_PHYS_TO_UNCACHED(d->iada_addr));
+ sc->sc_mem = (void *)TC_PHYS_TO_UNCACHED(le_iomem);
+ sc->sc_copytodesc = le_ioasic_copytobuf_gap2;
+ sc->sc_copyfromdesc = le_ioasic_copyfrombuf_gap2;
+ sc->sc_copytobuf = le_ioasic_copytobuf_gap16;
+ sc->sc_copyfrombuf = le_ioasic_copyfrombuf_gap16;
+ sc->sc_zerobuf = le_ioasic_zerobuf_gap16;
+
+ if (le_iomem == 0) {
+ printf("%s: DMA area not set up\n", sc->sc_dev.dv_xname);
+ return ENXIO;
+ }
+ sc->unit = device_get_unit(dev);
+ dec_le_common_attach(sc, ioasic_lance_ether_address());
+
+ ioasic_intr_establish(device_get_parent(dev), d->iad_cookie, 0, am7990_intr, sc);
+ return(0);
+}
+
+/*
+ * Special memory access functions needed by ioasic-attached LANCE
+ * chips.
+ */
+
+/*
+ * gap2: two bytes of data followed by two bytes of pad.
+ *
+ * Buffers must be 4-byte aligned. The code doesn't worry about
+ * doing an extra byte.
+ */
+
+void
+le_ioasic_copytobuf_gap2(sc, fromv, boff, len)
+ struct am7990_softc *sc;
+ void *fromv;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t from = fromv;
+ register volatile u_int16_t *bptr;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_int16_t *)buf) + (boff - 1);
+ *bptr = (*from++ << 8) | (*bptr & 0xff);
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_int16_t *)buf) + boff;
+ while (len > 1) {
+ *bptr = (from[1] << 8) | (from[0] & 0xff);
+ bptr += 2;
+ from += 2;
+ len -= 2;
+ }
+ if (len == 1)
+ *bptr = (u_int16_t)*from;
+}
+
+void
+le_ioasic_copyfrombuf_gap2(sc, tov, boff, len)
+ struct am7990_softc *sc;
+ void *tov;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t to = tov;
+ register volatile u_int16_t *bptr;
+ register u_int16_t tmp;
+
+ if (boff & 0x1) {
+ /* handle unaligned first byte */
+ bptr = ((volatile u_int16_t *)buf) + (boff - 1);
+ *to++ = (*bptr >> 8) & 0xff;
+ bptr += 2;
+ len--;
+ } else
+ bptr = ((volatile u_int16_t *)buf) + boff;
+ while (len > 1) {
+ tmp = *bptr;
+ *to++ = tmp & 0xff;
+ *to++ = (tmp >> 8) & 0xff;
+ bptr += 2;
+ len -= 2;
+ }
+ if (len == 1)
+ *to = *bptr & 0xff;
+}
+
+/*
+ * gap16: 16 bytes of data followed by 16 bytes of pad.
+ *
+ * Buffers must be 32-byte aligned.
+ */
+
+void
+le_ioasic_copytobuf_gap16(sc, fromv, boff, len)
+ struct am7990_softc *sc;
+ void *fromv;
+ int boff;
+ register int len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t from = fromv;
+ register caddr_t bptr;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+
+ /*
+ * Dispose of boff so destination of subsequent copies is
+ * 16-byte aligned.
+ */
+ if (boff) {
+ register int xfer;
+ xfer = min(len, 16 - boff);
+ bcopy(from, bptr + boff, xfer);
+ from += xfer;
+ bptr += 32;
+ len -= xfer;
+ }
+
+ /* Destination of copies is now 16-byte aligned. */
+ if (len >= 16)
+ switch ((u_long)from & (sizeof(u_int32_t) -1)) {
+ case 2:
+ /* Ethernet headers make this the dominant case. */
+ do {
+ register u_int32_t *dst = (u_int32_t*)bptr;
+ register u_int16_t t0;
+ register u_int32_t t1, t2, t3, t4;
+
+ /* read from odd-16-bit-aligned, cached src */
+ t0 = *(u_int16_t*)from;
+ t1 = *(u_int32_t*)(from+2);
+ t2 = *(u_int32_t*)(from+6);
+ t3 = *(u_int32_t*)(from+10);
+ t4 = *(u_int16_t*)(from+14);
+
+ /* DMA buffer is uncached on mips */
+ dst[0] = t0 | (t1 << 16);
+ dst[1] = (t1 >> 16) | (t2 << 16);
+ dst[2] = (t2 >> 16) | (t3 << 16);
+ dst[3] = (t3 >> 16) | (t4 << 16);
+
+ from += 16;
+ bptr += 32;
+ len -= 16;
+ } while (len >= 16);
+ break;
+
+ case 0:
+ do {
+ register u_int32_t *src = (u_int32_t*)from;
+ register u_int32_t *dst = (u_int32_t*)bptr;
+ register u_int32_t t0, t1, t2, t3;
+
+ t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
+ dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
+
+ from += 16;
+ bptr += 32;
+ len -= 16;
+ } while (len >= 16);
+ break;
+
+ default:
+ /* Does odd-aligned case ever happen? */
+ do {
+ bcopy(from, bptr, 16);
+ from += 16;
+ bptr += 32;
+ len -= 16;
+ } while (len >= 16);
+ break;
+ }
+ if (len)
+ bcopy(from, bptr, len);
+}
+
+void
+le_ioasic_copyfrombuf_gap16(sc, tov, boff, len)
+ struct am7990_softc *sc;
+ void *tov;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t to = tov;
+ register caddr_t bptr;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+
+ /* Dispose of boff. source of copy is subsequently 16-byte aligned. */
+ if (boff) {
+ register int xfer;
+ xfer = min(len, 16 - boff);
+ bcopy(bptr+boff, to, xfer);
+ to += xfer;
+ bptr += 32;
+ len -= xfer;
+ }
+ if (len >= 16)
+ switch ((u_long)to & (sizeof(u_int32_t) -1)) {
+ case 2:
+ /*
+ * to is aligned to an odd 16-bit boundary. Ethernet headers
+ * make this the dominant case (98% or more).
+ */
+ do {
+ register u_int32_t *src = (u_int32_t*)bptr;
+ register u_int32_t t0, t1, t2, t3;
+
+ /* read from uncached aligned DMA buf */
+ t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
+
+ /* write to odd-16-bit-word aligned dst */
+ *(u_int16_t *) (to+0) = (u_short) t0;
+ *(u_int32_t *) (to+2) = (t0 >> 16) | (t1 << 16);
+ *(u_int32_t *) (to+6) = (t1 >> 16) | (t2 << 16);
+ *(u_int32_t *) (to+10) = (t2 >> 16) | (t3 << 16);
+ *(u_int16_t *) (to+14) = (t3 >> 16);
+ bptr += 32;
+ to += 16;
+ len -= 16;
+ } while (len > 16);
+ break;
+ case 0:
+ /* 32-bit aligned aligned copy. Rare. */
+ do {
+ register u_int32_t *src = (u_int32_t*)bptr;
+ register u_int32_t *dst = (u_int32_t*)to;
+ register u_int32_t t0, t1, t2, t3;
+
+ t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
+ dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
+ to += 16;
+ bptr += 32;
+ len -= 16;
+ } while (len > 16);
+ break;
+
+ /* XXX Does odd-byte-aligned case ever happen? */
+ default:
+ do {
+ bcopy(bptr, to, 16);
+ to += 16;
+ bptr += 32;
+ len -= 16;
+ } while (len > 16);
+ break;
+ }
+ if (len)
+ bcopy(bptr, to, len);
+}
+
+void
+le_ioasic_zerobuf_gap16(sc, boff, len)
+ struct am7990_softc *sc;
+ int boff, len;
+{
+ volatile caddr_t buf = sc->sc_mem;
+ register caddr_t bptr;
+ register int xfer;
+
+ bptr = buf + ((boff << 1) & ~0x1f);
+ boff &= 0xf;
+ xfer = min(len, 16 - boff);
+ while (len > 0) {
+ bzero(bptr + boff, xfer);
+ bptr += 32;
+ boff = 0;
+ len -= xfer;
+ xfer = min(len, 16);
+ }
+}
+
+
+
+DRIVER_MODULE(le_ioasic, ioasic, le_ioasic_driver, le_ioasic_devclass, 0, 0);
diff --git a/sys/alpha/tc/if_levar.h b/sys/alpha/tc/if_levar.h
new file mode 100644
index 0000000..53f3f80
--- /dev/null
+++ b/sys/alpha/tc/if_levar.h
@@ -0,0 +1,69 @@
+/* $Id$ */
+/* $NetBSD: if_levar.h,v 1.4 1997/03/15 18:12:07 is Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)if_lereg.h 8.1 (Berkeley) 6/10/93
+ */
+
+/* Local Area Network Controller for Ethernet (LANCE) registers */
+struct lereg1 {
+ volatile u_int16_t ler1_rdp; /* data port */
+ int16_t pad0;
+#ifdef __alpha__
+ int32_t pad1;
+#endif
+ volatile u_int16_t ler1_rap; /* register select port */
+ int16_t pad2;
+#ifdef __alpha__
+ int32_t pad3;
+#endif
+};
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * ethercom.ec_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+struct le_softc {
+ struct am7990_softc sc_am7990; /* glue to MI code */
+
+ struct lereg1 *sc_r1; /* LANCE registers */
+};
+
+void dec_le_common_attach __P((struct am7990_softc *, u_char *));
diff --git a/sys/alpha/tc/ioasic.c b/sys/alpha/tc/ioasic.c
new file mode 100644
index 0000000..5c862a9
--- /dev/null
+++ b/sys/alpha/tc/ioasic.c
@@ -0,0 +1,381 @@
+/* $Id$ */
+/* from $NetBSD: ioasic.c,v 1.19 1998/05/27 00:18:13 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Keith Bostic, Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "opt_cpu.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+
+#include <machine/rpb.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdevs.h>
+#include <alpha/tc/ioasicreg.h>
+#include <alpha/tc/ioasicvar.h>
+
+
+#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa)
+
+static devclass_t ioasic_devclass;
+static device_t ioasic0; /* there can be only one */
+
+struct ioasic_softc {
+ device_t sc_dv;
+ vm_offset_t sc_base;
+ void *sc_cookie;
+};
+
+#define IOASIC_SOFTC(dev) (struct ioasic_softc*) device_get_softc(dev)
+
+static int ioasic_probe(device_t dev);
+static int ioasic_attach(device_t dev);
+static driver_intr_t ioasic_intrnull;
+static void ioasic_print_child(device_t bus, device_t dev);
+static void ioasic_lance_dma_setup(void *v);
+int ioasic_intr __P((void *));
+
+caddr_t le_iomem = 0;
+
+static device_method_t ioasic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ioasic_probe),
+ DEVMETHOD(device_attach, ioasic_attach),
+ DEVMETHOD(bus_print_child, ioasic_print_child),
+
+ { 0, 0 }
+};
+
+static driver_t ioasic_driver = {
+ "ioasic",
+ ioasic_methods,
+ DRIVER_TYPE_MISC,
+ sizeof(struct ioasic_softc),
+};
+
+#define IOASIC_DEV_LANCE 0
+#define IOASIC_DEV_SCC0 1
+#define IOASIC_DEV_SCC1 2
+#define IOASIC_DEV_ISDN 3
+
+#define IOASIC_DEV_BOGUS -1
+
+#define IOASIC_NCOOKIES 4
+
+#define C(x) ((void *)(u_long)x)
+
+
+struct ioasic_dev ioasic_devs[] = {
+ { "le", 0x000c0000, 0, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, },
+#ifdef notyet
+ { "z8530 ", 0x00100000, 0, C(IOASIC_DEV_SCC0), IOASIC_INTR_SCC_0, },
+ { "z8530 ", 0x00180000, 0, C(IOASIC_DEV_SCC1), IOASIC_INTR_SCC_1, },
+#endif
+ { "mcclock", 0x00200000, 0, C(IOASIC_DEV_BOGUS), 0, },
+#ifdef notyet
+ { "AMD79c30", 0x00240000, 0, C(IOASIC_DEV_ISDN), IOASIC_INTR_ISDN, },
+#endif
+};
+int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
+struct ioasicintr {
+ void (*iai_func) __P((void *));
+ void *iai_arg;
+} ioasicintrs[IOASIC_NCOOKIES];
+
+tc_addr_t ioasic_base; /* XXX XXX XXX */
+
+static int
+ioasic_probe(device_t dev)
+{
+ if (ioasic0)
+ return ENXIO;
+ if((hwrpb->rpb_type != ST_DEC_3000_300) &&
+ (hwrpb->rpb_type != ST_DEC_3000_500))
+ return ENXIO;
+ if(strcmp(device_get_name(dev),"ioasic")){
+ return ENXIO;
+ }
+ ioasic0 = dev;
+ if (hwrpb->rpb_type == ST_DEC_3000_300)
+ device_set_desc(dev, "Turbochannel ioasic: slow mode");
+ else
+ device_set_desc(dev, "Turbochannel ioasic: fast mode");
+ return 0;
+}
+
+static int
+ioasic_attach(device_t dev)
+{
+ struct ioasic_softc* sc = IOASIC_SOFTC(dev);
+ struct tc_attach_args *ta = device_get_ivars(dev);
+ device_t parent = device_get_parent(dev);
+ vm_offset_t regs,va;
+ u_long i;
+ ioasic0 = dev;
+
+ sc->sc_base = ta->ta_addr;
+ sc->sc_cookie = ta->ta_cookie;
+ ioasic_base = sc->sc_base;
+
+
+#ifdef DEC_3000_300
+ if (hwrpb->rpb_type == ST_DEC_3000_300) {
+ *(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |=
+ IOASIC_CSR_FASTMODE;
+ tc_mb();
+ }
+#endif
+ /*
+ * Turn off all device interrupt bits.
+ * (This does _not_ include 3000/300 TC option slot bits.
+ */
+ for (i = 0; i < ioasic_ndevs; i++)
+ *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
+ ~ioasic_devs[i].iad_intrbits;
+ tc_mb();
+
+ /*
+ * Set up interrupt handlers.
+ */
+ for (i = 0; i < IOASIC_NCOOKIES; i++) {
+ ioasicintrs[i].iai_func = ioasic_intrnull;
+ ioasicintrs[i].iai_arg = (void *)i;
+ }
+
+ tc_intr_establish(parent, sc->sc_cookie, 0, ioasic_intr, sc);
+
+#define LANCE_DMA_SIZE 128*1024
+#define LANCE_DMA_ALIGN 128*1024
+ /*
+ * Set up the LANCE DMA area.
+ */
+ le_iomem = (caddr_t)vm_page_alloc_contig(round_page(LANCE_DMA_SIZE),
+ 0, 0xffffffff,LANCE_DMA_ALIGN);
+ le_iomem = (caddr_t)ALPHA_PHYS_TO_K0SEG(vtophys(le_iomem));
+ ioasic_lance_dma_setup((void *)le_iomem);
+
+ /*
+ * round up our children
+ */
+
+ for (i = 0; i < ioasic_ndevs; i++) {
+ ioasic_devs[i].iada_addr = sc->sc_base + ioasic_devs[i].iad_offset;
+ device_probe_and_attach(device_add_child(dev, ioasic_devs[i].iad_modname, -1, &ioasic_devs[i]));
+ }
+ return 0;
+}
+
+static void
+ioasic_intrnull(void *val)
+{
+
+ panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld\n",
+ (u_long)val);
+}
+
+static void
+ioasic_print_child(device_t bus, device_t dev)
+{
+ struct ioasic_dev *ioasic = device_get_ivars(dev);
+ printf(" at %s%d, offset 0x%lx",
+ device_get_name(bus), device_get_unit(bus),
+ ioasic->iad_offset);
+}
+
+char *
+ioasic_lance_ether_address()
+{
+ return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base);
+}
+
+static void
+ioasic_lance_dma_setup(void *v)
+{
+ volatile u_int32_t *ldp;
+ tc_addr_t tca;
+
+ tca = (tc_addr_t)v;
+ tca &= 0xffffffff;
+ ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
+ *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
+ tc_wmb();
+ *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
+ IOASIC_CSR_DMAEN_LANCE;
+ tc_mb();
+}
+
+void
+ioasic_intr_establish(ioa, cookie, level, func, arg)
+ struct device *ioa;
+ void *cookie, *arg;
+ tc_intrlevel_t level;
+ void (*func) __P((void *));
+{
+ u_long dev, i;
+
+ dev = (u_long)cookie;
+#ifdef DIAGNOSTIC
+ /* XXX check cookie. */
+#endif
+
+ if (ioasicintrs[dev].iai_func != ioasic_intrnull)
+ panic("ioasic_intr_establish: cookie %d twice", dev);
+
+ ioasicintrs[dev].iai_func = func;
+ ioasicintrs[dev].iai_arg = arg;
+
+ /* Enable interrupts for the device. */
+ for (i = 0; i < ioasic_ndevs; i++)
+ if (ioasic_devs[i].iad_cookie == cookie)
+ break;
+ if (i == ioasic_ndevs)
+ panic("ioasic_intr_establish: invalid cookie.");
+ *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
+ ioasic_devs[i].iad_intrbits;
+ tc_mb();
+}
+
+void
+ioasic_intr_disestablish(ioa, cookie)
+ struct device *ioa;
+ void *cookie;
+{
+ u_long dev, i;
+
+ dev = (u_long)cookie;
+#ifdef DIAGNOSTIC
+ /* XXX check cookie. */
+#endif
+
+ if (ioasicintrs[dev].iai_func == ioasic_intrnull)
+ panic("ioasic_intr_disestablish: cookie %d missing intr", dev);
+
+ /* Enable interrupts for the device. */
+ for (i = 0; i < ioasic_ndevs; i++)
+ if (ioasic_devs[i].iad_cookie == cookie)
+ break;
+ if (i == ioasic_ndevs)
+ panic("ioasic_intr_disestablish: invalid cookie.");
+ *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
+ ~ioasic_devs[i].iad_intrbits;
+ tc_mb();
+
+ ioasicintrs[dev].iai_func = ioasic_intrnull;
+ ioasicintrs[dev].iai_arg = (void *)dev;
+}
+
+
+
+
+/*
+ * asic_intr --
+ * ASIC interrupt handler.
+ */
+int
+ioasic_intr(val)
+ void *val;
+{
+ register struct ioasic_softc *sc = val;
+ register int i, ifound;
+ int gifound;
+ u_int32_t sir, junk;
+ volatile u_int32_t *sirp, *junkp;
+
+ sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base);
+
+ gifound = 0;
+ do {
+ ifound = 0;
+ tc_syncbus();
+
+ sir = *sirp;
+
+ /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
+#define CHECKINTR(slot, bits) \
+ if (sir & bits) { \
+ ifound = 1; \
+ (*ioasicintrs[slot].iai_func) \
+ (ioasicintrs[slot].iai_arg); \
+ }
+ CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0);
+ CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1);
+ CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE);
+ CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN);
+
+ gifound |= ifound;
+ } while (ifound);
+
+ return (gifound);
+}
+
+
+DRIVER_MODULE(ioasic, tc, ioasic_driver, ioasic_devclass, 0, 0);
+
diff --git a/sys/alpha/tc/ioasicreg.h b/sys/alpha/tc/ioasicreg.h
new file mode 100644
index 0000000..f7ca6d6
--- /dev/null
+++ b/sys/alpha/tc/ioasicreg.h
@@ -0,0 +1,227 @@
+/* $Id$ */
+/* $NetBSD: ioasicreg.h,v 1.2 1997/04/06 22:30:28 cgd Exp $ */
+
+/*
+ * Copyright (c) 1991,1990,1989,1994,1995 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University,
+ * Ralph Campbell and Rick Macklem.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)asic.h 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * Slot definitions
+ */
+
+#define IOASIC_SLOT_0_START 0x000000
+#define IOASIC_SLOT_1_START 0x040000
+#define IOASIC_SLOT_2_START 0x080000
+#define IOASIC_SLOT_3_START 0x0c0000
+#define IOASIC_SLOT_4_START 0x100000
+#define IOASIC_SLOT_5_START 0x140000
+#define IOASIC_SLOT_6_START 0x180000
+#define IOASIC_SLOT_7_START 0x1c0000
+#define IOASIC_SLOT_8_START 0x200000
+#define IOASIC_SLOT_9_START 0x240000
+#define IOASIC_SLOT_10_START 0x280000
+#define IOASIC_SLOT_11_START 0x2c0000
+#define IOASIC_SLOT_12_START 0x300000
+#define IOASIC_SLOT_13_START 0x340000
+#define IOASIC_SLOT_14_START 0x380000
+#define IOASIC_SLOT_15_START 0x3c0000
+#define IOASIC_SLOTS_END 0x3fffff
+
+/*
+ * Register offsets (slot 1)
+ */
+
+#define IOASIC_SCSI_DMAPTR IOASIC_SLOT_1_START+0x000
+#define IOASIC_SCSI_NEXTPTR IOASIC_SLOT_1_START+0x010
+#define IOASIC_LANCE_DMAPTR IOASIC_SLOT_1_START+0x020
+#define IOASIC_SCC_T1_DMAPTR IOASIC_SLOT_1_START+0x030
+#define IOASIC_SCC_R1_DMAPTR IOASIC_SLOT_1_START+0x040
+#define IOASIC_SCC_T2_DMAPTR IOASIC_SLOT_1_START+0x050
+#define IOASIC_SCC_R2_DMAPTR IOASIC_SLOT_1_START+0x060
+#define IOASIC_FLOPPY_DMAPTR IOASIC_SLOT_1_START+0x070
+#define IOASIC_ISDN_X_DMAPTR IOASIC_SLOT_1_START+0x080
+#define IOASIC_ISDN_X_NEXTPTR IOASIC_SLOT_1_START+0x090
+#define IOASIC_ISDN_R_DMAPTR IOASIC_SLOT_1_START+0x0a0
+#define IOASIC_ISDN_R_NEXTPTR IOASIC_SLOT_1_START+0x0b0
+#define IOASIC_BUFF0 IOASIC_SLOT_1_START+0x0c0
+#define IOASIC_BUFF1 IOASIC_SLOT_1_START+0x0d0
+#define IOASIC_BUFF2 IOASIC_SLOT_1_START+0x0e0
+#define IOASIC_BUFF3 IOASIC_SLOT_1_START+0x0f0
+#define IOASIC_CSR IOASIC_SLOT_1_START+0x100
+#define IOASIC_INTR IOASIC_SLOT_1_START+0x110
+#define IOASIC_IMSK IOASIC_SLOT_1_START+0x120
+#define IOASIC_CURADDR IOASIC_SLOT_1_START+0x130
+#define IOASIC_ISDN_X_DATA IOASIC_SLOT_1_START+0x140
+#define IOASIC_ISDN_R_DATA IOASIC_SLOT_1_START+0x150
+#define IOASIC_LANCE_DECODE IOASIC_SLOT_1_START+0x160
+#define IOASIC_SCSI_DECODE IOASIC_SLOT_1_START+0x170
+#define IOASIC_SCC0_DECODE IOASIC_SLOT_1_START+0x180
+#define IOASIC_SCC1_DECODE IOASIC_SLOT_1_START+0x190
+#define IOASIC_FLOPPY_DECODE IOASIC_SLOT_1_START+0x1a0
+#define IOASIC_SCSI_SCR IOASIC_SLOT_1_START+0x1b0
+#define IOASIC_SCSI_SDR0 IOASIC_SLOT_1_START+0x1c0
+#define IOASIC_SCSI_SDR1 IOASIC_SLOT_1_START+0x1d0
+
+/* System Status and control Register (SSR). */
+#define IOASIC_CSR_DMAEN_T1 0x80000000 /* rw */
+#define IOASIC_CSR_DMAEN_R1 0x40000000 /* rw */
+#define IOASIC_CSR_DMAEN_T2 0x20000000 /* rw */
+#define IOASIC_CSR_DMAEN_R2 0x10000000 /* rw */
+#define IOASIC_CSR_FASTMODE 0x08000000 /* rw */
+#define IOASIC_CSR_xxx 0x07800000 /* unused/reserved */
+#define IOASIC_CSR_FLOPPY_DIR 0x00400000 /* rw */
+#define IOASIC_CSR_DMAEN_FLOPPY 0x00200000 /* rw */
+#define IOASIC_CSR_DMAEN_ISDN_T 0x00100000 /* rw */
+#define IOASIC_CSR_DMAEN_ISDN_R 0x00080000 /* rw */
+#define IOASIC_CSR_SCSI_DIR 0x00040000 /* rw */
+#define IOASIC_CSR_DMAEN_SCSI 0x00020000 /* rw */
+#define IOASIC_CSR_DMAEN_LANCE 0x00010000 /* rw */
+/* low 16 bits are rw gp outputs */
+
+/* System Interrupt Register (and Interrupt Mask Register). */
+#define IOASIC_INTR_T1_PAGE_END 0x80000000 /* rz */
+#define IOASIC_INTR_T1_READ_E 0x40000000 /* rz */
+#define IOASIC_INTR_R1_HALF_PAGE 0x20000000 /* rz */
+#define IOASIC_INTR_R1_DMA_OVRUN 0x10000000 /* rz */
+#define IOASIC_INTR_T2_PAGE_END 0x08000000 /* rz */
+#define IOASIC_INTR_T2_READ_E 0x04000000 /* rz */
+#define IOASIC_INTR_R2_HALF_PAGE 0x02000000 /* rz */
+#define IOASIC_INTR_R2_DMA_OVRUN 0x01000000 /* rz */
+#define IOASIC_INTR_FLOPPY_DMA_E 0x00800000 /* rz */
+#define IOASIC_INTR_ISDN_PTR_LOAD 0x00400000 /* rz */
+#define IOASIC_INTR_ISDN_OVRUN 0x00200000 /* rz */
+#define IOASIC_INTR_ISDN_READ_E 0x00100000 /* rz */
+#define IOASIC_INTR_SCSI_PTR_LOAD 0x00080000 /* rz */
+#define IOASIC_INTR_SCSI_OVRUN 0x00040000 /* rz */
+#define IOASIC_INTR_SCSI_READ_E 0x00020000 /* rz */
+#define IOASIC_INTR_LANCE_READ_E 0x00010000 /* rz */
+#define IOASIC_INTR_ISDN 0x00002000 /* ro */
+#define IOASIC_INTR_SEC_CON 0x00000200 /* ro */
+#define IOASIC_INTR_LANCE 0x00000100 /* ro */
+#define IOASIC_INTR_SCC_1 0x00000080 /* ro */
+#define IOASIC_INTR_SCC_0 0x00000040 /* ro */
+#define IOASIC_INTR_ALT_CON 0x00000008 /* ro - 3000/500 */
+#define IOASIC_INTR_300_OPT1 IOASIC_INTR_ALT_CON /* ro - 3000/300 */
+#define IOASIC_INTR_300_OPT0 0x00000004 /* ro - 3000/300 */
+
+/* DMA pointer registers (SCSI, Comm, ...) */
+
+#define IOASIC_DMAPTR_MASK 0xffffffe0
+#define IOASIC_DMAPTR_SHIFT 5
+#define IOASIC_DMAPTR_SET(reg,val) \
+ (reg) = (((val)<<IOASIC_DMAPTR_SHIFT)&IOASIC_DMAPTR_MASK)
+#define IOASIC_DMAPTR_GET(reg,val) \
+ (val) = (((reg)&IOASIC_DMAPTR_MASK)>>IOASIC_DMAPTR_SHIFT)
+#define IOASIC_DMA_ADDR(p) (((unsigned)p) << (5-2))
+
+/* For the LANCE DMA pointer register initialization the above suffices */
+
+/* More SCSI DMA registers */
+
+#define IOASIC_SCR_STATUS 0x00000004
+#define IOASIC_SCR_WORD 0x00000003
+
+/* Various Decode registers */
+
+#define IOASIC_DECODE_HW_ADDRESS 0x000003f0
+#define IOASIC_DECODE_CHIP_SELECT 0x0000000f
+
+/*
+ * Asic register addresses at offset from base.
+ */
+#define IOASIC_REG_SCSI_DMAPTR(base) ((base) + IOASIC_SCSI_DMAPTR)
+#define IOASIC_REG_SCSI_DMANPTR(base) ((base) + IOASIC_SCSI_NEXTPTR)
+#define IOASIC_REG_LANCE_DMAPTR(base) ((base) + IOASIC_LANCE_DMAPTR)
+#define IOASIC_REG_SCC_T1_DMAPTR(base) ((base) + IOASIC_SCC_T1_DMAPTR)
+#define IOASIC_REG_SCC_R1_DMAPTR(base) ((base) + IOASIC_SCC_R1_DMAPTR)
+#define IOASIC_REG_SCC_T2_DMAPTR(base) ((base) + IOASIC_SCC_T2_DMAPTR)
+#define IOASIC_REG_SCC_R2_DMAPTR(base) ((base) + IOASIC_SCC_R2_DMAPTR)
+#define IOASIC_REG_FLOPPY_DMAPTR(base) ((base) + IOASIC_FLOPPY_DMAPTR)
+#define IOASIC_REG_ISDN_X_DMAPTR(base) ((base) + IOASIC_ISDN_X_DMAPTR)
+#define IOASIC_REG_ISDN_X_NEXTPTR(base) ((base) + IOASIC_ISDN_X_NEXTPTR)
+#define IOASIC_REG_ISDN_R_DMAPTR(base) ((base) + IOASIC_ISDN_R_DMAPTR)
+#define IOASIC_REG_ISDN_R_NEXTPTR(base) ((base) + IOASIC_ISDN_R_NEXTPTR)
+#define IOASIC_REG_BUFF0(base) ((base) + IOASIC_BUFF0)
+#define IOASIC_REG_BUFF1(base) ((base) + IOASIC_BUFF1)
+#define IOASIC_REG_BUFF2(base) ((base) + IOASIC_BUFF2)
+#define IOASIC_REG_BUFF3(base) ((base) + IOASIC_BUFF3)
+#define IOASIC_REG_CSR(base) ((base) + IOASIC_CSR)
+#define IOASIC_REG_INTR(base) ((base) + IOASIC_INTR)
+#define IOASIC_REG_IMSK(base) ((base) + IOASIC_IMSK)
+#define IOASIC_REG_CURADDR(base) ((base) + IOASIC_CURADDR)
+#define IOASIC_REG_ISDN_X_DATA(base) ((base) + IOASIC_ISDN_X_DATA)
+#define IOASIC_REG_ISDN_R_DATA(base) ((base) + IOASIC_ISDN_R_DATA)
+#define IOASIC_REG_LANCE_DECODE(base) ((base) + IOASIC_LANCE_DECODE)
+#define IOASIC_REG_SCSI_DECODE(base) ((base) + IOASIC_SCSI_DECODE)
+#define IOASIC_REG_SCC0_DECODE(base) ((base) + IOASIC_SCC0_DECODE)
+#define IOASIC_REG_SCC1_DECODE(base) ((base) + IOASIC_SCC1_DECODE)
+#define IOASIC_REG_FLOPPY_DECODE(base) ((base) + IOASIC_FLOPPY_DECODE)
+#define IOASIC_REG_SCSI_SCR(base) ((base) + IOASIC_SCSI_SCR)
+#define IOASIC_REG_SCSI_SDR0(base) ((base) + IOASIC_SCSI_SDR0)
+#define IOASIC_REG_SCSI_SDR1(base) ((base) + IOASIC_SCSI_SDR1)
+
+/*
+ * And slot assignments.
+ */
+#define IOASIC_SYS_ETHER_ADDRESS(base) ((base) + IOASIC_SLOT_2_START)
+#define IOASIC_SYS_LANCE(base) ((base) + IOASIC_SLOT_3_START)
diff --git a/sys/alpha/tc/ioasicvar.h b/sys/alpha/tc/ioasicvar.h
new file mode 100644
index 0000000..cb48da0
--- /dev/null
+++ b/sys/alpha/tc/ioasicvar.h
@@ -0,0 +1,59 @@
+/* $Id$ */
+/* $NetBSD: ioasicvar.h,v 1.5 1998/01/19 02:50:19 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * IOASIC subdevice attachment information.
+ */
+
+/* Attachment arguments. */
+struct ioasicdev_attach_args {
+ char iada_modname[TC_ROM_LLEN];
+ tc_offset_t iada_offset;
+ tc_addr_t iada_addr;
+ void *iada_cookie;
+};
+
+struct ioasic_dev {
+ char *iad_modname;
+ tc_offset_t iad_offset;
+ tc_addr_t iada_addr;
+ void *iad_cookie;
+ u_int32_t iad_intrbits;
+};
+
+
+char *ioasic_lance_ether_address __P((void));
+/*
+ * Interrupt establishment/disestablishment functions
+ */
+
+void ioasic_intr_establish __P((struct device *, void *, tc_intrlevel_t,
+ void (*)(void *), void *));
+void ioasic_intr_disestablish __P((struct device *, void *));
diff --git a/sys/alpha/tc/mcclock_ioasic.c b/sys/alpha/tc/mcclock_ioasic.c
new file mode 100644
index 0000000..2dee0c0
--- /dev/null
+++ b/sys/alpha/tc/mcclock_ioasic.c
@@ -0,0 +1,130 @@
+/* $Id$ */
+/* $NetBSD: mcclock_ioasic.c,v 1.8 1997/09/02 13:20:14 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/clockvar.h>
+#include <dev/dec/mcclockvar.h>
+
+#include <alpha/tlsb/gbusvar.h>
+
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdevs.h>
+#include <alpha/tc/ioasicreg.h>
+#include <alpha/tc/ioasicvar.h>
+
+#include <dev/dec/mc146818reg.h>
+
+
+
+struct mcclock_ioasic_clockdatum {
+ u_char datum;
+ char pad[3];
+};
+
+#define KV(_addr) ((caddr_t)ALPHA_PHYS_TO_K0SEG((_addr)))
+/*
+ * Registers are 64 bytes apart (and 1 byte wide)
+ */
+#define REGSHIFT 6
+
+struct mcclock_ioasic_softc {
+ unsigned long regbase;
+ struct mcclock_ioasic_clockdatum *sc_dp;
+};
+
+static int mcclock_ioasic_probe(device_t dev);
+static int mcclock_ioasic_attach(device_t dev);
+static void mcclock_ioasic_write(device_t, u_int, u_int);
+static u_int mcclock_ioasic_read(device_t, u_int);
+
+static device_method_t mcclock_ioasic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, mcclock_ioasic_probe),
+ DEVMETHOD(device_attach, mcclock_ioasic_attach),
+
+ /* mcclock interface */
+ DEVMETHOD(mcclock_write, mcclock_ioasic_write),
+ DEVMETHOD(mcclock_read, mcclock_ioasic_read),
+
+ /* clock interface */
+ DEVMETHOD(clock_init, mcclock_init),
+ DEVMETHOD(clock_get, mcclock_get),
+ DEVMETHOD(clock_set, mcclock_set),
+
+ { 0, 0 }
+};
+
+static driver_t mcclock_ioasic_driver = {
+ "mcclock",
+ mcclock_ioasic_methods,
+ DRIVER_TYPE_MISC,
+ sizeof(struct mcclock_ioasic_softc),
+};
+
+static devclass_t mcclock_devclass;
+
+int
+mcclock_ioasic_probe(device_t dev)
+{
+ device_set_desc(dev, "MC146818A real time clock");
+ return 0;
+}
+
+static int
+mcclock_ioasic_attach(device_t dev)
+{
+ struct mcclock_ioasic_softc *sc = device_get_softc(dev);
+ struct ioasic_dev *ioasic = device_get_ivars(dev);
+ sc->sc_dp = (struct mcclock_ioasic_clockdatum *)ioasic->iada_addr;
+ mcclock_attach(dev);
+ return 0;
+}
+
+void
+mcclock_ioasic_write(device_t dev, u_int reg, u_int datum)
+{
+ struct mcclock_ioasic_softc *sc = device_get_softc(dev);
+ sc->sc_dp[reg].datum = datum;
+}
+
+u_int
+mcclock_ioasic_read(device_t dev, u_int reg)
+{
+ struct mcclock_ioasic_softc *sc = device_get_softc(dev);
+ return (sc->sc_dp[reg].datum);
+}
+
+DRIVER_MODULE(mcclock, ioasic, mcclock_ioasic_driver, mcclock_devclass, 0, 0);
diff --git a/sys/alpha/tc/sticreg.h b/sys/alpha/tc/sticreg.h
new file mode 100644
index 0000000..31e30e5
--- /dev/null
+++ b/sys/alpha/tc/sticreg.h
@@ -0,0 +1,101 @@
+/* $Id$ */
+/* $NetBSD: sticreg.h,v 1.1 1997/11/08 07:27:50 jonathan Exp $ */
+
+/*
+ * Copyright (c) 1997 Jonathan Stone
+ * 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 Jonathan Stone for
+ * the NetBSD Project.
+ * 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.
+ */
+
+/*
+ * Register definitions for the pixelstamp and stamp interface chip (STIC)
+ * used in PMAG-C 2-d and PMAG-D 3-d accelerated TurboChannel framebuffers.
+ */
+
+#ifndef _TC_STICREG_H_
+#define _TC_STICREG_H_
+
+struct stic_regs {
+ volatile int32_t stic__pad0, __pad1;
+ volatile int32_t hsync;
+ volatile int32_t hsync2;
+ volatile int32_t hblank;
+ volatile int32_t vsync;
+ volatile int32_t vblank;
+ volatile int32_t vtest;
+ volatile int32_t ipdvint;
+ volatile int32_t stic__pad2;
+ volatile int32_t sticsr;
+ volatile int32_t busdat;
+ volatile int32_t busadr;
+ volatile int32_t stic__pad3;
+ volatile int32_t buscsr;
+ volatile int32_t modcl;
+};
+
+#define STICADDR(x) ((volatile struct stic_regs*) (x))
+
+
+/*
+ * Bit definitions for stic_regs.stic_csr.
+ * these appear to exactly what the PROM tests use.
+ */
+#define STIC_CSR_TSTFNC 0x00000003
+# define STIC_CSR_TSTFNC_NORMAL 0
+# define STIC_CSR_TSTFNC_PARITY 1
+# define STIC_CSR_TSTFNC_CNTPIX 2
+# define STIC_CSR_TSTFNC_TSTDAC 3
+#define STIC_CSR_CHECKPAR 0x00000004
+#define STIC_CSR_STARTVT 0x00000010
+#define STIC_CSR_START 0x00000020
+#define STIC_CSR_RESET 0x00000040
+#define STIC_CSR_STARTST 0x00000080
+
+/*
+ * Bit definitions for stic_regs.int.
+ * Three four-bit wide fields, for error (E), vertical-blank (V), and
+ * packetbuf-done (P) intererupts, respectively.
+ * The low-order three bits of each field are enable, requested,
+ * and acknowledge bits. The top bit of each field is unused.
+ */
+#define STIC_INT_E_EN 0x00000001
+#define STIC_INT_E 0x00000002
+#define STIC_INT_E_WE 0x00000004
+
+#define STIC_INT_V_EN 0x00000100
+#define STIC_INT_V 0x00000200
+#define STIC_INT_V_WE 0x00000400
+
+#define STIC_INT_P_EN 0x00010000
+#define STIC_INT_P 0x00020000
+#define STIC_INT_P_WE 0x00040000
+
+#define STIC_INT_WE (STIC_INT_E_WE|STIC_INT_V_WE|STIC_INT_PE_WE)
+#define STIC_INT_CLR (STIC_INT_E_EN|STIC_INT_V_EN|STIC_INT_P_EN)
+
+#endif /* _TC_STICREG_H_ */
diff --git a/sys/alpha/tc/sticvar.h b/sys/alpha/tc/sticvar.h
new file mode 100644
index 0000000..fd9ed46
--- /dev/null
+++ b/sys/alpha/tc/sticvar.h
@@ -0,0 +1,53 @@
+/* $Id$ */
+/* $NetBSD: sticvar.h,v 1.1 1997/11/08 07:27:51 jonathan Exp $ */
+
+/*
+ * Copyright (c) 1997 Jonathan Stone
+ * 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 Jonathan Stone for
+ * the NetBSD Project.
+ * 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.
+ */
+
+#ifndef _TC_STICVAR_H_
+#define _TC_STICVAR_H_
+
+#include <dev/tc/sticreg.h>
+
+/*
+ * A "softc" used to communicate address info to functions
+ * that need to deal with all of the STAMP, the STIC, and the VDAC,
+ * on eihter 2-d or 3-d boards.
+ */
+struct stic_softc {
+ struct stic_reg *stic_addr;
+ void * stamp_addr;
+ void * vdac_addr;
+ void* stic_pktbuf; /* kva of packet/polling area. */
+};
+
+int stic_init __P((struct stic_softc *stic_sc));
+#endif /*_TC_STICVAR_H_ */
diff --git a/sys/alpha/tc/tc.c b/sys/alpha/tc/tc.c
new file mode 100644
index 0000000..0c88726
--- /dev/null
+++ b/sys/alpha/tc/tc.c
@@ -0,0 +1,704 @@
+/* $Id$ */
+/*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <machine/rpb.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdevs.h>
+#include <alpha/tc/ioasicreg.h>
+
+/*#include <alpha/tc/dwlpxreg.h>*/
+
+#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa)
+
+static devclass_t tc_devclass;
+device_t tc0; /* XXX only one for now */
+
+struct tc_softc {
+ device_t sc_dv;
+ int sc_speed;
+ int sc_nslots;
+ int nbuiltins;
+ struct tc_builtin *builtins;
+ struct tc_slotdesc *sc_slots;
+ void (*sc_intr_establish) __P((struct device *, void *,
+ tc_intrlevel_t, int (*)(void *), void *));
+ void (*sc_intr_disestablish) __P((struct device *, void *));
+/* bus_dma_tag_t (*sc_get_dma_tag) __P((int));
+*/
+};
+#define NTC_ROMOFFS 2
+static tc_offset_t tc_slot_romoffs[NTC_ROMOFFS] = {
+ TC_SLOT_ROM,
+ TC_SLOT_PROTOROM,
+};
+
+
+#define TC_SOFTC(dev) (struct tc_softc*) device_get_softc(dev)
+
+static int tc_probe(device_t dev);
+static int tc_attach(device_t dev);
+static void tc_print_child(device_t bus, device_t dev);
+static driver_intr_t tc_intr;
+int tc_checkslot( tc_addr_t slotbase, char *namep);
+
+static device_method_t tc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tc_probe),
+ DEVMETHOD(device_attach, tc_attach),
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, tc_print_child),
+ { 0, 0 },
+};
+
+static driver_t tc_driver = {
+ "tc",
+ tc_methods,
+ DRIVER_TYPE_MISC,
+ sizeof(struct tc_softc),
+};
+
+#define C(x) ((void *)(u_long)x)
+
+int tc_intrnull __P((void *));
+struct tcintr {
+ int (*tci_func) __P((void *));
+ void *tci_arg;
+};
+
+#ifdef DEC_3000_300
+
+void tc_3000_300_intr_setup __P((void));
+void tc_3000_300_intr_establish __P((struct device *, void *,
+ tc_intrlevel_t, int (*)(void *), void *));
+void tc_3000_300_intr_disestablish __P((struct device *, void *));
+void tc_3000_300_iointr __P((void *, unsigned long));
+
+
+
+#define DEC_3000_300_IOASIC_ADDR KV(0x1a0000000)
+
+struct tc_slotdesc tc_3000_300_slots[] = {
+ { KV(0x100000000), C(TC_3000_300_DEV_OPT0), }, /* 0 - opt slot 0 */
+ { KV(0x120000000), C(TC_3000_300_DEV_OPT1), }, /* 1 - opt slot 1 */
+ { KV(0x180000000), C(TC_3000_300_DEV_BOGUS), }, /* 2 - TCDS ASIC */
+ { KV(0x1a0000000), C(TC_3000_300_DEV_BOGUS), }, /* 3 - IOCTL ASIC */
+ { KV(0x1c0000000), C(TC_3000_300_DEV_CXTURBO), }, /* 4 - CXTurbo */
+};
+int tc_3000_300_nslots =
+ sizeof(tc_3000_300_slots) / sizeof(tc_3000_300_slots[0]);
+
+struct tc_builtin tc_3000_300_builtins[] = {
+#ifdef notyet
+ { "PMAGB-BA", 4, 0x02000000, C(TC_3000_300_DEV_CXTURBO), },
+#endif
+ { "ioasic", 3, 0x00000000, C(TC_3000_300_DEV_IOASIC), },
+ { "tcds", 2, 0x00000000, C(TC_3000_300_DEV_TCDS), },
+};
+int tc_3000_300_nbuiltins =
+ sizeof(tc_3000_300_builtins) / sizeof(tc_3000_300_builtins[0]);
+
+struct tcintr tc_3000_300_intr[TC_3000_300_NCOOKIES];
+
+
+#endif /* DEC_3000_300 */
+
+#ifdef DEC_3000_500
+void tc_3000_500_intr_setup __P((void));
+void tc_3000_500_intr_establish __P((struct device *, void *,
+ tc_intrlevel_t, int (*)(void *), void *));
+void tc_3000_500_intr_disestablish __P((struct device *, void *));
+void tc_3000_500_iointr __P((void *, unsigned long));
+
+struct tc_slotdesc tc_3000_500_slots[] = {
+ { KV(0x100000000), C(TC_3000_500_DEV_OPT0), }, /* 0 - opt slot 0 */
+ { KV(0x120000000), C(TC_3000_500_DEV_OPT1), }, /* 1 - opt slot 1 */
+ { KV(0x140000000), C(TC_3000_500_DEV_OPT2), }, /* 2 - opt slot 2 */
+ { KV(0x160000000), C(TC_3000_500_DEV_OPT3), }, /* 3 - opt slot 3 */
+ { KV(0x180000000), C(TC_3000_500_DEV_OPT4), }, /* 4 - opt slot 4 */
+ { KV(0x1a0000000), C(TC_3000_500_DEV_OPT5), }, /* 5 - opt slot 5 */
+ { KV(0x1c0000000), C(TC_3000_500_DEV_BOGUS), }, /* 6 - TCDS ASIC */
+ { KV(0x1e0000000), C(TC_3000_500_DEV_BOGUS), }, /* 7 - IOCTL ASIC */
+};
+int tc_3000_500_nslots =
+ sizeof(tc_3000_500_slots) / sizeof(tc_3000_500_slots[0]);
+
+struct tc_builtin tc_3000_500_builtins[] = {
+ { "ioasic", 7, 0x00000000, C(TC_3000_500_DEV_IOASIC), },
+#ifdef notyet
+ { "PMAGB-BA", 7, 0x02000000, C(TC_3000_500_DEV_CXTURBO), },
+#endif
+ { "tcds", 6, 0x00000000, C(TC_3000_500_DEV_TCDS), },
+};
+int tc_3000_500_nbuiltins = sizeof(tc_3000_500_builtins) /
+ sizeof(tc_3000_500_builtins[0]);
+
+u_int32_t tc_3000_500_intrbits[TC_3000_500_NCOOKIES] = {
+ TC_3000_500_IR_OPT0,
+ TC_3000_500_IR_OPT1,
+ TC_3000_500_IR_OPT2,
+ TC_3000_500_IR_OPT3,
+ TC_3000_500_IR_OPT4,
+ TC_3000_500_IR_OPT5,
+ TC_3000_500_IR_TCDS,
+ TC_3000_500_IR_IOASIC,
+ TC_3000_500_IR_CXTURBO,
+};
+
+struct tcintr tc_3000_500_intr[TC_3000_500_NCOOKIES];
+
+u_int32_t tc_3000_500_imask; /* intrs we want to ignore; mirrors IMR. */
+
+
+#endif /* DEC_3000_500 */
+
+
+#ifdef DEC_3000_300
+
+void
+tc_3000_300_intr_setup()
+{
+ volatile u_int32_t *imskp;
+ u_long i;
+
+ /*
+ * Disable all interrupts that we can (can't disable builtins).
+ */
+ imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR);
+ *imskp &= ~(IOASIC_INTR_300_OPT0 | IOASIC_INTR_300_OPT1);
+
+ /*
+ * Set up interrupt handlers.
+ */
+ for (i = 0; i < TC_3000_300_NCOOKIES; i++) {
+ tc_3000_300_intr[i].tci_func = tc_intrnull;
+ tc_3000_300_intr[i].tci_arg = (void *)i;
+ }
+}
+
+void
+tc_3000_300_intr_establish(tcadev, cookie, level, func, arg)
+ struct device *tcadev;
+ void *cookie, *arg;
+ tc_intrlevel_t level;
+ int (*func) __P((void *));
+{
+ volatile u_int32_t *imskp;
+ u_long dev = (u_long)cookie;
+
+#ifdef DIAGNOSTIC
+ /* XXX bounds-check cookie. */
+#endif
+
+ if (tc_3000_300_intr[dev].tci_func != tc_intrnull)
+ panic("tc_3000_300_intr_establish: cookie %d twice", dev);
+
+ tc_3000_300_intr[dev].tci_func = func;
+ tc_3000_300_intr[dev].tci_arg = arg;
+
+ imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR);
+ switch (dev) {
+ case TC_3000_300_DEV_OPT0:
+ *imskp |= IOASIC_INTR_300_OPT0;
+ break;
+ case TC_3000_300_DEV_OPT1:
+ *imskp |= IOASIC_INTR_300_OPT1;
+ break;
+ default:
+ /* interrupts for builtins always enabled */
+ break;
+ }
+}
+
+void
+tc_3000_300_intr_disestablish(tcadev, cookie)
+ struct device *tcadev;
+ void *cookie;
+{
+ volatile u_int32_t *imskp;
+ u_long dev = (u_long)cookie;
+
+#ifdef DIAGNOSTIC
+ /* XXX bounds-check cookie. */
+#endif
+
+ if (tc_3000_300_intr[dev].tci_func == tc_intrnull)
+ panic("tc_3000_300_intr_disestablish: cookie %d bad intr",
+ dev);
+
+ imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR);
+ switch (dev) {
+ case TC_3000_300_DEV_OPT0:
+ *imskp &= ~IOASIC_INTR_300_OPT0;
+ break;
+ case TC_3000_300_DEV_OPT1:
+ *imskp &= ~IOASIC_INTR_300_OPT1;
+ break;
+ default:
+ /* interrupts for builtins always enabled */
+ break;
+ }
+
+ tc_3000_300_intr[dev].tci_func = tc_intrnull;
+ tc_3000_300_intr[dev].tci_arg = (void *)dev;
+}
+
+void
+tc_3000_300_iointr(framep, vec)
+ void *framep;
+ unsigned long vec;
+{
+ u_int32_t tcir, ioasicir, ioasicimr;
+ int ifound;
+
+#ifdef DIAGNOSTIC
+ int s;
+ if (vec != 0x800)
+ panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec);
+ s = splhigh();
+ if (s != ALPHA_PSL_IPL_IO)
+ panic("INVALID ASSUMPTION: IPL %d, not %d", s,
+ ALPHA_PSL_IPL_IO);
+ splx(s);
+#endif
+
+ do {
+ tc_syncbus();
+
+ /* find out what interrupts/errors occurred */
+ tcir = *(volatile u_int32_t *)TC_3000_300_IR;
+ ioasicir = *(volatile u_int32_t *)
+ IOASIC_REG_INTR(DEC_3000_300_IOASIC_ADDR);
+ ioasicimr = *(volatile u_int32_t *)
+ IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR);
+ tc_mb();
+
+ /* Ignore interrupts that aren't enabled out. */
+ ioasicir &= ioasicimr;
+
+ /* clear the interrupts/errors we found. */
+ *(volatile u_int32_t *)TC_3000_300_IR = tcir;
+ /* XXX can't clear TC option slot interrupts here? */
+ tc_wmb();
+
+ ifound = 0;
+
+
+#define CHECKINTR(slot, flag) \
+ if (flag) { \
+ ifound = 1; \
+ (*tc_3000_300_intr[slot].tci_func) \
+ (tc_3000_300_intr[slot].tci_arg); \
+ }
+ /* Do them in order of priority; highest slot # first. */
+ CHECKINTR(TC_3000_300_DEV_CXTURBO,
+ tcir & TC_3000_300_IR_CXTURBO);
+ CHECKINTR(TC_3000_300_DEV_IOASIC,
+ (tcir & TC_3000_300_IR_IOASIC) &&
+ (ioasicir & ~(IOASIC_INTR_300_OPT1|IOASIC_INTR_300_OPT0)));
+ CHECKINTR(TC_3000_300_DEV_TCDS, tcir & TC_3000_300_IR_TCDS);
+ CHECKINTR(TC_3000_300_DEV_OPT1,
+ ioasicir & IOASIC_INTR_300_OPT1);
+ CHECKINTR(TC_3000_300_DEV_OPT0,
+ ioasicir & IOASIC_INTR_300_OPT0);
+#undef CHECKINTR
+
+#ifdef DIAGNOSTIC
+#define PRINTINTR(msg, bits) \
+ if (tcir & bits) \
+ printf(msg);
+ PRINTINTR("BCache tag parity error\n",
+ TC_3000_300_IR_BCTAGPARITY);
+ PRINTINTR("TC overrun error\n", TC_3000_300_IR_TCOVERRUN);
+ PRINTINTR("TC I/O timeout\n", TC_3000_300_IR_TCTIMEOUT);
+ PRINTINTR("Bcache parity error\n",
+ TC_3000_300_IR_BCACHEPARITY);
+ PRINTINTR("Memory parity error\n", TC_3000_300_IR_MEMPARITY);
+#undef PRINTINTR
+#endif
+ } while (ifound);
+}
+
+#endif /* DEC_3000_300 */
+
+#ifdef DEC_3000_500
+
+void
+tc_3000_500_intr_setup()
+{
+ u_long i;
+
+ /*
+ * Disable all slot interrupts. Note that this cannot
+ * actually disable CXTurbo, TCDS, and IOASIC interrupts.
+ */
+ tc_3000_500_imask = *(volatile u_int32_t *)TC_3000_500_IMR_READ;
+ for (i = 0; i < TC_3000_500_NCOOKIES; i++)
+ tc_3000_500_imask |= tc_3000_500_intrbits[i];
+ *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
+ tc_mb();
+
+ /*
+ * Set up interrupt handlers.
+ */
+ for (i = 0; i < TC_3000_500_NCOOKIES; i++) {
+ tc_3000_500_intr[i].tci_func = tc_intrnull;
+ tc_3000_500_intr[i].tci_arg = (void *)i;
+ }
+}
+
+void
+tc_3000_500_intr_establish(tcadev, cookie, level, func, arg)
+ struct device *tcadev;
+ void *cookie, *arg;
+ tc_intrlevel_t level;
+ int (*func) __P((void *));
+{
+ u_long dev = (u_long)cookie;
+
+#ifdef DIAGNOSTIC
+ /* XXX bounds-check cookie. */
+#endif
+
+ if (tc_3000_500_intr[dev].tci_func != tc_intrnull)
+ panic("tc_3000_500_intr_establish: cookie %d twice", dev);
+
+ tc_3000_500_intr[dev].tci_func = func;
+ tc_3000_500_intr[dev].tci_arg = arg;
+
+ tc_3000_500_imask &= ~tc_3000_500_intrbits[dev];
+ *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
+ tc_mb();
+}
+
+void
+tc_3000_500_intr_disestablish(tcadev, cookie)
+ struct device *tcadev;
+ void *cookie;
+{
+ u_long dev = (u_long)cookie;
+
+#ifdef DIAGNOSTIC
+ /* XXX bounds-check cookie. */
+#endif
+
+ if (tc_3000_500_intr[dev].tci_func == tc_intrnull)
+ panic("tc_3000_500_intr_disestablish: cookie %d bad intr",
+ dev);
+
+ tc_3000_500_imask |= tc_3000_500_intrbits[dev];
+ *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
+ tc_mb();
+
+ tc_3000_500_intr[dev].tci_func = tc_intrnull;
+ tc_3000_500_intr[dev].tci_arg = (void *)dev;
+}
+
+void
+tc_3000_500_iointr(framep, vec)
+ void *framep;
+ unsigned long vec;
+{
+ u_int32_t ir;
+ int ifound;
+
+#ifdef DIAGNOSTIC
+ int s;
+ if (vec != 0x800)
+ panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec);
+ s = splhigh();
+ if (s != ALPHA_PSL_IPL_IO)
+ panic("INVALID ASSUMPTION: IPL %d, not %d", s,
+ ALPHA_PSL_IPL_IO);
+ splx(s);
+#endif
+
+ do {
+ tc_syncbus();
+ ir = *(volatile u_int32_t *)TC_3000_500_IR_CLEAR;
+
+ /* Ignore interrupts that we haven't enabled. */
+ ir &= ~(tc_3000_500_imask & 0x1ff);
+
+ ifound = 0;
+
+#define CHECKINTR(slot) \
+ if (ir & tc_3000_500_intrbits[slot]) { \
+ ifound = 1; \
+ (*tc_3000_500_intr[slot].tci_func) \
+ (tc_3000_500_intr[slot].tci_arg); \
+ }
+ /* Do them in order of priority; highest slot # first. */
+ CHECKINTR(TC_3000_500_DEV_CXTURBO);
+ CHECKINTR(TC_3000_500_DEV_IOASIC);
+ CHECKINTR(TC_3000_500_DEV_TCDS);
+ CHECKINTR(TC_3000_500_DEV_OPT5);
+ CHECKINTR(TC_3000_500_DEV_OPT4);
+ CHECKINTR(TC_3000_500_DEV_OPT3);
+ CHECKINTR(TC_3000_500_DEV_OPT2);
+ CHECKINTR(TC_3000_500_DEV_OPT1);
+ CHECKINTR(TC_3000_500_DEV_OPT0);
+#undef CHECKINTR
+
+#ifdef DIAGNOSTIC
+#define PRINTINTR(msg, bits) \
+ if (ir & bits) \
+ printf(msg);
+ PRINTINTR("Second error occurred\n", TC_3000_500_IR_ERR2);
+ PRINTINTR("DMA buffer error\n", TC_3000_500_IR_DMABE);
+ PRINTINTR("DMA cross 2K boundary\n", TC_3000_500_IR_DMA2K);
+ PRINTINTR("TC reset in progress\n", TC_3000_500_IR_TCRESET);
+ PRINTINTR("TC parity error\n", TC_3000_500_IR_TCPAR);
+ PRINTINTR("DMA tag error\n", TC_3000_500_IR_DMATAG);
+ PRINTINTR("Single-bit error\n", TC_3000_500_IR_DMASBE);
+ PRINTINTR("Double-bit error\n", TC_3000_500_IR_DMADBE);
+ PRINTINTR("TC I/O timeout\n", TC_3000_500_IR_TCTIMEOUT);
+ PRINTINTR("DMA block too long\n", TC_3000_500_IR_DMABLOCK);
+ PRINTINTR("Invalid I/O address\n", TC_3000_500_IR_IOADDR);
+ PRINTINTR("DMA scatter/gather invalid\n", TC_3000_500_IR_DMASG);
+ PRINTINTR("Scatter/gather parity error\n",
+ TC_3000_500_IR_SGPAR);
+#undef PRINTINTR
+#endif
+ } while (ifound);
+}
+
+#if 0
+/*
+ * tc_3000_500_ioslot --
+ * Set the PBS bits for devices on the TC.
+ */
+void
+tc_3000_500_ioslot(slot, flags, set)
+ u_int32_t slot, flags;
+ int set;
+{
+ volatile u_int32_t *iosp;
+ u_int32_t ios;
+ int s;
+
+ iosp = (volatile u_int32_t *)TC_3000_500_IOSLOT;
+ ios = *iosp;
+ flags <<= (slot * 3);
+ if (set)
+ ios |= flags;
+ else
+ ios &= ~flags;
+ s = splhigh();
+ *iosp = ios;
+ tc_mb();
+ splx(s);
+}
+#endif
+
+#endif /* DEC_3000_500 */
+
+int
+tc_intrnull(val)
+ void *val;
+{
+
+ panic("tc_intrnull: uncaught TC intr for cookie %ld\n",
+ (u_long)val);
+}
+
+
+static int
+tc_probe(device_t dev)
+{
+ if((hwrpb->rpb_type != ST_DEC_3000_300) &&
+ (hwrpb->rpb_type != ST_DEC_3000_500))
+ return ENXIO;
+ tc0 = dev;
+ if(hwrpb->rpb_type == ST_DEC_3000_300) {
+ device_set_desc(dev, "12.5 Mhz Turbochannel Bus");
+ } else {
+ device_set_desc(dev, "25 Mhz Turbochannel Bus");
+
+ }
+ return 0;
+}
+
+static int
+tc_attach(device_t dev)
+{
+ struct tc_softc* sc = TC_SOFTC(dev);
+ device_t parent = device_get_parent(dev);
+ vm_offset_t regs;
+ tc_addr_t tcaddr;
+ const struct tc_builtin *builtin;
+ struct tc_slotdesc *slot;
+ struct tc_attach_args *ta;
+ int i;
+ device_t child = NULL;
+
+ tc0 = dev;
+
+ chipset.intrdev = dev;
+
+ switch(hwrpb->rpb_type){
+#ifdef DEC_3000_300
+ case ST_DEC_3000_300:
+ sc->sc_speed = TC_SPEED_12_5_MHZ;
+ sc->sc_nslots = tc_3000_300_nslots;
+ sc->sc_slots = tc_3000_300_slots;
+ sc->nbuiltins = tc_3000_300_nbuiltins;
+ sc->builtins = tc_3000_300_builtins;
+ tc_3000_300_intr_setup();
+ set_iointr(tc_3000_300_iointr);
+ sc->sc_intr_establish = tc_3000_300_intr_establish;
+ sc->sc_intr_disestablish = tc_3000_300_intr_disestablish;
+ break;
+#endif /* DEC_3000_500 */
+#ifdef DEC_3000_500
+ case ST_DEC_3000_500:
+ sc->sc_speed = TC_SPEED_25_MHZ;
+ sc->sc_nslots = tc_3000_500_nslots;
+ sc->sc_slots = tc_3000_500_slots;
+ sc->nbuiltins = tc_3000_500_nbuiltins;
+ sc->builtins = tc_3000_500_builtins;
+ tc_3000_500_intr_setup();
+ set_iointr(tc_3000_500_iointr);
+ sc->sc_intr_establish = tc_3000_500_intr_establish;
+ sc->sc_intr_disestablish = tc_3000_500_intr_disestablish;
+ break;
+#endif /* DEC_3000_500 */
+
+ default:
+ panic("tcattach: bad cpu type");
+ }
+ /*
+ * Try to configure each built-in device
+ */
+
+ for (i = 0; i < sc->nbuiltins; i++) {
+ builtin = &sc->builtins[i];
+ tcaddr = sc->sc_slots[builtin->tcb_slot].tcs_addr +
+ builtin->tcb_offset;
+ if (tc_badaddr(tcaddr))
+ continue;
+ ta = malloc(sizeof(struct tc_attach_args), M_DEVBUF, M_NOWAIT);
+ if (!ta)
+ continue;
+ ta->ta_slot = builtin->tcb_slot;
+ ta->ta_offset = builtin->tcb_offset;
+ ta->ta_addr = tcaddr;
+ ta->ta_cookie = builtin->tcb_cookie;
+ ta->ta_busspeed = sc->sc_speed;
+
+ child = device_add_child(dev, builtin->tcb_modname, 0, ta);
+ device_probe_and_attach(child);
+ }
+
+ return 0;
+}
+
+
+int
+tc_checkslot(slotbase, namep)
+ tc_addr_t slotbase;
+ char *namep;
+{
+ struct tc_rommap *romp;
+ int i, j;
+
+ for (i = 0; i < NTC_ROMOFFS; i++) {
+ romp = (struct tc_rommap *)
+ (slotbase + tc_slot_romoffs[i]);
+
+ switch (romp->tcr_width.v) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+
+ default:
+ continue;
+ }
+
+ if (romp->tcr_stride.v != 4)
+ continue;
+
+ for (j = 0; j < 4; j++)
+ if (romp->tcr_test[j+0*romp->tcr_stride.v] != 0x55 ||
+ romp->tcr_test[j+1*romp->tcr_stride.v] != 0x00 ||
+ romp->tcr_test[j+2*romp->tcr_stride.v] != 0xaa ||
+ romp->tcr_test[j+3*romp->tcr_stride.v] != 0xff)
+ continue;
+
+ for (j = 0; j < TC_ROM_LLEN; j++)
+ namep[j] = romp->tcr_modname[j].v;
+ namep[j] = '\0';
+ return (1);
+ }
+ return (0);
+}
+
+void
+tc_intr_establish(dev, cookie, level, handler, arg)
+ struct device *dev;
+ void *cookie, *arg;
+ tc_intrlevel_t level;
+ int (*handler) __P((void *));
+{
+ struct tc_softc *sc = (struct tc_softc *)device_get_softc(dev);
+
+ (*sc->sc_intr_establish)(device_get_parent(dev), cookie, level,
+ handler, arg);
+}
+
+void
+tc_intr_disestablish(dev, cookie)
+ struct device *dev;
+ void *cookie;
+{
+ struct tc_softc *sc = (struct tc_softc *)device_get_softc(dev);
+
+ (*sc->sc_intr_disestablish)(device_get_parent(dev), cookie);
+}
+
+
+
+static void
+tc_print_child(device_t bus, device_t dev)
+{
+ printf(" at %s%d",
+ device_get_name(bus), device_get_unit(bus));
+}
+
+DRIVER_MODULE(tc, tcasic, tc_driver, tc_devclass, 0, 0);
+
diff --git a/sys/alpha/tc/tcasic.c b/sys/alpha/tc/tcasic.c
new file mode 100644
index 0000000..1dd4fee
--- /dev/null
+++ b/sys/alpha/tc/tcasic.c
@@ -0,0 +1,115 @@
+/* $Id$ */
+/* from $NetBSD: tcasic.c,v 1.23 1998/05/14 00:01:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/rpb.h>
+
+/*#include <alpha/tc/dwlpxreg.h>*/
+
+#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa)
+
+static devclass_t tcasic_devclass;
+static device_t tcasic0; /* XXX only one for now */
+
+struct tcasic_softc {
+ vm_offset_t dmem_base; /* dense memory */
+ vm_offset_t smem_base; /* sparse memory */
+ vm_offset_t io_base; /* sparse i/o */
+ vm_offset_t cfg_base; /* sparse pci config */
+};
+
+#define TCASIC_SOFTC(dev) (struct tcasic_softc*) device_get_softc(dev)
+
+static int tcasic_probe(device_t dev);
+static int tcasic_attach(device_t dev);
+static void tcasic_print_child(device_t bus, device_t dev);
+
+static device_method_t tcasic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tcasic_probe),
+ DEVMETHOD(device_attach, tcasic_attach),
+ DEVMETHOD(bus_print_child, tcasic_print_child),
+ { 0, 0 }
+};
+
+static driver_t tcasic_driver = {
+ "tcasic",
+ tcasic_methods,
+ DRIVER_TYPE_MISC,
+ sizeof(struct tcasic_softc),
+};
+
+extern device_t tc0;
+static int
+tcasic_probe(device_t dev)
+{
+ if (tcasic0)
+ return ENXIO;
+ if((hwrpb->rpb_type != ST_DEC_3000_300) &&
+ (hwrpb->rpb_type != ST_DEC_3000_500))
+ return ENXIO;
+ tcasic0 = dev;
+ device_set_desc(dev, "Turbochannel Host Bus Adapter");
+ tc0 = device_add_child(dev, "tc", 0, 0);
+ return 0;
+}
+
+static int
+tcasic_attach(device_t dev)
+{
+ struct tcasic_softc* sc = TCASIC_SOFTC(dev);
+ device_t parent = device_get_parent(dev);
+ vm_offset_t regs;
+ tcasic0 = dev;
+
+/* chipset = tcasic_chipset;*/
+ chipset.intrdev = dev;
+ device_probe_and_attach(tc0);
+ return 0;
+}
+
+static void
+tcasic_print_child(device_t bus, device_t dev)
+{
+ printf(" at %s%d",
+ device_get_name(bus), device_get_unit(bus));
+}
+
+
+
+DRIVER_MODULE(tcasic, root, tcasic_driver, tcasic_devclass, 0, 0);
+
diff --git a/sys/alpha/tc/tcdevs.h b/sys/alpha/tc/tcdevs.h
new file mode 100644
index 0000000..cdbae33
--- /dev/null
+++ b/sys/alpha/tc/tcdevs.h
@@ -0,0 +1,118 @@
+/* $Id$ */
+/* $NetBSD: tcdevs.h,v 1.12 1998/06/18 23:29:46 jonathan Exp $ */
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ * generated from:
+ * NetBSD: tcdevs,v 1.10 1998/06/18 23:28:12 jonathan Exp
+ */
+
+/*
+ * Copyright (c) 1996 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 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.
+ */
+
+#define TC_DEVICE_AV01B_AA "lofi"
+#define TC_DESCRIPTION_AV01B_AA "DecAudio \"LoFi\" audio/isdn"
+
+#define TC_DEVICE_DGLTA_FA "otto"
+#define TC_DESCRIPTION_DGLTA_FA "DGLTA ATM"
+
+#define TC_DEVICE_FORE_ATM "fa"
+#define TC_DESCRIPTION_FORE_ATM "Fore TCA-100 ATM"
+
+#define TC_DEVICE_KZTSA_AA "tza"
+#define TC_DESCRIPTION_KZTSA_AA "TZA FWD SCSI"
+
+#define TC_DEVICE_OTTO "otto"
+#define TC_DESCRIPTION_OTTO "DEC SRC \"OTTO\" ATM"
+
+#define TC_DEVICE_PMAD_AA "le"
+#define TC_DESCRIPTION_PMAD_AA "LANCE Ethernet"
+
+#define TC_DEVICE_PMAF_AA "fza"
+#define TC_DESCRIPTION_PMAF_AA "DEC FDDIcontroller 700 (DEFZA; fiber optic)"
+
+#define TC_DEVICE_PMAF_F "fta"
+#define TC_DESCRIPTION_PMAF_F "DEFTA FDDI"
+
+#define TC_DEVICE_PMAG_AA "mfb"
+#define TC_DESCRIPTION_PMAG_AA "Monochrome Frame Buffer"
+
+#define TC_DEVICE_PMAG_BA "cfb"
+#define TC_DESCRIPTION_PMAG_BA "Color Frame Buffer"
+
+#define TC_DEVICE_PMAG_CA "ga"
+#define TC_DESCRIPTION_PMAG_CA "2D Graphics"
+
+#define TC_DEVICE_PMAG_DA "gq"
+#define TC_DESCRIPTION_PMAG_DA "3D Graphics (LM)"
+
+#define TC_DEVICE_PMAG_DV "xcfb"
+#define TC_DESCRIPTION_PMAG_DV "Maxine Color Frame Buffer"
+
+#define TC_DEVICE_PMAG_FA "gq"
+#define TC_DESCRIPTION_PMAG_FA "3D Graphics (HE)"
+
+#define TC_DEVICE_PMAGB_BA "sfb"
+#define TC_DESCRIPTION_PMAGB_BA "Smart Frame Buffer"
+
+#define TC_DEVICE_PMAGD "sfbp"
+#define TC_DESCRIPTION_PMAGD "Smart Frame Buffer Plus, unknown bpp"
+
+#define TC_DEVICE_PMAGD_AA "sfbp"
+#define TC_DESCRIPTION_PMAGD_AA "Smart Frame Buffer Plus, 8bpp"
+
+#define TC_DEVICE_PMAGD_BA "sfbp"
+#define TC_DESCRIPTION_PMAGD_BA "Smart Frame Buffer Plus, 32bpp"
+
+#define TC_DEVICE_PMAZ_AA "asc"
+#define TC_DESCRIPTION_PMAZ_AA "53c94 SCSI"
+
+#define TC_DEVICE_PMAZ_DS "tcds"
+#define TC_DESCRIPTION_PMAZ_DS "53c94 TCDS SCSI (baseboard)"
+
+#define TC_DEVICE_PMAZ_FS "tcds"
+#define TC_DESCRIPTION_PMAZ_FS "53c94 TCDS Fast SCSI (baseboard)"
+
+#define TC_DEVICE_PMAZB_AA "tcds"
+#define TC_DESCRIPTION_PMAZB_AA "53c94 TCDS SCSI option card"
+
+#define TC_DEVICE_PMAZC_AA "tcds"
+#define TC_DESCRIPTION_PMAZC_AA "53c94 TCDS Fast SCSI option card"
+
+#define TC_DEVICE_T1D4PKT "ds"
+#define TC_DESCRIPTION_T1D4PKT "DECWRL Turbochannel T1"
+
+#define TC_DEVICE_T3PKT "tt"
+#define TC_DESCRIPTION_T3PKT "DECWRL Turbochannel T3"
+
+#define TC_DEVICE_PMAT_AA "tra"
+#define TC_DESCRIPTION_PMAT_AA "DEC TurboChannel Token Ring Controller"
diff --git a/sys/alpha/tc/tcdevs_data.h b/sys/alpha/tc/tcdevs_data.h
new file mode 100644
index 0000000..61c054c
--- /dev/null
+++ b/sys/alpha/tc/tcdevs_data.h
@@ -0,0 +1,174 @@
+/* $Id$ */
+/* $NetBSD: tcdevs_data.h,v 1.12 1998/06/18 23:29:46 jonathan Exp $ */
+
+/*
+ * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ * generated from:
+ * NetBSD: tcdevs,v 1.10 1998/06/18 23:28:12 jonathan Exp
+ */
+
+/*
+ * Copyright (c) 1996 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 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.
+ */
+
+struct tc_knowndev tc_knowndevs[] = {
+ {
+ "AV01B-AA",
+ TC_DEVICE_AV01B_AA,
+ TC_DESCRIPTION_AV01B_AA,
+ },
+ {
+ "DGLTA-FA",
+ TC_DEVICE_DGLTA_FA,
+ TC_DESCRIPTION_DGLTA_FA,
+ },
+ {
+ "FORE_ATM",
+ TC_DEVICE_FORE_ATM,
+ TC_DESCRIPTION_FORE_ATM,
+ },
+ {
+ "KZTSA-AA",
+ TC_DEVICE_KZTSA_AA,
+ TC_DESCRIPTION_KZTSA_AA,
+ },
+ {
+ "OTTO ",
+ TC_DEVICE_OTTO,
+ TC_DESCRIPTION_OTTO,
+ },
+ {
+ "PMAD-AA ",
+ TC_DEVICE_PMAD_AA,
+ TC_DESCRIPTION_PMAD_AA,
+ },
+ {
+ "PMAF-AA ",
+ TC_DEVICE_PMAF_AA,
+ TC_DESCRIPTION_PMAF_AA,
+ },
+ {
+ "PMAF-F ",
+ TC_DEVICE_PMAF_F,
+ TC_DESCRIPTION_PMAF_F,
+ },
+ {
+ "PMAG-AA ",
+ TC_DEVICE_PMAG_AA,
+ TC_DESCRIPTION_PMAG_AA,
+ },
+ {
+ "PMAG-BA ",
+ TC_DEVICE_PMAG_BA,
+ TC_DESCRIPTION_PMAG_BA,
+ },
+ {
+ "PMAG-CA ",
+ TC_DEVICE_PMAG_CA,
+ TC_DESCRIPTION_PMAG_CA,
+ },
+ {
+ "PMAG-DA ",
+ TC_DEVICE_PMAG_DA,
+ TC_DESCRIPTION_PMAG_DA,
+ },
+ {
+ "PMAG-DV ",
+ TC_DEVICE_PMAG_DV,
+ TC_DESCRIPTION_PMAG_DV,
+ },
+ {
+ "PMAG-FA ",
+ TC_DEVICE_PMAG_FA,
+ TC_DESCRIPTION_PMAG_FA,
+ },
+ {
+ "PMAGB-BA",
+ TC_DEVICE_PMAGB_BA,
+ TC_DESCRIPTION_PMAGB_BA,
+ },
+ {
+ "PMAGD ",
+ TC_DEVICE_PMAGD,
+ TC_DESCRIPTION_PMAGD,
+ },
+ {
+ "PMAGD-AA",
+ TC_DEVICE_PMAGD_AA,
+ TC_DESCRIPTION_PMAGD_AA,
+ },
+ {
+ "PMAGD-BA",
+ TC_DEVICE_PMAGD_BA,
+ TC_DESCRIPTION_PMAGD_BA,
+ },
+ {
+ "PMAZ-AA ",
+ TC_DEVICE_PMAZ_AA,
+ TC_DESCRIPTION_PMAZ_AA,
+ },
+ {
+ "PMAZ-DS ",
+ TC_DEVICE_PMAZ_DS,
+ TC_DESCRIPTION_PMAZ_DS,
+ },
+ {
+ "PMAZ-FS ",
+ TC_DEVICE_PMAZ_FS,
+ TC_DESCRIPTION_PMAZ_FS,
+ },
+ {
+ "PMAZB-AA",
+ TC_DEVICE_PMAZB_AA,
+ TC_DESCRIPTION_PMAZB_AA,
+ },
+ {
+ "PMAZC-AA",
+ TC_DEVICE_PMAZC_AA,
+ TC_DESCRIPTION_PMAZC_AA,
+ },
+ {
+ "T1D4PKT ",
+ TC_DEVICE_T1D4PKT,
+ TC_DESCRIPTION_T1D4PKT,
+ },
+ {
+ "T3PKT ",
+ TC_DEVICE_T3PKT,
+ TC_DESCRIPTION_T3PKT,
+ },
+ {
+ "PMAT-AA ",
+ TC_DEVICE_PMAT_AA,
+ TC_DESCRIPTION_PMAT_AA,
+ },
+ { NULL, NULL, NULL, }
+};
diff --git a/sys/alpha/tc/tcds.c b/sys/alpha/tc/tcds.c
new file mode 100644
index 0000000..37a3da9
--- /dev/null
+++ b/sys/alpha/tc/tcds.c
@@ -0,0 +1,459 @@
+/* $Id$ */
+/* from $NetBSD: tcds.c,v 1.25 1998/05/26 23:43:05 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Keith Bostic, Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "opt_cpu.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+
+#include <machine/rpb.h>
+#include <machine/clock.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdevs.h>
+#include <alpha/tc/tcdsreg.h>
+#include <alpha/tc/tcdsvar.h>
+
+
+#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa)
+
+static devclass_t tcds_devclass;
+static device_t tcds0; /* there can be only one */
+
+struct tcds_softc {
+ device_t sc_dv;
+ vm_offset_t sc_base;
+ void *sc_cookie;
+ volatile u_int32_t *sc_cir;
+ volatile u_int32_t *sc_imer;
+ struct tcds_slotconfig sc_slots[2];
+};
+
+#define TCDS_SOFTC(dev) (struct tcds_softc*) device_get_softc(dev)
+
+static int tcds_probe(device_t dev);
+static int tcds_attach(device_t dev);
+static void tcds_intrnull __P((void *));
+static void tcds_print_child(device_t bus, device_t dev);
+static void tcds_lance_dma_setup(void *v);
+static int tcds_intr __P((void *));
+
+
+
+static device_method_t tcds_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tcds_probe),
+ DEVMETHOD(device_attach, tcds_attach),
+ DEVMETHOD(bus_print_child, tcds_print_child),
+
+ { 0, 0 }
+};
+
+static driver_t tcds_driver = {
+ "tcds",
+ tcds_methods,
+ DRIVER_TYPE_MISC,
+ sizeof(struct tcds_softc),
+};
+
+
+extern device_t tc0;
+static int
+tcds_probe(device_t dev)
+{
+ if((hwrpb->rpb_type != ST_DEC_3000_300) &&
+ (hwrpb->rpb_type != ST_DEC_3000_500))
+ return ENXIO;
+ if(strcmp(device_get_name(dev),"tcds")){
+ return ENXIO;
+ }
+ tcds0 = dev;
+ device_set_desc(dev, "Turbochannel Dual Scsi");
+ return 0;
+}
+
+struct tcdsdev_attach_args tcdsdev;
+
+
+static int
+tcds_attach(device_t dev)
+{
+ struct tcds_softc* sc = TCDS_SOFTC(dev);
+ struct tc_attach_args *ta = device_get_ivars(dev);
+ device_t parent = device_get_parent(dev);
+ vm_offset_t regs,va;
+ u_long i;
+ struct tcds_slotconfig *slotc;
+ struct tcdsdev_attach_args *tcdsdev;
+ tcds0 = dev;
+
+/*
+ XXXXXX
+
+ */
+ sc->sc_base = ta->ta_addr;
+ sc->sc_cookie = ta->ta_cookie;
+ sc->sc_cir = TCDS_REG(sc->sc_base, TCDS_CIR);
+ sc->sc_imer = TCDS_REG(sc->sc_base, TCDS_IMER);
+
+ tc_intr_establish(device_get_parent(dev), sc->sc_cookie, 0, tcds_intr, sc);
+
+ /*
+ * XXX
+ * IMER apparently has some random (or, not so random, but still
+ * not useful) bits set in it when the system boots. Clear it.
+ */
+ *sc->sc_imer = 0;
+ alpha_wmb();
+ /* fill in common information first */
+ for (i = 0; i < 2; i++) {
+ slotc = &sc->sc_slots[i];
+
+ bzero(slotc, sizeof *slotc); /* clear everything */
+
+ slotc->sc_slot = i;
+ slotc->sc_tcds = sc;
+ slotc->sc_esp = NULL;
+ slotc->sc_intrhand = tcds_intrnull;
+ slotc->sc_intrarg = (void *)(long)i;
+ }
+
+ /* information for slot 0 */
+ slotc = &sc->sc_slots[0];
+ slotc->sc_resetbits = TCDS_CIR_SCSI0_RESET;
+ slotc->sc_intrmaskbits =
+ TCDS_IMER_SCSI0_MASK | TCDS_IMER_SCSI0_ENB;
+ slotc->sc_intrbits = TCDS_CIR_SCSI0_INT;
+ slotc->sc_dmabits = TCDS_CIR_SCSI0_DMAENA;
+ slotc->sc_errorbits = 0; /* XXX */
+ slotc->sc_sda = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_ADDR);
+ slotc->sc_dic = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_INTR);
+ slotc->sc_dud0 = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_DUD0);
+ slotc->sc_dud1 = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_DUD1);
+
+ /* information for slot 1 */
+ slotc = &sc->sc_slots[1];
+ slotc->sc_resetbits = TCDS_CIR_SCSI1_RESET;
+ slotc->sc_intrmaskbits =
+ TCDS_IMER_SCSI1_MASK | TCDS_IMER_SCSI1_ENB;
+ slotc->sc_intrbits = TCDS_CIR_SCSI1_INT;
+ slotc->sc_dmabits = TCDS_CIR_SCSI1_DMAENA;
+ slotc->sc_errorbits = 0; /* XXX */
+ slotc->sc_sda = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_ADDR);
+ slotc->sc_dic = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_INTR);
+ slotc->sc_dud0 = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_DUD0);
+ slotc->sc_dud1 = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_DUD1);
+
+
+ /* find the hardware attached to the TCDS ASIC */
+ tcdsdev = malloc(sizeof(struct tcdsdev_attach_args),
+ M_DEVBUF, M_NOWAIT);
+ if (tcdsdev) {
+ strncpy(tcdsdev->tcdsda_modname, "PMAZ-AA ", TC_ROM_LLEN);
+ tcdsdev->tcdsda_slot = 0;
+ tcdsdev->tcdsda_offset = 0;
+ tcdsdev->tcdsda_addr = (tc_addr_t)
+ TC_DENSE_TO_SPARSE(sc->sc_base + TCDS_SCSI0_OFFSET);
+ tcdsdev->tcdsda_cookie = (void *)(long)0;
+ tcdsdev->tcdsda_sc = &sc->sc_slots[0];
+ tcdsdev->tcdsda_id = 7; /* XXX */
+ tcdsdev->tcdsda_freq = 25000000; /* XXX */
+
+ tcds_scsi_reset(tcdsdev->tcdsda_sc);
+ device_probe_and_attach(device_add_child(dev, "esp", -1, tcdsdev));
+ }
+
+ /* the second SCSI chip isn't present on the 3000/300 series. */
+ if (hwrpb->rpb_type != ST_DEC_3000_300) {
+ tcdsdev = malloc(sizeof(struct tcdsdev_attach_args),
+ M_DEVBUF, M_NOWAIT);
+ if (tcdsdev) {
+ strncpy(tcdsdev->tcdsda_modname, "PMAZ-AA ",
+ TC_ROM_LLEN);
+ tcdsdev->tcdsda_slot = 1;
+ tcdsdev->tcdsda_offset = 0;
+ tcdsdev->tcdsda_addr = (tc_addr_t)
+ TC_DENSE_TO_SPARSE(sc->sc_base + TCDS_SCSI1_OFFSET);
+ tcdsdev->tcdsda_cookie = (void *)(long)1;
+ tcdsdev->tcdsda_sc = &sc->sc_slots[1];
+ tcdsdev->tcdsda_id = 7; /* XXX */
+ tcdsdev->tcdsda_freq = 25000000; /* XXX */
+ tcds_scsi_reset(tcdsdev->tcdsda_sc);
+ device_probe_and_attach(device_add_child(dev, "esp", -1, tcdsdev));
+ }
+ }
+ return 0;
+}
+
+void
+tcds_scsi_reset(sc)
+ struct tcds_slotconfig *sc;
+{
+ tcds_dma_enable(sc, 0);
+ tcds_scsi_enable(sc, 0);
+
+ TCDS_CIR_CLR(*sc->sc_tcds->sc_cir, sc->sc_resetbits);
+ alpha_mb();
+ DELAY(1);
+ TCDS_CIR_SET(*sc->sc_tcds->sc_cir, sc->sc_resetbits);
+ alpha_mb();
+
+ tcds_scsi_enable(sc, 1);
+ tcds_dma_enable(sc, 1);
+}
+
+
+void
+tcds_scsi_enable(sc, on)
+ struct tcds_slotconfig *sc;
+ int on;
+{
+
+ if (on)
+ *sc->sc_tcds->sc_imer |= sc->sc_intrmaskbits;
+ else
+ *sc->sc_tcds->sc_imer &= ~sc->sc_intrmaskbits;
+ alpha_mb();
+}
+
+void
+tcds_dma_enable(sc, on)
+ struct tcds_slotconfig *sc;
+ int on;
+{
+
+ /* XXX Clear/set IOSLOT/PBS bits. */
+ if (on)
+ TCDS_CIR_SET(*sc->sc_tcds->sc_cir, sc->sc_dmabits);
+ else
+ TCDS_CIR_CLR(*sc->sc_tcds->sc_cir, sc->sc_dmabits);
+ alpha_mb();
+}
+
+int
+tcds_scsi_isintr(sc, clear)
+ struct tcds_slotconfig *sc;
+ int clear;
+{
+
+ if ((*sc->sc_tcds->sc_cir & sc->sc_intrbits) != 0) {
+ if (clear) {
+ TCDS_CIR_CLR(*sc->sc_tcds->sc_cir, sc->sc_intrbits);
+ alpha_mb();
+ }
+ return (1);
+ } else
+ return (0);
+}
+
+
+int
+tcds_scsi_iserr(sc)
+ struct tcds_slotconfig *sc;
+{
+
+ return ((*sc->sc_tcds->sc_cir & sc->sc_errorbits) != 0);
+}
+
+static void
+tcds_intrnull(void *val)
+{
+
+ panic("tcds_intrnull: uncaught IOASIC intr for cookie %ld\n",
+ (u_long)val);
+}
+
+void
+tcds_intr_establish(tcds, cookie, level, func, arg)
+ struct device *tcds;
+ void *cookie, *arg;
+ tc_intrlevel_t level;
+ int (*func) __P((void *));
+{
+ struct tcds_softc *sc = device_get_softc(tcds);
+ u_long slot;
+
+ slot = (u_long)cookie;
+#ifdef DIAGNOSTIC
+ /* XXX check cookie. */
+#endif
+ if (sc->sc_slots[slot].sc_intrhand != tcds_intrnull){
+ panic("tcds_intr_establish: cookie %d twice, intrhdlr = 0x%lx",
+ slot,sc->sc_slots[slot].sc_intrhand );
+ }
+ sc->sc_slots[slot].sc_intrhand = func;
+ sc->sc_slots[slot].sc_intrarg = arg;
+ tcds_scsi_reset(&sc->sc_slots[slot]);
+}
+void
+tcds_intr_disestablish(tcds, cookie)
+ struct device *tcds;
+ void *cookie;
+{
+ struct tcds_softc *sc = device_get_softc(tcds);
+ u_long slot;
+
+ slot = (u_long)cookie;
+#ifdef DIAGNOSTIC
+ /* XXX check cookie. */
+#endif
+
+ if (sc->sc_slots[slot].sc_intrhand == tcds_intrnull)
+ panic("tcds_intr_disestablish: cookie %d missing intr",
+ slot);
+
+ sc->sc_slots[slot].sc_intrhand = tcds_intrnull;
+ sc->sc_slots[slot].sc_intrarg = (void *)slot;
+
+ tcds_dma_enable(&sc->sc_slots[slot], 0);
+ tcds_scsi_enable(&sc->sc_slots[slot], 0);
+}
+
+static int
+tcds_intr(val)
+ void *val;
+{
+ struct tcds_softc *sc;
+ u_int32_t ir;
+
+ sc = val;
+
+ /*
+ * XXX
+ * Copy and clear (gag!) the interrupts.
+ */
+ ir = *sc->sc_cir;
+ alpha_mb();
+ TCDS_CIR_CLR(*sc->sc_cir, TCDS_CIR_ALLINTR);
+ alpha_mb();
+ tc_syncbus();
+ alpha_mb();
+
+#define CHECKINTR(slot) \
+ if (ir & sc->sc_slots[slot].sc_intrbits) { \
+ (void)(*sc->sc_slots[slot].sc_intrhand) \
+ (sc->sc_slots[slot].sc_intrarg); \
+ }
+ CHECKINTR(0);
+ CHECKINTR(1);
+#undef CHECKINTR
+
+#ifdef DIAGNOSTIC
+ /*
+ * Interrupts not currently handled, but would like to know if they
+ * occur.
+ *
+ * XXX
+ * Don't know if we have to set the interrupt mask and enable bits
+ * in the IMER to allow some of them to happen?
+ */
+#define PRINTINTR(msg, bits) \
+ if (ir & bits) \
+ printf(msg);
+ PRINTINTR("SCSI0 DREQ interrupt.\n", TCDS_CIR_SCSI0_DREQ);
+ PRINTINTR("SCSI1 DREQ interrupt.\n", TCDS_CIR_SCSI1_DREQ);
+ PRINTINTR("SCSI0 prefetch interrupt.\n", TCDS_CIR_SCSI0_PREFETCH);
+ PRINTINTR("SCSI1 prefetch interrupt.\n", TCDS_CIR_SCSI1_PREFETCH);
+ PRINTINTR("SCSI0 DMA error.\n", TCDS_CIR_SCSI0_DMA);
+ PRINTINTR("SCSI1 DMA error.\n", TCDS_CIR_SCSI1_DMA);
+ PRINTINTR("SCSI0 DB parity error.\n", TCDS_CIR_SCSI0_DB);
+ PRINTINTR("SCSI1 DB parity error.\n", TCDS_CIR_SCSI1_DB);
+ PRINTINTR("SCSI0 DMA buffer parity error.\n", TCDS_CIR_SCSI0_DMAB_PAR);
+ PRINTINTR("SCSI1 DMA buffer parity error.\n", TCDS_CIR_SCSI1_DMAB_PAR);
+ PRINTINTR("SCSI0 DMA read parity error.\n", TCDS_CIR_SCSI0_DMAR_PAR);
+ PRINTINTR("SCSI1 DMA read parity error.\n", TCDS_CIR_SCSI1_DMAR_PAR);
+ PRINTINTR("TC write parity error.\n", TCDS_CIR_TCIOW_PAR);
+ PRINTINTR("TC I/O address parity error.\n", TCDS_CIR_TCIOA_PAR);
+#undef PRINTINTR
+#endif
+
+ /*
+ * XXX
+ * The MACH source had this, with the comment:
+ * This is wrong, but machine keeps dying.
+ */
+ DELAY(1);
+ return 1;
+}
+
+static void
+tcds_print_child(device_t bus, device_t dev)
+{
+ struct tcds_dev *ioasic = device_get_ivars(dev);
+ printf(" at %s%d", device_get_name(bus), device_get_unit(bus));
+}
+
+
+DRIVER_MODULE(tcds, tc, tcds_driver, tcds_devclass, 0, 0);
+
diff --git a/sys/alpha/tc/tcds_dma.c b/sys/alpha/tc/tcds_dma.c
new file mode 100644
index 0000000..d07811e
--- /dev/null
+++ b/sys/alpha/tc/tcds_dma.c
@@ -0,0 +1,286 @@
+/* $Id$ */
+/* $NetBSD: tcds_dma.c,v 1.6.4.1 1996/09/10 17:28:19 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Peter Galbavy. 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 Peter Galbavy.
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <machine/clock.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <alpha/tc/tcreg.h>
+#include <alpha/tc/tcvar.h>
+#include <alpha/tc/tcdsreg.h>
+#include <alpha/tc/tcdsvar.h>
+#include <alpha/tc/espreg.h>
+#include <alpha/tc/espvar.h>
+
+void
+tcds_dma_reset(sc)
+ struct tcds_slotconfig *sc;
+{
+ /* TCDS SCSI disable/reset/enable. */
+ tcds_scsi_reset(sc); /* XXX */
+
+ sc->sc_active = 0; /* and of course we aren't */
+}
+
+int
+tcds_dma_isintr(sc)
+ struct tcds_slotconfig *sc;
+{
+ int x;
+
+ x = tcds_scsi_isintr(sc, 0);
+
+ /* Clear the TCDS interrupt bit. */
+ (void)tcds_scsi_isintr(sc, 1);
+
+ /* XXX */
+ return x;
+}
+
+/*
+ * Pseudo (chained) interrupt from the esp driver to kick the
+ * current running DMA transfer. I am replying on espintr() to
+ * pickup and clean errors for now
+ *
+ * return 1 if it was a DMA continue.
+ */
+int
+tcds_dma_intr(sc)
+ struct tcds_slotconfig *sc;
+{
+ u_int32_t dud;
+ int trans = 0, resid = 0;
+ u_int32_t *addr, dudmask;
+ u_char tcl, tcm, tch;
+
+ ESP_DMA(("tcds_dma %d: intr", sc->sc_slot));
+
+ if (tcds_scsi_iserr(sc))
+ return (0);
+
+ /* This is an "assertion" :) */
+ if (sc->sc_active == 0)
+ panic("dmaintr: DMA wasn't active");
+
+ /* DMA has stopped */
+ tcds_dma_enable(sc, 0);
+ sc->sc_active = 0;
+
+ if (sc->sc_dmasize == 0) {
+ /* A "Transfer Pad" operation completed */
+ tcl = ESP_READ_REG(sc->sc_esp, ESP_TCL);
+ tcm = ESP_READ_REG(sc->sc_esp, ESP_TCM);
+ ESP_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
+ tcl | (tcm << 8), tcl, tcm));
+ return 0;
+ }
+
+ if (!sc->sc_iswrite &&
+ (resid = (ESP_READ_REG(sc->sc_esp, ESP_FFLAG) & ESPFIFO_FF)) != 0) {
+ printf("empty FIFO of %d ", resid);
+ ESPCMD(sc->sc_esp, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+
+ resid += (tcl = ESP_READ_REG(sc->sc_esp, ESP_TCL));
+ resid += (tcm = ESP_READ_REG(sc->sc_esp, ESP_TCM)) << 8;
+ if (sc->sc_esp->sc_rev == ESP200)
+ resid += (tch = ESP_READ_REG(sc->sc_esp, ESP_TCH)) << 16;
+ else
+ tch = 0;
+
+ if (resid == 0 && (sc->sc_esp->sc_rev <= ESP100A) &&
+ (sc->sc_esp->sc_espstat & ESPSTAT_TC) == 0)
+ resid = 65536;
+
+ trans = sc->sc_dmasize - resid;
+ if (trans < 0) { /* transferred < 0 ? */
+ printf("tcds_dma %d: xfer (%d) > req (%d)\n",
+ sc->sc_slot, trans, sc->sc_dmasize);
+ trans = sc->sc_dmasize;
+ }
+
+ ESP_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
+ tcl, tcm, tch, trans, resid));
+
+ /*
+ * Clean up unaligned DMAs into main memory.
+ */
+ if (sc->sc_iswrite) {
+ /* Handle unaligned starting address, length. */
+ dud = *sc->sc_dud0;
+ if ((dud & TCDS_DUD0_VALIDBITS) != 0) {
+ addr = (u_int32_t *)
+ ((vm_offset_t)sc->sc_dmaaddr & ~0x3);
+ dudmask = 0;
+ if (dud & TCDS_DUD0_VALID00)
+ panic("tcds_dma: dud0 byte 0 valid");
+ if (dud & TCDS_DUD0_VALID01)
+ dudmask |= TCDS_DUD_BYTE01;
+ if (dud & TCDS_DUD0_VALID10)
+ dudmask |= TCDS_DUD_BYTE10;
+#ifdef DIAGNOSTIC
+ if (dud & TCDS_DUD0_VALID11)
+ dudmask |= TCDS_DUD_BYTE11;
+#endif
+ ESP_DMA(("dud0 at 0x%lx dudmask 0x%x\n",
+ addr, dudmask));
+ addr = (u_int32_t *)ALPHA_PHYS_TO_K0SEG((vm_offset_t)addr);
+ *addr = (*addr & ~dudmask) | (dud & dudmask);
+ }
+ dud = *sc->sc_dud1;
+ if ((dud & TCDS_DUD1_VALIDBITS) != 0) {
+
+ addr = (u_int32_t *)
+ ((vm_offset_t)*sc->sc_sda << 2);
+ dudmask = 0;
+ if (dud & TCDS_DUD1_VALID00)
+ dudmask |= TCDS_DUD_BYTE00;
+ if (dud & TCDS_DUD1_VALID01)
+ dudmask |= TCDS_DUD_BYTE01;
+ if (dud & TCDS_DUD1_VALID10)
+ dudmask |= TCDS_DUD_BYTE10;
+#ifdef DIAGNOSTIC
+ if (dud & TCDS_DUD1_VALID11)
+ panic("tcds_dma: dud1 byte 3 valid");
+#endif
+ ESP_DMA(("dud1 at 0x%lx dudmask 0x%x\n",
+ addr, dudmask));
+ addr = (u_int32_t *)ALPHA_PHYS_TO_K0SEG((vm_offset_t)addr);
+ *addr = (*addr & ~dudmask) | (dud & dudmask);
+ }
+ /* XXX deal with saved residual byte? */
+ }
+
+ *sc->sc_dmalen -= trans;
+ *sc->sc_dmaaddr += trans;
+
+#if 0 /* this is not normal operation just yet */
+ if (*sc->sc_dmalen == 0 ||
+ sc->sc_esp->sc_phase != sc->sc_esp->sc_prevphase)
+ return 0;
+
+ /* and again */
+ dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, sc->sc_iswrite);
+ return 1;
+#endif
+ return 0;
+}
+
+#define DMAMAX(a) (0x02000 - ((a) & 0x1fff))
+
+/*
+ * start a dma transfer or keep it going
+ */
+
+int
+tcds_dma_setup(sc, addr, len, datain, dmasize)
+ struct tcds_slotconfig *sc;
+ caddr_t *addr;
+ size_t *len, *dmasize;
+ int datain; /* DMA into main memory */
+{
+ u_int32_t dic;
+ size_t size;
+
+ sc->sc_dmaaddr = addr;
+ sc->sc_dmalen = len;
+ sc->sc_iswrite = datain;
+
+ ESP_DMA(("tcds_dma %d: start %d@0x%lx,%d\n", sc->sc_slot, *sc->sc_dmalen, *sc->sc_dmaaddr, sc->sc_iswrite));
+
+ /*
+ * the rules say we cannot transfer more than the limit
+ * of this DMA chip (64k) and we cannot cross a 8k boundary.
+ */
+
+ size = min(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr));
+ *dmasize = sc->sc_dmasize = size;
+
+ ESP_DMA(("dma_start: dmasize = %d\n", sc->sc_dmasize));
+
+ /* Load address, set/clear unaligned transfer and read/write bits. */
+ /* XXX PICK AN ADDRESS TYPE, AND STICK TO IT! */
+ if ((u_long)*addr > avail_end) {
+ *sc->sc_sda = pmap_kextract((u_long)*addr) >> 2;
+ } else {
+ *sc->sc_sda = ALPHA_K0SEG_TO_PHYS((u_long)*addr) >> 2;
+ }
+ alpha_mb();
+ dic = *sc->sc_dic;
+ dic &= ~TCDS_DIC_ADDRMASK;
+ dic |= (vm_offset_t)*addr & TCDS_DIC_ADDRMASK;
+ if (datain)
+ dic |= TCDS_DIC_WRITE;
+ else
+ dic &= ~TCDS_DIC_WRITE;
+ *sc->sc_dic = dic;
+ alpha_mb();
+
+ return (0);
+}
+
+void
+tcds_dma_go(sc)
+ struct tcds_slotconfig *sc;
+{
+
+ /* mark unit as DMA-active */
+ sc->sc_active = 1;
+
+ /* Start DMA */
+ tcds_dma_enable(sc, 1);
+}
+
+int
+tcds_dma_isactive(sc)
+ struct tcds_slotconfig *sc;
+{
+
+ return (sc->sc_active);
+}
diff --git a/sys/alpha/tc/tcdsreg.h b/sys/alpha/tc/tcdsreg.h
new file mode 100644
index 0000000..6c24281
--- /dev/null
+++ b/sys/alpha/tc/tcdsreg.h
@@ -0,0 +1,215 @@
+/* $Id$ */
+/* $NetBSD: tcdsreg.h,v 1.1 1995/12/20 00:40:36 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Keith Bostic, Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Offsets to the SCSI chips
+ */
+#define TCDS_SCSI0_OFFSET 0x080000
+#define TCDS_SCSI1_OFFSET 0x080100
+
+/*
+ * TCDS register offsets, bit masks.
+ */
+#define TCDS_CIR 0x040000 /* CIR offset */
+
+/*
+ * TCDS CIR control bits.
+ */
+#define TCDS_CIR_GPO_0 0x00000001 /* Not used */
+#define TCDS_CIR_GPO_1 0x00000002 /* Not used */
+#define TCDS_CIR_GPO_2 0x00000004 /* Not used */
+#define TCDS_CIR_STD 0x00000008 /* Serial transmit disable */
+#define TCDS_CIR_GPI_0 0x00000010 /* Not used */
+#define TCDS_CIR_GPI_1 0x00000020 /* Not used */
+#define TCDS_CIR_GPI_2 0x00000040 /* Not used */
+#define TCDS_CIR_GPI_3 0x00000080 /* Not used */
+#define TCDS_CIR_SCSI0_DMAENA 0x00000100 /* SCSI 0 DMA enable */
+#define TCDS_CIR_SCSI1_DMAENA 0x00000200 /* SCSI 1 DMA enable */
+#define TCDS_CIR_SCSI0_RESET 0x00000400 /* SCSI 0 reset */
+#define TCDS_CIR_SCSI1_RESET 0x00000800 /* SCSI 1 reset */
+#define TCDS_CIR_SCSI0_DMA_TEST 0x00001000 /* SCSI 0 DMA buf parity test */
+#define TCDS_CIR_SCSI1_DMA_TEST 0x00002000 /* SCSI 1 DMA buf parity test */
+#define TCDS_CIR_DB_PAR 0x00004000 /* DB parity test mode */
+#define TCDS_CIR_TC_PAR 0x00008000 /* TC parity test mode */
+#define TCDS_CIR_ALLCONTROL 0x0000ffff /* all control bits */
+
+/* TCDS CIR interrupt bits. */
+#define TCDS_CIR_SCSI0_DREQ 0x00010000 /* SCSI 0 DREQ */
+#define TCDS_CIR_SCSI1_DREQ 0x00020000 /* SCSI 1 DREQ */
+#define TCDS_CIR_SCSI0_INT 0x00040000 /* SCSI 0 interrupt */
+#define TCDS_CIR_SCSI1_INT 0x00080000 /* SCSI 1 interrupt */
+#define TCDS_CIR_SCSI0_PREFETCH 0x00100000 /* SCSI 0 prefetch */
+#define TCDS_CIR_SCSI1_PREFETCH 0x00200000 /* SCSI 1 prefetch */
+#define TCDS_CIR_SCSI0_DMA 0x00400000 /* SCSI 0 DMA error */
+#define TCDS_CIR_SCSI1_DMA 0x00800000 /* SCSI 1 DMA error */
+#define TCDS_CIR_SCSI0_DB 0x01000000 /* SCSI 0 DB parity */
+#define TCDS_CIR_SCSI1_DB 0x02000000 /* SCSI 1 DB parity */
+#define TCDS_CIR_SCSI0_DMAB_PAR 0x04000000 /* SCSI 0 DMA buffer parity */
+#define TCDS_CIR_SCSI1_DMAB_PAR 0x08000000 /* SCSI 1 DMA buffer parity */
+#define TCDS_CIR_SCSI0_DMAR_PAR 0x10000000 /* SCSI 0 DMA read parity */
+#define TCDS_CIR_SCSI1_DMAR_PAR 0x20000000 /* SCSI 1 DMA read parity */
+#define TCDS_CIR_TCIOW_PAR 0x40000000 /* TC I/O write parity */
+#define TCDS_CIR_TCIOA_PAR 0x80000000 /* TC I/O address parity */
+#define TCDS_CIR_ALLINTR 0xffff0000 /* all interrupt bits */
+
+#define TCDS_CIR_CLR(c, b) c = ((c | TCDS_CIR_ALLINTR) & ~b)
+#define TCDS_CIR_SET(c, b) c = ((c | TCDS_CIR_ALLINTR) | b)
+
+/* TCDS IMER masks and enables, for interrupts in the CIR. */
+#define TCDS_IMER_SCSI0_MASK 0x04 /* SCSI 0 intr/enable mask */
+#define TCDS_IMER_SCSI1_MASK 0x08 /* SCSI 1 intr/enable mask */
+#define TCDS_IMER_SCSI0_ENB (TCDS_IMER_SCSI0_MASK << 16)
+#define TCDS_IMER_SCSI1_ENB (TCDS_IMER_SCSI1_MASK << 16)
+#define TCDS_IMER 0x040004 /* IMER offset */
+
+#define TCDS_SCSI0_DMA_ADDR 0x041000 /* DMA address */
+#define TCDS_SCSI0_DMA_INTR 0x041004 /* DMA interrupt control */
+#define TCDS_SCSI0_DMA_DUD0 0x041008 /* DMA unaligned data[0] */
+#define TCDS_SCSI0_DMA_DUD1 0x04100c /* DMA unaligned data[1] */
+
+#define TCDS_SCSI1_DMA_ADDR 0x041100 /* DMA address */
+#define TCDS_SCSI1_DMA_INTR 0x041104 /* DMA interrupt control */
+#define TCDS_SCSI1_DMA_DUD0 0x041108 /* DMA unaligned data[0] */
+#define TCDS_SCSI1_DMA_DUD1 0x04110c /* DMA unaligned data[1] */
+
+#define TCDS_DIC_ADDRMASK 0x03 /* DMA address bits <1:0> */
+#define TCDS_DIC_READ_PREFETCH 0x40 /* DMA read prefetch enable */
+#define TCDS_DIC_WRITE 0x80 /* DMA write */
+
+#define TCDS_DUD0_VALID00 0x00000001 /* byte 00 valid mask (zero) */
+#define TCDS_DUD0_VALID01 0x00000002 /* byte 01 valid mask */
+#define TCDS_DUD0_VALID10 0x00000004 /* byte 10 valid mask */
+#define TCDS_DUD0_VALID11 0x00000008 /* byte 11 valid mask */
+#define TCDS_DUD0_VALIDBITS 0x0000000f /* bits that show valid bytes */
+
+#define TCDS_DUD1_VALID00 0x01000000 /* byte 00 valid mask */
+#define TCDS_DUD1_VALID01 0x02000000 /* byte 01 valid mask */
+#define TCDS_DUD1_VALID10 0x04000000 /* byte 10 valid mask */
+#define TCDS_DUD1_VALID11 0x08000000 /* byte 11 valid mask (zero) */
+#define TCDS_DUD1_VALIDBITS 0x0f000000 /* bits that show valid bytes */
+
+#define TCDS_DUD_BYTE00 0x000000ff /* byte 00 mask */
+#define TCDS_DUD_BYTE01 0x0000ff00 /* byte 01 mask */
+#define TCDS_DUD_BYTE10 0x00ff0000 /* byte 10 mask */
+#define TCDS_DUD_BYTE11 0xff000000 /* byte 11 mask */
+
+#if 0
+int tcds_scsi_iserr __P((struct dma_softc *));
+int tcds_scsi_isintr __P((int, int));
+void tcds_dma_disable __P((int));
+void tcds_dma_enable __P((int));
+void tcds_dma_init __P((struct dma_softc *, int));
+void tcds_scsi_disable __P((int));
+void tcds_scsi_enable __P((int));
+void tcds_scsi_reset __P((int));
+
+/*
+ * XXX
+ * Start of MACH #defines, minimal changes to port to NetBSD.
+ *
+ * The following register is the SCSI control interrupt register. It
+ * starts, stops and resets scsi DMA. It takes over the SCSI funtions
+ * that were handled by the ASIC on the 3min.
+ */
+#define KN15AA_SYS_SCSI 0x1d0000000
+#define KN15AA_REG_SCSI_CIR (KN15AA_SYS_SCSI + 0x80000)
+#define SCSI_CIR_AIOPAR 0x80000000 /* TC IO Address parity error */
+#define SCSI_CIR_WDIOPAR 0x40000000 /* TC IO write data parity error */
+#define SCSI_CIR_DMARPAR1 0x20000000 /* SCSI[1] TC DMA read data parity */
+#define SCSI_CIR_DMARPAR0 0x10000000 /* SCSI[0] TC DMA read data parity */
+#define SCSI_CIR_DMABUFPAR1 0x08000000 /* SCSI[1] DMA buffer parity error */
+#define SCSI_CIR_DMABUFPAR0 0x04000000 /* SCSI[0] DMA buffer parity error */
+#define SCSI_CIR_DBPAR1 0x02000000 /* SCSI[1] DB parity error */
+#define SCSI_CIR_DBPAR0 0x01000000 /* SCSI[0] DB parity error */
+#define SCSI_CIR_DMAERR1 0x00800000 /* SCSI[1] DMA error */
+#define SCSI_CIR_DMAERR0 0x00400000 /* SCSI[0] DMA error */
+#if fmm50
+#define SCSI_CIR_xxx0 0x00200000 /* RESERVED */
+#define SCSI_CIR_xxx1 0x00100000 /* RESERVED */
+#else
+#define SCSI_CIR_PREF1 0x00200000 /* 53C94 prefetch interupt */
+#define SCSI_CIR_PREF0 0x00100000 /* 53C94 prefetch interupt */
+#endif
+#define SCSI_CIR_53C94_INT1 0x00080000 /* SCSI[1] 53C94 Interupt */
+#define SCSI_CIR_53C94_INT0 0x00040000 /* SCSI[0] 53C94 Interupt */
+#define SCSI_CIR_53C94_DREQ1 0x00020000 /* SCSI[1] 53C94 DREQ */
+#define SCSI_CIR_53C94_DREQ0 0x00010000 /* SCSI[0] 53C94 DREQ */
+#define SCSI_CIR_TC_PAR_TEST 0x00008000 /* TC parity test mode */
+#define SCSI_CIR_DB_PAR_TEST 0x00004000 /* DB parity test mode */
+#define SCSI_CIR_DBUF_PAR_TEST1 0x00002000 /* SCSI[1] DMA buffer parity test */
+#define SCSI_CIR_DBUF_PAR_TEST0 0x00001000 /* SCSI[0] DMA buffer parity test */
+#define SCSI_CIR_RESET1 0x00000800 /* SCSI[1] ~Reset,enable(0)/disable(1) */
+#define SCSI_CIR_RESET0 0x00000400 /* SCSI[0] ~Reset,enable(0)/disable(1) */
+#define SCSI_CIR_DMAENA1 0x00000200 /* SCSI[1] DMA enable */
+#define SCSI_CIR_DMAENA0 0x00000100 /* SCSI[1] DMA enable */
+#define SCSI_CIR_GPI3 0x00000080 /* General purpose input <3> */
+#define SCSI_CIR_GPI2 0x00000040 /* General purpose input <2> */
+#define SCSI_CIR_GPI1 0x00000020 /* General purpose input <1> */
+#define SCSI_CIR_GPI0 0x00000010 /* General purpose input <0> */
+#define SCSI_CIR_TXDIS 0x00000008 /* TXDIS- serial transmit disable */
+#define SCSI_CIR_GPO2 0x00000004 /* General purpose output <2> */
+#define SCSI_CIR_GPO1 0x00000002 /* General purpose output <1> */
+#define SCSI_CIR_GPO0 0x00000001 /* General purpose output <0> */
+#define SCSI_CIR_ERROR (SCSI_CIR_AIOPAR | SCSI_CIR_WDIOPAR | SCSI_CIR_DMARPAR1 | SCSI_CIR_DMARPAR0 | SCSI_CIR_DMABUFPAR1 | SCSI_CIR_DMABUFPAR0 | SCSI_CIR_DBPAR1 |SCSI_CIR_DBPAR0 | SCSI_CIR_DMAERR1 | SCSI_CIR_DMAERR0 )
+
+#define KN15AA_REG_SCSI_DMAPTR0 (KN15AA_SYS_SCSI + 0x82000)
+#define KN15AA_REG_SCSI_DMAPTR1 (KN15AA_SYS_SCSI + 0x82200)
+
+#define KN15AA_REG_SCSI_DIC0 (KN15AA_SYS_SCSI + 0x82008)
+#define KN15AA_REG_SCSI_DIC1 (KN15AA_SYS_SCSI + 0x82208)
+#define SCSI_DIC_DMADIR 0x00000080 /* DMA direction read(0)/write(1) */
+#define SCSI_DIC_PREFENA 0x00000040 /* DMA read prefetch dis(0)/ena(1) */
+#define SCSI_DIC_DMAADDR1 0x00000002 /* DMA address <1> */
+#define SCSI_DIC_DMAADDR0 0x00000001 /* DMA address <0> */
+#define SCSI_DIC_ADDR_MASK (SCSI_DIC_DMAADDR0 |SCSI_DIC_DMAADDR1)
+
+#define KN15AA_REG_SCSI_94REG0 (KN15AA_SYS_SCSI + 0x100000)
+#define KN15AA_REG_SCSI_94REG1 (KN15AA_SYS_SCSI + 0x100200)
+
+#define KN15AA_REG_SCSI_IMER (KN15AA_SYS_SCSI + 0x80008)
+
+/* these are the bits that were unalligned at the beginning of the dma */
+#define KN15AA_REG_SCSI_DUDB0 (KN15AA_SYS_SCSI + 0x82010)
+#define KN15AA_REG_SCSI_DUDB1 (KN15AA_SYS_SCSI + 0x82210)
+# define SCSI_DUDB_MASK01 0x00000001 /* Mask bit for byte[01] */
+# define SCSI_DUDB_MASK10 0x00000002 /* Mask bit for byte[10] */
+# define SCSI_DUDB_MASK11 0x00000004 /* Mask bit for byte[11] */
+
+/* these are the bits that were unalligned at the end of the dma */
+#define KN15AA_REG_SCSI_DUDE0 (KN15AA_SYS_SCSI + 0x82018)
+#define KN15AA_REG_SCSI_DUDE1 (KN15AA_SYS_SCSI + 0x82218)
+# define SCSI_DUDE_MASK00 0x1000000 /* Mask bit for byte[00] */
+# define SCSI_DUDE_MASK01 0x2000000 /* Mask bit for byte[01] */
+# define SCSI_DUDE_MASK10 0x4000000 /* Mask bit for byte[10] */
+
+#define SCSI_CIR phystok0seg(KN15AA_REG_SCSI_CIR)
+#define SCSI_IMER phystok0seg(KN15AA_REG_SCSI_IMER)
+
+#endif
diff --git a/sys/alpha/tc/tcdsvar.h b/sys/alpha/tc/tcdsvar.h
new file mode 100644
index 0000000..e1c15e8
--- /dev/null
+++ b/sys/alpha/tc/tcdsvar.h
@@ -0,0 +1,111 @@
+/* $Id$ */
+/* $NetBSD: tcdsvar.h,v 1.3.4.1 1996/09/10 17:28:20 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+struct tcds_slotconfig {
+ /*
+ * Bookkeeping information
+ */
+ int sc_slot;
+ struct tcds_softc *sc_tcds; /* to frob TCDS regs */
+ struct esp_softc *sc_esp; /* to frob child's regs */
+ void (*sc_intrhand) __P((void *)); /* intr. handler */
+ void *sc_intrarg; /* intr. handler arg. */
+
+ /*
+ * Sets of bits in TCDS CIR and IMER that enable/check
+ * various things.
+ */
+ u_int32_t sc_resetbits;
+ u_int32_t sc_intrmaskbits;
+ u_int32_t sc_intrbits;
+ u_int32_t sc_dmabits;
+ u_int32_t sc_errorbits;
+
+ /*
+ * Pointers to slot-specific DMA resources.
+ */
+ volatile u_int32_t *sc_sda;
+ volatile u_int32_t *sc_dic;
+ volatile u_int32_t *sc_dud0;
+ volatile u_int32_t *sc_dud1;
+
+ /*
+ * DMA bookkeeping information.
+ */
+ int sc_active; /* DMA active ? */
+ int sc_iswrite; /* DMA into main memory? */
+ size_t sc_dmasize;
+ caddr_t *sc_dmaaddr;
+ size_t *sc_dmalen;
+};
+
+struct tcdsdev_attach_args {
+ struct tc_attach_args tcdsda_ta;
+ struct tcds_slotconfig *tcdsda_sc;
+ u_int tcdsda_id;
+ u_int tcdsda_freq;
+};
+#define tcdsda_modname tcdsda_ta.ta_modname
+#define tcdsda_slot tcdsda_ta.ta_slot
+#define tcdsda_offset tcdsda_ta.ta_offset
+#define tcdsda_addr tcdsda_ta.ta_addr
+#define tcdsda_cookie tcdsda_ta.ta_cookie
+
+#define TCDS_REG(base, off) \
+ (volatile u_int32_t *)TC_DENSE_TO_SPARSE((base) + (off))
+
+/*
+ * TCDS functions.
+ */
+void tcds_intr_establish __P((struct device *, void *, tc_intrlevel_t,
+ int (*)(void *), void *));
+void tcds_intr_disestablish __P((struct device *, void *));
+void tcds_dma_enable __P((struct tcds_slotconfig *, int));
+void tcds_scsi_enable __P((struct tcds_slotconfig *, int));
+int tcds_scsi_isintr __P((struct tcds_slotconfig *, int));
+void tcds_scsi_reset __P((struct tcds_slotconfig *));
+int tcds_scsi_iserr __P((struct tcds_slotconfig *sc));
+
+/*
+ * TCDS DMA functions (used the the 53c94 driver)
+ */
+int tcds_dma_isintr __P((struct tcds_slotconfig *));
+void tcds_dma_reset __P((struct tcds_slotconfig *));
+int tcds_dma_intr __P((struct tcds_slotconfig *));
+int tcds_dma_setup __P((struct tcds_slotconfig *, caddr_t *, size_t *,
+ int, size_t *));
+void tcds_dma_go __P((struct tcds_slotconfig *));
+int tcds_dma_isactive __P((struct tcds_slotconfig *));
+
+/*
+ * The TCDS (bus) cfdriver, so that subdevices can more
+ * easily tell what bus they're on.
+ */
+extern struct cfdriver tcds_cd;
diff --git a/sys/alpha/tc/tcreg.h b/sys/alpha/tc/tcreg.h
new file mode 100644
index 0000000..8075168
--- /dev/null
+++ b/sys/alpha/tc/tcreg.h
@@ -0,0 +1,162 @@
+/* $Id$ */
+/* $NetBSD: tcreg.h,v 1.1 1995/12/20 00:48:36 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef __DEV_TC_TCREG_H__
+#define __DEV_TC_TCREG_H__
+
+/*
+ * TurboChannel bus and register definitions.
+ */
+
+#define TC_ROM_LLEN 8
+#define TC_ROM_SLEN 4
+#define TC_ROM_TEST_SIZE 16
+
+#define TC_SLOT_ROM 0x000003e0
+#define TC_SLOT_PROTOROM 0x003c03e0
+
+typedef struct tc_padchar {
+ u_int8_t v;
+ u_int8_t pad[3];
+} tc_padchar_t;
+
+struct tc_rommap {
+ tc_padchar_t tcr_width;
+ tc_padchar_t tcr_stride;
+ tc_padchar_t tcr_rsize;
+ tc_padchar_t tcr_ssize;
+ u_int8_t tcr_test[TC_ROM_TEST_SIZE];
+ tc_padchar_t tcr_rev[TC_ROM_LLEN];
+ tc_padchar_t tcr_vendname[TC_ROM_LLEN];
+ tc_padchar_t tcr_modname[TC_ROM_LLEN];
+ tc_padchar_t tcr_firmtype[TC_ROM_SLEN];
+};
+
+
+
+/*
+ * TurboChannel-specific functions and structures for 3000_300.
+ */
+#define TC_3000_300_IR KV(0x00000001e0000000) /* Dense */
+#define TC_3000_300_CSR KV(0x00000001e0000008) /* Dense */
+#define TC_3000_300_MCR KV(0x00000001e0000010) /* Dense */
+#define TC_3000_300_LED KV(0x00000001e0000018) /* Dense */
+
+/* Interrupt bits. */
+#define TC_3000_300_IR_CXTURBO 0x00000004 /* TC CXTURBO */
+#define TC_3000_300_IR_TCDS 0x00000008 /* TC Dual SCSI */
+#define TC_3000_300_IR_IOASIC 0x00000010 /* TC IOASIC */
+#define TC_3000_300_IR_BCTAGPARITY 0x08000000 /* BC tag par. err. */
+#define TC_3000_300_IR_TCOVERRUN 0x10000000 /* TC overrun */
+#define TC_3000_300_IR_TCTIMEOUT 0x20000000 /* TC timeout on I/O */
+#define TC_3000_300_IR_BCACHEPARITY 0x40000000 /* Bcache par. err. */
+#define TC_3000_300_IR_MEMPARITY 0x80000000 /* Memory par. err. */
+
+/* Device number "cookies." */
+#define TC_3000_300_DEV_OPT0 0
+#define TC_3000_300_DEV_OPT1 1
+#define TC_3000_300_DEV_TCDS 2
+#define TC_3000_300_DEV_IOASIC 3
+#define TC_3000_300_DEV_CXTURBO 4
+
+#define TC_3000_300_DEV_BOGUS -1
+
+#define TC_3000_300_NCOOKIES 5
+
+#define TC_3000_500_IOSLOT KV(0x00000001c2000000) /* Dense */
+#define TC_3000_500_TCCONFIG KV(0x00000001c2000008) /* Dense */
+#define TC_3000_500_FADR KV(0x00000001c2000010) /* Dense */
+#define TC_3000_500_TCEREG KV(0x00000001c2000018) /* Dense */
+#define TC_3000_500_MEMCONF KV(0x00000001c2200000) /* Dense */
+#define TC_3000_500_IMR_READ KV(0x00000001c2400000) /* Dense */
+#define TC_3000_500_IMR_WRITE KV(0x00000001c281fffc) /* Dense */
+#define TC_3000_500_TCRESET KV(0x00000001c2a00000) /* Dense */
+#define TC_3000_500_IR KV(0x00000001d4800000) /* Sparse */
+#define TC_3000_500_IR_CLEAR KV(0x00000001d4c00000) /* Sparse */
+#define TC_3000_500_SCMAP KV(0x00000001d5000000) /* Sparse */
+
+/* Interrupt bits. */
+#define TC_3000_500_IR_OPT0 0x00000001 /* TC Option 0 */
+#define TC_3000_500_IR_OPT1 0x00000002 /* TC Option 1 */
+#define TC_3000_500_IR_OPT2 0x00000004 /* TC Option 2 */
+#define TC_3000_500_IR_OPT3 0x00000008 /* TC Option 3 */
+#define TC_3000_500_IR_OPT4 0x00000010 /* TC Option 4 */
+#define TC_3000_500_IR_OPT5 0x00000020 /* TC Option 5 */
+#define TC_3000_500_IR_TCDS 0x00000040 /* TC Dual SCSI */
+#define TC_3000_500_IR_IOASIC 0x00000080 /* TC IOASIC */
+#define TC_3000_500_IR_CXTURBO 0x00000100 /* TC CXTURBO */
+#define TC_3000_500_IR_ERR2 0x00080000 /* Second error */
+#define TC_3000_500_IR_DMABE 0x00100000 /* DMA buffer error */
+#define TC_3000_500_IR_DMA2K 0x00200000 /* DMA 2K boundary */
+#define TC_3000_500_IR_TCRESET 0x00400000 /* TC reset in prog. */
+#define TC_3000_500_IR_TCPAR 0x00800000 /* TC parity error */
+#define TC_3000_500_IR_DMATAG 0x01000000 /* DMA tag error */
+#define TC_3000_500_IR_DMASBE 0x02000000 /* Single-bit error */
+#define TC_3000_500_IR_DMADBE 0x04000000 /* Double-bit error */
+#define TC_3000_500_IR_TCTIMEOUT 0x08000000 /* TC timeout on I/O */
+#define TC_3000_500_IR_DMABLOCK 0x10000000 /* DMA block too long */
+#define TC_3000_500_IR_IOADDR 0x20000000 /* Invalid I/O addr */
+#define TC_3000_500_IR_DMASG 0x40000000 /* SG invalid */
+#define TC_3000_500_IR_SGPAR 0x80000000 /* SG parity error */
+
+/* I/O Slot Configuration (IOSLOT) bits. */
+#define IOSLOT_P 0x04 /* Parity enable. */
+#define IOSLOT_B 0x02 /* Block-mode write. */
+#define IOSLOT_S 0x01 /* DMA scatter/gather mode. */
+
+/* I/O Slot Configuration (IOSLOT) offsets. */
+#define TC_IOSLOT_OPT0 0 /* Option 0 PBS offset. */
+#define TC_IOSLOT_OPT1 1 /* Option 1 PBS offset. */
+#define TC_IOSLOT_OPT2 2 /* Option 2 PBS offset. */
+#define TC_IOSLOT_OPT3 3 /* Option 3 PBS offset. */
+#define TC_IOSLOT_OPT4 4 /* Option 4 PBS offset. */
+#define TC_IOSLOT_OPT5 5 /* Option 5 PBS offset. */
+#define TC_IOSLOT_SCSI 6 /* Option SCSI PBS offset. */
+#define TC_IOSLOT_IOASIC 7 /* Option IOASIC PBS offset. */
+#define TC_IOSLOT_CXTURBO 8 /* Option CXTURBO PBS offset. */
+
+/* Device number "cookies." */
+#define TC_3000_500_DEV_OPT0 0
+#define TC_3000_500_DEV_OPT1 1
+#define TC_3000_500_DEV_OPT2 2
+#define TC_3000_500_DEV_OPT3 3
+#define TC_3000_500_DEV_OPT4 4
+#define TC_3000_500_DEV_OPT5 5
+#define TC_3000_500_DEV_TCDS 6
+#define TC_3000_500_DEV_IOASIC 7
+#define TC_3000_500_DEV_CXTURBO 8
+
+#define TC_3000_500_DEV_BOGUS -1
+
+#define TC_3000_500_NCOOKIES 9
+
+
+
+#endif /* __DEV_TC_TCREG_H__ */
diff --git a/sys/alpha/tc/tcvar.h b/sys/alpha/tc/tcvar.h
new file mode 100644
index 0000000..17e7209
--- /dev/null
+++ b/sys/alpha/tc/tcvar.h
@@ -0,0 +1,200 @@
+/* $Id$ */
+/* $NetBSD: tcvar.h,v 1.13 1998/05/22 21:15:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef __DEV_TC_TCVAR_H__
+#define __DEV_TC_TCVAR_H__
+
+/*
+ * Definitions for TurboChannel autoconfiguration.
+ */
+
+/*
+ * In the long run, the following block will go completely away.
+ * For now, the MI TC code still uses the old TC_IPL_ names
+ * and not the new IPL_ names.
+ */
+#if 1
+/*
+ * Map the new definitions to the old.
+ */
+#include <machine/intr.h>
+
+#define tc_intrlevel_t int
+
+#define TC_IPL_NONE IPL_NONE
+#define TC_IPL_BIO IPL_BIO
+#define TC_IPL_NET IPL_NET
+#define TC_IPL_TTY IPL_TTY
+#define TC_IPL_CLOCK IPL_CLOCK
+#endif /* 1 */
+
+
+typedef u_int64_t tc_addr_t;
+typedef int32_t tc_offset_t;
+
+#define tc_mb() alpha_mb()
+#define tc_wmb() alpha_wmb()
+
+
+/*
+ * A junk address to read from, to make sure writes are complete. See
+ * System Programmer's Manual, section 9.3 (p. 9-4), and sacrifice a
+ * chicken.
+ */
+#define tc_syncbus() \
+ do { \
+ volatile u_int32_t no_optimize; \
+ no_optimize = \
+ *(volatile u_int32_t *)ALPHA_PHYS_TO_K0SEG(0x00000001f0080220); \
+ } while (0)
+
+#define tc_badaddr(tcaddr) \
+ badaddr((void *)(tcaddr), sizeof (u_int32_t))
+
+#define TC_SPACE_IND 0xffffffffe0000003
+#define TC_SPACE_DENSE 0x0000000000000000
+#define TC_SPACE_DENSE_OFFSET 0x0000000007fffffc
+#define TC_SPACE_SPARSE 0x0000000010000000
+#define TC_SPACE_SPARSE_OFFSET 0x000000000ffffff8
+
+#define TC_DENSE_TO_SPARSE(addr) \
+ (((addr) & TC_SPACE_IND) | TC_SPACE_SPARSE | \
+ (((addr) & TC_SPACE_DENSE_OFFSET) << 1))
+
+#define TC_PHYS_TO_UNCACHED(addr) \
+ (addr)
+
+/*
+ * These functions are private, and may not be called by
+ * machine-independent code.
+ */
+void tc_dma_init __P((void));
+
+/*
+ * Address of scatter/gather SRAM on the 3000/500-series.
+ *
+ * There is room for 32K entries, yielding 256M of sgva space.
+ * The page table is readable in both dense and sparse space.
+ * The page table is writable only in sparse space.
+ *
+ * In sparse space, the 32-bit PTEs are followed by 32-bits
+ * of pad.
+ */
+#define TC_SGSRAM_DENSE 0x0000001c2800000UL
+#define TC_SGSRAM_SPARSE 0x0000001d5000000UL
+
+
+/*
+ * Description of TurboChannel slots, provided by machine-dependent
+ * code to the TurboChannel bus driver.
+ */
+struct tc_slotdesc {
+ tc_addr_t tcs_addr;
+ void *tcs_cookie;
+ int tcs_used;
+};
+
+/*
+ * Description of built-in TurboChannel devices, provided by
+ * machine-dependent code to the TurboChannel bus driver.
+ */
+struct tc_builtin {
+ char *tcb_modname;
+ u_int tcb_slot;
+ tc_offset_t tcb_offset;
+ void *tcb_cookie;
+};
+
+/*
+ * Arguments used to attach TurboChannel busses.
+ */
+struct tcbus_attach_args {
+ char *tba_busname; /* XXX should be common */
+/* bus_space_tag_t tba_memt;*/
+
+ /* Bus information */
+ u_int tba_speed; /* see TC_SPEED_* below */
+ u_int tba_nslots;
+ struct tc_slotdesc *tba_slots;
+ u_int tba_nbuiltins;
+ const struct tc_builtin *tba_builtins;
+
+
+ /* TC bus resource management; XXX will move elsewhere eventually. */
+/*
+ void (*tba_intr_establish) __P((struct device *, void *,
+ tc_intrlevel_t, int (*)(void *), void *));
+ void (*tba_intr_disestablish) __P((struct device *, void *));
+*/
+};
+
+/*
+ * Arguments used to attach TurboChannel devices.
+ */
+struct tc_attach_args {
+/*
+ bus_space_tag_t ta_memt;
+ bus_dma_tag_t ta_dmat;
+*/
+ char ta_modname[TC_ROM_LLEN+1];
+ u_int ta_slot;
+ tc_offset_t ta_offset;
+ tc_addr_t ta_addr;
+ void *ta_cookie;
+ u_int ta_busspeed; /* see TC_SPEED_* below */
+};
+
+/*
+ * Interrupt establishment functions.
+ */
+void tc_intr_establish __P((struct device *, void *, tc_intrlevel_t,
+ int (*)(void *), void *));
+void tc_intr_disestablish __P((struct device *, void *));
+
+#if 0
+#include "locators.h"
+/*
+ * Easy to remember names for TurboChannel device locators.
+ */
+#define tccf_slot cf_loc[TCCF_SLOT] /* slot */
+#define tccf_offset cf_loc[TCCF_OFFSET] /* offset */
+
+#endif
+
+#define TCCF_SLOT_UNKNOWN TCCF_SLOT_DEFAULT
+#define TCCF_OFFSET_UNKNOWN TCCF_OFFSET_DEFAULT
+
+/*
+ * Miscellaneous definitions.
+ */
+#define TC_SPEED_12_5_MHZ 0 /* 12.5MHz TC bus */
+#define TC_SPEED_25_MHZ 1 /* 25MHz TC bus */
+
+#endif /* __DEV_TC_TCVAR_H__ */
diff --git a/sys/conf/files.alpha b/sys/conf/files.alpha
index 5e28c2c..68888d5 100644
--- a/sys/conf/files.alpha
+++ b/sys/conf/files.alpha
@@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
-# $Id: files.alpha,v 1.4 1998/07/22 08:24:39 dfr Exp $
+# $Id: files.alpha,v 1.5 1998/08/10 07:53:58 dfr Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@@ -22,6 +22,8 @@ alpha/alpha/dec_kn20aa.c optional dec_kn20aa
alpha/alpha/dec_2100_a50.c optional dec_2100_a50
alpha/alpha/dec_st550.c optional dec_st550
alpha/alpha/dec_axppci_33.c optional dec_axppci_33
+alpha/alpha/dec_3000_300.c optional dec_3000_300
+alpha/alpha/dec_3000_500.c optional dec_3000_500
alpha/alpha/mountroot.c optional slice
alpha/alpha/ipl_funcs.c standard
alpha/alpha/pal.s standard
@@ -70,6 +72,16 @@ alpha/tlsb/kftxx.c optional kft
alpha/tlsb/mcclock_tlsb.c optional gbus
alpha/tlsb/zs_tlsb.c optional gbus
alpha/tlsb/dwlpx.c optional dwlpx
+alpha/tc/tcasic.c optional tcasic
+alpha/tc/tc.c optional tc
+alpha/tc/ioasic.c optional tc
+alpha/tc/mcclock_ioasic.c optional tc
+alpha/tc/if_le_ioasic.c optional le device-driver
+alpha/tc/if_le_dec.c optional le device-driver
+alpha/tc/am7990.c optional le device-driver
+alpha/tc/tcds.c optional tcds device-driver
+alpha/tc/tcds_dma.c optional tcds device-driver
+alpha/tc/esp.c optional esp device-driver
dev/dec/mcclock.c standard
dev/dec/mcclock_if.m standard \
dependency "$S/kern/makedevops.sh" \
@@ -126,5 +138,6 @@ libkern/alpha/ntohl.S standard
libkern/alpha/ntohs.S standard
isa/sio.c optional sio device-driver
isa/kbdio.c optional psm device-driver
+isa/psm.c optional psm device-driver
isa/kbdio.c optional sc device-driver
isa/syscons.c optional sc device-driver
diff --git a/sys/conf/options.alpha b/sys/conf/options.alpha
index 3132f9a..de3aee2 100644
--- a/sys/conf/options.alpha
+++ b/sys/conf/options.alpha
@@ -1,12 +1,15 @@
-# $Id: options.alpha,v 1.3 1998/07/22 08:24:39 dfr Exp $
+# $Id: options.alpha,v 1.4 1998/08/10 07:53:58 dfr Exp $
EV5 opt_global.h
+EV4 opt_global.h
DEC_KN8AE opt_cpu.h
DEC_EB164 opt_cpu.h
DEC_KN20AA opt_cpu.h
DEC_2100_A50 opt_cpu.h
DEC_ST550 opt_cpu.h
DEC_AXPPCI_33 opt_cpu.h
+DEC_3000_300 opt_cpu.h
+DEC_3000_500 opt_cpu.h
ATAPI opt_atapi.h
ATAPI_STATIC opt_atapi.h
OpenPOWER on IntegriCloud