diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-26 18:12:13 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-12-26 18:12:13 +0000 |
commit | a8f00fc5aa9b1ee96395df57d191c0bb87ed6372 (patch) | |
tree | a849696c050436debbcd382004a307464642c7c1 /sys/arch/alpha | |
parent | f8bc9fc741886cdb6606326d80da919ef2cee3af (diff) |
from netbsd:
machine-independent TurboChannel bus configuration. These files
deal with stuff like:
(1) configuring built-in devices,
(2) looking at TC slots configuring any devices found.
The lists of slots, slot locations, etc. and built-in devices
are provided by machine-dependent code. Interrupt handling
is also provided by machine-dependent code, but the MD code provides
hooks so that standard names for 'establish' and 'disestablish'
can be used in drivers.
This code requires <machine/tc_machdep.h>, which defines some
portability types specific to the TurboChannel bus code.
Diffstat (limited to 'sys/arch/alpha')
-rw-r--r-- | sys/arch/alpha/tc/asic.c | 291 | ||||
-rw-r--r-- | sys/arch/alpha/tc/asic.h | 235 | ||||
-rw-r--r-- | sys/arch/alpha/tc/esp.c | 1536 | ||||
-rw-r--r-- | sys/arch/alpha/tc/espreg.h | 129 | ||||
-rw-r--r-- | sys/arch/alpha/tc/espvar.h | 208 | ||||
-rw-r--r-- | sys/arch/alpha/tc/if_le.c | 249 | ||||
-rw-r--r-- | sys/arch/alpha/tc/if_levar.h | 96 | ||||
-rw-r--r-- | sys/arch/alpha/tc/ioasic.c | 376 | ||||
-rw-r--r-- | sys/arch/alpha/tc/ioasicreg.h | 226 | ||||
-rw-r--r-- | sys/arch/alpha/tc/scc.c | 47 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc.c | 272 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc.h | 116 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc_3000_300.c | 222 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc_3000_300.h | 15 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc_3000_500.c | 237 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc_3000_500.h | 21 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tc_conf.h | 60 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcasic.c | 141 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcds.c | 533 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcds_dma.c | 320 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcds_dmavar.h | 54 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcdsreg.h (renamed from sys/arch/alpha/tc/tcds.h) | 53 | ||||
-rw-r--r-- | sys/arch/alpha/tc/tcdsvar.h | 108 |
23 files changed, 2648 insertions, 2897 deletions
diff --git a/sys/arch/alpha/tc/asic.c b/sys/arch/alpha/tc/asic.c deleted file mode 100644 index f571c4732fa..00000000000 --- a/sys/arch/alpha/tc/asic.c +++ /dev/null @@ -1,291 +0,0 @@ -/* $NetBSD: asic.c,v 1.5 1995/08/03 00:52:00 cgd Exp $ */ - -/* - * Copyright (c) 1994, 1995 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 <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/device.h> - -#include <machine/autoconf.h> -#include <machine/pte.h> -#include <machine/rpb.h> - -#include <alpha/tc/tc.h> -#include <alpha/tc/asic.h> - -struct asic_softc { - struct device sc_dv; - struct abus sc_bus; - caddr_t sc_base; -}; - -/* Definition of the driver for autoconfig. */ -int asicmatch __P((struct device *, void *, void *)); -void asicattach __P((struct device *, struct device *, void *)); -int asicprint(void *, char *); -struct cfdriver asiccd = - { NULL, "asic", asicmatch, asicattach, DV_DULL, sizeof(struct asic_softc) }; - -void asic_intr_establish __P((struct confargs *, int (*)(void *), void *)); -void asic_intr_disestablish __P((struct confargs *)); -caddr_t asic_cvtaddr __P((struct confargs *)); -int asic_matchname __P((struct confargs *, char *)); - -int asic_intr __P((void *)); -int asic_intrnull __P((void *)); - -struct asic_slot { - struct confargs as_ca; - u_int64_t as_bits; - intr_handler_t as_handler; - void *as_val; -} asic_slots[ASIC_MAX_NSLOTS] = { - { { "lance", /* XXX */ 0, 0x000c0000, }, - ASIC_INTR_LANCE, asic_intrnull, (void *)(long)ASIC_SLOT_LANCE, }, - { { "scc", /* XXX */ 1, 0x00100000, }, - ASIC_INTR_SCC_0, asic_intrnull, (void *)(long)ASIC_SLOT_SCC0, }, - { { "scc", /* XXX */ 2, 0x00180000, }, - ASIC_INTR_SCC_1, asic_intrnull, (void *)(long)ASIC_SLOT_SCC1, }, - { { "dallas_rtc", /* XXX */ 3, 0x00200000, }, - 0, asic_intrnull, (void *)(long)ASIC_SLOT_RTC, }, - { { "AMD79c30", /* XXX */ 4, 0x00240000, }, - 0 /* XXX */, asic_intrnull, (void *)(long)ASIC_SLOT_ISDN, }, -}; - -caddr_t asic_base; /* XXX XXX XXX */ - -int -asicmatch(parent, cfdata, aux) - struct device *parent; - void *cfdata; - void *aux; -{ - struct cfdata *cf = cfdata; - struct confargs *ca = aux; - - /* It can only occur on the turbochannel, anyway. */ - if (ca->ca_bus->ab_type != BUS_TC) - return (0); - - /* Make sure that we're looking for this type of device. */ - if (!BUS_MATCHNAME(ca, "IOCTL ")) - return (0); - - /* See if the unit number is valid. */ - switch (hwrpb->rpb_type) { -#if defined(DEC_3000_500) || defined(DEC_3000_300) - case ST_DEC_3000_500: - case ST_DEC_3000_300: - if (cf->cf_unit > 0) - return (0); - break; -#endif - default: - return (0); - } - - return (1); -} - -void -asicattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - struct asic_softc *sc = (struct asic_softc *)self; - struct confargs *ca = aux; - struct confargs *nca; - int i; - extern int cputype; - - sc->sc_base = BUS_CVTADDR(ca); - asic_base = sc->sc_base; /* XXX XXX XXX */ - - sc->sc_bus.ab_dv = (struct device *)sc; - sc->sc_bus.ab_type = BUS_ASIC; - sc->sc_bus.ab_intr_establish = asic_intr_establish; - sc->sc_bus.ab_intr_disestablish = asic_intr_disestablish; - sc->sc_bus.ab_cvtaddr = asic_cvtaddr; - sc->sc_bus.ab_matchname = asic_matchname; - - BUS_INTR_ESTABLISH(ca, asic_intr, sc); - -#ifdef DEC_3000_300 - if (cputype == ST_DEC_3000_300) { - *(volatile u_int *)ASIC_REG_CSR(sc->sc_base) |= - ASIC_CSR_FASTMODE; - wbflush(); - printf(": slow mode\n"); - } else -#endif - printf(": fast mode\n"); - - /* Try to configure each CPU-internal device */ - for (i = 0; i < ASIC_MAX_NSLOTS; i++) { - nca = &asic_slots[i].as_ca; - nca->ca_bus = &sc->sc_bus; - - /* Tell the autoconfig machinery we've found the hardware. */ - config_found(self, nca, asicprint); - } -} - -int -asicprint(aux, pnp) - void *aux; - char *pnp; -{ - struct confargs *ca = aux; - - if (pnp) - printf("%s at %s", ca->ca_name, pnp); - printf(" offset 0x%lx", ca->ca_offset); - return (UNCONF); -} - -void -asic_intr_establish(ca, handler, val) - struct confargs *ca; - int (*handler) __P((void *)); - void *val; -{ - -#ifdef DIAGNOSTIC - if (ca->ca_slot == ASIC_SLOT_RTC) - panic("setting clock interrupt incorrectly"); -#endif - - /* XXX SHOULD NOT BE THIS LITERAL */ - if (asic_slots[ca->ca_slot].as_handler != asic_intrnull) - panic("asic_intr_establish: slot %d twice", ca->ca_slot); - - asic_slots[ca->ca_slot].as_handler = handler; - asic_slots[ca->ca_slot].as_val = val; -} - -void -asic_intr_disestablish(ca) - struct confargs *ca; -{ - - if (ca->ca_slot == ASIC_SLOT_RTC) - panic("asic_intr_disestablish: can'd do clock interrupt"); - - /* XXX SHOULD NOT BE THIS LITERAL */ - if (asic_slots[ca->ca_slot].as_handler == asic_intrnull) - panic("asic_intr_disestablish: slot %d missing intr", - ca->ca_slot); - - asic_slots[ca->ca_slot].as_handler = asic_intrnull; - asic_slots[ca->ca_slot].as_val = (void *)(long)ca->ca_slot; -} - -caddr_t -asic_cvtaddr(ca) - struct confargs *ca; -{ - - return - (((struct asic_softc *)ca->ca_bus->ab_dv)->sc_base + ca->ca_offset); -} - -int -asic_matchname(ca, name) - struct confargs *ca; - char *name; -{ - - return (strcmp(name, ca->ca_name) == 0); -} - -/* - * asic_intr -- - * ASIC interrupt handler. - */ -int -asic_intr(val) - void *val; -{ - register struct asic_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 *)ASIC_REG_INTR(sc->sc_base); - - gifound = 0; - do { - ifound = 0; - wbflush(); - MAGIC_READ; - wbflush(); - - sir = *sirp; - for (i = 0; i < ASIC_MAX_NSLOTS; i++) - if (sir & asic_slots[i].as_bits) { - (void)(*asic_slots[i].as_handler) - (asic_slots[i].as_val); - ifound = 1; - } - gifound |= ifound; - } while (ifound); - - return (gifound); -} - -int -asic_intrnull(val) - void *val; -{ - - panic("uncaught IOCTL ASIC intr for slot %ld\n", (long)val); -} - -#ifdef DEC_3000_500 -/* - * flamingo_set_leds -- - * Set the LEDs on the 400/500/600/800's. - */ -void -flamingo_set_leds(value) - u_int value; -{ - register struct asic_softc *sc = asiccd.cd_devs[0]; - - /* - * The 500's use the 7th bit of the SSR for FEPROM - * selection. - */ - *(volatile u_int *)ASIC_REG_CSR(sc->sc_base) &= ~0x7f; - *(volatile u_int *)ASIC_REG_CSR(sc->sc_base) |= value & 0x7f; - wbflush(); - DELAY(10000); -} -#endif diff --git a/sys/arch/alpha/tc/asic.h b/sys/arch/alpha/tc/asic.h deleted file mode 100644 index 6cd54c95c2a..00000000000 --- a/sys/arch/alpha/tc/asic.h +++ /dev/null @@ -1,235 +0,0 @@ -/* $NetBSD: asic.h,v 1.2 1995/03/28 18:14:22 jtc 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 ASIC_SLOT_0_START 0x000000 -#define ASIC_SLOT_1_START 0x040000 -#define ASIC_SLOT_2_START 0x080000 -#define ASIC_SLOT_3_START 0x0c0000 -#define ASIC_SLOT_4_START 0x100000 -#define ASIC_SLOT_5_START 0x140000 -#define ASIC_SLOT_6_START 0x180000 -#define ASIC_SLOT_7_START 0x1c0000 -#define ASIC_SLOT_8_START 0x200000 -#define ASIC_SLOT_9_START 0x240000 -#define ASIC_SLOT_10_START 0x280000 -#define ASIC_SLOT_11_START 0x2c0000 -#define ASIC_SLOT_12_START 0x300000 -#define ASIC_SLOT_13_START 0x340000 -#define ASIC_SLOT_14_START 0x380000 -#define ASIC_SLOT_15_START 0x3c0000 -#define ASIC_SLOTS_END 0x3fffff - -/* - * Register offsets (slot 1) - */ - -#define ASIC_SCSI_DMAPTR ASIC_SLOT_1_START+0x000 -#define ASIC_SCSI_NEXTPTR ASIC_SLOT_1_START+0x010 -#define ASIC_LANCE_DMAPTR ASIC_SLOT_1_START+0x020 -#define ASIC_SCC_T1_DMAPTR ASIC_SLOT_1_START+0x030 -#define ASIC_SCC_R1_DMAPTR ASIC_SLOT_1_START+0x040 -#define ASIC_SCC_T2_DMAPTR ASIC_SLOT_1_START+0x050 -#define ASIC_SCC_R2_DMAPTR ASIC_SLOT_1_START+0x060 -#define ASIC_FLOPPY_DMAPTR ASIC_SLOT_1_START+0x070 -#define ASIC_ISDN_X_DMAPTR ASIC_SLOT_1_START+0x080 -#define ASIC_ISDN_X_NEXTPTR ASIC_SLOT_1_START+0x090 -#define ASIC_ISDN_R_DMAPTR ASIC_SLOT_1_START+0x0a0 -#define ASIC_ISDN_R_NEXTPTR ASIC_SLOT_1_START+0x0b0 -#define ASIC_BUFF0 ASIC_SLOT_1_START+0x0c0 -#define ASIC_BUFF1 ASIC_SLOT_1_START+0x0d0 -#define ASIC_BUFF2 ASIC_SLOT_1_START+0x0e0 -#define ASIC_BUFF3 ASIC_SLOT_1_START+0x0f0 -#define ASIC_CSR ASIC_SLOT_1_START+0x100 -#define ASIC_INTR ASIC_SLOT_1_START+0x110 -#define ASIC_IMSK ASIC_SLOT_1_START+0x120 -#define ASIC_CURADDR ASIC_SLOT_1_START+0x130 -#define ASIC_ISDN_X_DATA ASIC_SLOT_1_START+0x140 -#define ASIC_ISDN_R_DATA ASIC_SLOT_1_START+0x150 -#define ASIC_LANCE_DECODE ASIC_SLOT_1_START+0x160 -#define ASIC_SCSI_DECODE ASIC_SLOT_1_START+0x170 -#define ASIC_SCC0_DECODE ASIC_SLOT_1_START+0x180 -#define ASIC_SCC1_DECODE ASIC_SLOT_1_START+0x190 -#define ASIC_FLOPPY_DECODE ASIC_SLOT_1_START+0x1a0 -#define ASIC_SCSI_SCR ASIC_SLOT_1_START+0x1b0 -#define ASIC_SCSI_SDR0 ASIC_SLOT_1_START+0x1c0 -#define ASIC_SCSI_SDR1 ASIC_SLOT_1_START+0x1d0 - -/* System Status and control Register (SSR). */ -#define ASIC_CSR_DMAEN_T1 0x80000000 /* rw */ -#define ASIC_CSR_DMAEN_R1 0x40000000 /* rw */ -#define ASIC_CSR_DMAEN_T2 0x20000000 /* rw */ -#define ASIC_CSR_DMAEN_R2 0x10000000 /* rw */ -#define ASIC_CSR_FASTMODE 0x08000000 /* rw */ -#define ASIC_CSR_xxx 0x07800000 /* unused/reserved */ -#define ASIC_CSR_FLOPPY_DIR 0x00400000 /* rw */ -#define ASIC_CSR_DMAEN_FLOPPY 0x00200000 /* rw */ -#define ASIC_CSR_DMAEN_ISDN_T 0x00100000 /* rw */ -#define ASIC_CSR_DMAEN_ISDN_R 0x00080000 /* rw */ -#define ASIC_CSR_SCSI_DIR 0x00040000 /* rw */ -#define ASIC_CSR_DMAEN_SCSI 0x00020000 /* rw */ -#define ASIC_CSR_DMAEN_LANCE 0x00010000 /* rw */ -/* low 16 bits are rw gp outputs */ - -/* System Interrupt Register (and Interrupt Mask Register). */ -#define ASIC_INTR_T1_PAGE_END 0x80000000 /* rz */ -#define ASIC_INTR_T1_READ_E 0x40000000 /* rz */ -#define ASIC_INTR_R1_HALF_PAGE 0x20000000 /* rz */ -#define ASIC_INTR_R1_DMA_OVRUN 0x10000000 /* rz */ -#define ASIC_INTR_T2_PAGE_END 0x08000000 /* rz */ -#define ASIC_INTR_T2_READ_E 0x04000000 /* rz */ -#define ASIC_INTR_R2_HALF_PAGE 0x02000000 /* rz */ -#define ASIC_INTR_R2_DMA_OVRUN 0x01000000 /* rz */ -#define ASIC_INTR_FLOPPY_DMA_E 0x00800000 /* rz */ -#define ASIC_INTR_ISDN_PTR_LOAD 0x00400000 /* rz */ -#define ASIC_INTR_ISDN_OVRUN 0x00200000 /* rz */ -#define ASIC_INTR_ISDN_READ_E 0x00100000 /* rz */ -#define ASIC_INTR_SCSI_PTR_LOAD 0x00080000 /* rz */ -#define ASIC_INTR_SCSI_OVRUN 0x00040000 /* rz */ -#define ASIC_INTR_SCSI_READ_E 0x00020000 /* rz */ -#define ASIC_INTR_LANCE_READ_E 0x00010000 /* rz */ -#define ASIC_INTR_ISDN 0x00002000 /* ro */ -#define ASIC_INTR_SEC_CON 0x00000200 /* ro */ -#define ASIC_INTR_LANCE 0x00000100 /* ro */ -#define ASIC_INTR_SCC_1 0x00000080 /* ro */ -#define ASIC_INTR_SCC_0 0x00000040 /* ro */ -#define ASIC_INTR_ALT_CON 0x00000008 /* ro */ - -/* DMA pointer registers (SCSI, Comm, ...) */ - -#define ASIC_DMAPTR_MASK 0xffffffe0 -#define ASIC_DMAPTR_SHIFT 5 -# define ASIC_DMAPTR_SET(reg,val) \ - (reg) = (((val)<<ASIC_DMAPTR_SHIFT)&ASIC_DMAPTR_MASK) -# define ASIC_DMAPTR_GET(reg,val) \ - (val) = (((reg)&ASIC_DMAPTR_MASK)>>ASIC_DMAPTR_SHIFT) -#define ASIC_DMA_ADDR(p) (((unsigned)p) << (5-2)) - -/* For the LANCE DMA pointer register initialization the above suffices */ - -/* More SCSI DMA registers */ - -#define ASIC_SCR_STATUS 0x00000004 -#define ASIC_SCR_WORD 0x00000003 - -/* Various Decode registers */ - -#define ASIC_DECODE_HW_ADDRESS 0x000003f0 -#define ASIC_DECODE_CHIP_SELECT 0x0000000f - -/* - * Asic register addresses at offset from base. - */ -#define ASIC_REG_SCSI_DMAPTR(base) ((base) + ASIC_SCSI_DMAPTR) -#define ASIC_REG_SCSI_DMANPTR(base) ((base) + ASIC_SCSI_NEXTPTR) -#define ASIC_REG_LANCE_DMAPTR(base) ((base) + ASIC_LANCE_DMAPTR) -#define ASIC_REG_SCC_T1_DMAPTR(base) ((base) + ASIC_SCC_T1_DMAPTR) -#define ASIC_REG_SCC_R1_DMAPTR(base) ((base) + ASIC_SCC_R1_DMAPTR) -#define ASIC_REG_SCC_T2_DMAPTR(base) ((base) + ASIC_SCC_T2_DMAPTR) -#define ASIC_REG_SCC_R2_DMAPTR(base) ((base) + ASIC_SCC_R2_DMAPTR) -#define ASIC_REG_FLOPPY_DMAPTR(base) ((base) + ASIC_FLOPPY_DMAPTR) -#define ASIC_REG_ISDN_X_DMAPTR(base) ((base) + ASIC_ISDN_X_DMAPTR) -#define ASIC_REG_ISDN_X_NEXTPTR(base) ((base) + ASIC_ISDN_X_NEXTPTR) -#define ASIC_REG_ISDN_R_DMAPTR(base) ((base) + ASIC_ISDN_R_DMAPTR) -#define ASIC_REG_ISDN_R_NEXTPTR(base) ((base) + ASIC_ISDN_R_NEXTPTR) -#define ASIC_REG_BUFF0(base) ((base) + ASIC_BUFF0) -#define ASIC_REG_BUFF1(base) ((base) + ASIC_BUFF1) -#define ASIC_REG_BUFF2(base) ((base) + ASIC_BUFF2) -#define ASIC_REG_BUFF3(base) ((base) + ASIC_BUFF3) -#define ASIC_REG_CSR(base) ((base) + ASIC_CSR) -#define ASIC_REG_INTR(base) ((base) + ASIC_INTR) -#define ASIC_REG_IMSK(base) ((base) + ASIC_IMSK) -#define ASIC_REG_CURADDR(base) ((base) + ASIC_CURADDR) -#define ASIC_REG_ISDN_X_DATA(base) ((base) + ASIC_ISDN_X_DATA) -#define ASIC_REG_ISDN_R_DATA(base) ((base) + ASIC_ISDN_R_DATA) -#define ASIC_REG_LANCE_DECODE(base) ((base) + ASIC_LANCE_DECODE) -#define ASIC_REG_SCSI_DECODE(base) ((base) + ASIC_SCSI_DECODE) -#define ASIC_REG_SCC0_DECODE(base) ((base) + ASIC_SCC0_DECODE) -#define ASIC_REG_SCC1_DECODE(base) ((base) + ASIC_SCC1_DECODE) -#define ASIC_REG_FLOPPY_DECODE(base) ((base) + ASIC_FLOPPY_DECODE) -#define ASIC_REG_SCSI_SCR(base) ((base) + ASIC_SCSI_SCR) -#define ASIC_REG_SCSI_SDR0(base) ((base) + ASIC_SCSI_SDR0) -#define ASIC_REG_SCSI_SDR1(base) ((base) + ASIC_SCSI_SDR1) - -/* - * And slot assignments. - */ -#define ASIC_SYS_ETHER_ADDRESS(base) ((base) + ASIC_SLOT_2_START) -#define ASIC_SYS_LANCE(base) ((base) + ASIC_SLOT_3_START) - -#ifdef _KERNEL -#define ASIC_SLOT_LANCE 0 /* ASIC slots for interrupt lookup. */ -#define ASIC_SLOT_SCC0 1 -#define ASIC_SLOT_SCC1 2 -#define ASIC_SLOT_RTC 3 -#define ASIC_SLOT_ISDN 4 -#define ASIC_MAX_NSLOTS 5 /* clock + 2 scc + lance + isdn */ - -caddr_t asic_base; -#endif diff --git a/sys/arch/alpha/tc/esp.c b/sys/arch/alpha/tc/esp.c index f2518cf558c..a7ec01b33ae 100644 --- a/sys/arch/alpha/tc/esp.c +++ b/sys/arch/alpha/tc/esp.c @@ -1,7 +1,8 @@ -/* $NetBSD: esp.c,v 1.5 1995/08/03 00:52:06 cgd Exp $ */ +/* $NetBSD: esp.c,v 1.6 1995/12/20 00:40:21 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 @@ -53,37 +54,43 @@ #include <scsi/scsi_all.h> #include <scsi/scsiconf.h> +#include <scsi/scsi_message.h> #include <machine/cpu.h> +#ifdef SPARC_DRIVER #include <machine/autoconf.h> - -#include <alpha/tc/tcds_dmavar.h> +#include <sparc/dev/sbusvar.h> +#include <sparc/dev/dmareg.h> +#include <sparc/dev/dmavar.h> +#include <sparc/dev/espreg.h> +#include <sparc/dev/espvar.h> +#else +#include <dev/tc/tcvar.h> +#include <alpha/tc/tcdsvar.h> #include <alpha/tc/espreg.h> #include <alpha/tc/espvar.h> -#include <alpha/tc/tc.h> -#include <alpha/tc/tcds.h> - -int esp_debug = ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS; /**/ - -void espattach __P((struct device *, struct device *, void *)); -int espmatch __P((struct device *, void *, void *)); -int espprint __P((void *, char *)); -void espreadregs __P((struct esp_softc *)); -u_char espgetbyte __P((struct esp_softc *)); -void espselect __P((struct esp_softc *, u_char, u_char, - caddr_t, u_char)); -void esp_scsi_reset __P((struct esp_softc *)); -void esp_reset __P((struct esp_softc *)); -void esp_init __P((struct esp_softc *)); -int esp_scsi_cmd __P((struct scsi_xfer *)); -int esp_poll __P((struct esp_softc *, struct ecb *)); -int espphase __P((struct esp_softc *)); -void esp_sched __P((struct esp_softc *)); -void esp_done __P((struct ecb *)); -void esp_msgin __P((struct esp_softc *)); -void esp_msgout __P((struct esp_softc *)); -int espintr __P((void *)); -void esp_timeout __P((void *arg)); +#endif + +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*/ 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 *)); /* Linkup to the rest of the kernel */ struct cfdriver espcd = { @@ -93,7 +100,7 @@ struct cfdriver espcd = { struct scsi_adapter esp_switch = { esp_scsi_cmd, - minphys, /* no max transfer size; DMA engine deals */ + minphys, /* no max at this level; handled by DMA code */ NULL, NULL, }; @@ -105,132 +112,14 @@ struct scsi_device esp_dev = { NULL, /* Use default 'done' routine */ }; -/* - * Does anyone actually use this, and what for ? - */ int espprint(aux, name) void *aux; char *name; { - return -1; -} - -#define CXXX(esp) (RR((esp)->esp_stat) & ESPSTAT_INT) - -/* - * 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. So I have - * coded this to not do anything if there is no interrupt or error - * pending. - */ -void -espreadregs(sc) - struct esp_softc *sc; -{ - int s; - volatile espreg_t *esp = sc->sc_reg; - - /* They mean nothing if there is no pending interrupt??? */ - if (!(DMA_ISINTR(sc))) - return; - - s = splhigh(); - - /* Only the stepo bits are of interest. */ - sc->sc_espstep = RR(esp->esp_step) & ESPSTEP_MASK; wbflush(); - sc->sc_espstat = RR(esp->esp_stat); wbflush(); - sc->sc_espintr = RR(esp->esp_intr); wbflush(); - - /* Clear the TCDS interrupt bit. */ - (void)tcds_scsi_isintr(sc->sc_dev.dv_unit, 1); - - splx(s); - - ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", sc->sc_espintr, - sc->sc_espstat, sc->sc_espstep)); -} - -/* - * no error checking ouch - */ -u_char -espgetbyte(sc) - struct esp_softc *sc; -{ - volatile espreg_t *esp = sc->sc_reg; - u_int esp_fflag, esp_fifo; - - ESP_TRACE(("esp_getbyte ")); - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (!(esp_fflag & ESPFIFO_FF)) { -xxx: - ESPCMD(sc, ESPCMD_TRANS); - while (!DMA_ISINTR_CLR(sc)) - DELAY(1); - /* - * If we read something, then clear the outstanding - * interrupts - */ - espreadregs(sc); - } - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (!(esp_fflag & ESPFIFO_FF)) { - printf("error...\n"); - goto xxx; - } - esp_fifo = RR(esp->esp_fifo); wbflush(); - return esp_fifo; -} - -/* - * 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; - caddr_t cmd; - u_char clen; -{ - volatile espreg_t *esp = sc->sc_reg; - int i; - - ESP_TRACE(("esp_select ")); - - /* - * The docs say the target register is never reset, and I - * can't think of a better place to set it - */ - esp->esp_id = target; wbflush(); - esp->esp_syncoff = sc->sc_tinfo[target].offset; wbflush(); - esp->esp_synctp = 250 / sc->sc_tinfo[target].period; wbflush(); - - /* - * Who am I. This is where we tell the target that we are - * happy for it to disconnect etc. - */ - esp->esp_fifo = ESP_MSG_IDENTIFY(lun); wbflush(); - - /* Now the command into the FIFO */ - for (i = 0; i < clen; i++) { - esp->esp_fifo = (u_int)*cmd++; - wbflush(); - } - - /* And get the targets attention */ - ESPCMD(sc, ESPCMD_SELATN); - - /* new state ESP_SELECTING */ - sc->sc_state = ESP_SELECTING; + if (name != NULL) + printf("scsibus at %s", name); + return UNCONF; } int @@ -239,23 +128,23 @@ espmatch(parent, vcf, aux) void *vcf, *aux; { struct cfdata *cf = vcf; - struct confargs *ca = aux; - void *addr; +#ifdef SPARC_DRIVER + register struct confargs *ca = aux; + register struct romaux *ra = &ca->ca_ra; - if (!BUS_MATCHNAME(ca, "esp")) + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - -#define ESP0_OFFSET 0x100000 /* SPARSE!! offset. */ -#define ESP1_OFFSET 0x100200 /* SPARSE!! offset. */ - addr = BUS_CVTADDR(ca); -#ifdef SPARSE - addr = TC_DENSE_TO_SPARSE(addr); + if (ca->ca_bustype == BUS_SBUS) + return (1); + ra->ra_len = NBPG; + return (probeget(ra->ra_vaddr, 1) != -1); #else - AXP requires sparse addressing for the 53CF94. + struct tcdsdev_attach_args *tcdsdev = aux; + + if (strncmp(tcdsdev->tcdsda_modname, "PMAZ-AA ", TC_ROM_LLEN)) + return (0); + return (!tc_badaddr(tcdsdev->tcdsda_addr)); #endif - addr = (u_int8_t *)addr + - (ca->ca_slot == 0 ? ESP0_OFFSET : ESP1_OFFSET); - return (!badaddr(addr, 4)); } /* @@ -266,11 +155,16 @@ espattach(parent, self, aux) struct device *parent, *self; void *aux; { +#ifdef SPARC_DRIVER register struct confargs *ca = aux; +#else + register struct tcdsdev_attach_args *tcdsdev = aux; +#endif struct esp_softc *sc = (void *)self; +#ifdef SPARC_DRIVER struct bootpath *bp; - void *addr; - u_int esp_cfg2, esp_cfg3; + int dmachild = strncmp(parent->dv_xname, "espdma", 6) == 0; +#endif #ifdef SPARC_DRIVER /* @@ -290,22 +184,19 @@ espattach(parent, self, aux) * address space. */ if (ca->ca_ra.ra_vaddr) - sc->sc_reg = (volatile caddr_t) ca->ca_ra.ra_vaddr; + sc->sc_reg = (volatile u_char *) ca->ca_ra.ra_vaddr; else { - sc->sc_reg = (volatile caddr_t) - mapiodev(ca->ca_ra.ra_paddr, ca->ca_ra.ra_len, ca->ca_bustype); + sc->sc_reg = (volatile u_char *) + mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len, ca->ca_bustype); } #else - addr = BUS_CVTADDR(ca); -#ifdef SPARSE - addr = TC_DENSE_TO_SPARSE(addr); -#else - AXP requires sparse addressing for the 53CF94. -#endif - sc->sc_reg = (espreg_t *)((u_int8_t *)addr + - (ca->ca_slot == 0 ? ESP0_OFFSET : ESP1_OFFSET)); + sc->sc_reg = (volatile u_int32_t *)tcdsdev->tcdsda_tc.tcda_addr; + sc->sc_cookie = tcdsdev->tcdsda_tc.tcda_cookie; + sc->sc_dma = tcdsdev->tcdsda_sc; + printf(": address %x", sc->sc_reg); - BUS_INTR_ESTABLISH(ca, espintr, (void *)sc); + tcds_intr_establish(parent, sc->sc_cookie, TC_IPL_BIO, + (int (*)(void *))espintr, sc); #endif #ifdef SPARC_DRIVER @@ -322,125 +213,156 @@ espattach(parent, self, aux) sc->sc_freq = ((struct sbus_softc *) sc->sc_dev.dv_parent)->sc_clockfreq; #else - /* - * XXX - * Bus ID on AXP should be 6? - */ - sc->sc_id = 7; - sc->sc_freq = 25000000; + if (parent->dv_cfdata->cf_driver == &tcdscd) { + sc->sc_id = tcdsdev->tcdsda_id; + sc->sc_freq = tcdsdev->tcdsda_freq; + } else { + /* XXX */ + sc->sc_id = 7; + sc->sc_freq = 24000000; + } #endif /* gimme Mhz */ sc->sc_freq /= 1000000; - /* - * This is the value used to start sync negotiations - * For a 25Mhz clock, this gives us 40, or 160nS, or - * 6.25Mb/s. It is constant for each adapter. - * - * In turn, notice that the ESP register "SYNCTP" is - * = (250 / the negotiated period). It works, try it - * on paper. - */ - sc->sc_minsync = 1000 / sc->sc_freq; - - /* 0 is actually 8, even though the register only has 3 bits */ - sc->sc_ccf = FREQTOCCF(sc->sc_freq) & 0x07; - - /* 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) - * - * We have the CCF from above, so the sum is simple, and generally - * gives us a constant of 153. Try working out a few and see. - */ - sc->sc_timeout = ESP_DEF_TIMEOUT; - #ifdef SPARC_DRIVER - /* - * find the DMA by poking around the dma device structures - * - * What happens here is that if the dma driver has not been - * configured, then this returns a NULL pointer. Then when the - * dma actually gets configured, it does the opposing test, and - * if the sc->sc_esp field in it's softc is NULL, then tries to - * find the matching esp driver. - * - */ - sc->sc_dma = ((struct dma_softc *)getdevunit("dma", - sc->sc_dev.dv_unit)); + if (dmachild) { + sc->sc_dma = (struct dma_softc *)parent; + sc->sc_dma->sc_esp = sc; + } else { + /* + * find the DMA by poking around the dma device structures + * + * What happens here is that if the dma driver has not been + * configured, then this returns a NULL pointer. Then when the + * dma actually gets configured, it does the opposing test, and + * if the sc->sc_esp field in it's softc is NULL, then tries to + * find the matching esp driver. + * + */ + sc->sc_dma = (struct dma_softc *) + getdevunit("dma", sc->sc_dev.dv_unit); + + /* + * and a back pointer to us, for DMA + */ + if (sc->sc_dma) + sc->sc_dma->sc_esp = sc; + } #else - sc->sc_dma = &sc->__dma; - sc->sc_dma->sc_dev = sc->sc_dev; /* XXX */ - dma_init(sc->sc_dma); + sc->sc_dma->sc_esp = sc; /* XXX */ #endif /* - * and a back pointer to us, for DMA - */ - if (sc->sc_dma) - sc->sc_dma->sc_esp = sc; - - /* * 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; #ifdef SPARC_DRIVER - sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RSVD; + sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE; sc->sc_cfg3 = ESPCFG3_CDB; - sc->sc_reg->esp_cfg2 = sc->sc_cfg2; wbflush(); + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); - esp_cfg2 = RR(sc->sc_reg->esp_cfg2); wbflush(); - if ((esp_cfg2 & ~ESPCFG2_RSVD) != - (ESPCFG2_SCSI2 | ESPCFG2_RPE)) { + if ((ESP_READ_REG(sc, ESP_CFG2) & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) { printf(": ESP100"); sc->sc_rev = ESP100; } else { - sc->sc_cfg2 = 0; - sc->sc_reg->esp_cfg2 = sc->sc_cfg2; wbflush(); + sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_FE; + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); sc->sc_cfg3 = 0; - sc->sc_reg->esp_cfg3 = sc->sc_cfg3; wbflush(); - sc->sc_cfg3 = 5; - sc->sc_reg->esp_cfg3 = sc->sc_cfg3; wbflush(); - esp_cfg3 = RR(sc->sc_reg->esp_cfg3); wbflush(); - if (esp_cfg3 != 5) { + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); + sc->sc_cfg3 = (ESPCFG3_CDB | ESPCFG3_FCLK); + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); + if (ESP_READ_REG(sc, ESP_CFG3) != (ESPCFG3_CDB | ESPCFG3_FCLK)) { printf(": ESP100A"); sc->sc_rev = ESP100A; } else { sc->sc_cfg3 = 0; - sc->sc_reg->esp_cfg3 = sc->sc_cfg3; wbflush(); + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); printf(": ESP200"); sc->sc_rev = ESP200; } } #else sc->sc_cfg2 = ESPCFG2_SCSI2; - sc->sc_cfg3 = 0x4; /* Save residual byte. */ + sc->sc_cfg3 = 0x4; /* Save residual byte. XXX??? */ printf(": NCR53C94"); sc->sc_rev = NCR53C94; #endif + /* + * 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; + +#ifdef SPARC_DRIVER + /* + * Alas, we must now modify the value a bit, because it's + * only valid when can switch on FASTCLK and FASTSCSI bits + * in config register 3... + */ + switch (sc->sc_rev) { + case ESP100: + sc->sc_minsync = 0; /* No synch on old chip? */ + break; + case ESP100A: + sc->sc_minsync = esp_cpb2stp(sc, 5); /* Min clocks/byte is 5 */ + break; + case ESP200: + /* XXX - do actually set FAST* bits */ + } +#endif + + 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); + esp_init(sc, 1); printf(" %dMhz, target %d\n", sc->sc_freq, sc->sc_id); #ifdef SPARC_DRIVER /* add me to the sbus structures */ sc->sc_sd.sd_reset = (void *) esp_reset; - if (ca->ca_bustype == BUS_SBUS) - sbus_establish(&sc->sc_sd, &sc->sc_dev); +#if defined(SUN4C) || defined(SUN4M) + if (ca->ca_bustype == BUS_SBUS) { + if (dmachild) + sbus_establish(&sc->sc_sd, sc->sc_dev.dv_parent); + else + sbus_establish(&sc->sc_sd, &sc->sc_dev); + } +#endif /* SUN4C || SUN4M */ +#endif +#ifdef SPARC_DRIVER /* and the interuppts */ sc->sc_ih.ih_fun = (void *) espintr; sc->sc_ih.ih_arg = sc; @@ -468,11 +390,12 @@ espattach(parent, self, aux) case BUS_SBUS: if (bp != NULL && strcmp(bp->name, "esp") == 0 && SAME_ESP(sc, bp, ca)) - sc->sc_bp = bp + 1; + bootpath_store(1, bp + 1); break; default: - if (bp != NULL && strcmp(bp->name, "esp") == 0) - sc->sc_bp = bp + 1; + if (bp != NULL && strcmp(bp->name, "esp") == 0 && + bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit) + bootpath_store(1, bp + 1); break; } #endif @@ -481,6 +404,10 @@ espattach(parent, self, aux) * Now try to attach all the sub-devices */ config_found(self, &sc->sc_link, espprint); + +#ifdef SPARC_DRIVER + bootpath_store(1, NULL); +#endif } /* @@ -495,42 +422,37 @@ void esp_reset(sc) struct esp_softc *sc; { - volatile espreg_t *esp = sc->sc_reg; /* reset DMA first */ DMA_RESET(sc->sc_dma); - ESPCMD(sc, ESPCMD_RSTCHIP); /* reset chip */ - ESPCMD(sc, ESPCMD_NOP); /* requires following NOP. */ + /* reset SCSI chip */ + ESPCMD(sc, ESPCMD_RSTCHIP); + ESPCMD(sc, ESPCMD_NOP); DELAY(500); - /* ESP: do these backwards, and fall through */ + /* do these backwards, and fall through */ switch (sc->sc_rev) { +#ifndef SPARC_DRIVER case NCR53C94: - esp->esp_cfg1 = sc->sc_cfg1; wbflush(); - esp->esp_cfg2 = sc->sc_cfg2; wbflush(); - esp->esp_cfg3 = sc->sc_cfg3; wbflush(); - esp->esp_ccf = sc->sc_ccf; wbflush(); - esp->esp_syncoff = 0; wbflush(); - esp->esp_timeout = sc->sc_timeout; wbflush(); - break; +#endif case ESP200: - esp->esp_cfg3 = sc->sc_cfg3; wbflush(); + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); case ESP100A: - esp->esp_cfg2 = sc->sc_cfg2; wbflush(); + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); case ESP100: - esp->esp_cfg1 = sc->sc_cfg1; wbflush(); - esp->esp_ccf = sc->sc_ccf; wbflush(); - esp->esp_syncoff = 0; wbflush(); - esp->esp_timeout = sc->sc_timeout; wbflush(); + 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->esp_cfg1 = sc->sc_cfg1; wbflush(); - esp->esp_ccf = sc->sc_ccf; wbflush(); - esp->esp_syncoff = 0; wbflush(); - esp->esp_timeout = sc->sc_timeout; wbflush(); + 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); } } @@ -541,66 +463,202 @@ void esp_scsi_reset(sc) struct esp_softc *sc; { +#ifdef SPARC_DRIVER + /* stop DMA first, as the chip will return to Bus Free phase */ + DMACSR(sc->sc_dma) &= ~D_EN_DMA; +#else + /* + * XXX STOP DMA FIRST + */ +#endif + printf("esp: resetting SCSI bus\n"); ESPCMD(sc, ESPCMD_RSTSCSI); - DELAY(50); } /* * Initialize esp state machine */ void -esp_init(sc) +esp_init(sc, doreset) struct esp_softc *sc; + int doreset; { struct ecb *ecb; int r; - - /* - * reset the chip to a known state - */ - esp_reset(sc); + + 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 = 0; + 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++; } - /* XXX: NetBSD error. */ bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo)); } else { + sc->sc_flags |= ESP_ABORTING; sc->sc_state = ESP_IDLE; if (sc->sc_nexus != NULL) { - sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, sc->sc_nexus); + sc->sc_nexus->xs->error = XS_TIMEOUT; esp_done(sc->sc_nexus); } sc->sc_nexus = NULL; - while (ecb = sc->nexus_list.tqh_first) { - ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); + 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]; - tp->flags = DO_NEGOTIATE | NEED_TO_RESET; + + tp->flags = (sc->sc_minsync ? T_NEGOTIATE : 0) | + T_NEED_TO_RESET | (tp->flags & T_XXX); tp->period = sc->sc_minsync; - tp->offset = ESP_SYNC_REQ_ACK_OFS; + 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); +#ifndef SPARC_DRIVER + /* Clear the TCDS interrupt bit. */ + (void)tcds_scsi_isintr(sc->sc_dma, 1); +#endif + + /* + * 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. + */ +esp_stp2cpb(sc, period) + struct esp_softc *sc; +{ + 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. + */ +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; + + /* + * 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, 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 */ @@ -618,7 +676,7 @@ esp_scsi_cmd(xs) struct ecb *ecb; int s, flags; - ESP_TRACE(("\nesp_scsi_cmd ")); + ESP_TRACE(("[esp_scsi_cmd] ")); ESP_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen, sc_link->target)); @@ -629,17 +687,16 @@ esp_scsi_cmd(xs) 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) { - xs->error = XS_DRIVER_STUFFUP; ESP_MISC(("TRY_AGAIN_LATER")); return TRY_AGAIN_LATER; } /* Initialize ecb */ - ecb->flags = ECB_ACTIVE; ecb->xs = xs; bcopy(xs->cmd, &ecb->cmd, xs->cmdlen); ecb->clen = xs->cmdlen; @@ -649,6 +706,7 @@ esp_scsi_cmd(xs) s = splbio(); TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain); + ECB_SETQ(ecb, ECB_QREADY); timeout(esp_timeout, ecb, (xs->timeout*hz)/1000); if (sc->sc_state == ESP_IDLE) @@ -675,17 +733,24 @@ esp_poll(sc, ecb) struct ecb *ecb; { struct scsi_xfer *xs = ecb->xs; - int count = xs->timeout * 10; - - ESP_TRACE(("esp_poll ")); + int count = xs->timeout * 100; + ESP_TRACE(("[esp_poll] ")); while (count) { - if (DMA_ISINTR(sc)) { + 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(5); + DELAY(10); + if (sc->sc_state == ESP_IDLE) { + ESP_TRACE(("[esp_poll: rescheduling] ")); + esp_sched(sc); + } count--; } @@ -697,36 +762,10 @@ esp_poll(sc, ecb) return COMPLETE; } -/* - * LOW LEVEL SCSI UTILITIES - */ /* - * Determine the SCSI bus phase, return either a real SCSI bus phase - * or some pseudo phase we use to detect certain exceptions. - * - * Notice that we do not read the live register on an ESP100. On the - * ESP100A and above the FE (Feature Enable) bit in config 2 latches - * the phase in the register so it is safe to read. + * LOW LEVEL SCSI UTILITIES */ -int -espphase(sc) - struct esp_softc *sc; -{ - u_int esp_stat; - - ESP_TRACE(("espphase ")); - if (sc->sc_espintr & ESPINTR_DIS) /* Disconnected */ - return BUSFREE_PHASE; - - if (sc->sc_rev != ESP100) { - esp_stat = RR(sc->sc_reg->esp_stat); wbflush(); - return (esp_stat & ESPSTAT_PHASE); - } - - return (sc->sc_espstat & ESPSTAT_PHASE); -} - /* * Schedule a scsi operation. This has now been pulled out of the interrupt @@ -742,29 +781,39 @@ esp_sched(sc) struct ecb *ecb; int t; - ESP_TRACE(("esp_sched ")); + 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) { - caddr_t cmd = (caddr_t) &ecb->cmd; 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[ecb->xs->sc_link->target]; + 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_link = ecb->xs->sc_link; - espselect(sc, t, sc_link->lun, cmd, ecb->clen); - ti = &sc->sc_tinfo[sc_link->target]; sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; ti->lubusy |= (1<<sc_link->lun); +/*XXX*/if (sc->sc_msgpriq) { + printf("esp: message queue not empty: %x!\n", sc->sc_msgpriq); +} +/*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0; + espselect(sc, t, sc_link->lun, + (u_char *)&ecb->cmd, ecb->clen); break; } else ESP_MISC(("%d:%d busy\n", t, sc_link->lun)); @@ -781,8 +830,11 @@ esp_done(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)); - ESP_TRACE(("esp_done ")); + untimeout(esp_timeout, ecb); /* * Now, if we've come here with no error code, i.e. we've kept the @@ -792,8 +844,12 @@ esp_done(ecb) * 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 && !(ecb->flags & ECB_CHKSENSE)) { - if ((ecb->stat & ST_MASK)==SCSI_CHECK) { + 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 */ @@ -802,38 +858,39 @@ esp_done(ecb) /* Next, setup a request sense command block */ bzero(ss, sizeof(*ss)); ss->opcode = REQUEST_SENSE; - ss->byte2 = sc_link->lun << 5; + /*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_ACTIVE|ECB_CHKSENSE; + ecb->flags |= ECB_CHKSENSE; +/*XXX - must take off queue here */ TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); - sc->sc_tinfo[sc_link->target].lubusy &= - ~(1<<sc_link->lun); - sc->sc_tinfo[sc_link->target].senses++; - /* found it */ + ECB_SETQ(ecb, ECB_QREADY); + ti->lubusy &= ~(1<<sc_link->lun); + ti->senses++; + timeout(esp_timeout, ecb, (xs->timeout*hz)/1000); if (sc->sc_nexus == ecb) { sc->sc_nexus = NULL; sc->sc_state = ESP_IDLE; esp_sched(sc); } return; + } else { + xs->resid = ecb->dleft; } } - - if (xs->error == XS_NOERROR && (ecb->flags & ECB_CHKSENSE)) { - xs->error = XS_SENSE; - } else { - xs->resid = ecb->dleft; - } + xs->flags |= ITSDONE; -#if ESP_DEBUG > 1 +#ifdef ESP_DEBUG if (esp_debug & ESP_SHOWMISC) { printf("err=0x%02x ",xs->error); - if (xs->error == XS_SENSE) - printf("sense=%2x\n", xs->sense.error_code); + if (xs->error == XS_SENSE) { + printf("sense=%2x; ", xs->sense.error_code); + if (xs->sense.error_code == 0x70) + printf("extcode: %x; ", xs->sense.extended_flags); + } } if ((xs->resid || xs->error > XS_SENSE) && esp_debug & ESP_SHOWMISC) { if (xs->resid) @@ -844,43 +901,34 @@ esp_done(ecb) #endif /* - * Remove the ECB from whatever queue it's on. We have to do a bit of - * a hack to figure out which queue it's on. Note that it is *not* - * necessary to cdr down the ready queue, but we must cdr down the - * nexus queue and see if it's there, so we can mark the unit as no - * longer busy. This code is sickening, but it works. + * Remove the ECB from whatever queue it's on. */ - if (ecb == sc->sc_nexus) { + switch (ecb->flags & ECB_QBITS) { + case ECB_QNONE: + if (ecb != sc->sc_nexus) { + panic("%s: floating ecb", sc->sc_dev.dv_xname); + } sc->sc_state = ESP_IDLE; - sc->sc_tinfo[sc_link->target].lubusy &= ~(1<<sc_link->lun); + ti->lubusy &= ~(1<<sc_link->lun); esp_sched(sc); - } else if (sc->ready_list.tqh_last == &ecb->chain.tqe_next) { + break; + case ECB_QREADY: TAILQ_REMOVE(&sc->ready_list, ecb, chain); - } else { - register struct ecb *ecb2; - for (ecb2 = sc->nexus_list.tqh_first; ecb2; - ecb2 = ecb2->chain.tqe_next) - if (ecb2 == ecb) { - TAILQ_REMOVE(&sc->nexus_list, ecb, chain); - sc->sc_tinfo[sc_link->target].lubusy - &= ~(1<<sc_link->lun); - break; - } - if (ecb2) - ; - else if (ecb->chain.tqe_next) { - TAILQ_REMOVE(&sc->ready_list, ecb, chain); - } else { - printf("%s: can't find matching ecb\n", - sc->sc_dev.dv_xname); - Debugger(); - } + break; + case ECB_QNEXUS: + TAILQ_REMOVE(&sc->nexus_list, ecb, chain); + ti->lubusy &= ~(1<<sc_link->lun); + break; + case ECB_QFREE: + panic("%s: busy ecb on free list", sc->sc_dev.dv_xname); + break; } - /* Put it on the free list. */ - ecb->flags = ECB_FREE; + + /* Put it on the free list, and clear flags. */ TAILQ_INSERT_HEAD(&sc->free_list, ecb, chain); + ecb->flags = ECB_QFREE; - sc->sc_tinfo[sc_link->target].cmds++; + ti->cmds++; scsi_done(xs); return; } @@ -915,14 +963,13 @@ void esp_msgin(sc) register struct esp_softc *sc; { - volatile espreg_t *esp = sc->sc_reg; - int extlen; + register int v; - ESP_TRACE(("esp_msgin ")); + ESP_TRACE(("[esp_msgin(curmsglen:%d)] ", sc->sc_imlen)); - /* is something wrong ? */ - if (sc->sc_phase != MESSAGE_IN_PHASE) { - printf("%s: not MESSAGE_IN_PHASE\n", sc->sc_dev.dv_xname); + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) == 0) { + printf("%s: msgin: no msg byte available\n", + sc->sc_dev.dv_xname); return; } @@ -937,56 +984,61 @@ esp_msgin(sc) sc->sc_imlen = 0; } + v = ESP_READ_REG(sc, ESP_FIFO); + ESP_MISC(("<msgbyte:0x%02x>", v)); + +#if 0 if (sc->sc_state == ESP_RESELECTED && sc->sc_imlen == 0) { /* * Which target is reselecting us? (The ID bit really) */ - sc->sc_selid = espgetbyte(sc) & ~(1<<sc->sc_id); + sc->sc_selid = v; + sc->sc_selid &= ~(1<<sc->sc_id); ESP_MISC(("selid=0x%2x ", sc->sc_selid)); + return; } +#endif - for (;;) { - /* - * If parity errors just dump everything on the floor - */ - if (sc->sc_espstat & ESPSTAT_PE) { - esp_sched_msgout(SEND_PARITY_ERROR); - sc->sc_flags |= ESP_DROP_MSGI; - } + 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 we're going to reject the message, don't bother storing + * the incoming bytes. But still, we need to ACK them. + */ + + if ((sc->sc_flags & ESP_DROP_MSGI)) { + ESPCMD(sc, ESPCMD_SETATN); + ESPCMD(sc, ESPCMD_MSGOK); + printf("<dropping msg byte %x>", + sc->sc_imess[sc->sc_imlen]); + return; + } + + if (sc->sc_imlen >= ESP_MAX_MSG_LEN) { + esp_sched_msgout(SEND_REJECT); + sc->sc_flags |= ESP_DROP_MSGI; + } else { + sc->sc_imlen++; + /* + * This testing is suboptimal, but most + * messages will be of the one byte variety, so + * it should not effect performance + * significantly. */ - if ((sc->sc_flags & ESP_DROP_MSGI) == 0) { - sc->sc_imess[sc->sc_imlen] = espgetbyte(sc); - ESP_MISC(("0x%02x ", sc->sc_imess[sc->sc_imlen])); - 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])) - break; - if (sc->sc_imlen == 2 && - IS2BYTEMSG(sc->sc_imess[0])) - break; - if (sc->sc_imlen >= 3 && - ISEXTMSG(sc->sc_imess[0]) && - sc->sc_imlen == sc->sc_imess[1] + 2) - break; - } - } + 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; - ESP_MISC(("gotmsg ")); +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 @@ -999,115 +1051,153 @@ esp_msgin(sc) switch (sc->sc_imess[0]) { case MSG_CMDCOMPLETE: - ESP_MISC(("cmdcomplete ")); - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - printf("%s: CMDCOMPLETE but no command?\n", - sc->sc_dev.dv_xname); - break; - } + 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); - ecb->dleft = 0; + -sc->sc_dleft, + sc_link->target, sc_link->lun); + sc->sc_dleft = 0; } - ESPCMD(sc, ESPCMD_MSGOK); ecb->xs->resid = ecb->dleft = sc->sc_dleft; sc->sc_flags |= ESP_BUSFREE_OK; - return; + break; case MSG_MESSAGE_REJECT: - if (esp_debug & ESP_SHOWMISC) + if (esp_debug & ESP_SHOWMSGS) printf("%s: our msg rejected by target\n", sc->sc_dev.dv_xname); +#if 0 /* XXX - must remember last message */ +printf("<<target%d: MSG_MESSAGE_REJECT>>", ecb->xs->sc_link->target); +ti->period = ti->offset = 0; +sc->sc_flags &= ~ESP_SYNCHNEGO; +ti->flags &= ~T_NEGOTIATE; +#endif if (sc->sc_flags & ESP_SYNCHNEGO) { ti->period = ti->offset = 0; sc->sc_flags &= ~ESP_SYNCHNEGO; - ti->flags &= ~DO_NEGOTIATE; + ti->flags &= ~T_NEGOTIATE; } /* Not all targets understand INITIATOR_DETECTED_ERR */ if (sc->sc_msgout == SEND_INIT_DET_ERR) esp_sched_msgout(SEND_ABORT); - ESPCMD(sc, ESPCMD_MSGOK); break; case MSG_NOOP: - ESPCMD(sc, ESPCMD_MSGOK); + ESP_MSGS(("noop ")); break; case MSG_DISCONNECT: - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - printf("%s: nothing to DISCONNECT\n", - sc->sc_dev.dv_xname); - break; - } - ESPCMD(sc, ESPCMD_MSGOK); + ESP_MSGS(("disconnect ")); ti->dconns++; - TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain); - ecb = sc->sc_nexus = NULL; - sc->sc_state = ESP_IDLE; + sc->sc_flags |= ESP_DISCON; sc->sc_flags |= ESP_BUSFREE_OK; break; case MSG_SAVEDATAPOINTER: - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - printf("%s: no DATAPOINTERs to save\n", - sc->sc_dev.dv_xname); - break; - } - ESPCMD(sc, ESPCMD_MSGOK); + 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; } - ESPCMD(sc, ESPCMD_MSGOK); sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; break; + case MSG_PARITY_ERROR: +printf("<<esp:target%d: MSG_PARITY_ERROR>>", 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])); + /*XXX*/if (ti->flags & T_XXX) { + printf("%s:%d: rejecting SDTR\n", + "esp", ecb->xs->sc_link->target); + sc->sc_flags &= ~ESP_SYNCHNEGO; + esp_sched_msgout(SEND_REJECT); + break; + } ti->period = sc->sc_imess[3]; ti->offset = sc->sc_imess[4]; - if (ti->offset == 0) { - printf("%s: async\n", TARGETNAME(ecb)); + 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: async\n", TARGETNAME(ecb)); + printf("%s:%d: async\n", "esp", + ecb->xs->sc_link->target); ti->offset = 0; esp_sched_msgout(SEND_SDTR); - } else { /* we are sync */ - printf("%s: sync rate %2fMb/s\n", - TARGETNAME(ecb), - sc->sc_freq/ti->period); + } 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); + if ((sc->sc_flags&ESP_SYNCHNEGO) == 0) { + /* Target initiated negotiation */ + sc->sc_flags |= ESP_SYNCHNEGO; + if (ti->flags & T_SYNCMODE) { + sc_print_addr(ecb->xs->sc_link); +#ifdef ESP_DEBUG + printf("%s:%d: dropping out of sync mode\n"); +#endif + } + ti->flags &= ~T_SYNCMODE; + ESP_WRITE_REG(sc, + ESP_SYNCOFF, 0); + 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; + sc_print_addr(ecb->xs->sc_link); +#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; } - ESPCMD(sc, ESPCMD_MSGOK); break; default: + ESP_MSGS(("ident ")); /* thanks for that ident... */ - if (!ESP_MSG_ISIDENT(sc->sc_imess[0])) { + 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); } - ESPCMD(sc, ESPCMD_MSGOK); break; } } else if (sc->sc_state == ESP_RESELECTED) { struct scsi_link *sc_link; struct ecb *ecb; + struct esp_tinfo *ti; u_char lunit; - if (ESP_MSG_ISIDENT(sc->sc_imess[0])) { /* Identify? */ + + if (MSG_ISIDENTIFY(sc->sc_imess[0])) { /* Identify? */ ESP_MISC(("searching ")); /* * Search wait queue for disconnected cmd @@ -1117,12 +1207,13 @@ esp_msgin(sc) */ lunit = sc->sc_imess[0] & 0x07; for (ecb = sc->nexus_list.tqh_first; ecb; - ecb = ecb->chain.tqe_next) { + ecb = ecb->chain.tqe_next) { sc_link = ecb->xs->sc_link; if (sc_link->lun == lunit && sc->sc_selid == (1<<sc_link->target)) { TAILQ_REMOVE(&sc->nexus_list, ecb, chain); + ECB_SETQ(ecb, ECB_QNONE); break; } } @@ -1136,17 +1227,15 @@ esp_msgin(sc) * Setup driver data structures and * do an implicit RESTORE POINTERS */ + ti = &sc->sc_tinfo[sc_link->target]; sc->sc_nexus = ecb; sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; sc->sc_tinfo[sc_link->target].lubusy |= (1<<sc_link->lun); - esp->esp_syncoff = - sc->sc_tinfo[sc_link->target].offset; - wbflush(); - esp->esp_synctp = - 250 / sc->sc_tinfo[sc_link->target].period; - wbflush(); + ESP_WRITE_REG(sc, ESP_SYNCOFF, ti->offset); + ESP_WRITE_REG(sc, ESP_SYNCTP, + esp_stp2cpb(sc, ti->period)); ESP_MISC(("... found ecb")); sc->sc_state = ESP_HASNEXUS; } @@ -1160,6 +1249,13 @@ esp_msgin(sc) 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; } @@ -1170,41 +1266,44 @@ void esp_msgout(sc) register struct esp_softc *sc; { - volatile espreg_t *esp = sc->sc_reg; struct esp_tinfo *ti; struct ecb *ecb; - ESP_TRACE(("esp_msgout ")); + 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: /* Also implies an IDENTIFY message */ + case SEND_SDTR: ecb = sc->sc_nexus; sc->sc_flags |= ESP_SYNCHNEGO; ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; - sc->sc_omess[1] = MSG_EXTENDED; - sc->sc_omess[2] = 3; - sc->sc_omess[3] = MSG_EXT_SDTR; - sc->sc_omess[4] = ti->period; - sc->sc_omess[5] = ti->offset; - sc->sc_omlen = 6; - /* Fallthrough! */ + 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__); - Debugger(); } ecb = sc->sc_nexus; - sc->sc_omess[0] = ESP_MSG_IDENTIFY(ecb->xs->sc_link->lun); + 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_ERR; + sc->sc_omess[0] = MSG_PARITY_ERROR; break; case SEND_ABORT: sc->sc_omess[0] = MSG_ABORT; @@ -1223,8 +1322,20 @@ esp_msgout(sc) sc->sc_omp = sc->sc_omess; } +#if 1 /* (re)send the message */ DMA_START(sc->sc_dma, &sc->sc_omp, &sc->sc_omlen, 0); +#else + { int i; + ESPCMD(sc, ESPCMD_FLUSH); + for (i = 0; i < sc->sc_omlen; i++) + ESP_WRITE_REG(sc, FIFO, sc->sc_omess[i]); + ESPCMD(sc, ESPCMD_TRANS); +#if test_stuck_on_msgout +printf("<<XXXmsgoutdoneXXX>>"); +#endif + } +#endif } /* @@ -1237,19 +1348,15 @@ esp_msgout(sc) * Most of this needs verifying. */ int -espintr(__sc) - void *__sc; +espintr(sc) + register struct esp_softc *sc; { - register struct esp_softc *sc = __sc; - register struct ecb *ecb = sc->sc_nexus; + register struct ecb *ecb; register struct scsi_link *sc_link; - volatile espreg_t *esp = sc->sc_reg; struct esp_tinfo *ti; - caddr_t cmd; - u_int esp_fflag; int loop; - ESP_TRACE(("espintr ")); + ESP_TRACE(("[espintr]")); /* * I have made some (maybe seriously flawed) assumptions here, @@ -1270,11 +1377,10 @@ espintr(__sc) * This is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1 * at 40Mhz. This needs testing. */ -#define FOREVER - for (loop = 0; FOREVER;loop++) { + for (loop = 0; ; loop++, DELAY(50/sc->sc_freq)) { /* a feeling of deja-vu */ - if (!DMA_ISINTR(sc) && loop) - return 1; + if (!DMA_ISINTR(sc->sc_dma)) + return (loop != 0); #if 0 if (loop) printf("*"); @@ -1282,30 +1388,12 @@ espintr(__sc) /* and what do the registers say... */ espreadregs(sc); -#ifndef SPARC_DRIVER - if (!(sc->sc_espstat & ESPSTAT_INT)) - return (0); -#endif - if (sc->sc_state == ESP_IDLE || - !(sc->sc_espstat & ESPSTAT_INT)) { - printf("%s: stray interrupt\n", sc->sc_dev.dv_xname); - return 0; - } sc->sc_intrcnt.ev_count++; /* - * What phase are we in when we *entered* the - * interrupt handler ? - * - * On laster ESP chips (ESP236 and up) the FE (features - * enable) bit in config 2 latches the phase bits - * at each "command completion". - */ - sc->sc_phase = espphase(sc); - /* * At the moment, only a SCSI Bus Reset or Illegal - * Command are classed as errors. A diconnect is a + * 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. @@ -1319,35 +1407,48 @@ espintr(__sc) * If there are too many parity error, go to slow * cable mode ? */ -#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL) - if (sc->sc_espintr & ESPINTR_ERR - || sc->sc_espstat & ESPSTAT_GE) { - /* SCSI Reset */ - if (sc->sc_espintr & ESPINTR_SBR) { - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (esp_fflag & ESPFIFO_FF) { - ESPCMD(sc, ESPCMD_FLUSH); - DELAY(1); - } + /* 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); /* Restart everything */ + sc->sc_dev.dv_xname); + esp_init(sc, 0); /* Restart everything */ return 1; } +#if 0 + /*XXX*/ printf("<expected bus reset: " + "[intr %x, stat %x, step %d]>\n", + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); +#endif + if (sc->sc_nexus) + panic("%s: nexus in reset state", + sc->sc_dev.dv_xname); + sc->sc_state = ESP_IDLE; + esp_sched(sc); + return 1; + } + + ecb = sc->sc_nexus; + +#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL) + if (sc->sc_espintr & ESPINTR_ERR || + sc->sc_espstat & ESPSTAT_GE) { if (sc->sc_espstat & ESPSTAT_GE) { /* no target ? */ - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (esp_fflag & ESPFIFO_FF) { + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { ESPCMD(sc, ESPCMD_FLUSH); DELAY(1); } - DELAY(1); - if (sc->sc_state == ESP_HASNEXUS) { + if (sc->sc_state == ESP_HASNEXUS || + sc->sc_state == ESP_SELECTING) { ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); - espreadregs(sc); esp_done(ecb); } return 1; @@ -1355,19 +1456,15 @@ espintr(__sc) if (sc->sc_espintr & ESPINTR_ILL) { /* illegal command, out of sync ? */ - printf("%s: illegal command\n", - sc->sc_dev.dv_xname); - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (esp_fflag & ESPFIFO_FF) { + 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); } - if (sc->sc_state == ESP_HASNEXUS) { - ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); - esp_done(ecb); - } - esp_reset(sc); /* so start again */ + esp_init(sc, 0); /* Restart everything */ return 1; } } @@ -1383,7 +1480,8 @@ espintr(__sc) /* If DMA active here, then go back to work... */ if (sc->sc_dma->sc_active) return 1; - DELAY(50/sc->sc_freq); + if (!(sc->sc_espstat & ESPSTAT_TC)) + printf("%s: !TC\n", sc->sc_dev.dv_xname); continue; } @@ -1391,7 +1489,8 @@ espintr(__sc) * check for less serious errors */ if (sc->sc_espstat & ESPSTAT_PE) { - printf("esp: SCSI bus parity error\n"); + 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 @@ -1399,9 +1498,8 @@ espintr(__sc) } if (sc->sc_espintr & ESPINTR_DIS) { - ESP_MISC(("disc ")); - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (esp_fflag & ESPFIFO_FF) { + ESP_MISC(("<DISC [intr %x, stat %x, step %d]>", sc->sc_espintr, sc->sc_espstat, sc->sc_espstep)); + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { ESPCMD(sc, ESPCMD_FLUSH); DELAY(1); } @@ -1411,13 +1509,29 @@ espintr(__sc) */ ESPCMD(sc, ESPCMD_ENSEL); if (sc->sc_state != ESP_IDLE) { + if ((sc->sc_flags & ESP_SYNCHNEGO)) { + printf("%s: sync nego not completed!\n", + sc->sc_dev.dv_xname); + } + /*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0; + /* it may be OK to disconnect */ if (!(sc->sc_flags & ESP_BUSFREE_OK)) ecb->xs->error = XS_TIMEOUT; - untimeout(esp_timeout, ecb); + 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; + esp_sched(sc); + return 1; + } + esp_done(ecb); return 1; } + printf("DISCONNECT in IDLE state!\n"); } /* did a message go out OK ? This must be broken */ @@ -1430,27 +1544,36 @@ espintr(__sc) 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); + sc->sc_dev.dv_xname); + esp_init(sc, 1); return 1; } +printf("<<RESELECT CONT'd>>"); +#if XXXX esp_msgin(sc); if (sc->sc_state != ESP_HASNEXUS) { /* IDENTIFY fail?! */ printf("%s: identify failed\n", - sc->sc_dev.dv_xname); - esp_init(sc); + 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) { @@ -1461,9 +1584,13 @@ espintr(__sc) */ 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); - sc->sc_nexus = NULL; + ECB_SETQ(sc->sc_nexus, ECB_QREADY); + ti->lubusy &= ~(1<<sc_link->lun); + ecb = sc->sc_nexus = NULL; } sc->sc_state = ESP_RESELECTED; if (sc->sc_phase != MESSAGE_IN_PHASE) { @@ -1472,19 +1599,25 @@ espintr(__sc) * Pull the brakes, i.e. reset */ printf("%s: target didn't identify\n", - sc->sc_dev.dv_xname); - esp_init(sc); + sc->sc_dev.dv_xname); + esp_init(sc, 1); return 1; } + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) { +printf("<RESELECT: %d bytes in FIFO>", ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF); + } + sc->sc_selid = ESP_READ_REG(sc, ESP_FIFO); + sc->sc_selid &= ~(1<<sc->sc_id); + ESP_MISC(("selid=0x%2x ", sc->sc_selid)); esp_msgin(sc); /* Handle identify message */ if (sc->sc_state != ESP_HASNEXUS) { /* IDENTIFY fail?! */ printf("%s: identify failed\n", - sc->sc_dev.dv_xname); - esp_init(sc); + sc->sc_dev.dv_xname); + esp_init(sc, 1); return 1; } - break; + continue; /* ie. next phase expected soon */ } #define ESPINTR_DONE (ESPINTR_FC|ESPINTR_BS) @@ -1492,47 +1625,148 @@ espintr(__sc) 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; + 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); + 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 & DO_NEGOTIATE) + 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_flags = 0; */ + sc->sc_prevphase = INVALID_PHASE; /* ?? */ sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; ti->lubusy |= (1<<sc_link->lun); break; - } else if (sc->sc_espintr & ESPINTR_FC) { - if (sc->sc_espstep != ESPSTEP_DONE) { - esp_fflag = RR(esp->esp_fflag); - wbflush(); - if (esp_fflag & ESPFIFO_FF) { - ESPCMD(sc, ESPCMD_FLUSH); - DELAY(1); - } - } + } 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); } - /* We aren't done yet, but expect to be soon */ - DELAY(50/sc->sc_freq); - continue; + if (sc->sc_state == ESP_IDLE) { + printf("%s: stray interrupt\n", sc->sc_dev.dv_xname); + return 0; + } + break; case ESP_HASNEXUS: + if (sc->sc_flags & ESP_ICCS) { + unsigned char msg; + + sc->sc_flags &= ~ESP_ICCS; + + if (!(sc->sc_espintr & ESPINTR_DONE)) { + printf("%s: ICCS: " + ": [intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + } + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) { + printf("%s: ICCS: expected 2, got %d " + ": [intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + ESPCMD(sc, ESPCMD_FLUSH); + esp_abort(sc, ecb); + return 1; + } + ecb->stat = ESP_READ_REG(sc, ESP_FIFO); + msg = ESP_READ_REG(sc, ESP_FIFO); + ESP_PHASE(("<stat:(%x,%x)>", ecb->stat, msg)); + if (msg == MSG_CMDCOMPLETE) { + sc->sc_flags |= ESP_BUSFREE_OK; + ecb->xs->resid = ecb->dleft = sc->sc_dleft; + } else + printf("%s: STATUS_PHASE: msg %d\n", + sc->sc_dev.dv_xname, msg); + ESPCMD(sc, ESPCMD_MSGOK); + continue; /* ie. wait for disconnect */ + } break; default: - panic("esp unknown state"); + 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. */ - cmd = (caddr_t) &ecb->cmd; if (sc->sc_state != ESP_HASNEXUS || ecb == NULL) { panic("esp no nexus"); } @@ -1545,39 +1779,80 @@ espintr(__sc) break; case MESSAGE_IN_PHASE: ESP_PHASE(("MESSAGE_IN_PHASE ")); - esp_msgin(sc); + 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: + 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)); - esp_fflag = RR(esp->esp_fflag); wbflush(); - if (esp_fflag & ESPFIFO_FF) { + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { ESPCMD(sc, ESPCMD_FLUSH); DELAY(1); } - espselect(sc, ecb->xs->sc_link->target, - ecb->xs->sc_link->lun, (caddr_t)&ecb->cmd, - ecb->clen); + /* 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); DMA_START(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 0); sc->sc_prevphase = DATA_OUT_PHASE; - break; + return 1; case DATA_IN_PHASE: ESP_PHASE(("DATA_IN_PHASE ")); + if (sc->sc_rev == ESP100) + ESPCMD(sc, ESPCMD_FLUSH); +#if 0 /* Why is the fifo sometimes full after re-connect? */ + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + static int xxx; + if (xxx <= 3) { + printf("%s: lost %d bytes from FIFO ", + sc->sc_dev.dv_xname, + ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF); + printf(" previous phase %x\n", + sc->sc_prevphase); + if (xxx == 3) + printf("(stopped logging)"); + ++xxx; + } + } +#endif DMA_DRAIN(sc->sc_dma); DMA_START(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 1); sc->sc_prevphase = DATA_IN_PHASE; - break; + return 1; case STATUS_PHASE: ESP_PHASE(("STATUS_PHASE ")); + sc->sc_flags |= ESP_ICCS; ESPCMD(sc, ESPCMD_ICCS); - ecb->stat = espgetbyte(sc); - ESP_PHASE(("0x%02x ", ecb->stat)); sc->sc_prevphase = STATUS_PHASE; break; case INVALID_PHASE: @@ -1591,7 +1866,24 @@ espintr(__sc) default: panic("esp: bogus bus phase\n"); } - DELAY(50/sc->sc_freq); + } + panic("esp: should not get here.."); +} + +void +esp_abort(sc, ecb) + struct esp_softc *sc; + struct ecb *ecb; +{ + if (ecb == sc->sc_nexus) { +/*XXX*/sc->sc_tinfo[ecb->xs->sc_link->target].flags |= T_XXX; + 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); } } @@ -1602,15 +1894,55 @@ esp_timeout(arg) int s = splbio(); struct ecb *ecb = (struct ecb *)arg; struct esp_softc *sc; + struct scsi_xfer *xs = ecb->xs; - ESP_TRACE(("esp_timeout ")); - - sc = ecb->xs->sc_link->adapter_softc; - sc_print_addr(ecb->xs->sc_link); - ecb->xs->error = XS_TIMEOUT; - printf("timed out\n"); + sc = xs->sc_link->adapter_softc; + sc_print_addr(xs->sc_link); +again: + printf("timed out (ecb 0x%x (flags 0x%x, dleft %x), state %d, phase %d, msgpriq %x, msgout %x)", + ecb, ecb->flags, ecb->dleft, sc->sc_state, sc->sc_phase, + sc->sc_msgpriq, sc->sc_msgout); - esp_done(ecb); - esp_reset(sc); + if (ecb->flags == ECB_QFREE) { + printf("note: ecb already on free list\n"); + splx(s); + return; + } + if (ecb->flags & ECB_ABORTED) { + /* abort timed out */ + printf(" AGAIN\n"); + xs->retries = 0; + esp_init(sc, 1); + } else { + /* abort the operation that has timed out */ + printf("\n"); + xs->error = XS_TIMEOUT; + ecb->flags |= ECB_ABORTED; +#if 0 +if (sc->sc_dma->sc_active) { + int x = esp_debug; esp_debug=0x3ff; + DMA_INTR(sc->sc_dma); + esp_debug = x; +} +#endif + esp_abort(sc, ecb); + /* 2 secs for the abort */ + if ((xs->flags & SCSI_POLL) == 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); } diff --git a/sys/arch/alpha/tc/espreg.h b/sys/arch/alpha/tc/espreg.h index 4f5100d339d..4b2bf02cd70 100644 --- a/sys/arch/alpha/tc/espreg.h +++ b/sys/arch/alpha/tc/espreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: espreg.h,v 1.1 1995/02/13 23:08:57 cgd Exp $ */ +/* $NetBSD: espreg.h,v 1.2 1995/12/20 00:40:25 cgd Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. @@ -29,77 +29,18 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if 1 -#define SPARSE -#endif - -#ifdef SPARSE -#define PAD(p) u_int32_t p; -#else -#define PAD(p) -#endif - -typedef struct { - volatile u_int esp_tcl; /* RW - Transfer Count Low */ - PAD(pad0) - volatile u_int esp_tcm; /* RW - Transfer Count Mid */ - PAD(pad1) - volatile u_int esp_fifo; /* RW - FIFO data */ - PAD(pad2) - volatile u_int esp_cmd; /* RW - Command */ - PAD(pad3) - volatile u_int esp_stat; /* RO - Status */ -#define esp_id esp_stat /* WO - Destination ID */ -#define esp_selid esp_stat /* WO - Select/Reselect Bus ID */ - PAD(pad4) - volatile u_int esp_intr; /* RO - Interrupt */ -#define esp_timeout esp_intr /* WO - Select/Reselect Timeout */ - PAD(pad5) - volatile u_int esp_step; /* RO - Sequence Step */ -#define esp_synctp esp_step /* WO - Synch Transfer Period */ - PAD(pad6) - volatile u_int esp_fflag; /* RO - FIFO Flags */ -#define esp_syncoff esp_fflag /* WO - Synch Offset */ - PAD(pad7) - volatile u_int esp_cfg1; /* RW - Configuration #1 */ - PAD(pad8) - volatile u_int esp_ccf; /* WO - Clock Conversion Factor */ - PAD(pad9) - volatile u_int esp_test; /* WO - Test (Chip Test Only) */ - PAD(pad10) - volatile u_int esp_cfg2; /* RW - Configuration #2 */ - PAD(pad11) - volatile u_int esp_cfg3; /* RW - Configuration #3 */ - PAD(pad12) - volatile u_int esp_cfg4; /* RW - Configuration #4 */ - PAD(pad13) - volatile u_int esp_tch; /* RW - Transfer Count High */ - PAD(pad14) - volatile u_int esp_fbottom; /* WO - Fifo Bottom */ -} espreg_t; - -/* - * Only bits <7:0> of the addressed longword are valid; other bits are - * unpredictable during read, ignored during write. - */ -#define RR(reg) ((reg) & 0xff) - /* * Register addresses, relative to some base address */ -#define ESP_TCL 0x00 /* RW - Transfer Count Low */ -#define ESP_TCM 0x04 /* RW - Transfer Count Mid */ -#define ESP_TCH 0x38 /* RW - Transfer Count High */ +#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 0x08 /* RW - FIFO data */ +#define ESP_FIFO 0x02 /* RW - FIFO data */ -#define ESP_FFLAG 0x1c /* RO - FIFO Flags */ -#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */ -#define ESPFIFO_FF 0x1f /* Bytes in FIFO */ - -#define ESP_CMD 0x0c /* RW - Command (2 deep) */ +#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 */ @@ -132,7 +73,7 @@ typedef struct { #define ESPCMD_SETATN 0x1a /* Set ATN */ #define ESPCMD_RSTATN 0x1b /* Reset ATN */ -#define ESP_STAT 0x10 /* RO - Status */ +#define ESP_STAT 0x04 /* RO - Status */ #define ESPSTAT_INT 0x80 /* Interrupt */ #define ESPSTAT_GE 0x40 /* Gross Error */ #define ESPSTAT_PE 0x20 /* Parity Error */ @@ -140,9 +81,9 @@ typedef struct { #define ESPSTAT_VGC 0x08 /* Valid Group Code */ #define ESPSTAT_PHASE 0x07 /* Phase bits */ -#define ESP_ID 0x10 /* WO - Destination ID */ +#define ESP_SELID 0x04 /* WO - Select/Reselect Bus ID */ -#define ESP_INTR 0x14 /* RO - Interrupt */ +#define ESP_INTR 0x05 /* RO - Interrupt */ #define ESPINTR_SBR 0x80 /* SCSI Bus Reset */ #define ESPINTR_ILL 0x40 /* Illegal Command */ #define ESPINTR_DIS 0x20 /* Disconnect */ @@ -152,21 +93,24 @@ typedef struct { #define ESPINTR_SELATN 0x02 /* Select with ATN */ #define ESPINTR_SEL 0x01 /* Selected */ -#define ESP_SELID 0x10 /* WO - Select/Reselect Bus ID */ -#define ESP_TIMEOUT 0x14 /* WO - Select/Reselect Timeout */ +#define ESP_TIMEOUT 0x05 /* WO - Select/Reselect Timeout */ -#define ESP_STEP 0x18 /* RO - Sequence Step */ +#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 0x18 /* WO - Synch Transfer Period */ +#define ESP_SYNCTP 0x06 /* WO - Synch Transfer Period */ /* Default 5 (53C9X) */ -#define ESP_SYNCOFF 0x1c /* WO - Synch Offset */ + +#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 0x20 /* RW - Configuration #1 */ +#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 */ @@ -174,9 +118,23 @@ typedef struct { #define ESPCFG1_CTEST 0x08 /* Enable Chip Test */ #define ESPCFG1_BUSID 0x07 /* Bus ID */ -#define ESP_CFG2 0x2c /* RW - Configuration #2 */ -#define ESPCFG2_RSVD 0xe0 /* reserved */ +#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 */ +#if 0 +#define ESPCFG2_RSVD 0xa0 /* reserved */ #define ESPCFG2_FE 0x40 /* Features Enable */ +#endif #define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */ #define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */ #define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */ @@ -184,21 +142,12 @@ typedef struct { #define ESPCFG2_DPE 0x01 /* DMA Parity Error */ /* Config #3 only on 53C9X */ -#define ESP_CFG3 0x30 /* RW - Configuration #3 */ +#define ESP_CFG3 0x0c /* RW - Configuration #3 */ +#if 0 +#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) */ - -#define ESP_CCF 0x24 /* 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 0x28 /* WO - Test (Chip Test Only) */ +#endif diff --git a/sys/arch/alpha/tc/espvar.h b/sys/arch/alpha/tc/espvar.h index b1ef9b9c894..e3073a027dc 100644 --- a/sys/arch/alpha/tc/espvar.h +++ b/sys/arch/alpha/tc/espvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: espvar.h,v 1.2 1995/08/03 00:52:10 cgd Exp $ */ +/* $NetBSD: espvar.h,v 1.3 1995/12/20 00:40:26 cgd Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. @@ -29,12 +29,9 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define ESP_SYNC_REQ_ACK_OFS 0 - #define ESP_DEBUG 0 #define FREQTOCCF(freq) (((freq + 4) / 5)) -#define ESP_DEF_TIMEOUT 153 /* esp revisions */ #define ESP100 0x01 @@ -42,25 +39,6 @@ #define ESP200 0x03 #define NCR53C94 0x04 -/* Grabbed from Julians SCSI aha-drivers */ -#ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here (esp.c)") -#endif DDB - -typedef caddr_t physaddr; - -struct esp_dma_seg { - physaddr addr; - long len; -}; - -extern int delaycount; -#define FUDGE(X) ((X)>>1) /* get 1 ms spincount */ -#define MINIFUDGE(X) ((X)>>4) /* get (approx) 125us spincount */ -#define NUM_CONCURRENT 7 /* Only one per target for now */ - /* * ECB. Holds additional information for each SCSI command Comments: We * need a separate scsi command block because we may need to overwrite it @@ -73,15 +51,19 @@ struct ecb { TAILQ_ENTRY(ecb) chain; struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ int flags; /* Status */ -#define ECB_FREE 0x00 -#define ECB_ACTIVE 0x01 -#define ECB_DONE 0x04 +#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 */ - int stat; /* SCSI status byte */ + u_char stat; /* SCSI status byte */ }; /* @@ -97,9 +79,12 @@ struct esp_tinfo { int senses; /* #request sense commands sent */ ushort lubusy; /* What local units/subr. are busy? */ u_char flags; -#define NEED_TO_RESET 0x01 /* Should send a BUS_DEV_RESET */ -#define DO_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */ -#define TARGET_BUSY 0x04 /* Target is busy, i.e. cmd in progress */ +#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_XXX 0x10 /* Target is XXX */ +#define T_SYNCHNEGO 0x20 /* .. */ u_char period; /* Period suggestion */ u_char offset; /* Offset suggestion */ } tinfo_t; @@ -107,22 +92,28 @@ struct esp_tinfo { /* 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 - -#if 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_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) @@ -131,6 +122,8 @@ struct esp_tinfo { #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 @@ -144,12 +137,13 @@ struct esp_softc { struct evcnt sc_intrcnt; /* intr count */ struct scsi_link sc_link; /* scsi lint struct */ #ifdef SPARC_DRIVER - volatile caddr_t sc_reg; /* the registers */ + volatile u_char *sc_reg; /* the registers */ + struct dma_softc *sc_dma; /* pointer to my dma */ #else - espreg_t *sc_reg; /* the registers */ - struct dma_softc __dma; /* DMA info lives here. */ + 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 - struct dma_softc *sc_dma; /* pointer to my dma */ /* register defaults */ u_char sc_cfg1; /* Config 1 */ @@ -164,11 +158,6 @@ struct esp_softc { u_char sc_espstep; u_char sc_espfflags; -#ifdef SPARC_DRIVER - /* the current boot path component */ - struct bootpath *sc_bp; -#endif - /* Lists of command blocks */ TAILQ_HEAD(ecb_list, ecb) free_list, ready_list, @@ -180,7 +169,7 @@ struct esp_softc { /* Data about the current nexus (updated for every cmd switch) */ caddr_t sc_dp; /* Current data pointer */ - size_t sc_dleft; /* Data left to transfer */ + ssize_t sc_dleft; /* Data left to transfer */ /* Adapter state */ int sc_phase; /* Copy of what bus phase we are in */ @@ -188,14 +177,15 @@ struct esp_softc { u_char sc_state; /* State applicable to the adapter */ u_char sc_flags; u_char sc_selid; + u_char sc_lastcmd; /* Message stuff */ - char sc_msgpriq; /* One or more messages to send (encoded) */ - char sc_msgout; /* What message is on its way out? */ - char sc_omess[ESP_MAX_MSG_LEN]; + 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; - char sc_imess[ESP_MAX_MSG_LEN + 1]; + u_char sc_imess[ESP_MAX_MSG_LEN + 1]; caddr_t sc_imp; /* Message pointer (for multibyte messages) */ size_t sc_imlen; @@ -217,13 +207,18 @@ struct esp_softc { #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_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 @@ -234,42 +229,6 @@ struct esp_softc { #define SEND_IDENTIFY 0x20 #define SEND_SDTR 0x40 -/* - * Generic SCSI messages. For now we reject most of them. - */ -/* Messages (1 byte) */ /* I/T M(andatory) or (O)ptional */ -#define MSG_CMDCOMPLETE 0x00 /* M/M */ -#define MSG_EXTENDED 0x01 /* O/O */ -#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ -#define MSG_RESTOREPOINTERS 0x03 /* O/O */ -#define MSG_DISCONNECT 0x04 /* O/O */ -#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ -#define MSG_ABORT 0x06 /* O/M */ -#define MSG_MESSAGE_REJECT 0x07 /* M/M */ -#define MSG_NOOP 0x08 /* M/M */ -#define MSG_PARITY_ERR 0x09 /* M/M */ -#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ -#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ -#define MSG_BUS_DEV_RESET 0x0c /* O/M */ -#define MSG_ABORT_TAG 0x0d /* O/O */ -#define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ - -/* Messages (2 byte) */ -#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ -#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ -#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ -#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ - -/* Identify message */ -#define ESP_MSG_IDENTIFY(lun) (0x80|(lun & 0x7)) /* XXX 0xc0=selection on */ -#define ESP_MSG_ISIDENT(m) ((m) & 0x80) - -/* Extended messages (opcode) */ -#define MSG_EXT_SDTR 0x01 - /* SCSI Status codes */ #define ST_GOOD 0x00 #define ST_CHKCOND 0x02 @@ -303,41 +262,60 @@ struct esp_softc { #define INVALID_PHASE 0x101 /* Re/Selection valid, but no REQ yet */ #define PSEUDO_PHASE 0x100 /* "pseudo" bit */ -#if ESP_DEBUG > 1 -#define ESPCMD(sc, cmd) \ - printf("cmd:0x%02x ", sc->sc_reg->esp_cmd = cmd); wbflush(); +#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; + wbflush(); + 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; \ + wbflush(); \ + } while (0) + +#ifdef ESP_DEBUG +#define ESPCMD(sc, cmd) do { \ + if (esp_debug & ESP_SHOWCCMDS) \ + printf("<cmd:0x%x>", (unsigned)cmd); \ + sc->sc_lastcmd = cmd; \ + ESP_WRITE_REG(sc, ESP_CMD, cmd); \ +} while (0) #else -#define ESPCMD(sc, cmd) sc->sc_reg->esp_cmd = cmd; wbflush(); +#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)) -#define TARGETNAME(ecb) \ - ((struct device *)ecb->xs->sc_link->adapter_softc)->dv_xname - /* DMA macros for ESP */ -#define DMA_ENINTR(r) ((r->enintr)(r)) #ifdef SPARC_DRIVER +#define DMA_ENINTR(r) ((r->enintr)(r)) #define DMA_ISINTR(r) ((r->isintr)(r)) -#else -#define DMA_ISINTR(r) \ - ((RR(r->sc_reg->esp_stat) & ESPSTAT_INT) || \ - tcds_scsi_isintr(r->sc_dma->sc_dev.dv_unit, 0)) -#define DMA_ISINTR_CLR(r) \ - ((RR(r->sc_reg->esp_stat) & ESPSTAT_INT) || \ - tcds_scsi_isintr(r->sc_dma->sc_dev.dv_unit, 1)) -#endif #define DMA_RESET(r) ((r->reset)(r)) #define DMA_START(a, b, c, d) ((a->start)(a, b, c, d)) #define DMA_INTR(r) ((r->intr)(r)) - -#ifdef SPARC_DRIVER #define DMA_DRAIN(sc) if (sc->sc_rev < DMAREV_2) { \ DMACSR(sc) |= D_DRAIN; \ DMAWAIT1(sc); \ } #else +#define DMA_ENINTR(r) tcds_dma_enintr(r) +#define DMA_ISINTR(r) tcds_dma_isintr(r) +#define DMA_RESET(r) tcds_dma_reset(r) +#define DMA_START(a, b, c, d) tcds_dma_start(a, b, c, d) +#define DMA_INTR(r) tcds_dma_intr(r) #define DMA_DRAIN(sc) #endif diff --git a/sys/arch/alpha/tc/if_le.c b/sys/arch/alpha/tc/if_le.c deleted file mode 100644 index d7c47ff0514..00000000000 --- a/sys/arch/alpha/tc/if_le.c +++ /dev/null @@ -1,249 +0,0 @@ -/* $NetBSD: if_le.c,v 1.9 1995/11/25 01:31:09 cgd 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_le.c 8.2 (Berkeley) 11/16/93 - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/syslog.h> -#include <sys/socket.h> -#include <sys/device.h> - -#include <net/if.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/if_ether.h> -#endif - -#include <machine/autoconf.h> -#include <machine/rpb.h> - -#include <alpha/tc/tc.h> -#include <alpha/tc/asic.h> -#include <alpha/tc/if_levar.h> -#include <dev/ic/am7990reg.h> -#define LE_NEED_BUF_CONTIG -#define LE_NEED_BUF_GAP2 -#define LE_NEED_BUF_GAP16 -#include <dev/ic/am7990var.h> - -/* access LANCE registers */ -void lewritereg(); -#define LERDWR(cntl, src, dst) { (dst) = (src); wbflush(); } -#define LEWREG(src, dst) lewritereg(&(dst), (src)) - -#define LE_OFFSET_RAM 0x0 -#define LE_OFFSET_LANCE 0x100000 -#define LE_OFFSET_ROM 0x1c0000 - -extern caddr_t le_iomem; - -#define LE_SOFTC(unit) lecd.cd_devs[unit] -#define LE_DELAY(x) DELAY(x) - -int lematch __P((struct device *, void *, void *)); -void leattach __P((struct device *, struct device *, void *)); -int leintr __P((void *)); - -struct cfdriver lecd = { - NULL, "le", lematch, leattach, DV_IFNET, sizeof (struct le_softc) -}; - -integrate void -lewrcsr(sc, port, val) - struct le_softc *sc; - u_int16_t port, val; -{ - struct lereg1 *ler1 = sc->sc_r1; - - LEWREG(port, ler1->ler1_rap); - LERDWR(port, val, ler1->ler1_rdp); -} - -integrate u_int16_t -lerdcsr(sc, port) - struct le_softc *sc; - u_int16_t port; -{ - struct lereg1 *ler1 = sc->sc_r1; - u_int16_t val; - - LEWREG(port, ler1->ler1_rap); - LERDWR(0, ler1->ler1_rdp, val); - return (val); -} - -int -lematch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct cfdata *cf = match; - struct confargs *ca = aux; -#ifdef notdef /* XXX */ - struct tc_cfloc *tc_locp; - struct asic_cfloc *asic_locp; -#endif - -#ifdef notdef /* XXX */ - tclocp = (struct tc_cfloc *)cf->cf_loc; -#endif - - /* XXX CHECK BUS */ - /* make sure that we're looking for this type of device. */ -#ifdef notdef - if (!BUS_MATCHNAME(ca, "PMAD-BA ")) -#endif - if (!BUS_MATCHNAME(ca, "lance")) - return (0); - -#ifdef notdef /* XXX */ - /* make sure the unit matches the cfdata */ - if ((cf->cf_unit != tap->ta_unit && - tap->ta_unit != TA_ANYUNIT) || - (tclocp->cf_slot != tap->ta_slot && - tclocp->cf_slot != TC_SLOT_WILD) || - (tclocp->cf_offset != tap->ta_offset && - tclocp->cf_offset != TC_OFFSET_WILD)) - return (0); -#endif - - return (1); -} - -void -leattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - register struct le_softc *sc = (void *)self; - struct confargs *ca = aux; - u_char *cp; - int i; - - if (sc->sc_dev.dv_unit == 0 && (hwrpb->rpb_type == ST_DEC_3000_300 || - hwrpb->rpb_type == ST_DEC_3000_500)) { - /* It's on the system ASIC */ - volatile u_int *ldp; - - sc->sc_r1 = (struct lereg1 *)BUS_CVTADDR(ca); - sc->sc_r1 = TC_DENSE_TO_SPARSE(sc->sc_r1); - sc->sc_mem = (void *)le_iomem; -/* XXX */ cp = (u_char *)ASIC_SYS_ETHER_ADDRESS(asic_base); - - sc->sc_copytodesc = copytobuf_gap2; - sc->sc_copyfromdesc = copyfrombuf_gap2; - sc->sc_copytobuf = copytobuf_gap16; - sc->sc_copyfrombuf = copyfrombuf_gap16; - sc->sc_zerobuf = zerobuf_gap16; - - /* - * And enable Lance dma through the asic. - */ - ldp = (volatile u_int *)ASIC_REG_LANCE_DMAPTR(asic_base); - *ldp = (((u_int64_t)le_iomem << 3) & ~(u_int64_t)0x1f) | - (((u_int64_t)le_iomem >> 29) & 0x1f); - *(volatile u_int *)ASIC_REG_CSR(asic_base) |= - ASIC_CSR_DMAEN_LANCE; - wbflush(); - } else { - /* It's on the turbochannel proper */ - sc->sc_r1 = (struct lereg1 *) - (BUS_CVTADDR(ca) + LE_OFFSET_LANCE); - sc->sc_mem = (void *) - (BUS_CVTADDR(ca) + LE_OFFSET_RAM); - cp = (u_char *)(BUS_CVTADDR(ca) + LE_OFFSET_ROM + 2); - - sc->sc_copytodesc = copytobuf_contig; - sc->sc_copyfromdesc = copyfrombuf_contig; - sc->sc_copytobuf = copytobuf_contig; - sc->sc_copyfrombuf = copyfrombuf_contig; - sc->sc_zerobuf = zerobuf_contig; - } - - 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_arpcom.ac_enaddr); i++) { - sc->sc_arpcom.ac_enaddr[i] = *cp; - cp += 4; - } - - sc->sc_arpcom.ac_if.if_name = lecd.cd_name; - leconfig(sc); - - BUS_INTR_ESTABLISH(ca, leintr, sc); - /* XXX YEECH!!! */ - *(volatile u_int *)ASIC_REG_IMSK(asic_base) |= ASIC_INTR_LANCE; - wbflush(); -} - -/* - * 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 -lewritereg(regptr, val) - register volatile u_short *regptr; - register u_short val; -{ - register int i = 0; - - while (*regptr != val) { - *regptr = val; - wbflush(); - if (++i > 10000) { - printf("le: Reg did not settle (to x%x): x%x\n", val, - *regptr); - return; - } - DELAY(100); - } -} - -#include <dev/ic/am7990.c> diff --git a/sys/arch/alpha/tc/if_levar.h b/sys/arch/alpha/tc/if_levar.h deleted file mode 100644 index 9b4e24ea7db..00000000000 --- a/sys/arch/alpha/tc/if_levar.h +++ /dev/null @@ -1,96 +0,0 @@ -/* $NetBSD: if_levar.h,v 1.1 1995/06/28 01:48:26 cgd 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; - int32_t pad1; - volatile u_int16_t ler1_rap; /* register select port */ - int16_t pad2; - int32_t pad3; -}; - -/* - * Ethernet software status per interface. - * - * Each interface is referenced by a network interface structure, - * arpcom.ac_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 device sc_dev; /* base structure */ - struct arpcom sc_arpcom; /* Ethernet common part */ - - void (*sc_copytodesc) /* Copy to descriptor */ - __P((struct le_softc *, void *, int, int)); - void (*sc_copyfromdesc) /* Copy from descriptor */ - __P((struct le_softc *, void *, int, int)); - - void (*sc_copytobuf) /* Copy to buffer */ - __P((struct le_softc *, void *, int, int)); - void (*sc_copyfrombuf) /* Copy from buffer */ - __P((struct le_softc *, void *, int, int)); - void (*sc_zerobuf) /* and Zero bytes in buffer */ - __P((struct le_softc *, int, int)); - - u_int16_t sc_conf3; /* CSR3 value */ - - void *sc_mem; /* base addr of RAM -- CPU's view */ - u_long sc_addr; /* base addr 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 - - struct lereg1 *sc_r1; /* LANCE registers */ -}; diff --git a/sys/arch/alpha/tc/ioasic.c b/sys/arch/alpha/tc/ioasic.c new file mode 100644 index 00000000000..209c0e68314 --- /dev/null +++ b/sys/arch/alpha/tc/ioasic.c @@ -0,0 +1,376 @@ +/* $NetBSD: ioasic.c,v 1.1 1995/12/20 00:43:20 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 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 <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/pte.h> +#include <machine/rpb.h> + +#include <dev/tc/tcvar.h> +#include <alpha/tc/ioasicreg.h> +#include <dev/tc/ioasicvar.h> + +struct ioasic_softc { + struct device sc_dv; + + tc_addr_t sc_base; + void *sc_cookie; +}; + +/* Definition of the driver for autoconfig. */ +int ioasicmatch __P((struct device *, void *, void *)); +void ioasicattach __P((struct device *, struct device *, void *)); +int ioasicprint(void *, char *); +struct cfdriver ioasiccd = + { NULL, "ioasic", ioasicmatch, ioasicattach, DV_DULL, + sizeof(struct ioasic_softc) }; + +int ioasic_intr __P((void *)); +int ioasic_intrnull __P((void *)); + +#define C(x) ((void *)(x)) + +#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 + +struct ioasic_dev { + char *iad_modname; + tc_offset_t iad_offset; + void *iad_cookie; + u_int32_t iad_intrbits; +} ioasic_devs[] = { + { "lance ", 0x000c0000, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, }, + { "z8530 ", 0x00100000, C(IOASIC_DEV_SCC0), IOASIC_INTR_SCC_0, }, + { "z8530 ", 0x00180000, C(IOASIC_DEV_SCC1), IOASIC_INTR_SCC_1, }, + { "TOY_RTC ", 0x00200000, C(IOASIC_DEV_BOGUS), 0, }, + { "AMD79c30", 0x00240000, C(IOASIC_DEV_ISDN), IOASIC_INTR_ISDN, }, +}; +int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]); + +struct ioasicintr { + int (*iai_func) __P((void *)); + void *iai_arg; +} ioasicintrs[IOASIC_NCOOKIES]; + +tc_addr_t ioasic_base; /* XXX XXX XXX */ + +/* There can be only one. */ +int ioasicfound; + +extern int cputype; + +int +ioasicmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct tcdev_attach_args *tcdev = aux; + + /* Make sure that we're looking for this type of device. */ + if (strncmp("FLAMG-IO", tcdev->tcda_modname, TC_ROM_LLEN)) + return (0); + + /* Check that it can actually exist. */ + if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) + panic("ioasicmatch: how did we get here?"); + + if (ioasicfound) + return (0); + + return (1); +} + +void +ioasicattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct ioasic_softc *sc = (struct ioasic_softc *)self; + struct tcdev_attach_args *tcdev = aux; + struct ioasicdev_attach_args ioasicdev; + u_long i; + + ioasicfound = 1; + + sc->sc_base = tcdev->tcda_addr; + ioasic_base = sc->sc_base; /* XXX XXX XXX */ + sc->sc_cookie = tcdev->tcda_cookie; + +#ifdef DEC_3000_300 + if (cputype == ST_DEC_3000_300) { + *(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |= + IOASIC_CSR_FASTMODE; + tc_mb(); + printf(": slow mode\n"); + } else +#endif + printf(": fast mode\n"); + + /* + * 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, TC_IPL_NONE, ioasic_intr, sc); + + /* + * Try to configure each device. + */ + for (i = 0; i < ioasic_ndevs; i++) { + strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname, + TC_ROM_LLEN); + ioasicdev.iada_modname[TC_ROM_LLEN] = '\0'; + ioasicdev.iada_offset = ioasic_devs[i].iad_offset; + ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset; + ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie; + + /* Tell the autoconfig machinery we've found the hardware. */ + config_found(self, &ioasicdev, ioasicprint); + } +} + +int +ioasicprint(aux, pnp) + void *aux; + char *pnp; +{ + struct ioasicdev_attach_args *d = aux; + + if (pnp) + printf("%s at %s", d->iada_modname, pnp); + printf(" offset 0x%lx", (long)d->iada_offset); + return (UNCONF); +} + +int +ioasic_submatch(match, d) + struct cfdata *match; + struct ioasicdev_attach_args *d; +{ + + return ((match->ioasiccf_offset == d->iada_offset) || + (match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN)); +} + +void +ioasic_intr_establish(ioa, cookie, level, func, arg) + struct device *ioa; + void *cookie, *arg; + tc_intrlevel_t level; + int (*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; +} + +int +ioasic_intrnull(val) + void *val; +{ + + panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld\n", + (u_long)val); +} + +/* + * 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); +} + +/* XXX */ +char * +ioasic_lance_ether_address() +{ + + return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base); +} + +void +ioasic_lance_dma_setup(v) + void *v; +{ + volatile u_int32_t *ldp; + tc_addr_t tca; + + tca = (tc_addr_t)v; + + 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(); +} + +#ifdef DEC_3000_300 +void +ioasic_intr_300_opt0_enable(enable) + int enable; +{ + + if (enable) + *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |= + IOASIC_INTR_300_OPT0; + else + *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &= + ~IOASIC_INTR_300_OPT0; +} + +void +ioasic_intr_300_opt1_enable(enable) + int enable; +{ + + if (enable) + *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |= + IOASIC_INTR_300_OPT1; + else + *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &= + ~IOASIC_INTR_300_OPT1; +} + +void +ioasic_300_opts_isintr(opt0, opt1) + int *opt0, *opt1; +{ + u_int32_t sir; + + sir = *(volatile u_int32_t *)IOASIC_REG_INTR(ioasic_base); + *opt0 = sir & IOASIC_INTR_300_OPT0; + *opt1 = sir & IOASIC_INTR_300_OPT1; +} +#endif diff --git a/sys/arch/alpha/tc/ioasicreg.h b/sys/arch/alpha/tc/ioasicreg.h new file mode 100644 index 00000000000..c0ca70dc3f2 --- /dev/null +++ b/sys/arch/alpha/tc/ioasicreg.h @@ -0,0 +1,226 @@ +/* $NetBSD: ioasicreg.h,v 1.1 1995/12/20 00:43:22 cgd Exp $ */ + +/* + * Copyright (c) 1991,1990,1989,1994,1995 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University, + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)asic.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Slot definitions + */ + +#define IOASIC_SLOT_0_START 0x000000 +#define IOASIC_SLOT_1_START 0x040000 +#define IOASIC_SLOT_2_START 0x080000 +#define IOASIC_SLOT_3_START 0x0c0000 +#define IOASIC_SLOT_4_START 0x100000 +#define IOASIC_SLOT_5_START 0x140000 +#define IOASIC_SLOT_6_START 0x180000 +#define IOASIC_SLOT_7_START 0x1c0000 +#define IOASIC_SLOT_8_START 0x200000 +#define IOASIC_SLOT_9_START 0x240000 +#define IOASIC_SLOT_10_START 0x280000 +#define IOASIC_SLOT_11_START 0x2c0000 +#define IOASIC_SLOT_12_START 0x300000 +#define IOASIC_SLOT_13_START 0x340000 +#define IOASIC_SLOT_14_START 0x380000 +#define IOASIC_SLOT_15_START 0x3c0000 +#define IOASIC_SLOTS_END 0x3fffff + +/* + * Register offsets (slot 1) + */ + +#define IOASIC_SCSI_DMAPTR IOASIC_SLOT_1_START+0x000 +#define IOASIC_SCSI_NEXTPTR IOASIC_SLOT_1_START+0x010 +#define IOASIC_LANCE_DMAPTR IOASIC_SLOT_1_START+0x020 +#define IOASIC_SCC_T1_DMAPTR IOASIC_SLOT_1_START+0x030 +#define IOASIC_SCC_R1_DMAPTR IOASIC_SLOT_1_START+0x040 +#define IOASIC_SCC_T2_DMAPTR IOASIC_SLOT_1_START+0x050 +#define IOASIC_SCC_R2_DMAPTR IOASIC_SLOT_1_START+0x060 +#define IOASIC_FLOPPY_DMAPTR IOASIC_SLOT_1_START+0x070 +#define IOASIC_ISDN_X_DMAPTR IOASIC_SLOT_1_START+0x080 +#define IOASIC_ISDN_X_NEXTPTR IOASIC_SLOT_1_START+0x090 +#define IOASIC_ISDN_R_DMAPTR IOASIC_SLOT_1_START+0x0a0 +#define IOASIC_ISDN_R_NEXTPTR IOASIC_SLOT_1_START+0x0b0 +#define IOASIC_BUFF0 IOASIC_SLOT_1_START+0x0c0 +#define IOASIC_BUFF1 IOASIC_SLOT_1_START+0x0d0 +#define IOASIC_BUFF2 IOASIC_SLOT_1_START+0x0e0 +#define IOASIC_BUFF3 IOASIC_SLOT_1_START+0x0f0 +#define IOASIC_CSR IOASIC_SLOT_1_START+0x100 +#define IOASIC_INTR IOASIC_SLOT_1_START+0x110 +#define IOASIC_IMSK IOASIC_SLOT_1_START+0x120 +#define IOASIC_CURADDR IOASIC_SLOT_1_START+0x130 +#define IOASIC_ISDN_X_DATA IOASIC_SLOT_1_START+0x140 +#define IOASIC_ISDN_R_DATA IOASIC_SLOT_1_START+0x150 +#define IOASIC_LANCE_DECODE IOASIC_SLOT_1_START+0x160 +#define IOASIC_SCSI_DECODE IOASIC_SLOT_1_START+0x170 +#define IOASIC_SCC0_DECODE IOASIC_SLOT_1_START+0x180 +#define IOASIC_SCC1_DECODE IOASIC_SLOT_1_START+0x190 +#define IOASIC_FLOPPY_DECODE IOASIC_SLOT_1_START+0x1a0 +#define IOASIC_SCSI_SCR IOASIC_SLOT_1_START+0x1b0 +#define IOASIC_SCSI_SDR0 IOASIC_SLOT_1_START+0x1c0 +#define IOASIC_SCSI_SDR1 IOASIC_SLOT_1_START+0x1d0 + +/* System Status and control Register (SSR). */ +#define IOASIC_CSR_DMAEN_T1 0x80000000 /* rw */ +#define IOASIC_CSR_DMAEN_R1 0x40000000 /* rw */ +#define IOASIC_CSR_DMAEN_T2 0x20000000 /* rw */ +#define IOASIC_CSR_DMAEN_R2 0x10000000 /* rw */ +#define IOASIC_CSR_FASTMODE 0x08000000 /* rw */ +#define IOASIC_CSR_xxx 0x07800000 /* unused/reserved */ +#define IOASIC_CSR_FLOPPY_DIR 0x00400000 /* rw */ +#define IOASIC_CSR_DMAEN_FLOPPY 0x00200000 /* rw */ +#define IOASIC_CSR_DMAEN_ISDN_T 0x00100000 /* rw */ +#define IOASIC_CSR_DMAEN_ISDN_R 0x00080000 /* rw */ +#define IOASIC_CSR_SCSI_DIR 0x00040000 /* rw */ +#define IOASIC_CSR_DMAEN_SCSI 0x00020000 /* rw */ +#define IOASIC_CSR_DMAEN_LANCE 0x00010000 /* rw */ +/* low 16 bits are rw gp outputs */ + +/* System Interrupt Register (and Interrupt Mask Register). */ +#define IOASIC_INTR_T1_PAGE_END 0x80000000 /* rz */ +#define IOASIC_INTR_T1_READ_E 0x40000000 /* rz */ +#define IOASIC_INTR_R1_HALF_PAGE 0x20000000 /* rz */ +#define IOASIC_INTR_R1_DMA_OVRUN 0x10000000 /* rz */ +#define IOASIC_INTR_T2_PAGE_END 0x08000000 /* rz */ +#define IOASIC_INTR_T2_READ_E 0x04000000 /* rz */ +#define IOASIC_INTR_R2_HALF_PAGE 0x02000000 /* rz */ +#define IOASIC_INTR_R2_DMA_OVRUN 0x01000000 /* rz */ +#define IOASIC_INTR_FLOPPY_DMA_E 0x00800000 /* rz */ +#define IOASIC_INTR_ISDN_PTR_LOAD 0x00400000 /* rz */ +#define IOASIC_INTR_ISDN_OVRUN 0x00200000 /* rz */ +#define IOASIC_INTR_ISDN_READ_E 0x00100000 /* rz */ +#define IOASIC_INTR_SCSI_PTR_LOAD 0x00080000 /* rz */ +#define IOASIC_INTR_SCSI_OVRUN 0x00040000 /* rz */ +#define IOASIC_INTR_SCSI_READ_E 0x00020000 /* rz */ +#define IOASIC_INTR_LANCE_READ_E 0x00010000 /* rz */ +#define IOASIC_INTR_ISDN 0x00002000 /* ro */ +#define IOASIC_INTR_SEC_CON 0x00000200 /* ro */ +#define IOASIC_INTR_LANCE 0x00000100 /* ro */ +#define IOASIC_INTR_SCC_1 0x00000080 /* ro */ +#define IOASIC_INTR_SCC_0 0x00000040 /* ro */ +#define IOASIC_INTR_ALT_CON 0x00000008 /* ro - 3000/500 */ +#define IOASIC_INTR_300_OPT1 IOASIC_INTR_ALT_CON /* ro - 3000/300 */ +#define IOASIC_INTR_300_OPT0 0x00000004 /* ro - 3000/300 */ + +/* DMA pointer registers (SCSI, Comm, ...) */ + +#define IOASIC_DMAPTR_MASK 0xffffffe0 +#define IOASIC_DMAPTR_SHIFT 5 +#define IOASIC_DMAPTR_SET(reg,val) \ + (reg) = (((val)<<IOASIC_DMAPTR_SHIFT)&IOASIC_DMAPTR_MASK) +#define IOASIC_DMAPTR_GET(reg,val) \ + (val) = (((reg)&IOASIC_DMAPTR_MASK)>>IOASIC_DMAPTR_SHIFT) +#define IOASIC_DMA_ADDR(p) (((unsigned)p) << (5-2)) + +/* For the LANCE DMA pointer register initialization the above suffices */ + +/* More SCSI DMA registers */ + +#define IOASIC_SCR_STATUS 0x00000004 +#define IOASIC_SCR_WORD 0x00000003 + +/* Various Decode registers */ + +#define IOASIC_DECODE_HW_ADDRESS 0x000003f0 +#define IOASIC_DECODE_CHIP_SELECT 0x0000000f + +/* + * Asic register addresses at offset from base. + */ +#define IOASIC_REG_SCSI_DMAPTR(base) ((base) + IOASIC_SCSI_DMAPTR) +#define IOASIC_REG_SCSI_DMANPTR(base) ((base) + IOASIC_SCSI_NEXTPTR) +#define IOASIC_REG_LANCE_DMAPTR(base) ((base) + IOASIC_LANCE_DMAPTR) +#define IOASIC_REG_SCC_T1_DMAPTR(base) ((base) + IOASIC_SCC_T1_DMAPTR) +#define IOASIC_REG_SCC_R1_DMAPTR(base) ((base) + IOASIC_SCC_R1_DMAPTR) +#define IOASIC_REG_SCC_T2_DMAPTR(base) ((base) + IOASIC_SCC_T2_DMAPTR) +#define IOASIC_REG_SCC_R2_DMAPTR(base) ((base) + IOASIC_SCC_R2_DMAPTR) +#define IOASIC_REG_FLOPPY_DMAPTR(base) ((base) + IOASIC_FLOPPY_DMAPTR) +#define IOASIC_REG_ISDN_X_DMAPTR(base) ((base) + IOASIC_ISDN_X_DMAPTR) +#define IOASIC_REG_ISDN_X_NEXTPTR(base) ((base) + IOASIC_ISDN_X_NEXTPTR) +#define IOASIC_REG_ISDN_R_DMAPTR(base) ((base) + IOASIC_ISDN_R_DMAPTR) +#define IOASIC_REG_ISDN_R_NEXTPTR(base) ((base) + IOASIC_ISDN_R_NEXTPTR) +#define IOASIC_REG_BUFF0(base) ((base) + IOASIC_BUFF0) +#define IOASIC_REG_BUFF1(base) ((base) + IOASIC_BUFF1) +#define IOASIC_REG_BUFF2(base) ((base) + IOASIC_BUFF2) +#define IOASIC_REG_BUFF3(base) ((base) + IOASIC_BUFF3) +#define IOASIC_REG_CSR(base) ((base) + IOASIC_CSR) +#define IOASIC_REG_INTR(base) ((base) + IOASIC_INTR) +#define IOASIC_REG_IMSK(base) ((base) + IOASIC_IMSK) +#define IOASIC_REG_CURADDR(base) ((base) + IOASIC_CURADDR) +#define IOASIC_REG_ISDN_X_DATA(base) ((base) + IOASIC_ISDN_X_DATA) +#define IOASIC_REG_ISDN_R_DATA(base) ((base) + IOASIC_ISDN_R_DATA) +#define IOASIC_REG_LANCE_DECODE(base) ((base) + IOASIC_LANCE_DECODE) +#define IOASIC_REG_SCSI_DECODE(base) ((base) + IOASIC_SCSI_DECODE) +#define IOASIC_REG_SCC0_DECODE(base) ((base) + IOASIC_SCC0_DECODE) +#define IOASIC_REG_SCC1_DECODE(base) ((base) + IOASIC_SCC1_DECODE) +#define IOASIC_REG_FLOPPY_DECODE(base) ((base) + IOASIC_FLOPPY_DECODE) +#define IOASIC_REG_SCSI_SCR(base) ((base) + IOASIC_SCSI_SCR) +#define IOASIC_REG_SCSI_SDR0(base) ((base) + IOASIC_SCSI_SDR0) +#define IOASIC_REG_SCSI_SDR1(base) ((base) + IOASIC_SCSI_SDR1) + +/* + * And slot assignments. + */ +#define IOASIC_SYS_ETHER_ADDRESS(base) ((base) + IOASIC_SLOT_2_START) +#define IOASIC_SYS_LANCE(base) ((base) + IOASIC_SLOT_3_START) diff --git a/sys/arch/alpha/tc/scc.c b/sys/arch/alpha/tc/scc.c index fff9e26bf3c..cb2f4718217 100644 --- a/sys/arch/alpha/tc/scc.c +++ b/sys/arch/alpha/tc/scc.c @@ -1,4 +1,4 @@ -/* $NetBSD: scc.c,v 1.10 1995/11/23 02:41:29 cgd Exp $ */ +/* $NetBSD: scc.c,v 1.11 1995/12/20 00:43:24 cgd Exp $ */ /* * Copyright (c) 1991,1990,1989,1994,1995 Carnegie Mellon University @@ -100,11 +100,11 @@ #include <pmax/dev/fbreg.h> #endif -#include <machine/autoconf.h> #include <machine/rpb.h> -#include <alpha/tc/asic.h> -#include <alpha/tc/tc.h> +#include <dev/tc/tcvar.h> +#include <alpha/tc/ioasicreg.h> +#include <dev/tc/ioasicvar.h> extern void ttrstrt __P((void *)); @@ -205,13 +205,13 @@ sccmatch(parent, cfdata, aux) void *aux; { struct cfdata *cf = cfdata; - struct confargs *ca = aux; + struct ioasicdev_attach_args *d = aux; void *sccaddr; /* XXX BUS TYPE? */ /* Make sure that we're looking for this type of device. */ - if (!BUS_MATCHNAME(ca, "scc")) + if (strncmp(d->iada_modname, "z8530 ", TC_ROM_LLEN)) return (0); /* XXX MATCH CFLOC */ @@ -219,9 +219,9 @@ sccmatch(parent, cfdata, aux) return (0); /* Get the address, and check it for validity. */ - sccaddr = BUS_CVTADDR(ca); + sccaddr = (void *)d->iada_addr; #ifdef SPARSE - sccaddr = TC_DENSE_TO_SPARSE(sccaddr); + sccaddr = (void *)TC_DENSE_TO_SPARSE((tc_addr_t)sccaddr); #endif if (badaddr(sccaddr, 2)) return (0); @@ -234,20 +234,20 @@ scc_alphaintr(onoff) int onoff; { if (onoff) { - *(volatile u_int *)ASIC_REG_IMSK(asic_base) |= - ASIC_INTR_SCC_1 | ASIC_INTR_SCC_0; + *(volatile u_int *)IOASIC_REG_IMSK(ioasic_base) |= + IOASIC_INTR_SCC_1 | IOASIC_INTR_SCC_0; #if !defined(DEC_3000_300) && defined(SCC_DMA) - *(volatile u_int *)ASIC_REG_CSR(asic_base) |= - ASIC_CSR_DMAEN_T1 | ASIC_CSR_DMAEN_R1 | - ASIC_CSR_DMAEN_T2 | ASIC_CSR_DMAEN_R2; + *(volatile u_int *)IOASIC_REG_CSR(ioasic_base) |= + IOASIC_CSR_DMAEN_T1 | IOASIC_CSR_DMAEN_R1 | + IOASIC_CSR_DMAEN_T2 | IOASIC_CSR_DMAEN_R2; #endif } else { - *(volatile u_int *)ASIC_REG_IMSK(asic_base) &= - ~(ASIC_INTR_SCC_1 | ASIC_INTR_SCC_0); + *(volatile u_int *)IOASIC_REG_IMSK(ioasic_base) &= + ~(IOASIC_INTR_SCC_1 | IOASIC_INTR_SCC_0); #if !defined(DEC_3000_300) && defined(SCC_DMA) - *(volatile u_int *)ASIC_REG_CSR(asic_base) &= - ~(ASIC_CSR_DMAEN_T1 | ASIC_CSR_DMAEN_R1 | - ASIC_CSR_DMAEN_T2 | ASIC_CSR_DMAEN_R2); + *(volatile u_int *)IOASIC_REG_CSR(ioasic_base) &= + ~(IOASIC_CSR_DMAEN_T1 | IOASIC_CSR_DMAEN_R1 | + IOASIC_CSR_DMAEN_T2 | IOASIC_CSR_DMAEN_R2); #endif } wbflush(); @@ -260,7 +260,7 @@ sccattach(parent, self, aux) void *aux; { struct scc_softc *sc = (struct scc_softc *)self; - struct confargs *ca = aux; + struct ioasicdev_attach_args *d = aux; struct pdma *pdp; struct tty *tp; void *sccaddr; @@ -271,13 +271,14 @@ sccattach(parent, self, aux) extern int cputype; /* Get the address, and check it for validity. */ - sccaddr = BUS_CVTADDR(ca); + sccaddr = (void *)d->iada_addr; #ifdef SPARSE - sccaddr = TC_DENSE_TO_SPARSE(sccaddr); + sccaddr = (void *)TC_DENSE_TO_SPARSE((tc_addr_t)sccaddr); #endif /* Register the interrupt handler. */ - BUS_INTR_ESTABLISH(ca, sccintr, (void *)(long)sc->sc_dv.dv_unit); + ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_TTY, + sccintr, (void *)(long)sc->sc_dv.dv_unit); /* * For a remote console, wait a while for previous output to @@ -765,7 +766,7 @@ sccparam(tp, t) SCC_WRITE_REG(regs, line, SCC_WR9, value); SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1); - scc_alphaintr(1); + scc_alphaintr(1); /* XXX XXX XXX */ return (0); } diff --git a/sys/arch/alpha/tc/tc.c b/sys/arch/alpha/tc/tc.c deleted file mode 100644 index e75dea86155..00000000000 --- a/sys/arch/alpha/tc/tc.c +++ /dev/null @@ -1,272 +0,0 @@ -/* $NetBSD: tc.c,v 1.2 1995/03/08 00:39:05 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. - */ - -#include <sys/param.h> -#include <sys/device.h> - -#include <machine/autoconf.h> -#include <machine/rpb.h> - -#include <alpha/tc/tc.h> - -struct tc_softc { - struct device sc_dv; - struct abus sc_bus; - struct tc_cpu_desc *sc_desc; -}; - -/* Definition of the driver for autoconfig. */ -int tcmatch(struct device *, void *, void *); -void tcattach(struct device *, struct device *, void *); -int tcprint(void *, char *); -struct cfdriver tccd = - { NULL, "tc", tcmatch, tcattach, DV_DULL, sizeof (struct tc_softc) }; - -void tc_intr_establish __P((struct confargs *, int (*)(void *), void *)); -void tc_intr_disestablish __P((struct confargs *)); -caddr_t tc_cvtaddr __P((struct confargs *)); -int tc_matchname __P((struct confargs *, char *)); - -extern int cputype; - -#ifdef DEC_3000_300 -extern struct tc_cpu_desc dec_3000_300_cpu; -#endif -#ifdef DEC_3000_500 -extern struct tc_cpu_desc dec_3000_500_cpu; -#endif - -struct tc_cpu_desc *tc_cpu_devs[] = { - NULL, /* Unused */ - NULL, /* ST_ADU */ - NULL, /* ST_DEC_4000 */ - NULL, /* ST_DEC_7000 */ -#ifdef DEC_3000_500 - &dec_3000_500_cpu, /* ST_DEC_3000_500 */ -#else - NULL, -#endif - NULL, /* Unused */ - NULL, /* ST_DEC_2000_300 */ -#ifdef DEC_3000_300 - &dec_3000_300_cpu, /* ST_DEC_3000_300 */ -#else - NULL, -#endif -}; -int ntc_cpu_devs = sizeof tc_cpu_devs / sizeof tc_cpu_devs[0]; - -int -tcmatch(parent, cfdata, aux) - struct device *parent; - void *cfdata; - void *aux; -{ - struct cfdata *cf = cfdata; - struct confargs *ca = aux; - - /* Make sure that we're looking for a TC. */ - if (strcmp(ca->ca_name, tccd.cd_name) != 0) - return (0); - - /* Make sure that unit exists. */ - if (cf->cf_unit != 0 || - cputype > ntc_cpu_devs || tc_cpu_devs[cputype] == NULL) - return (0); - - return (1); -} - -void -tcattach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; -{ - struct tc_softc *sc = (struct tc_softc *)self; - struct confargs *nca; - char namebuf[TC_ROM_LLEN+1]; - int i; - - printf("\n"); - - /* keep our CPU description handy */ - sc->sc_desc = tc_cpu_devs[cputype]; - - /* set up interrupt handlers */ - (*sc->sc_desc->tc_intr_setup)(); - set_iointr(sc->sc_desc->tc_iointr); - - sc->sc_bus.ab_dv = (struct device *)sc; - sc->sc_bus.ab_type = BUS_TC; - sc->sc_bus.ab_intr_establish = tc_intr_establish; - sc->sc_bus.ab_intr_disestablish = tc_intr_disestablish; - sc->sc_bus.ab_cvtaddr = tc_cvtaddr; - sc->sc_bus.ab_matchname = tc_matchname; - - /* Try to configure each CPU-internal device */ - for (i = 0; i < sc->sc_desc->tcd_ndevs; i++) { - nca = &sc->sc_desc->tcd_devs[i]; - nca->ca_bus = &sc->sc_bus; - -#ifdef DIAGNOSTIC - if (nca->ca_slot > sc->sc_desc->tcd_nslots) - panic("tcattach: dev slot > number of slots for %s", - nca->ca_name); -#endif - - if (tc_checkdevmem(nca) == 0) - continue; - - /* If no name, we have to see what might be there. */ - if (nca->ca_name == NULL) { - if (tc_checkslot(nca, namebuf) == 0) - continue; - nca->ca_name = namebuf; - } - - /* Tell the autoconfig machinery we've found the hardware. */ - config_found(self, nca, tcprint); - } -} - -int -tcprint(aux, pnp) - void *aux; - char *pnp; -{ - struct confargs *ca = aux; - - if (pnp) - printf("%s at %s", ca->ca_name, pnp); - printf(" slot %ld offset 0x%lx", ca->ca_slot, ca->ca_offset); - return (UNCONF); -} - -caddr_t -tc_cvtaddr(ca) - struct confargs *ca; -{ - struct tc_softc *sc = tccd.cd_devs[0]; - - return (sc->sc_desc->tcd_slots[ca->ca_slot].tsd_dense + ca->ca_offset); - -} - -void -tc_intr_establish(ca, handler, val) - struct confargs *ca; - intr_handler_t handler; - void *val; -{ - struct tc_softc *sc = tccd.cd_devs[0]; - - (*sc->sc_desc->tc_intr_establish)(ca, handler, val); -} - -void -tc_intr_disestablish(ca) - struct confargs *ca; -{ - struct tc_softc *sc = tccd.cd_devs[0]; - - (*sc->sc_desc->tc_intr_disestablish)(ca); -} - -int -tc_matchname(ca, name) - struct confargs *ca; - char *name; -{ - - return (bcmp(name, ca->ca_name, TC_ROM_LLEN) == 0); -} - -int -tc_checkdevmem(ca) - struct confargs *ca; -{ - u_int32_t *datap; - - datap = (u_int32_t *)BUS_CVTADDR(ca); - - /* Return non-zero if memory was there (i.e. address wasn't bad). */ - return (!badaddr(datap, sizeof (u_int32_t))); -} - -u_int64_t tc_slot_romoffs[] = { TC_SLOT_ROM, TC_SLOT_PROTOROM }; -int ntc_slot_romoffs = sizeof tc_slot_romoffs / sizeof tc_slot_romoffs[0]; - -int -tc_checkslot(ca, namep) - struct confargs *ca; - char *namep; -{ - struct tc_rommap *romp; - int i, j; - - for (i = 0; i < ntc_slot_romoffs; i++) { - romp = (struct tc_rommap *) - (BUS_CVTADDR(ca) + 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[TC_ROM_LLEN] = '\0'; - return (1); - } - return (0); -} - -int -tc_intrnull(val) - void *val; -{ - - panic("uncaught TC intr for slot %ld\n", (long)val); -} diff --git a/sys/arch/alpha/tc/tc.h b/sys/arch/alpha/tc/tc.h deleted file mode 100644 index ffa81f1eb33..00000000000 --- a/sys/arch/alpha/tc/tc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* $NetBSD: tc.h,v 1.1 1995/02/13 23:09:07 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. - */ - -/* - * TurboChannel-specific functions and structures. - */ - -/* - * 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 MAGIC_READ do { \ - extern u_int32_t no_optimize; \ - no_optimize = *(u_int32_t *)phystok0seg(0x00000001f0080220); \ -} while (0); - -#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) \ - ((void *) \ - (((u_int64_t)addr & TC_SPACE_IND) | \ - TC_SPACE_SPARSE | \ - (((u_int64_t)addr & TC_SPACE_DENSE_OFFSET) << 1))) - -#define TC_SPARSE_TO_DENSE(addr) \ - ((void *) \ - (((u_int64_t)addr & TC_SPACE_IND) | \ - TC_SPACE_DENSE | \ - (((u_int64_t)addr & TC_SPACE_SPARSE_OFFSET) >> 1))) - - -#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]; -}; - -/* The contents of a cfdata->cf_loc for a TurboChannel device */ -struct tc_cfloc { - int cf_slot; /* Slot number */ - int cf_offset; /* XXX? Offset into slot. */ - int cf_vec; - int cf_ipl; -}; - -#define TC_SLOT_WILD -1 /* wildcarded slot */ -#define TC_OFFSET_WILD -1 /* wildcarded offset */ -#define TC_VEC_WILD -1 /* wildcarded vec */ -#define TC_IPL_WILD -1 /* wildcarded ipl */ - -struct tc_slot_desc { - caddr_t tsd_dense; -}; - -struct tc_cpu_desc { - struct tc_slot_desc *tcd_slots; - long tcd_nslots; - struct confargs *tcd_devs; - long tcd_ndevs; - void (*tc_intr_setup) __P((void)); - void (*tc_intr_establish) - __P((struct confargs *, intr_handler_t, void *)); - void (*tc_intr_disestablish) __P((struct confargs *)); - void (*tc_iointr) __P((void *, int)); -}; - -int tc_intrnull __P((void *)); diff --git a/sys/arch/alpha/tc/tc_3000_300.c b/sys/arch/alpha/tc/tc_3000_300.c index 6790d0cb9cb..571afab6148 100644 --- a/sys/arch/alpha/tc/tc_3000_300.c +++ b/sys/arch/alpha/tc/tc_3000_300.c @@ -1,4 +1,4 @@ -/* $NetBSD: tc_3000_300.c,v 1.3 1995/08/03 00:52:29 cgd Exp $ */ +/* $NetBSD: tc_3000_300.c,v 1.4 1995/12/20 00:43:27 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. @@ -33,109 +33,139 @@ #include <machine/autoconf.h> #include <machine/pte.h> -#include <alpha/tc/tc.h> +#include <dev/tc/tcvar.h> +#include <alpha/tc/tc_conf.h> #include <alpha/tc/tc_3000_300.h> -/* XXX ESTABLISH, DISESTABLISH */ void tc_3000_300_intr_setup __P((void)); -void tc_3000_300_intr_establish - __P((struct confargs *, intr_handler_t, void *)); -void tc_3000_300_intr_disestablish __P((struct confargs *)); +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 *, int)); -int tc_3000_300_getdev __P((struct confargs *)); - -#define KV(x) ((caddr_t)phystok0seg(x)) -#define TC_3000_300_NSLOTS 5 -#define TC_3000_300_MAXDEVS 5 - -static struct tc_slot_desc dec_3000_300_slots[TC_3000_300_NSLOTS] = { - { KV(0x100000000), }, /* slot 0 - TC option slot 0 */ - { KV(0x120000000), }, /* slot 1 - TC option slot 1 */ - { KV(0x180000000), }, /* slot 2 - TCDS ASIC on cpu board */ - { KV(0x1a0000000), }, /* slot 3 - IOCTL ASIC on cpu board */ - { KV(0x1c0000000), }, /* slot 4 - CXTurbo on cpu board */ -}; -static struct confargs dec_3000_300_devs[TC_3000_300_MAXDEVS] = { - { "PMAGB-BA", 4, 0x02000000, }, - { "IOCTL ", 3, 0x00000000, }, - { "PMAZ-DS ", 2, 0x00000000, }, - { NULL, 1, 0x0, }, - { NULL, 0, 0x0, }, +int tc_3000_300_intrnull __P((void *)); + +#define C(x) ((void *)(u_long)x) +#define KV(x) (phystok0seg(x)) + +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]); -/* Indices into the struct confargs array. */ -#define TC_3000_300_DEV_CXTURBO 0 -#define TC_3000_300_DEV_IOCTL 1 -#define TC_3000_300_DEV_TCDS 2 -#define TC_3000_300_DEV_OPT1 3 -#define TC_3000_300_DEV_OPT0 4 - -struct tc_cpu_desc dec_3000_300_cpu = { - dec_3000_300_slots, TC_3000_300_NSLOTS, - dec_3000_300_devs, TC_3000_300_MAXDEVS, - tc_3000_300_intr_setup, - tc_3000_300_intr_establish, - tc_3000_300_intr_disestablish, - tc_3000_300_iointr, +struct tc_builtin tc_3000_300_builtins[] = { + { "PMAGB-BA", 4, 0x02000000, C(TC_3000_300_DEV_CXTURBO), }, + { "FLAMG-IO", 3, 0x00000000, C(TC_3000_300_DEV_IOASIC), }, + { "PMAZ-DS ", 2, 0x00000000, C(TC_3000_300_DEV_TCDS), }, }; +int tc_3000_300_nbuiltins = + sizeof(tc_3000_300_builtins) / sizeof(tc_3000_300_builtins[0]); -intr_handler_t tc_3000_300_intrhand[TC_3000_300_MAXDEVS]; -void *tc_3000_300_intrval[TC_3000_300_MAXDEVS]; +struct tcintr { + int (*tci_func) __P((void *)); + void *tci_arg; +} tc_3000_300_intr[TC_3000_300_NCOOKIES]; + +/* XXX */ +void ioasic_intr_300_opt0_enable __P((int)); +void ioasic_intr_300_opt1_enable __P((int)); +void ioasic_300_opts_isintr __P((int *, int *)); void tc_3000_300_intr_setup() { - int i; - - /* Set up interrupt handlers. */ - for (i = 0; i < TC_3000_300_MAXDEVS; i++) { - tc_3000_300_intrhand[i] = tc_intrnull; - tc_3000_300_intrval[i] = (void *)(long)i; + u_long i; + + /* + * Sisable all interrupts that we can (can't disable builtins). + */ + ioasic_intr_300_opt0_enable(0); + ioasic_intr_300_opt1_enable(0); + + /* + * Set up interrupt handlers. + */ + for (i = 0; i < TC_3000_300_NCOOKIES; i++) { + tc_3000_300_intr[i].tci_func = tc_3000_300_intrnull; + tc_3000_300_intr[i].tci_arg = (void *)i; } } void -tc_3000_300_intr_establish(ca, handler, val) - struct confargs *ca; - int (*handler) __P((void *)); - void *val; +tc_3000_300_intr_establish(tcadev, cookie, level, func, arg) + struct device *tcadev; + void *cookie, *arg; + tc_intrlevel_t level; + int (*func) __P((void *)); { - int dev = tc_3000_300_getdev(ca); + u_long dev = (u_long)cookie; #ifdef DIAGNOSTIC - if (dev == -1) - panic("tc_3000_300_intr_establish: dev == -1"); + /* XXX bounds-check cookie. */ #endif - if (tc_3000_300_intrhand[dev] != tc_intrnull) - panic("tc_3000_300_intr_establish: dev %d twice", dev); - - tc_3000_300_intrhand[dev] = handler; - tc_3000_300_intrval[dev] = val; - - /* XXX ENABLE INTERRUPT MASK FOR DEV */ + if (tc_3000_300_intr[dev].tci_func != tc_3000_300_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; + + switch (dev) { + case TC_3000_300_DEV_OPT0: + ioasic_intr_300_opt0_enable(1); + break; + case TC_3000_300_DEV_OPT1: + ioasic_intr_300_opt1_enable(1); + break; + default: + /* interrupts for builtins always enabled */ + break; + } } void -tc_3000_300_intr_disestablish(ca) - struct confargs *ca; +tc_3000_300_intr_disestablish(tcadev, cookie) + struct device *tcadev; + void *cookie; { - int dev = tc_3000_300_getdev(ca); + u_long dev = (u_long)cookie; #ifdef DIAGNOSTIC - if (dev == -1) - panic("tc_3000_300_intr_disestablish: somebody goofed"); + /* XXX bounds-check cookie. */ #endif - if (tc_3000_300_intrhand[dev] == tc_intrnull) - panic("tc_3000_300_intr_disestablish: dev %d missing intr", + if (tc_3000_300_intr[dev].tci_func == tc_3000_300_intrnull) + panic("tc_3000_300_intr_disestablish: cookie %d bad intr", dev); - tc_3000_300_intrhand[dev] = tc_intrnull; - tc_3000_300_intrval[dev] = (void *)(long)dev; + switch (dev) { + case TC_3000_300_DEV_OPT0: + ioasic_intr_300_opt0_enable(0); + break; + case TC_3000_300_DEV_OPT1: + ioasic_intr_300_opt1_enable(0); + break; + default: + /* interrupts for builtins always enabled */ + break; + } + + tc_3000_300_intr[dev].tci_func = tc_3000_300_intrnull; + tc_3000_300_intr[dev].tci_arg = (void *)dev; +} + +int +tc_3000_300_intrnull(val) + void *val; +{ - /* XXX DISABLE INTERRUPT MASK FOR DEV */ + panic("tc_3000_300_intrnull: uncaught TC intr for cookie %ld\n", + (u_long)val); } void @@ -144,7 +174,7 @@ tc_3000_300_iointr(framep, vec) int vec; { u_int32_t ir; - int ifound; + int opt0intr, opt1intr, ifound; #ifdef DIAGNOSTIC int s; @@ -157,38 +187,33 @@ tc_3000_300_iointr(framep, vec) #endif do { - MAGIC_READ; - wbflush(); + tc_syncbus(); /* find out what interrupts/errors occurred */ ir = *(volatile u_int32_t *)TC_3000_300_IR; - wbflush(); + ioasic_300_opts_isintr(&opt0intr, &opt1intr); + tc_mb(); /* clear the interrupts/errors we found. */ *(volatile u_int32_t *)TC_3000_300_IR = ir; - wbflush(); + /* XXX can't clear TC option slot interrupts here? */ + tc_wmb(); ifound = 0; -#define CHECKINTR(slot, bits) \ - if (ir & bits) { \ +#define CHECKINTR(slot, flag) \ + if (flag) { \ ifound = 1; \ - (*tc_3000_300_intrhand[slot]) \ - (tc_3000_300_intrval[slot]); \ + (*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, TC_3000_300_IR_CXTURBO); - CHECKINTR(TC_3000_300_DEV_IOCTL, TC_3000_300_IR_IOCTL); - CHECKINTR(TC_3000_300_DEV_TCDS, TC_3000_300_IR_TCDS); -#if 0 - CHECKINTR(TC_3000_300_DEV_OPT1, TC_3000_300_IR_OPT1); - CHECKINTR(TC_3000_300_DEV_OPT0, TC_3000_300_IR_OPT0); -#else - /* XXX XXX XXX CHECK OPTION SLOT INTERRUPTS!!! */ - /* XXX XXX XXX THEIR BITS LIVE IN ANOTHER REG. */ -#endif + CHECKINTR(TC_3000_300_DEV_CXTURBO, ir & TC_3000_300_IR_CXTURBO); + CHECKINTR(TC_3000_300_DEV_IOASIC, ir & TC_3000_300_IR_IOASIC); + CHECKINTR(TC_3000_300_DEV_TCDS, ir & TC_3000_300_IR_TCDS); + CHECKINTR(TC_3000_300_DEV_OPT1, opt1intr); + CHECKINTR(TC_3000_300_DEV_OPT0, opt0intr); #undef CHECKINTR - #ifdef DIAGNOSTIC #define PRINTINTR(msg, bits) \ if (ir & bits) \ @@ -204,18 +229,3 @@ tc_3000_300_iointr(framep, vec) #endif } while (ifound); } - -int -tc_3000_300_getdev(ca) - struct confargs *ca; -{ - int i; - - for (i = 0; i < TC_3000_300_MAXDEVS; i++) - if (ca->ca_slot == dec_3000_300_devs[i].ca_slot && - ca->ca_offset == dec_3000_300_devs[i].ca_offset && - !strncmp(ca->ca_name, dec_3000_300_devs[i].ca_name)) - return (i); - - return (-1); -} diff --git a/sys/arch/alpha/tc/tc_3000_300.h b/sys/arch/alpha/tc/tc_3000_300.h index 1942e6cc4d4..9d4b35cdca9 100644 --- a/sys/arch/alpha/tc/tc_3000_300.h +++ b/sys/arch/alpha/tc/tc_3000_300.h @@ -1,4 +1,4 @@ -/* $NetBSD: tc_3000_300.h,v 1.1 1995/03/08 00:39:07 cgd Exp $ */ +/* $NetBSD: tc_3000_300.h,v 1.2 1995/12/20 00:43:28 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. @@ -42,9 +42,20 @@ /* 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_IOCTL 0x00000010 /* TC IOCTL */ +#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 diff --git a/sys/arch/alpha/tc/tc_3000_500.c b/sys/arch/alpha/tc/tc_3000_500.c index 83f7971c16e..1ac7250e57c 100644 --- a/sys/arch/alpha/tc/tc_3000_500.c +++ b/sys/arch/alpha/tc/tc_3000_500.c @@ -1,4 +1,4 @@ -/* $NetBSD: tc_3000_500.c,v 1.2 1995/08/03 00:52:36 cgd Exp $ */ +/* $NetBSD: tc_3000_500.c,v 1.3 1995/12/20 00:43:30 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. @@ -33,133 +33,141 @@ #include <machine/autoconf.h> #include <machine/pte.h> -#include <alpha/tc/tc.h> +#include <dev/tc/tcvar.h> +#include <alpha/tc/tc_conf.h> #include <alpha/tc/tc_3000_500.h> -/* XXX ESTABLISH, DISESTABLISH */ void tc_3000_500_intr_setup __P((void)); -void tc_3000_500_intr_establish - __P((struct confargs *, intr_handler_t, void *)); -void tc_3000_500_intr_disestablish __P((struct confargs *)); +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 *, int)); -int tc_3000_500_getdev __P((struct confargs *)); - -#define KV(x) ((caddr_t)phystok0seg(x)) -#define TC_3000_500_NSLOTS 8 -#define TC_3000_500_MAXDEVS 9 - -static struct tc_slot_desc dec_3000_500_slots[TC_3000_500_NSLOTS] = { - { KV(0x100000000), }, /* slot 0 - TC option slot 0 */ - { KV(0x120000000), }, /* slot 1 - TC option slot 1 */ - { KV(0x140000000), }, /* slot 2 - TC option slot 2 */ - { KV(0x160000000), }, /* slot 3 - TC option slot 3 */ - { KV(0x180000000), }, /* slot 4 - TC option slot 4 */ - { KV(0x1a0000000), }, /* slot 5 - TC option slot 5 */ - { KV(0x1c0000000), }, /* slot 6 - TCDS ASIC on cpu board */ - { KV(0x1e0000000), }, /* slot 7 - IOCTL ASIC on cpu board */ -}; -static struct confargs dec_3000_500_devs[TC_3000_500_MAXDEVS] = { - { "IOCTL ", 7, 0x00000000, }, - { "PMAGB-BA", 7, 0x02000000, }, - { "PMAZ-DS ", 6, 0x00000000, }, - { NULL, 5, 0x0, }, - { NULL, 4, 0x0, }, - { NULL, 3, 0x0, }, - { NULL, 2, 0x0, }, - { NULL, 1, 0x0, }, - { NULL, 0, 0x0, }, +int tc_3000_500_intrnull __P((void *)); + +#define C(x) ((void *)(u_long)x) +#define KV(x) (phystok0seg(x)) + +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]); -/* Indices into the struct confargs array. */ -#define TC_3000_500_DEV_IOCTL 0 -#define TC_3000_500_DEV_CXTURBO 1 -#define TC_3000_500_DEV_TCDS 2 -#define TC_3000_500_DEV_OPT5 3 -#define TC_3000_500_DEV_OPT4 4 -#define TC_3000_500_DEV_OPT3 5 -#define TC_3000_500_DEV_OPT2 6 -#define TC_3000_500_DEV_OPT1 7 -#define TC_3000_500_DEV_OPT0 8 - -struct tc_cpu_desc dec_3000_500_cpu = { - dec_3000_500_slots, TC_3000_500_NSLOTS, - dec_3000_500_devs, TC_3000_500_MAXDEVS, - tc_3000_500_intr_setup, - tc_3000_500_intr_establish, - tc_3000_500_intr_disestablish, - tc_3000_500_iointr, +struct tc_builtin tc_3000_500_builtins[] = { + { "FLAMG-IO", 7, 0x00000000, C(TC_3000_500_DEV_IOASIC), }, + { "PMAGB-BA", 7, 0x02000000, C(TC_3000_500_DEV_CXTURBO), }, + { "PMAZ-DS ", 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, }; -intr_handler_t tc_3000_500_intrhand[TC_3000_500_MAXDEVS]; -void *tc_3000_500_intrval[TC_3000_500_MAXDEVS]; +struct tcintr { + int (*tci_func) __P((void *)); + void *tci_arg; +} tc_3000_500_intr[TC_3000_500_NCOOKIES]; void tc_3000_500_intr_setup() { - int i; - - /* Set up interrupt handlers. */ - for (i = 0; i < TC_3000_500_MAXDEVS; i++) { - tc_3000_500_intrhand[i] = tc_intrnull; - tc_3000_500_intrval[i] = (void *)(long)i; - } + u_long i; + u_int32_t imr; /* - * XXX - * The System Programmer's Manual (3-15) says IMR entries for option - * slots are initialized to 0. I think this is wrong, and that they - * are initialized to 1, i.e. the option slots are disabled. Enable - * them. - * - * XXX - * The MACH code appears to enable them by setting them to 1. !?!?! + * Disable all slot interrupts. */ - *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = 0; - wbflush(); + imr = *(volatile u_int32_t *)TC_3000_500_IMR_READ; + for (i = 0; i < TC_3000_500_NCOOKIES; i++) + imr |= tc_3000_500_intrbits[i]; + *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = imr; + tc_mb(); + + /* + * Set up interrupt handlers. + */ + for (i = 0; i < TC_3000_500_NCOOKIES; i++) { + tc_3000_500_intr[i].tci_func = tc_3000_500_intrnull; + tc_3000_500_intr[i].tci_arg = (void *)i; + } } void -tc_3000_500_intr_establish(ca, handler, val) - struct confargs *ca; - int (*handler) __P((void *)); - void *val; +tc_3000_500_intr_establish(tcadev, cookie, level, func, arg) + struct device *tcadev; + void *cookie, *arg; + tc_intrlevel_t level; + int (*func) __P((void *)); { - int dev = tc_3000_500_getdev(ca); + u_long dev = (u_long)cookie; + u_int32_t imr; #ifdef DIAGNOSTIC - if (dev == -1) - panic("tc_3000_500_intr_establish: dev == -1"); + /* XXX bounds-check cookie. */ #endif - if (tc_3000_500_intrhand[dev] != tc_intrnull) - panic("tc_3000_500_intr_establish: dev %d twice", dev); + if (tc_3000_500_intr[dev].tci_func != tc_3000_500_intrnull) + panic("tc_3000_500_intr_establish: cookie %d twice", dev); - tc_3000_500_intrhand[dev] = handler; - tc_3000_500_intrval[dev] = val; + tc_3000_500_intr[dev].tci_func = func; + tc_3000_500_intr[dev].tci_arg = arg; - /* XXX ENABLE INTERRUPT MASK FOR DEV */ + imr = *(volatile u_int32_t *)TC_3000_500_IMR_READ; + imr &= ~tc_3000_500_intrbits[dev]; + *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = imr; + tc_mb(); } void -tc_3000_500_intr_disestablish(ca) - struct confargs *ca; +tc_3000_500_intr_disestablish(tcadev, cookie) + struct device *tcadev; + void *cookie; { - int dev = tc_3000_500_getdev(ca); + u_long dev = (u_long)cookie; + u_int32_t imr; #ifdef DIAGNOSTIC - if (dev == -1) - panic("tc_3000_500_intr_disestablish: somebody goofed"); + /* XXX bounds-check cookie. */ #endif - if (tc_3000_500_intrhand[dev] == tc_intrnull) - panic("tc_3000_500_intr_disestablish: dev %d missing intr", + if (tc_3000_500_intr[dev].tci_func == tc_3000_500_intrnull) + panic("tc_3000_500_intr_disestablish: cookie %d bad intr", dev); - tc_3000_500_intrhand[dev] = tc_intrnull; - tc_3000_500_intrval[dev] = (void *)(long)dev; + imr = *(volatile u_int32_t *)TC_3000_500_IMR_READ; + imr |= tc_3000_500_intrbits[dev]; + *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = imr; + tc_mb(); - /* XXX DISABLE INTERRUPT MASK FOR DEV */ + tc_3000_500_intr[dev].tci_func = tc_3000_500_intrnull; + tc_3000_500_intr[dev].tci_arg = (void *)dev; +} + +int +tc_3000_500_intrnull(val) + void *val; +{ + + panic("tc_3000_500_intrnull: uncaught TC intr for cookie %ld\n", + (u_long)val); } void @@ -181,28 +189,26 @@ tc_3000_500_iointr(framep, vec) #endif do { - MAGIC_READ; - wbflush(); + tc_syncbus(); ir = *(volatile u_int32_t *)TC_3000_500_IR_CLEAR; - wbflush(); ifound = 0; -#define CHECKINTR(slot, bits) \ - if (ir & bits) { \ +#define CHECKINTR(slot) \ + if (ir & tc_3000_500_intrbits[slot]) { \ ifound = 1; \ - (*tc_3000_500_intrhand[slot]) \ - (tc_3000_500_intrval[slot]); \ + (*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, TC_3000_500_IR_CXTURBO); - CHECKINTR(TC_3000_500_DEV_IOCTL, TC_3000_500_IR_IOCTL); - CHECKINTR(TC_3000_500_DEV_TCDS, TC_3000_500_IR_TCDS); - CHECKINTR(TC_3000_500_DEV_OPT5, TC_3000_500_IR_OPT5); - CHECKINTR(TC_3000_500_DEV_OPT4, TC_3000_500_IR_OPT4); - CHECKINTR(TC_3000_500_DEV_OPT3, TC_3000_500_IR_OPT3); - CHECKINTR(TC_3000_500_DEV_OPT2, TC_3000_500_IR_OPT2); - CHECKINTR(TC_3000_500_DEV_OPT1, TC_3000_500_IR_OPT1); - CHECKINTR(TC_3000_500_DEV_OPT0, TC_3000_500_IR_OPT0); + 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 @@ -228,21 +234,6 @@ tc_3000_500_iointr(framep, vec) } while (ifound); } -int -tc_3000_500_getdev(ca) - struct confargs *ca; -{ - int i; - - for (i = 0; i < TC_3000_500_MAXDEVS; i++) - if (ca->ca_slot == dec_3000_500_devs[i].ca_slot && - ca->ca_offset == dec_3000_500_devs[i].ca_offset && - !strncmp(ca->ca_name, dec_3000_500_devs[i].ca_name)) - return (i); - - return (-1); -} - /* * tc_3000_500_ioslot -- * Set the PBS bits for devices on the TC. @@ -265,6 +256,6 @@ tc_3000_500_ioslot(slot, flags, set) ios &= ~flags; s = splhigh(); *iosp = ios; - wbflush(); + tc_mb(); splx(s); } diff --git a/sys/arch/alpha/tc/tc_3000_500.h b/sys/arch/alpha/tc/tc_3000_500.h index 4c3e9d9bf71..676b89f730d 100644 --- a/sys/arch/alpha/tc/tc_3000_500.h +++ b/sys/arch/alpha/tc/tc_3000_500.h @@ -1,4 +1,4 @@ -/* $NetBSD: tc_3000_500.h,v 1.1 1995/02/13 23:09:09 cgd Exp $ */ +/* $NetBSD: tc_3000_500.h,v 1.2 1995/12/20 00:43:31 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. @@ -57,7 +57,7 @@ #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_IOCTL 0x00000080 /* TC IOCTL */ +#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 */ @@ -86,5 +86,20 @@ #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_IOCTL 7 /* Option IOCTL 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 diff --git a/sys/arch/alpha/tc/tc_conf.h b/sys/arch/alpha/tc/tc_conf.h new file mode 100644 index 00000000000..1d73b9ac660 --- /dev/null +++ b/sys/arch/alpha/tc/tc_conf.h @@ -0,0 +1,60 @@ +/* $NetBSD: tc_conf.h,v 1.1 1995/12/20 00:43:32 cgd 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. + */ + +/* + * Machine-specific TurboChannel configuration definitions. + */ + +#ifdef DEC_3000_500 +extern void tc_3000_500_intr_setup __P((void)); +extern void tc_3000_500_iointr __P((void *, int)); + +extern void tc_3000_500_intr_establish __P((struct device *, void *, + tc_intrlevel_t, int (*)(void *), void *)); +extern void tc_3000_500_intr_disestablish __P((struct device *, void *)); + +extern int tc_3000_500_nslots; +extern struct tc_slotdesc tc_3000_500_slots[]; +extern int tc_3000_500_nbuiltins; +extern struct tc_builtin tc_3000_500_builtins[]; +#endif /* DEC_3000_500 */ + +#ifdef DEC_3000_300 +extern void tc_3000_300_intr_setup __P((void)); +extern void tc_3000_300_iointr __P((void *, int)); + +extern void tc_3000_300_intr_establish __P((struct device *, void *, + tc_intrlevel_t, int (*)(void *), void *)); +extern void tc_3000_300_intr_disestablish __P((struct device *, void *)); + +extern int tc_3000_300_nslots; +extern struct tc_slotdesc tc_3000_300_slots[]; +extern int tc_3000_300_nbuiltins; +extern struct tc_builtin tc_3000_300_builtins[]; +#endif /* DEC_3000_300 */ diff --git a/sys/arch/alpha/tc/tcasic.c b/sys/arch/alpha/tc/tcasic.c new file mode 100644 index 00000000000..9524b08957f --- /dev/null +++ b/sys/arch/alpha/tc/tcasic.c @@ -0,0 +1,141 @@ +/* $NetBSD: tcasic.c,v 1.1 1995/12/20 00:43:34 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. + */ + +#include <sys/param.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/rpb.h> + +#include <dev/tc/tcvar.h> +#include <alpha/tc/tc_conf.h> + +/* Definition of the driver for autoconfig. */ +int tcasicmatch(struct device *, void *, void *); +void tcasicattach(struct device *, struct device *, void *); +struct cfdriver tcasiccd = + { NULL, "tcasic", tcasicmatch, tcasicattach, DV_DULL, + sizeof (struct device) }; + +int tcasicprint __P((void *, char *)); + +extern int cputype; + +/* There can be only one. */ +int tcasicfound; + +int +tcasicmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct confargs *ca = aux; + + /* Make sure that we're looking for a TurboChannel ASIC. */ + if (strcmp(ca->ca_name, tcasiccd.cd_name)) + return (0); + + /* Make sure that the system supports a TurboChannel ASIC. */ + if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) + return (0); + + if (tcasicfound) + return (0); + + return (1); +} + +void +tcasicattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct tc_attach_args tc; + void (*intr_setup) __P((void)); + void (*iointr) __P((void *, int)); + + tcasicfound = 1; + + switch (cputype) { +#ifdef DEC_3000_500 + case ST_DEC_3000_500: + printf(": 25MHz\n"); + + intr_setup = tc_3000_500_intr_setup; + iointr = tc_3000_500_iointr; + + tc.tca_nslots = tc_3000_500_nslots; + tc.tca_slots = tc_3000_500_slots; + tc.tca_nbuiltins = tc_3000_500_nbuiltins; + tc.tca_builtins = tc_3000_500_builtins; + tc.tca_intr_establish = tc_3000_500_intr_establish; + tc.tca_intr_disestablish = tc_3000_500_intr_disestablish; + break; +#endif /* DEC_3000_500 */ + +#ifdef DEC_3000_300 + case ST_DEC_3000_300: + printf(": 12.5MHz\n"); + + intr_setup = tc_3000_300_intr_setup; + iointr = tc_3000_300_iointr; + + tc.tca_nslots = tc_3000_300_nslots; + tc.tca_slots = tc_3000_300_slots; + tc.tca_nbuiltins = tc_3000_300_nbuiltins; + tc.tca_builtins = tc_3000_300_builtins; + tc.tca_intr_establish = tc_3000_300_intr_establish; + tc.tca_intr_disestablish = tc_3000_300_intr_disestablish; + break; +#endif /* DEC_3000_300 */ + + default: + printf("\n"); + panic("tcasicattach: bad cputype"); + } + + (*intr_setup)(); + set_iointr(iointr); + + config_found(self, &tc, tcasicprint); +} + +int +tcasicprint(aux, pnp) + void *aux; + char *pnp; +{ + + /* only TCs can attach to tcasics; easy. */ + if (pnp) + printf("tc at %s", pnp); + return (UNCONF); +} diff --git a/sys/arch/alpha/tc/tcds.c b/sys/arch/alpha/tc/tcds.c index 9d93c0c7d6c..6c0c6490fec 100644 --- a/sys/arch/alpha/tc/tcds.c +++ b/sys/arch/alpha/tc/tcds.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcds.c,v 1.5 1995/08/03 00:52:39 cgd Exp $ */ +/* $NetBSD: tcds.c,v 1.6 1995/12/20 00:40:29 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. @@ -32,18 +32,23 @@ #include <sys/systm.h> #include <sys/device.h> -#include <machine/autoconf.h> #include <machine/pte.h> #include <machine/rpb.h> -#include <alpha/tc/tc.h> -#include <alpha/tc/tcds_dmavar.h> -#include <alpha/tc/tcds.h> +#include <dev/tc/tcreg.h> +#include <dev/tc/tcvar.h> +#include <alpha/tc/tcdsreg.h> +#include <alpha/tc/tcdsvar.h> struct tcds_softc { struct device sc_dv; - struct abus sc_bus; - caddr_t sc_base; + tc_addr_t sc_base; + void *sc_cookie; + + volatile u_int32_t *sc_cir; + volatile u_int32_t *sc_imer; + + struct tcds_slotconfig sc_slots[2]; }; /* Definition of the driver for autoconfig. */ @@ -53,43 +58,26 @@ int tcdsprint(void *, char *); struct cfdriver tcdscd = { NULL, "tcds", tcdsmatch, tcdsattach, DV_DULL, sizeof(struct tcds_softc) }; -void tcds_intr_establish __P((struct confargs *, int (*)(void *), void *)); -void tcds_intr_disestablish __P((struct confargs *)); -caddr_t tcds_cvtaddr __P((struct confargs *)); -int tcds_matchname __P((struct confargs *, char *)); - -int tcds_intr __P((void *)); -int tcds_intrnull __P((void *)); - -#define TCDS_SLOT_SCSI0 0 -#define TCDS_SLOT_SCSI1 1 - -struct tcds_slot { - struct confargs ts_ca; - intr_handler_t ts_handler; - void *ts_val; -} tcds_slots[] = { - { { "esp", 0, 0x0, }, - tcds_intrnull, (void *)(long)TCDS_SLOT_SCSI0, }, - { { "esp", 1, 0x0, }, - tcds_intrnull, (void *)(long)TCDS_SLOT_SCSI1, }, -}; +/*static*/ int tcds_intr __P((void *)); +/*static*/ int tcds_intrnull __P((void *)); int -tcdsmatch(parent, vcf, aux) +tcdsmatch(parent, cfdata, aux) struct device *parent; - void *vcf, *aux; + void *cfdata; + void *aux; { - struct cfdata *cf = vcf; - struct confargs *ca = aux; - - /* It can only occur on the turbochannel, anyway. */ - if (ca->ca_bus->ab_type != BUS_TC) - return (0); + struct tcdev_attach_args *tcdev = aux; + extern int cputype; /* Make sure that we're looking for this type of device. */ - if (!BUS_MATCHNAME(ca, "PMAZ-DS ")) + if (strncmp("PMAZ-DS ", tcdev->tcda_modname, TC_ROM_LLEN)) return (0); + /* PMAZ-FS? */ + + /* Check that it can actually exist. */ + if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) + panic("tcdsmatch: how did we get here?"); return (1); } @@ -100,44 +88,106 @@ tcdsattach(parent, self, aux) void *aux; { struct tcds_softc *sc = (struct tcds_softc *)self; - struct confargs *ca = aux; - struct confargs *nca; - volatile u_int32_t *cir, *imer; + struct tcdev_attach_args *tcdev = aux; + struct tcdsdev_attach_args tcdsdev; + struct tcds_slotconfig *slotc; int i; extern int cputype; printf("\n"); - sc->sc_base = BUS_CVTADDR(ca); + sc->sc_base = tcdev->tcda_addr; + sc->sc_cookie = tcdev->tcda_cookie; - sc->sc_bus.ab_dv = (struct device *)sc; - sc->sc_bus.ab_type = BUS_TCDS; - sc->sc_bus.ab_intr_establish = tcds_intr_establish; - sc->sc_bus.ab_intr_disestablish = tcds_intr_disestablish; - sc->sc_bus.ab_cvtaddr = tcds_cvtaddr; - sc->sc_bus.ab_matchname = tcds_matchname; + sc->sc_cir = TCDS_REG(sc->sc_base, TCDS_CIR); + sc->sc_imer = TCDS_REG(sc->sc_base, TCDS_IMER); - BUS_INTR_ESTABLISH(ca, tcds_intr, sc); + tc_intr_establish(parent, sc->sc_cookie, TC_IPL_BIO, 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. */ - imer = TCDS_REG(sc->sc_base, TCDS_IMER); - *imer = 0; + *sc->sc_imer = 0; wbflush(); + /* XXX Initial contents of CIR? */ + + /* + * Set up the per-slot defintions for later use. + */ + + /* 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 */ - nca = &tcds_slots[TCDS_SLOT_SCSI0].ts_ca; - nca->ca_bus = &sc->sc_bus; - config_found(self, nca, tcdsprint); + 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); + + config_found(self, &tcdsdev, tcdsprint); /* the second SCSI chip isn't present on the 3000/300 series. */ if (cputype != ST_DEC_3000_300) { - nca = &tcds_slots[TCDS_SLOT_SCSI1].ts_ca; - nca->ca_bus = &sc->sc_bus; - config_found(self, nca, tcdsprint); + 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); + + config_found(self, &tcdsdev, tcdsprint); } } @@ -146,87 +196,59 @@ tcdsprint(aux, pnp) void *aux; char *pnp; { - struct confargs *ca = aux; + struct tcdev_attach_args *tcdev = aux; if (pnp) - printf("%s at %s", ca->ca_name, pnp); - printf(" slot 0x%lx", ca->ca_slot); + printf("%s at %s", tcdev->tcda_modname, pnp); + printf(" slot 0x%lx", tcdev->tcda_slot); return (UNCONF); } void -tcds_intr_establish(ca, handler, val) - struct confargs *ca; - int (*handler) __P((void *)); - void *val; +tcds_intr_establish(tcds, cookie, level, func, arg) + struct device *tcds; + void *cookie, *arg; + tc_intrlevel_t level; + int (*func) __P((void *)); { - if (tcds_slots[ca->ca_slot].ts_handler != tcds_intrnull) - panic("tcds_intr_establish: slot %d twice", ca->ca_slot); + struct tcds_softc *sc = (struct tcds_softc *)tcds; + u_long slot; - tcds_slots[ca->ca_slot].ts_handler = handler; - tcds_slots[ca->ca_slot].ts_val = val; - - switch (ca->ca_slot) { - case TCDS_SLOT_SCSI0: - tcds_scsi_reset(0); - break; + slot = (u_long)cookie; +#ifdef DIAGNOSTIC + /* XXX check cookie. */ +#endif - case TCDS_SLOT_SCSI1: - tcds_scsi_reset(1); - break; + if (sc->sc_slots[slot].sc_intrhand != tcds_intrnull) + panic("tcds_intr_establish: cookie %d twice", slot); - default: - panic("tcds_intr_establish: unknown slot number %d", - ca->ca_slot); - /* NOTREACHED */ - } + 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(ca) - struct confargs *ca; +tcds_intr_disestablish(tcds, cookie) + struct device *tcds; + void *cookie; { - if (tcds_slots[ca->ca_slot].ts_handler == tcds_intrnull) - panic("tcds_intr_disestablish: slot %d missing intr", - ca->ca_slot); - - tcds_slots[ca->ca_slot].ts_handler = tcds_intrnull; - tcds_slots[ca->ca_slot].ts_val = (void *)(long)ca->ca_slot; - - switch (ca->ca_slot) { - case TCDS_SLOT_SCSI0: - tcds_dma_disable(0); - tcds_scsi_disable(0); - break; - - case TCDS_SLOT_SCSI1: - tcds_dma_disable(1); - tcds_scsi_disable(1); - break; - - default: - panic("tcds_intr_disestablish: unknown slot number %d", - ca->ca_slot); - /* NOTREACHED */ - } -} + struct tcds_softc *sc = (struct tcds_softc *)tcds; + u_long slot; -caddr_t -tcds_cvtaddr(ca) - struct confargs *ca; -{ + slot = (u_long)cookie; +#ifdef DIAGNOSTIC + /* XXX check cookie. */ +#endif - return - (((struct tcds_softc *)ca->ca_bus->ab_dv)->sc_base + ca->ca_offset); -} + if (sc->sc_slots[slot].sc_intrhand == tcds_intrnull) + panic("tcds_intr_disestablish: cookie %d missing intr", + slot); -int -tcds_matchname(ca, name) - struct confargs *ca; - char *name; -{ + sc->sc_slots[slot].sc_intrhand = tcds_intrnull; + sc->sc_slots[slot].sc_intrarg = (void *)slot; - return (strcmp(name, ca->ca_name) == 0); + tcds_dma_enable(&sc->sc_slots[slot], 0); + tcds_scsi_enable(&sc->sc_slots[slot], 0); } int @@ -234,254 +256,84 @@ tcds_intrnull(val) void *val; { - panic("uncaught TCDS ASIC intr for slot %ld\n", (long)val); -} - -void -tcds_scsi_reset(unit) - int unit; -{ - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *cir; - - tcds_dma_disable(unit); - tcds_scsi_disable(unit); - - /* XXX: Clear/set IOSLOT/PBS bits. */ - cir = TCDS_REG(sc->sc_base, TCDS_CIR); - switch (unit) { - case 0: - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI0_RESET); - wbflush(); - DELAY(1); /* XXX */ - TCDS_CIR_SET(*cir, TCDS_CIR_SCSI0_RESET); - wbflush(); - break; - - case 1: - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI1_RESET); - wbflush(); - DELAY(1); /* XXX */ - TCDS_CIR_SET(*cir, TCDS_CIR_SCSI1_RESET); - wbflush(); - break; - - default: - panic("tcds_scsi_disable: unknown unit number\n", unit); - /* NOTREACHED */ - } - - tcds_scsi_enable(unit); - tcds_dma_enable(unit); -} - -void -tcds_scsi_enable(unit) - int unit; -{ - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *imer; - - imer = TCDS_REG(sc->sc_base, TCDS_IMER); - - /* - * XXX - * Should we be setting all the "interrupt bits" in the IMER? - * Do we need to set a bit in the mask so that SCSI DMA errors - * cause interrupts? - */ - switch (unit) { - case 0: - *imer |= TCDS_IMER_SCSI0_MASK | TCDS_IMER_SCSI0_ENB; - wbflush(); - break; - - case 1: - *imer |= TCDS_IMER_SCSI1_MASK | TCDS_IMER_SCSI1_ENB; - wbflush(); - break; - - default: - panic("tcds_scsi_enable: unknown unit number\n", unit); - /* NOTREACHED */ - } + panic("tcds_intrnull: uncaught TCDS intr for cookie %ld\n", + (u_long)val); } void -tcds_scsi_disable(unit) - int unit; +tcds_scsi_reset(sc) + struct tcds_slotconfig *sc; { - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *imer; - - imer = TCDS_REG(sc->sc_base, TCDS_IMER); - switch (unit) { - case 0: - *imer &= ~(TCDS_IMER_SCSI0_MASK | TCDS_IMER_SCSI0_ENB); - wbflush(); - break; + tcds_dma_enable(sc, 0); + tcds_scsi_enable(sc, 0); - case 1: - *imer &= ~(TCDS_IMER_SCSI1_MASK | TCDS_IMER_SCSI1_ENB); - wbflush(); - break; - - default: - panic("tcds_scsi_disable: unknown unit number\n", unit); - /* NOTREACHED */ - } -} + TCDS_CIR_CLR(*sc->sc_tcds->sc_cir, sc->sc_resetbits); + wbflush(); + DELAY(1); + TCDS_CIR_SET(*sc->sc_tcds->sc_cir, sc->sc_resetbits); + wbflush(); -void -tcds_dma_init(dsc, unit) - struct dma_softc *dsc; - int unit; -{ - struct tcds_softc *sc = tcdscd.cd_devs[0]; - - switch (unit) { - case 0: - dsc->sda = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_ADDR); - dsc->dic = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_INTR); - dsc->dud0 = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_DUD0); - dsc->dud1 = TCDS_REG(sc->sc_base, TCDS_SCSI0_DMA_DUD1); - break; - - case 1: - dsc->sda = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_ADDR); - dsc->dic = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_INTR); - dsc->dud0 = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_DUD0); - dsc->dud1 = TCDS_REG(sc->sc_base, TCDS_SCSI1_DMA_DUD1); - break; - - default: - panic("tcds_dma_init: unknown unit number\n", unit); - /* NOTREACHED */ - } + tcds_scsi_enable(sc, 1); + tcds_dma_enable(sc, 1); } void -tcds_dma_enable(unit) - int unit; +tcds_scsi_enable(sc, on) + struct tcds_slotconfig *sc; + int on; { - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *cir; - - cir = TCDS_REG(sc->sc_base, TCDS_CIR); - /* XXX Clear/set IOSLOT/PBS bits. */ - switch (unit) { - case 0: - TCDS_CIR_SET(*cir, TCDS_CIR_SCSI0_DMAENA); - wbflush(); - break; - - case 1: - TCDS_CIR_SET(*cir, TCDS_CIR_SCSI1_DMAENA); - wbflush(); - break; - - default: - panic("tcds_dma_enable: unknown unit number\n", unit); - /* NOTREACHED */ - } + if (on) + *sc->sc_tcds->sc_imer |= sc->sc_intrmaskbits; + else + *sc->sc_tcds->sc_imer &= ~sc->sc_intrmaskbits; + wbflush(); } void -tcds_dma_disable(unit) - int unit; +tcds_dma_enable(sc, on) + struct tcds_slotconfig *sc; + int on; { - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *cir; - - cir = TCDS_REG(sc->sc_base, TCDS_CIR); /* XXX Clear/set IOSLOT/PBS bits. */ - switch (unit) { - case 0: - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI0_DMAENA); - wbflush(); - break; - - case 1: - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI1_DMAENA); - wbflush(); - break; - - default: - panic("tcds_dma_disable: unknown unit number\n", unit); - /* NOTREACHED */ - } + 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); + wbflush(); } int -tcds_scsi_isintr(unit, clear) - int unit, clear; +tcds_scsi_isintr(sc, clear) + struct tcds_slotconfig *sc; + int clear; { - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *cir, ir; - - cir = TCDS_REG(sc->sc_base, TCDS_CIR); - ir = *cir; - wbflush(); - switch (unit) { - case 0: - if (ir & TCDS_CIR_SCSI0_INT) { - if (clear) { - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI0_INT); - wbflush(); - } - return (1); + if ((*sc->sc_tcds->sc_cir & sc->sc_intrbits) != 0) { + if (clear) { + TCDS_CIR_CLR(*sc->sc_tcds->sc_cir, sc->sc_intrbits); + wbflush(); } - break; - - case 1: - if (ir & TCDS_CIR_SCSI1_INT) { - if (clear) { - TCDS_CIR_CLR(*cir, TCDS_CIR_SCSI1_INT); - wbflush(); - } - return (1); - } - break; - - default: - panic("tcds_scsi_isintr: unknown unit number\n", unit); - /* NOTREACHED */ - } - return (0); + return (1); + } else + return (0); } int -tcds_scsi_iserr(dsc) - struct dma_softc *dsc; +tcds_scsi_iserr(sc) + struct tcds_slotconfig *sc; { - struct tcds_softc *sc = tcdscd.cd_devs[0]; - volatile u_int32_t *cir, ir; - - cir = TCDS_REG(sc->sc_base, TCDS_CIR); - ir = *cir; - wbflush(); - if (ir & SCSI_CIR_ERROR) { - printf("%s: error <CIR = %x>\n", dsc->sc_dev.dv_xname, ir); - return (1); - } - return (0); + return ((*sc->sc_tcds->sc_cir & sc->sc_errorbits) != 0); } -/* - * tcds_intr -- - * TCDS ASIC interrupt handler. - */ int tcds_intr(val) void *val; { struct tcds_softc *sc; - volatile u_int32_t *cir; u_int32_t ir; sc = val; @@ -490,21 +342,20 @@ tcds_intr(val) * XXX * Copy and clear (gag!) the interrupts. */ - cir = TCDS_REG(sc->sc_base, TCDS_CIR); - ir = *cir; + ir = *sc->sc_cir; wbflush(); - TCDS_CIR_CLR(*cir, TCDS_CIR_ALLINTR); + TCDS_CIR_CLR(*sc->sc_cir, TCDS_CIR_ALLINTR); wbflush(); - MAGIC_READ; + tc_syncbus(); wbflush(); -#define CHECKINTR(slot, bits) \ - if (ir & bits) { \ - (void)(*tcds_slots[slot].ts_handler) \ - (tcds_slots[slot].ts_val); \ +#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(TCDS_SLOT_SCSI0, TCDS_CIR_SCSI0_INT); - CHECKINTR(TCDS_SLOT_SCSI1, TCDS_CIR_SCSI1_INT); + CHECKINTR(0); + CHECKINTR(1); #undef CHECKINTR #ifdef DIAGNOSTIC diff --git a/sys/arch/alpha/tc/tcds_dma.c b/sys/arch/alpha/tc/tcds_dma.c index 30acc24c48c..f717ec6cd26 100644 --- a/sys/arch/alpha/tc/tcds_dma.c +++ b/sys/arch/alpha/tc/tcds_dma.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcds_dma.c,v 1.5 1995/09/05 15:07:05 cgd Exp $ */ +/* $NetBSD: tcds_dma.c,v 1.6 1995/12/20 00:40:32 cgd Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. @@ -41,138 +41,120 @@ #include <sys/proc.h> #include <sys/user.h> -#include <alpha/autoconf.h> -#include <alpha/cpu.h> - #include <scsi/scsi_all.h> #include <scsi/scsiconf.h> -#include <alpha/tc/tcds_dmavar.h> +#include <dev/tc/tcvar.h> +#include <alpha/tc/tcdsreg.h> +#include <alpha/tc/tcdsvar.h> #include <alpha/tc/espreg.h> #include <alpha/tc/espvar.h> -#include <alpha/tc/tcds.h> - -int dmaprint __P((void *, char *)); -void dmaattach __P((struct device *, struct device *, void *)); -int dmamatch __P((struct device *, struct cfdata *, void *)); -void dma_reset __P((struct dma_softc *)); -void dma_start __P((struct dma_softc *, caddr_t *, size_t *, int)); -int dmaintr __P((struct dma_softc *)); -/* - * dma_init -- - * Initialize AXP DMA for ESP. - */ void -dma_init(sc) - struct dma_softc *sc; +tcds_dma_reset(sc) + struct tcds_slotconfig *sc; { - /* TCDS register address initialization. */ - tcds_dma_init(sc, sc->sc_dev.dv_unit); - - /* Indirect functions. */ - sc->reset = dma_reset; - sc->enintr = NULL; - sc->start = dma_start; - sc->isintr = NULL; - sc->intr = dmaintr; + /* TCDS SCSI disable/reset/enable. */ + tcds_scsi_reset(sc); /* XXX */ + + sc->sc_active = 0; /* and of course we aren't */ } + void -dma_reset(sc) - struct dma_softc *sc; +tcds_dma_enintr(sc) + struct tcds_slotconfig *sc; { - /* TCDS SCSI disable/reset/enable. */ - tcds_scsi_reset(sc->sc_dev.dv_unit); - sc->sc_active = 0; /* and of course we aren't */ + /* XXX */ } -/* - * SPARC: - * The rules say we cannot transfer more than the limit of this - * DMA chip (64k for old and 16Mb for new), and we cannot cross - * a 16Mb boundary. - * AXP: - * We're doing physical DMA. Since pages on the AXP are 8K, we - * don't transfer more than that, or cross an 8K boundary, in a - * single transfer. - */ -#define ESPMAX \ - ((sc->sc_esp->sc_rev == ESP200) ? (16 * 1024 * 1024) : \ - (sc->sc_esp->sc_rev == NCR53C94) ? (8 * 1024) : (64 * 1024)) -#define DMAMAX(a) \ - (sc->sc_esp->sc_rev == NCR53C94) ? 0x2000 - ((a) & 0x1fff) : \ - (0x01000000 - ((a) & 0x00ffffff)) +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; +} + +#define ESPMAX (64 * 1024) +#define DMAMAX(a) (0x02000 - ((a) & 0x1fff)) /* * start a dma transfer or keep it going */ void -dma_start(sc, addr, len, datain) - struct dma_softc *sc; - char **addr; +tcds_dma_start(sc, addr, len, datain) + struct tcds_slotconfig *sc; + caddr_t *addr; size_t *len; - int datain; + int datain; /* DMA into main memory */ { - /* we do the loading of the transfer counter */ - volatile espreg_t *esp = sc->sc_esp->sc_reg; u_int32_t dic; - int size; + size_t size; sc->sc_dmaaddr = addr; sc->sc_dmalen = len; + sc->sc_iswrite = datain; -#ifdef DMA_DEBUG - printf("%s: dma_start %d bytes %s 0x%08x\n", - sc->sc_dev.dv_xname, *len, datain ? "to" : "from", *addr); -#endif - size = min(*len, ESPMAX); - size = min(size, DMAMAX((size_t)*addr)); - sc->sc_dmasize = size; - -#ifdef DMA_DEBUG - printf("dma_start: transfer = %d\n", sc->sc_dmasize); -#endif + ESP_DMA(("tcds_dma %d: start %d@0x%lx,%d\n", sc->sc_slot, *sc->sc_dmalen, *sc->sc_dmaaddr, sc->sc_iswrite)); -#ifdef TK_NOT_NECESSARY - tcds_dma_disable(sc->sc_dev.dv_unit); wbflush(); - tcds_scsi_disable(sc->sc_dev.dv_unit); wbflush(); -#endif + /* + * the rules say we cannot transfer more than the limit + * of this DMA chip (64k) and we cannot cross a 8k boundary. + */ + size = min(*sc->sc_dmalen, ESPMAX); + size = min(size, DMAMAX((size_t) *sc->sc_dmaaddr)); + sc->sc_dmasize = size; - /* Load the count in. */ - esp->esp_tcl = size & 0xff; wbflush(); - esp->esp_tcm = (size >> 8) & 0xff; wbflush(); - if (sc->sc_esp->sc_rev == ESP200) { - esp->esp_tch = (size >> 16) & 0xff; wbflush(); - } - ESPCMD(sc->sc_esp, ESPCMD_NOP|ESPCMD_DMA); + 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 > VM_MIN_KERNEL_ADDRESS) { - *sc->sda = vatopa((u_long)*addr) >> 2; wbflush(); + *sc->sc_sda = vatopa((u_long)*addr) >> 2; } else { - *sc->sda = k0segtophys((u_long)*addr) >> 2; wbflush(); + *sc->sc_sda = k0segtophys((u_long)*addr) >> 2; } - dic = *sc->dic; + wbflush(); + 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->dic = dic; wbflush(); + *sc->sc_dic = dic; + wbflush(); -#ifdef TK_NOT_NECESSARY - tcds_scsi_enable(sc->sc_dev.dv_unit); wbflush(); - tcds_dma_enable(sc->sc_dev.dv_unit); wbflush(); -#endif + /* Program the SCSI counter */ + ESP_WRITE_REG(sc->sc_esp, ESP_TCL, size); + ESP_WRITE_REG(sc->sc_esp, ESP_TCM, size >> 8); + if (sc->sc_esp->sc_rev == ESP200) { + ESP_WRITE_REG(sc->sc_esp, ESP_TCH, size >> 16); + } + /* load the count in */ + ESPCMD(sc->sc_esp, ESPCMD_NOP|ESPCMD_DMA); - /* and kick the SCSI */ - ESPCMD(sc->sc_esp, ESPCMD_TRANS|ESPCMD_DMA); + /* + * Note that if `size' is 0, we've already transceived all + * the bytes we want but we're still in the DATA PHASE. + * Apparently, the device needs padding. Also, a transfer + * size of 0 means "maximum" to the chip DMA logic. + */ + ESPCMD(sc->sc_esp, (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA); sc->sc_active = 1; + + /* Start DMA */ + tcds_dma_enable(sc, 1); } /* @@ -183,100 +165,124 @@ dma_start(sc, addr, len, datain) * return 1 if it was a DMA continue. */ int -dmaintr(sc) - struct dma_softc *sc; +tcds_dma_intr(sc) + struct tcds_slotconfig *sc; { - volatile espreg_t *esp = sc->sc_esp->sc_reg; u_int32_t dud; - int resid, trans; - char *addr; + int trans = 0, resid = 0; + u_int32_t *addr, dudmask; + u_char tcl, tcm, tch; -#ifdef DMA_DEBUG - printf("%s: dmaintr\n", sc->sc_dev.dv_xname); -#endif - -#ifdef DIAGNOSTIC - if (sc->sc_active == 0) - panic("dmaintr: %s: DMA inactive", sc->sc_dev.dv_xname); -#endif + ESP_DMA(("tcds_dma %d: intr", sc->sc_slot)); if (tcds_scsi_iserr(sc)) return (0); -#ifdef TK_NOT_NECESSARY - tcds_dma_disable(sc->sc_dev.dv_unit); wbflush(); - tcds_scsi_disable(sc->sc_dev.dv_unit); wbflush(); -#endif + /* 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; - resid = RR(esp->esp_fflag) & ESPFIFO_FF; wbflush(); - if (!(*sc->dic & TCDS_DIC_WRITE) && resid != 0) { wbflush(); - printf("%s: empty FIFO of %d ", sc->sc_dev.dv_xname, resid); + 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 += RR(esp->esp_tcl); wbflush(); - resid += RR(esp->esp_tcm) << 8; wbflush(); + 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 += RR(esp->esp_tch) << 16; wbflush(); + 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("%s: xfer (%d) > req (%d)\n", - sc->sc_dev.dv_xname, trans, sc->sc_dmasize); + 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; } - /* Handle unaligned starting address, length. */ - dud = *sc->dud0; wbflush(); - if (dud & (TCDS_SCSI0_DUD0_VALID01 | - TCDS_SCSI0_DUD0_VALID10 | TCDS_SCSI0_DUD0_VALID11)) { - addr = (char *)((vm_offset_t)*sc->sc_dmaaddr & ~0x03); - if (dud & TCDS_SCSI0_DUD0_VALID01) - addr[1] = dud & TCDS_SCSI0_DUD0_BYTE01; - if (dud & TCDS_SCSI0_DUD0_VALID10) - addr[2] = dud & TCDS_SCSI0_DUD0_BYTE10; - if (dud & TCDS_SCSI0_DUD0_VALID11) - addr[3] = dud & TCDS_SCSI0_DUD0_BYTE11; - } - dud = *sc->dud1; wbflush(); - if (dud & (TCDS_SCSI0_DUD1_VALID00 | - TCDS_SCSI0_DUD1_VALID01 | TCDS_SCSI0_DUD1_VALID10)) { - addr = (char *)((vm_offset_t)(*sc->sc_dmaaddr + trans) & ~0x03); - if (dud & TCDS_SCSI0_DUD1_VALID00) - addr[0] = dud & TCDS_SCSI0_DUD1_BYTE00; - if (dud & TCDS_SCSI0_DUD1_VALID01) - addr[1] = dud & TCDS_SCSI0_DUD1_BYTE01; - if (dud & TCDS_SCSI0_DUD1_VALID10) - addr[2] = dud & TCDS_SCSI0_DUD1_BYTE10; - } - -#ifdef DMA_DEBUG - { u_int32_t tcl, tcm, tch; - tcl = RR(esp->esp_tcl); wbflush(); - tcm = RR(esp->esp_tcm); wbflush(); - tch = sc->sc_esp->sc_rev == ESP200 ? RR(esp->esp_tch) : 0; - wbflush(); - printf("dmaintr: tcl=%d, tcm=%d, tch=%d, resid=%d, trans=%d\n", - tcl, tcm, tch, resid, trans); - } + 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 -#ifdef SPARC_DRIVER - if (DMACSR(sc) & D_WRITE) - cache_flush(*sc->sc_dmaaddr, trans); + ESP_DMA(("dud0 at 0x%lx dudmask 0x%x\n", + addr, dudmask)); + addr = (u_int32_t *)phystok0seg(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 *)phystok0seg(addr); + *addr = (*addr & ~dudmask) | (dud & dudmask); + } + /* XXX deal with saved residual byte? */ + } + *sc->sc_dmalen -= trans; *sc->sc_dmaaddr += trans; - if (!*sc->sc_dmalen || - sc->sc_esp->sc_phase != sc->sc_esp->sc_prevphase) { -#ifdef TK_NOT_NECESSARY - tcds_scsi_enable(sc->sc_dev.dv_unit); wbflush(); -#endif +#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->dic & TCDS_DIC_WRITE); + dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, sc->sc_iswrite); return 1; +#endif + return 0; } diff --git a/sys/arch/alpha/tc/tcds_dmavar.h b/sys/arch/alpha/tc/tcds_dmavar.h deleted file mode 100644 index 8d4bf7b490f..00000000000 --- a/sys/arch/alpha/tc/tcds_dmavar.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $NetBSD: tcds_dmavar.h,v 1.1 1995/02/13 23:08:54 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. - */ - -struct dma_softc { - struct device sc_dev; /* us as a device */ - struct esp_softc *sc_esp; /* my scsi */ - int sc_active; /* DMA active ? */ - int sc_rev; /* revision */ - int sc_node; /* PROM node ID */ - size_t sc_dmasize; - caddr_t *sc_dmaaddr; - size_t *sc_dmalen; - void (*reset)(struct dma_softc *); /* reset routine */ - void (*enintr)(struct dma_softc *); /* enable interrupts */ - void (*start)(struct dma_softc *, caddr_t *, size_t *, int); - int (*isintr)(struct dma_softc *); /* interrupt ? */ - int (*intr)(struct dma_softc *); /* interrupt ! */ - -/* - * AXP additions. -- TK - */ - volatile u_int *sda; /* TCDS SCSI DMA address */ - volatile u_int *dic; /* TCDS SCSI DMA interrupt control */ - volatile u_int *dud0; /* TCDS DMA unaligned data[0] */ - volatile u_int *dud1; /* TCDS DMA unaligned data[1] */ -}; diff --git a/sys/arch/alpha/tc/tcds.h b/sys/arch/alpha/tc/tcdsreg.h index 589428dd993..529fad75214 100644 --- a/sys/arch/alpha/tc/tcds.h +++ b/sys/arch/alpha/tc/tcdsreg.h @@ -1,10 +1,10 @@ -/* $NetBSD: tcds.h,v 1.2 1995/03/03 01:38:59 cgd Exp $ */ +/* $NetBSD: tcdsreg.h,v 1.1 1995/12/20 00:40:36 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Carnegie-Mellon University. * All rights reserved. * - * Author: Keith Bostic + * 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 @@ -28,6 +28,12 @@ */ /* + * 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 */ @@ -83,26 +89,8 @@ #define TCDS_IMER 0x040004 /* IMER offset */ #define TCDS_SCSI0_DMA_ADDR 0x041000 /* DMA address */ - -#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_SCSI0_DMA_INTR 0x041004 /* DMA interrupt control */ - -#define TCDS_SCSI0_DUD0_VALID01 0x00000001 /* byte 01 valid mask */ -#define TCDS_SCSI0_DUD0_VALID10 0x00000002 /* byte 10 valid mask */ -#define TCDS_SCSI0_DUD0_VALID11 0x00000004 /* byte 11 valid mask */ -#define TCDS_SCSI0_DUD0_BYTE01 0x0000ff00 /* byte 01 mask */ -#define TCDS_SCSI0_DUD0_BYTE10 0x00ff0000 /* byte 10 mask */ -#define TCDS_SCSI0_DUD0_BYTE11 0xff000000 /* byte 11 mask */ #define TCDS_SCSI0_DMA_DUD0 0x041008 /* DMA unaligned data[0] */ - -#define TCDS_SCSI0_DUD1_VALID00 0x01000000 /* byte 00 valid mask */ -#define TCDS_SCSI0_DUD1_VALID01 0x02000000 /* byte 01 valid mask */ -#define TCDS_SCSI0_DUD1_VALID10 0x04000000 /* byte 10 valid mask */ -#define TCDS_SCSI0_DUD1_BYTE00 0x000000ff /* byte 00 mask */ -#define TCDS_SCSI0_DUD1_BYTE01 0x0000ff00 /* byte 01 mask */ -#define TCDS_SCSI0_DUD1_BYTE10 0x00ff0000 /* byte 10 mask */ #define TCDS_SCSI0_DMA_DUD1 0x04100c /* DMA unaligned data[1] */ #define TCDS_SCSI1_DMA_ADDR 0x041100 /* DMA address */ @@ -110,9 +98,28 @@ #define TCDS_SCSI1_DMA_DUD0 0x041108 /* DMA unaligned data[0] */ #define TCDS_SCSI1_DMA_DUD1 0x04110c /* DMA unaligned data[1] */ -#define TCDS_REG(base, off) \ - (volatile u_int32_t *)TC_DENSE_TO_SPARSE((base) + (off)) +#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)); @@ -203,3 +210,5 @@ void tcds_scsi_reset __P((int)); #define SCSI_CIR phystok0seg(KN15AA_REG_SCSI_CIR) #define SCSI_IMER phystok0seg(KN15AA_REG_SCSI_IMER) + +#endif diff --git a/sys/arch/alpha/tc/tcdsvar.h b/sys/arch/alpha/tc/tcdsvar.h new file mode 100644 index 00000000000..5bee7191694 --- /dev/null +++ b/sys/arch/alpha/tc/tcdsvar.h @@ -0,0 +1,108 @@ +/* $NetBSD: tcdsvar.h,v 1.1 1995/12/20 00:40:41 cgd 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. + */ + +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 */ + int (*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 tcdev_attach_args tcdsda_tc; + struct tcds_slotconfig *tcdsda_sc; + u_int tcdsda_id; + u_int tcdsda_freq; +}; +#define tcdsda_modname tcdsda_tc.tcda_modname +#define tcdsda_slot tcdsda_tc.tcda_slot +#define tcdsda_offset tcdsda_tc.tcda_offset +#define tcdsda_addr tcdsda_tc.tcda_addr +#define tcdsda_cookie tcdsda_tc.tcda_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 *)); + +/* + * TCDS DMA functions (used the the 53c94 driver) + */ +void tcds_dma_reset __P((struct tcds_slotconfig *)); +void tcds_dma_enintr __P((struct tcds_slotconfig *)); +int tcds_dma_isintr __P((struct tcds_slotconfig *)); +void tcds_dma_start __P((struct tcds_slotconfig *, caddr_t *, + size_t *, int)); +int tcds_dmaintr __P((struct tcds_slotconfig *)); + +/* + * The TCDS (bus) cfdriver, so that subdevices can more + * easily tell what bus they're on. + */ +extern struct cfdriver tcdscd; |