From 0c47a30d50ae5d445fee4feb919e88eda179d382 Mon Sep 17 00:00:00 2001 From: dfr Date: Thu, 20 Aug 1998 08:27:11 +0000 Subject: Add support for TurboChannel alphas (DEC 3000/300 and 3000/500). Obtained from: NetBSD Submitted by: Andrew Gallatin --- sys/alpha/alpha/autoconf.c | 17 +- sys/alpha/alpha/dec_3000_300.c | 82 ++ sys/alpha/alpha/dec_3000_500.c | 102 +++ sys/alpha/conf/GENERIC | 23 +- sys/alpha/conf/NOTES | 23 +- sys/alpha/conf/files.alpha | 15 +- sys/alpha/conf/options.alpha | 5 +- sys/alpha/tc/am7990.c | 1473 +++++++++++++++++++++++++++++++ sys/alpha/tc/am7990reg.h | 216 +++++ sys/alpha/tc/am7990var.h | 208 +++++ sys/alpha/tc/ascvar.h | 92 ++ sys/alpha/tc/esp.c | 1898 ++++++++++++++++++++++++++++++++++++++++ sys/alpha/tc/espreg.h | 149 ++++ sys/alpha/tc/espvar.h | 330 +++++++ sys/alpha/tc/if_le_dec.c | 170 ++++ sys/alpha/tc/if_le_ioasic.c | 398 +++++++++ sys/alpha/tc/if_levar.h | 69 ++ sys/alpha/tc/ioasic.c | 381 ++++++++ sys/alpha/tc/ioasicreg.h | 227 +++++ sys/alpha/tc/ioasicvar.h | 59 ++ sys/alpha/tc/mcclock_ioasic.c | 130 +++ sys/alpha/tc/sticreg.h | 101 +++ sys/alpha/tc/sticvar.h | 53 ++ sys/alpha/tc/tc.c | 704 +++++++++++++++ sys/alpha/tc/tcasic.c | 115 +++ sys/alpha/tc/tcdevs.h | 118 +++ sys/alpha/tc/tcdevs_data.h | 174 ++++ sys/alpha/tc/tcds.c | 459 ++++++++++ sys/alpha/tc/tcds_dma.c | 286 ++++++ sys/alpha/tc/tcdsreg.h | 215 +++++ sys/alpha/tc/tcdsvar.h | 111 +++ sys/alpha/tc/tcreg.h | 162 ++++ sys/alpha/tc/tcvar.h | 200 +++++ sys/conf/files.alpha | 15 +- sys/conf/options.alpha | 5 +- 35 files changed, 8772 insertions(+), 13 deletions(-) create mode 100644 sys/alpha/alpha/dec_3000_300.c create mode 100644 sys/alpha/alpha/dec_3000_500.c create mode 100644 sys/alpha/tc/am7990.c create mode 100644 sys/alpha/tc/am7990reg.h create mode 100644 sys/alpha/tc/am7990var.h create mode 100644 sys/alpha/tc/ascvar.h create mode 100644 sys/alpha/tc/esp.c create mode 100644 sys/alpha/tc/espreg.h create mode 100644 sys/alpha/tc/espvar.h create mode 100644 sys/alpha/tc/if_le_dec.c create mode 100644 sys/alpha/tc/if_le_ioasic.c create mode 100644 sys/alpha/tc/if_levar.h create mode 100644 sys/alpha/tc/ioasic.c create mode 100644 sys/alpha/tc/ioasicreg.h create mode 100644 sys/alpha/tc/ioasicvar.h create mode 100644 sys/alpha/tc/mcclock_ioasic.c create mode 100644 sys/alpha/tc/sticreg.h create mode 100644 sys/alpha/tc/sticvar.h create mode 100644 sys/alpha/tc/tc.c create mode 100644 sys/alpha/tc/tcasic.c create mode 100644 sys/alpha/tc/tcdevs.h create mode 100644 sys/alpha/tc/tcdevs_data.h create mode 100644 sys/alpha/tc/tcds.c create mode 100644 sys/alpha/tc/tcds_dma.c create mode 100644 sys/alpha/tc/tcdsreg.h create mode 100644 sys/alpha/tc/tcdsvar.h create mode 100644 sys/alpha/tc/tcreg.h create mode 100644 sys/alpha/tc/tcvar.h 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 @@ -41,6 +41,7 @@ #include #include #include +#include #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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +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 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#endif +#include +#include + +#include + +#include +#include + +#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 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 = ⊤ + + 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 +#include +#include +#include +#include +#include + +#include +/*#include */ +#include +#include +#include +/*#include */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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<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<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<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<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<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(("", 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_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("", + 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<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<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("<>"); +#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("\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(("", + 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("<>"); +#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<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_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<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(("", 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)], " + "", + 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("", (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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#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) +#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 +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + + + +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 + +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*#include */ + +#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 +#include +#include +#include +#include + +#include + +/*#include */ + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + +#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 -- cgit v1.1