diff options
Diffstat (limited to 'sys/arch/sun3')
87 files changed, 4782 insertions, 7870 deletions
diff --git a/sys/arch/sun3/dev/bw2.c b/sys/arch/sun3/dev/bw2.c index 6825a694da5..3207e8da415 100644 --- a/sys/arch/sun3/dev/bw2.c +++ b/sys/arch/sun3/dev/bw2.c @@ -1,4 +1,4 @@ -/* $NetBSD: bw2.c,v 1.5 1995/11/10 21:59:30 gwr Exp $ */ +/* $NetBSD: bw2.c,v 1.6 1996/03/17 02:03:41 thorpej Exp $ */ /* * Copyright (c) 1992, 1993 @@ -81,9 +81,13 @@ struct bw2_softc { static void bw2attach __P((struct device *, struct device *, void *)); static int bw2match __P((struct device *, void *, void *)); -struct cfdriver bwtwocd = { - NULL, "bwtwo", bw2match, bw2attach, - DV_DULL, sizeof(struct bw2_softc) }; +struct cfattach bwtwo_ca = { + sizeof(struct bw2_softc), bw2match, bw2attach +}; + +struct cfdriver bwtwo_cd = { + NULL, "bwtwo", DV_DULL +}; /* XXX we do not handle frame buffer interrupts */ @@ -184,7 +188,7 @@ bw2open(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= bwtwocd.cd_ndevs || bwtwocd.cd_devs[unit] == NULL) + if (unit >= bwtwo_cd.cd_ndevs || bwtwo_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -207,7 +211,7 @@ bw2ioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - struct bw2_softc *sc = bwtwocd.cd_devs[minor(dev)]; + struct bw2_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; return (fbioctlfb(&sc->sc_fb, cmd, data)); } @@ -221,7 +225,7 @@ bw2mmap(dev, off, prot) dev_t dev; int off, prot; { - struct bw2_softc *sc = bwtwocd.cd_devs[minor(dev)]; + struct bw2_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; if (off & PGOFSET) return (-1); diff --git a/sys/arch/sun3/dev/cg2.c b/sys/arch/sun3/dev/cg2.c index e89a0e7a461..765274e7594 100644 --- a/sys/arch/sun3/dev/cg2.c +++ b/sys/arch/sun3/dev/cg2.c @@ -1,4 +1,4 @@ -/* $NetBSD: cg2.c,v 1.4 1995/04/10 07:05:57 mycroft Exp $ */ +/* $NetBSD: cg2.c,v 1.5 1996/03/17 02:03:43 thorpej Exp $ */ /* * Copyright (c) 1992, 1993 @@ -94,9 +94,13 @@ struct cg2_softc { static void cg2attach __P((struct device *, struct device *, void *)); static int cg2match __P((struct device *, void *, void *)); -struct cfdriver cgtwocd = { - NULL, "cgtwo", cg2match, cg2attach, - DV_DULL, sizeof(struct cg2_softc) }; +struct cfattach cgtwo_ca = { + sizeof(struct cg2_softc), cg2match, cg2attach +}; + +struct cfdriver cgtwo_cd = { + NULL, "cgtwo", DV_DULL +}; /* frame buffer generic driver */ int cg2open(), cg2close(), cg2mmap(); @@ -196,7 +200,7 @@ cg2open(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgtwocd.cd_ndevs || cgtwocd.cd_devs[unit] == NULL) + if (unit >= cgtwo_cd.cd_ndevs || cgtwo_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -219,7 +223,7 @@ cg2ioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - struct cg2_softc *sc = cgtwocd.cd_devs[minor(dev)]; + struct cg2_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; return (fbioctlfb(&sc->sc_fb, cmd, data)); } @@ -233,7 +237,7 @@ cg2mmap(dev, off, prot) dev_t dev; int off, prot; { - struct cg2_softc *sc = cgtwocd.cd_devs[minor(dev)]; + struct cg2_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; int realoff; if (off & PGOFSET) diff --git a/sys/arch/sun3/dev/cg4.c b/sys/arch/sun3/dev/cg4.c index c28158302b4..99f4ed80872 100644 --- a/sys/arch/sun3/dev/cg4.c +++ b/sys/arch/sun3/dev/cg4.c @@ -1,4 +1,4 @@ -/* $NetBSD: cg4.c,v 1.6 1995/04/13 21:51:34 gwr Exp $ */ +/* $NetBSD: cg4.c,v 1.7 1996/03/17 02:03:45 thorpej Exp $ */ /* * Copyright (c) 1992, 1993 @@ -87,9 +87,13 @@ struct cg4_softc { static void cg4attach __P((struct device *, struct device *, void *)); static int cg4match __P((struct device *, void *, void *)); -struct cfdriver cgfourcd = { - NULL, "cgfour", cg4match, cg4attach, - DV_DULL, sizeof(struct cg4_softc) }; +struct cfattach cgfour_ca = { + sizeof(struct cg4_softc), cg4match, cg4attach +}; + +struct cfdriver cgfour_cd = { + NULL, "cgfour", DV_DULL +}; /* frame buffer generic driver */ int cg4open(), cg4close(), cg4mmap(); @@ -208,7 +212,7 @@ cg4open(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgfourcd.cd_ndevs || cgfourcd.cd_devs[unit] == NULL) + if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -231,7 +235,7 @@ cg4ioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - struct cg4_softc *sc = cgfourcd.cd_devs[minor(dev)]; + struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)]; return (fbioctlfb(&sc->sc_fb, cmd, data)); } @@ -260,7 +264,7 @@ cg4mmap(dev, off, prot) register int off; int prot; { - struct cg4_softc *sc = cgfourcd.cd_devs[minor(dev)]; + struct cg4_softc *sc = cgfour_cd.cd_devs[minor(dev)]; register int physbase; if (off & PGOFSET) diff --git a/sys/arch/sun3/dev/eeprom.c b/sys/arch/sun3/dev/eeprom.c index e0d096d0448..b8ecd04031b 100644 --- a/sys/arch/sun3/dev/eeprom.c +++ b/sys/arch/sun3/dev/eeprom.c @@ -1,4 +1,4 @@ -/* $NetBSD: eeprom.c,v 1.6 1995/05/24 20:47:41 gwr Exp $ */ +/* $NetBSD: eeprom.c,v 1.8 1996/03/26 15:16:06 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -55,12 +55,16 @@ static int ee_update(caddr_t buf, int off, int cnt); static char *eeprom_va; static int ee_busy, ee_want; -int eeprom_match __P((struct device *, void *vcf, void *args)); -void eeprom_attach __P((struct device *, struct device *, void *)); +static int eeprom_match __P((struct device *, void *vcf, void *args)); +static void eeprom_attach __P((struct device *, struct device *, void *)); -struct cfdriver eepromcd = { - NULL, "eeprom", eeprom_match, eeprom_attach, - DV_DULL, sizeof(struct device), 0 }; +struct cfattach eeprom_ca = { + sizeof(struct device), eeprom_match, eeprom_attach +}; + +struct cfdriver eeprom_cd = { + NULL, "eeprom", DV_DULL +}; /* Called very early by internal_configure. */ void eeprom_init() @@ -69,24 +73,38 @@ void eeprom_init() ee_console = ((struct eeprom *)eeprom_va)->eeConsole; } -int eeprom_match(parent, vcf, args) +static int +eeprom_match(parent, vcf, args) struct device *parent; void *vcf, *args; { struct cfdata *cf = vcf; struct confargs *ca = args; + int pa; /* This driver only supports one unit. */ if (cf->cf_unit != 0) return (0); + + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_EEPROM; + } else { + /* Validate the given PA. */ + if (pa != OBIO_EEPROM) + return (0); + } + if (pa != ca->ca_paddr) + return (0); + if (eeprom_va == NULL) return (0); - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_EEPROM; + return (1); } -void eeprom_attach(parent, self, args) +static void +eeprom_attach(parent, self, args) struct device *parent; struct device *self; void *args; diff --git a/sys/arch/sun3/dev/idprom.c b/sys/arch/sun3/dev/idprom.c index 53de1b57567..7dd09171120 100644 --- a/sys/arch/sun3/dev/idprom.c +++ b/sys/arch/sun3/dev/idprom.c @@ -1,4 +1,4 @@ -/* $NetBSD: idprom.c,v 1.10 1995/02/11 20:57:11 gwr Exp $ */ +/* $NetBSD: idprom.c,v 1.12 1996/03/26 15:16:09 gwr Exp $ */ /* * Copyright (c) 1993 Adam Glass @@ -51,51 +51,6 @@ extern long hostid; /* in kern_sysctl.c */ */ struct idprom identity_prom; -static int idprom_match __P((struct device *, void *vcf, void *args)); -static void idprom_attach __P((struct device *, struct device *, void *)); - -struct cfdriver idpromcd = { - NULL, "idprom", idprom_match, idprom_attach, - DV_DULL, sizeof(struct device), 0 }; - -int idprom_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; -{ - struct cfdata *cf = vcf; - - /* This driver only supports one unit. */ - if (cf->cf_unit != 0) - return (0); - - return (1); -} - -void idprom_attach(parent, self, args) - struct device *parent; - struct device *self; - void *args; -{ - struct idprom *idp; - union { - long l; - char c[4]; - } id; - - /* - * Construct the hostid from the idprom contents. - * This appears to be the way SunOS does it. - */ - idp = &identity_prom; - id.c[0] = idp->idp_machtype; - id.c[1] = idp->idp_serialnum[0]; - id.c[2] = idp->idp_serialnum[1]; - id.c[3] = idp->idp_serialnum[2]; - hostid = id.l; - - printf(" hostid 0x%x\n", id.l); -} - int idpromopen(dev, oflags, devtype, p) dev_t dev; int oflags; @@ -141,6 +96,10 @@ int idprom_init() struct idprom *idp; char *src, *dst; int len, x, xorsum; + union { + long l; + char c[4]; + } hid; idp = &identity_prom; dst = (char*)idp; @@ -162,6 +121,17 @@ int idprom_init() mon_printf("idprom_fetch: bad version=%d\n", idp->idp_format); return -1; } + + /* + * Construct the hostid from the idprom contents. + * This appears to be the way SunOS does it. + */ + hid.c[0] = idp->idp_machtype; + hid.c[1] = idp->idp_serialnum[0]; + hid.c[2] = idp->idp_serialnum[1]; + hid.c[3] = idp->idp_serialnum[2]; + hostid = hid.l; + return 0; } diff --git a/sys/arch/sun3/dev/if_ie.c b/sys/arch/sun3/dev/if_ie.c index 10ecdf0e7f1..eafc268cf9c 100644 --- a/sys/arch/sun3/dev/if_ie.c +++ b/sys/arch/sun3/dev/if_ie.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ie.c,v 1.6 1995/12/24 02:30:48 mycroft Exp $ */ +/* $NetBSD: if_ie.c,v 1.10 1996/03/26 22:04:14 gwr Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -147,8 +147,8 @@ #include <machine/pmap.h> #include "i82586.h" -#include "if_ie.h" -#include "if_ie_subr.h" +#include "if_iereg.h" +#include "if_ievar.h" static struct mbuf *last_not_for_us; @@ -178,8 +178,6 @@ static int command_and_wait __P((struct ie_softc *, int, void volatile *, int)); static void ierint __P((struct ie_softc *)); static void ietint __P((struct ie_softc *)); -static int ieget __P((struct ie_softc *, struct mbuf **, - struct ether_header *, int *)); static void setup_bufs __P((struct ie_softc *)); static int mc_setup __P((struct ie_softc *, void *)); static void mc_reset __P((struct ie_softc *)); @@ -190,13 +188,12 @@ int in_ierint = 0; int in_ietint = 0; #endif -void ie_attach(); -struct cfdriver iecd = { - NULL, "ie", ie_md_match, ie_attach, - DV_IFNET, sizeof(struct ie_softc), +struct cfdriver ie_cd = { + NULL, "ie", DV_IFNET }; + /* * address generation macros * MK_24 = KVA -> 24 bit address in SUN byte order @@ -265,21 +262,32 @@ ie_ack(sc, mask) * then modified beyond recognition... */ void -ie_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +ie_attach(sc) + struct ie_softc *sc; { - struct ie_softc *sc = (void *) self; struct ifnet *ifp = &sc->sc_if; + int off; - /* - * Do machine-dependent parts of attach. - */ - ie_md_attach(parent, self, aux); + /* MD code has done its part before calling this. */ printf(" hwaddr %s\n", ether_sprintf(sc->sc_addr)); + /* Allocate from end of buffer space for ISCP, SCB */ + off = sc->buf_area_sz; + off &= ~3; + + /* Space for ISCP */ + off -= sizeof(*sc->iscp); + sc->iscp = (volatile void *) (sc->buf_area + off); + + /* Space for SCB */ + off -= sizeof(*sc->scb); + sc->scb = (volatile void *) (sc->buf_area + off); + + /* Remainder is for buffers, etc. */ + sc->buf_area_sz = off; + /* - * Setup for transmit/receive + * Setup RAM for transmit/receive */ if (ie_setupram(sc) == 0) { printf(": RAM CONFIG FAILED!\n"); @@ -291,7 +299,7 @@ ie_attach(parent, self, aux) * Initialize and attach S/W interface */ ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = iecd.cd_name; + ifp->if_name = ie_cd.cd_name; ifp->if_start = iestart; ifp->if_ioctl = ieioctl; ifp->if_watchdog = iewatchdog; @@ -314,7 +322,7 @@ void iewatchdog(unit) short unit; { - struct ie_softc *sc = iecd.cd_devs[unit]; + struct ie_softc *sc = ie_cd.cd_devs[unit]; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -500,18 +508,26 @@ ietint(sc) /* * Compare two Ether/802 addresses for equality, inlined and * unrolled for speed. I'd love to have an inline assembler - * version of this... + * version of this... XXX: Who wanted that? mycroft? + * I wrote one, but the following is just as efficient. + * This expands to 10 short m68k instructions! -gwr + * Note: use this like bcmp() */ -static inline int -ether_equal(one, two) +static inline u_short +ether_cmp(one, two) u_char *one, *two; { + register u_short *a = (u_short *) one; + register u_short *b = (u_short *) two; + register u_short diff; - if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] || - one[3] != two[3] || one[4] != two[4] || one[5] != two[5]) - return 0; - return 1; + diff = *a++ - *b++; + diff |= *a++ - *b++; + diff |= *a++ - *b++; + + return (diff); } +#define ether_equal !ether_cmp /* * Check for a valid address. to_bpf is filled in with one of the following: @@ -1026,7 +1042,7 @@ void iestart(ifp) struct ifnet *ifp; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; struct mbuf *m0, *m; u_char *buffer; u_short len; @@ -1545,7 +1561,7 @@ ieioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ie_cd.cd_devs[ifp->if_unit]; struct ifaddr *ifa = (struct ifaddr *) data; struct ifreq *ifr = (struct ifreq *) data; int s, error = 0; diff --git a/sys/arch/sun3/dev/if_ie.h b/sys/arch/sun3/dev/if_ie.h index 5e5ed58fe9c..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_ie.h +++ b/sys/arch/sun3/dev/if_ie.h @@ -1,163 +0,0 @@ -/* $NetBSD: if_ie.h,v 1.1 1994/12/12 18:59:09 gwr Exp $ */ - -/* - * if_sunie.h - * - * sun's ie interface - */ - -/* - * programming notes: - * - * the ie chip operates in a 24 bit address space. - * - * most ie interfaces appear to be divided into two parts: - * - generic 586 stuff - * - board specific - * - * generic: - * the generic stuff of the ie chip is all done with data structures - * that live in the chip's memory address space. the chip expects - * its main data structure (the sys conf ptr -- SCP) to be at a fixed - * address in its 24 bit space: 0xfffff4 - * - * the SCP points to another structure called the ISCP. - * the ISCP points to another structure called the SCB. - * the SCB has a status field, a linked list of "commands", and - * a linked list of "receive buffers". these are data structures that - * live in memory, not registers. - * - * board: - * to get the chip to do anything, you first put a command in the - * command data structure list. then you have to signal "attention" - * to the chip to get it to look at the command. how you - * signal attention depends on what board you have... on PC's - * there is an i/o port number to do this, on sun's there is a - * register bit you toggle. - * - * to get data from the chip you program it to interrupt... - * - * - * sun issues: - * - * there are 3 kinds of sun "ie" interfaces: - * 1 - a VME/multibus card - * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's) - * 3 - another VME board called the 3E - * - * the VME boards lives in vme16 space. only 16 and 8 bit accesses - * are allowed, so functions that copy data must be aware of this. - * - * the chip is an intel chip. this means that the byte order - * on all the "short"s in the chip's data structures is wrong. - * so, constants described in the intel docs are swapped for the sun. - * that means that any buffer pointers you give the chip must be - * swapped to intel format. yuck. - * - * VME/multibus interface: - * for the multibus interface the board ignores the top 4 bits - * of the chip address. the multibus interface seems to have its - * own MMU like page map (without protections or valid bits, etc). - * there are 256 pages of physical memory on the board (each page - * is 1024 bytes). there are 1024 slots in the page map. so, - * a 1024 byte page takes up 10 bits of address for the offset, - * and if there are 1024 slots in the page that is another 10 bits - * of the address. that makes a 20 bit address, and as stated - * earlier the board ignores the top 4 bits, so that accounts - * for all 24 bits of address. - * - * note that the last entry of the page map maps the top of the - * 24 bit address space and that the SCP is supposed to be at - * 0xfffff4 (taking into account allignment). so, - * for multibus, that entry in the page map has to be used for the SCP. - * - * the page map effects BOTH how the ie chip sees the - * memory, and how the host sees it. - * - * the page map is part of the "register" area of the board - * - * on-board interface: - * - * <fill in useful info later> - * - * - * VME3E interface: - * - * <fill in useful info later> - * - */ - -/* - * PART 1: VME/multibus defs - */ -#define IEVME_PAGESIZE 1024 /* bytes */ -#define IEVME_PAGSHIFT 10 /* bits */ -#define IEVME_NPAGES 256 /* number of pages on chip */ -#define IEVME_MAPSZ 1024 /* number of entries in the map */ - -/* - * PTE for the page map - */ -#define IEVME_SBORDR 0x8000 /* sun byte order */ -#define IEVME_IBORDR 0x0000 /* intel byte ordr */ - -#define IEVME_P2MEM 0x2000 /* memory is on P2 */ -#define IEVME_OBMEM 0x0000 /* memory is on board */ - -#define IEVME_PGMASK 0x0fff /* gives the physical page frame number */ - -struct ievme { - u_short pgmap[IEVME_MAPSZ]; - u_short xxx[32]; /* prom */ - u_short status; /* see below for bits */ - u_short xxx2; /* filler */ - u_short pectrl; /* parity control (see below) */ - u_short peaddr; /* low 16 bits of address */ -}; - -/* - * status bits - */ -#define IEVME_RESET 0x8000 /* reset board */ -#define IEVME_ONAIR 0x4000 /* go out of loopback 'on-air' */ -#define IEVME_ATTEN 0x2000 /* attention */ -#define IEVME_IENAB 0x1000 /* interrupt enable */ -#define IEVME_PEINT 0x0800 /* parity error interrupt enable */ -#define IEVME_PERR 0x0200 /* parity error flag */ -#define IEVME_INT 0x0100 /* interrupt flag */ -#define IEVME_P2EN 0x0020 /* enable p2 bus */ -#define IEVME_256K 0x0010 /* 256kb rams */ -#define IEVME_HADDR 0x000f /* mask for bits 17-20 of address */ - -/* - * parity control - */ -#define IEVME_PARACK 0x0100 /* parity error ack */ -#define IEVME_PARSRC 0x0080 /* parity error source */ -#define IEVME_PAREND 0x0040 /* which end of the data got the error */ -#define IEVME_PARADR 0x000f /* mask to get bits 17-20 of parity address */ - - -/* - * PART 2: the on-board interface - */ -struct ieob { - u_char obctrl; -}; -#define IEOB_NORSET 0x80 /* don't reset the board */ -#define IEOB_ONAIR 0x40 /* put us on the air */ -#define IEOB_ATTEN 0x20 /* attention! */ -#define IEOB_IENAB 0x10 /* interrupt enable */ -#define IEOB_XXXXX 0x08 /* free bit */ -#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */ -#define IEOB_BUSERR 0x02 /* bus error */ -#define IEOB_INT 0x01 /* interrupt */ - -/* - * PART 3: the 3E board - */ - -/* - * not supported (yet?) - */ - diff --git a/sys/arch/sun3/dev/if_ie_obio.c b/sys/arch/sun3/dev/if_ie_obio.c new file mode 100644 index 00000000000..a163ea497ab --- /dev/null +++ b/sys/arch/sun3/dev/if_ie_obio.c @@ -0,0 +1,214 @@ +/* $NetBSD: if_ie_obio.c,v 1.2 1996/03/26 22:04:19 gwr Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * 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 Gordon Ross + * 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. + */ + +/* + * Machine-dependent glue for the Intel Ethernet (ie) driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/dvma.h> +#include <machine/isr.h> +#include <machine/obio.h> +#include <machine/idprom.h> +#include <machine/vmparam.h> + +#include "i82586.h" +#include "if_iereg.h" +#include "if_ievar.h" + +static void ie_obreset __P((struct ie_softc *)); +static void ie_obattend __P((struct ie_softc *)); +static void ie_obrun __P((struct ie_softc *)); + +/* + * New-style autoconfig attachment + */ + +static int ie_obio_match __P((struct device *, void *, void *)); +static void ie_obio_attach __P((struct device *, struct device *, void *)); + +struct cfattach ie_obio_ca = { + sizeof(struct ie_softc), ie_obio_match, ie_obio_attach +}; + + +static int +ie_obio_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + int pa, x; + +#ifdef DIAGNOSTIC + if (ca->ca_bustype != BUS_OBIO) { + printf("ie_obio_match: bustype %d?\n", ca->ca_bustype); + return (0); + } +#endif + + /* + * OBIO match functions may be called for every possible + * physical address, so match only our physical address. + */ + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_INTEL_ETHER; + } + if (pa != ca->ca_paddr) + return (0); + + x = bus_peek(ca->ca_bustype, ca->ca_paddr, 1); + return (x != -1); +} + +void +ie_obio_attach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + struct ie_softc *sc = (void *) self; + struct cfdata *cf = self->dv_cfdata; + struct confargs *ca = args; + int intpri; + + /* Default interrupt level. */ + if ((intpri = cf->cf_intpri) == -1) + intpri = 3; + printf(" level %d", intpri); + + sc->hard_type = IE_OBIO; + sc->reset_586 = ie_obreset; + sc->chan_attn = ie_obattend; + sc->run_586 = ie_obrun; + sc->sc_bcopy = bcopy; + sc->sc_bzero = bzero; + + /* + * The on-board "ie" just uses main memory, so + * we can choose how much memory to give it. + * XXX: Would like to use less than 64K... + */ + sc->sc_msize = 0x8000; /* MEMSIZE 32K */ + + /* Map in the control registers. */ + sc->sc_reg = obio_alloc(ca->ca_paddr, OBIO_INTEL_ETHER_SIZE); + + /* Allocate "shared" memory (in DVMA space). */ + sc->sc_maddr = dvma_malloc(sc->sc_msize); + if (sc->sc_maddr == NULL) + panic(": not enough dvma space"); + + /* + * The on-board "ie" is wired-up such that its + * memory access goes to the high 16 megabytes + * of the on-board memory space (on-board DVMA). + */ + sc->sc_iobase = (caddr_t)DVMA_OBIO_SLAVE_BASE; + + /* + * Set the System Configuration Pointer (SCP). + * Its location is system-dependent because the + * i82586 reads it from a fixed physical address. + * On this hardware, the i82586 address maps to + * a 24-bit offset in on-board DVMA space. The + * SCP happens to fall in a page used by the + * PROM monitor, which the PROM knows about. + */ + sc->scp = (volatile void *) (sc->sc_iobase + IE_SCP_ADDR); + + /* + * The rest of ram is used for buffers. + */ + sc->buf_area = sc->sc_maddr; + sc->buf_area_sz = sc->sc_msize; + + /* Set the ethernet address. */ + idprom_etheraddr(sc->sc_addr); + + /* Do machine-independent parts of attach. */ + ie_attach(sc); + + /* Install interrupt handler. */ + isr_add_autovect(ie_intr, (void *)sc, intpri); +} + + +/* + * onboard ie support + */ +void +ie_obreset(sc) + struct ie_softc *sc; +{ + volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; + ieo->obctrl = 0; + delay(100); /* XXX could be shorter? */ + ieo->obctrl = IEOB_NORSET; +} +void +ie_obattend(sc) + struct ie_softc *sc; +{ + volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; + + ieo->obctrl |= IEOB_ATTEN; /* flag! */ + ieo->obctrl &= ~IEOB_ATTEN; /* down. */ +} + +void +ie_obrun(sc) + struct ie_softc *sc; +{ + volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; + + ieo->obctrl |= (IEOB_ONAIR|IEOB_IENAB|IEOB_NORSET); +} + diff --git a/sys/arch/sun3/dev/if_ie_subr.c b/sys/arch/sun3/dev/if_ie_subr.c index 71af7166f5e..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_ie_subr.c +++ b/sys/arch/sun3/dev/if_ie_subr.c @@ -1,366 +0,0 @@ -/* $NetBSD: if_ie_subr.c,v 1.7 1995/09/26 04:02:04 gwr Exp $ */ - -/* - * Copyright (c) 1994 Gordon W. Ross - * 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 Gordon Ross - * 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. - */ - -/* - * Machine-dependent glue for the Intel Ethernet (ie) driver. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/device.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <net/if.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/if_ether.h> -#endif - -#include <machine/autoconf.h> -#include <machine/cpu.h> -#include <machine/dvma.h> -#include <machine/isr.h> -#include <machine/obio.h> -#include <machine/idprom.h> -#include <machine/vmparam.h> - -#include "i82586.h" -#include "if_ie.h" -#include "if_ie_subr.h" - -static void ie_obreset __P((struct ie_softc *)); -static void ie_obattend __P((struct ie_softc *)); -static void ie_obrun __P((struct ie_softc *)); -static void ie_vmereset __P((struct ie_softc *)); -static void ie_vmeattend __P((struct ie_softc *)); -static void ie_vmerun __P((struct ie_softc *)); - -/* - * zero/copy functions: OBIO can use the normal functions, but VME - * must do only byte or half-word (16 bit) accesses... - */ -static void wcopy(), wzero(); - -int -ie_md_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; -{ - struct cfdata *cf = vcf; - struct confargs *ca = args; - int x, sz; - - switch (ca->ca_bustype) { - - case BUS_OBIO: - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_INTEL_ETHER; - sz = 1; - break; - - case BUS_VME16: - /* No default VME address. */ - if (ca->ca_paddr == -1) - return(0); - sz = 2; - break; - - default: - return (0); - } - - /* Default interrupt level. */ - if (ca->ca_intpri == -1) - ca->ca_intpri = 3; - - x = bus_peek(ca->ca_bustype, ca->ca_paddr, sz); - return (x != -1); -} - -void -ie_md_attach(parent, self, args) - struct device *parent; - struct device *self; - void *args; -{ - struct ie_softc *sc = (void *) self; - struct confargs *ca = args; - caddr_t mem, reg; - - /* - * *note*: we don't detect the difference between a VME3E and - * a multibus/vme card. if you want to use a 3E you'll have - * to fix this. - */ - - switch (ca->ca_bustype) { - case BUS_OBIO: - sc->hard_type = IE_OBIO; - sc->reset_586 = ie_obreset; - sc->chan_attn = ie_obattend; - sc->run_586 = ie_obrun; - sc->sc_bcopy = bcopy; - sc->sc_bzero = bzero; - sc->sc_iobase = (caddr_t)DVMA_OBIO_SLAVE_BASE; - sc->sc_msize = MEMSIZE; - - /* Map in the control register. */ - reg = obio_alloc(ca->ca_paddr, OBIO_INTEL_ETHER_SIZE); - if (reg == NULL) - panic(": not enough obio space\n"); - sc->sc_reg = reg; - - /* Allocate "shared" memory (DVMA space). */ - mem = dvma_malloc(sc->sc_msize); - if (mem == NULL) - panic(": not enough dvma space"); - sc->sc_maddr = mem; - - /* This is a FIXED address, in a page left by the PROM. */ - sc->scp = (volatile struct ie_sys_conf_ptr *) - (sc->sc_iobase + IE_SCP_ADDR); - - /* Install interrupt handler. */ - isr_add_autovect(ie_intr, (void *)sc, ca->ca_intpri); - - break; - - case BUS_VME16: { - volatile struct ievme *iev; - u_long rampaddr; - int lcv; - - sc->hard_type = IE_VME; - sc->reset_586 = ie_vmereset; - sc->chan_attn = ie_vmeattend; - sc->run_586 = ie_vmerun; - sc->sc_bcopy = wcopy; - sc->sc_bzero = wzero; - sc->sc_msize = MEMSIZE; - sc->sc_reg = bus_mapin(ca->ca_bustype, ca->ca_paddr, - sizeof(struct ievme)); - - iev = (volatile struct ievme *) sc->sc_reg; - /* top 12 bits */ - rampaddr = ca->ca_paddr & 0xfff00000; - /* 4 more */ - rampaddr |= ((iev->status & IEVME_HADDR) << 16); - sc->sc_maddr = bus_mapin(ca->ca_bustype, rampaddr, sc->sc_msize); - sc->sc_iobase = sc->sc_maddr; - iev->pectrl = iev->pectrl | IEVME_PARACK; /* clear to start */ - - sc->scp = (volatile struct ie_sys_conf_ptr *) - (sc->sc_iobase + (IE_SCP_ADDR & (IEVME_PAGESIZE - 1))); - - /* - * set up mappings, direct map except for last page - * which is mapped at zero and at high address (for - * scp), zero ram - */ - - for (lcv = 0; lcv < IEVME_MAPSZ - 1; lcv++) - iev->pgmap[lcv] = IEVME_SBORDR | IEVME_OBMEM | lcv; - iev->pgmap[IEVME_MAPSZ - 1] = IEVME_SBORDR | IEVME_OBMEM | 0; - (sc->sc_bzero)(sc->sc_maddr, sc->sc_msize); - - isr_add_vectored(ie_intr, (void *)sc, - ca->ca_intpri, - ca->ca_intvec); - break; - } - - default: - printf("unknown\n"); - return; - } - - /* - * set up pointers to data structures and buffer area. - */ - sc->iscp = (volatile struct ie_int_sys_conf_ptr *) - sc->sc_maddr; - sc->scb = (volatile struct ie_sys_ctl_block *) - sc->sc_maddr + sizeof(struct ie_int_sys_conf_ptr); - - /* - * rest of first page is unused, rest of ram - * for buffers - */ - sc->buf_area = sc->sc_maddr + IEVME_PAGESIZE; - sc->buf_area_sz = sc->sc_msize - IEVME_PAGESIZE; - - idprom_etheraddr(sc->sc_addr); /* ethernet addr */ -} - - -/* - * MULTIBUS/VME support - */ -void -ie_vmereset(sc) - struct ie_softc *sc; -{ - volatile struct ievme *iev = (struct ievme *) sc->sc_reg; - iev->status = IEVME_RESET; - delay(100); /* XXX could be shorter? */ - iev->status = 0; -} - -void -ie_vmeattend(sc) - struct ie_softc *sc; -{ - volatile struct ievme *iev = (struct ievme *) sc->sc_reg; - - iev->status |= IEVME_ATTEN; /* flag! */ - iev->status &= ~IEVME_ATTEN; /* down. */ -} - -void -ie_vmerun(sc) - struct ie_softc *sc; -{ - volatile struct ievme *iev = (struct ievme *) sc->sc_reg; - - iev->status |= (IEVME_ONAIR | IEVME_IENAB | IEVME_PEINT); -} - -/* - * onboard ie support - */ -void -ie_obreset(sc) - struct ie_softc *sc; -{ - volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; - ieo->obctrl = 0; - delay(100); /* XXX could be shorter? */ - ieo->obctrl = IEOB_NORSET; -} -void -ie_obattend(sc) - struct ie_softc *sc; -{ - volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; - - ieo->obctrl |= IEOB_ATTEN; /* flag! */ - ieo->obctrl &= ~IEOB_ATTEN; /* down. */ -} - -void -ie_obrun(sc) - struct ie_softc *sc; -{ - volatile struct ieob *ieo = (struct ieob *) sc->sc_reg; - - ieo->obctrl |= (IEOB_ONAIR|IEOB_IENAB|IEOB_NORSET); -} - -/* - * wcopy/wzero - like bcopy/bzero but largest access is 16-bits, - * and also does byte swaps... - * XXX - Would be nice to have asm versions in some library... - */ - -static void -wzero(vb, l) - void *vb; - u_int l; -{ - u_char *b = vb; - u_char *be = b + l; - u_short *sp; - - if (l == 0) - return; - - /* front, */ - if ((u_long)b & 1) - *b++ = 0; - - /* back, */ - if (b != be && ((u_long)be & 1) != 0) { - be--; - *be = 0; - } - - /* and middle. */ - sp = (u_short *)b; - while (sp != (u_short *)be) - *sp++ = 0; -} - -static void -wcopy(vb1, vb2, l) - const void *vb1; - void *vb2; - u_int l; -{ - const u_char *b1e, *b1 = vb1; - u_char *b2 = vb2; - u_short *sp; - int bstore = 0; - - if (l == 0) - return; - - /* front, */ - if ((u_long)b1 & 1) { - *b2++ = *b1++; - l--; - } - - /* middle, */ - sp = (u_short *)b1; - b1e = b1 + l; - if (l & 1) - b1e--; - bstore = (u_long)b2 & 1; - - while (sp < (u_short *)b1e) { - if (bstore) { - b2[1] = *sp & 0xff; - b2[0] = *sp >> 8; - } else - *((short *)b2) = *sp; - sp++; - b2 += 2; - } - - /* and back. */ - if (l & 1) - *b2 = *b1e; -} diff --git a/sys/arch/sun3/dev/if_ie_subr.h b/sys/arch/sun3/dev/if_ie_subr.h index ed673881948..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_ie_subr.h +++ b/sys/arch/sun3/dev/if_ie_subr.h @@ -1,124 +0,0 @@ -/* $NetBSD: if_ie_subr.h,v 1.5 1995/02/13 22:23:56 gwr Exp $ */ - -/* - * Machine-dependent glue for the Intel Ethernet (ie) driver. - */ - -#define B_PER_F 3 /* number of buffers to allocate per frame */ -#define MXFRAMES 300 /* max number of frames to allow for receive */ -#define MXRXBUF (MXFRAMES*B_PER_F) /* max number of buffers to allocate */ -#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */ -#define NTXBUF 2 /* number of transmit buffer/command pairs */ -#define IE_TBUF_SIZE 1536 /* length of transmit buffer */ - -#define MEMSIZE 0x10000 - -enum ie_hardware { - IE_VME, /* multibus to VME ie card */ - IE_OBIO, /* on board */ - IE_VME3E, /* sun 3e VME card */ - IE_UNKNOWN -}; - -/* - * Ethernet status, per interface. - * - * hardware addresses/sizes to know (all KVA): - * sc_iobase = base of chip's 24 bit address space - * sc_maddr = base address of chip RAM as stored in ie_base of iscp - * sc_msize = size of chip's RAM - * sc_reg = address of card dependent registers - * - * the chip uses two types of pointers: 16 bit and 24 bit - * 16 bit pointers are offsets from sc_maddr/ie_base - * KVA(16 bit offset) = offset + sc_maddr - * 24 bit pointers are offset from sc_iobase in KVA - * KVA(24 bit address) = address + sc_iobase - * - * on the vme/multibus we have the page map to control where ram appears - * in the address space. we choose to have RAM start at 0 in the - * 24 bit address space. this means that sc_iobase == sc_maddr! - * to get the phyiscal address of the board's RAM you must take the - * top 12 bits of the physical address of the register address - * and or in the 4 bits from the status word as bits 17-20 (remember that - * the board ignores the chip's top 4 address lines). - * For example: - * if the register is @ 0xffe88000, then the top 12 bits are 0xffe00000. - * to get the 4 bits from the the status word just do status & IEVME_HADDR. - * suppose the value is "4". Then just shift it left 16 bits to get - * it into bits 17-20 (e.g. 0x40000). Then or it to get the - * address of RAM (in our example: 0xffe40000). see the attach routine! - * - * In the onboard ie interface, the 24 bit address space is hardwired - * to be 0xff000000 -> 0xffffffff of KVA. this means that sc_iobase - * will be 0xff000000. sc_maddr will be where ever we allocate RAM - * in KVA. note that since the SCP is at a fixed address it means - * that we have to use some memory at a fixed KVA for the SCP. - * The Sun PROM leaves a page for us at the end of KVA space. - */ -struct ie_softc { - struct device sc_dev; /* device structure */ - - struct arpcom sc_arpcom;/* system arpcom structure */ -#define sc_if sc_arpcom.ac_if /* network-visible interface */ -#define sc_addr sc_arpcom.ac_enaddr /* hardware Ethernet address */ - - caddr_t sc_iobase; /* KVA of base of 24bit addr space */ - caddr_t sc_maddr; /* KVA of base of chip's RAM */ - u_int sc_msize; /* how much RAM we have/use */ - caddr_t sc_reg; /* KVA of card's register */ - - enum ie_hardware hard_type; /* card type */ - void (*reset_586)(); /* card dependent reset function */ - void (*chan_attn)(); /* card dependent attn function */ - void (*run_586)(); /* card dependent "go on-line" function */ - void (*sc_bcopy) __P((const void *, void *, u_int)); - void (*sc_bzero) __P((void *, u_int)); - - int want_mcsetup; /* flag for multicast setup */ - int promisc; /* are we in promisc mode? */ - - /* - * pointers to the 3 major control structures - */ - volatile struct ie_sys_conf_ptr *scp; - volatile struct ie_int_sys_conf_ptr *iscp; - volatile struct ie_sys_ctl_block *scb; - - /* - * pointer and size of a block of KVA where the buffers - * are to be allocated from - */ - caddr_t buf_area; - int buf_area_sz; - - /* - * the actual buffers (recv and xmit) - */ - volatile struct ie_recv_frame_desc *rframes[MXFRAMES]; - volatile struct ie_recv_buf_desc *rbuffs[MXRXBUF]; - volatile char *cbuffs[MXRXBUF]; - int rfhead, rftail, rbhead, rbtail; - - volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF]; - volatile struct ie_xmit_buf *xmit_buffs[NTXBUF]; - u_char *xmit_cbuffs[NTXBUF]; - int xmit_busy; - int xmit_free; - int xchead, xctail; - - struct ie_en_addr mcast_addrs[MAXMCAST + 1]; - int mcast_count; - - int nframes; /* number of frames in use */ - int nrxbuf; /* number of recv buffs in use */ - -#ifdef IEDEBUG - int sc_debug; -#endif -}; - - -extern int ie_md_match(struct device *, void *, void *args); -extern void ie_md_attach(struct device *, struct device *, void *); -extern int ie_intr(void *); diff --git a/sys/arch/sun3/dev/if_ie_vmes.c b/sys/arch/sun3/dev/if_ie_vmes.c new file mode 100644 index 00000000000..575f0e3c0d3 --- /dev/null +++ b/sys/arch/sun3/dev/if_ie_vmes.c @@ -0,0 +1,305 @@ +/* $NetBSD: if_ie_vmes.c,v 1.2 1996/03/26 22:04:28 gwr Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * 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 Gordon Ross + * 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. + */ + +/* + * Machine-dependent glue for the Intel Ethernet (ie) driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/dvma.h> +#include <machine/isr.h> +#include <machine/idprom.h> +#include <machine/vmparam.h> + +#include "i82586.h" +#include "if_iereg.h" +#include "if_ievar.h" + +static void ie_vmereset __P((struct ie_softc *)); +static void ie_vmeattend __P((struct ie_softc *)); +static void ie_vmerun __P((struct ie_softc *)); + +/* + * zero/copy functions: OBIO can use the normal functions, but VME + * must do only byte or half-word (16 bit) accesses... + */ +static void wcopy(), wzero(); + +/* + * New-style autoconfig attachment + */ + +static int ie_vmes_match __P((struct device *, void *, void *)); +static void ie_vmes_attach __P((struct device *, struct device *, void *)); + +struct cfattach ie_vmes_ca = { + sizeof(struct ie_softc), ie_vmes_match, ie_vmes_attach +}; + + +static int +ie_vmes_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct confargs *ca = args; + int x, sz; + +#ifdef DIAGNOSTIC + if (ca->ca_bustype != BUS_VME16) { + printf("ie_vmes_match: bustype %d?\n", ca->ca_bustype); + return (0); + } +#endif + + /* No default VME address. */ + if (ca->ca_paddr == -1) + return(0); + + /* Default interrupt level. */ + if (ca->ca_intpri == -1) + ca->ca_intpri = 3; + + x = bus_peek(ca->ca_bustype, ca->ca_paddr, 2); + return (x != -1); +} + +/* + * *note*: we don't detect the difference between a VME3E and + * a multibus/vme card. if you want to use a 3E you'll have + * to fix this. + */ +void +ie_vmes_attach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + struct ie_softc *sc = (void *) self; + struct confargs *ca = args; + volatile struct ievme *iev; + u_long rampaddr; + int lcv, off; + + sc->hard_type = IE_VME; + sc->reset_586 = ie_vmereset; + sc->chan_attn = ie_vmeattend; + sc->run_586 = ie_vmerun; + sc->sc_bcopy = wcopy; + sc->sc_bzero = wzero; + + /* + * There is 64K of memory on the VME board. + * (determined by hardware - NOT configurable!) + */ + sc->sc_msize = 0x10000; /* MEMSIZE 64K */ + + /* Map in the board control regs. */ + sc->sc_reg = bus_mapin(ca->ca_bustype, ca->ca_paddr, + sizeof(struct ievme)); + iev = (volatile struct ievme *) sc->sc_reg; + + /* + * Find and map in the board memory. + */ + /* top 12 bits */ + rampaddr = ca->ca_paddr & 0xfff00000; + /* 4 more */ + rampaddr |= ((iev->status & IEVME_HADDR) << 16); + sc->sc_maddr = bus_mapin(ca->ca_bustype, rampaddr, sc->sc_msize); + + /* + * On this hardware, the i82586 address is just + * masked to 16 bits, so sc_iobase == sc_maddr + */ + sc->sc_iobase = sc->sc_maddr; + + /* + * Set up on-board mapping registers for linear map. + */ + iev->pectrl |= IEVME_PARACK; /* clear to start */ + for (lcv = 0; lcv < IEVME_MAPSZ; lcv++) + iev->pgmap[lcv] = IEVME_SBORDR | IEVME_OBMEM | lcv; + (sc->sc_bzero)(sc->sc_maddr, sc->sc_msize); + + /* + * Set the System Configuration Pointer (SCP). + * Its location is system-dependent because the + * i82586 reads it from a fixed physical address. + * On this hardware, the i82586 address is just + * masked down to 16 bits, so the SCP is found + * at the end of the RAM on the VME board. + */ + off = IE_SCP_ADDR & 0xFFFF; + sc->scp = (volatile void *) (sc->sc_maddr + off); + + /* + * The rest of ram is used for buffers, etc. + */ + sc->buf_area = sc->sc_maddr; + sc->buf_area_sz = off; + + /* Set the ethernet address. */ + idprom_etheraddr(sc->sc_addr); + + /* Do machine-independent parts of attach. */ + ie_attach(sc); + + /* Install interrupt handler. */ + isr_add_vectored(ie_intr, (void *)sc, + ca->ca_intpri, ca->ca_intvec); +} + + +/* + * MULTIBUS/VME support + */ +void +ie_vmereset(sc) + struct ie_softc *sc; +{ + volatile struct ievme *iev = (struct ievme *) sc->sc_reg; + iev->status = IEVME_RESET; + delay(100); /* XXX could be shorter? */ + iev->status = 0; +} + +void +ie_vmeattend(sc) + struct ie_softc *sc; +{ + volatile struct ievme *iev = (struct ievme *) sc->sc_reg; + + iev->status |= IEVME_ATTEN; /* flag! */ + iev->status &= ~IEVME_ATTEN; /* down. */ +} + +void +ie_vmerun(sc) + struct ie_softc *sc; +{ + volatile struct ievme *iev = (struct ievme *) sc->sc_reg; + + iev->status |= (IEVME_ONAIR | IEVME_IENAB | IEVME_PEINT); +} + +/* + * wcopy/wzero - like bcopy/bzero but largest access is 16-bits, + * and also does byte swaps... + * XXX - Would be nice to have asm versions in some library... + */ + +static void +wzero(vb, l) + void *vb; + u_int l; +{ + u_char *b = vb; + u_char *be = b + l; + u_short *sp; + + if (l == 0) + return; + + /* front, */ + if ((u_long)b & 1) + *b++ = 0; + + /* back, */ + if (b != be && ((u_long)be & 1) != 0) { + be--; + *be = 0; + } + + /* and middle. */ + sp = (u_short *)b; + while (sp != (u_short *)be) + *sp++ = 0; +} + +static void +wcopy(vb1, vb2, l) + const void *vb1; + void *vb2; + u_int l; +{ + const u_char *b1e, *b1 = vb1; + u_char *b2 = vb2; + u_short *sp; + int bstore = 0; + + if (l == 0) + return; + + /* front, */ + if ((u_long)b1 & 1) { + *b2++ = *b1++; + l--; + } + + /* middle, */ + sp = (u_short *)b1; + b1e = b1 + l; + if (l & 1) + b1e--; + bstore = (u_long)b2 & 1; + + while (sp < (u_short *)b1e) { + if (bstore) { + b2[1] = *sp & 0xff; + b2[0] = *sp >> 8; + } else + *((short *)b2) = *sp; + sp++; + b2 += 2; + } + + /* and back. */ + if (l & 1) + *b2 = *b1e; +} diff --git a/sys/arch/sun3/dev/if_iereg.h b/sys/arch/sun3/dev/if_iereg.h new file mode 100644 index 00000000000..5986a89c182 --- /dev/null +++ b/sys/arch/sun3/dev/if_iereg.h @@ -0,0 +1,163 @@ +/* $NetBSD: if_iereg.h,v 1.1 1994/12/12 18:59:09 gwr Exp $ */ + +/* + * if_sunie.h + * + * sun's ie interface + */ + +/* + * programming notes: + * + * the ie chip operates in a 24 bit address space. + * + * most ie interfaces appear to be divided into two parts: + * - generic 586 stuff + * - board specific + * + * generic: + * the generic stuff of the ie chip is all done with data structures + * that live in the chip's memory address space. the chip expects + * its main data structure (the sys conf ptr -- SCP) to be at a fixed + * address in its 24 bit space: 0xfffff4 + * + * the SCP points to another structure called the ISCP. + * the ISCP points to another structure called the SCB. + * the SCB has a status field, a linked list of "commands", and + * a linked list of "receive buffers". these are data structures that + * live in memory, not registers. + * + * board: + * to get the chip to do anything, you first put a command in the + * command data structure list. then you have to signal "attention" + * to the chip to get it to look at the command. how you + * signal attention depends on what board you have... on PC's + * there is an i/o port number to do this, on sun's there is a + * register bit you toggle. + * + * to get data from the chip you program it to interrupt... + * + * + * sun issues: + * + * there are 3 kinds of sun "ie" interfaces: + * 1 - a VME/multibus card + * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's) + * 3 - another VME board called the 3E + * + * the VME boards lives in vme16 space. only 16 and 8 bit accesses + * are allowed, so functions that copy data must be aware of this. + * + * the chip is an intel chip. this means that the byte order + * on all the "short"s in the chip's data structures is wrong. + * so, constants described in the intel docs are swapped for the sun. + * that means that any buffer pointers you give the chip must be + * swapped to intel format. yuck. + * + * VME/multibus interface: + * for the multibus interface the board ignores the top 4 bits + * of the chip address. the multibus interface seems to have its + * own MMU like page map (without protections or valid bits, etc). + * there are 256 pages of physical memory on the board (each page + * is 1024 bytes). there are 1024 slots in the page map. so, + * a 1024 byte page takes up 10 bits of address for the offset, + * and if there are 1024 slots in the page that is another 10 bits + * of the address. that makes a 20 bit address, and as stated + * earlier the board ignores the top 4 bits, so that accounts + * for all 24 bits of address. + * + * note that the last entry of the page map maps the top of the + * 24 bit address space and that the SCP is supposed to be at + * 0xfffff4 (taking into account allignment). so, + * for multibus, that entry in the page map has to be used for the SCP. + * + * the page map effects BOTH how the ie chip sees the + * memory, and how the host sees it. + * + * the page map is part of the "register" area of the board + * + * on-board interface: + * + * <fill in useful info later> + * + * + * VME3E interface: + * + * <fill in useful info later> + * + */ + +/* + * PART 1: VME/multibus defs + */ +#define IEVME_PAGESIZE 1024 /* bytes */ +#define IEVME_PAGSHIFT 10 /* bits */ +#define IEVME_NPAGES 256 /* number of pages on chip */ +#define IEVME_MAPSZ 1024 /* number of entries in the map */ + +/* + * PTE for the page map + */ +#define IEVME_SBORDR 0x8000 /* sun byte order */ +#define IEVME_IBORDR 0x0000 /* intel byte ordr */ + +#define IEVME_P2MEM 0x2000 /* memory is on P2 */ +#define IEVME_OBMEM 0x0000 /* memory is on board */ + +#define IEVME_PGMASK 0x0fff /* gives the physical page frame number */ + +struct ievme { + u_short pgmap[IEVME_MAPSZ]; + u_short xxx[32]; /* prom */ + u_short status; /* see below for bits */ + u_short xxx2; /* filler */ + u_short pectrl; /* parity control (see below) */ + u_short peaddr; /* low 16 bits of address */ +}; + +/* + * status bits + */ +#define IEVME_RESET 0x8000 /* reset board */ +#define IEVME_ONAIR 0x4000 /* go out of loopback 'on-air' */ +#define IEVME_ATTEN 0x2000 /* attention */ +#define IEVME_IENAB 0x1000 /* interrupt enable */ +#define IEVME_PEINT 0x0800 /* parity error interrupt enable */ +#define IEVME_PERR 0x0200 /* parity error flag */ +#define IEVME_INT 0x0100 /* interrupt flag */ +#define IEVME_P2EN 0x0020 /* enable p2 bus */ +#define IEVME_256K 0x0010 /* 256kb rams */ +#define IEVME_HADDR 0x000f /* mask for bits 17-20 of address */ + +/* + * parity control + */ +#define IEVME_PARACK 0x0100 /* parity error ack */ +#define IEVME_PARSRC 0x0080 /* parity error source */ +#define IEVME_PAREND 0x0040 /* which end of the data got the error */ +#define IEVME_PARADR 0x000f /* mask to get bits 17-20 of parity address */ + + +/* + * PART 2: the on-board interface + */ +struct ieob { + u_char obctrl; +}; +#define IEOB_NORSET 0x80 /* don't reset the board */ +#define IEOB_ONAIR 0x40 /* put us on the air */ +#define IEOB_ATTEN 0x20 /* attention! */ +#define IEOB_IENAB 0x10 /* interrupt enable */ +#define IEOB_XXXXX 0x08 /* free bit */ +#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */ +#define IEOB_BUSERR 0x02 /* bus error */ +#define IEOB_INT 0x01 /* interrupt */ + +/* + * PART 3: the 3E board + */ + +/* + * not supported (yet?) + */ + diff --git a/sys/arch/sun3/dev/if_ievar.h b/sys/arch/sun3/dev/if_ievar.h new file mode 100644 index 00000000000..a68c5142d00 --- /dev/null +++ b/sys/arch/sun3/dev/if_ievar.h @@ -0,0 +1,121 @@ +/* $NetBSD: if_ievar.h,v 1.6 1996/03/26 14:38:33 gwr Exp $ */ + +/* + * Machine-dependent glue for the Intel Ethernet (ie) driver. + */ + +#define B_PER_F 3 /* number of buffers to allocate per frame */ +#define MXFRAMES 256 /* max number of frames to allow for receive */ +#define MXRXBUF (MXFRAMES*B_PER_F) /* max number of buffers to allocate */ +#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */ +#define NTXBUF 2 /* number of transmit buffer/command pairs */ +#define IE_TBUF_SIZE (3*512) /* length of transmit buffer */ + +enum ie_hardware { + IE_VME, /* multibus to VME ie card */ + IE_OBIO, /* on board */ + IE_VME3E, /* sun 3e VME card */ + IE_UNKNOWN +}; + +/* + * Ethernet status, per interface. + * + * hardware addresses/sizes to know (all KVA): + * sc_iobase = base of chip's 24 bit address space + * sc_maddr = base address of chip RAM as stored in ie_base of iscp + * sc_msize = size of chip's RAM + * sc_reg = address of card dependent registers + * + * the chip uses two types of pointers: 16 bit and 24 bit + * 16 bit pointers are offsets from sc_maddr/ie_base + * KVA(16 bit offset) = offset + sc_maddr + * 24 bit pointers are offset from sc_iobase in KVA + * KVA(24 bit address) = address + sc_iobase + * + * on the vme/multibus we have the page map to control where ram appears + * in the address space. we choose to have RAM start at 0 in the + * 24 bit address space. this means that sc_iobase == sc_maddr! + * to get the phyiscal address of the board's RAM you must take the + * top 12 bits of the physical address of the register address + * and or in the 4 bits from the status word as bits 17-20 (remember that + * the board ignores the chip's top 4 address lines). + * For example: + * if the register is @ 0xffe88000, then the top 12 bits are 0xffe00000. + * to get the 4 bits from the the status word just do status & IEVME_HADDR. + * suppose the value is "4". Then just shift it left 16 bits to get + * it into bits 17-20 (e.g. 0x40000). Then or it to get the + * address of RAM (in our example: 0xffe40000). see the attach routine! + * + * In the onboard ie interface, the 24 bit address space is hardwired + * to be 0xff000000 -> 0xffffffff of KVA. this means that sc_iobase + * will be 0xff000000. sc_maddr will be where ever we allocate RAM + * in KVA. note that since the SCP is at a fixed address it means + * that we have to use some memory at a fixed KVA for the SCP. + * The Sun PROM leaves a page for us at the end of KVA space. + */ +struct ie_softc { + struct device sc_dev; /* device structure */ + + struct arpcom sc_arpcom;/* system arpcom structure */ +#define sc_if sc_arpcom.ac_if /* network-visible interface */ +#define sc_addr sc_arpcom.ac_enaddr /* hardware Ethernet address */ + + caddr_t sc_iobase; /* KVA of base of 24bit addr space */ + caddr_t sc_maddr; /* KVA of base of chip's RAM */ + u_int sc_msize; /* how much RAM we have/use */ + caddr_t sc_reg; /* KVA of card's register */ + + enum ie_hardware hard_type; /* card type */ + void (*reset_586)(); /* card dependent reset function */ + void (*chan_attn)(); /* card dependent attn function */ + void (*run_586)(); /* card dependent "go on-line" function */ + void (*sc_bcopy) __P((const void *, void *, u_int)); + void (*sc_bzero) __P((void *, u_int)); + + int want_mcsetup; /* flag for multicast setup */ + int promisc; /* are we in promisc mode? */ + + /* + * pointers to the 3 major control structures + */ + volatile struct ie_sys_conf_ptr *scp; + volatile struct ie_int_sys_conf_ptr *iscp; + volatile struct ie_sys_ctl_block *scb; + + /* + * pointer and size of a block of KVA where the buffers + * are to be allocated from + */ + caddr_t buf_area; + int buf_area_sz; + + /* + * the actual buffers (recv and xmit) + */ + volatile struct ie_recv_frame_desc *rframes[MXFRAMES]; + volatile struct ie_recv_buf_desc *rbuffs[MXRXBUF]; + volatile char *cbuffs[MXRXBUF]; + int rfhead, rftail, rbhead, rbtail; + + volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF]; + volatile struct ie_xmit_buf *xmit_buffs[NTXBUF]; + u_char *xmit_cbuffs[NTXBUF]; + int xmit_busy; + int xmit_free; + int xchead, xctail; + + struct ie_en_addr mcast_addrs[MAXMCAST + 1]; + int mcast_count; + + int nframes; /* number of frames in use */ + int nrxbuf; /* number of recv buffs in use */ + +#ifdef IEDEBUG + int sc_debug; +#endif +}; + + +extern void ie_attach __P((struct ie_softc *)); +extern int ie_intr __P((void *)); diff --git a/sys/arch/sun3/dev/if_le.c b/sys/arch/sun3/dev/if_le.c index 7ce0b32d43a..10d21fcc04e 100644 --- a/sys/arch/sun3/dev/if_le.c +++ b/sys/arch/sun3/dev/if_le.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_le.c,v 1.24 1995/12/10 08:46:05 mycroft Exp $ */ +/* $NetBSD: if_le.c,v 1.28 1996/04/22 02:25:54 christos Exp $ */ /*- * Copyright (c) 1995 Charles M. Hannum. All rights reserved. @@ -68,17 +68,27 @@ #define LE_NEED_BUF_CONTIG #include <dev/ic/am7990var.h> -#define LE_SOFTC(unit) lecd.cd_devs[unit] +#define LE_SOFTC(unit) le_cd.cd_devs[unit] #define LE_DELAY(x) DELAY(x) -int lematch __P((struct device *, void *, void *)); -void leattach __P((struct device *, struct device *, void *)); +static int le_match __P((struct device *, void *, void *)); +static void le_attach __P((struct device *, struct device *, void *)); int leintr __P((void *)); -struct cfdriver lecd = { - NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) +struct cfattach le_ca = { + sizeof(struct le_softc), le_match, le_attach }; +struct cfdriver le_cd = { + NULL, "le", DV_IFNET +}; + +integrate void +lehwinit(sc) + struct le_softc *sc; +{ +} + integrate void lewrcsr(sc, port, val) struct le_softc *sc; @@ -104,17 +114,24 @@ lerdcsr(sc, port) } int -lematch(parent, match, aux) +le_match(parent, vcf, aux) struct device *parent; - void *match, *aux; + void *vcf, *aux; { + struct cfdata *cf = vcf; struct confargs *ca = aux; - int x; - - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_AMD_ETHER; - if (ca->ca_intpri == -1) - ca->ca_intpri = 3; + int pa, x; + + /* + * OBIO match functions may be called for every possible + * physical address, so match only our physical address. + */ + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_AMD_ETHER; + } + if (pa != ca->ca_paddr) + return (0); /* The peek returns -1 on bus error. */ x = bus_peek(ca->ca_bustype, ca->ca_paddr, 1); @@ -122,33 +139,66 @@ lematch(parent, match, aux) } void -leattach(parent, self, aux) +le_attach(parent, self, aux) struct device *parent, *self; void *aux; { struct le_softc *sc = (void *)self; + struct cfdata *cf = self->dv_cfdata; struct confargs *ca = aux; + int intpri; + + /* Default interrupt level. */ + if ((intpri = cf->cf_intpri) == -1) + intpri = 3; + printf(" level %d", intpri); sc->sc_r1 = (struct lereg1 *) obio_alloc(ca->ca_paddr, OBIO_AMD_ETHER_SIZE); - sc->sc_mem = dvma_malloc(MEMSIZE); - sc->sc_conf3 = LE_C3_BSWP; + + sc->sc_memsize = 0x4000; /* 16K */ + sc->sc_mem = dvma_malloc(sc->sc_memsize); sc->sc_addr = (u_long)sc->sc_mem & 0xffffff; - sc->sc_memsize = MEMSIZE; + sc->sc_conf3 = LE_C3_BSWP; idprom_etheraddr(sc->sc_arpcom.ac_enaddr); - 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_copytodesc = am7990_copytobuf_contig; + sc->sc_copyfromdesc = am7990_copyfrombuf_contig; + sc->sc_copytobuf = am7990_copytobuf_contig; + sc->sc_copyfrombuf = am7990_copyfrombuf_contig; + sc->sc_zerobuf = am7990_zerobuf_contig; - sc->sc_arpcom.ac_if.if_name = lecd.cd_name; + sc->sc_arpcom.ac_if.if_name = le_cd.cd_name; leconfig(sc); /* Install interrupt handler. */ - isr_add_autovect(leintr, (void *)sc, ca->ca_intpri); + isr_add_autovect(leintr, (void *)sc, intpri); } +/* + * Compare two Ether/802 addresses for equality, inlined and + * unrolled for speed. I'd love to have an inline assembler + * version of this... XXX: Who wanted that? mycroft? + * I wrote one, but the following is just as efficient. + * This expands to 10 short m68k instructions! -gwr + * Note: use this like bcmp() + */ +static inline u_short +ether_cmp(one, two) + u_char *one, *two; +{ + register u_short *a = (u_short *) one; + register u_short *b = (u_short *) two; + register u_short diff; + + diff = *a++ - *b++; + diff |= *a++ - *b++; + diff |= *a++ - *b++; + + return (diff); +} + +#define ETHER_CMP ether_cmp + #include <dev/ic/am7990.c> diff --git a/sys/arch/sun3/dev/if_le.h b/sys/arch/sun3/dev/if_le.h index da03421e409..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_le.h +++ b/sys/arch/sun3/dev/if_le.h @@ -1,28 +0,0 @@ -/* $NetBSD: if_le.h,v 1.6 1995/01/03 15:43:38 gwr Exp $ */ - -/* - * Ethernet software status per interface. - * - * Each interface is referenced by a network interface structure, - * arpcom, 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 device */ - struct arpcom sc_ac; /* common Ethernet structures */ -#define sc_if sc_ac.ac_if /* network-visible interface */ -#define sc_enaddr sc_ac.ac_enaddr /* hardware Ethernet address */ - - volatile struct le_regs *sc_regs; /* LANCE registers */ - void *sc_mem; /* Shared RAM */ - - volatile struct init_block *sc_init; /* Lance init. block */ - volatile struct mds *sc_rd, *sc_td; - u_char *sc_rbuf, *sc_tbuf; - int sc_last_rd, sc_last_td; - int sc_no_td; -#ifdef LEDEBUG - int sc_debug; -#endif -}; diff --git a/sys/arch/sun3/dev/if_le_subr.c b/sys/arch/sun3/dev/if_le_subr.c index c7649b41928..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_le_subr.c +++ b/sys/arch/sun3/dev/if_le_subr.c @@ -1,108 +0,0 @@ -/* $NetBSD: if_le_subr.c,v 1.12 1995/09/26 04:02:05 gwr Exp $ */ - -/* - * Copyright (c) 1994 Gordon W. Ross - * Copyright (c) 1993 Adam Glass - * 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 Adam Glass. - * 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 Adam Glass ``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 Adam Glass 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. - */ - -/* - * Machine-dependent glue for the LANCE Ethernet (le) driver. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/device.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <net/if.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/if_ether.h> -#endif - -#include <machine/autoconf.h> -#include <machine/cpu.h> -#include <machine/dvma.h> -#include <machine/isr.h> -#include <machine/obio.h> -#include <machine/idprom.h> - -#include "if_lereg.h" -#include "if_le.h" -#include "if_le_subr.h" - -int -le_md_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; -{ - struct cfdata *cf = vcf; - struct confargs *ca = args; - int x; - - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_AMD_ETHER; - if (ca->ca_intpri == -1) - ca->ca_intpri = 3; - - /* The peek returns -1 on bus error. */ - x = bus_peek(ca->ca_bustype, ca->ca_paddr, 1); - return (x != -1); -} - -void -le_md_attach(parent, self, args) - struct device *parent; - struct device *self; - void *args; -{ - struct le_softc *sc = (void *) self; - struct confargs *ca = args; - caddr_t p; - - /* register access */ - sc->sc_regs = (struct le_regs *) - obio_alloc(ca->ca_paddr, OBIO_AMD_ETHER_SIZE); - if (sc->sc_regs == NULL) - panic(": not enough obio space\n"); - - /* allocate "shared" memory */ - sc->sc_mem = dvma_malloc(MEMSIZE); - if (sc->sc_mem == NULL) - panic(": not enough dvma space"); - - /* Install interrupt handler. */ - isr_add_autovect(leintr, (void *)sc, ca->ca_intpri); - idprom_etheraddr(sc->sc_enaddr); /* ethernet addr */ -} diff --git a/sys/arch/sun3/dev/if_le_subr.h b/sys/arch/sun3/dev/if_le_subr.h index c2cb658517e..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/if_le_subr.h +++ b/sys/arch/sun3/dev/if_le_subr.h @@ -1,8 +0,0 @@ -/* $NetBSD: if_le_subr.h,v 1.7 1995/01/03 15:43:40 gwr Exp $ */ - -/* One might also set: LE_ACON | LE_BCON */ -#define LE_CONF3 (LE_BSWP) - -extern int le_md_match(struct device *, void *, void *args); -extern void le_md_attach(struct device *, struct device *, void *); -extern int leintr(void *); diff --git a/sys/arch/sun3/dev/if_lereg.h b/sys/arch/sun3/dev/if_lereg.h index 07580beed4c..01ac6fdfdd8 100644 --- a/sys/arch/sun3/dev/if_lereg.h +++ b/sys/arch/sun3/dev/if_lereg.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_lereg.h,v 1.11 1995/12/10 08:46:07 mycroft Exp $ */ +/* $NetBSD: if_lereg.h,v 1.12 1996/03/26 14:42:20 gwr Exp $ */ /* * Copyright (c) 1982, 1990 The Regents of the University of California. @@ -35,8 +35,6 @@ * @(#)if_lereg.h 7.1 (Berkeley) 5/8/90 */ -#define MEMSIZE 0x4000 - /* * LANCE registers. */ diff --git a/sys/arch/sun3/dev/kd.c b/sys/arch/sun3/dev/kd.c index 61307b54697..862b831ae1f 100644 --- a/sys/arch/sun3/dev/kd.c +++ b/sys/arch/sun3/dev/kd.c @@ -1,4 +1,4 @@ -/* $NetBSD: kd.c,v 1.14 1996/01/24 22:40:20 gwr Exp $ */ +/* $NetBSD: kd.c,v 1.16 1996/04/26 18:36:54 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -329,10 +329,7 @@ kd_later(tpaddr) s = spltty(); tp->t_state &= ~TS_BUSY; - if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); - else - kdstart(tp); splx(s); } @@ -360,7 +357,8 @@ static void kd_putfb(tp) } /* - * Our "interrupt" routine for input. + * Our "interrupt" routine for input. This is called by + * the keyboard driver (dev/sun/kbd.c) at spltty. */ void kd_input(c) @@ -376,7 +374,7 @@ kd_input(c) if ((tp->t_state & TS_ISOPEN) == 0) return; - ttyinput(c, kd->kd_tty); + (*linesw[tp->t_line].l_rint)(c, tp); } diff --git a/sys/arch/sun3/dev/memerr.c b/sys/arch/sun3/dev/memerr.c new file mode 100644 index 00000000000..e71b10f4c7a --- /dev/null +++ b/sys/arch/sun3/dev/memerr.c @@ -0,0 +1,249 @@ +/* $NetBSD: memerr.c,v 1.2 1996/04/07 05:47:28 gwr Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)memreg.c 8.1 (Berkeley) 6/11/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/obio.h> +#include <machine/pte.h> + +#include <sun3/dev/memerr.h> +/* #include <sun3/dev/eccreg.h> - not yet */ + +#define ME_PRI 7 /* Interrupt level (NMI) */ + +extern unsigned char cpu_machine_id; + +enum memerr_type { ME_PAR = 0, ME_ECC = 1 }; + +struct memerr_softc { + struct device sc_dev; + struct memerr *sc_reg; + enum memerr_type sc_type; + char *sc_typename; /* "Parity" or "ECC" */ + char *sc_csrbits; /* how to print csr bits */ + /* XXX: counters? */ +}; + +static int memerr_match __P((struct device *, void *vcf, void *args)); +static void memerr_attach __P((struct device *, struct device *, void *)); +static int memerr_interrupt __P((void *)); +static void memerr_correctable __P((struct memerr_softc *)); + +struct cfattach memerr_ca = { + sizeof(struct memerr_softc), memerr_match, memerr_attach +}; + +struct cfdriver memerr_cd = { + NULL, "memerr", DV_DULL +}; + + +static int +memerr_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + int pa, x; + + /* This driver only supports one unit. */ + if (cf->cf_unit != 0) + return (0); + + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_MEMERR; + } + if (pa != ca->ca_paddr) + return (0); + + /* The peek returns -1 on bus error. */ + x = bus_peek(ca->ca_bustype, ca->ca_paddr, 1); + return (x != -1); +} + +static void +memerr_attach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + struct memerr_softc *sc = (void *)self; + struct confargs *ca = args; + struct memerr *mer; + + mer = (struct memerr *) + obio_alloc(ca->ca_paddr, sizeof(*mer)); + if (mer == NULL) + panic(": can not map register"); + sc->sc_reg = mer; + + /* + * Which type of memory subsystem do we have? + */ + switch (cpu_machine_id) { + case SUN3_MACH_160: /* XXX: correct? */ + case SUN3_MACH_260: + sc->sc_type = ME_ECC; + sc->sc_typename = "ECC"; + sc->sc_csrbits = ME_ECC_STR; + break; + + default: + sc->sc_type = ME_PAR; + sc->sc_typename = "Parity"; + sc->sc_csrbits = ME_PAR_STR; + break; + } + + printf(" (%s memory)\n", sc->sc_typename); + + /* Install interrupt handler. */ + isr_add_autovect(memerr_interrupt, (void *)sc, ME_PRI); + + /* Enable error interrupt (and checking). */ + if (sc->sc_type == ME_PAR) + mer->me_csr = ME_CSR_IENA | ME_PAR_CHECK; + else { + /* + * XXX: Some day, figure out how to decode + * correctable errors and set ME_ECC_CE_ENA + * here so we can log them... + */ + mer->me_csr = ME_CSR_IENA; /* | ME_ECC_CE_ENA */ + } +} + +/***************************************************************** + * Functions for ECC memory + *****************************************************************/ + +static int +memerr_interrupt(arg) + void *arg; +{ + struct memerr_softc *sc = arg; + volatile struct memerr *me = sc->sc_reg; + u_char csr, ctx, err; + u_int pa, va; + int pte; + + csr = me->me_csr; + if ((csr & ME_CSR_IPEND) == 0) + return (0); + + va = me->me_vaddr; + ctx = (va >> 28) & 0xF; + va &= 0x0FFFffff; + pte = get_pte(va); + pa = PG_PA(pte); + + printf("\nMemory error on %s cycle!\n", + (ctx & 8) ? "DVMA" : "CPU"); + printf(" ctx=%d, vaddr=0x%x, paddr=0x%x\n", + (ctx & 7), va, pa); + printf(" csr=%b\n", csr, sc->sc_csrbits); + + /* + * If we have parity-checked memory, there is + * not much to be done. Any error is fatal. + */ + if (sc->sc_type == ME_PAR) { + if (csr & ME_PAR_EMASK) { + /* Parity errors are fatal. */ + goto die; + } + /* The IPEND bit was set, but no error bits. */ + goto noerror; + } + + /* + * We have ECC memory. More complicated... + */ + if (csr & (ME_ECC_WBTMO | ME_ECC_WBERR)) { + printf(" write-back failed, pte=0x%x\n", pte); + goto die; + } + if (csr & ME_ECC_UE) { + printf(" uncorrectable ECC error\n"); + goto die; + } + if (csr & ME_ECC_CE) { + /* Just log this and continue. */ + memerr_correctable(sc); + goto recover; + } + /* The IPEND bit was set, but no error bits. */ + goto noerror; + +die: + panic("all bets are off..."); + +noerror: + printf("memerr: no error bits set?\n"); + +recover: + /* Clear the error by writing the address register. */ + me->me_vaddr = 0; + return (1); +} + +/* + * Announce (and log) a correctable ECC error. + * Need to look at the ECC syndrome register on + * the memory board that caused the error... + */ +void +memerr_correctable(sc) + struct memerr_softc *sc; +{ + /* XXX: Not yet... */ +} diff --git a/sys/arch/sun3/dev/memerr.h b/sys/arch/sun3/dev/memerr.h new file mode 100644 index 00000000000..9fafbafaba7 --- /dev/null +++ b/sys/arch/sun3/dev/memerr.h @@ -0,0 +1,95 @@ +/* $NetBSD: memerr.h,v 1.1 1996/03/26 14:57:44 gwr Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)memreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Sun3 memory error register. + * + * All Sun3 memory systems use either parity checking or + * Error Correction Coding (ECC). A memory error causes + * the Memory Error Register (MER) to latch information + * about the location and type of error, and if the MER + * interrupt is enabled, generateds a level 7 interrupt. + * The latched information persists (even if more errors + * occur) until the MER is cleared by a write (at mer_er). + */ + + +struct memerr { + volatile u_char me_csr; /* MER control/status reg. */ + volatile u_char me__pad[3]; + volatile u_int me_vaddr; +}; + +/* + * Bits in me_csr common between ECC/parity memory systems: + */ +#define ME_CSR_IPEND 0x80 /* (ro) error interrupt pending */ +#define ME_CSR_IENA 0x40 /* (rw) error interrupt enable */ + +/* + * Bits in me_csr on parity-checked memory system: + */ +#define ME_PAR_TEST 0x20 /* (rw) write inverse parity */ +#define ME_PAR_CHECK 0x10 /* (rw) enable parity checking */ +#define ME_PAR_ERR3 0x08 /* (ro) parity error in <24..31> */ +#define ME_PAR_ERR2 0x04 /* (ro) parity error in <16..23> */ +#define ME_PAR_ERR1 0x02 /* (ro) parity error in <8..15> */ +#define ME_PAR_ERR0 0x01 /* (ro) parity error in <0..7> */ +#define ME_PAR_EMASK 0x0F /* (ro) mask of above four */ +#define ME_PAR_STR "\20\10IPEND\7IENA\6TEST\5CHK\4ERR3\3ERR2\2ERR1\1ERR0" + +/* + * Bits in me_csr on an ECC memory system: + */ +#define ME_ECC_BUSLK 0x20 /* (rw) hold memory bus mastership */ +#define ME_ECC_CE_ENA 0x10 /* (rw) enable CE recording */ +#define ME_ECC_WBTMO 0x08 /* (ro) write-back timeout */ +#define ME_ECC_WBERR 0x04 /* (ro) write-back error */ +#define ME_ECC_UE 0x02 /* (ro) UE, uncorrectable error */ +#define ME_ECC_CE 0x01 /* (ro) CE, correctable (single bit) error */ +#define ME_ECC_EMASK 0x0F /* (ro) mask for some ECC error occuring */ +#define ME_ECC_STR "\20\10IPEND\7IENA\6BUSLK\5CE_ENA\4TMOUT\3WBERR\2UE\1CE" + diff --git a/sys/arch/sun3/dev/ncr5380.doc b/sys/arch/sun3/dev/ncr5380.doc index 82b8c721b23..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr5380.doc +++ b/sys/arch/sun3/dev/ncr5380.doc @@ -1,146 +0,0 @@ -MI 5380 driver -============== - -(What? Documentation? Is this guy nuts? :-) - -Reselection ------------ - -This driver will permit reselection on non-polled commands if -sc->sc_flags & NCR5380_PERMIT_RESELECT is 1. This permits enabling of -reselection on a per-device basis. - -Disconnect/reselect is never permitted for polled commands. - - - -Interfacing the driver to MD code ---------------------------------- - -/sys/dev/ic/ncr5380.c is now stand-alone. DON'T include it after your -MD stuff! - -This allows for more than one 5380-based SCSI board in your system. This is -a real possibility for Amiga generic kernels. - -Your driver's softc structure must have an instance of struct ncr5380_softc -as the first thing in the structure. The MD code must initialize the -following: - -sci_*: pointers to the 5380 registers. All accesses are done through - these pointers. This indirection allows the driver to work with - boards that map the 5380 on even addresses only or do other - wierdnesses. - -int (*sc_pio_out)(sc, phase, datalen, data) -int (*sc_pio_in)(sc, phase, datalen, data) - These point to functions that do programmed I/O transfers to the bus and - from the bus, respectively. Arguments: - - sc points to the softc - phase the current SCSI bus phase - datalen length of data to transfer - data pointer to the buffer - - Both functions must return the number of bytes successfully transferred. - A transfer operation must be aborted if the target requests a different - phase before the transfer completes. - - If you have no special requirements, you can point these to - ncr5380_pio_out() and ncr5380_pio_in() respectively. If your board - can do pseudo-DMA, then you might want to point these to functions - that use this feature. - -void (*sc_dma_alloc)(sc) - This function is called to set up a DMA transfer. You must create and - return a "DMA handle" in sc->sc_dma_hand which identifies the DMA transfer. - The driver will pass you your DMA handle in sc->sc_dma_hand for future - operations. The contents of the DMA handle are immaterial to the MI - code - the DMA handle is for your bookkeeping only. Usually, you - create a structure and point to it here. - - For example, you can record the mapped and unmapped addresses of the - buffer. The Sun driver places an Am9516 UDC control block in the DMA - handle. - - If for some reason you decide not to do DMA for the transfer, make - sc->sc_dma_hand NULL. This might happen if the proposed transfer is - misaligned, or in the wrong type of memory, or... - -void (*sc_dma_start)(sc) - This function starts the transfer. - -void (*sc_dma_stop)(sc) - This function stops a transfer. sc->sc_datalen and sc->sc_dataptr must - be updated to reflect the portion of the DMA already done. - -void (*sc_dma_eop)(sc) - This function is called when the 5380 signals EOP. Either continue - the DMA or stop the DMA. - -void (*sc_dma_free)(sc) - This function frees the current DMA handle. - -u_char *sc_dataptr; -int sc_datalen; - These variables form the active SCSI data pointer. DMA code must start - DMA at the location given, and update the pointer/length in response to - DMA operations. - -u_short sc_dma_flags; - See ncr5380var.h - - - -Writing your DMA code ---------------------- - -DMA on a system with protected or virtual memory is always a problem. Even -though a disk transfer may be logically contiguous, the physical pages backing -the transfer may not be. There are two common solutions to this problem: - -DMA chains: the DMA is broken up into a list of contiguous segments. The first -segment is submitted to the DMA controller, and when it completes, the second -segment is submitted, without stopping the 5380. This is what the sc_dma_eop() -function can do efficiently - if you have a DMA chain, it can quickly load up -the next link in the chain. The sc_dma_alloc() function builds the chain and -sc_dma_free() releases any resources you used to build it. - -DVMA: Direct Virtual Memory Access. In this scheme, DMA requests go through -the MMU. Although you can't page fault, you can program the MMU to remap -things so the DMA controller sees contiguous data. In this mode, sc_dma_alloc() -is used to map the transfer into the address space reserved for DVMA and -sc_dma_free() is used to unmap it. - - -Interrupts ----------- - -ncr5380_sbc_intr() must be called when the 5380 interrupts the host. - -You must write an interrupt routine pretty much from scratch to check for -things generated by MD hardware. - - -Known problems --------------- - -I'm getting this out now so that other ports can hack on it and integrate it. - -The sun3, DMA/Interrupt appears to be working now, but needs testing. - -Polled commands submitted while non-polled commands are in progress are not -handled correctly. This can happen if reselection is enabled and a new disk -is mounted while an I/O is in progress on another disk. - -The problem is: what to do if you get reselected while doing the selection -for the polled command? Currently, the driver busy waits for the non-polled -command to complete, but this is bogus. I need to complete the non-polled -command in polled mode, then do the polled command. - - -Timeouts in the driver are EXTREMELY sensitive to the characteristics of the -local implementation of delay(). The Sun3 version delays for a minimum of 5us. -However, the driver must assume that delay(1) will delay only 1us. For this -reason, performance on the Sun3 sucks in some places. - diff --git a/sys/arch/sun3/dev/ncr5380reg.h b/sys/arch/sun3/dev/ncr5380reg.h index 5b7f7bebc15..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr5380reg.h +++ b/sys/arch/sun3/dev/ncr5380reg.h @@ -1,160 +0,0 @@ -/* $NetBSD: ncr5380reg.h,v 1.2 1995/11/17 23:27:41 gwr Exp $ */ - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 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 - * 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. - */ -/* - * HISTORY (mach3) - * Revision 2.3 91/08/24 12:25:10 af - * Moved padding of regmap in impl file. - * [91/08/02 04:22:39 af] - * - * Revision 2.2 91/06/19 16:28:35 rvb - * From the NCR data sheets - * "NCR 5380 Family, SCSI Protocol Controller Data Manual" - * NCR Microelectronics Division, Colorado Spring, 6/98 T01891L - * [91/04/21 af] - * - */ - -/* - * File: scsi_5380.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 5/91 - * - * Defines for the NCR 5380 (SCSI chip), aka Am5380 - */ - -/* - * Register map: Note not declared here anymore! - * All the 5380 registers are accessed through individual - * pointers initialized by MD code. This allows the 5380 - * MI functions to be shared between MD drivers that have - * different padding between the registers (i.e. amiga). - */ -#if 0 /* example only */ -struct ncr5380regs { - volatile u_char sci_r0; - volatile u_char sci_r1; - volatile u_char sci_r2; - volatile u_char sci_r3; - volatile u_char sci_r4; - volatile u_char sci_r5; - volatile u_char sci_r6; - volatile u_char sci_r7; -}; -#endif - -/* - * Machine-independent code uses these names: - */ -#define sci_data sci_r0 /* r: Current data */ -#define sci_odata sci_r0 /* w: Out data */ - -#define sci_icmd sci_r1 /* rw: Initiator command */ -#define sci_mode sci_r2 /* rw: Mode */ -#define sci_tcmd sci_r3 /* rw: Target command */ - -#define sci_bus_csr sci_r4 /* r: Bus Status */ -#define sci_sel_enb sci_r4 /* w: Select enable */ - -#define sci_csr sci_r5 /* r: Status */ -#define sci_dma_send sci_r5 /* w: Start dma send data */ - -#define sci_idata sci_r6 /* r: Input data */ -#define sci_trecv sci_r6 /* w: Start dma receive, target */ - -#define sci_iack sci_r7 /* r: Interrupt Acknowledge */ -#define sci_irecv sci_r7 /* w: Start dma receive, initiator */ - - -/* - * R1: Initiator command register - */ -#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */ -#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */ -#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */ -#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */ -#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */ -#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */ -#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */ -#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */ -#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */ -#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */ -/* Bits to keep when doing read/modify/write (leave out RST) */ -#define SCI_ICMD_RMASK 0x1F - - -/* - * R2: Mode register - */ -#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */ -#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */ -#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */ -#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */ -#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */ -#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */ -#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */ -#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake */ - - -/* - * R3: Target command register - */ -#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */ -#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */ -#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */ -#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */ -#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */ -#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred - * (not on 5380/1) */ - -#define SCI_TCMD_PHASE(x) ((x) & 0x7) - -/* - * R4: Current (SCSI) Bus status (.sci_bus_csr) - */ -#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */ -#define SCI_BUS_SEL 0x02 /* r: SEL signal */ -#define SCI_BUS_IO 0x04 /* r: I/O signal */ -#define SCI_BUS_CD 0x08 /* r: C/D signal */ -#define SCI_BUS_MSG 0x10 /* r: MSG signal */ -#define SCI_BUS_REQ 0x20 /* r: REQ signal */ -#define SCI_BUS_BSY 0x40 /* r: BSY signal */ -#define SCI_BUS_RST 0x80 /* r: RST signal */ - -#define SCI_BUS_PHASE(x) (((x) >> 2) & 7) - -/* - * R5: Bus and Status register (.sci_csr) - */ -#define SCI_CSR_ACK 0x01 /* r: ACK signal */ -#define SCI_CSR_ATN 0x02 /* r: ATN signal */ -#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */ -#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */ -#define SCI_CSR_INT 0x10 /* r: Interrupt request */ -#define SCI_CSR_PERR 0x20 /* r: Parity error */ -#define SCI_CSR_DREQ 0x40 /* r: DMA request */ -#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */ diff --git a/sys/arch/sun3/dev/ncr5380sbc.c b/sys/arch/sun3/dev/ncr5380sbc.c index 3060cbb2a6f..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr5380sbc.c +++ b/sys/arch/sun3/dev/ncr5380sbc.c @@ -1,2508 +0,0 @@ -/* $NetBSD: ncr5380sbc.c,v 1.2 1995/11/17 23:27:45 gwr Exp $ */ - -/* - * Copyright (c) 1995 David Jones, Gordon W. Ross - * Copyright (c) 1994 Jarle Greipsland - * 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. The name of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by - * David Jones and Gordon Ross - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. - */ - -/* - * This is a machine-independent driver for the NCR5380 - * SCSI Bus Controller (SBC), also known as the Am5380. - * - * This code should work with any memory-mapped 5380, - * and can be shared by multiple adapters that address - * the 5380 with different register offset spacings. - * (This can happen on the atari, for example.) - * For porting/design info. see: ncr5380.doc - * - * Credits, history: - * - * David Jones is the author of most of the code that now - * appears in this file, and was the architect of the - * current overall structure (MI/MD code separation, etc.) - * - * Gordon Ross integrated the message phase code, added lots of - * comments about what happens when and why (re. SCSI spec.), - * debugged some reentrance problems, and added several new - * "hooks" needed for the Sun3 "si" adapters. - * - * The message in/out code was taken nearly verbatim from - * the aic6360 driver by Jarle Greipsland. - * - * Several other NCR5380 drivers were used for reference - * while developing this driver, including work by: - * The Alice Group (mac68k port) namely: - * Allen K. Briggs, Chris P. Caputo, Michael L. Finch, - * Bradley A. Grantham, and Lawrence A. Kesteloot - * Michael L. Hitch (amiga drivers: sci.c) - * Leo Weppelman (atari driver: ncr5380.c) - * There are others too. Thanks, everyone. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/errno.h> -#include <sys/device.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsi_message.h> -#include <scsi/scsiconf.h> - -#define DEBUG XXX - -#if 0 /* XXX - not yet... */ -#include <dev/ic/ncr5380reg.h> -#include <dev/ic/ncr5380var.h> -#else -#include "ncr5380reg.h" -#include "ncr5380var.h" -#endif - -static int ncr5380_wait_req __P((struct ncr5380_softc *)); -static int ncr5380_wait_not_req __P((struct ncr5380_softc *)); - -static void ncr5380_sched __P((struct ncr5380_softc *)); -static void ncr5380_done __P((struct ncr5380_softc *)); - -static int ncr5380_select - __P((struct ncr5380_softc *, struct sci_req *)); -static void ncr5380_reselect __P((struct ncr5380_softc *)); - -static int ncr5380_msg_in __P((struct ncr5380_softc *)); -static int ncr5380_msg_out __P((struct ncr5380_softc *)); -static int ncr5380_data_xfer __P((struct ncr5380_softc *, int)); -static int ncr5380_command __P((struct ncr5380_softc *)); -static int ncr5380_status __P((struct ncr5380_softc *)); -static void ncr5380_machine __P((struct ncr5380_softc *)); - -/* - * Action flags returned by the info_tranfer functions: - * (These determine what happens next.) - */ -#define ACT_CONTINUE 0x00 /* No flags: expect another phase */ -#define ACT_DISCONNECT 0x01 /* Target is disconnecting */ -#define ACT_CMD_DONE 0x02 /* Need to call scsi_done() */ -#define ACT_RESET_BUS 0x04 /* Need bus reset (cmd timeout) */ -#define ACT_WAIT_DMA 0x10 /* Wait for DMA to complete */ - -/***************************************************************** - * Debugging stuff - *****************************************************************/ - -#ifdef DDB -int Debugger(); -#else -/* This is used only in recoverable places. */ -#define Debugger() printf("Debug: ncr5380.c:%d\n", __LINE__) -#endif - -#ifdef DEBUG - -#define NCR_DBG_BREAK 1 -#define NCR_DBG_CMDS 2 -int ncr5380_debug = NCR_DBG_BREAK; -#define NCR_BREAK() \ - do { if (ncr5380_debug & NCR_DBG_BREAK) Debugger(); } while (0) -static void ncr5380_show_scsi_cmd __P((struct scsi_xfer *)); -static void ncr5380_show_sense __P((struct scsi_xfer *)); -#else /* DEBUG */ -#define NCR_BREAK() /* nada */ -#define ncr5380_show_scsi_cmd(xs) /* nada */ -#define ncr5380_show_sense(xs) /* nada */ -#endif /* DEBUG */ - -static char * -phase_names[8] = { - "DATA_OUT", - "DATA_IN", - "COMMAND", - "STATUS", - "UNSPEC1", - "UNSPEC2", - "MSG_OUT", - "MSG_IN", -}; - -/***************************************************************** - * Actual chip control - *****************************************************************/ - -/* - * XXX: These timeouts might need to be tuned... - */ - -/* This one is used when waiting for a phase change. (X100uS.) */ -int ncr5380_wait_phase_timo = 1000 * 10 * 300; /* 5 min. */ - -/* These are used in the following inline functions. */ -int ncr5380_wait_req_timo = 1000 * 50; /* X2 = 100 mS. */ -int ncr5380_wait_nrq_timo = 1000 * 25; /* X2 = 50 mS. */ - -/* Return zero on success. */ -static __inline__ int ncr5380_wait_req(sc) - struct ncr5380_softc *sc; -{ - register int timo = ncr5380_wait_req_timo; - for (;;) { - if (*sc->sci_bus_csr & SCI_BUS_REQ) { - timo = 0; /* return 0 */ - break; - } - if (--timo < 0) - break; /* return -1 */ - delay(2); - } - return (timo); -} - -/* Return zero on success. */ -static __inline__ int ncr5380_wait_not_req(sc) - struct ncr5380_softc *sc; -{ - register int timo = ncr5380_wait_nrq_timo; - for (;;) { - if ((*sc->sci_bus_csr & SCI_BUS_REQ) == 0) { - timo = 0; /* return 0 */ - break; - } - if (--timo < 0) - break; /* return -1 */ - delay(2); - } - return (timo); -} - -/* Ask the target for a MSG_OUT phase. */ -static __inline__ void -ncr_sched_msgout(sc, msg_code) - struct ncr5380_softc *sc; - int msg_code; -{ - /* First time, raise ATN line. */ - if (sc->sc_msgpriq == 0) { - register u_char icmd; - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - *sc->sci_icmd = icmd | SCI_ICMD_ATN; - delay(2); - } - sc->sc_msgpriq |= msg_code; -} - - -int -ncr5380_pio_out(sc, phase, count, data) - struct ncr5380_softc *sc; - int phase, count; - unsigned char *data; -{ - register u_char icmd; - register int resid; - register int error; - - icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; - - icmd |= SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - resid = count; - while (resid > 0) { - if (!SCI_BUSY(sc)) { - NCR_TRACE("pio_out: lost BSY, resid=%d\n", resid); - break; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("pio_out: no REQ, resid=%d\n", resid); - break; - } - if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) - break; - - /* Put the data on the bus. */ - *sc->sci_odata = *data++; - - /* Tell the target it's there. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for target to get it. */ - error = ncr5380_wait_not_req(sc); - - /* OK, it's got it (or we gave up waiting). */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (error) { - NCR_TRACE("pio_out: stuck REQ, resid=%d\n", resid); - break; - } - - --resid; - } - - /* Stop driving the data bus. */ - icmd &= ~SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - return (count - resid); -} - - -int -ncr5380_pio_in(sc, phase, count, data) - struct ncr5380_softc *sc; - int phase, count; - unsigned char *data; -{ - register u_char icmd; - register int resid; - register int error; - - icmd = *(sc->sci_icmd) & SCI_ICMD_RMASK; - - resid = count; - while (resid > 0) { - if (!SCI_BUSY(sc)) { - NCR_TRACE("pio_in: lost BSY, resid=%d\n", resid); - break; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("pio_in: no REQ, resid=%d\n", resid); - break; - } - /* A phase change is not valid until AFTER REQ rises! */ - if (SCI_BUS_PHASE(*sc->sci_bus_csr) != phase) - break; - - /* Read the data bus. */ - *data++ = *sc->sci_data; - - /* Tell target we got it. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for target to drop REQ... */ - error = ncr5380_wait_not_req(sc); - - /* OK, we can drop ACK. */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (error) { - NCR_TRACE("pio_in: stuck REQ, resid=%d\n", resid); - break; - } - - --resid; - } - - return (count - resid); -} - - -void -ncr5380_init(sc) - struct ncr5380_softc *sc; -{ - int i, j; - -#ifdef DEBUG - ncr5380_debug_sc = sc; -#endif - - for (i = 0; i < SCI_OPENINGS; i++) - sc->sc_ring[i].sr_xs = NULL; - for (i = 0; i < 8; i++) - for (j = 0; j < 8; j++) - sc->sc_matrix[i][j] = NULL; - - sc->sc_link.openings = 2; /* XXX - Not SCI_OPENINGS */ - sc->sc_prevphase = PHASE_INVALID; - sc->sc_state = NCR_IDLE; - - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - - /* XXX: Enable reselect interrupts... */ - *sc->sci_sel_enb = 0x80; - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("init: intr ON\n", 0); - sc->sc_intr_on(sc); - } -} - - -void -ncr5380_reset_scsibus(sc) - struct ncr5380_softc *sc; -{ - - NCR_TRACE("reset_scsibus, cur=0x%x\n", - (long) sc->sc_current); - - *sc->sci_icmd = SCI_ICMD_RST; - delay(500); - *sc->sci_icmd = 0; - - *sc->sci_mode = 0; - *sc->sci_tcmd = PHASE_INVALID; - - SCI_CLR_INTR(sc); - /* XXX - Need long delay here! */ - delay(100000); - - /* XXX - Need to cancel disconnected requests. */ -} - - -/* - * Interrupt handler for the SCSI Bus Controller (SBC) - * This may also called for a DMA timeout (at splbio). - */ -int -ncr5380_intr(sc) - struct ncr5380_softc *sc; -{ - int claimed = 0; - - /* - * Do not touch SBC regs here unless sc_current == NULL - * or it will complain about "register conflict" errors. - * Instead, just let ncr5380_machine() deal with it. - */ - NCR_TRACE("intr: top, state=%d\n", sc->sc_state); - - if (sc->sc_state == NCR_IDLE) { - /* - * Might be reselect. ncr5380_reselect() will check, - * and set up the connection if so. This will verify - * that sc_current == NULL at the beginning... - */ - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("intr: for reselect, intr off\n", 0); - sc->sc_intr_off(sc); - } - - ncr5380_reselect(sc); - } - - /* - * The remaining documented interrupt causes are phase mismatch and - * disconnect. In addition, the sunsi controller may produce a state - * where SCI_CSR_DONE is false, yet DMA is complete. - * - * The procedure in all these cases is to let ncr5380_machine() - * figure out what to do next. - */ - if (sc->sc_state & NCR_WORKING) { - NCR_TRACE("intr: call machine, cur=0x%x\n", - (long) sc->sc_current); - /* This will usually free-up the nexus. */ - ncr5380_machine(sc); - NCR_TRACE("intr: machine done, cur=0x%x\n", - (long) sc->sc_current); - claimed = 1; - } - - /* Maybe we can run some commands now... */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("intr: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("intr: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - - return claimed; -} - - -/* - * Abort the current command (i.e. due to timeout) - */ -void -ncr5380_abort(sc) - struct ncr5380_softc *sc; -{ - - /* - * Finish it now. If DMA is in progress, we - * can not call ncr_sched_msgout() because - * that hits the SBC (avoid DMA conflict). - */ - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("abort: intr off\n", 0); - sc->sc_intr_off(sc); - } - - sc->sc_state |= NCR_ABORTING; - if ((sc->sc_state & NCR_DOINGDMA) == 0) { - ncr_sched_msgout(sc, SEND_ABORT); - } - NCR_TRACE("abort: call machine, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_machine(sc); - NCR_TRACE("abort: machine done, cur=0x%x\n", - (long) sc->sc_current); - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("abort: intr ON\n", 0); - sc->sc_intr_on(sc); - } -} - -/* - * Timeout handler, scheduled for each SCSI command. - */ -void -ncr5380_cmd_timeout(arg) - void *arg; -{ - struct sci_req *sr = arg; - struct scsi_xfer *xs; - struct scsi_link *sc_link; - struct ncr5380_softc *sc; - int s; - - s = splbio(); - - /* Get all our variables... */ - xs = sr->sr_xs; - if (xs == NULL) { - printf("ncr5380_cmd_timeout: no scsi_xfer\n"); - goto out; - } - sc_link = xs->sc_link; - sc = sc_link->adapter_softc; - - printf("%s: cmd timeout, targ=%d, lun=%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - - /* - * Mark the overdue job as failed, and arrange for - * ncr5380_machine to terminate it. If the victim - * is the current job, call ncr5380_machine() now. - * Otherwise arrange for ncr5380_sched() to do it. - */ - sr->sr_flags |= SR_OVERDUE; - if (sc->sc_current == sr) { - NCR_TRACE("cmd_tmo: call abort, sr=0x%x\n", (long) sr); - ncr5380_abort(sc); - } else { - /* - * The driver may be idle, or busy with another job. - * Arrange for ncr5380_sched() to do the deed. - */ - NCR_TRACE("cmd_tmo: clear matrix, t/l=0x%02x\n", - (sr->sr_target << 4) | sr->sr_lun); - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - } - - /* - * We may have aborted the current job, or may have - * already been idle. In either case, we should now - * be idle, so try to start another job. - */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("cmd_tmo: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("cmd_tmo: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - -out: - splx(s); -} - - -/***************************************************************** - * Interface to higher level - *****************************************************************/ - - -/* - * Enter a new SCSI command into the "issue" queue, and - * if there is work to do, start it going. - * - * WARNING: This can be called recursively! - * (see comment in ncr5380_done) - */ -int -ncr5380_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct ncr5380_softc *sc; - struct sci_req *sr; - int s, rv, i, flags; - extern int cold; /* XXX */ - - sc = xs->sc_link->adapter_softc; - - flags = xs->flags; - /* - * XXX: Hack: During autoconfig, force polling mode. - * Needed as long as sdsize() can be called while cold, - * otherwise timeouts will never call back (grumble). - */ - if (cold) - flags |= SCSI_POLL; - - if (sc->sc_flags & NCR5380_FORCE_POLLING) - flags |= SCSI_POLL; - - if (flags & SCSI_DATA_UIO) - panic("ncr5380: scsi data uio requested"); - - s = splbio(); - - if (flags & SCSI_POLL) { - /* Terminate any current command. */ - sr = sc->sc_current; - if (sr) { - printf("%s: polled request aborting %d/%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - ncr5380_abort(sc); - } - if (sc->sc_state != NCR_IDLE) { - panic("ncr5380_scsi_cmd: polled request, abort failed"); - } - } - - /* - * Find lowest empty slot in ring buffer. - * XXX: What about "fairness" and cmd order? - */ - for (i = 0; i < SCI_OPENINGS; i++) - if (sc->sc_ring[i].sr_xs == NULL) - goto new; - - rv = TRY_AGAIN_LATER; - NCR_TRACE("scsi_cmd: no openings, rv=%d\n", rv); - goto out; - -new: - /* Create queue entry */ - sr = &sc->sc_ring[i]; - sr->sr_xs = xs; - sr->sr_target = xs->sc_link->target; - sr->sr_lun = xs->sc_link->lun; - sr->sr_dma_hand = NULL; - sr->sr_dataptr = xs->data; - sr->sr_datalen = xs->datalen; - sr->sr_flags = (flags & SCSI_POLL) ? SR_IMMED : 0; - sr->sr_status = -1; /* no value */ - sc->sc_ncmds++; - rv = SUCCESSFULLY_QUEUED; - - NCR_TRACE("scsi_cmd: new sr=0x%x\n", (long)sr); - - if (flags & SCSI_POLL) { - /* Force this new command to be next. */ - sc->sc_rr = i; - } - - /* - * If we were idle, run some commands... - */ - if (sc->sc_state == NCR_IDLE) { - NCR_TRACE("scsi_cmd: call sched, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_sched(sc); - NCR_TRACE("scsi_cmd: sched done, cur=0x%x\n", - (long) sc->sc_current); - } - - if (flags & SCSI_POLL) { - /* Make sure ncr5380_sched() finished it. */ - if ((xs->flags & ITSDONE) == 0) - panic("ncr5380_scsi_cmd: poll didn't finish"); - rv = COMPLETE; - } - -out: - splx(s); - return (rv); -} - - -/* - * POST PROCESSING OF SCSI_CMD (usually current) - * Called by ncr5380_sched(), ncr5380_machine() - */ -static void -ncr5380_done(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_done: bad spl"); - if (sc->sc_state == NCR_IDLE) - panic("ncr5380_done: state=idle"); - if (sc->sc_current == NULL) - panic("ncr5380_done: current=0"); -#endif - - sr = sc->sc_current; - xs = sr->sr_xs; - - NCR_TRACE("done: top, cur=0x%x\n", (long) sc->sc_current); - - /* - * Clean up DMA resources for this command. - */ - if (sr->sr_dma_hand) { - NCR_TRACE("done: dma_free, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_free)(sc); - } -#ifdef DIAGNOSTIC - if (sr->sr_dma_hand) - panic("ncr5380_done: dma free did not"); -#endif - - if (sc->sc_state & NCR_ABORTING) { - NCR_TRACE("done: aborting, error=%d\n", xs->error); - if (xs->error == XS_NOERROR) - xs->error = XS_TIMEOUT; - } - - NCR_TRACE("done: check error=%d\n", (long) xs->error); - - /* If error is already set, ignore sr_status value. */ - if (xs->error != XS_NOERROR) - goto finish; - - NCR_TRACE("done: check status=%d\n", sr->sr_status); - - switch (sr->sr_status) { - case SCSI_OK: /* 0 */ - if (sr->sr_flags & SR_SENSE) { - if (ncr5380_debug & NCR_DBG_CMDS) { - ncr5380_show_sense(xs); - } - xs->error = XS_SENSE; - } - break; - - case SCSI_CHECK: - if (sr->sr_flags & SR_SENSE) { - /* Sense command also asked for sense? */ - printf("ncr5380_done: sense asked for sense\n"); - NCR_BREAK(); - xs->error = XS_DRIVER_STUFFUP; - break; - } - sr->sr_flags |= SR_SENSE; - NCR_TRACE("done: get sense, sr=0x%x\n", (long) sr); - /* - * Leave queued, but clear sc_current so we start over - * with selection. Guaranteed to get the same request. - */ - sc->sc_state = NCR_IDLE; - sc->sc_current = NULL; - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - return; /* XXX */ - - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - - case -1: - /* This is our "impossible" initial value. */ - /* fallthrough */ - default: - printf("%s: target %d, bad status=%d\n", - sc->sc_dev.dv_xname, sr->sr_target, sr->sr_status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - -finish: - - NCR_TRACE("done: finish, error=%d\n", xs->error); - - /* - * Dequeue the finished command, but don't clear sc_state until - * after the call to scsi_done(), because that may call back to - * ncr5380_scsi_cmd() - unwanted recursion! - * - * Keeping sc->sc_state != idle terminates the recursion. - */ -#ifdef DIAGNOSTIC - if ((sc->sc_state & NCR_WORKING) == 0) - panic("ncr5380_done: bad state"); -#endif - - /* Clear our pointers to the request. */ - sc->sc_current = NULL; - sc->sc_matrix[sr->sr_target][sr->sr_lun] = NULL; - untimeout(ncr5380_cmd_timeout, sr); - - /* Make the request free. */ - sr->sr_xs = NULL; - sc->sc_ncmds--; - - /* Tell common SCSI code it is done. */ - xs->flags |= ITSDONE; - scsi_done(xs); - - sc->sc_state = NCR_IDLE; - /* Now ncr5380_sched() may be called again. */ -} - - -/* - * Schedule a SCSI operation. This routine should return - * only after it achieves one of the following conditions: - * Busy (sc->sc_state != NCR_IDLE) - * No more work can be started. - */ -static void -ncr5380_sched(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - int target, lun; - int error, i; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_sched: bad spl"); -#endif - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_off) { - NCR_TRACE("sched: top, intr off\n", 0); - sc->sc_intr_off(sc); - } - -next_job: - /* - * Grab the next job from queue. Must be idle. - */ -#ifdef DIAGNOSTIC - if (sc->sc_state != NCR_IDLE) - panic("ncr5380_sched: not idle"); - if (sc->sc_current) - panic("ncr5380_sched: current set"); -#endif - - /* - * Always start the search where we last looked. - * The REQUEST_SENSE logic depends on this to - * choose the same job as was last picked, so it - * can just clear sc_current and reschedule. - * (Avoids loss of "contingent allegiance".) - */ - i = sc->sc_rr; - sr = NULL; - do { - if (sc->sc_ring[i].sr_xs) { - target = sc->sc_ring[i].sr_target; - lun = sc->sc_ring[i].sr_lun; - if (sc->sc_matrix[target][lun] == NULL) { - sc->sc_matrix[target][lun] = - sr = &sc->sc_ring[i]; - sc->sc_rr = i; - break; - } - } - i++; - if (i == SCI_OPENINGS) - i = 0; - } while (i != sc->sc_rr); - - if (sr == NULL) { - NCR_TRACE("sched: no work, cur=0x%x\n", - (long) sc->sc_current); - - /* Another hack (Er.. hook!) for the sun3 si: */ - if (sc->sc_intr_on) { - NCR_TRACE("sched: ret, intr ON\n", 0); - sc->sc_intr_on(sc); - } - - return; /* No more work to do. */ - } - - NCR_TRACE("sched: select for t/l=0x%02x\n", - (sr->sr_target << 4) | sr->sr_lun); - - sc->sc_state = NCR_WORKING; - error = ncr5380_select(sc, sr); - if (sc->sc_current) { - /* Lost the race! reselected out from under us! */ - /* Work with the reselected job. */ - if (sr->sr_flags & SR_IMMED) { - printf("%s: reselected while polling (abort)\n", - sc->sc_dev.dv_xname); - /* Abort the reselected job. */ - sc->sc_state |= NCR_ABORTING; - sc->sc_msgpriq |= SEND_ABORT; - } - sr = sc->sc_current; - xs = sr->sr_xs; - NCR_TRACE("sched: reselect, new sr=0x%x\n", (long)sr); - goto have_nexus; - } - - /* Normal selection result */ - sc->sc_current = sr; /* connected */ - xs = sr->sr_xs; - - /* - * Initialize pointers, etc. for this job - */ - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = SEND_IDENTIFY; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - NCR_TRACE("sched: select rv=%d\n", error); - - switch (error) { - case XS_NOERROR: - break; - - case XS_BUSY: - /* XXX - Reset and try again. */ - printf("%s: SCSI bus busy, resetting...\n", - sc->sc_dev.dv_xname); - ncr5380_reset_scsibus(sc); - /* fallthrough */ - case XS_SELTIMEOUT: - default: - xs->error = error; /* from select */ - NCR_TRACE("sched: call done, sr=0x%x\n", (long)sr); - ncr5380_done(sc); - - /* Paranoia: clear everything. */ - sc->sc_dataptr = NULL; - sc->sc_datalen = 0; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - goto next_job; - } - - /* - * Selection was successful. Normally, this means - * we are starting a new command. However, this - * might be the termination of an overdue job. - */ - if (sr->sr_flags & SR_OVERDUE) { - NCR_TRACE("sched: overdue, sr=0x%x\n", (long)sr); - sc->sc_state |= NCR_ABORTING; - sc->sc_msgpriq |= SEND_ABORT; - goto have_nexus; - } - - /* - * This may be the continuation of some job that - * completed with a "check condition" code. - */ - if (sr->sr_flags & SR_SENSE) { - NCR_TRACE("sched: get sense, sr=0x%x\n", (long)sr); - /* Do not allocate DMA, nor set timeout. */ - goto have_nexus; - } - - /* - * OK, we are starting a new command. - * Initialize and allocate resources for the new command. - * Device reset is special (only uses MSG_OUT phase). - * Normal commands start in MSG_OUT phase where we will - * send and IDENDIFY message, and then expect CMD phase. - */ - if (ncr5380_debug & NCR_DBG_CMDS) { - printf("ncr5380_sched: begin, target=%d, LUN=%d\n", - xs->sc_link->target, xs->sc_link->lun); - ncr5380_show_scsi_cmd(xs); - } - if (xs->flags & SCSI_RESET) { - NCR_TRACE("sched: cmd=reset, sr=0x%x\n", (long)sr); - /* Not an error, so do not set NCR_ABORTING */ - sc->sc_msgpriq |= SEND_DEV_RESET; - goto have_nexus; - } - -#ifdef DIAGNOSTIC - if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) == 0) { - if (sc->sc_dataptr) { - printf("%s: ptr but no data in/out flags?\n"); - NCR_BREAK(); - sc->sc_dataptr = NULL; - } - } -#endif - - /* Allocate DMA space (maybe) */ - if (sc->sc_dataptr && sc->sc_dma_alloc && - (sc->sc_datalen >= sc->sc_min_dma_len)) - { - NCR_TRACE("sched: dma_alloc, len=%d\n", sc->sc_datalen); - (*sc->sc_dma_alloc)(sc); - } - - /* - * Initialization hook called just after select, - * at the beginning of COMMAND phase. - * (but AFTER the DMA allocation is done) - * - * The evil Sun "si" adapter (OBIO variant) needs some - * setup done to the DMA engine BEFORE the target puts - * the SCSI bus into any DATA phase. - */ - if (sr->sr_dma_hand && sc->sc_dma_setup) { - NCR_TRACE("sched: dma_setup, dh=0x%x\n", - (long) sr->sr_dma_hand); - sc->sc_dma_setup(sc); - } - - /* - * Schedule a timeout for the job we are starting. - */ - if ((sr->sr_flags & SR_IMMED) == 0) { - i = (xs->timeout * hz) / 1000; - NCR_TRACE("sched: set timeout=%d\n", i); - timeout(ncr5380_cmd_timeout, sr, i); - } - -have_nexus: - NCR_TRACE("sched: call machine, cur=0x%x\n", - (long) sc->sc_current); - ncr5380_machine(sc); - NCR_TRACE("sched: machine done, cur=0x%x\n", - (long) sc->sc_current); - - /* - * What state did ncr5380_machine() leave us in? - * Hopefully it sometimes completes a job... - */ - if (sc->sc_state == NCR_IDLE) - goto next_job; - - return; /* Have work in progress. */ -} - - -/* - * Reselect handler: checks for reselection, and if we are being - * reselected, it sets up sc->sc_current. - * - * We are reselected when: - * SEL is TRUE - * IO is TRUE - * BSY is FALSE - */ -void -ncr5380_reselect(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - int target, lun, phase, timo; - u_char bus, data, icmd, msg; - -#ifdef DIAGNOSTIC - /* - * Note: sc_state will be "idle" when ncr5380_intr() - * calls, or "working" when ncr5380_select() calls. - * (So don't test that in this DIAGNOSTIC) - */ - if (sc->sc_current) - panic("ncr5380_reselect: current set"); -#endif - - /* - * First, check the select line. - * (That has to be set first.) - */ - bus = *(sc->sci_bus_csr); - if ((bus & SCI_BUS_SEL) == 0) { - /* Not a selection or reselection. */ - return; - } - - /* - * The target will assert BSY first (for bus arbitration), - * then raise SEL, and finally drop BSY. Only then is the - * data bus required to have valid selection ID bits set. - * Wait for: SEL==1, BSY==0 before reading the data bus. - */ - timo = ncr5380_wait_nrq_timo; - for (;;) { - if ((bus & SCI_BUS_BSY) == 0) - break; - /* Probably never get here... */ - if (--timo <= 0) { - printf("%s: reselect, BSY stuck, bus=0x%x\n", - sc->sc_dev.dv_xname, bus); - /* Not much we can do. Reset the bus. */ - ncr5380_reset_scsibus(sc); - return; - } - delay(10); - bus = *(sc->sci_bus_csr); - /* If SEL went away, forget it. */ - if ((bus & SCI_BUS_SEL) == 0) - return; - /* Still have SEL, check BSY. */ - } - NCR_TRACE("reselect, valid data after %d loops\n", - ncr5380_wait_nrq_timo - timo); - - /* - * Good. We have SEL=1 and BSY=0. Now wait for a - * "bus settle delay" before we sample the data bus - */ - delay(2); - data = *(sc->sci_data) & 0xFF; - /* XXX - Should check parity... */ - - /* - * Is this a reselect (I/O == 1) or have we been - * selected as a target? (I/O == 0) - */ - if ((bus & SCI_BUS_IO) == 0) { - printf("%s: selected as target, data=0x%x\n", - sc->sc_dev.dv_xname, data); - /* Not much we can do. Reset the bus. */ - ncr5380_reset_scsibus(sc); - return; - } - - /* - * OK, this is a reselection. - */ - for (target = 0; target < 7; target++) - if (data & (1 << target)) - break; - - if ((data & 0x7F) != (1 << target)) { - /* No selecting ID? or >2 IDs on bus? */ - printf("%s: bad reselect, data=0x%x\n", - sc->sc_dev.dv_xname, data); - return; - } - - NCR_TRACE("reselect: target=0x%x\n", target); - - /* Raise BSY to acknowledge target reselection. */ - *(sc->sci_icmd) = SCI_ICMD_BSY; - - /* Wait for target to drop SEL. */ - timo = ncr5380_wait_nrq_timo; - for (;;) { - bus = *(sc->sci_bus_csr); - if ((bus & SCI_BUS_SEL) == 0) - break; /* success */ - if (--timo <= 0) { - printf("%s: reselect, SEL stuck, bus=0x%x\n", - sc->sc_dev.dv_xname, bus); - NCR_BREAK(); - /* assume connected (fail later if not) */ - break; - } - delay(2); - } - - /* Now we drop BSY, and we are connected. */ - *(sc->sci_icmd) = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - - /* - * At this point the target should send an IDENTIFY message, - * which will permit us to determine the reselecting LUN. - * If not, we assume LUN 0. - */ - lun = 0; - /* Wait for REQ before reading bus phase. */ - if (ncr5380_wait_req(sc)) { - printf("%s: reselect, no REQ\n", - sc->sc_dev.dv_xname); - /* Try to send an ABORT message. */ - goto abort; - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_IN) { - printf("%s: reselect, phase=%d\n", - sc->sc_dev.dv_xname, phase); - goto abort; - } - - /* Ack. the change to PHASE_MSG_IN */ - *(sc->sci_tcmd) = PHASE_MSG_IN; - - /* Peek at the message byte without consuming it! */ - msg = *(sc->sci_data); - if ((msg & 0x80) == 0) { - printf("%s: reselect, not identify, msg=%d\n", - sc->sc_dev.dv_xname, msg); - goto abort; - } - lun = msg & 7; - - /* We now know target/LUN. Do we have the request? */ - sr = sc->sc_matrix[target][lun]; - if (sr) { - /* We now have a nexus. */ - sc->sc_state |= NCR_WORKING; - sc->sc_current = sr; - NCR_TRACE("reselect: resume sr=0x%x\n", (long)sr); - - /* Implicit restore pointers message */ - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - /* - * Another hack for the Sun3 "si", which needs - * some setup done to its DMA engine before the - * target puts the SCSI bus into any DATA phase. - */ - if (sr->sr_dma_hand && sc->sc_dma_setup) { - NCR_TRACE("reselect: call DMA setup, dh=0x%x\n", - (long) sr->sr_dma_hand); - sc->sc_dma_setup(sc); - } - - /* Now consume the IDENTIFY message. */ - ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg); - return; - } - - printf("%s: phantom reselect: target=%d, LUN=%d\n", - sc->sc_dev.dv_xname, target, lun); -abort: - /* - * Try to send an ABORT message. This makes us - * temporarily busy, but no current command... - */ - sc->sc_state |= NCR_ABORTING; - - /* Raise ATN, delay, raise ACK... */ - icmd = SCI_ICMD_ATN; - *sc->sci_icmd = icmd; - delay(2); - - /* Now consume the IDENTIFY message. */ - ncr5380_pio_in(sc, PHASE_MSG_IN, 1, &msg); - - /* Finally try to send the ABORT. */ - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = SEND_ABORT; - ncr5380_msg_out(sc); - - *(sc->sci_tcmd) = PHASE_INVALID; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - - sc->sc_state &= ~NCR_ABORTING; -} - - -/* - * Select target: xs is the transfer that we are selecting for. - * sc->sc_current should be NULL. - * - * Returns: - * sc->sc_current != NULL ==> we were reselected (race!) - * XS_NOERROR ==> selection worked - * XS_BUSY ==> lost arbitration - * XS_SELTIMEOUT ==> no response to selection - */ -static int -ncr5380_select(sc, sr) - struct ncr5380_softc *sc; - struct sci_req *sr; -{ - int timo; - u_char bus, data, icmd; - - /* Check for reselect */ - ncr5380_reselect(sc); - if (sc->sc_current) { - NCR_TRACE("select: reselect, cur=0x%x\n", - (long) sc->sc_current); - return XS_BUSY; /* reselected */ - } - - /* - * Set phase bits to 0, otherwise the 5380 won't drive the bus during - * selection. - */ - *sc->sci_tcmd = PHASE_DATA_OUT; - *sc->sci_icmd = icmd = 0; - *sc->sci_mode = 0; - - /* - * Arbitrate for the bus. The 5380 takes care of the - * time-critical bus interactions. We set our ID bit - * in the output data register and set MODE_ARB. The - * 5380 watches for the required "bus free" period. - * If and when the "bus free" period is detected, the - * 5380 then drives BSY, drives the data bus, and sets - * the "arbitration in progress" (AIP) bit to let us - * know arbitration has started. We then wait for one - * arbitration delay (2.2uS) and check the ICMD_LST bit, - * which will be set if someone else drives SEL. - */ - *(sc->sci_odata) = 0x80; /* OUR_ID */ - *(sc->sci_mode) = SCI_MODE_ARB; - - /* Wait for ICMD_AIP. */ - timo = ncr5380_wait_req_timo; - for (;;) { - if (*(sc->sci_icmd) & SCI_ICMD_AIP) - break; - if (--timo <= 0) { - /* Did not see any "bus free" period. */ - *sc->sci_mode = 0; - NCR_TRACE("select: bus busy, rc=%d\n", XS_BUSY); - return XS_BUSY; - } - delay(2); - } - NCR_TRACE("select: have AIP after %d loops\n", - ncr5380_wait_req_timo - timo); - - /* Got AIP. Wait one arbitration delay (2.2 uS.) */ - delay(3); - - /* Check for ICMD_LST */ - if (*(sc->sci_icmd) & SCI_ICMD_LST) { - /* Some other target asserted SEL. */ - *sc->sci_mode = 0; - NCR_TRACE("select: lost one, rc=%d\n", XS_BUSY); - ncr5380_reselect(sc); /* XXX */ - return XS_BUSY; - } - - /* - * No other device has declared itself the winner. - * The spec. says to check for higher IDs, but we - * are always the highest (ID=7) so don't bother. - * We can now declare victory by asserting SEL. - * - * Note that the 5380 is asserting BSY because we - * asked it to do arbitration. We will now hold - * BSY directly so we can turn off ARB mode. - */ - icmd = (SCI_ICMD_BSY | SCI_ICMD_SEL); - *sc->sci_icmd = icmd; - - /* - * "The SCSI device that wins arbitration shall wait - * at least a bus clear delay plus a bus settle delay - * after asserting the SEL signal before changing - * any [other] signal." (1.2uS. total) - */ - delay(2); - -#if 1 - /* - * XXX: Check one last time to see if we really - * XXX: did win arbitration. (too paranoid?) - */ - if (*(sc->sci_icmd) & SCI_ICMD_LST) { - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - NCR_TRACE("select: lost two, rc=%d\n", XS_BUSY); - return XS_BUSY; - } -#endif - /* Leave ARB mode Now that we drive BSY+SEL */ - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - - /* - * Arbitration is complete. Now do selection: - * Drive the data bus with the ID bits for both - * the host and target. Also set ATN now, to - * ask the target for a messgae out phase. - */ - data = 0x80 | (1 << sr->sr_target); - *(sc->sci_odata) = data; - icmd |= (SCI_ICMD_DATA | SCI_ICMD_ATN); - *(sc->sci_icmd) = icmd; - delay(2); /* two deskew delays. */ - - /* De-assert BSY (targets sample the data now). */ - icmd &= ~SCI_ICMD_BSY; - *(sc->sci_icmd) = icmd; - delay(3); /* Bus settle delay. */ - - /* - * Wait for the target to assert BSY. - * SCSI spec. says wait for 250 mS. - */ - for (timo = 25000;;) { - if (*sc->sci_bus_csr & SCI_BUS_BSY) - goto success; - if (--timo <= 0) - break; - delay(10); - } - - /* - * There is no reaction from the target. Start the selection - * timeout procedure. We release the databus but keep SEL+ATN - * asserted. After that we wait a 'selection abort time' (200 - * usecs) and 2 deskew delays (90 ns) and check BSY again. - * When BSY is asserted, we assume the selection succeeded, - * otherwise we release the bus. - */ - icmd &= ~SCI_ICMD_DATA; - *(sc->sci_icmd) = icmd; - delay(201); - if ((*sc->sci_bus_csr & SCI_BUS_BSY) == 0) { - /* Really no device on bus */ - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - NCR_TRACE("select: device down, rc=%d\n", XS_SELTIMEOUT); - return XS_SELTIMEOUT; - } - -success: - /* - * The target is now driving BSY, so we can stop - * driving SEL and the data bus (keep ATN true). - * Configure the ncr5380 to monitor BSY, parity. - */ - icmd &= ~(SCI_ICMD_DATA | SCI_ICMD_SEL); - *sc->sci_icmd = icmd; - - /* XXX - Make parity checking optional? */ - *sc->sci_mode = (SCI_MODE_MONBSY | SCI_MODE_PAR_CHK); - - return XS_NOERROR; -} - - -/***************************************************************** - * Functions to handle each info. transfer phase: - *****************************************************************/ - -/* - * The message system: - * - * This is a revamped message system that now should easier accomodate - * new messages, if necessary. - * - * Currently we accept these messages: - * IDENTIFY (when reselecting) - * COMMAND COMPLETE # (expect bus free after messages marked #) - * NOOP - * MESSAGE REJECT - * SYNCHRONOUS DATA TRANSFER REQUEST - * SAVE DATA POINTER - * RESTORE POINTERS - * DISCONNECT # - * - * We may send these messages in prioritized order: - * BUS DEVICE RESET # if SCSI_RESET & xs->flags (or in weird sits.) - * MESSAGE PARITY ERROR par. err. during MSGI - * MESSAGE REJECT If we get a message we don't know how to handle - * ABORT # send on errors - * INITIATOR DETECTED ERROR also on errors (SCSI2) (during info xfer) - * IDENTIFY At the start of each transfer - * SYNCHRONOUS DATA TRANSFER REQUEST if appropriate - * NOOP if nothing else fits the bill ... - */ - -#define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80) -#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20) -#define ISEXTMSG(m) ((m) == 0x01) - -/* - * Precondition: - * The SCSI bus is already in the MSGI phase and there is a message byte - * on the bus, along with an asserted REQ signal. - * - * Our return value determines whether our caller, ncr5380_machine() - * will expect to see another REQ (and possibly phase change). - */ -static int -ncr5380_msg_in(sc) - register struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - int n, phase, timo; - int act_flags; - register u_char icmd; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_MSG_IN; - - act_flags = ACT_CONTINUE; - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - - if (sc->sc_prevphase == PHASE_MSG_IN) { - /* This is a continuation of the previous message. */ - n = sc->sc_imp - sc->sc_imess; - NCR_TRACE("msg_in: continuation, n=%d\n", n); - goto nextbyte; - } - - /* This is a new MESSAGE IN phase. Clean up our state. */ - sc->sc_state &= ~NCR_DROP_MSGIN; - -nextmsg: - n = 0; - sc->sc_imp = &sc->sc_imess[n]; - -nextbyte: - /* - * Read a whole message, but don't ack the last byte. If we reject the - * message, we have to assert ATN during the message transfer phase - * itself. - */ - for (;;) { - /* - * Read a message byte. - * First, check BSY, REQ, phase... - */ - if (!SCI_BUSY(sc)) { - NCR_TRACE("msg_in: lost BSY, n=%d\n", n); - /* XXX - Assume the command completed? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - return (act_flags); - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("msg_in: BSY but no REQ, n=%d\n", n); - /* Just let ncr5380_machine() handle it... */ - return (act_flags); - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_IN) { - /* - * Target left MESSAGE IN, probably because it - * a) noticed our ATN signal, or - * b) ran out of messages. - */ - return (act_flags); - } - /* Still in MESSAGE IN phase, and REQ is asserted. */ - if (*sc->sci_csr & SCI_CSR_PERR) { - ncr_sched_msgout(sc, SEND_PARITY_ERROR); - sc->sc_state |= NCR_DROP_MSGIN; - } - - /* Gather incoming message bytes if needed. */ - if ((sc->sc_state & NCR_DROP_MSGIN) == 0) { - if (n >= NCR_MAX_MSG_LEN) { - ncr_sched_msgout(sc, SEND_REJECT); - sc->sc_state |= NCR_DROP_MSGIN; - } else { - *sc->sc_imp++ = *sc->sci_data; - n++; - /* - * This testing is suboptimal, but most - * messages will be of the one byte variety, so - * it should not affect performance - * significantly. - */ - if (n == 1 && IS1BYTEMSG(sc->sc_imess[0])) - goto have_msg; - if (n == 2 && IS2BYTEMSG(sc->sc_imess[0])) - goto have_msg; - if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) && - n == sc->sc_imess[1] + 2) - goto have_msg; - } - } - - /* - * If we reach this spot we're either: - * a) in the middle of a multi-byte message, or - * b) dropping bytes. - */ - - /* Ack the last byte read. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_in: drop, stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (act_flags != ACT_CONTINUE) - return (act_flags); - - /* back to nextbyte */ - } - -have_msg: - /* We now have a complete message. Parse it. */ - - switch (sc->sc_imess[0]) { - case MSG_CMDCOMPLETE: - NCR_TRACE("msg_in: CMDCOMPLETE\n", 0); - /* Target is about to disconnect. */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - break; - - case MSG_DISCONNECT: - NCR_TRACE("msg_in: DISCONNECT\n", 0); - /* Target is about to disconnect. */ - act_flags |= ACT_DISCONNECT; - break; - - case MSG_PARITY_ERROR: - NCR_TRACE("msg_in: PARITY_ERROR\n", 0); - /* Resend the last message. */ - ncr_sched_msgout(sc, sc->sc_msgout); - break; - - case MSG_MESSAGE_REJECT: - /* The target rejects the last message we sent. */ - NCR_TRACE("msg_in: got reject for 0x%x\n", sc->sc_msgout); - switch (sc->sc_msgout) { - case SEND_IDENTIFY: - /* Really old target controller? */ - /* XXX ... */ - break; - case SEND_INIT_DET_ERR: - goto abort; - } - break; - - case MSG_NOOP: - NCR_TRACE("msg_in: NOOP\n", 0); - break; - - case MSG_SAVEDATAPOINTER: - NCR_TRACE("msg_in: SAVE_PTRS\n", 0); - sr->sr_dataptr = sc->sc_dataptr; - sr->sr_datalen = sc->sc_datalen; - break; - - case MSG_RESTOREPOINTERS: - NCR_TRACE("msg_in: RESTORE_PTRS\n", 0); - sc->sc_dataptr = sr->sr_dataptr; - sc->sc_datalen = sr->sr_datalen; - break; - - case MSG_EXTENDED: - switch (sc->sc_imess[2]) { - case MSG_EXT_SDTR: - case MSG_EXT_WDTR: - /* The ncr5380 can not do synchronous mode. */ - goto reject; - default: - printf("%s: unrecognized MESSAGE EXTENDED; sending REJECT\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto reject; - } - break; - - default: - NCR_TRACE("msg_in: eh? imsg=0x%x\n", sc->sc_imess[0]); - printf("%s: unrecognized MESSAGE; sending REJECT\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - /* fallthrough */ - reject: - ncr_sched_msgout(sc, SEND_REJECT); - break; - - abort: - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - break; - } - - /* Ack the last byte read. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_in: last, stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Go get the next message, if any. */ - if (act_flags == ACT_CONTINUE) - goto nextmsg; - - return (act_flags); -} - - -/* - * The message out (and in) stuff is a bit complicated: - * If the target requests another message (sequence) without - * having changed phase in between it really asks for a - * retransmit, probably due to parity error(s). - * The following messages can be sent: - * IDENTIFY @ These 4 stem from SCSI command activity - * SDTR @ - * WDTR @ - * DEV_RESET @ - * REJECT if MSGI doesn't make sense - * PARITY_ERROR if parity error while in MSGI - * INIT_DET_ERR if parity error while not in MSGI - * ABORT if INIT_DET_ERR rejected - * NOOP if asked for a message and there's nothing to send - * - * Note that we call this one with (sc_current == NULL) - * when sending ABORT for unwanted reselections. - */ -static int -ncr5380_msg_out(sc) - register struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - int n, phase, resel; - int progress, act_flags; - register u_char icmd; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_MSG_OUT; - - progress = 0; /* did we send any messages? */ - act_flags = ACT_CONTINUE; - - /* - * Set ATN. If we're just sending a trivial 1-byte message, - * we'll clear ATN later on anyway. Also drive the data bus. - */ - icmd = *sc->sci_icmd & SCI_ICMD_RMASK; - icmd |= (SCI_ICMD_ATN | SCI_ICMD_DATA); - *sc->sci_icmd = icmd; - - if (sc->sc_prevphase == PHASE_MSG_OUT) { - if (sc->sc_omp == sc->sc_omess) { - /* - * This is a retransmission. - * - * We get here if the target stayed in MESSAGE OUT - * phase. Section 5.1.9.2 of the SCSI 2 spec indicates - * that all of the previously transmitted messages must - * be sent again, in the same order. Therefore, we - * requeue all the previously transmitted messages, and - * start again from the top. Our simple priority - * scheme keeps the messages in the right order. - */ - sc->sc_msgpriq |= sc->sc_msgoutq; - NCR_TRACE("msg_out: retrans priq=0x%x\n", sc->sc_msgpriq); - } else { - /* This is a continuation of the previous message. */ - n = sc->sc_omp - sc->sc_omess; - NCR_TRACE("msg_out: continuation, n=%d\n", n); - goto nextbyte; - } - } - - /* No messages transmitted so far. */ - sc->sc_msgoutq = 0; - -nextmsg: - /* Pick up highest priority message. */ - sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; - sc->sc_msgpriq &= ~sc->sc_msgout; - sc->sc_msgoutq |= sc->sc_msgout; - - /* Build the outgoing message data. */ - switch (sc->sc_msgout) { - case SEND_IDENTIFY: - NCR_TRACE("msg_out: SEND_IDENTIFY\n", 0); - if (sr == NULL) { - printf("%s: SEND_IDENTIFY while not connected; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto noop; - } - resel = (sc->sc_flags & NCR5380_PERMIT_RESELECT) ? 1 : 0; - resel &= (sr->sr_flags & (SR_IMMED | SR_SENSE)) ? 0 : 1; - sc->sc_omess[0] = MSG_IDENTIFY(sr->sr_lun, resel); - n = 1; - break; - - case SEND_DEV_RESET: - NCR_TRACE("msg_out: SEND_DEV_RESET\n", 0); - /* Expect disconnect after this! */ - /* XXX: Kill jobs for this target? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - sc->sc_omess[0] = MSG_BUS_DEV_RESET; - n = 1; - break; - - case SEND_REJECT: - NCR_TRACE("msg_out: SEND_REJECT\n", 0); - sc->sc_omess[0] = MSG_MESSAGE_REJECT; - n = 1; - break; - - case SEND_PARITY_ERROR: - NCR_TRACE("msg_out: SEND_PARITY_ERROR\n", 0); - sc->sc_omess[0] = MSG_PARITY_ERROR; - n = 1; - break; - - case SEND_INIT_DET_ERR: - NCR_TRACE("msg_out: SEND_INIT_DET_ERR\n", 0); - sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; - n = 1; - break; - - case SEND_ABORT: - NCR_TRACE("msg_out: SEND_ABORT\n", 0); - /* Expect disconnect after this! */ - /* XXX: Set error flag? */ - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - sc->sc_omess[0] = MSG_ABORT; - n = 1; - break; - - case 0: - printf("%s: unexpected MESSAGE OUT; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - noop: - NCR_TRACE("msg_out: send NOOP\n", 0); - sc->sc_omess[0] = MSG_NOOP; - n = 1; - break; - - default: - printf("%s: weird MESSAGE OUT; sending NOOP\n", - sc->sc_dev.dv_xname); - NCR_BREAK(); - goto noop; - } - sc->sc_omp = &sc->sc_omess[n]; - -nextbyte: - /* Send message bytes. */ - while (n > 0) { - /* - * Send a message byte. - * First check BSY, REQ, phase... - */ - if (!SCI_BUSY(sc)) { - NCR_TRACE("msg_out: lost BSY, n=%d\n", n); - goto out; - } - if (ncr5380_wait_req(sc)) { - NCR_TRACE("msg_out: no REQ, n=%d\n", n); - goto out; - } - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - if (phase != PHASE_MSG_OUT) { - /* - * Target left MESSAGE OUT, possibly to reject - * our message. - */ - NCR_TRACE("msg_out: new phase=%d\n", phase); - goto out; - } - - /* Yes, we can send this message byte. */ - --n; - - /* Clear ATN before last byte if this is the last message. */ - if (n == 0 && sc->sc_msgpriq == 0) { - icmd &= ~SCI_ICMD_ATN; - *sc->sci_icmd = icmd; - /* 2 deskew delays */ - delay(2); /* XXX */ - } - - /* Put data on the bus. */ - *sc->sci_odata = *--sc->sc_omp; - - /* Raise ACK to tell target data is on the bus. */ - icmd |= SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Wait for REQ to be negated. */ - if (ncr5380_wait_not_req(sc)) { - NCR_TRACE("msg_out: stuck REQ, n=%d\n", n); - act_flags |= ACT_RESET_BUS; - } - - /* Finally, drop ACK. */ - icmd &= ~SCI_ICMD_ACK; - *sc->sci_icmd = icmd; - - /* Stuck bus or something... */ - if (act_flags & ACT_RESET_BUS) - goto out; - - } - progress++; - - /* We get here only if the entire message has been transmitted. */ - if (sc->sc_msgpriq != 0) { - /* There are more outgoing messages. */ - goto nextmsg; - } - - /* - * The last message has been transmitted. We need to remember the last - * message transmitted (in case the target switches to MESSAGE IN phase - * and sends a MESSAGE REJECT), and the list of messages transmitted - * this time around (in case the target stays in MESSAGE OUT phase to - * request a retransmit). - */ - -out: - /* Stop driving the data bus. */ - icmd &= ~SCI_ICMD_DATA; - *sc->sci_icmd = icmd; - - if (!progress) - act_flags |= ACT_RESET_BUS; - - return (act_flags); -} - - -/* - * Handle command phase. - */ -static int -ncr5380_command(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - struct scsi_sense rqs; - int len; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_COMMAND; - - if (sr->sr_flags & SR_SENSE) { - rqs.opcode = REQUEST_SENSE; - rqs.byte2 = xs->sc_link->lun << 5; - rqs.length = sizeof(xs->sense); - - rqs.unused[0] = rqs.unused[1] = rqs.control = 0; - len = ncr5380_pio_out(sc, PHASE_COMMAND, sizeof(rqs), - (u_char *)&rqs); - } - else { - /* Assume command can be sent in one go. */ - /* XXX: Do this using DMA, and get a phase change intr? */ - len = ncr5380_pio_out(sc, PHASE_COMMAND, xs->cmdlen, - (u_char *)xs->cmd); - } - - if (len != xs->cmdlen) { -#ifdef DEBUG - printf("ncr5380_command: short transfer: wanted %d got %d.\n", - xs->cmdlen, len); - ncr5380_show_scsi_cmd(xs); - NCR_BREAK(); -#endif - if (len < 6) { - xs->error = XS_DRIVER_STUFFUP; - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - } - - } - - return ACT_CONTINUE; -} - - -/* - * Handle either data_in or data_out - */ -static int -ncr5380_data_xfer(sc, phase) - struct ncr5380_softc *sc; - int phase; -{ - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - int expected_phase; - int i, len; - - if (sr->sr_flags & SR_SENSE) { - NCR_TRACE("data_xfer: get sense, sr=0x%x\n", (long)sr); - if (phase != PHASE_DATA_IN) { - printf("%s: sense phase error\n", sc->sc_dev.dv_xname); - goto abort; - } - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_DATA_IN; - len = ncr5380_pio_in(sc, phase, sizeof(xs->sense), - (u_char *)&xs->sense); - return ACT_CONTINUE; - } - - /* - * When aborting a command, disallow any data phase. - */ - if (sc->sc_state & NCR_ABORTING) { - printf("%s: aborting, but phase=%s (reset)\n", - sc->sc_dev.dv_xname, - phase_names[phase & 7]); - return ACT_RESET_BUS; /* XXX */ - } - - /* Validate expected phase (data_in or data_out) */ - expected_phase = (xs->flags & SCSI_DATA_OUT) ? - PHASE_DATA_OUT : PHASE_DATA_IN; - if (phase != expected_phase) { - printf("%s: data phase error\n", - sc->sc_dev.dv_xname); - goto abort; - } - - /* Make sure we have some data to move. */ - if (sc->sc_datalen <= 0) { - printf("%s: can not transfer more data\n", - sc->sc_dev.dv_xname); - goto abort; - } - - /* - * Attempt DMA only if dma_alloc gave us a DMA handle AND - * there is enough left to transfer so DMA is worth while. - */ - if (sr->sr_dma_hand && - (sc->sc_datalen >= sc->sc_min_dma_len)) - { - /* - * OK, really start DMA. Note, the MI start function - * is responsible for setting the TCMD register, etc. - * (Acknowledge the phase change there, not here.) - */ - NCR_TRACE("data_xfer: dma_start, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_start)(sc); - return ACT_WAIT_DMA; - } - - NCR_TRACE("data_xfer: doing PIO, len=%d\n", sc->sc_datalen); - - /* acknowledge phase change */ - *sc->sci_tcmd = phase; - if (phase == PHASE_DATA_OUT) { - len = ncr5380_pio_out(sc, phase, sc->sc_datalen, sc->sc_dataptr); - } else { - len = ncr5380_pio_in (sc, phase, sc->sc_datalen, sc->sc_dataptr); - } - sc->sc_dataptr += len; - sc->sc_datalen -= len; - - NCR_TRACE("data_xfer: did PIO, resid=%d\n", sc->sc_datalen); - return (ACT_CONTINUE); - -abort: - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - return (ACT_CONTINUE); -} - - -static int -ncr5380_status(sc) - struct ncr5380_softc *sc; -{ - int len; - u_char status; - struct sci_req *sr = sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - - /* acknowledge phase change */ - *sc->sci_tcmd = PHASE_STATUS; - - len = ncr5380_pio_in(sc, PHASE_STATUS, 1, &status); - if (len) { - sr->sr_status = status; - } else { - printf("ncr5380_status: none?\n"); - } - - return ACT_CONTINUE; -} - - -/* - * This is the big state machine that follows SCSI phase changes. - * This is somewhat like a co-routine. It will do a SCSI command, - * and exit if the command is complete, or if it must wait, i.e. - * for DMA to complete or for reselect to resume the job. - * - * The bus must be selected, and we need to know which command is - * being undertaken. - */ -static void -ncr5380_machine(sc) - struct ncr5380_softc *sc; -{ - struct sci_req *sr; - struct scsi_xfer *xs; - int act_flags, phase, timo; - -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr5380_machine: bad spl"); - if (sc->sc_state == NCR_IDLE) - panic("ncr5380_machine: state=idle"); - if (sc->sc_current == NULL) - panic("ncr5380_machine: no current cmd"); -#endif - - sr = sc->sc_current; - xs = sr->sr_xs; - act_flags = ACT_CONTINUE; - - /* - * This will be called by ncr5380_intr() when DMA is - * complete. Must stop DMA before touching the 5380 or - * there will be "register conflict" errors. - */ - if (sc->sc_state & NCR_DOINGDMA) { - /* Pick-up where where we left off... */ - goto dma_done; - } - -next_phase: - - if (!SCI_BUSY(sc)) { - /* Unexpected disconnect */ - printf("ncr5380_machine: unexpected disconnect.\n"); - xs->error = XS_DRIVER_STUFFUP; - act_flags |= (ACT_DISCONNECT | ACT_CMD_DONE); - goto do_actions; - } - - /* - * Wait for REQ before reading the phase. - * Need to wait longer than usual here, because - * some devices are just plain slow... - */ - timo = ncr5380_wait_phase_timo; - for (;;) { - if (*sc->sci_bus_csr & SCI_BUS_REQ) - break; - if (--timo <= 0) { - if (sc->sc_state & NCR_ABORTING) { - printf("%s: no REQ while aborting, reset\n", - sc->sc_dev.dv_xname); - act_flags |= ACT_RESET_BUS; - goto do_actions; - } - printf("%s: no REQ for next phase, abort\n", - sc->sc_dev.dv_xname); - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - goto next_phase; - } - delay(100); - } - - phase = SCI_BUS_PHASE(*sc->sci_bus_csr); - NCR_TRACE("machine: phase=%s\n", - (long) phase_names[phase & 7]); - - /* - * We assume that the device knows what it's doing, - * so any phase is good. - */ - -#if 0 - /* - * XXX: Do not ACK the phase yet! do it later... - * XXX: ... each phase routine does that itself. - * In particular, DMA needs it done LATER. - */ - *sc->sci_tcmd = phase; /* acknowledge phase change */ -#endif - - switch (phase) { - - case PHASE_DATA_OUT: - case PHASE_DATA_IN: - act_flags = ncr5380_data_xfer(sc, phase); - break; - - case PHASE_COMMAND: - act_flags = ncr5380_command(sc); - break; - - case PHASE_STATUS: - act_flags = ncr5380_status(sc); - break; - - case PHASE_MSG_OUT: - act_flags = ncr5380_msg_out(sc); - break; - - case PHASE_MSG_IN: - act_flags = ncr5380_msg_in(sc); - break; - - default: - printf("ncr5380_machine: Unexpected phase 0x%x\n", phase); - sc->sc_state |= NCR_ABORTING; - ncr_sched_msgout(sc, SEND_ABORT); - goto next_phase; - - } /* switch */ - sc->sc_prevphase = phase; - -do_actions: - __asm("_ncr5380_actions:"); - - if (act_flags & ACT_WAIT_DMA) { - act_flags &= ~ACT_WAIT_DMA; - /* Wait for DMA to complete (polling, or interrupt). */ - if ((sr->sr_flags & SR_IMMED) == 0) { - NCR_TRACE("machine: wait for DMA intr.\n", 0); - return; /* will resume at dma_done */ - } - /* Busy-wait for it to finish. */ - NCR_TRACE("machine: dma_poll, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_poll)(sc); - dma_done: - /* Return here after interrupt. */ - if (sr->sr_flags & SR_OVERDUE) - sc->sc_state |= NCR_ABORTING; - NCR_TRACE("machine: dma_stop, dh=0x%x\n", - (long) sr->sr_dma_hand); - (*sc->sc_dma_stop)(sc); - SCI_CLR_INTR(sc); /* XXX */ - /* - * While DMA is running we can not touch the SBC, - * so various places just set NCR_ABORTING and - * expect us the "kick it" when DMA is done. - */ - if (sc->sc_state & NCR_ABORTING) { - ncr_sched_msgout(sc, SEND_ABORT); - } - } - - /* - * Check for parity error. - * XXX - better place to check? - */ - if (*(sc->sci_csr) & SCI_CSR_PERR) { - printf("%s: parity error!\n", - sc->sc_dev.dv_xname); - /* XXX: sc->sc_state |= NCR_ABORTING; */ - ncr_sched_msgout(sc, SEND_PARITY_ERROR); - } - - if (act_flags == ACT_CONTINUE) - goto next_phase; - /* All other actions "break" from the loop. */ - - NCR_TRACE("machine: act_flags=0x%x\n", act_flags); - - if (act_flags & ACT_RESET_BUS) { - act_flags |= ACT_CMD_DONE; - /* - * Reset the SCSI bus, usually due to a timeout. - * The error code XS_TIMEOUT allows retries. - */ - sc->sc_state |= NCR_ABORTING; - printf("%s: reset SCSI bus for TID=%d LUN=%d\n", - sc->sc_dev.dv_xname, - sr->sr_target, sr->sr_lun); - ncr5380_reset_scsibus(sc); - } - - if (act_flags & ACT_CMD_DONE) { - act_flags |= ACT_DISCONNECT; - /* Need to call scsi_done() */ - /* XXX: from the aic6360 driver, but why? */ - if (sc->sc_datalen < 0) { - printf("%s: %d extra bytes from %d:%d\n", - sc->sc_dev.dv_xname, -sc->sc_datalen, - sr->sr_target, sr->sr_lun); - sc->sc_datalen = 0; - } - xs->resid = sc->sc_datalen; - /* Note: this will clear sc_current */ - NCR_TRACE("machine: call done, cur=0x%x\n", (long)sr); - ncr5380_done(sc); - } - - if (act_flags & ACT_DISCONNECT) { - /* - * The device has dropped BSY (or will soon). - * Return and let ncr5380_sched() do its thing. - */ - *sc->sci_icmd = 0; - *sc->sci_mode = 0; - *sc->sci_tcmd = PHASE_INVALID; - *sc->sci_sel_enb = 0; - SCI_CLR_INTR(sc); - *sc->sci_sel_enb = 0x80; - - if ((act_flags & ACT_CMD_DONE) == 0) { - __asm("_ncr5380_disconnected:"); - NCR_TRACE("machine: discon, cur=0x%x\n", (long)sr); - } - - /* - * We may be here due to a disconnect message, - * in which case we did NOT call ncr5380_done, - * and we need to clear sc_current. - */ - sc->sc_state = NCR_IDLE; - sc->sc_current = NULL; - - /* Paranoia: clear everything. */ - sc->sc_dataptr = NULL; - sc->sc_datalen = 0; - sc->sc_prevphase = PHASE_INVALID; - sc->sc_msgpriq = 0; - sc->sc_msgoutq = 0; - sc->sc_msgout = 0; - - /* Our caller will re-enable interrupts. */ - } -} - - -#ifdef DEBUG - -static void -ncr5380_show_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - u_char *b = (u_char *) xs->cmd; - int i = 0; - - if ( ! ( xs->flags & SCSI_RESET ) ) { - printf("si(%d:%d:%d)-", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); - while (i < xs->cmdlen) { - if (i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } else { - printf("si(%d:%d:%d)-RESET-\n", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); - } -} - - -static void -ncr5380_show_sense(xs) - struct scsi_xfer *xs; -{ - u_char *b = (u_char *)&xs->sense; - int i; - - printf("sense:"); - for (i = 0; i < sizeof(xs->sense); i++) - printf(" %02x", b[i]); - printf("\n"); -} - -int ncr5380_traceidx = 0; - -#define TRACE_MAX 1024 -struct trace_ent { - char *msg; - long val; -} ncr5380_tracebuf[TRACE_MAX]; - -void -ncr5380_trace(msg, val) - char *msg; - long val; -{ - register struct trace_ent *tr; - register int s; - - s = splhigh(); - - tr = &ncr5380_tracebuf[ncr5380_traceidx]; - - ncr5380_traceidx++; - if (ncr5380_traceidx >= TRACE_MAX) - ncr5380_traceidx = 0; - - tr->msg = msg; - tr->val = val; - - splx(s); -} - -#ifdef DDB -void -ncr5380_clear_trace() -{ - ncr5380_traceidx = 0; - bzero((char*) ncr5380_tracebuf, sizeof(ncr5380_tracebuf)); -} - -void -ncr5380_show_trace() -{ - struct trace_ent *tr; - int idx; - - idx = ncr5380_traceidx; - do { - tr = &ncr5380_tracebuf[idx]; - idx++; - if (idx >= TRACE_MAX) - idx = 0; - if (tr->msg) - db_printf(tr->msg, tr->val); - } while (idx != ncr5380_traceidx); -} - -void -ncr5380_show_req(sr) - struct sci_req *sr; -{ - struct scsi_xfer *xs = sr->sr_xs; - - db_printf("TID=%d ", sr->sr_target); - db_printf("LUN=%d ", sr->sr_lun); - db_printf("dh=0x%x ", sr->sr_dma_hand); - db_printf("dptr=0x%x ", sr->sr_dataptr); - db_printf("dlen=0x%x ", sr->sr_datalen); - db_printf("flags=%d ", sr->sr_flags); - db_printf("stat=%d ", sr->sr_status); - - if (xs == NULL) { - db_printf("(xs=NULL)\n"); - return; - } - db_printf("\n"); -#ifdef SCSIDEBUG - show_scsi_xs(xs); -#else - db_printf("xs=0x%x\n", xs); -#endif -} - -void -ncr5380_show_state() -{ - struct ncr5380_softc *sc; - struct sci_req *sr; - int i, j, k; - - sc = ncr5380_debug_sc; - - if (sc == NULL) { - db_printf("ncr5380_debug_sc == NULL\n"); - return; - } - - db_printf("sc_ncmds=%d\n", sc->sc_ncmds); - k = -1; /* which is current? */ - for (i = 0; i < SCI_OPENINGS; i++) { - sr = &sc->sc_ring[i]; - if (sr->sr_xs) { - if (sr == sc->sc_current) - k = i; - db_printf("req %d: (sr=0x%x)", i, (long)sr); - ncr5380_show_req(sr); - } - } - db_printf("sc_rr=%d, current=%d\n", sc->sc_rr, k); - - db_printf("Active request matrix:\n"); - for(i = 0; i < 8; i++) { /* targets */ - for (j = 0; j < 8; j++) { /* LUN */ - sr = sc->sc_matrix[i][j]; - if (sr) { - db_printf("TID=%d LUN=%d sr=0x%x\n", i, j, (long)sr); - } - } - } - - db_printf("sc_state=0x%x\n", sc->sc_state); - db_printf("sc_current=0x%x\n", sc->sc_current); - db_printf("sc_dataptr=0x%x\n", sc->sc_dataptr); - db_printf("sc_datalen=0x%x\n", sc->sc_datalen); - - db_printf("sc_prevphase=%d\n", sc->sc_prevphase); - db_printf("sc_msgpriq=0x%x\n", sc->sc_msgpriq); -} - -#endif /* DDB */ -#endif /* DEBUG */ diff --git a/sys/arch/sun3/dev/ncr5380var.h b/sys/arch/sun3/dev/ncr5380var.h index a481210c1a6..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr5380var.h +++ b/sys/arch/sun3/dev/ncr5380var.h @@ -1,178 +0,0 @@ -/* $NetBSD: ncr5380var.h,v 1.2 1995/11/17 23:27:49 gwr Exp $ */ - -/* - * Copyright (c) 1995 David Jones, Gordon W. Ross - * Copyright (c) 1994 Jarle Greipsland - * 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. The name of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by - * David Jones and Gordon Ross - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. - */ - -/* - * This file defines the interface between the machine-dependent - * module and the machine-indepenedent ncr5380sbc.c module. - */ - -#define SCI_CLR_INTR(sc) (*(sc)->sci_iack) -#define SCI_BUSY(sc) (*sc->sci_bus_csr & SCI_BUS_BSY) - -/* These are NOT artibtrary, but map to bits in sci_tcmd */ -#define PHASE_DATA_OUT 0x0 -#define PHASE_DATA_IN 0x1 -#define PHASE_COMMAND 0x2 -#define PHASE_STATUS 0x3 -#define PHASE_UNSPEC1 0x4 -#define PHASE_UNSPEC2 0x5 -#define PHASE_MSG_OUT 0x6 -#define PHASE_MSG_IN 0x7 - -/* - * This illegal phase is used to prevent the 5380 from having - * a phase-match condition when we don't want one, such as - * when setting up the DMA engine or whatever... - */ -#define PHASE_INVALID PHASE_UNSPEC1 - - -/* Per-request state. This is required in order to support reselection. */ -struct sci_req { - struct scsi_xfer *sr_xs; /* Pointer to xfer struct, NULL=unused */ - int sr_target, sr_lun; /* For fast access */ - void *sr_dma_hand; /* Current DMA hnadle */ - u_char *sr_dataptr; /* Saved data pointer */ - int sr_datalen; - int sr_flags; /* Internal error code */ -#define SR_IMMED 1 /* Immediate command */ -#define SR_SENSE 2 /* We are getting sense */ -#define SR_OVERDUE 4 /* Timeout while not current */ -#define SR_ERROR 8 /* Error occurred */ - int sr_status; /* Status code from last cmd */ -}; -#define SCI_OPENINGS 16 /* How many commands we can enqueue. */ - - -struct ncr5380_softc { - struct device sc_dev; - struct scsi_link sc_link; - - /* Pointers to 5380 registers. See ncr5380reg.h */ - volatile u_char *sci_r0; - volatile u_char *sci_r1; - volatile u_char *sci_r2; - volatile u_char *sci_r3; - volatile u_char *sci_r4; - volatile u_char *sci_r5; - volatile u_char *sci_r6; - volatile u_char *sci_r7; - - /* Functions set from MD code */ - int (*sc_pio_out) __P((struct ncr5380_softc *, - int, int, u_char *)); - int (*sc_pio_in) __P((struct ncr5380_softc *, - int, int, u_char *)); - void (*sc_dma_alloc) __P((struct ncr5380_softc *)); - void (*sc_dma_free) __P((struct ncr5380_softc *)); - - void (*sc_dma_setup) __P((struct ncr5380_softc *)); - void (*sc_dma_start) __P((struct ncr5380_softc *)); - void (*sc_dma_poll) __P((struct ncr5380_softc *)); - void (*sc_dma_eop) __P((struct ncr5380_softc *)); - void (*sc_dma_stop) __P((struct ncr5380_softc *)); - - void (*sc_intr_on) __P((struct ncr5380_softc *)); - void (*sc_intr_off) __P((struct ncr5380_softc *)); - - int sc_flags; /* Misc. flags and capabilities */ -#define NCR5380_PERMIT_RESELECT 1 /* Allow disconnect/reselect */ -#define NCR5380_FORCE_POLLING 2 /* Do not use interrupts. */ - - int sc_min_dma_len; /* Smaller than this is done with PIO */ - - /* Begin MI shared data */ - - int sc_state; -#define NCR_IDLE 0 /* Ready for new work. */ -#define NCR_WORKING 0x01 /* Some command is in progress. */ -#define NCR_ABORTING 0x02 /* Bailing out */ -#define NCR_DOINGDMA 0x04 /* The FIFO data path is active! */ -#define NCR_DROP_MSGIN 0x10 /* Discard all msgs (parity err detected) */ - - /* The request that has the bus now. */ - struct sci_req *sc_current; - - /* Active data pointer for current SCSI command. */ - u_char *sc_dataptr; - int sc_datalen; - - /* Begin MI private data */ - - /* The number of operations in progress on the bus */ - volatile int sc_ncmds; - - /* Ring buffer of pending/active requests */ - struct sci_req sc_ring[SCI_OPENINGS]; - int sc_rr; /* Round-robin scan pointer */ - - /* Active requests, by target/LUN */ - struct sci_req *sc_matrix[8][8]; - - /* Message stuff */ - int sc_prevphase; - - u_int sc_msgpriq; /* Messages we want to send */ - u_int sc_msgoutq; /* Messages sent during last MESSAGE OUT */ - u_int sc_msgout; /* Message last transmitted */ -#define SEND_DEV_RESET 0x01 -#define SEND_PARITY_ERROR 0x02 -#define SEND_ABORT 0x04 -#define SEND_REJECT 0x08 -#define SEND_INIT_DET_ERR 0x10 -#define SEND_IDENTIFY 0x20 -#define SEND_SDTR 0x40 -#define SEND_WDTR 0x80 -#define NCR_MAX_MSG_LEN 8 - u_char sc_omess[NCR_MAX_MSG_LEN]; - u_char *sc_omp; /* Outgoing message pointer */ - u_char sc_imess[NCR_MAX_MSG_LEN]; - u_char *sc_imp; /* Incoming message pointer */ - -}; - -void ncr5380_init __P((struct ncr5380_softc *)); -void ncr5380_reset_scsibus __P((struct ncr5380_softc *)); -int ncr5380_intr __P((struct ncr5380_softc *)); -int ncr5380_scsi_cmd __P((struct scsi_xfer *)); -int ncr5380_pio_in __P((struct ncr5380_softc *, int, int, u_char *)); -int ncr5380_pio_out __P((struct ncr5380_softc *, int, int, u_char *)); - -#ifdef DEBUG -struct ncr5380_softc *ncr5380_debug_sc; -void ncr5380_trace __P((char *msg, long val)); -#define NCR_TRACE(msg, val) ncr5380_trace(msg, val) -#else -#define NCR_TRACE(msg, val) /* nada */ -#endif diff --git a/sys/arch/sun3/dev/ncr_si.c b/sys/arch/sun3/dev/ncr_si.c index 658e886d819..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr_si.c +++ b/sys/arch/sun3/dev/ncr_si.c @@ -1,1286 +0,0 @@ -/* $NetBSD: ncr_si.c,v 1.3 1996/01/01 22:51:26 thorpej Exp $ */ - -/* - * Copyright (c) 1995 David Jones, Gordon W. Ross - * Copyright (c) 1994 Adam Glass - * 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. The name of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by - * Adam Glass, David Jones, and Gordon Ross - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. - */ - -/* - * This file contains only the machine-dependent parts of the - * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) - * The machine-independent parts are in ncr5380sbc.c - * - * Supported hardware includes: - * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) - * Sun SCSI-3 on VME (Sun3/160,Sun3/260) - * - * Could be made to support the Sun3/E if someone wanted to. - * - * Note: Both supported variants of the Sun SCSI-3 adapter have - * some really unusual "features" for this driver to deal with, - * generally related to the DMA engine. The OBIO variant will - * ignore any attempt to write the FIFO count register while the - * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with - * by setting the FIFO count early in COMMAND or MSG_IN phase. - * - * The VME variant has a bit to enable or disable the DMA engine, - * but that bit also gates the interrupt line from the NCR5380! - * Therefore, in order to get any interrupt from the 5380, (i.e. - * for reselect) one must clear the DMA engine transfer count and - * then enable DMA. This has the further complication that you - * CAN NOT touch the NCR5380 while the DMA enable bit is set, so - * we have to turn DMA back off before we even look at the 5380. - * - * What wonderfully whacky hardware this is! - * - * Credits, history: - * - * David Jones wrote the initial version of this module, which - * included support for the VME adapter only. (no reselection). - * - * Gordon Ross added support for the OBIO adapter, and re-worked - * both the VME and OBIO code to support disconnect/reselect. - * (Required figuring out the hardware "features" noted above.) - * - * The autoconfiguration boilerplate came from Adam Glass. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/errno.h> -#include <sys/device.h> -#include <sys/buf.h> -#include <sys/proc.h> -#include <sys/user.h> - -#include <scsi/scsi_all.h> -#include <scsi/scsi_debug.h> -#include <scsi/scsiconf.h> - -#include <machine/autoconf.h> -#include <machine/isr.h> -#include <machine/obio.h> -#include <machine/dvma.h> - -#define DEBUG XXX - -#include <dev/ic/ncr5380reg.h> -#include <dev/ic/ncr5380var.h> - -#include "ncr_sireg.h" -#include "am9516.h" - -/* - * Transfers smaller than this are done using PIO - * (on assumption they're not worth DMA overhead) - */ -#define MIN_DMA_LEN 128 - -/* - * Transfers lager than 65535 bytes need to be split-up. - * (Some of the FIFO logic has only 16 bits counters.) - * Make the size an integer multiple of the page size - * to avoid buf/cluster remap problems. (paranoid?) - */ -#define MAX_DMA_LEN 0xE000 - -/* - * How many uS. to delay after touching the am9516 UDC. - */ -#define UDC_WAIT_USEC 5 - -#ifdef DEBUG -int si_debug = 0; -static int si_link_flags = 0 /* | SDEV_DB2 */ ; -#endif - -/* - * This structure is used to keep track of mapped DMA requests. - * Note: combined the UDC command block with this structure, so - * the array of these has to be in DVMA space. - */ -struct si_dma_handle { - int dh_flags; -#define SIDH_BUSY 1 /* This DH is in use */ -#define SIDH_OUT 2 /* DMA does data out (write) */ - u_char * dh_addr; /* KVA of start of buffer */ - int dh_maplen; /* Length of KVA mapping. */ - long dh_dvma; /* VA of buffer in DVMA space */ - /* DMA command block for the OBIO controller. */ - struct udc_table dh_cmd; -}; - -/* - * The first structure member has to be the ncr5380_softc - * so we can just cast to go back and fourth between them. - */ -struct si_softc { - struct ncr5380_softc ncr_sc; - volatile struct si_regs *sc_regs; - int sc_adapter_type; - int sc_adapter_iv_am; /* int. vec + address modifier */ - struct si_dma_handle *sc_dma; - int sc_xlen; /* length of current DMA segment. */ -}; - -/* Options. Interesting values are: 1,3,7 */ -int si_options = 0; -#define SI_ENABLE_DMA 1 /* Use DMA (maybe polled) */ -#define SI_DMA_INTR 2 /* DMA completion interrupts */ -#define SI_DO_RESELECT 4 /* Allow disconnect/reselect */ - -/* How long to wait for DMA before declaring an error. */ -int si_dma_intr_timo = 500; /* ticks (sec. X 100) */ - -static char si_name[] = "si"; -static int si_match(); -static void si_attach(); -static int si_intr(void *arg); -static void si_reset_adapter(struct ncr5380_softc *sc); -static void si_minphys(struct buf *bp); - -void si_dma_alloc __P((struct ncr5380_softc *)); -void si_dma_free __P((struct ncr5380_softc *)); -void si_dma_poll __P((struct ncr5380_softc *)); - -void si_vme_dma_setup __P((struct ncr5380_softc *)); -void si_vme_dma_start __P((struct ncr5380_softc *)); -void si_vme_dma_eop __P((struct ncr5380_softc *)); -void si_vme_dma_stop __P((struct ncr5380_softc *)); - -void si_vme_intr_on __P((struct ncr5380_softc *)); -void si_vme_intr_off __P((struct ncr5380_softc *)); - -void si_obio_dma_setup __P((struct ncr5380_softc *)); -void si_obio_dma_start __P((struct ncr5380_softc *)); -void si_obio_dma_eop __P((struct ncr5380_softc *)); -void si_obio_dma_stop __P((struct ncr5380_softc *)); - - -static struct scsi_adapter si_ops = { - ncr5380_scsi_cmd, /* scsi_cmd() */ - si_minphys, /* scsi_minphys() */ - NULL, /* open_target_lu() */ - NULL, /* close_target_lu() */ -}; - -/* This is copied from julian's bt driver */ -/* "so we have a default dev struct for our link struct." */ -static struct scsi_device si_dev = { - NULL, /* Use default error handler. */ - NULL, /* Use default start handler. */ - NULL, /* Use default async handler. */ - NULL, /* Use default "done" routine. */ -}; - - -struct cfdriver ncr_sicd = { - NULL, si_name, si_match, si_attach, - DV_DULL, sizeof(struct si_softc), NULL, 0, -}; - -static int -si_print(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} - -static int -si_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; -{ - struct cfdata *cf = vcf; - struct confargs *ca = args; - int x, probe_addr; - - /* Default interrupt priority always splbio==2 */ - if (ca->ca_intpri == -1) - ca->ca_intpri = 2; - - if ((cpu_machine_id == SUN3_MACH_50) || - (cpu_machine_id == SUN3_MACH_60) ) - { - /* Sun3/50 or Sun3/60 have only OBIO "si" */ - if (ca->ca_bustype != BUS_OBIO) - return(0); - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_NCR_SCSI; - /* OK... */ - } else { - /* Other Sun3 models may have VME "si" or "sc" */ - if (ca->ca_bustype != BUS_VME16) - return (0); - if (ca->ca_paddr == -1) - return (0); - /* OK... */ - } - - /* Make sure there is something there... */ - x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1); - if (x == -1) - return (0); - - /* - * If this is a VME SCSI board, we have to determine whether - * it is an "sc" (Sun2) or "si" (Sun3) SCSI board. This can - * be determined using the fact that the "sc" board occupies - * 4K bytes in VME space but the "si" board occupies 2K bytes. - */ - if (ca->ca_bustype == BUS_VME16) { - /* Note, the "si" board should NOT respond here. */ - x = bus_peek(ca->ca_bustype, ca->ca_paddr + 0x801, 1); - if (x != -1) - return(0); - } - - return (1); -} - -static void -si_attach(parent, self, args) - struct device *parent, *self; - void *args; -{ - struct si_softc *sc = (struct si_softc *) self; - struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *)sc; - volatile struct si_regs *regs; - struct confargs *ca = args; - int i; - - switch (ca->ca_bustype) { - - case BUS_OBIO: - regs = (struct si_regs *) - obio_alloc(ca->ca_paddr, sizeof(*regs)); - break; - - case BUS_VME16: - regs = (struct si_regs *) - bus_mapin(ca->ca_bustype, ca->ca_paddr, sizeof(*regs)); - break; - - default: - printf("unknown\n"); - return; - } - printf("\n"); - - /* - * Fill in the prototype scsi_link. - */ - ncr_sc->sc_link.adapter_softc = sc; - ncr_sc->sc_link.adapter_target = 7; - ncr_sc->sc_link.adapter = &si_ops; - ncr_sc->sc_link.device = &si_dev; - - /* - * Initialize fields used by the MI code - */ - ncr_sc->sci_r0 = ®s->sci.sci_r0; - ncr_sc->sci_r1 = ®s->sci.sci_r1; - ncr_sc->sci_r2 = ®s->sci.sci_r2; - ncr_sc->sci_r3 = ®s->sci.sci_r3; - ncr_sc->sci_r4 = ®s->sci.sci_r4; - ncr_sc->sci_r5 = ®s->sci.sci_r5; - ncr_sc->sci_r6 = ®s->sci.sci_r6; - ncr_sc->sci_r7 = ®s->sci.sci_r7; - - /* - * MD function pointers used by the MI code. - */ - ncr_sc->sc_pio_out = ncr5380_pio_out; - ncr_sc->sc_pio_in = ncr5380_pio_in; - ncr_sc->sc_dma_alloc = si_dma_alloc; - ncr_sc->sc_dma_free = si_dma_free; - ncr_sc->sc_dma_poll = si_dma_poll; - ncr_sc->sc_intr_on = NULL; - ncr_sc->sc_intr_off = NULL; - if (ca->ca_bustype == BUS_VME16) { - ncr_sc->sc_dma_setup = si_vme_dma_setup; - ncr_sc->sc_dma_start = si_vme_dma_start; - ncr_sc->sc_dma_eop = si_vme_dma_stop; - ncr_sc->sc_dma_stop = si_vme_dma_stop; - if (si_options & SI_DO_RESELECT) { - /* - * Need to enable interrupts (and DMA!) - * on this H/W for reselect to work. - */ - ncr_sc->sc_intr_on = si_vme_intr_on; - ncr_sc->sc_intr_off = si_vme_intr_off; - } - } else { - ncr_sc->sc_dma_setup = si_obio_dma_setup; - ncr_sc->sc_dma_start = si_obio_dma_start; - ncr_sc->sc_dma_eop = si_obio_dma_stop; - ncr_sc->sc_dma_stop = si_obio_dma_stop; - } - ncr_sc->sc_flags = 0; - if (si_options & SI_DO_RESELECT) - ncr_sc->sc_flags |= NCR5380_PERMIT_RESELECT; - if ((si_options & SI_DMA_INTR) == 0) - ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; - ncr_sc->sc_min_dma_len = MIN_DMA_LEN; - - /* - * Initialize fields used only here in the MD code. - */ - - /* Need DVMA-capable memory for the UDC command blocks. */ - i = SCI_OPENINGS * sizeof(struct si_dma_handle); - sc->sc_dma = (struct si_dma_handle *) dvma_malloc(i); - if (sc->sc_dma == NULL) - panic("si: dvma_malloc failed\n"); - for (i = 0; i < SCI_OPENINGS; i++) - sc->sc_dma[i].dh_flags = 0; - - sc->sc_regs = regs; - sc->sc_adapter_type = ca->ca_bustype; - - /* Now ready for interrupts. */ - if (ca->ca_bustype == BUS_OBIO) { - isr_add_autovect(si_intr, (void *)sc, - ca->ca_intpri); - } else { - isr_add_vectored(si_intr, (void *)sc, - ca->ca_intpri, ca->ca_intvec); - sc->sc_adapter_iv_am = - VME_SUPV_DATA_24 | (ca->ca_intvec & 0xFF); - } - -#ifdef DEBUG - if (si_debug) - printf("si: Set TheSoftC=%x TheRegs=%x\n", sc, regs); - ncr_sc->sc_link.flags |= si_link_flags; -#endif - - /* - * Initialize si board itself. - */ - si_reset_adapter(ncr_sc); - ncr5380_init(ncr_sc); - ncr5380_reset_scsibus(ncr_sc); - config_found(self, &(ncr_sc->sc_link), si_print); -} - -static void -si_minphys(struct buf *bp) -{ - if (bp->b_bcount > MAX_DMA_LEN) { -#ifdef DEBUG - if (si_debug) { - printf("si_minphys len = 0x%x.\n", bp->b_bcount); - Debugger(); - } -#endif - bp->b_bcount = MAX_DMA_LEN; - } - return (minphys(bp)); -} - - -#define CSR_WANT (SI_CSR_SBC_IP | SI_CSR_DMA_IP | \ - SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR ) - -static int -si_intr(void *arg) -{ - struct si_softc *sc = arg; - volatile struct si_regs *si = sc->sc_regs; - int dma_error, claimed; - u_short csr; - - claimed = 0; - dma_error = 0; - - /* SBC interrupt? DMA interrupt? */ - csr = si->si_csr; - NCR_TRACE("si_intr: csr=0x%x\n", csr); - - if (csr & SI_CSR_DMA_CONFLICT) { - dma_error |= SI_CSR_DMA_CONFLICT; - printf("si_intr: DMA conflict\n"); - } - if (csr & SI_CSR_DMA_BUS_ERR) { - dma_error |= SI_CSR_DMA_BUS_ERR; - printf("si_intr: DMA bus error\n"); - } - if (dma_error) { - if (sc->ncr_sc.sc_state & NCR_DOINGDMA) - sc->ncr_sc.sc_state |= NCR_ABORTING; - /* Make sure we will call the main isr. */ - csr |= SI_CSR_DMA_IP; - } - - if (csr & (SI_CSR_SBC_IP | SI_CSR_DMA_IP)) { - claimed = ncr5380_intr(&sc->ncr_sc); -#ifdef DEBUG - if (!claimed) { - printf("si_intr: spurious from SBC\n"); - if (si_debug & 4) { - Debugger(); /* XXX */ - } - } -#endif - } - - return (claimed); -} - - -static void -si_reset_adapter(struct ncr5380_softc *ncr_sc) -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - -#ifdef DEBUG - if (si_debug) { - printf("si_reset_adapter\n"); - } -#endif - - /* - * The SCSI3 controller has an 8K FIFO to buffer data between the - * 5380 and the DMA. Make sure it starts out empty. - * - * The reset bits in the CSR are active low. - */ - si->si_csr = 0; - delay(10); - si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES | SI_CSR_INTR_EN; - delay(10); - si->fifo_count = 0; - - if (sc->sc_adapter_type == BUS_VME16) { - si->dma_addrh = 0; - si->dma_addrl = 0; - si->dma_counth = 0; - si->dma_countl = 0; - si->si_iv_am = sc->sc_adapter_iv_am; - si->fifo_cnt_hi = 0; - } - - SCI_CLR_INTR(ncr_sc); -} - - -/***************************************************************** - * Common functions for DMA - ****************************************************************/ - -/* - * Allocate a DMA handle and put it in sc->sc_dma. Prepare - * for DMA transfer. On the Sun3, this means mapping the buffer - * into DVMA space. dvma_mapin() flushes the cache for us. - */ -void -si_dma_alloc(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - struct si_dma_handle *dh; - int i, xlen; - u_long addr; - -#ifdef DIAGNOSTIC - if (sr->sr_dma_hand != NULL) - panic("si_dma_alloc: already have DMA handle"); -#endif - -#if 1 /* XXX - Temporary */ - /* XXX - In case we think DMA is completely broken... */ - if ((si_options & SI_ENABLE_DMA) == 0) - return; -#endif - - addr = (u_long) ncr_sc->sc_dataptr; - xlen = ncr_sc->sc_datalen; - - /* If the DMA start addr is misaligned then do PIO */ - if ((addr & 1) || (xlen & 1)) { - printf("si_dma_alloc: misaligned.\n"); - return; - } - - /* Make sure our caller checked sc_min_dma_len. */ - if (xlen < MIN_DMA_LEN) - panic("si_dma_alloc: xlen=0x%x\n", xlen); - - /* - * Never attempt single transfers of more than 63k, because - * our count register may be only 16 bits (an OBIO adapter). - * This should never happen since already bounded by minphys(). - * XXX - Should just segment these... - */ - if (xlen > MAX_DMA_LEN) { - printf("si_dma_alloc: excessive xlen=0x%x\n", xlen); - Debugger(); - ncr_sc->sc_datalen = xlen = MAX_DMA_LEN; - } - - /* Find free DMA handle. Guaranteed to find one since we have - as many DMA handles as the driver has processes. */ - for (i = 0; i < SCI_OPENINGS; i++) { - if ((sc->sc_dma[i].dh_flags & SIDH_BUSY) == 0) - goto found; - } - panic("si: no free DMA handles."); -found: - - dh = &sc->sc_dma[i]; - dh->dh_flags = SIDH_BUSY; - dh->dh_addr = (u_char*) addr; - dh->dh_maplen = xlen; - dh->dh_dvma = 0; - - /* Copy the "write" flag for convenience. */ - if (xs->flags & SCSI_DATA_OUT) - dh->dh_flags |= SIDH_OUT; - -#if 0 - /* - * Some machines might not need to remap B_PHYS buffers. - * The sun3 does not map B_PHYS buffers into DVMA space, - * (they are mapped into normal KV space) so on the sun3 - * we must always remap to a DVMA address here. Re-map is - * cheap anyway, because it's done by segments, not pages. - */ - if (xs->bp && (xs->bp->b_flags & B_PHYS)) - dh->dh_flags |= SIDH_PHYS; -#endif - - dh->dh_dvma = (u_long) dvma_mapin((char *)addr, xlen); - if (!dh->dh_dvma) { - /* Can't remap segment */ - printf("si_dma_alloc: can't remap %x/%x\n", - dh->dh_addr, dh->dh_maplen); - dh->dh_flags = 0; - return; - } - - /* success */ - sr->sr_dma_hand = dh; - - return; -} - - -void -si_dma_free(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - -#ifdef DIAGNOSTIC - if (dh == NULL) - panic("si_dma_free: no DMA handle"); -#endif - - if (ncr_sc->sc_state & NCR_DOINGDMA) - panic("si_dma_free: free while in progress"); - - if (dh->dh_flags & SIDH_BUSY) { - /* XXX - Should separate allocation and mapping. */ - /* Give back the DVMA space. */ - dvma_mapout((caddr_t)dh->dh_dvma, dh->dh_maplen); - dh->dh_dvma = 0; - dh->dh_flags = 0; - } - sr->sr_dma_hand = NULL; -} - - -/* - * Poll (spin-wait) for DMA completion. - * Called right after xx_dma_start(), and - * xx_dma_stop() will be called next. - * Same for either VME or OBIO. - */ -void -si_dma_poll(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - int tmo, csr_mask; - - /* Make sure DMA started successfully. */ - if (ncr_sc->sc_state & NCR_ABORTING) - return; - - csr_mask = SI_CSR_SBC_IP | SI_CSR_DMA_IP | - SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR; - - tmo = 50000; /* X100 = 5 sec. */ - for (;;) { - if (si->si_csr & csr_mask) - break; - if (--tmo <= 0) { - printf("si: DMA timeout (while polling)\n"); - /* Indicate timeout as MI code would. */ - sr->sr_flags |= SR_OVERDUE; - break; - } - delay(100); - } - -#ifdef DEBUG - if (si_debug) { - printf("si_dma_poll: done, csr=0x%x\n", si->si_csr); - } -#endif -} - - -/***************************************************************** - * VME functions for DMA - ****************************************************************/ - - -/* - * This is called when the bus is going idle, - * so we want to enable the SBC interrupts. - * That is controlled by the DMA enable! - * Who would have guessed! - * What a NASTY trick! - */ -void -si_vme_intr_on(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - - si_vme_dma_setup(ncr_sc); - si->si_csr |= SI_CSR_DMA_EN; -} - -/* - * This is called when the bus is idle and we are - * about to start playing with the SBC chip. - */ -void -si_vme_intr_off(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - - si->si_csr &= ~SI_CSR_DMA_EN; -} - -/* - * This function is called during the COMMAND or MSG_IN phase - * that preceeds a DATA_IN or DATA_OUT phase, in case we need - * to setup the DMA engine before the bus enters a DATA phase. - * - * XXX: The VME adapter appears to suppress SBC interrupts - * when the FIFO is not empty or the FIFO count is non-zero! - * - * On the VME version we just clear the DMA count and address - * here (to make sure it stays idle) and do the real setup - * later, in dma_start. - */ -void -si_vme_dma_setup(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - - /* Reset the FIFO */ - si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ - si->si_csr |= SI_CSR_FIFO_RES; - - /* Set direction (assume recv here) */ - si->si_csr &= ~SI_CSR_SEND; - /* Assume worst alignment */ - si->si_csr |= SI_CSR_BPCON; - - si->dma_addrh = 0; - si->dma_addrl = 0; - - si->dma_counth = 0; - si->dma_countl = 0; - - /* Clear FIFO counter. (also hits dma_count) */ - si->fifo_cnt_hi = 0; - si->fifo_count = 0; -} - - -void -si_vme_dma_start(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - long data_pa; - int xlen; - - /* - * Get the DVMA mapping for this segment. - * XXX - Should separate allocation and mapin. - */ - data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type); - data_pa += (ncr_sc->sc_dataptr - dh->dh_addr); - if (data_pa & 1) - panic("si_dma_start: bad pa=0x%x", data_pa); - xlen = ncr_sc->sc_datalen; - xlen &= ~1; - sc->sc_xlen = xlen; /* XXX: or less... */ - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", - dh, data_pa, xlen); - } -#endif - - /* - * Set up the DMA controller. - */ - si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ - si->si_csr |= SI_CSR_FIFO_RES; - - /* Set direction (send/recv) */ - if (dh->dh_flags & SIDH_OUT) { - si->si_csr |= SI_CSR_SEND; - } else { - si->si_csr &= ~SI_CSR_SEND; - } - - if (data_pa & 2) { - si->si_csr |= SI_CSR_BPCON; - } else { - si->si_csr &= ~SI_CSR_BPCON; - } - - si->dma_addrh = (ushort)(data_pa >> 16); - si->dma_addrl = (ushort)(data_pa & 0xFFFF); - - si->dma_counth = (ushort)(xlen >> 16); - si->dma_countl = (ushort)(xlen & 0xFFFF); - -#if 1 - /* Set it anyway, even though dma_count hits it? */ - si->fifo_cnt_hi = (ushort)(xlen >> 16); - si->fifo_count = (ushort)(xlen & 0xFFFF); -#endif - -#ifdef DEBUG - if (si->fifo_count != xlen) { - printf("si_dma_start: fifo_count=0x%x, xlen=0x%x\n", - si->fifo_count, xlen); - Debugger(); - } -#endif - - /* - * Acknowledge the phase change. (After DMA setup!) - * Put the SBIC into DMA mode, and start the transfer. - */ - if (dh->dh_flags & SIDH_OUT) { - *ncr_sc->sci_tcmd = PHASE_DATA_OUT; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = SCI_ICMD_DATA; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_dma_send = 0; /* start it */ - } else { - *ncr_sc->sci_tcmd = PHASE_DATA_IN; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = 0; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_irecv = 0; /* start it */ - } - - /* Let'er rip! */ - si->si_csr |= SI_CSR_DMA_EN; - - ncr_sc->sc_state |= NCR_DOINGDMA; - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: started, flags=0x%x\n", - ncr_sc->sc_state); - } -#endif -} - - -void -si_vme_dma_eop(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - - /* Not needed - DMA was stopped prior to examining sci_csr */ -} - - -void -si_vme_dma_stop(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - int resid, ntrans; - - if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { -#ifdef DEBUG - printf("si_dma_stop: dma not running\n"); -#endif - return; - } - ncr_sc->sc_state &= ~NCR_DOINGDMA; - - /* First, halt the DMA engine. */ - si->si_csr &= ~SI_CSR_DMA_EN; /* VME only */ - - if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { - printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); - sr->sr_xs->error = XS_DRIVER_STUFFUP; - ncr_sc->sc_state |= NCR_ABORTING; - si_reset_adapter(ncr_sc); - } - - /* Note that timeout may have set the error flag. */ - if (ncr_sc->sc_state & NCR_ABORTING) - goto out; - - /* - * Now try to figure out how much actually transferred - * - * The fifo_count does not reflect how many bytes were - * actually transferred for VME. - * - * SCSI-3 VME interface is a little funny on writes: - * if we have a disconnect, the dma has overshot by - * one byte and needs to be incremented. This is - * true if we have not transferred either all data - * or no data. XXX - from Matt Jacob - */ - - resid = si->fifo_count & 0xFFFF; - ntrans = sc->sc_xlen - resid; - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_stop: resid=0x%x ntrans=0x%x\n", - resid, ntrans); - } -#endif - - if (ntrans < MIN_DMA_LEN) { - printf("si: fifo count: 0x%x\n", resid); - ncr_sc->sc_state |= NCR_ABORTING; - goto out; - } - if (ntrans > ncr_sc->sc_datalen) - panic("si_dma_stop: excess transfer"); - - /* Adjust data pointer */ - ncr_sc->sc_dataptr += ntrans; - ncr_sc->sc_datalen -= ntrans; - - /* - * After a read, we may need to clean-up - * "Left-over bytes" (yuck!) - */ - if (((dh->dh_flags & SIDH_OUT) == 0) && - ((si->si_csr & SI_CSR_LOB) != 0)) - { - char *cp = ncr_sc->sc_dataptr; -#ifdef DEBUG - printf("si: Got Left-over bytes!\n"); -#endif - if (si->si_csr & SI_CSR_BPCON) { - /* have SI_CSR_BPCON */ - cp[-1] = (si->si_bprl & 0xff00) >> 8; - } else { - switch (si->si_csr & SI_CSR_LOB) { - case SI_CSR_LOB_THREE: - cp[-3] = (si->si_bprh & 0xff00) >> 8; - cp[-2] = (si->si_bprh & 0x00ff); - cp[-1] = (si->si_bprl & 0xff00) >> 8; - break; - case SI_CSR_LOB_TWO: - cp[-2] = (si->si_bprh & 0xff00) >> 8; - cp[-1] = (si->si_bprh & 0x00ff); - break; - case SI_CSR_LOB_ONE: - cp[-1] = (si->si_bprh & 0xff00) >> 8; - break; - } - } - } - -out: - si->dma_addrh = 0; - si->dma_addrl = 0; - - si->dma_counth = 0; - si->dma_countl = 0; - - si->fifo_cnt_hi = 0; - si->fifo_count = 0; - - /* Put SBIC back in PIO mode. */ - *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_icmd = 0; -} - - -/***************************************************************** - * OBIO functions for DMA - ****************************************************************/ - - -static __inline__ void -si_obio_udc_write(si, regnum, value) - volatile struct si_regs *si; - int regnum, value; -{ - delay(UDC_WAIT_USEC); - si->udc_addr = regnum; - delay(UDC_WAIT_USEC); - si->udc_data = value; -} - -static __inline__ int -si_obio_udc_read(si, regnum) - volatile struct si_regs *si; - int regnum; -{ - delay(UDC_WAIT_USEC); - si->udc_addr = regnum; - delay(UDC_WAIT_USEC); - return (si->udc_data); -} - - -/* - * This function is called during the COMMAND or MSG_IN phase - * that preceeds a DATA_IN or DATA_OUT phase, in case we need - * to setup the DMA engine before the bus enters a DATA phase. - * - * The OBIO "si" IGNORES any attempt to set the FIFO count - * register after the SCSI bus goes into any DATA phase, so - * this function has to setup the evil FIFO logic. - */ -void -si_obio_dma_setup(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - struct sci_req *sr; - struct si_dma_handle *dh; - int send = 0; - int xlen = 0; - - /* Let this work even without a dma hand, for testing... */ - if ((sr = ncr_sc->sc_current) != NULL) { - if ((dh = sr->sr_dma_hand) != NULL) { - send = dh->dh_flags & SIDH_OUT; - xlen = ncr_sc->sc_datalen; - xlen &= ~1; - } - } - -#ifdef DEBUG - if (si_debug) { - printf("si_dma_setup: send=%d xlen=%d\n", send, xlen); - } -#endif - - /* Reset the FIFO */ - si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ - si->si_csr |= SI_CSR_FIFO_RES; - - /* Set direction (send/recv) */ - if (send) { - si->si_csr |= SI_CSR_SEND; - } else { - si->si_csr &= ~SI_CSR_SEND; - } - - /* Set the FIFO counter. */ - si->fifo_count = xlen; - -#ifdef DEBUG - if ((si->fifo_count > xlen) || (si->fifo_count < (xlen - 1))) { - printf("si_dma_setup: fifo_count=0x%x, xlen=0x%x\n", - si->fifo_count, xlen); - Debugger(); - } -#endif -} - - -void -si_obio_dma_start(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - struct udc_table *cmd; - long data_pa, cmd_pa; - int xlen; - - /* - * Get the DVMA mapping for this segment. - * XXX - Should separate allocation and mapin. - */ - data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type); - data_pa += (ncr_sc->sc_dataptr - dh->dh_addr); - if (data_pa & 1) - panic("si_dma_start: bad pa=0x%x", data_pa); - xlen = ncr_sc->sc_datalen; - xlen &= ~1; - sc->sc_xlen = xlen; /* XXX: or less... */ - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", - dh, data_pa, xlen); - } -#endif - - /* - * Set up the DMA controller. - * Already set FIFO count in dma_setup. - */ - -#ifdef DEBUG - if ((si->fifo_count > xlen) || - (si->fifo_count < (xlen - 1))) - { - printf("si_dma_start: fifo_count=0x%x, xlen=0x%x\n", - si->fifo_count, xlen); - Debugger(); - } -#endif - - /* - * The OBIO controller needs a command block. - */ - cmd = &dh->dh_cmd; - cmd->addrh = ((data_pa & 0xFF0000) >> 8) | UDC_ADDR_INFO; - cmd->addrl = data_pa & 0xFFFF; - cmd->count = xlen / 2; /* bytes -> words */ - cmd->cmrh = UDC_CMR_HIGH; - if (dh->dh_flags & SIDH_OUT) { - cmd->cmrl = UDC_CMR_LSEND; - cmd->rsel = UDC_RSEL_SEND; - } else { - cmd->cmrl = UDC_CMR_LRECV; - cmd->rsel = UDC_RSEL_RECV; - } - - /* Tell the DMA chip where the control block is. */ - cmd_pa = dvma_kvtopa((long)cmd, BUS_OBIO); - si_obio_udc_write(si, UDC_ADR_CAR_HIGH, - (cmd_pa & 0xff0000) >> 8); - si_obio_udc_write(si, UDC_ADR_CAR_LOW, - (cmd_pa & 0xffff)); - - /* Tell the chip to be a DMA master. */ - si_obio_udc_write(si, UDC_ADR_MODE, UDC_MODE); - - /* Tell the chip to interrupt on error. */ - si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_CIE); - - /* Finally, give the UDC a "start chain" command. */ - si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_STRT_CHN); - - /* - * Acknowledge the phase change. (After DMA setup!) - * Put the SBIC into DMA mode, and start the transfer. - */ - if (dh->dh_flags & SIDH_OUT) { - *ncr_sc->sci_tcmd = PHASE_DATA_OUT; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = SCI_ICMD_DATA; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_dma_send = 0; /* start it */ - } else { - *ncr_sc->sci_tcmd = PHASE_DATA_IN; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = 0; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_irecv = 0; /* start it */ - } - - ncr_sc->sc_state |= NCR_DOINGDMA; - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: started, flags=0x%x\n", - ncr_sc->sc_state); - } -#endif -} - - -void -si_obio_dma_eop(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - - /* Not needed - DMA was stopped prior to examining sci_csr */ -} - - -void -si_obio_dma_stop(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - int resid, ntrans, tmo, udc_cnt; - - if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { -#ifdef DEBUG - printf("si_dma_stop: dma not running\n"); -#endif - return; - } - ncr_sc->sc_state &= ~NCR_DOINGDMA; - - if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { - printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); - sr->sr_xs->error = XS_DRIVER_STUFFUP; - ncr_sc->sc_state |= NCR_ABORTING; - si_reset_adapter(ncr_sc); - } - - /* Note that timeout may have set the error flag. */ - if (ncr_sc->sc_state & NCR_ABORTING) - goto out; - - /* - * After a read, wait for the FIFO to empty. - * Note: this only works on the OBIO version. - */ - if ((dh->dh_flags & SIDH_OUT) == 0) { - tmo = 200000; /* X10 = 2 sec. */ - for (;;) { - if (si->si_csr & SI_CSR_FIFO_EMPTY) - break; - if (--tmo <= 0) { - printf("si: dma fifo did not empty, reset\n"); - ncr_sc->sc_state |= NCR_ABORTING; - /* si_reset_adapter(ncr_sc); */ - goto out; - } - delay(10); - } - } - - /* - * Now try to figure out how much actually transferred - * - * The fifo_count might not reflect how many bytes were - * actually transferred for VME. - */ - - resid = si->fifo_count & 0xFFFF; - ntrans = sc->sc_xlen - resid; - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_stop: resid=0x%x ntrans=0x%x\n", - resid, ntrans); - } -#endif - - if (ntrans < MIN_DMA_LEN) { - printf("si: fifo count: 0x%x\n", resid); - ncr_sc->sc_state |= NCR_ABORTING; - goto out; - } - if (ntrans > ncr_sc->sc_datalen) - panic("si_dma_stop: excess transfer"); - - /* Adjust data pointer */ - ncr_sc->sc_dataptr += ntrans; - ncr_sc->sc_datalen -= ntrans; - - /* - * After a read, we may need to clean-up - * "Left-over bytes" (yuck!) - */ - if ((dh->dh_flags & SIDH_OUT) == 0) { - /* If odd transfer count, grab last byte by hand. */ - if (ntrans & 1) { - ncr_sc->sc_dataptr[-1] = - (si->fifo_data & 0xff00) >> 8; - goto out; - } - /* UDC might not have transfered the last word. */ - udc_cnt = si_obio_udc_read(si, UDC_ADR_COUNT); - if (((udc_cnt * 2) - resid) == 2) { - ncr_sc->sc_dataptr[-2] = - (si->fifo_data & 0xff00) >> 8; - ncr_sc->sc_dataptr[-1] = - (si->fifo_data & 0x00ff); - } - } - -out: - /* Reset the UDC. */ - si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); - si->fifo_count = 0; - - /* Put SBIC back in PIO mode. */ - *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_icmd = 0; -} - diff --git a/sys/arch/sun3/dev/ncr_sireg.h b/sys/arch/sun3/dev/ncr_sireg.h index 2d75eb6f824..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/ncr_sireg.h +++ b/sys/arch/sun3/dev/ncr_sireg.h @@ -1,103 +0,0 @@ -/* $NetBSD: ncr_sireg.h,v 1.2 1995/11/17 23:27:55 gwr Exp $ */ - -/* - * Register map for the Sun3 SCSI Interface (si) - * The first part of this register map is an NCR5380 - * SCSI Bus Interface Controller (SBIC). The rest is a - * DMA controller and custom logic in one of two flavors, - * one for the OBIO interface (3/50,3/60) and one for the - * VME interface (3/160,3/260,etc.), where some registers - * are implemented only on one or the other, some on both. - */ - -/* - * Some of these registers apply to only one interface and some - * apply to both. The registers which apply to the Sun3/50 onboard - * version only are udc_rdata and udc_raddr. The registers which - * apply to the Sun3 vme version only are dma_addr, dma_count, bpr, - * iv_am, and bcrh. Thus, the sbc registers, fifo_data, bcr, and csr - * apply to both interfaces. - * One other feature of the vme interface: a write to the dma count - * register also causes a write to the fifo byte count register and - * vis versa. - */ - -/* - * Am5380 Register map (no padding) - */ -struct ncr5380regs { - volatile u_char sci_r0; - volatile u_char sci_r1; - volatile u_char sci_r2; - volatile u_char sci_r3; - volatile u_char sci_r4; - volatile u_char sci_r5; - volatile u_char sci_r6; - volatile u_char sci_r7; -}; - -struct si_regs { - struct ncr5380regs sci; - - /* DMA controller registers */ - u_short dma_addrh; /* dma address (VME only) */ - u_short dma_addrl; /* (high word, low word) */ - u_short dma_counth; /* dma count (VME only) */ - u_short dma_countl; /* (high word, low word) */ - - /* AMD 9516 regs (OBIO only) see am9516.h */ - u_short udc_data; /* Am9516, reg data (OBIO only) */ - u_short udc_addr; /* Am9516, reg addr (OBIO only) */ - - /* These three registers are on both OBIO and VME versions. */ - u_short fifo_data; /* fifo data register */ - /* holds extra byte on odd */ - /* byte dma read */ - u_short fifo_count; /* fifo byte count */ - u_short si_csr; /* control/status register */ - - /* The rest of these are on the VME interface only: */ - u_short si_bprh; /* byte pack, high (VME only) */ - u_short si_bprl; /* byte pack, low (VME only) */ - u_short si_iv_am; /* bits 0-7: intr vector */ - /* bits 8-13: addr modifier (VME only) */ - /* bits 14-15: unused */ - u_short fifo_cnt_hi; /* high part of fifo_count (VME only) */ - - /* Whole thing repeats after 32 bytes. */ - u_short _space[3]; -}; - -/* possible values for the address modifier, sun3 vme version only */ -#define VME_SUPV_DATA_24 0x3d00 - -/* - * Status Register. - * Note: - * (r) indicates bit is read only. - * (rw) indicates bit is read or write. - * (v) vme host adaptor interface only. - * (o) sun3/50 onboard host adaptor interface only. - * (b) both vme and sun3/50 host adaptor interfaces. - */ -#define SI_CSR_DMA_ACTIVE 0x8000 /* (r,o) dma transfer active */ -#define SI_CSR_DMA_CONFLICT 0x4000 /* (r,b) reg accessed while dmaing */ -#define SI_CSR_DMA_BUS_ERR 0x2000 /* (r,b) bus error during dma */ -#define SI_CSR_ID 0x1000 /* (r,b) 0 for 3/50, 1 for SCSI-3, */ - /* 0 if SCSI-3 unmodified */ -#define SI_CSR_FIFO_FULL 0x0800 /* (r,b) fifo full */ -#define SI_CSR_FIFO_EMPTY 0x0400 /* (r,b) fifo empty */ -#define SI_CSR_SBC_IP 0x0200 /* (r,b) sbc interrupt pending */ -#define SI_CSR_DMA_IP 0x0100 /* (r,b) dma interrupt pending */ -#define SI_CSR_LOB 0x00c0 /* (r,v) number of leftover bytes */ -#define SI_CSR_LOB_THREE 0x00c0 /* (r,v) three leftover bytes */ -#define SI_CSR_LOB_TWO 0x0080 /* (r,v) two leftover bytes */ -#define SI_CSR_LOB_ONE 0x0040 /* (r,v) one leftover byte */ -#define SI_CSR_BPCON 0x0020 /* (rw,v) byte packing control */ - /* dma is in 0=longwords, 1=words */ -#define SI_CSR_DMA_EN 0x0010 /* (rw,v) dma/interrupt enable */ -#define SI_CSR_SEND 0x0008 /* (rw,b) dma dir, 1=to device */ -#define SI_CSR_INTR_EN 0x0004 /* (rw,b) interrupts enable */ -#define SI_CSR_FIFO_RES 0x0002 /* (rw,b) inits fifo, 0=reset */ -#define SI_CSR_SCSI_RES 0x0001 /* (rw,b) reset sbc and udc, 0=reset */ - diff --git a/sys/arch/sun3/dev/obctl.c b/sys/arch/sun3/dev/obctl.c index 91780040e91..9eb21c03559 100644 --- a/sys/arch/sun3/dev/obctl.c +++ b/sys/arch/sun3/dev/obctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: obctl.c,v 1.6 1994/12/12 18:59:21 gwr Exp $ */ +/* $NetBSD: obctl.c,v 1.8 1996/03/26 15:16:12 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -15,21 +15,25 @@ * 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 Adam Glass. - * 4. The name of the Author may not be used to endorse or promote products + * This product includes software developed by Adam Glass and Gordon Ross. + * 4. The name of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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 Adam Glass 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * On-board control space (OBCTL) + * Used by the idprom... */ #include <sys/param.h> @@ -39,12 +43,28 @@ #include <machine/autoconf.h> #include <machine/obctl.h> +static int obctl_match __P((struct device *, void *, void *)); static void obctl_attach __P((struct device *, struct device *, void *)); -static void obctl_scan __P((struct device *, void *)); -struct cfdriver obctlcd = { - NULL, "obctl", always_match, obctl_attach, DV_DULL, - sizeof(struct device), 0 }; +struct cfattach obctl_ca = { + sizeof(struct device), obctl_match, obctl_attach +}; + +struct cfdriver obctl_cd = { + NULL, "obctl", DV_DULL +}; + +static int +obctl_match(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + + if (ca->ca_bustype != BUS_OBCTL) + return (0); + return(1); +} static void obctl_attach(parent, self, args) @@ -53,13 +73,7 @@ obctl_attach(parent, self, args) void *args; { printf("\n"); - config_scan(obctl_scan, self); -} -static void -obctl_scan(parent, child) - struct device *parent; - void *child; -{ - bus_scan(parent, child, BUS_OBCTL); + /* We know ca_bustype == BUS_OBCTL */ + (void) config_search(bus_scan, self, args); } diff --git a/sys/arch/sun3/dev/obio.c b/sys/arch/sun3/dev/obio.c index b15a67dcfd4..8573ec2ef7a 100644 --- a/sys/arch/sun3/dev/obio.c +++ b/sys/arch/sun3/dev/obio.c @@ -1,4 +1,4 @@ -/* $NetBSD: obio.c,v 1.16 1995/02/13 22:23:57 gwr Exp $ */ +/* $NetBSD: obio.c,v 1.18 1996/03/26 15:16:14 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -41,31 +41,78 @@ #include <machine/isr.h> #include <machine/obio.h> +static int obio_match __P((struct device *, void *, void *)); static void obio_attach __P((struct device *, struct device *, void *)); -static void obio_scan __P((struct device *, void *)); +static int obio_print __P((void *, char *parentname)); -struct cfdriver obiocd = { - NULL, "obio", always_match, obio_attach, DV_DULL, - sizeof(struct device), 0 }; +struct cfattach obio_ca = { + sizeof(struct device), obio_match, obio_attach +}; + +struct cfdriver obio_cd = { + NULL, "obio", DV_DULL +}; + +static int +obio_match(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + + if (ca->ca_bustype != BUS_OBIO) + return (0); + return(1); +} + +#define OBIO_INCR 0x020000 +#define OBIO_END 0x200000 static void -obio_attach(parent, self, args) +obio_attach(parent, self, aux) struct device *parent; struct device *self; - void *args; + void *aux; { + struct confargs *ca = aux; + int addr; + printf("\n"); - config_scan(obio_scan, self); + + /* Configure these in order of address. */ + for (addr = 0; addr < OBIO_END; addr += OBIO_INCR) { + + /* We know ca_bustype == BUS_OBIO */ + ca->ca_paddr = addr; + ca->ca_intpri = -1; + ca->ca_intvec = -1; + + (void) config_found(self, ca, obio_print); + } } -static void -obio_scan(parent, child) - struct device *parent; - void *child; +/* + * Print out the confargs. The (parent) name is non-NULL + * when there was no match found by config_found(). + */ +static int +obio_print(args, name) + void *args; + char *name; { - bus_scan(parent, child, BUS_OBIO); + struct confargs *ca = args; + + /* Be quiet about empty OBIO locations. */ + if (name) + return(QUIET); + + printf(" addr 0x%x", ca->ca_paddr); + + return(UNCONF); } +/*****************************************************************/ + /* * Spacing of "interesting" OBIO mappings. We will * record only those with an OBIO address that is a diff --git a/sys/arch/sun3/dev/obmem.c b/sys/arch/sun3/dev/obmem.c index 6a9f557648a..37cce8348bc 100644 --- a/sys/arch/sun3/dev/obmem.c +++ b/sys/arch/sun3/dev/obmem.c @@ -1,4 +1,4 @@ -/* $NetBSD: obmem.c,v 1.6 1994/12/12 18:59:23 gwr Exp $ */ +/* $NetBSD: obmem.c,v 1.8 1996/03/26 15:16:17 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -15,21 +15,20 @@ * 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 Adam Glass. - * 4. The name of the Author may not be used to endorse or promote products + * This product includes software developed by Adam Glass and Gordon Ross. + * 4. The name of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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 Adam Glass 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. + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. */ /* @@ -44,12 +43,28 @@ #include <machine/autoconf.h> #include <machine/obmem.h> +static int obmem_match __P((struct device *, void *, void *)); static void obmem_attach __P((struct device *, struct device *, void *)); -static void obmem_scan __P((struct device *, void *)); -struct cfdriver obmemcd = { - NULL, "obmem", always_match, obmem_attach, DV_DULL, - sizeof(struct device), 0 }; +struct cfattach obmem_ca = { + sizeof(struct device), obmem_match, obmem_attach +}; + +struct cfdriver obmem_cd = { + NULL, "obmem", DV_DULL +}; + +static int +obmem_match(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + + if (ca->ca_bustype != BUS_OBMEM) + return (0); + return(1); +} static void obmem_attach(parent, self, args) @@ -58,13 +73,7 @@ obmem_attach(parent, self, args) void *args; { printf("\n"); - config_scan(obmem_scan, self); -} -static void -obmem_scan(parent, child) - struct device *parent; - void *child; -{ - bus_scan(parent, child, BUS_OBMEM); + /* We know ca_bustype == BUS_OBMEM */ + (void) config_search(bus_scan, self, args); } diff --git a/sys/arch/sun3/dev/prom.c b/sys/arch/sun3/dev/prom.c index 14033fe11bd..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/prom.c +++ b/sys/arch/sun3/dev/prom.c @@ -1,342 +0,0 @@ -/* $NetBSD: prom.c,v 1.15 1995/04/10 06:14:57 mycroft Exp $ */ - -/* - * Copyright (c) 1993 Adam Glass - * 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 Adam Glass. - * 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 Adam Glass ``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 Adam Glass BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "prom.h" - -#include <sys/param.h> -#include <sys/proc.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/ioctl.h> -#include <sys/tty.h> -#include <sys/file.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/device.h> - -#include <machine/autoconf.h> -#include <machine/mon.h> - -#include <dev/cons.h> -#include "../sun3/interreg.h" - -/* - * cleanup: - * get autoconfiguration right, right style - * not a true serial driver but a tty driver, i.e no carrier - * make sure start is non-blocking - * add read support via timeouts - */ - -void promattach __P((struct device *, struct device *, void *)); - -struct prom_softc { - struct device sc_dev; - int sc_flags; - int sc_nopen; -}; -struct tty *prom_tty[NPROM]; - -struct cfdriver promcd = { - NULL, "prom", always_match, promattach, DV_TTY, sizeof(struct prom_softc) -}; - -#define UNIT_TO_PROM_SC(unit) promcd.cd_devs[unit] -#ifndef PROM_RECEIVE_FREQ -#define PROM_RECEIVE_FREQ 10 -#endif - -int promopen __P((dev_t, int, int, struct proc *)); -int promclose __P((dev_t, int, int, struct proc *)); -int promread __P((dev_t, struct uio *, int)); -int promwrite __P((dev_t, struct uio *, int)); -int promioctl __P((dev_t, int, caddr_t, int, struct proc *)); -int promstop __P((struct tty *, int)); - -static int promparam __P((struct tty *, struct termios *)); -static void promstart __P((struct tty *)); -static void promreceive __P((void *)); - -void -promattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - - printf("\n"); -} - -int -promopen(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - struct tty *tp; - struct prom_softc *sc; - int unit, result; - - unit = minor(dev); - if (unit >= promcd.cd_ndevs) - return ENXIO; - sc = UNIT_TO_PROM_SC(unit); - if (sc == NULL) - return ENXIO; - - if (prom_tty[unit] == NULL) - tp = prom_tty[unit] = ttymalloc(); - else - tp = prom_tty[unit]; - - tp->t_oproc = promstart; - tp->t_param = promparam; - tp->t_dev = dev; - if ((tp->t_state & TS_ISOPEN) == 0) { - tp->t_state |= TS_WOPEN; - ttychars(tp); - if (tp->t_ispeed == 0) { - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - } - promparam(tp, &tp->t_termios); - ttsetwater(tp); - } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { - return EBUSY; - } - - tp->t_state |= TS_CARR_ON; - result = (*linesw[tp->t_line].l_open)(dev, tp); - if (result) - return result; - timeout(promreceive, tp, hz/PROM_RECEIVE_FREQ); - return 0; -} - -int -promclose(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - struct tty *tp; - int unit; - struct prom_softc *sc; - - unit = minor(dev); - sc = UNIT_TO_PROM_SC(unit); - tp = prom_tty[unit]; - - (*linesw[tp->t_line].l_close)(tp, flag); - return ttyclose(tp); -} - -int -promread(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - register struct tty *tp; - - tp = prom_tty[minor(dev)]; - return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); -} - -int -promwrite(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - register struct tty *tp; - - tp = prom_tty[minor(dev)]; - return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); -} - -int -promioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - register struct tty *tp; - int error; - - tp = prom_tty[minor(dev)]; - - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error >= 0) - return error; - error = ttioctl(tp, cmd, data, flag, p); - if (error >= 0) - return error; - - return ENOTTY; -} - -void -promstart(tp) - struct tty *tp; -{ - int s, c, count; - u_char outbuf[50]; - u_char *bufp; - - s = spltty(); - if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) - goto out; - tp->t_state |= TS_BUSY; - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state & TS_ASLEEP) { - tp->t_state &=~ TS_ASLEEP; - wakeup((caddr_t)&tp->t_outq); - } - selwakeup(&tp->t_wsel); - } - count = q_to_b(&tp->t_outq, outbuf, 49); - if (count) { - outbuf[count] = '\0'; - (void) splhigh(); - mon_printf("%s", outbuf); - (void) spltty(); - } - tp->t_state &= ~TS_BUSY; -out: - splx(s); -} - -void -promstop(tp, flag) - struct tty *tp; - int flag; -{ - -} - -static int -promparam(tp, t) - struct tty *tp; - struct termios *t; -{ - struct prom_softc *sc; - - if (t->c_ispeed == 0 || (t->c_ispeed != t->c_ospeed)) - return EINVAL; - tp->t_ispeed = t->c_ispeed; - tp->t_ospeed = t->c_ospeed; - tp->t_cflag = t->c_cflag; - return 0; -} - -static void -promreceive(arg) - void *arg; -{ - struct tty *tp = arg; - int c, s; - extern unsigned int orig_nmi_vector; - extern int nmi_intr(); - - s = spltty(); - if (tp->t_state & TS_ISOPEN) { - if ((tp->t_state & TS_BUSY) == 0) { - set_clk_mode(0, IREG_CLOCK_ENAB_7|IREG_CLOCK_ENAB_5, 0); - isr_add_custom(7, orig_nmi_vector); - set_clk_mode(IREG_CLOCK_ENAB_7, 0, 1); - c = mon_may_getchar(); - set_clk_mode(0, IREG_CLOCK_ENAB_7|IREG_CLOCK_ENAB_5, 0); - isr_add_custom(7, nmi_intr); - set_clk_mode(IREG_CLOCK_ENAB_5, 0, 1); - if (c != -1) - (*linesw[tp->t_line].l_rint)(c, tp); - } - timeout(promreceive, tp, hz/PROM_RECEIVE_FREQ); - } - splx(s); -} - -void -promcnprobe(cp) - struct consdev *cp; -{ - int prommajor; - - /* locate the major number */ - for (prommajor = 0; prommajor < nchrdev; prommajor++) - if (cdevsw[prommajor].d_open == promopen) - break; - - cp->cn_dev = makedev(prommajor, 0); - cp->cn_pri = CN_INTERNAL; /* will always exist but you don't - * want to use it unless you have to - */ -} - -void -promcninit(cp) - struct consdev *cp; -{ - - mon_printf("console on prom0\n"); -} - -int -promcngetc(dev) - dev_t dev; -{ - - mon_printf("not sure how to do promcngetc() yet\n"); -} - -/* - * Console kernel output character routine. - */ -void -promcnputc(dev, c) - dev_t dev; - int c; -{ - int s; - - s = splhigh(); - if (minor(dev) != 0) - mon_printf("non unit 0 prom console???\n"); - mon_putchar(c); - splx(s); -} diff --git a/sys/arch/sun3/dev/rd_root.c b/sys/arch/sun3/dev/rd_root.c index 10b341611a5..72b7328a339 100644 --- a/sys/arch/sun3/dev/rd_root.c +++ b/sys/arch/sun3/dev/rd_root.c @@ -1,4 +1,4 @@ -/* $NetBSD: rd_root.c,v 1.2 1995/11/17 23:24:56 gwr Exp $ */ +/* $NetBSD: rd_root.c,v 1.4 1996/03/26 14:58:47 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross diff --git a/sys/arch/sun3/dev/scsi_5380.h b/sys/arch/sun3/dev/scsi_5380.h index ff27756e1c6..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/scsi_5380.h +++ b/sys/arch/sun3/dev/scsi_5380.h @@ -1,142 +0,0 @@ -/* $NetBSD: scsi_5380.h,v 1.4 1994/11/21 21:31:18 gwr Exp $ */ - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 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 - * 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. - */ -/* - * HISTORY (mach3) - * Revision 2.3 91/08/24 12:25:10 af - * Moved padding of regmap in impl file. - * [91/08/02 04:22:39 af] - * - * Revision 2.2 91/06/19 16:28:35 rvb - * From the NCR data sheets - * "NCR 5380 Family, SCSI Protocol Controller Data Manual" - * NCR Microelectronics Division, Colorado Spring, 6/98 T01891L - * [91/04/21 af] - * - */ - -/* - * File: scsi_5380.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 5/91 - * - * Defines for the NCR 5380 (SCSI chip), aka Am5380 - */ - -/* - * Register map - */ - -typedef struct { - volatile unsigned char sci_data; /* r: Current data */ -#define sci_odata sci_data /* w: Out data */ - volatile unsigned char sci_icmd; /* rw: Initiator command */ - volatile unsigned char sci_mode; /* rw: Mode */ - volatile unsigned char sci_tcmd; /* rw: Target command */ - volatile unsigned char sci_bus_csr; /* r: Bus Status */ -#define sci_sel_enb sci_bus_csr /* w: Select enable */ - volatile unsigned char sci_csr; /* r: Status */ -#define sci_dma_send sci_csr /* w: Start dma send data */ - volatile unsigned char sci_idata; /* r: Input data */ -#define sci_trecv sci_idata /* w: Start dma receive, target */ - volatile unsigned char sci_iack; /* r: Interrupt Acknowledge */ -#define sci_irecv sci_iack /* w: Start dma receive, initiator */ -} sci_regmap_t; - - -/* - * Initiator command register - */ - -#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */ -#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */ -#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */ -#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */ -#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */ -#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */ -#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */ -#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */ -#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */ -#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */ - - -/* - * Mode register - */ - -#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */ -#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */ -#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */ -#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */ -#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */ -#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */ -#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */ -#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake (MBZ) */ - - -/* - * Target command register - */ - -#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */ -#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */ -#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */ -#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */ -#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */ -#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred - * (not on 5380/1) */ - -#define SCI_PHASE(x) SCSI_PHASE(x) - -/* - * Current (SCSI) Bus status - */ - -#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */ -#define SCI_BUS_SEL 0x02 /* r: SEL signal */ -#define SCI_BUS_IO 0x04 /* r: I/O signal */ -#define SCI_BUS_CD 0x08 /* r: C/D signal */ -#define SCI_BUS_MSG 0x10 /* r: MSG signal */ -#define SCI_BUS_REQ 0x20 /* r: REQ signal */ -#define SCI_BUS_BSY 0x40 /* r: BSY signal */ -#define SCI_BUS_RST 0x80 /* r: RST signal */ - -#define SCI_CUR_PHASE(x) SCSI_PHASE((x)>>2) - -/* - * Bus and Status register - */ - -#define SCI_CSR_ACK 0x01 /* r: ACK signal */ -#define SCI_CSR_ATN 0x02 /* r: ATN signal */ -#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */ -#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */ -#define SCI_CSR_INT 0x10 /* r: Interrupt request */ -#define SCI_CSR_PERR 0x20 /* r: Parity error */ -#define SCI_CSR_DREQ 0x40 /* r: DMA request */ -#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */ - diff --git a/sys/arch/sun3/dev/scsi_defs.h b/sys/arch/sun3/dev/scsi_defs.h index c2916d30363..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/scsi_defs.h +++ b/sys/arch/sun3/dev/scsi_defs.h @@ -1,58 +0,0 @@ -/* $NetBSD: scsi_defs.h,v 1.4 1995/06/01 20:22:17 gwr Exp $ */ - -/*- - * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, - * Michael L. Finch, Bradley A. Grantham, and - * Lawrence A. Kesteloot - * 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 the Alice Group. - * 4. The names of the Alice Group or any of its members may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCSI_DEFS_H -#define _SCSI_DEFS_H - -#define SCSI_PHASE_DATA_OUT 0x0 -#define SCSI_PHASE_DATA_IN 0x1 -#define SCSI_PHASE_CMD 0x2 -#define SCSI_PHASE_STATUS 0x3 -#define SCSI_PHASE_UNSPEC1 0x4 -#define SCSI_PHASE_UNSPEC2 0x5 -#define SCSI_PHASE_MESSAGE_OUT 0x6 -#define SCSI_PHASE_MESSAGE_IN 0x7 - -#define SCSI_PHASE(x) ((x)&0x7) - -/* These should be fixed up. */ - -#define SCSI_RET_SUCCESS 0 -#define SCSI_RET_RETRY 1 -#define SCSI_RET_DEVICE_DOWN 2 -#define SCSI_RET_COMMAND_FAIL 3 -#define SCSI_RET_NEED_RESET 4 - -#endif diff --git a/sys/arch/sun3/dev/scsi_sunsi.h b/sys/arch/sun3/dev/scsi_sunsi.h index 6068ec3a508..e69de29bb2d 100644 --- a/sys/arch/sun3/dev/scsi_sunsi.h +++ b/sys/arch/sun3/dev/scsi_sunsi.h @@ -1,88 +0,0 @@ -/* $NetBSD: scsi_sunsi.h,v 1.2 1995/06/01 20:22:27 gwr Exp $ */ - -/* - * Register map for the Sun3 SCSI Interface (si) - * The first part of this register map is an NCR5380 - * SCSI Bus Interface Controller (SBIC). The rest is a - * DMA controller and custom logic in one of two flavors, - * one for the OBIO interface (3/50,3/60) and one for the - * VME interface (3/160,3/260,etc.), where some registers - * are implemented only on one or the other, some on both. - */ - -/* - * Some of these registers apply to only one interface and some - * apply to both. The registers which apply to the Sun3/50 onboard - * version only are udc_rdata and udc_raddr. The registers which - * apply to the Sun3 vme version only are dma_addr, dma_count, bpr, - * iv_am, and bcrh. Thus, the sbc registers, fifo_data, bcr, and csr - * apply to both interfaces. - * One other feature of the vme interface: a write to the dma count - * register also causes a write to the fifo byte count register and - * vis versa. - */ - -struct si_regs { - sci_regmap_t sci; /* See scsi_5380.h */ - /* DMA controller registers */ - u_short dma_addrh; /* dma address (VME only) */ - u_short dma_addrl; /* (high word, low word) */ - u_short dma_counth; /* dma count (VME only) */ - u_short dma_countl; /* (high word, low word) */ - - /* AMD 9516 regs (OBIO only) see am9516.h */ - u_short udc_data; /* Am9516, reg data (OBIO only) */ - u_short udc_addr; /* Am9516, reg addr (OBIO only) */ - - /* These three registers are on both OBIO and VME versions. */ - u_short fifo_data; /* fifo data register */ - /* holds extra byte on odd */ - /* byte dma read */ - u_short fifo_count; /* fifo byte count */ - u_short si_csr; /* control/status register */ - - /* The rest of these are on the VME interface only: */ - u_short bprh; /* byte pack, high (VME only) */ - u_short bprl; /* byte pack, low (VME only) */ - u_short iv_am; /* bits 0-7: intr vector */ - /* bits 8-13: addr modifier (VME only) */ - /* bits 14-15: unused */ - u_short bcrh; /* high portion of bcr (VME only) */ -}; - -/* possible values for the address modifier, sun3 vme version only */ -#define VME_SUPV_DATA_24 0x3d00 - -/* XXX - must massage dvma addresses for Sun3/50 hardware (?) */ -#define DVMA_OFFSET (int)(DVMA - (char *)KERNELBASE) - -/* - * Status Register. - * Note: - * (r) indicates bit is read only. - * (rw) indicates bit is read or write. - * (v) vme host adaptor interface only. - * (o) sun3/50 onboard host adaptor interface only. - * (b) both vme and sun3/50 host adaptor interfaces. - */ -#define SI_CSR_DMA_ACTIVE 0x8000 /* (r,o) dma transfer active */ -#define SI_CSR_DMA_CONFLICT 0x4000 /* (r,b) reg accessed while dmaing */ -#define SI_CSR_DMA_BUS_ERR 0x2000 /* (r,b) bus error during dma */ -#define SI_CSR_ID 0x1000 /* (r,b) 0 for 3/50, 1 for SCSI-3, */ - /* 0 if SCSI-3 unmodified */ -#define SI_CSR_FIFO_FULL 0x0800 /* (r,b) fifo full */ -#define SI_CSR_FIFO_EMPTY 0x0400 /* (r,b) fifo empty */ -#define SI_CSR_SBC_IP 0x0200 /* (r,b) sbc interrupt pending */ -#define SI_CSR_DMA_IP 0x0100 /* (r,b) dma interrupt pending */ -#define SI_CSR_LOB 0x00c0 /* (r,v) number of leftover bytes */ -#define SI_CSR_LOB_THREE 0x00c0 /* (r,v) three leftover bytes */ -#define SI_CSR_LOB_TWO 0x0080 /* (r,v) two leftover bytes */ -#define SI_CSR_LOB_ONE 0x0040 /* (r,v) one leftover byte */ -#define SI_CSR_BPCON 0x0020 /* (rw,v) byte packing control */ - /* dma is in 0=longwords, 1=words */ -#define SI_CSR_DMA_EN 0x0010 /* (rw,v) dma enable */ -#define SI_CSR_SEND 0x0008 /* (rw,b) dma dir, 1=to device */ -#define SI_CSR_INTR_EN 0x0004 /* (rw,b) interrupts enable */ -#define SI_CSR_FIFO_RES 0x0002 /* (rw,b) inits fifo, 0=reset */ -#define SI_CSR_SCSI_RES 0x0001 /* (rw,b) reset sbc and udc, 0=reset */ - diff --git a/sys/arch/sun3/dev/si.c b/sys/arch/sun3/dev/si.c index b803393242e..893c5368c3a 100644 --- a/sys/arch/sun3/dev/si.c +++ b/sys/arch/sun3/dev/si.c @@ -1,10 +1,8 @@ -/* $NetBSD: si.c,v 1.22 1995/10/08 23:42:58 gwr Exp $ */ +/* $NetBSD: si.c,v 1.24 1996/03/26 15:01:10 gwr Exp $ */ /* - * Copyright (C) 1994 Adam Glass, Gordon W. Ross - * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, - * Michael L. Finch, Bradley A. Grantham, and - * Lawrence A. Kesteloot + * Copyright (c) 1995 David Jones, Gordon W. Ross + * Copyright (c) 1994 Adam Glass * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,406 +13,262 @@ * 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 + * 3. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the Alice Group. - * 4. The names of the Alice Group or any of its members may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This product includes software developed by + * Adam Glass, David Jones, and Gordon Ross * - * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, + * IN NO EVENT SHALL THE AUTHORS 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. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define DEBUG 1 - -/* XXX - Need to add support for real DMA. -gwr */ -/* #define PSEUDO_DMA 1 (broken) */ +/* + * This file contains only the machine-dependent parts of the + * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) + * The machine-independent parts are in ncr5380sbc.c + * + * Supported hardware includes: + * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) + * Sun SCSI-3 on VME (Sun3/160,Sun3/260) + * + * Could be made to support the Sun3/E if someone wanted to. + * + * Note: Both supported variants of the Sun SCSI-3 adapter have + * some really unusual "features" for this driver to deal with, + * generally related to the DMA engine. The OBIO variant will + * ignore any attempt to write the FIFO count register while the + * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with + * by setting the FIFO count early in COMMAND or MSG_IN phase. + * + * The VME variant has a bit to enable or disable the DMA engine, + * but that bit also gates the interrupt line from the NCR5380! + * Therefore, in order to get any interrupt from the 5380, (i.e. + * for reselect) one must clear the DMA engine transfer count and + * then enable DMA. This has the further complication that you + * CAN NOT touch the NCR5380 while the DMA enable bit is set, so + * we have to turn DMA back off before we even look at the 5380. + * + * What wonderfully whacky hardware this is! + * + * Credits, history: + * + * David Jones wrote the initial version of this module, which + * included support for the VME adapter only. (no reselection). + * + * Gordon Ross added support for the OBIO adapter, and re-worked + * both the VME and OBIO code to support disconnect/reselect. + * (Required figuring out the hardware "features" noted above.) + * + * The autoconfiguration boilerplate came from Adam Glass. + */ -#include <sys/types.h> -#include <sys/malloc.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/device.h> #include <sys/buf.h> #include <sys/proc.h> #include <sys/user.h> -#include <sys/device.h> - -#include <machine/autoconf.h> -#include <machine/isr.h> -#include <machine/obio.h> #include <scsi/scsi_all.h> #include <scsi/scsi_debug.h> #include <scsi/scsiconf.h> -#include "scsi_defs.h" -#include "scsi_5380.h" -#include "scsi_sunsi.h" - -#ifdef DEBUG -static int si_debug = 0; -static int si_flags = 0 /* | SDEV_DB2 */ ; -#endif - -#define SCI_PHASE_DISC 0 /* sort of ... */ -#define SCI_CLR_INTR(regs) ((volatile)(regs->sci_iack)) -#define SCI_ACK(ptr,phase) (ptr)->sci_tcmd = (phase) -#define SCSI_TIMEOUT_VAL 1000000 -#define WAIT_FOR_NOT_REQ(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_NOT_REQ---%s, line %d.\n", \ - __FILE__, __LINE__); \ - goto scsi_timeout_error; \ - } \ - } -#define WAIT_FOR_REQ(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_REQ---%s, line %d.\n", \ - __FILE__, __LINE__); \ - goto scsi_timeout_error; \ - } \ - } -#define WAIT_FOR_BSY(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ( (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_BSY---%s, line %d.\n", \ - __FILE__, __LINE__); \ - goto scsi_timeout_error; \ - } \ - } - -#define ARBITRATION_RETRIES 1000 +#include <machine/autoconf.h> +#include <machine/isr.h> +#include <machine/obio.h> +#include <machine/dvma.h> -/* XXX - Always available, but might do nothing. */ -int Debugger(); +#define DEBUG XXX -struct ncr5380_softc { - struct device sc_dev; - volatile void *sc_regs; - int sc_adapter_type; - int sc_adapter_iv_am; /* int. vec + address modifier */ - struct scsi_link sc_link; -}; +#include <dev/ic/ncr5380reg.h> +#include <dev/ic/ncr5380var.h> -static void ncr5380_minphys(struct buf *bp); -static int ncr5380_scsi_cmd(struct scsi_xfer *xs); -static int ncr5380_reset_adapter(struct ncr5380_softc *); -static int ncr5380_reset_scsibus(struct ncr5380_softc *); -static int ncr5380_poll(int adapter, int timeout); -static int ncr5380_send_cmd(struct scsi_xfer *xs); +#include "sireg.h" +#include "sivar.h" -static int ncr_intr(void *); +int si_debug = 0; +#ifdef DEBUG +static int si_link_flags = 0 /* | SDEV_DB2 */ ; +#endif -static int si_generic(int adapter, int id, int lun, - struct scsi_generic *cmd, int cmdlen, - void *databuf, int datalen); -static int si_group0(int adapter, int id, int lun, - int opcode, int addr, int len, - int flags, caddr_t databuf, int datalen); +/* How long to wait for DMA before declaring an error. */ +int si_dma_intr_timo = 500; /* ticks (sec. X 100) */ -static char scsi_name[] = "si"; +static void si_minphys __P((struct buf *)); +static int si_print __P((void *, char *)); -struct scsi_adapter ncr5380_switch = { +static struct scsi_adapter si_ops = { ncr5380_scsi_cmd, /* scsi_cmd() */ - ncr5380_minphys, /* scsi_minphys() */ + si_minphys, /* scsi_minphys() */ NULL, /* open_target_lu() */ NULL, /* close_target_lu() */ }; /* This is copied from julian's bt driver */ /* "so we have a default dev struct for our link struct." */ -struct scsi_device ncr_dev = { +static struct scsi_device si_dev = { NULL, /* Use default error handler. */ NULL, /* Use default start handler. */ NULL, /* Use default async handler. */ NULL, /* Use default "done" routine. */ }; -static int si_match(); -static void si_attach(); +/* + * New-style autoconfig attachment. The cfattach + * structures are in si_obio.c and si_vme.c + */ -struct cfdriver sicd = { - NULL, "si", si_match, si_attach, DV_DULL, - sizeof(struct ncr5380_softc), NULL, 0, +struct cfdriver si_cd = { + NULL, "si", DV_DULL }; -static int -si_print(aux, name) - void *aux; - char *name; -{ - if (name != NULL) - printf("%s: scsibus ", name); - return UNCONF; -} -static int -si_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; +void +si_attach(sc) + struct si_softc *sc; { - struct cfdata *cf = vcf; - struct confargs *ca = args; - int x, probe_addr; - - /* Default interrupt priority always splbio==2 */ - if (ca->ca_intpri == -1) - ca->ca_intpri = 2; - - if ((cpu_machine_id == SUN3_MACH_50) || - (cpu_machine_id == SUN3_MACH_60) ) - { - /* Sun3/50 or Sun3/60 have only OBIO "si" */ - if (ca->ca_bustype != BUS_OBIO) - return(0); - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_NCR_SCSI; - /* OK... */ - } else { - /* Other Sun3 models may have VME "si" or "sc" */ - if (ca->ca_bustype != BUS_VME16) - return (0); - if (ca->ca_paddr == -1) - return (0); - /* OK... */ - } - - /* Make sure there is something there... */ - x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1); - if (x == -1) - return (0); + struct ncr5380_softc *ncr_sc = (void *)sc; + volatile struct si_regs *regs = sc->sc_regs; + int i; /* - * If this is a VME SCSI board, we have to determine whether - * it is an "sc" (Sun2) or "si" (Sun3) SCSI board. This can - * be determined using the fact that the "sc" board occupies - * 4K bytes in VME space but the "si" board occupies 2K bytes. + * Fill in the prototype scsi_link. */ - if (ca->ca_bustype == BUS_VME16) { - /* Note, the "si" board should NOT respond here. */ - x = bus_peek(ca->ca_bustype, ca->ca_paddr + 0x801, 1); - if (x != -1) - return(0); - } + ncr_sc->sc_link.adapter_softc = sc; + ncr_sc->sc_link.adapter_target = 7; + ncr_sc->sc_link.adapter = &si_ops; + ncr_sc->sc_link.device = &si_dev; - return (1); -} +#ifdef DEBUG + if (si_debug) + printf("si: Set TheSoftC=%x TheRegs=%x\n", sc, regs); + ncr_sc->sc_link.flags |= si_link_flags; +#endif -static void -si_attach(parent, self, args) - struct device *parent, *self; - void *args; -{ - struct ncr5380_softc *ncr5380 = (struct ncr5380_softc *) self; - volatile struct si_regs *regs; - struct confargs *ca = args; - - switch (ca->ca_bustype) { - - case BUS_OBIO: - regs = (struct si_regs *) - obio_alloc(ca->ca_paddr, sizeof(*regs)); - isr_add_autovect(ncr_intr, (void *)ncr5380, - ca->ca_intpri); - break; - - case BUS_VME16: - regs = (struct si_regs *) - bus_mapin(ca->ca_bustype, ca->ca_paddr, sizeof(*regs)); - isr_add_vectored(ncr_intr, (void *)ncr5380, - ca->ca_intpri, ca->ca_intvec); - break; - - default: - printf("unknown\n"); - return; - } + /* + * Initialize fields used by the MI code + */ + ncr_sc->sci_r0 = ®s->sci.sci_r0; + ncr_sc->sci_r1 = ®s->sci.sci_r1; + ncr_sc->sci_r2 = ®s->sci.sci_r2; + ncr_sc->sci_r3 = ®s->sci.sci_r3; + ncr_sc->sci_r4 = ®s->sci.sci_r4; + ncr_sc->sci_r5 = ®s->sci.sci_r5; + ncr_sc->sci_r6 = ®s->sci.sci_r6; + ncr_sc->sci_r7 = ®s->sci.sci_r7; - ncr5380->sc_adapter_type = ca->ca_bustype; - ncr5380->sc_adapter_iv_am = - VME_SUPV_DATA_24 | (ca->ca_intvec & 0xFF); - ncr5380->sc_regs = regs; + /* + * Allocate DMA handles. + */ + i = SCI_OPENINGS * sizeof(struct si_dma_handle); + sc->sc_dma = (struct si_dma_handle *) + malloc(i, M_DEVBUF, M_WAITOK); + if (sc->sc_dma == NULL) + panic("si: dvma_malloc failed\n"); + for (i = 0; i < SCI_OPENINGS; i++) + sc->sc_dma[i].dh_flags = 0; /* - * fill in the prototype scsi_link. + * Initialize si board itself. */ - ncr5380->sc_link.adapter_softc = ncr5380; - ncr5380->sc_link.adapter_target = 7; - ncr5380->sc_link.adapter = &ncr5380_switch; - ncr5380->sc_link.device = &ncr_dev; - ncr5380->sc_link.openings = 2; -#ifdef DEBUG - ncr5380->sc_link.flags |= si_flags; -#endif + si_reset_adapter(ncr_sc); + ncr5380_init(ncr_sc); + ncr5380_reset_scsibus(ncr_sc); + config_found(&(ncr_sc->sc_dev), &(ncr_sc->sc_link), si_print); +} - printf("\n"); - ncr5380_reset_adapter(ncr5380); - ncr5380_reset_scsibus(ncr5380); - config_found(self, &(ncr5380->sc_link), si_print); +static int +si_print(aux, name) + void *aux; + char *name; +{ + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; } -#define MIN_PHYS 65536 /*BARF!!!!*/ static void -ncr5380_minphys(struct buf *bp) +si_minphys(struct buf *bp) { - if (bp->b_bcount > MIN_PHYS) { - printf("Uh-oh... ncr5380_minphys setting bp->b_bcount = %x.\n", MIN_PHYS); - bp->b_bcount = MIN_PHYS; + if (bp->b_bcount > MAX_DMA_LEN) { +#ifdef DEBUG + if (si_debug) { + printf("si_minphys len = 0x%x.\n", bp->b_bcount); + Debugger(); + } +#endif + bp->b_bcount = MAX_DMA_LEN; } - minphys(bp); + return (minphys(bp)); } -#undef MIN_PHYS -static int -ncr5380_scsi_cmd(struct scsi_xfer *xs) + +#define CSR_WANT (SI_CSR_SBC_IP | SI_CSR_DMA_IP | \ + SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR ) + +int +si_intr(void *arg) { - int flags, s, r; + struct si_softc *sc = arg; + volatile struct si_regs *si = sc->sc_regs; + int dma_error, claimed; + u_short csr; - flags = xs->flags; - if (xs->bp) flags |= (SCSI_NOSLEEP); - if ( flags & ITSDONE ) { - printf("Already done?"); - xs->flags &= ~ITSDONE; - } - if ( ! ( flags & INUSE ) ) { - printf("Not in use?"); - xs->flags |= INUSE; - } + claimed = 0; + dma_error = 0; - s = splbio(); + /* SBC interrupt? DMA interrupt? */ + csr = si->si_csr; + NCR_TRACE("si_intr: csr=0x%x\n", csr); - if ( flags & SCSI_RESET ) { - printf("flags & SCSIRESET.\n"); - ncr5380_reset_scsibus(xs->sc_link->adapter_softc); - r = COMPLETE; - } else { - r = ncr5380_send_cmd(xs); - xs->flags |= ITSDONE; - scsi_done(xs); + if (csr & SI_CSR_DMA_CONFLICT) { + dma_error |= SI_CSR_DMA_CONFLICT; + printf("si_intr: DMA conflict\n"); } - - splx(s); - - switch(r) { - case COMPLETE: - case SUCCESSFULLY_QUEUED: - r = SUCCESSFULLY_QUEUED; - if (xs->flags & SCSI_POLL) - r = COMPLETE; - break; - default: - break; + if (csr & SI_CSR_DMA_BUS_ERR) { + dma_error |= SI_CSR_DMA_BUS_ERR; + printf("si_intr: DMA bus error\n"); } - return r; -} - -#ifdef DEBUG -static int -ncr5380_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *) xs->cmd; - int i = 0; - - if ( ! ( xs->flags & SCSI_RESET ) ) { - printf("si(%d:%d:%d)-", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); - while (i < xs->cmdlen) { - if (i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } else { - printf("si(%d:%d:%d)-RESET-\n", - xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun); + if (dma_error) { + if (sc->ncr_sc.sc_state & NCR_DOINGDMA) + sc->ncr_sc.sc_state |= NCR_ABORTING; + /* Make sure we will call the main isr. */ + csr |= SI_CSR_DMA_IP; } -} -#endif - -/* - * Actual chip control. - */ -static void -ncr_sbc_intr(struct ncr5380_softc *ncr5380) -{ - volatile sci_regmap_t *regs = ncr5380->sc_regs; - - if ((regs->sci_csr & SCI_CSR_INT) == 0) { + if (csr & (SI_CSR_SBC_IP | SI_CSR_DMA_IP)) { + claimed = ncr5380_intr(&sc->ncr_sc); #ifdef DEBUG - printf (" ncr_sbc_intr: spurrious\n"); + if (!claimed) { + printf("si_intr: spurious from SBC\n"); + if (si_debug & 4) { + Debugger(); /* XXX */ + } + } #endif - return; } - SCI_CLR_INTR(regs); -#ifdef DEBUG - printf (" ncr_sbc_intr\n"); -#endif -} - -static void -ncr_dma_intr(struct ncr5380_softc *ncr5380) -{ - volatile struct si_regs *regs = ncr5380->sc_regs; - -#ifdef DEBUG - printf (" ncr_dma_intr\n"); -#endif + return (claimed); } -static int -ncr_intr(void *arg) -{ - struct ncr5380_softc *ncr5380 = arg; - volatile struct si_regs *si = ncr5380->sc_regs; - int rv = 0; - - /* Interrupts not enabled? Can not be for us. */ - if ((si->si_csr & SI_CSR_INTR_EN) == 0) - return rv; - - if (si->si_csr & SI_CSR_DMA_IP) { - ncr_dma_intr(ncr5380); - rv++; - } - if (si->si_csr & SI_CSR_SBC_IP) { - ncr_sbc_intr(ncr5380); - rv++; - } - return rv; -} -static int -ncr5380_reset_adapter(struct ncr5380_softc *sc) +void +si_reset_adapter(struct ncr5380_softc *ncr_sc) { + struct si_softc *sc = (struct si_softc *)ncr_sc; volatile struct si_regs *si = sc->sc_regs; #ifdef DEBUG @@ -423,585 +277,194 @@ ncr5380_reset_adapter(struct ncr5380_softc *sc) } #endif - /* The reset bits in the CSR are active low. */ + /* + * The SCSI3 controller has an 8K FIFO to buffer data between the + * 5380 and the DMA. Make sure it starts out empty. + * + * The reset bits in the CSR are active low. + */ si->si_csr = 0; - delay(20); - si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES; + delay(10); + si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES | SI_CSR_INTR_EN; + delay(10); si->fifo_count = 0; + if (sc->sc_adapter_type == BUS_VME16) { si->dma_addrh = 0; si->dma_addrl = 0; si->dma_counth = 0; si->dma_countl = 0; - si->iv_am = sc->sc_adapter_iv_am; + si->si_iv_am = sc->sc_adapter_iv_am; + si->fifo_cnt_hi = 0; } -} - -static int -ncr5380_reset_scsibus(struct ncr5380_softc *ncr5380) -{ - volatile sci_regmap_t *regs = ncr5380->sc_regs; -#ifdef DEBUG - if (si_debug) { - printf("si_reset_scsibus\n"); - } -#endif - - regs->sci_icmd = SCI_ICMD_RST; - delay(100); - regs->sci_icmd = 0; - - regs->sci_mode = 0; - regs->sci_tcmd = SCI_PHASE_DISC; - regs->sci_sel_enb = 0; - - SCI_CLR_INTR(regs); - /* XXX - Need long delay here! */ + SCI_CLR_INTR(ncr_sc); } -static int -ncr5380_poll(int adapter, int timeout) -{ -} - -static int -ncr5380_send_cmd(struct scsi_xfer *xs) -{ - int sense; -#ifdef DIAGNOSTIC - if ((getsr() & PSL_IPL) < PSL_IPL2) - panic("ncr_send_cmd: bad spl"); -#endif +/***************************************************************** + * Common functions for DMA + ****************************************************************/ -#ifdef DEBUG - if (si_debug & 2) - ncr5380_show_scsi_cmd(xs); -#endif - - sense = si_generic( xs->sc_link->scsibus, xs->sc_link->target, - xs->sc_link->lun, xs->cmd, xs->cmdlen, - xs->data, xs->datalen ); - - switch (sense) { - case 0: /* success */ - xs->resid = 0; - xs->error = XS_NOERROR; - break; - - case 0x02: /* Check condition */ -#ifdef DEBUG - if (si_debug) - printf("check cond. target %d.\n", - xs->sc_link->target); -#endif - delay(10); /* Phil's fix for slow devices. */ - si_group0(xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun, - 0x3, 0x0, - sizeof(struct scsi_sense_data), - 0, (caddr_t) &(xs->sense), - sizeof(struct scsi_sense_data)); - xs->error = XS_SENSE; - break; - case 0x08: /* Busy - common code will delay, retry. */ - xs->error = XS_BUSY; - break; - default: /* Dead - tell common code to give up. */ - xs->error = XS_DRIVER_STUFFUP; - break; - - } - return (COMPLETE); -} - -static int -si_select_target(register volatile sci_regmap_t *regs, - u_char myid, u_char tid, int with_atn) +/* + * Allocate a DMA handle and put it in sc->sc_dma. Prepare + * for DMA transfer. On the Sun3, this means mapping the buffer + * into DVMA space. dvma_mapin() flushes the cache for us. + */ +void +si_dma_alloc(ncr_sc) + struct ncr5380_softc *ncr_sc; { - register u_char bid, icmd; - int ret = SCSI_RET_RETRY; - int arb_retries, arb_wait; - - /* for our purposes.. */ - myid = 1 << myid; - tid = 1 << tid; - - regs->sci_sel_enb = 0; /* we don't want any interrupts. */ - regs->sci_tcmd = 0; /* get into a harmless state */ + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct scsi_xfer *xs = sr->sr_xs; + struct si_dma_handle *dh; + int i, xlen; + u_long addr; - arb_retries = ARBITRATION_RETRIES; - -retry_arbitration: - regs->sci_mode = 0; /* get into a harmless state */ -wait_for_bus_free: - if (--arb_retries <= 0) { -#ifdef DEBUG - if (si_debug) { - printf("si_select: arb_retries expended; resetting...\n"); - } +#ifdef DIAGNOSTIC + if (sr->sr_dma_hand != NULL) + panic("si_dma_alloc: already have DMA handle"); #endif - ret = SCSI_RET_NEED_RESET; - goto nosel; - } - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + addr = (u_long) ncr_sc->sc_dataptr; + xlen = ncr_sc->sc_datalen; - if (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) { - /* Something is sitting on the SCSI bus... */ -#ifdef DEBUG - /* Only complain once (the last time through). */ - if (si_debug && (arb_retries <= 1)) { - printf("si_select_target: still BSY+SEL\n"); - } -#endif - /* Give it a little time, then try again. */ - delay(10); - goto wait_for_bus_free; + /* If the DMA start addr is misaligned then do PIO */ + if ((addr & 1) || (xlen & 1)) { + printf("si_dma_alloc: misaligned.\n"); + return; } - regs->sci_odata = myid; - regs->sci_mode = SCI_MODE_ARB; -/* regs->sci_mode |= SCI_MODE_ARB; XXX? */ - - /* AIP might not set if BSY went true after we checked */ - /* Wait up to about 100 usec. for it to appear. */ - arb_wait = 50; /* X2 */ - do { - if (regs->sci_icmd & SCI_ICMD_AIP) - goto got_aip; - delay2us(); - } while (--arb_wait > 0); - /* XXX - Could have missed it? */ -#ifdef DEBUG - if (si_debug) - printf("si_select_target: API did not appear\n"); -#endif - goto retry_arbitration; + /* Make sure our caller checked sc_min_dma_len. */ + if (xlen < MIN_DMA_LEN) + panic("si_dma_alloc: xlen=0x%x\n", xlen); - got_aip: -#ifdef DEBUG - if (si_debug & 4) { - printf("si_select_target: API after %d tries (last wait %d)\n", - ARBITRATION_RETRIES - arb_retries, - (50 - arb_wait)); + /* + * Never attempt single transfers of more than 63k, because + * our count register may be only 16 bits (an OBIO adapter). + * This should never happen since already bounded by minphys(). + * XXX - Should just segment these... + */ + if (xlen > MAX_DMA_LEN) { + printf("si_dma_alloc: excessive xlen=0x%x\n", xlen); + Debugger(); + ncr_sc->sc_datalen = xlen = MAX_DMA_LEN; } -#endif - delay(3); /* 2.2 uSec. arbitration delay */ - - if (regs->sci_icmd & SCI_ICMD_LST) { -#ifdef DEBUG - if (si_debug) - printf ("lost 1\n"); -#endif - goto retry_arbitration; /* XXX */ + /* Find free DMA handle. Guaranteed to find one since we have + as many DMA handles as the driver has processes. */ + for (i = 0; i < SCI_OPENINGS; i++) { + if ((sc->sc_dma[i].dh_flags & SIDH_BUSY) == 0) + goto found; } + panic("si: no free DMA handles."); +found: - regs->sci_mode &= ~SCI_MODE_PAR_CHK; - bid = regs->sci_data; - - if ((bid & ~myid) > myid) { -#ifdef DEBUG - if (si_debug) - printf ("lost 2\n"); -#endif - /* Trying again will not help. */ - goto lost; - } - if (regs->sci_icmd & SCI_ICMD_LST) { -#ifdef DEBUG - if (si_debug) - printf ("lost 3\n"); -#endif - goto lost; - } + dh = &sc->sc_dma[i]; + dh->dh_flags = SIDH_BUSY; + dh->dh_addr = (u_char*) addr; + dh->dh_maplen = xlen; + dh->dh_dvma = 0; - /* Won arbitration, enter selection phase now */ - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); - icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL); - regs->sci_icmd = icmd; + /* Copy the "write" flag for convenience. */ + if (xs->flags & SCSI_DATA_OUT) + dh->dh_flags |= SIDH_OUT; - if (regs->sci_icmd & SCI_ICMD_LST) { -#ifdef DEBUG - if (si_debug) - printf ("nosel\n"); +#if 0 + /* + * Some machines might not need to remap B_PHYS buffers. + * The sun3 does not map B_PHYS buffers into DVMA space, + * (they are mapped into normal KV space) so on the sun3 + * we must always remap to a DVMA address here. Re-map is + * cheap anyway, because it's done by segments, not pages. + */ + if (xs->bp && (xs->bp->b_flags & B_PHYS)) + dh->dh_flags |= SIDH_PHYS; #endif - goto nosel; - } - - /* XXX a target that violates specs might still drive the bus XXX */ - /* XXX should put our id out, and after the delay check nothi XXX */ - /* XXX ng else is out there. XXX */ - - delay2us(); - - regs->sci_sel_enb = 0; - - regs->sci_odata = myid | tid; - - icmd |= SCI_ICMD_BSY|SCI_ICMD_DATA; - regs->sci_icmd = icmd; - -/* regs->sci_mode &= ~SCI_MODE_ARB; 2 deskew delays, too */ - regs->sci_mode = 0; /* 2 deskew delays, too */ - - icmd &= ~SCI_ICMD_BSY; - regs->sci_icmd = icmd; - - /* bus settle delay, 400ns */ - delay2us(); /* too much (was 2) ? */ - regs->sci_mode |= SCI_MODE_PAR_CHK; - - { - register int timeo = 2500;/* 250 msecs in 100 usecs chunks */ - while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) { - if (--timeo > 0) { - delay(100); - } else { - /* This is the "normal" no-such-device select error. */ -#ifdef DEBUG - if (si_debug) - printf("si_select: not BSY (nothing there)\n"); -#endif - goto nodev; - } - } + dh->dh_dvma = (u_long) dvma_mapin((char *)addr, xlen); + if (!dh->dh_dvma) { + /* Can't remap segment */ + printf("si_dma_alloc: can't remap %x/%x\n", + dh->dh_addr, dh->dh_maplen); + dh->dh_flags = 0; + return; } - icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL); - regs->sci_icmd = icmd; -/* regs->sci_sel_enb = myid;*/ /* looks like we should NOT have it */ - /* XXX - SCI_MODE_PAR_CHK ? */ - return SCSI_RET_SUCCESS; - -nodev: - ret = SCSI_RET_DEVICE_DOWN; - regs->sci_sel_enb = myid; -nosel: - regs->sci_icmd = 0; - regs->sci_mode = 0; - return ret; - -lost: - regs->sci_icmd = 0; - regs->sci_mode = 0; -#ifdef DEBUG - if (si_debug) { - printf("si_select: lost arbitration\n"); - } -#endif - return ret; -} + /* success */ + sr->sr_dma_hand = dh; -sci_data_out(regs, phase, count, data) - register volatile sci_regmap_t *regs; - unsigned char *data; -{ - register unsigned char icmd; - register int cnt=0; - - /* ..checks.. */ - - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); -loop: - /* SCSI bus phase not valid until REQ is true. */ - WAIT_FOR_REQ(regs); - if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) - return cnt; - - icmd |= SCI_ICMD_DATA; - regs->sci_icmd = icmd; - regs->sci_odata = *data++; - icmd |= SCI_ICMD_ACK; - regs->sci_icmd = icmd; - - icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK); - WAIT_FOR_NOT_REQ(regs); - regs->sci_icmd = icmd; - ++cnt; - if (--count > 0) - goto loop; -scsi_timeout_error: - return cnt; + return; } -sci_data_in(regs, phase, count, data) - register volatile sci_regmap_t *regs; - unsigned char *data; -{ - register unsigned char icmd; - register int cnt=0; - - /* ..checks.. */ - - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); - -loop: - /* SCSI bus phase not valid until REQ is true. */ - WAIT_FOR_REQ(regs); - if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) - return cnt; - - *data++ = regs->sci_data; - icmd |= SCI_ICMD_ACK; - regs->sci_icmd = icmd; - icmd &= ~SCI_ICMD_ACK; - WAIT_FOR_NOT_REQ(regs); - regs->sci_icmd = icmd; - ++cnt; - if (--count > 0) - goto loop; - -scsi_timeout_error: - return cnt; -} - -/* Return -1 (error) or number of bytes sent (>=0). */ -static int -si_command_transfer(register volatile sci_regmap_t *regs, - int maxlen, u_char *data, u_char *status, u_char *msg) +void +si_dma_free(ncr_sc) + struct ncr5380_softc *ncr_sc; { - int xfer, phase; - - xfer = 0; - regs->sci_icmd = 0; - - while (1) { - - WAIT_FOR_REQ(regs); - - phase = SCI_CUR_PHASE(regs->sci_bus_csr); - - switch (phase) { - case SCSI_PHASE_CMD: - SCI_ACK(regs,SCSI_PHASE_CMD); - xfer += sci_data_out(regs, SCSI_PHASE_CMD, - maxlen, data); - goto out; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; - case SCSI_PHASE_DATA_IN: - printf("command_transfer: Data in phase?\n"); - goto err; - - case SCSI_PHASE_DATA_OUT: - printf("command_transfer: Data out phase?\n"); - goto err; - - case SCSI_PHASE_STATUS: - SCI_ACK(regs,SCSI_PHASE_STATUS); - printf("command_transfer: status in...\n"); - sci_data_in(regs, SCSI_PHASE_STATUS, - 1, status); - printf("command_transfer: status=0x%x\n", *status); - goto err; - - case SCSI_PHASE_MESSAGE_IN: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); - printf("command_transfer: msg in?\n"); - sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, - 1, msg); - break; +#ifdef DIAGNOSTIC + if (dh == NULL) + panic("si_dma_free: no DMA handle"); +#endif - case SCSI_PHASE_MESSAGE_OUT: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); - sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, - 1, msg); - break; + if (ncr_sc->sc_state & NCR_DOINGDMA) + panic("si_dma_free: free while in progress"); - default: - printf("command_transfer: Unexpected phase 0x%x\n", phase); - goto err; - } + if (dh->dh_flags & SIDH_BUSY) { + /* XXX - Should separate allocation and mapping. */ + /* Give back the DVMA space. */ + dvma_mapout((caddr_t)dh->dh_dvma, dh->dh_maplen); + dh->dh_dvma = 0; + dh->dh_flags = 0; } -scsi_timeout_error: - err: - xfer = -1; - out: - return xfer; + sr->sr_dma_hand = NULL; } -static int -si_data_transfer(register volatile sci_regmap_t *regs, - int maxlen, u_char *data, u_char *status, u_char *msg) -{ - int retlen = 0, xfer, phase; - - regs->sci_icmd = 0; - - *status = 0; - - while (1) { - - WAIT_FOR_REQ(regs); - - phase = SCI_CUR_PHASE(regs->sci_bus_csr); - - switch (phase) { - case SCSI_PHASE_CMD: - printf("Command phase in data_transfer().\n"); - return retlen; - case SCSI_PHASE_DATA_IN: - SCI_ACK(regs,SCSI_PHASE_DATA_IN); -#if PSEUDO_DMA - xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN, - maxlen, data); -#else - xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN, - maxlen, data); -#endif - retlen += xfer; - maxlen -= xfer; - break; - case SCSI_PHASE_DATA_OUT: - SCI_ACK(regs,SCSI_PHASE_DATA_OUT); -#if PSEUDO_DMA - xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT, - maxlen, data); -#else - xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT, - maxlen, data); -#endif - retlen += xfer; - maxlen -= xfer; - break; - case SCSI_PHASE_STATUS: - SCI_ACK(regs,SCSI_PHASE_STATUS); - sci_data_in(regs, SCSI_PHASE_STATUS, - 1, status); - break; - case SCSI_PHASE_MESSAGE_IN: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); - sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, - 1, msg); - if (*msg == 0) { - return retlen; - } else { - printf( "message 0x%x in " - "data_transfer.\n", *msg); - } - break; - case SCSI_PHASE_MESSAGE_OUT: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); - sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, - 1, msg); - break; - default: - printf( "Unexpected phase 0x%x in " - "data_transfer().\n", phase); -scsi_timeout_error: - return retlen; - break; - } - } -} -static int -si_dorequest(struct ncr5380_softc *sc, - int target, int lun, u_char *cmd, int cmdlen, - char *databuf, int datalen, int *sent) - /* Returns 0 on success, -1 on internal error, or the status byte */ +/* + * Poll (spin-wait) for DMA completion. + * Called right after xx_dma_start(), and + * xx_dma_stop() will be called next. + * Same for either VME or OBIO. + */ +void +si_dma_poll(ncr_sc) + struct ncr5380_softc *ncr_sc; { - register volatile sci_regmap_t *regs = sc->sc_regs; - int cmd_bytes_sent, r; - u_char stat, msg, c; - -#ifdef DEBUG - if (si_debug) { - printf("si_dorequest: target=%d, lun=%d\n", target, lun); - } -#endif - - *sent = 0; + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; + volatile struct si_regs *si = sc->sc_regs; + int tmo, csr_mask; - if ( ( r = si_select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) { -#ifdef DEBUG - if (si_debug) { - printf("si_dorequest: select returned %d\n", r); - } -#endif + /* Make sure DMA started successfully. */ + if (ncr_sc->sc_state & NCR_ABORTING) + return; - SCI_CLR_INTR(regs); - switch (r) { - - case SCSI_RET_NEED_RESET: - printf("si_dorequest: target=%d, lun=%d, resetting...\n", - target, lun, r); - ncr5380_reset_adapter(sc); - ncr5380_reset_scsibus(sc); - /* fall through */ - case SCSI_RET_RETRY: - return 0x08; /* Busy - tell common code to retry. */ - - default: - printf("si_dorequest: target=%d, lun=%d, error=%d.\n", - target, lun, r); - /* fall through */ - case SCSI_RET_DEVICE_DOWN: - return -1; /* Dead - tell common code to give up. */ - } + csr_mask = SI_CSR_SBC_IP | SI_CSR_DMA_IP | + SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR; + + tmo = 50000; /* X100 = 5 sec. */ + for (;;) { + if (si->si_csr & csr_mask) + break; + if (--tmo <= 0) { + printf("si: DMA timeout (while polling)\n"); + /* Indicate timeout as MI code would. */ + sr->sr_flags |= SR_OVERDUE; + break; } - - c = 0x80 | lun; - - if ((cmd_bytes_sent = si_command_transfer(regs, cmdlen, - (u_char *) cmd, &stat, &c)) != cmdlen) - { - SCI_CLR_INTR(regs); - if (cmd_bytes_sent >= 0) { - printf("Data underrun sending CCB (%d bytes of %d, sent).\n", - cmd_bytes_sent, cmdlen); - } - return -1; + delay(100); } - *sent = si_data_transfer(regs, datalen, (u_char *)databuf, - &stat, &msg); #ifdef DEBUG if (si_debug) { - printf("si_dorequest: data transfered = %d\n", *sent); + printf("si_dma_poll: done, csr=0x%x\n", si->si_csr); } #endif - - return stat; } -static int -si_generic(int adapter, int id, int lun, struct scsi_generic *cmd, - int cmdlen, void *databuf, int datalen) -{ - register struct ncr5380_softc *sc = sicd.cd_devs[adapter]; - int i, j, sent; - - if (cmd->opcode == TEST_UNIT_READY) /* XXX */ - cmd->bytes[0] = ((u_char) lun << 5); - - i = si_dorequest(sc, id, lun, (u_char *) cmd, cmdlen, - databuf, datalen, &sent); - - return i; -} - -static int -si_group0(int adapter, int id, int lun, int opcode, int addr, int len, - int flags, caddr_t databuf, int datalen) -{ - register struct ncr5380_softc *sc = sicd.cd_devs[adapter]; - unsigned char cmd[6]; - int i, j, sent; - - cmd[0] = opcode; /* Operation code */ - cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F); /* Lun & MSB of addr */ - cmd[2] = (addr >> 8) & 0xFF; /* addr */ - cmd[3] = addr & 0xFF; /* LSB of addr */ - cmd[4] = len; /* Allocation length */ - cmd[5] = flags; /* Link/Flag */ - - i = si_dorequest(sc, id, lun, cmd, 6, databuf, datalen, &sent); - - return i; -} diff --git a/sys/arch/sun3/dev/si_obio.c b/sys/arch/sun3/dev/si_obio.c new file mode 100644 index 00000000000..b808b030874 --- /dev/null +++ b/sys/arch/sun3/dev/si_obio.c @@ -0,0 +1,580 @@ +/* $NetBSD: si_obio.c,v 1.1 1996/03/26 15:01:12 gwr Exp $ */ + +/* + * Copyright (c) 1995 David Jones, Gordon W. Ross + * Copyright (c) 1994 Adam Glass + * 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. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Adam Glass, David Jones, and Gordon Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * This file contains only the machine-dependent parts of the + * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) + * The machine-independent parts are in ncr5380sbc.c + * + * Supported hardware includes: + * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) + * Sun SCSI-3 on VME (Sun3/160,Sun3/260) + * + * Could be made to support the Sun3/E if someone wanted to. + * + * Note: Both supported variants of the Sun SCSI-3 adapter have + * some really unusual "features" for this driver to deal with, + * generally related to the DMA engine. The OBIO variant will + * ignore any attempt to write the FIFO count register while the + * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with + * by setting the FIFO count early in COMMAND or MSG_IN phase. + * + * The VME variant has a bit to enable or disable the DMA engine, + * but that bit also gates the interrupt line from the NCR5380! + * Therefore, in order to get any interrupt from the 5380, (i.e. + * for reselect) one must clear the DMA engine transfer count and + * then enable DMA. This has the further complication that you + * CAN NOT touch the NCR5380 while the DMA enable bit is set, so + * we have to turn DMA back off before we even look at the 5380. + * + * What wonderfully whacky hardware this is! + * + * Credits, history: + * + * David Jones wrote the initial version of this module, which + * included support for the VME adapter only. (no reselection). + * + * Gordon Ross added support for the OBIO adapter, and re-worked + * both the VME and OBIO code to support disconnect/reselect. + * (Required figuring out the hardware "features" noted above.) + * + * The autoconfiguration boilerplate came from Adam Glass. + */ + +/***************************************************************** + * OBIO functions for DMA + ****************************************************************/ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_debug.h> +#include <scsi/scsiconf.h> + +#include <machine/autoconf.h> +#include <machine/isr.h> +#include <machine/obio.h> +#include <machine/dvma.h> + +#define DEBUG XXX + +#include <dev/ic/ncr5380reg.h> +#include <dev/ic/ncr5380var.h> + +#include "sireg.h" +#include "sivar.h" +#include "am9516.h" + +/* + * How many uS. to delay after touching the am9516 UDC. + */ +#define UDC_WAIT_USEC 5 + +void si_obio_dma_setup __P((struct ncr5380_softc *)); +void si_obio_dma_start __P((struct ncr5380_softc *)); +void si_obio_dma_eop __P((struct ncr5380_softc *)); +void si_obio_dma_stop __P((struct ncr5380_softc *)); + +/* + * New-style autoconfig attachment + */ + +static int si_obio_match __P((struct device *, void *, void *)); +static void si_obio_attach __P((struct device *, struct device *, void *)); + +struct cfattach si_obio_ca = { + sizeof(struct si_softc), si_obio_match, si_obio_attach +}; + +/* Options. Interesting values are: 1,3,7 */ +int si_obio_options = 3; +#define SI_ENABLE_DMA 1 /* Use DMA (maybe polled) */ +#define SI_DMA_INTR 2 /* DMA completion interrupts */ +#define SI_DO_RESELECT 4 /* Allow disconnect/reselect */ + + +static int +si_obio_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + int pa, x; + +#ifdef DIAGNOSTIC + if (ca->ca_bustype != BUS_OBIO) { + printf("si_obio_match: bustype %d?\n", ca->ca_bustype); + return (0); + } +#endif + + /* + * OBIO match functions may be called for every possible + * physical address, so match only our physical address. + */ + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_NCR_SCSI; + } + if (pa != ca->ca_paddr) + return (0); + +#if 0 + if ((cpu_machine_id != SUN3_MACH_50) && + (cpu_machine_id != SUN3_MACH_60) ) + { + /* Only 3/50 and 3/60 have the obio si. */ + return (0); + } +#endif + + /* Make sure there is something there... */ + x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1); + return (x != -1); +} + +static void +si_obio_attach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct si_softc *sc = (struct si_softc *) self; + struct ncr5380_softc *ncr_sc = &sc->ncr_sc; + struct cfdata *cf = self->dv_cfdata; + struct confargs *ca = args; + int intpri; + + /* Default interrupt level. */ + if ((intpri = cf->cf_intpri) == -1) + intpri = 2; + printf(" level %d", intpri); + + /* XXX: Get options from flags... */ + printf(" : options=%d\n", si_obio_options); + + ncr_sc->sc_flags = 0; + if (si_obio_options & SI_DO_RESELECT) + ncr_sc->sc_flags |= NCR5380_PERMIT_RESELECT; + if ((si_obio_options & SI_DMA_INTR) == 0) + ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; + + sc->sc_adapter_type = ca->ca_bustype; + sc->sc_regs = (struct si_regs *) + obio_alloc(ca->ca_paddr, sizeof(struct si_regs)); + + /* + * MD function pointers used by the MI code. + */ + ncr_sc->sc_pio_out = ncr5380_pio_out; + ncr_sc->sc_pio_in = ncr5380_pio_in; + + ncr_sc->sc_dma_alloc = si_dma_alloc; + ncr_sc->sc_dma_free = si_dma_free; + ncr_sc->sc_dma_poll = si_dma_poll; + + ncr_sc->sc_dma_setup = si_obio_dma_setup; + ncr_sc->sc_dma_start = si_obio_dma_start; + ncr_sc->sc_dma_eop = si_obio_dma_stop; + ncr_sc->sc_dma_stop = si_obio_dma_stop; + ncr_sc->sc_intr_on = NULL; + ncr_sc->sc_intr_off = NULL; + + ncr_sc->sc_min_dma_len = MIN_DMA_LEN; + +#if 1 /* XXX - Temporary */ + /* XXX - In case we think DMA is completely broken... */ + if ((si_obio_options & SI_ENABLE_DMA) == 0) { + /* Override this function pointer. */ + ncr_sc->sc_dma_alloc = NULL; + } +#endif + + /* Need DVMA-capable memory for the UDC command block. */ + sc->sc_dmacmd = dvma_malloc(sizeof (struct udc_table)); + + /* Attach interrupt handler. */ + isr_add_autovect(si_intr, (void *)sc, intpri); + + /* Do the common attach stuff. */ + si_attach(sc); +} + + +static __inline__ void +si_obio_udc_write(si, regnum, value) + volatile struct si_regs *si; + int regnum, value; +{ + si->udc_addr = regnum; + delay(UDC_WAIT_USEC); + si->udc_data = value; + delay(UDC_WAIT_USEC); +} + +static __inline__ int +si_obio_udc_read(si, regnum) + volatile struct si_regs *si; + int regnum; +{ + int value; + + si->udc_addr = regnum; + delay(UDC_WAIT_USEC); + value = si->udc_data; + delay(UDC_WAIT_USEC); + + return (value); +} + + +/* + * This function is called during the COMMAND or MSG_IN phase + * that preceeds a DATA_IN or DATA_OUT phase, in case we need + * to setup the DMA engine before the bus enters a DATA phase. + * + * The OBIO "si" IGNORES any attempt to set the FIFO count + * register after the SCSI bus goes into any DATA phase, so + * this function has to setup the evil FIFO logic. + */ +void +si_obio_dma_setup(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + volatile struct si_regs *si = sc->sc_regs; + struct sci_req *sr; + struct si_dma_handle *dh; + int send = 0; + int xlen = 0; + + /* Let this work even without a dma hand, for testing... */ + if ((sr = ncr_sc->sc_current) != NULL) { + if ((dh = sr->sr_dma_hand) != NULL) { + send = dh->dh_flags & SIDH_OUT; + xlen = ncr_sc->sc_datalen; + xlen &= ~1; + } + } + +#ifdef DEBUG + if (si_debug) { + printf("si_dma_setup: send=%d xlen=%d\n", send, xlen); + } +#endif + + /* Reset the UDC. (In case not already reset?) */ + si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); + + /* Reset the FIFO */ + si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ + si->si_csr |= SI_CSR_FIFO_RES; + + /* Set direction (send/recv) */ + if (send) { + si->si_csr |= SI_CSR_SEND; + } else { + si->si_csr &= ~SI_CSR_SEND; + } + + /* Set the FIFO counter. */ + si->fifo_count = xlen; + + /* + * XXX: Reset DMA engine again! Comment from Sprite: + * Go through reset again becuase of the bug on the 3/50 + * where bytes occasionally linger in the DMA fifo. + */ + + /* Reset the UDC. */ + si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); + + /* Reset the FIFO */ + si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ + si->si_csr |= SI_CSR_FIFO_RES; + +#ifdef DEBUG + if ((si->fifo_count > xlen) || (si->fifo_count < (xlen - 1))) { + printf("si_dma_setup: fifo_count=0x%x, xlen=0x%x\n", + si->fifo_count, xlen); + Debugger(); + } +#endif +} + + +void +si_obio_dma_start(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; + volatile struct si_regs *si = sc->sc_regs; + struct udc_table *cmd; + long data_pa, cmd_pa; + int xlen; + + /* + * Get the DVMA mapping for this segment. + * XXX - Should separate allocation and mapin. + */ + data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type); + data_pa += (ncr_sc->sc_dataptr - dh->dh_addr); + if (data_pa & 1) + panic("si_dma_start: bad pa=0x%x", data_pa); + xlen = ncr_sc->sc_datalen; + xlen &= ~1; + sc->sc_reqlen = xlen; /* XXX: or less... */ + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", + dh, data_pa, xlen); + } +#endif + + /* + * Set up the DMA controller. + * Already set FIFO count in dma_setup. + */ + +#ifdef DEBUG + if ((si->fifo_count > xlen) || + (si->fifo_count < (xlen - 1))) + { + printf("si_dma_start: fifo_count=0x%x, xlen=0x%x\n", + si->fifo_count, xlen); + Debugger(); + } +#endif + + /* + * The OBIO controller needs a command block. + */ + cmd = sc->sc_dmacmd; + cmd->addrh = ((data_pa & 0xFF0000) >> 8) | UDC_ADDR_INFO; + cmd->addrl = data_pa & 0xFFFF; + cmd->count = xlen / 2; /* bytes -> words */ + cmd->cmrh = UDC_CMR_HIGH; + if (dh->dh_flags & SIDH_OUT) { + cmd->cmrl = UDC_CMR_LSEND; + cmd->rsel = UDC_RSEL_SEND; + } else { + cmd->cmrl = UDC_CMR_LRECV; + cmd->rsel = UDC_RSEL_RECV; + } + + /* Tell the DMA chip where the control block is. */ + cmd_pa = dvma_kvtopa((long)cmd, BUS_OBIO); + si_obio_udc_write(si, UDC_ADR_CAR_HIGH, + (cmd_pa & 0xff0000) >> 8); + si_obio_udc_write(si, UDC_ADR_CAR_LOW, + (cmd_pa & 0xffff)); + + /* Tell the chip to be a DMA master. */ + si_obio_udc_write(si, UDC_ADR_MODE, UDC_MODE); + + /* Tell the chip to interrupt on error. */ + si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_CIE); + + /* XXX: Move all of the above to _setup? */ + + /* Finally, give the UDC a "start chain" command. */ + si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_STRT_CHN); + + /* + * Acknowledge the phase change. (After DMA setup!) + * Put the SBIC into DMA mode, and start the transfer. + */ + if (dh->dh_flags & SIDH_OUT) { + *ncr_sc->sci_tcmd = PHASE_DATA_OUT; + SCI_CLR_INTR(ncr_sc); + *ncr_sc->sci_icmd = SCI_ICMD_DATA; + *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_dma_send = 0; /* start it */ + } else { + *ncr_sc->sci_tcmd = PHASE_DATA_IN; + SCI_CLR_INTR(ncr_sc); + *ncr_sc->sci_icmd = 0; + *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_irecv = 0; /* start it */ + } + + ncr_sc->sc_state |= NCR_DOINGDMA; + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_start: started, flags=0x%x\n", + ncr_sc->sc_state); + } +#endif +} + + +void +si_obio_dma_eop(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + + /* Not needed - DMA was stopped prior to examining sci_csr */ +} + + +void +si_obio_dma_stop(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; + volatile struct si_regs *si = sc->sc_regs; + int resid, ntrans, tmo, udc_cnt; + + if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { +#ifdef DEBUG + printf("si_dma_stop: dma not running\n"); +#endif + return; + } + ncr_sc->sc_state &= ~NCR_DOINGDMA; + + if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { + printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); + sr->sr_xs->error = XS_DRIVER_STUFFUP; + ncr_sc->sc_state |= NCR_ABORTING; + si_reset_adapter(ncr_sc); + } + + /* Note that timeout may have set the error flag. */ + if (ncr_sc->sc_state & NCR_ABORTING) + goto out; + + /* + * After a read, wait for the FIFO to empty. + * Note: this only works on the OBIO version. + */ + if ((dh->dh_flags & SIDH_OUT) == 0) { + tmo = 200000; /* X10 = 2 sec. */ + for (;;) { + if (si->si_csr & SI_CSR_FIFO_EMPTY) + break; + if (--tmo <= 0) { + printf("si: dma fifo did not empty, reset\n"); + ncr_sc->sc_state |= NCR_ABORTING; + /* si_reset_adapter(ncr_sc); */ + goto out; + } + delay(10); + } + } + + /* + * Now try to figure out how much actually transferred + * + * The fifo_count might not reflect how many bytes were + * actually transferred for VME. + */ + + resid = si->fifo_count & 0xFFFF; + ntrans = sc->sc_reqlen - resid; + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_stop: resid=0x%x ntrans=0x%x\n", + resid, ntrans); + } +#endif + + /* XXX: Treat (ntrans==0) as a special, non-error case? */ + if (ntrans < MIN_DMA_LEN) { + printf("si: fifo count: 0x%x\n", resid); + ncr_sc->sc_state |= NCR_ABORTING; + goto out; + } + if (ntrans > ncr_sc->sc_datalen) + panic("si_dma_stop: excess transfer"); + + /* Adjust data pointer */ + ncr_sc->sc_dataptr += ntrans; + ncr_sc->sc_datalen -= ntrans; + + /* + * After a read, we may need to clean-up + * "Left-over bytes" (yuck!) + */ + if ((dh->dh_flags & SIDH_OUT) == 0) { + /* If odd transfer count, grab last byte by hand. */ + if (ntrans & 1) { + NCR_TRACE("si_dma_stop: leftover 1 at 0x%x\n", + (int) ncr_sc->sc_dataptr - 1); + ncr_sc->sc_dataptr[-1] = + (si->fifo_data & 0xff00) >> 8; + goto out; + } + /* UDC might not have transfered the last word. */ + udc_cnt = si_obio_udc_read(si, UDC_ADR_COUNT); + if (((udc_cnt * 2) - resid) == 2) { + NCR_TRACE("si_dma_stop: leftover 2 at 0x%x\n", + (int) ncr_sc->sc_dataptr - 2); + ncr_sc->sc_dataptr[-2] = + (si->fifo_data & 0xff00) >> 8; + ncr_sc->sc_dataptr[-1] = + (si->fifo_data & 0x00ff); + } + } + +out: + /* Reset the UDC. */ + si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); + si->fifo_count = 0; + si->si_csr &= ~SI_CSR_SEND; + + /* Reset the FIFO */ + si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ + si->si_csr |= SI_CSR_FIFO_RES; + + /* Put SBIC back in PIO mode. */ + *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_icmd = 0; +} + diff --git a/sys/arch/sun3/dev/si_vme.c b/sys/arch/sun3/dev/si_vme.c new file mode 100644 index 00000000000..637f8932bcd --- /dev/null +++ b/sys/arch/sun3/dev/si_vme.c @@ -0,0 +1,558 @@ +/* $NetBSD: si_vme.c,v 1.1 1996/03/26 15:01:13 gwr Exp $ */ + +/* + * Copyright (c) 1995 David Jones, Gordon W. Ross + * Copyright (c) 1994 Adam Glass + * 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. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Adam Glass, David Jones, and Gordon Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * This file contains only the machine-dependent parts of the + * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) + * The machine-independent parts are in ncr5380sbc.c + * + * Supported hardware includes: + * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) + * Sun SCSI-3 on VME (Sun3/160,Sun3/260) + * + * Could be made to support the Sun3/E if someone wanted to. + * + * Note: Both supported variants of the Sun SCSI-3 adapter have + * some really unusual "features" for this driver to deal with, + * generally related to the DMA engine. The OBIO variant will + * ignore any attempt to write the FIFO count register while the + * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with + * by setting the FIFO count early in COMMAND or MSG_IN phase. + * + * The VME variant has a bit to enable or disable the DMA engine, + * but that bit also gates the interrupt line from the NCR5380! + * Therefore, in order to get any interrupt from the 5380, (i.e. + * for reselect) one must clear the DMA engine transfer count and + * then enable DMA. This has the further complication that you + * CAN NOT touch the NCR5380 while the DMA enable bit is set, so + * we have to turn DMA back off before we even look at the 5380. + * + * What wonderfully whacky hardware this is! + * + * Credits, history: + * + * David Jones wrote the initial version of this module, which + * included support for the VME adapter only. (no reselection). + * + * Gordon Ross added support for the OBIO adapter, and re-worked + * both the VME and OBIO code to support disconnect/reselect. + * (Required figuring out the hardware "features" noted above.) + * + * The autoconfiguration boilerplate came from Adam Glass. + */ + +/***************************************************************** + * VME functions for DMA + ****************************************************************/ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_debug.h> +#include <scsi/scsiconf.h> + +#include <machine/autoconf.h> +#include <machine/isr.h> +#include <machine/obio.h> +#include <machine/dvma.h> + +#define DEBUG XXX + +#include <dev/ic/ncr5380reg.h> +#include <dev/ic/ncr5380var.h> + +#include "sireg.h" +#include "sivar.h" + +/* + * Transfers smaller than this are done using PIO + * (on assumption they're not worth DMA overhead) + */ +#define MIN_DMA_LEN 128 + +void si_vme_dma_setup __P((struct ncr5380_softc *)); +void si_vme_dma_start __P((struct ncr5380_softc *)); +void si_vme_dma_eop __P((struct ncr5380_softc *)); +void si_vme_dma_stop __P((struct ncr5380_softc *)); + +void si_vme_intr_on __P((struct ncr5380_softc *)); +void si_vme_intr_off __P((struct ncr5380_softc *)); + +/* + * New-style autoconfig attachment + */ + +static int si_vmes_match __P((struct device *, void *, void *)); +static void si_vmes_attach __P((struct device *, struct device *, void *)); + +struct cfattach si_vmes_ca = { + sizeof(struct si_softc), si_vmes_match, si_vmes_attach +}; + +/* Options. Interesting values are: 1,3,7 */ +int si_vme_options = 3; +#define SI_ENABLE_DMA 1 /* Use DMA (maybe polled) */ +#define SI_DMA_INTR 2 /* DMA completion interrupts */ +#define SI_DO_RESELECT 4 /* Allow disconnect/reselect */ + + +static int +si_vmes_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + int x, probe_addr; + +#ifdef DIAGNOSTIC + if (ca->ca_bustype != BUS_VME16) { + printf("si_vmes_match: bustype %d?\n", ca->ca_bustype); + return (0); + } +#endif + + if ((cpu_machine_id == SUN3_MACH_50) || + (cpu_machine_id == SUN3_MACH_60) ) + { + /* Sun3/50 or Sun3/60 do not have VME. */ + return(0); + } + + /* + * Other Sun3 models may have VME "si" or "sc". + * This driver has no default address. + */ + if (ca->ca_paddr == -1) + return (0); + + /* Default interrupt priority always splbio==2 */ + if (ca->ca_intpri == -1) + ca->ca_intpri = 2; + + /* Make sure there is something there... */ + x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1); + if (x == -1) + return (0); + + /* + * If this is a VME SCSI board, we have to determine whether + * it is an "sc" (Sun2) or "si" (Sun3) SCSI board. This can + * be determined using the fact that the "sc" board occupies + * 4K bytes in VME space but the "si" board occupies 2K bytes. + */ + /* Note: the "si" board should NOT respond here. */ + x = bus_peek(ca->ca_bustype, ca->ca_paddr + 0x801, 1); + if (x != -1) { + /* Something responded at 2K+1. Maybe an "sc" board? */ +#ifdef DEBUG + printf("si_vmes_match: May be an `sc' board at pa=0x%x\n", + ca->ca_paddr); +#endif + return(0); + } + + return (1); +} + + +static void +si_vmes_attach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct si_softc *sc = (struct si_softc *) self; + struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *)sc; + struct confargs *ca = args; + int s; + + /* XXX: Get options from flags... */ + printf(" : options=%d\n", si_vme_options); + + ncr_sc->sc_flags = 0; + if (si_vme_options & SI_DO_RESELECT) + ncr_sc->sc_flags |= NCR5380_PERMIT_RESELECT; + if ((si_vme_options & SI_DMA_INTR) == 0) + ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; + + sc->sc_adapter_type = ca->ca_bustype; + sc->sc_adapter_iv_am = + VME_SUPV_DATA_24 | (ca->ca_intvec & 0xFF); + + sc->sc_regs = (struct si_regs *) + bus_mapin(ca->ca_bustype, ca->ca_paddr, + sizeof(struct si_regs)); + + /* + * MD function pointers used by the MI code. + */ + ncr_sc->sc_pio_out = ncr5380_pio_out; + ncr_sc->sc_pio_in = ncr5380_pio_in; + + ncr_sc->sc_dma_alloc = si_dma_alloc; + ncr_sc->sc_dma_free = si_dma_free; + ncr_sc->sc_dma_poll = si_dma_poll; + + ncr_sc->sc_dma_setup = si_vme_dma_setup; + ncr_sc->sc_dma_start = si_vme_dma_start; + ncr_sc->sc_dma_eop = si_vme_dma_stop; + ncr_sc->sc_dma_stop = si_vme_dma_stop; + ncr_sc->sc_intr_on = si_vme_intr_on; + ncr_sc->sc_intr_off = si_vme_intr_off; + + ncr_sc->sc_min_dma_len = MIN_DMA_LEN; + +#if 1 /* XXX - Temporary */ + /* XXX - In case we think DMA is completely broken... */ + if ((si_vme_options & SI_ENABLE_DMA) == 0) { + /* Override this function pointer. */ + ncr_sc->sc_dma_alloc = NULL; + } +#endif + + /* Attach interrupt handler. */ + isr_add_vectored(si_intr, (void *)sc, + ca->ca_intpri, ca->ca_intvec); + + /* Do the common attach stuff. */ + si_attach(sc); +} + + +/* + * This is called when the bus is going idle, + * so we want to enable the SBC interrupts. + * That is controlled by the DMA enable! + * Who would have guessed! + * What a NASTY trick! + */ +void +si_vme_intr_on(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + volatile struct si_regs *si = sc->sc_regs; + + si_vme_dma_setup(ncr_sc); + si->si_csr |= SI_CSR_DMA_EN; +} + +/* + * This is called when the bus is idle and we are + * about to start playing with the SBC chip. + */ +void +si_vme_intr_off(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + volatile struct si_regs *si = sc->sc_regs; + + si->si_csr &= ~SI_CSR_DMA_EN; +} + +/* + * This function is called during the COMMAND or MSG_IN phase + * that preceeds a DATA_IN or DATA_OUT phase, in case we need + * to setup the DMA engine before the bus enters a DATA phase. + * + * XXX: The VME adapter appears to suppress SBC interrupts + * when the FIFO is not empty or the FIFO count is non-zero! + * + * On the VME version we just clear the DMA count and address + * here (to make sure it stays idle) and do the real setup + * later, in dma_start. + */ +void +si_vme_dma_setup(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + volatile struct si_regs *si = sc->sc_regs; + + /* Reset the FIFO */ + si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ + si->si_csr |= SI_CSR_FIFO_RES; + + /* Set direction (assume recv here) */ + si->si_csr &= ~SI_CSR_SEND; + /* Assume worst alignment */ + si->si_csr |= SI_CSR_BPCON; + + si->dma_addrh = 0; + si->dma_addrl = 0; + + si->dma_counth = 0; + si->dma_countl = 0; + + /* Clear FIFO counter. (also hits dma_count) */ + si->fifo_cnt_hi = 0; + si->fifo_count = 0; +} + + +void +si_vme_dma_start(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; + volatile struct si_regs *si = sc->sc_regs; + long data_pa; + int xlen; + + /* + * Get the DVMA mapping for this segment. + * XXX - Should separate allocation and mapin. + */ + data_pa = dvma_kvtopa(dh->dh_dvma, sc->sc_adapter_type); + data_pa += (ncr_sc->sc_dataptr - dh->dh_addr); + if (data_pa & 1) + panic("si_dma_start: bad pa=0x%x", data_pa); + xlen = ncr_sc->sc_datalen; + xlen &= ~1; + sc->sc_reqlen = xlen; /* XXX: or less... */ + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", + dh, data_pa, xlen); + } +#endif + + /* + * Set up the DMA controller. + */ + si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ + si->si_csr |= SI_CSR_FIFO_RES; + + /* Set direction (send/recv) */ + if (dh->dh_flags & SIDH_OUT) { + si->si_csr |= SI_CSR_SEND; + } else { + si->si_csr &= ~SI_CSR_SEND; + } + + if (data_pa & 2) { + si->si_csr |= SI_CSR_BPCON; + } else { + si->si_csr &= ~SI_CSR_BPCON; + } + + si->dma_addrh = (ushort)(data_pa >> 16); + si->dma_addrl = (ushort)(data_pa & 0xFFFF); + + si->dma_counth = (ushort)(xlen >> 16); + si->dma_countl = (ushort)(xlen & 0xFFFF); + +#if 1 + /* Set it anyway, even though dma_count hits it? */ + si->fifo_cnt_hi = (ushort)(xlen >> 16); + si->fifo_count = (ushort)(xlen & 0xFFFF); +#endif + +#ifdef DEBUG + if (si->fifo_count != xlen) { + printf("si_dma_start: fifo_count=0x%x, xlen=0x%x\n", + si->fifo_count, xlen); + Debugger(); + } +#endif + + /* + * Acknowledge the phase change. (After DMA setup!) + * Put the SBIC into DMA mode, and start the transfer. + */ + if (dh->dh_flags & SIDH_OUT) { + *ncr_sc->sci_tcmd = PHASE_DATA_OUT; + SCI_CLR_INTR(ncr_sc); + *ncr_sc->sci_icmd = SCI_ICMD_DATA; + *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_dma_send = 0; /* start it */ + } else { + *ncr_sc->sci_tcmd = PHASE_DATA_IN; + SCI_CLR_INTR(ncr_sc); + *ncr_sc->sci_icmd = 0; + *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_irecv = 0; /* start it */ + } + + /* Let'er rip! */ + si->si_csr |= SI_CSR_DMA_EN; + + ncr_sc->sc_state |= NCR_DOINGDMA; + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_start: started, flags=0x%x\n", + ncr_sc->sc_state); + } +#endif +} + + +void +si_vme_dma_eop(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + + /* Not needed - DMA was stopped prior to examining sci_csr */ +} + + +void +si_vme_dma_stop(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + struct si_softc *sc = (struct si_softc *)ncr_sc; + struct sci_req *sr = ncr_sc->sc_current; + struct si_dma_handle *dh = sr->sr_dma_hand; + volatile struct si_regs *si = sc->sc_regs; + int resid, ntrans; + + if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { +#ifdef DEBUG + printf("si_dma_stop: dma not running\n"); +#endif + return; + } + ncr_sc->sc_state &= ~NCR_DOINGDMA; + + /* First, halt the DMA engine. */ + si->si_csr &= ~SI_CSR_DMA_EN; /* VME only */ + + if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { + printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); + sr->sr_xs->error = XS_DRIVER_STUFFUP; + ncr_sc->sc_state |= NCR_ABORTING; + si_reset_adapter(ncr_sc); + } + + /* Note that timeout may have set the error flag. */ + if (ncr_sc->sc_state & NCR_ABORTING) + goto out; + + /* + * Now try to figure out how much actually transferred + * + * The fifo_count does not reflect how many bytes were + * actually transferred for VME. + * + * SCSI-3 VME interface is a little funny on writes: + * if we have a disconnect, the dma has overshot by + * one byte and the resid needs to be incremented. + * Only happens for partial transfers. + * (Thanks to Matt Jacob) + */ + + resid = si->fifo_count & 0xFFFF; + if (dh->dh_flags & SIDH_OUT) + if ((resid > 0) && (resid < sc->sc_reqlen)) + resid++; + ntrans = sc->sc_reqlen - resid; + +#ifdef DEBUG + if (si_debug & 2) { + printf("si_dma_stop: resid=0x%x ntrans=0x%x\n", + resid, ntrans); + } +#endif + + if (ntrans < MIN_DMA_LEN) { + printf("si: fifo count: 0x%x\n", resid); + ncr_sc->sc_state |= NCR_ABORTING; + goto out; + } + if (ntrans > ncr_sc->sc_datalen) + panic("si_dma_stop: excess transfer"); + + /* Adjust data pointer */ + ncr_sc->sc_dataptr += ntrans; + ncr_sc->sc_datalen -= ntrans; + + /* + * After a read, we may need to clean-up + * "Left-over bytes" (yuck!) + */ + if (((dh->dh_flags & SIDH_OUT) == 0) && + ((si->si_csr & SI_CSR_LOB) != 0)) + { + char *cp = ncr_sc->sc_dataptr; +#ifdef DEBUG + printf("si: Got Left-over bytes!\n"); +#endif + if (si->si_csr & SI_CSR_BPCON) { + /* have SI_CSR_BPCON */ + cp[-1] = (si->si_bprl & 0xff00) >> 8; + } else { + switch (si->si_csr & SI_CSR_LOB) { + case SI_CSR_LOB_THREE: + cp[-3] = (si->si_bprh & 0xff00) >> 8; + cp[-2] = (si->si_bprh & 0x00ff); + cp[-1] = (si->si_bprl & 0xff00) >> 8; + break; + case SI_CSR_LOB_TWO: + cp[-2] = (si->si_bprh & 0xff00) >> 8; + cp[-1] = (si->si_bprh & 0x00ff); + break; + case SI_CSR_LOB_ONE: + cp[-1] = (si->si_bprh & 0xff00) >> 8; + break; + } + } + } + +out: + si->dma_addrh = 0; + si->dma_addrl = 0; + + si->dma_counth = 0; + si->dma_countl = 0; + + si->fifo_cnt_hi = 0; + si->fifo_count = 0; + + /* Put SBIC back in PIO mode. */ + *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); + *ncr_sc->sci_icmd = 0; +} diff --git a/sys/arch/sun3/dev/sireg.h b/sys/arch/sun3/dev/sireg.h new file mode 100644 index 00000000000..2cf847f69c2 --- /dev/null +++ b/sys/arch/sun3/dev/sireg.h @@ -0,0 +1,103 @@ +/* $NetBSD: sireg.h,v 1.1 1996/03/26 15:01:14 gwr Exp $ */ + +/* + * Register map for the Sun3 SCSI Interface (si) + * The first part of this register map is an NCR5380 + * SCSI Bus Interface Controller (SBIC). The rest is a + * DMA controller and custom logic in one of two flavors, + * one for the OBIO interface (3/50,3/60) and one for the + * VME interface (3/160,3/260,etc.), where some registers + * are implemented only on one or the other, some on both. + */ + +/* + * Some of these registers apply to only one interface and some + * apply to both. The registers which apply to the Sun3/50 onboard + * version only are udc_rdata and udc_raddr. The registers which + * apply to the Sun3 vme version only are dma_addr, dma_count, bpr, + * iv_am, and bcrh. Thus, the sbc registers, fifo_data, bcr, and csr + * apply to both interfaces. + * One other feature of the vme interface: a write to the dma count + * register also causes a write to the fifo byte count register and + * vis versa. + */ + +/* + * Am5380 Register map (no padding) + */ +struct ncr5380regs { + volatile u_char sci_r0; + volatile u_char sci_r1; + volatile u_char sci_r2; + volatile u_char sci_r3; + volatile u_char sci_r4; + volatile u_char sci_r5; + volatile u_char sci_r6; + volatile u_char sci_r7; +}; + +struct si_regs { + struct ncr5380regs sci; + + /* DMA controller registers */ + u_short dma_addrh; /* dma address (VME only) */ + u_short dma_addrl; /* (high word, low word) */ + u_short dma_counth; /* dma count (VME only) */ + u_short dma_countl; /* (high word, low word) */ + + /* AMD 9516 regs (OBIO only) see am9516.h */ + u_short udc_data; /* Am9516, reg data (OBIO only) */ + u_short udc_addr; /* Am9516, reg addr (OBIO only) */ + + /* These three registers are on both OBIO and VME versions. */ + u_short fifo_data; /* fifo data register */ + /* holds extra byte on odd */ + /* byte dma read */ + u_short fifo_count; /* fifo byte count */ + u_short si_csr; /* control/status register */ + + /* The rest of these are on the VME interface only: */ + u_short si_bprh; /* byte pack, high (VME only) */ + u_short si_bprl; /* byte pack, low (VME only) */ + u_short si_iv_am; /* bits 0-7: intr vector */ + /* bits 8-13: addr modifier (VME only) */ + /* bits 14-15: unused */ + u_short fifo_cnt_hi; /* high part of fifo_count (VME only) */ + + /* Whole thing repeats after 32 bytes. */ + u_short _space[3]; +}; + +/* possible values for the address modifier, sun3 vme version only */ +#define VME_SUPV_DATA_24 0x3d00 + +/* + * Status Register. + * Note: + * (r) indicates bit is read only. + * (rw) indicates bit is read or write. + * (v) vme host adaptor interface only. + * (o) sun3/50 onboard host adaptor interface only. + * (b) both vme and sun3/50 host adaptor interfaces. + */ +#define SI_CSR_DMA_ACTIVE 0x8000 /* (r,o) dma transfer active */ +#define SI_CSR_DMA_CONFLICT 0x4000 /* (r,b) reg accessed while dmaing */ +#define SI_CSR_DMA_BUS_ERR 0x2000 /* (r,b) bus error during dma */ +#define SI_CSR_ID 0x1000 /* (r,b) 0 for 3/50, 1 for SCSI-3, */ + /* 0 if SCSI-3 unmodified */ +#define SI_CSR_FIFO_FULL 0x0800 /* (r,b) fifo full */ +#define SI_CSR_FIFO_EMPTY 0x0400 /* (r,b) fifo empty */ +#define SI_CSR_SBC_IP 0x0200 /* (r,b) sbc interrupt pending */ +#define SI_CSR_DMA_IP 0x0100 /* (r,b) dma interrupt pending */ +#define SI_CSR_LOB 0x00c0 /* (r,v) number of leftover bytes */ +#define SI_CSR_LOB_THREE 0x00c0 /* (r,v) three leftover bytes */ +#define SI_CSR_LOB_TWO 0x0080 /* (r,v) two leftover bytes */ +#define SI_CSR_LOB_ONE 0x0040 /* (r,v) one leftover byte */ +#define SI_CSR_BPCON 0x0020 /* (rw,v) byte packing control */ + /* dma is in 0=longwords, 1=words */ +#define SI_CSR_DMA_EN 0x0010 /* (rw,v) dma/interrupt enable */ +#define SI_CSR_SEND 0x0008 /* (rw,b) dma dir, 1=to device */ +#define SI_CSR_INTR_EN 0x0004 /* (rw,b) interrupts enable */ +#define SI_CSR_FIFO_RES 0x0002 /* (rw,b) inits fifo, 0=reset */ +#define SI_CSR_SCSI_RES 0x0001 /* (rw,b) reset sbc and udc, 0=reset */ + diff --git a/sys/arch/sun3/dev/sivar.h b/sys/arch/sun3/dev/sivar.h new file mode 100644 index 00000000000..1bbaee4b7b3 --- /dev/null +++ b/sys/arch/sun3/dev/sivar.h @@ -0,0 +1,89 @@ +/* $NetBSD: sivar.h,v 1.1 1996/03/26 15:01:15 gwr Exp $ */ + +/* + * Copyright (c) 1995 David Jones, Gordon W. Ross + * 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. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * David Jones and Gordon Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * This file defines the interface between si.c and + * the bus-specific files: si_obio.c, si_vme.c + */ + +/* + * Transfers smaller than this are done using PIO + * (on assumption they're not worth DMA overhead) + */ +#define MIN_DMA_LEN 128 + +/* + * Transfers lager than 65535 bytes need to be split-up. + * (Some of the FIFO logic has only 16 bits counters.) + * Make the size an integer multiple of the page size + * to avoid buf/cluster remap problems. (paranoid?) + */ +#define MAX_DMA_LEN 0xE000 + +/* + * This structure is used to keep track of mapped DMA requests. + */ +struct si_dma_handle { + int dh_flags; +#define SIDH_BUSY 1 /* This DH is in use */ +#define SIDH_OUT 2 /* DMA does data out (write) */ + u_char * dh_addr; /* KVA of start of buffer */ + int dh_maplen; /* Length of KVA mapping. */ + long dh_dvma; /* VA of buffer in DVMA space */ +}; + +/* + * The first structure member has to be the ncr5380_softc + * so we can just cast to go back and fourth between them. + */ +struct si_softc { + struct ncr5380_softc ncr_sc; + volatile struct si_regs *sc_regs; + int sc_adapter_type; + int sc_adapter_iv_am; /* int. vec + address modifier */ + int sc_reqlen; /* requested transfer length */ + struct si_dma_handle *sc_dma; + /* DMA command block for the OBIO controller. */ + void *sc_dmacmd; +}; + +extern int si_debug; + +void si_attach __P((struct si_softc *)); +int si_intr __P((void *)); + +void si_reset_adapter __P((struct ncr5380_softc *)); + +void si_dma_alloc __P((struct ncr5380_softc *)); +void si_dma_free __P((struct ncr5380_softc *)); +void si_dma_poll __P((struct ncr5380_softc *)); diff --git a/sys/arch/sun3/dev/vme.c b/sys/arch/sun3/dev/vme.c index 20e9cc29fb5..086c8b725a5 100644 --- a/sys/arch/sun3/dev/vme.c +++ b/sys/arch/sun3/dev/vme.c @@ -1,4 +1,4 @@ -/* $NetBSD: vme.c,v 1.1 1994/12/12 18:59:26 gwr Exp $ */ +/* $NetBSD: vme.c,v 1.3 1996/03/26 15:16:19 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -37,62 +37,63 @@ #include <machine/autoconf.h> /* #include <machine/vme.h> */ -static int vme_match __P((struct device *, void *, void *)); -static void vme16attach __P((struct device *, struct device *, void *)); -static void vme32attach __P((struct device *, struct device *, void *)); -static void vme16scan __P((struct device *, void *)); -static void vme32scan __P((struct device *, void *)); +static int vmes_match __P((struct device *, void *, void *)); +static int vmel_match __P((struct device *, void *, void *)); -struct cfdriver vmescd = { - NULL, "vmes", vme_match, vme16attach, DV_DULL, - sizeof(struct device), 0 }; +static void vme_attach __P((struct device *, struct device *, void *)); -struct cfdriver vmelcd = { - NULL, "vmel", vme_match, vme32attach, DV_DULL, - sizeof(struct device), 0 }; +struct cfattach vmes_ca = { + sizeof(struct device), vmes_match, vme_attach +}; -int vme_match(parent, vcf, aux) +struct cfdriver vmes_cd = { + NULL, "vmes", DV_DULL +}; + +struct cfattach vmel_ca = { + sizeof(struct device), vmel_match, vme_attach +}; + +struct cfdriver vmel_cd = { + NULL, "vmel", DV_DULL +}; + + +/* Does this machine have a VME bus? */ +extern int cpu_has_vme; + +static int +vmes_match(parent, vcf, aux) struct device *parent; void *vcf, *aux; { - /* Does this machine have a VME bus? */ - extern int cpu_has_vme; + struct confargs *ca = aux; + if (ca->ca_bustype != BUS_VME16) + return (0); return (cpu_has_vme); } -static void -vme16attach(parent, self, args) +static int +vmel_match(parent, vcf, aux) struct device *parent; - struct device *self; - void *args; + void *vcf, *aux; { - printf("\n"); - config_scan(vme16scan, self); -} + struct confargs *ca = aux; -static void -vme16scan(parent, child) - struct device *parent; - void *child; -{ - bus_scan(parent, child, BUS_VME16); + if (ca->ca_bustype != BUS_VME32) + return (0); + return (cpu_has_vme); } static void -vme32attach(parent, self, args) +vme_attach(parent, self, args) struct device *parent; struct device *self; void *args; { printf("\n"); - config_scan(vme32scan, self); -} -static void -vme32scan(parent, child) - struct device *parent; - void *child; -{ - bus_scan(parent, child, BUS_VME32); + /* We know ca_bustype == BUS_VMExx */ + (void) config_search(bus_scan, self, args); } diff --git a/sys/arch/sun3/dev/xd.c b/sys/arch/sun3/dev/xd.c index a4ae623c13a..8c1e42f9b5e 100644 --- a/sys/arch/sun3/dev/xd.c +++ b/sys/arch/sun3/dev/xd.c @@ -1,4 +1,4 @@ -/* $NetBSD: xd.c,v 1.2 1996/01/07 22:03:17 thorpej Exp $ */ +/* $NetBSD: xd.c,v 1.7 1996/03/17 02:04:07 thorpej Exp $ */ /* * @@ -36,7 +36,7 @@ * x d . c x y l o g i c s 7 5 3 / 7 0 5 3 v m e / s m d d r i v e r * * author: Chuck Cranor <chuck@ccrc.wustl.edu> - * id: $Id: xd.c,v 1.5 1996/03/04 20:35:27 chuck Exp $ + * id: $NetBSD: xd.c,v 1.7 1996/03/17 02:04:07 thorpej Exp $ * started: 27-Feb-95 * references: [1] Xylogics Model 753 User's Manual * part number: 166-753-001, Revision B, May 21, 1988. @@ -245,12 +245,20 @@ int xdgetdisklabel __P((struct xd_softc *, void *)); * cfdrivers: device driver interface to autoconfig */ -struct cfdriver xdccd = { - NULL, "xdc", xdcmatch, xdcattach, DV_DULL, sizeof(struct xdc_softc) +struct cfattach xdc_ca = { + sizeof(struct xdc_softc), xdcmatch, xdcattach }; -struct cfdriver xdcd = { - NULL, "xd", xdmatch, xdattach, DV_DISK, sizeof(struct xd_softc) +struct cfdriver xdc_cd = { + NULL, "xdc", DV_DULL +}; + +struct cfattach xd_ca = { + sizeof(struct xd_softc), xdmatch, xdattach +}; + +struct cfdriver xd_cd = { + NULL, "xd", DV_DISK }; struct xdc_attach_args { /* this is the "aux" args to xdattach */ @@ -722,7 +730,7 @@ xdclose(dev, flag, fmt) int flag, fmt; { - struct xd_softc *xd = xdcd.cd_devs[DISKUNIT(dev)]; + struct xd_softc *xd = xd_cd.cd_devs[DISKUNIT(dev)]; int part = DISKPART(dev); /* clear mask bits */ @@ -752,11 +760,11 @@ xddump(dev) struct xd_softc *xd; unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs) + if (unit >= xd_cd.cd_ndevs) return ENXIO; part = DISKPART(dev); - xd = xdcd.cd_devs[unit]; + xd = xd_cd.cd_devs[unit]; printf("%s%c: crash dump not supported (yet)\n", xd->sc_dev.dv_xname, 'a' + part); @@ -795,7 +803,7 @@ xdioctl(dev, command, addr, flag, p) unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL) + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL) return (ENXIO); /* switch on ioctl type */ @@ -887,7 +895,7 @@ xdopen(dev, flag, fmt) /* first, could it be a valid target? */ unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL) + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL) return (ENXIO); part = DISKPART(dev); @@ -964,7 +972,7 @@ xdsize(dev) /* do it */ - xdsc = xdcd.cd_devs[DISKUNIT(dev)]; + xdsc = xd_cd.cd_devs[DISKUNIT(dev)]; part = DISKPART(dev); if (xdsc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; /* only give valid size for swap partitions */ @@ -993,7 +1001,7 @@ xdstrategy(bp) /* check for live device */ - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == 0 || + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % xd->sc_dk.dk_label->d_secsize) != 0) { bp->b_error = EINVAL; @@ -1425,6 +1433,9 @@ xdc_startbuf(xdcsc, xdsc, bp) /* Instrumentation. */ disk_busy(&xdsc->sc_dk); + /* Instrumentation. */ + disk_busy(&xdsc->sc_dk); + /* now submit [note that xdc_submit_iorq can never fail on NORM reqs] */ xdc_submit_iorq(xdcsc, rqno, XD_SUB_NORM); diff --git a/sys/arch/sun3/dev/xdreg.h b/sys/arch/sun3/dev/xdreg.h index 22397999eda..6272098ae02 100644 --- a/sys/arch/sun3/dev/xdreg.h +++ b/sys/arch/sun3/dev/xdreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: xdreg.h,v 1.1 1995/10/30 20:58:18 gwr Exp $ */ +/* $NetBSD: xdreg.h,v 1.2 1996/02/22 06:55:32 thorpej Exp $ */ /* * diff --git a/sys/arch/sun3/dev/xdvar.h b/sys/arch/sun3/dev/xdvar.h index 096d01e0566..35509803a97 100644 --- a/sys/arch/sun3/dev/xdvar.h +++ b/sys/arch/sun3/dev/xdvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: xdvar.h,v 1.2 1996/01/07 22:03:18 thorpej Exp $ */ +/* $NetBSD: xdvar.h,v 1.3 1996/02/22 06:55:33 thorpej Exp $ */ /* * diff --git a/sys/arch/sun3/dev/xy.c b/sys/arch/sun3/dev/xy.c index e66d57b187d..8bea7ab3e06 100644 --- a/sys/arch/sun3/dev/xy.c +++ b/sys/arch/sun3/dev/xy.c @@ -1,4 +1,4 @@ -/* $NetBSD: xy.c,v 1.2 1996/01/07 22:03:20 thorpej Exp $ */ +/* $NetBSD: xy.c,v 1.9 1996/03/17 02:04:10 thorpej Exp $ */ /* * @@ -36,7 +36,7 @@ * x y . c x y l o g i c s 4 5 0 / 4 5 1 s m d d r i v e r * * author: Chuck Cranor <chuck@ccrc.wustl.edu> - * id: $Id: xy.c,v 1.5 1996/03/04 20:35:29 chuck Exp $ + * id: $NetBSD: xy.c,v 1.5 1996/03/04 20:35:29 chuck Exp $ * started: 14-Sep-95 * references: [1] Xylogics Model 753 User's Manual * part number: 166-753-001, Revision B, May 21, 1988. @@ -188,12 +188,20 @@ int xygetdisklabel __P((struct xy_softc *, void *)); * cfdrivers: device driver interface to autoconfig */ -struct cfdriver xyccd = { - NULL, "xyc", xycmatch, xycattach, DV_DULL, sizeof(struct xyc_softc) +struct cfattach xyc_ca = { + sizeof(struct xyc_softc), xycmatch, xycattach }; -struct cfdriver xycd = { - NULL, "xy", xymatch, xyattach, DV_DISK, sizeof(struct xy_softc) +struct cfdriver xyc_cd = { + NULL, "xyc", DV_DULL +}; + +struct cfattach xy_ca = { + sizeof(struct xy_softc), xymatch, xyattach +}; + +struct cfdriver xy_cd = { + NULL, "xy", DV_DISK }; struct xyc_attach_args { /* this is the "aux" args to xyattach */ @@ -683,7 +691,7 @@ xyclose(dev, flag, fmt) int flag, fmt; { - struct xy_softc *xy = xycd.cd_devs[DISKUNIT(dev)]; + struct xy_softc *xy = xy_cd.cd_devs[DISKUNIT(dev)]; int part = DISKPART(dev); /* clear mask bits */ @@ -713,11 +721,11 @@ xydump(dev) struct xy_softc *xy; unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs) + if (unit >= xy_cd.cd_ndevs) return ENXIO; part = DISKPART(dev); - xy = xycd.cd_devs[unit]; + xy = xy_cd.cd_devs[unit]; printf("%s%c: crash dump not supported (yet)\n", xy->sc_dev.dv_xname, 'a' + part); @@ -756,7 +764,7 @@ xyioctl(dev, command, addr, flag, p) unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL) + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL) return (ENXIO); /* switch on ioctl type */ @@ -849,7 +857,7 @@ xyopen(dev, flag, fmt) /* first, could it be a valid target? */ unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL) + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL) return (ENXIO); part = DISKPART(dev); @@ -927,7 +935,7 @@ xysize(dev) /* do it */ - xysc = xycd.cd_devs[DISKUNIT(dev)]; + xysc = xy_cd.cd_devs[DISKUNIT(dev)]; part = DISKPART(dev); if (xysc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; /* only give valid size for swap partitions */ @@ -957,7 +965,7 @@ xystrategy(bp) /* check for live device */ - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == 0 || + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % xy->sc_dk.dk_label->d_secsize) != 0) { bp->b_error = EINVAL; @@ -1126,11 +1134,11 @@ xyc_rqtopb(iorq, iopb, cmd, subfun) iopb->cyl = block; } iopb->scnt = iorq->sectcnt; - dp = dvma_kvtopa((long)iorq->dbuf, BUS_VME16); if (iorq->dbuf == NULL) { iopb->dataa = 0; iopb->datar = 0; } else { + dp = dvma_kvtopa((long)iorq->dbuf, BUS_VME16); iopb->dataa = (dp & 0xffff); iopb->datar = ((dp & 0xff0000) >> 16); } @@ -1284,6 +1292,9 @@ xyc_startbuf(xycsc, xysc, bp) /* Instrumentation. */ disk_busy(&xysc->sc_dk); + /* Instrumentation. */ + disk_busy(&xysc->sc_dk); + return (XY_ERR_AOK); } @@ -1623,7 +1634,8 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc) iorq->xy->xyq.b_actf = iorq->buf->b_actf; disk_unbusy(&iorq->xy->sc_dk, - (iorq->buf->b_bcount - iorq->buf->b_resid)); + (iorq->buf->b_bcount - + iorq->buf->b_resid)); biodone(iorq->buf); iorq->mode = XY_SUB_FREE; break; diff --git a/sys/arch/sun3/dev/zs.c b/sys/arch/sun3/dev/zs.c index 152b40b67f3..e70f967a50b 100644 --- a/sys/arch/sun3/dev/zs.c +++ b/sys/arch/sun3/dev/zs.c @@ -1,4 +1,4 @@ -/* $NetBSD: zs.c,v 1.31 1996/01/24 22:40:25 gwr Exp $ */ +/* $NetBSD: zs.c,v 1.36 1996/04/04 06:26:15 cgd Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -76,6 +76,7 @@ #define ZSHARD_PRI 6 /* Wired on the CPU board... */ #define ZSSOFT_PRI 3 /* Want tty pri (4) but this is OK. */ +#define ZS_DELAY() delay(2) /* The layout of this is hardware-dependent (padding, order). */ struct zschan { @@ -164,12 +165,16 @@ static u_char zs_init_reg[16] = { ****************************************************************/ /* Definition of the driver for autoconfig. */ -static int zsc_match(struct device *, void *, void *); -static void zsc_attach(struct device *, struct device *, void *); +static int zsc_match __P((struct device *, void *, void *)); +static void zsc_attach __P((struct device *, struct device *, void *)); +static int zsc_print __P((void *, char *name)); -struct cfdriver zsccd = { - NULL, "zsc", zsc_match, zsc_attach, - DV_DULL, sizeof(struct zsc_softc), NULL, +struct cfattach zsc_ca = { + sizeof(struct zsc_softc), zsc_match, zsc_attach +}; + +struct cfdriver zsc_cd = { + NULL, "zsc", DV_DULL }; static int zshard(void *); @@ -182,49 +187,44 @@ static int zssoft(void *); static int zsc_match(parent, vcf, aux) struct device *parent; - void *vcf; - void *aux; + void *vcf, *aux; { struct cfdata *cf = vcf; struct confargs *ca = aux; - int unit, x; - void *zsva; + int pa, unit, x; + void *va; unit = cf->cf_unit; if (unit < 0 || unit >= NZS) return (0); - /* Make sure zs_init() found mappings. */ - zsva = zsaddr[unit]; - if (zsva == NULL) + /* + * OBIO match functions may be called for every possible + * physical address, so match only our physical address. + * This driver only supports its default mappings, so + * non-default locators must match our defaults. + */ + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = zs_physaddr[unit]; + } else { + /* Validate the given PA. */ + if (pa != zs_physaddr[unit]) + return (0); + } + if (pa != ca->ca_paddr) return (0); - if (ca->ca_paddr == -1) - ca->ca_paddr = zs_physaddr[unit]; - if (ca->ca_intpri == -1) - ca->ca_intpri = ZSHARD_PRI; + /* Make sure zs_init() found mappings. */ + va = zsaddr[unit]; + if (va == NULL) + return (0); /* This returns -1 on a fault (bus error). */ - x = peek_byte(zsva); + x = peek_byte(va); return (x != -1); } -static int -zsc_print(aux, name) - void *aux; - char *name; -{ - struct zsc_attach_args *args = aux; - - if (name != NULL) - printf("%s: ", name); - - if (args->channel != -1) - printf(" channel %d", args->channel); - - return UNCONF; -} - /* * Attach a found zs. * @@ -238,17 +238,21 @@ zsc_attach(parent, self, aux) void *aux; { struct zsc_softc *zsc = (void *) self; + struct cfdata *cf = self->dv_cfdata; struct confargs *ca = aux; struct zsc_attach_args zsc_args; volatile struct zschan *zc; struct zs_chanstate *cs; - int zsc_unit, channel; + int zsc_unit, intpri, channel; int reset, s; static int didintr; zsc_unit = zsc->zsc_dev.dv_unit; - printf(" softpri %d\n", ZSSOFT_PRI); + if ((intpri = cf->cf_intpri) == -1) + intpri = ZSHARD_PRI; + + printf(" level %d (softpri %d)\n", intpri, ZSSOFT_PRI); /* Use the mapping setup by the Sun PROM. */ if (zsaddr[zsc_unit] == NULL) @@ -283,7 +287,7 @@ zsc_attach(parent, self, aux) * so just do it on the A channel. */ if (channel == 0) { - ZS_WRITE(cs, 9, 0); + zs_write_reg(cs, 9, 0); } /* @@ -292,12 +296,12 @@ zsc_attach(parent, self, aux) */ zsc_args.channel = channel; zsc_args.hwflags = zs_hwflags[zsc_unit][channel]; - if (!config_found(self, (void *) &zsc_args, zsc_print)) { + if (config_found(self, (void *)&zsc_args, zsc_print) == NULL) { /* No sub-driver. Just reset it. */ reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splzs(); - ZS_WRITE(cs, 9, reset); + zs_write_reg(cs, 9, reset); splx(s); } } @@ -316,13 +320,29 @@ zsc_attach(parent, self, aux) cs = &zsc->zsc_cs[0]; s = splzs(); /* interrupt vector */ - ZS_WRITE(cs, 2, zs_init_reg[2]); + zs_write_reg(cs, 2, zs_init_reg[2]); /* master interrupt control (enable) */ - ZS_WRITE(cs, 9, zs_init_reg[9]); + zs_write_reg(cs, 9, zs_init_reg[9]); splx(s); } static int +zsc_print(aux, name) + void *aux; + char *name; +{ + struct zsc_attach_args *args = aux; + + if (name != NULL) + printf("%s: ", name); + + if (args->channel != -1) + printf(" channel %d", args->channel); + + return UNCONF; +} + +static int zshard(arg) void *arg; { @@ -331,9 +351,9 @@ zshard(arg) /* Do ttya/ttyb first, because they go faster. */ rval = 0; - unit = zsccd.cd_ndevs; + unit = zsc_cd.cd_ndevs; while (--unit >= 0) { - zsc = zsccd.cd_devs[unit]; + zsc = zsc_cd.cd_devs[unit]; if (zsc != NULL) { rval |= zsc_intr_hard(zsc); } @@ -375,9 +395,9 @@ zssoft(arg) zssoftpending = 0; /* Do ttya/ttyb first, because they go faster. */ - unit = zsccd.cd_ndevs; + unit = zsc_cd.cd_ndevs; while (--unit >= 0) { - zsc = zsccd.cd_devs[unit]; + zsc = zsc_cd.cd_devs[unit]; if (zsc != NULL) { (void) zsc_intr_soft(zsc); } @@ -415,6 +435,42 @@ zs_write_reg(cs, reg, val) ZS_DELAY(); } +u_char zs_read_csr(cs) + struct zs_chanstate *cs; +{ + register u_char v; + + v = *cs->cs_reg_csr; + ZS_DELAY(); + return v; +} + +u_char zs_read_data(cs) + struct zs_chanstate *cs; +{ + register u_char v; + + v = *cs->cs_reg_data; + ZS_DELAY(); + return v; +} + +void zs_write_csr(cs, val) + struct zs_chanstate *cs; + u_char val; +{ + *cs->cs_reg_csr = val; + ZS_DELAY(); +} + +void zs_write_data(cs, val) + struct zs_chanstate *cs; + u_char val; +{ + *cs->cs_reg_data = val; + ZS_DELAY(); +} + /**************************************************************** * Console support functions (Sun3 specific!) ****************************************************************/ diff --git a/sys/arch/sun3/dev/zs_kgdb.c b/sys/arch/sun3/dev/zs_kgdb.c index 5793efa529a..3ba576927cf 100644 --- a/sys/arch/sun3/dev/zs_kgdb.c +++ b/sys/arch/sun3/dev/zs_kgdb.c @@ -47,6 +47,12 @@ /* * Hooks for kgdb when attached vi the z8530 driver * XXX - not tested yet... + * + * To use this, build a kernel with: option KGDB, and + * boot that kernel with "-d". (The kernel will call + * zs_kgdb_init, kgdb_connect.) When the console prints + * "kgdb waiting..." you run "gdb -k kernel" and then + * connect to the remote using: "target remote /dev/ttyX" */ #include <sys/param.h> @@ -66,6 +72,8 @@ /* The Sun3 provides a 4.9152 MHz clock to the ZS chips. */ #define PCLK (9600 * 512) /* PCLK pin input clock rate */ +#define ZS_DELAY() delay(2) + extern int kgdb_dev; extern int kgdb_rate; @@ -175,7 +183,7 @@ zs_check_kgdb(cs, dev) * Yes, this is the kgdb port. Finish the autoconfig * message and set up the port for our exclusive use. */ - printf(" (kgdb,%d)\n", kgdb_rate); + printf(" (kgdb)\n"); cs->cs_private = NULL; cs->cs_ops = &zsops_kgdb; @@ -213,16 +221,14 @@ zs_kgdb_rxint(cs) register u_char c, rr1; /* Read the input data ASAP. */ - c = *(cs->cs_reg_data); - ZS_DELAY(); + c = zs_read_data(cs); /* Save the status register too. */ - rr1 = ZS_READ(cs, 1); + rr1 = zs_read_reg(cs, 1); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { /* Clear the receive error. */ - *(cs->cs_reg_csr) = ZSWR0_RESET_ERRORS; - ZS_DELAY(); + zs_write_csr(cs, ZSWR0_RESET_ERRORS); } if (c == FRAME_START) { @@ -238,11 +244,10 @@ static int zs_kgdb_txint(cs) register struct zs_chanstate *cs; { - register int count, rval; - - *(cs->cs_reg_csr) = ZSWR0_RESET_TXINT; - ZS_DELAY(); + register int rr0; + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_TXINT); return (0); } @@ -252,11 +257,8 @@ zs_kgdb_stint(cs) { register int rr0; - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); - - *(cs->cs_reg_csr) = ZSWR0_RESET_STATUS; - ZS_DELAY(); + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); return (0); } diff --git a/sys/arch/sun3/include/autoconf.h b/sys/arch/sun3/include/autoconf.h index 60b7e477c24..9b90ac4c081 100644 --- a/sys/arch/sun3/include/autoconf.h +++ b/sys/arch/sun3/include/autoconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.h,v 1.9 1995/01/11 20:38:33 gwr Exp $ */ +/* $NetBSD: autoconf.h,v 1.10 1996/03/26 15:16:28 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -41,8 +41,6 @@ #define BUS_OBIO 1 /* "obio" */ #define BUS_VME16 2 /* "vmes" */ #define BUS_VME32 3 /* "vmel" */ -/* These are pseudo buses: */ -#define BUS_OBCTL 4 /* * This is the "args" parameter to the bus match/attach functions. @@ -54,8 +52,13 @@ struct confargs { int ca_intvec; /* interrupt vector index */ }; -int always_match __P((struct device *, void *, void *)); -void bus_scan __P((struct device *, void *, int)); +/* Locator aliases */ +#define cf_paddr cf_loc[0] +#define cf_intpri cf_loc[1] +#define cf_intvec cf_loc[2] + +int bus_scan __P((struct device *, void *, void *)); int bus_print __P((void *, char *)); int bus_peek __P((int, int, int)); char * bus_mapin __P((int, int, int)); + diff --git a/sys/arch/sun3/include/dvma.h b/sys/arch/sun3/include/dvma.h index a48a2a19672..abe533fc5c3 100644 --- a/sys/arch/sun3/include/dvma.h +++ b/sys/arch/sun3/include/dvma.h @@ -1,4 +1,4 @@ -/* $NetBSD: dvma.h,v 1.1 1995/09/26 04:02:08 gwr Exp $ */ +/* $NetBSD: dvma.h,v 1.3 1996/02/20 22:06:28 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -54,25 +54,9 @@ */ /* - * This range could be managed as whole MMU segments. - * The last segment is pre-allocated (see below) - */ -#define DVMA_SEGMAP_BASE 0x0FF00000 -#define DVMA_SEGMAP_SIZE 0x000E0000 -#define DVMA_SEGMAP_END (DVMA_SEGMAP_BASE+DVMA_SEGMAP_SIZE) - -/* - * This range is managed as individual pages. - * The last page is owned by the PROM monitor. - */ -#define DVMA_PAGEMAP_BASE 0x0FFE0000 -#define DVMA_PAGEMAP_SIZE 0x0001E000 -#define DVMA_PAGEMAP_END (DVMA_PAGEMAP_BASE+DVMA_PAGEMAP_SIZE) - -/* * To convert an address in DVMA space to a slave address, * just use a logical AND with one of the following masks. - * To convert back, use logical OR with DVMA_SEGMAP_BASE. + * To convert back, just logical OR with the base address. */ #define DVMA_OBIO_SLAVE_BASE 0x0F000000 #define DVMA_OBIO_SLAVE_MASK 0x00FFffff /* 16MB */ @@ -81,25 +65,18 @@ #define DVMA_VME_SLAVE_MASK 0x000Fffff /* 1MB */ -#if 1 /* XXX - temporary */ -/* - * XXX - For compatibility, until DVMA is re-worked. - * Total DVMA space covers SEGMAP + PAGEMAP - */ -#define DVMA_SPACE_START DVMA_SEGMAP_BASE -#define DVMA_SPACE_END DVMA_PAGEMAP_END -#define DVMA_SPACE_SIZE (DVMA_SPACE_END - DVMA_SPACE_START) -#endif /* XXX */ - -/* - * XXX - These will change! (will be like the sparc) - */ +/* DVMA is the last 1MB, but the PROM gets the last page. */ +#define DVMA_SPACE_START 0x0FF00000 +#define DVMA_SPACE_END 0x0FFFE000 +/* Allocate/free actual pages of DVMA space. */ caddr_t dvma_malloc(size_t bytes); void dvma_free(caddr_t addr, size_t bytes); +/* Remap/unmap kernel memory in DVMA space. */ caddr_t dvma_mapin(char *kva, int len); void dvma_mapout(caddr_t dvma_addr, int len); +/* Convert a kernel DVMA pointer to a slave address. */ long dvma_kvtopa(long kva, int bus); diff --git a/sys/arch/sun3/include/obio.h b/sys/arch/sun3/include/obio.h index 414726fdbcd..b348e2e2f7a 100644 --- a/sys/arch/sun3/include/obio.h +++ b/sys/arch/sun3/include/obio.h @@ -1,4 +1,4 @@ -/* $NetBSD: obio.h,v 1.13 1994/12/12 18:59:42 gwr Exp $ */ +/* $NetBSD: obio.h,v 1.14 1996/03/26 15:16:32 gwr Exp $ */ /* * Copyright (c) 1993 Adam Glass @@ -71,7 +71,10 @@ #define OBIO_DES_SIZE 0x00004 #define OBIO_ECCREG_SIZE 0x00100 +#ifdef _KERNEL + caddr_t obio_alloc __P((int, int)); caddr_t obio_vm_alloc __P((int)); caddr_t obio_find_mapping __P((int pa, int size)); +#endif /* _KERNEL */ diff --git a/sys/arch/sun3/include/param.h b/sys/arch/sun3/include/param.h index aaaa50cd1aa..561a62fd55e 100644 --- a/sys/arch/sun3/include/param.h +++ b/sys/arch/sun3/include/param.h @@ -1,4 +1,4 @@ -/* $NetBSD: param.h,v 1.30 1995/11/10 22:04:48 gwr Exp $ */ +/* $NetBSD: param.h,v 1.34 1996/03/04 05:04:40 cgd Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -48,7 +48,9 @@ /* * Machine dependent constants for the Sun3 series. */ +#define _MACHINE sun3 #define MACHINE "sun3" +#define _MACHINE_ARCH m68k #define MACHINE_ARCH "m68k" #define MID_MACHINE MID_M68K @@ -149,17 +151,10 @@ /* XXX - Does this really belong here? -gwr */ #include <machine/psl.h> -#ifdef _KERNEL -#ifndef LOCORE +#if defined(_KERNEL) && !defined(_LOCORE) +extern void _delay __P((unsigned)); +#define delay(us) _delay((us)<<8) #define DELAY(n) delay(n) -extern int cpuspeed; -static inline void delay2us() -{ - register int n = cpuspeed; - - __asm __volatile ("0: subql #4,%0; jgt 0b" : "=d" (n) : "0" (n)); -} -#endif /* !LOCORE */ -#endif /* _KERNEL */ +#endif /* _KERNEL && !_LOCORE */ #endif /* MACHINE */ diff --git a/sys/arch/sun3/include/pmap.h b/sys/arch/sun3/include/pmap.h index 275fdce7255..d4def4b5237 100644 --- a/sys/arch/sun3/include/pmap.h +++ b/sys/arch/sun3/include/pmap.h @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.13 1995/04/10 12:42:29 mycroft Exp $ */ +/* $NetBSD: pmap.h,v 1.14 1996/02/28 22:50:43 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -59,6 +59,9 @@ struct pmap kernel_pmap_store; #define PMAP_DEACTIVATE(pmap, pcbp) \ pmap_deactivate(pmap, pcbp) +extern void pmap_prefer(vm_offset_t, vm_offset_t *); +#define PMAP_PREFER(fo, ap) pmap_prefer((fo), (ap)) + /* XXX - Need a (silly) #define get code in kern_sysctl.c */ extern segsz_t pmap_resident_pages(pmap_t); #define pmap_resident_count(pmap) pmap_resident_pages(pmap) diff --git a/sys/arch/sun3/include/psl.h b/sys/arch/sun3/include/psl.h index d716133399c..0419d103f3f 100644 --- a/sys/arch/sun3/include/psl.h +++ b/sys/arch/sun3/include/psl.h @@ -1,4 +1,4 @@ -/* $NetBSD: psl.h,v 1.8 1995/10/10 21:28:00 gwr Exp $ */ +/* $NetBSD: psl.h,v 1.9 1996/02/01 22:33:10 mycroft Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -35,7 +35,7 @@ /* Could define this in the common <m68k/psl.h> instead. */ -#if defined(_KERNEL) && !defined(LOCORE) +#if defined(_KERNEL) && !defined(_LOCORE) #ifndef __GNUC__ /* No inline, use real function in locore.s */ @@ -102,5 +102,5 @@ extern __inline__ int _spl(int new) #define splhigh() spl7() #define splsched() spl7() -#endif /* KERNEL && !LOCORE */ +#endif /* KERNEL && !_LOCORE */ #endif /* PSL_C */ diff --git a/sys/arch/sun3/include/z8530var.h b/sys/arch/sun3/include/z8530var.h index 9eb9551daf2..86f029efcff 100644 --- a/sys/arch/sun3/include/z8530var.h +++ b/sys/arch/sun3/include/z8530var.h @@ -1,4 +1,4 @@ -/* $NetBSD: z8530var.h,v 1.2 1996/01/24 22:40:48 gwr Exp $ */ +/* $NetBSD: z8530var.h,v 1.3 1996/01/30 22:35:04 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -48,16 +48,21 @@ #include <dev/ic/z8530sc.h> /* - * Macros to read and write individual registers (except 0) in a channel. - * The ZS chip requires a 1.6 uSec. recovery time between accesses, and - * the Sun3 hardware does NOT take care of this for you. + * Functions to read and write individual registers in a channel. + * The ZS chip requires a 1.6 uSec. recovery time between accesses, + * and the Sun3 hardware does NOT take care of this for you. + * The delay is now handled inside the chip access functions. + * These could be inlines, but with the delay, speed is moot. */ -#define ZS_READ(c, r) zs_read_reg(c, r) -#define ZS_WRITE(c, r, v) zs_write_reg(c, r, v) -#define ZS_DELAY() delay2us() -u_char zs_read_reg __P((struct zs_chanstate *zc, u_char reg)); -void zs_write_reg __P((struct zs_chanstate *zc, u_char reg, u_char val)); +u_char zs_read_reg __P((struct zs_chanstate *cs, u_char reg)); +u_char zs_read_csr __P((struct zs_chanstate *cs)); +u_char zs_read_data __P((struct zs_chanstate *cs)); + +void zs_write_reg __P((struct zs_chanstate *cs, u_char reg, u_char val)); +void zs_write_csr __P((struct zs_chanstate *cs, u_char val)); +void zs_write_data __P((struct zs_chanstate *cs, u_char val)); + /* * How to request a "soft" interrupt. diff --git a/sys/arch/sun3/stand/libsa/SRT1.c b/sys/arch/sun3/stand/libsa/SRT1.c index 800b6f9b485..c17569f1fcf 100644 --- a/sys/arch/sun3/stand/libsa/SRT1.c +++ b/sys/arch/sun3/stand/libsa/SRT1.c @@ -1,4 +1,4 @@ -/* $NetBSD: SRT1.c,v 1.3 1995/09/23 03:42:35 gwr Exp $ */ +/* $NetBSD: SRT1.c,v 1.4 1996/01/29 23:41:03 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -38,10 +38,10 @@ extern int edata[], end[]; extern int * getvbr(); -extern volatile void abort(); +extern __dead void abort(); extern void main(); -volatile void +__dead void exit() { mon_exit_to_mon(); @@ -52,7 +52,7 @@ exit() * This is called by SRT0.S * to do final prep for main */ -void +__dead void _start() { register int *p; diff --git a/sys/arch/sun3/stand/libsa/dev_disk.c b/sys/arch/sun3/stand/libsa/dev_disk.c index a6506ee560b..2d967f4d0ce 100644 --- a/sys/arch/sun3/stand/libsa/dev_disk.c +++ b/sys/arch/sun3/stand/libsa/dev_disk.c @@ -1,4 +1,4 @@ -/* $NetBSD: dev_disk.c,v 1.3 1995/10/17 23:07:19 gwr Exp $ */ +/* $NetBSD: dev_disk.c,v 1.4 1996/04/10 18:31:14 gwr Exp $ */ /* * Copyright (c) 1993 Paul Kranenburg @@ -49,6 +49,10 @@ #include "dvma.h" #include "promdev.h" +#define RETRY_COUNT 5 + +extern int debug; +int disk_opencount; struct saioreq disk_ioreq; int @@ -61,24 +65,25 @@ disk_open(f, devname) int error; #ifdef DEBUG_PROM + if (debug) printf("disk_open: %s\n", devname); #endif + si = &disk_ioreq; + if (disk_opencount == 0) { /* * Setup our part of the saioreq. * (determines what gets opened) */ - si = &disk_ioreq; - bzero((caddr_t)si, sizeof(*si)); bp = *romp->bootParam; - si->si_boottab = bp->bootDevice; si->si_ctlr = bp->ctlrNum; si->si_unit = bp->unitNum; si->si_boff = bp->partNum; - if ((error = prom_iopen(si)) != 0) return (error); + } + disk_opencount++; f->f_devdata = si; return 0; @@ -90,9 +95,17 @@ disk_close(f) { struct saioreq *si; +#ifdef DEBUG_PROM + if (debug) + printf("disk_close: ocnt=%d\n", disk_opencount); +#endif + si = f->f_devdata; - prom_iclose(si); f->f_devdata = NULL; + if (disk_opencount <= 0) + return 0; + if (--disk_opencount == 0) + prom_iclose(si); return 0; } @@ -108,27 +121,37 @@ disk_strategy(devdata, flag, dblk, size, buf, rsize) struct saioreq *si; struct boottab *ops; char *dmabuf; - int si_flag, xcnt; + int retry, si_flag, xcnt; si = devdata; ops = si->si_boottab; #ifdef DEBUG_PROM + if (debug > 1) printf("disk_strategy: size=%d dblk=%d\n", size, dblk); #endif dmabuf = dvma_mapin(buf, size); + si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE; + /* + * The PROM strategy will occasionally return -1 and expect + * us to try again. From mouse@Collatz.McRCIM.McGill.EDU + */ + retry = RETRY_COUNT; + do { si->si_bn = dblk; si->si_ma = dmabuf; si->si_cc = size; - - si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE; xcnt = (*ops->b_strategy)(si, si_flag); + } while ((xcnt <= 0) && (--retry > 0)); + dvma_mapout(dmabuf, size); #ifdef DEBUG_PROM - printf("disk_strategy: xcnt = %x\n", xcnt); + if (debug > 1) + printf("disk_strategy: xcnt = %x retries=%d\n", + xcnt, RETRY_COUNT - retry); #endif if (xcnt <= 0) diff --git a/sys/arch/sun3/stand/libsa/dvma.c b/sys/arch/sun3/stand/libsa/dvma.c index 618408f1c3e..deb039edabc 100644 --- a/sys/arch/sun3/stand/libsa/dvma.c +++ b/sys/arch/sun3/stand/libsa/dvma.c @@ -1,4 +1,4 @@ -/* $NetBSD: dvma.c,v 1.4 1995/09/26 21:29:25 gwr Exp $ */ +/* $NetBSD: dvma.c,v 1.6 1996/01/31 17:20:39 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -54,6 +54,9 @@ extern void set_segmap __P((int, int)); #define SA_MIN_VA 0x200000 #define SA_MAX_VA (SA_MIN_VA + DVMA_MAPLEN) +/* This points to the end of the free DVMA space. */ +u_int dvma_end = DVMA_BASE + DVMA_MAPLEN; + void dvma_init() { @@ -105,20 +108,13 @@ dvma_mapout(char *addr, int len) char * dvma_alloc(int len) { - char *mem; - - mem = alloc(len); - if (!mem) - return(mem); - return(dvma_mapin(mem, len)); + len = sun3_round_page(len); + dvma_end -= len; + return((char*)dvma_end); } void dvma_free(char *dvma, int len) { - char *mem; - - mem = dvma_mapout(dvma, len); - if (mem) - free(mem, len); + /* not worth the trouble */ } diff --git a/sys/arch/sun3/stand/libsa/exec_sun.c b/sys/arch/sun3/stand/libsa/exec_sun.c index 559a2a916e1..c22e9db71a9 100644 --- a/sys/arch/sun3/stand/libsa/exec_sun.c +++ b/sys/arch/sun3/stand/libsa/exec_sun.c @@ -1,4 +1,4 @@ -/* $NetBSD: exec_sun.c,v 1.4 1995/09/23 03:42:40 gwr Exp $ */ +/* $NetBSD: exec_sun.c,v 1.5 1996/01/29 23:41:06 gwr Exp $ */ /*- * Copyright (c) 1982, 1986, 1990, 1993 @@ -42,6 +42,7 @@ #include "stand.h" extern int debug; +int errno; /*ARGSUSED*/ int @@ -159,13 +160,8 @@ exec_sun(file, loadaddr) printf("=0x%x\n", cp - loadaddr); close(io); - if (debug) { - printf("Debug mode - enter c to continue..."); - /* This will print "\nAbort at ...\n" */ - asm(" trap #0"); - } - printf("Starting program at 0x%x\n", (int)entry); + asm("_exec_sun_call_entry:"); (*entry)(); panic("exec returned"); diff --git a/sys/arch/sun3/stand/libsa/netif.h b/sys/arch/sun3/stand/libsa/netif.h index 1636735eb74..09bb6098df3 100644 --- a/sys/arch/sun3/stand/libsa/netif.h +++ b/sys/arch/sun3/stand/libsa/netif.h @@ -2,7 +2,7 @@ #include "iodesc.h" struct netif { - void *devdata; + void *nif_devdata; }; ssize_t netif_get __P((struct iodesc *, void *, size_t, time_t)); diff --git a/sys/arch/sun3/stand/libsa/netif_sun.c b/sys/arch/sun3/stand/libsa/netif_sun.c index df921f99dfb..f1d7753628a 100644 --- a/sys/arch/sun3/stand/libsa/netif_sun.c +++ b/sys/arch/sun3/stand/libsa/netif_sun.c @@ -1,4 +1,4 @@ -/* $NetBSD: netif_sun.c,v 1.3 1995/10/13 21:45:18 gwr Exp $ */ +/* $NetBSD: netif_sun.c,v 1.4 1996/01/29 23:41:07 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -60,109 +60,247 @@ #include "dvma.h" #include "promdev.h" -static struct netif netif_prom; -static void sun3_getether __P((u_char *)); +#define PKT_BUF_SIZE 2048 -#ifdef NETIF_DEBUG -int netif_debug; -#endif +int debug; +int errno; + +static void sun3_getether __P((u_char *)); -struct saioreq net_ioreq; struct iodesc sockets[SOPEN_MAX]; -struct iodesc * -socktodesc(sock) - int sock; +static struct netif prom_nif; +static struct devdata { + struct saioreq dd_si; + int rbuf_len; + char *rbuf; + int tbuf_len; + char *tbuf; + u_short dd_opens; + char dd_myea[6]; +} prom_dd; + +static struct idprom sun3_idprom; + + +void +sun3_getether(ea) + u_char *ea; { - if (sock != 0) { - return(NULL); + u_char *src, *dst; + int len, x; + + if (sun3_idprom.idp_format == 0) { + dst = (char*)&sun3_idprom; + src = (char*)IDPROM_BASE; + len = IDPROM_SIZE; + do { + x = get_control_byte(src++); + *dst++ = x; + } while (--len > 0); } - return (sockets); + MACPY(sun3_idprom.idp_etheraddr, ea); } -int -netif_open(machdep_hint) - void *machdep_hint; + +/* + * Open the PROM device. + * Return netif ptr on success. + */ +struct devdata * +netif_init(aux) + void *aux; { - struct bootparam *bp; + struct devdata *dd = &prom_dd; struct saioreq *si; - struct iodesc *io; + struct bootparam *bp; int error; - /* find a free socket */ - io = sockets; - if (io->io_netif) { -#ifdef DEBUG - printf("netif_open: device busy\n"); -#endif - return (-1); - } - bzero(io, sizeof(*io)); - /* * Setup our part of the saioreq. * (determines what gets opened) */ - si = &net_ioreq; + si = &dd->dd_si; bzero((caddr_t)si, sizeof(*si)); bp = *romp->bootParam; - si->si_boottab = bp->bootDevice; si->si_ctlr = bp->ctlrNum; si->si_unit = bp->unitNum; si->si_boff = bp->partNum; +#ifdef NETIF_DEBUG + if (debug) + printf("netif_init: calling prom_iopen\n"); +#endif + /* * Note: Sun PROMs will do RARP on open, but does not tell * you the IP address it gets, so it is just noise to us... */ if ((error = prom_iopen(si)) != 0) { -#ifdef DEBUG - printf("netif_open: prom_iopen, error=%d\n", error); -#endif - return (-1); + printf("netif_init: prom_iopen, error=%d\n", error); + return (NULL); } + if (si->si_sif == NULL) { -#ifdef DEBUG - printf("netif_open: not a network device\n"); -#endif + printf("netif_init: not a network device\n"); prom_iclose(si); - return (-1); + return (NULL); } - netif_prom.devdata = si; - io->io_netif = &netif_prom; +#ifdef NETIF_DEBUG + if (debug) + printf("netif_init: allocating buffers\n"); +#endif + + /* Allocate the transmit/receive buffers. */ + if (dd->rbuf == NULL) { + dd->rbuf_len = PKT_BUF_SIZE; + dd->rbuf = dvma_alloc(dd->rbuf_len); + } + if (dd->tbuf == NULL) { + dd->tbuf_len = PKT_BUF_SIZE; + dd->tbuf = dvma_alloc(dd->tbuf_len); + } + if ((dd->rbuf == NULL) || + (dd->tbuf == NULL)) + panic("netif_init: malloc failed\n"); - /* Put our ethernet address in io->myea */ - sun3_getether(io->myea); +#ifdef NETIF_DEBUG + if (debug) + printf("netif_init: rbuf=0x%x, tbuf=0x%x\n", + dd->rbuf, dd->tbuf); +#endif + /* Record our ethernet address. */ + sun3_getether(dd->dd_myea); + dd->dd_opens = 0; + + return(dd); +} + +void +netif_fini(dd) + struct devdata *dd; +{ + struct saioreq *si; + + si = &dd->dd_si; + +#ifdef NETIF_DEBUG + if (debug) + printf("netif_fini: calling prom_iclose\n"); +#endif + + prom_iclose(si); + /* Dellocate the transmit/receive buffers. */ + if (dd->rbuf) { + dvma_free(dd->rbuf, dd->rbuf_len); + dd->rbuf = NULL; + } + if (dd->tbuf) { + dvma_free(dd->tbuf, dd->tbuf_len); + dd->tbuf = NULL; + } +} + +int +netif_attach(nif, s, aux) + struct netif *nif; + struct iodesc *s; + void *aux; +{ + struct devdata *dd; + + dd = nif->nif_devdata; + if (dd == NULL) { + dd = netif_init(aux); + if (dd == NULL) + return (ENXIO); + nif->nif_devdata = dd; + } + dd->dd_opens++; + MACPY(dd->dd_myea, s->myea); + s->io_netif = nif; return(0); } +void +netif_detach(nif) + struct netif *nif; +{ + struct devdata *dd; + + dd = nif->nif_devdata; + if (dd == NULL) + return; + dd->dd_opens--; + if (dd->dd_opens > 0) + return; + netif_fini(dd); + nif->nif_devdata = NULL; +} + +int +netif_open(aux) + void *aux; +{ + struct netif *nif; + struct iodesc *s; + int fd, error; + + /* find a free socket */ + for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) + if (s->io_netif == NULL) + goto found; + errno = EMFILE; + return (-1); + +found: + bzero(s, sizeof(*s)); + nif = &prom_nif; + error = netif_attach(nif, s); + if (error != 0) { + errno = error; + return (-1); + } + return (fd); +} + int netif_close(fd) int fd; { - struct saioreq *si; - struct iodesc *io; - struct netif *ni; + struct iodesc *s; + struct netif *nif; - if (fd != 0) { + if (fd < 0 || fd >= SOPEN_MAX) { errno = EBADF; return(-1); } + s = &sockets[fd]; + nif = s->io_netif; + /* Already closed? */ + if (nif == NULL) + return(0); + netif_detach(nif); + s->io_netif = NULL; + return(0); +} - io = sockets; - ni = io->io_netif; - if (ni != NULL) { - si = ni->devdata; - prom_iclose(si); - ni->devdata = NULL; - io->io_netif = NULL; + +struct iodesc * +socktodesc(fd) + int fd; +{ + if (fd < 0 || fd >= SOPEN_MAX) { + errno = EBADF; + return (NULL); } - return(0); + return (&sockets[fd]); } + /* * Send a packet. The ether header is already there. * Return the length sent (or -1 on error). @@ -173,13 +311,15 @@ netif_put(desc, pkt, len) void *pkt; size_t len; { + struct netif *nif; + struct devdata *dd; struct saioreq *si; struct saif *sif; char *dmabuf; - int rv, sendlen; + int rv, slen; #ifdef NETIF_DEBUG - if (netif_debug) { + if (debug > 1) { struct ether_header *eh; printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", @@ -191,33 +331,44 @@ netif_put(desc, pkt, len) } #endif - si = desc->io_netif->devdata; + nif = desc->io_netif; + dd = nif->nif_devdata; + si = &dd->dd_si; sif = si->si_sif; - sendlen = len; - if (sendlen < 60) { - sendlen = 60; -#ifdef NETIF_DEBUG - printf("netif_put: length padded to %d\n", sendlen); -#endif - } + slen = len; #ifdef PARANOID if (sif == NULL) panic("netif_put: no saif ptr\n"); #endif - dmabuf = dvma_mapin(pkt, sendlen); - rv = sif->sif_xmit(si->si_devdata, dmabuf, sendlen); - dvma_mapout(dmabuf, sendlen); + /* + * Copy into our transmit buffer because the PROM + * network driver might continue using the packet + * after the sif_xmit call returns. We never send + * very much data anyway, so the copy is fine. + */ + if (slen > dd->tbuf_len) + panic("netif_put: slen=%d\n", slen); + bcopy(pkt, dd->tbuf, slen); + + if (slen < 60) { + slen = 60; + } + + rv = (*sif->sif_xmit)(si->si_devdata, dd->tbuf, slen); #ifdef NETIF_DEBUG - if (netif_debug) + if (debug > 1) printf("netif_put: xmit returned %d\n", rv); #endif - if (rv == 0) rv = len; - else rv = -1; + /* + * Just ignore the return value. If the PROM transmit + * function fails, it will make some noise, such as: + * le: No Carrier + */ - return rv; + return len; } /* @@ -229,46 +380,65 @@ netif_get(desc, pkt, maxlen, timo) struct iodesc *desc; void *pkt; size_t maxlen; - time_t timo; + time_t timo; /* seconds */ { + struct netif *nif; + struct devdata *dd; struct saioreq *si; struct saif *sif; - char *dmabuf; int tick0, tmo_ticks; - int len; + int rlen = 0; #ifdef NETIF_DEBUG - if (netif_debug) + if (debug > 1) printf("netif_get: pkt=0x%x, maxlen=%d, tmo=%d\n", pkt, maxlen, timo); #endif - si = desc->io_netif->devdata; + nif = desc->io_netif; + dd = nif->nif_devdata; + si = &dd->dd_si; sif = si->si_sif; -#ifdef PARANOID - if (sif == NULL) - panic("netif_get: no saif ptr\n"); -#endif - tmo_ticks = timo * hz; + + /* Have to receive into our own buffer and copy. */ + do { tick0 = getticks(); + do { + rlen = (*sif->sif_poll)(si->si_devdata, dd->rbuf); + if (rlen != 0) + goto break2; + } while (getticks() == tick0); + } while (--tmo_ticks > 0); - dmabuf = dvma_mapin(pkt, maxlen); - do len = sif->sif_poll(si->si_devdata, dmabuf); - while ((len == 0) && ((getticks() - tick0) < tmo_ticks)); - dvma_mapout(dmabuf, maxlen); + /* No packet arrived. Better reset the interface. */ + printf("netif_get: timeout; resetting\n"); + (*sif->sif_reset)(si->si_devdata, si); + +break2: #ifdef NETIF_DEBUG - if (netif_debug) - printf("netif_get: received len=%d\n", len); + if (debug > 1) + printf("netif_get: received rlen=%d\n", rlen); #endif - if (len < 12) + /* Need at least a valid Ethernet header. */ + if (rlen < 12) return -1; + /* If we went beyond our buffer, were dead! */ + if (rlen > dd->rbuf_len) + panic("netif_get: rlen=%d\n", rlen); + + /* The caller's buffer may be smaller... */ + if (rlen > maxlen) + rlen = maxlen; + + bcopy(dd->rbuf, pkt, rlen); + #ifdef NETIF_DEBUG - if (netif_debug) { + if (debug > 1) { struct ether_header *eh = pkt; printf("dst: %s ", ether_sprintf(eh->ether_dhost)); @@ -277,27 +447,5 @@ netif_get(desc, pkt, maxlen, timo) } #endif - return len; + return rlen; } - -static struct idprom sun3_idprom; - -static void -sun3_getether(ea) - u_char *ea; -{ - u_char *src, *dst; - int len, x; - - if (sun3_idprom.idp_format == 0) { - dst = (char*)&sun3_idprom; - src = (char*)IDPROM_BASE; - len = IDPROM_SIZE; - do { - x = get_control_byte(src++); - *dst++ = x; - } while (--len > 0); - } - MACPY(sun3_idprom.idp_etheraddr, ea); -} - diff --git a/sys/arch/sun3/stand/libsa/panic.c b/sys/arch/sun3/stand/libsa/panic.c index 6705fea945b..97fddd3e5ff 100644 --- a/sys/arch/sun3/stand/libsa/panic.c +++ b/sys/arch/sun3/stand/libsa/panic.c @@ -2,15 +2,15 @@ #include <stdarg.h> #include "stand.h" -extern volatile void abort(); +extern __dead void abort(); -volatile void +__dead void panic(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - printf(fmt, ap); + vprintf(fmt, ap); printf("\n"); va_end(ap); abort(); diff --git a/sys/arch/sun3/stand/libsa/promboot.c b/sys/arch/sun3/stand/libsa/promboot.c index d360652f063..1a1cad0d8c7 100644 --- a/sys/arch/sun3/stand/libsa/promboot.c +++ b/sys/arch/sun3/stand/libsa/promboot.c @@ -10,7 +10,7 @@ char prom_bootdev[32]; char *prom_bootfile; int prom_boothow; -int debug; +int debug = 0; /* * Get useful info from the PROM bootparams struct, i.e.: @@ -59,13 +59,15 @@ prom_get_boot_info() break; case 'd': prom_boothow |= RB_KDB; - debug = 1; + debug++; break; } } } -#ifdef DEBUG - printf("promboot: device=\"%s\" file=\"%s\" how=0x%x\n", - prom_bootdev, prom_bootfile, prom_boothow); -#endif + + if (debug) { + printf("Debug level %d - enter c to continue...", debug); + /* This will print "\nAbort at ...\n" */ + asm(" trap #0"); + } } diff --git a/sys/arch/sun3/stand/libsa/promdev.c b/sys/arch/sun3/stand/libsa/promdev.c index 3f0e2b41040..130e4d8cb28 100644 --- a/sys/arch/sun3/stand/libsa/promdev.c +++ b/sys/arch/sun3/stand/libsa/promdev.c @@ -1,4 +1,4 @@ -/* $NetBSD: promdev.c,v 1.6 1995/10/13 21:45:21 gwr Exp $ */ +/* $NetBSD: promdev.c,v 1.7 1996/01/29 23:41:10 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -40,6 +40,7 @@ #include "dvma.h" extern void set_pte __P((int, int)); +extern int debug; static int promdev_inuse; @@ -69,15 +70,17 @@ prom_iopen(si) dip = ops->b_devinfo; #ifdef DEBUG_PROM - printf("Boot device type: %s\n", ops->b_desc); - printf("d_devbytes=%d\n", dip->d_devbytes); - printf("d_dmabytes=%d\n", dip->d_dmabytes); - printf("d_localbytes=%d\n", dip->d_localbytes); - printf("d_stdcount=%d\n", dip->d_stdcount); - printf("d_stdaddrs[%d]=%x\n", si->si_ctlr, + if (debug) { + printf("Boot device type: %s\n", ops->b_desc); + printf("d_devbytes=%d\n", dip->d_devbytes); + printf("d_dmabytes=%d\n", dip->d_dmabytes); + printf("d_localbytes=%d\n", dip->d_localbytes); + printf("d_stdcount=%d\n", dip->d_stdcount); + printf("d_stdaddrs[%d]=%x\n", si->si_ctlr, dip->d_stdaddrs[si->si_ctlr]); - printf("d_devtype=%d\n", dip->d_devtype); - printf("d_maxiobytes=%d\n", dip->d_maxiobytes); + printf("d_devtype=%d\n", dip->d_devtype); + printf("d_maxiobytes=%d\n", dip->d_maxiobytes); + } #endif if (si->si_ctlr > dip->d_stdcount) { @@ -91,14 +94,21 @@ prom_iopen(si) si->si_devaddr = prom_mapin(dip->d_stdaddrs[si->si_ctlr], dip->d_devbytes, dip->d_devtype); #ifdef DEBUG_PROM - printf("prom_iopen: devaddr=0x%x pte=0x%x\n", + if (debug) + printf("prom_iopen: devaddr=0x%x pte=0x%x\n", si->si_devaddr, get_pte(si->si_devaddr)); #endif } if (dip->d_dmabytes) { - si->si_dmaaddr = dvma_alloc(dip->d_dmabytes); + int addr, size; + /* try page-aligned address... */ + size = dip->d_dmabytes + NBPG; + addr = (int) dvma_alloc(size); + addr = sun3_round_page(addr); + si->si_dmaaddr = (char*) addr; #ifdef DEBUG_PROM + if (debug) printf("prom_iopen: dmaaddr=0x%x\n", si->si_dmaaddr); #endif } @@ -106,7 +116,8 @@ prom_iopen(si) if (dip->d_localbytes) { si->si_devdata = alloc(dip->d_localbytes); #ifdef DEBUG_PROM - printf("prom_iopen: devdata=0x%x\n", si->si_devdata); + if (debug) + printf("prom_iopen: devdata=0x%x\n", si->si_devdata); #endif } @@ -118,7 +129,8 @@ prom_iopen(si) return (ENXIO); } #ifdef DEBUG_PROM - printf("prom_iopen: succeeded, error=%d\n", error); + if (debug) + printf("prom_iopen: prom open returned %d\n", error); #endif promdev_inuse++; @@ -138,13 +150,12 @@ prom_iclose(si) ops = si->si_boottab; dip = ops->b_devinfo; +#ifdef DEBUG_PROM + if (debug) + printf("prom_iclose: calling prom close...\n"); +#endif (*ops->b_close)(si); - if (si->si_dmaaddr) { - dvma_free(si->si_dmaaddr, dip->d_dmabytes); - si->si_dmaaddr = NULL; - } - promdev_inuse = 0; } diff --git a/sys/arch/sun3/stand/netboot/conf.c b/sys/arch/sun3/stand/netboot/conf.c index 9f455eb0b9e..6b51da989bb 100644 --- a/sys/arch/sun3/stand/netboot/conf.c +++ b/sys/arch/sun3/stand/netboot/conf.c @@ -1,4 +1,4 @@ -/* $NetBSD: conf.c,v 1.2 1995/09/23 03:42:50 gwr Exp $ */ +/* $NetBSD: conf.c,v 1.3 1996/01/29 23:54:14 gwr Exp $ */ #include <sys/types.h> #include <netinet/in.h> @@ -17,7 +17,3 @@ struct devsw devsw[] = { }; int ndevs = 1; -/* XXX */ -int netif_debug; -int debug; -int errno; diff --git a/sys/arch/sun3/stand/netboot/dev_net.c b/sys/arch/sun3/stand/netboot/dev_net.c index 48a9064a29b..069b58ab519 100644 --- a/sys/arch/sun3/stand/netboot/dev_net.c +++ b/sys/arch/sun3/stand/netboot/dev_net.c @@ -1,4 +1,4 @@ -/* $NetBSD: dev_net.c,v 1.3 1995/09/23 03:42:51 gwr Exp $ */ +/* $NetBSD: dev_net.c,v 1.4 1996/01/29 23:54:15 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -48,6 +48,7 @@ * for use by the NFS open code (NFS/lookup). */ +#include <stdarg.h> #include <sys/param.h> #include <sys/socket.h> #include <net/if.h> @@ -59,7 +60,9 @@ #include "net.h" #include "netif.h" #include "bootparam.h" +#include "dev_net.h" +extern int debug; extern int nfs_root_node[]; /* XXX - get from nfs_mount() */ /* @@ -86,28 +89,63 @@ char domainname[FNAME_SIZE]; * Local things... */ static int netdev_sock = -1; -static int open_count; +static int netdev_opens; /* * Called by devopen after it sets f->f_dev to our devsw entry. * This opens the low-level device and sets f->f_devdata. + * This is declared with variable arguments... */ int -net_open(f, devname) - struct open_file *f; - char *devname; /* Device part of file name (or NULL). */ +net_open(struct open_file *f, ...) { + va_list ap; + char *devname; /* Device part of file name (or NULL). */ int error = 0; + va_start(ap, f); + devname = va_arg(ap, char*); + va_end(ap); + +#ifdef NETIF_DEBUG + if (debug) + printf("net_open: %s\n", devname); +#endif + /* On first open, do netif open, mount, etc. */ - if (open_count == 0) { + if (netdev_opens == 0) { /* Find network interface. */ - if ((netdev_sock = netif_open(devname)) < 0) - return (error=ENXIO); - if ((error = net_mountroot(f, devname)) != 0) + if (netdev_sock < 0) { + netdev_sock = netif_open(devname); + if (netdev_sock < 0) { + printf("net_open: netif_open() failed\n"); + return (ENXIO); + } + if (debug) + printf("net_open: netif_open() succeeded\n"); + } + if (rootip.s_addr == 0) { + /* Get root IP address, and path, etc. */ + error = net_getparams(netdev_sock); + if (error) { + /* getparams makes its own noise */ + goto fail; + } + /* Get the NFS file handle (mountd). */ + error = nfs_mount(netdev_sock, rootip, rootpath); + if (error) { + printf("net_open: NFS mount error=%d\n", error); + rootip.s_addr = 0; + fail: + netif_close(netdev_sock); + netdev_sock = -1; return (error); } - open_count++; + if (debug) + printf("net_open: NFS mount succeeded\n"); + } + } + netdev_opens++; f->f_devdata = nfs_root_node; return (error); } @@ -116,11 +154,29 @@ int net_close(f) struct open_file *f; { + +#ifdef NETIF_DEBUG + if (debug) + printf("net_close: opens=%d\n", netdev_opens); +#endif + /* On last close, do netif close, etc. */ - if (open_count > 0) - if (--open_count == 0) - netif_close(netdev_sock); f->f_devdata = NULL; + /* Extra close call? */ + if (netdev_opens <= 0) + return (0); + netdev_opens--; + /* Not last close? */ + if (netdev_opens > 0) + return(0); + rootip.s_addr = 0; + if (netdev_sock >= 0) { + if (debug) + printf("net_close: calling netif_close()\n"); + netif_close(netdev_sock); + netdev_sock = -1; + } + return (0); } int @@ -136,16 +192,9 @@ net_strategy() } int -net_mountroot(f, devname) - struct open_file *f; - char *devname; /* Device part of file name (or NULL). */ +net_getparams(sock) + int sock; { - int error; - -#ifdef DEBUG - printf("net_mountroot: %s\n", devname); -#endif - /* * Get info for NFS boot: our IP address, our hostname, * server IP address, and our root path on the server. @@ -155,23 +204,31 @@ net_mountroot(f, devname) #ifdef SUN_BOOTPARAMS /* Get our IP address. (rarp.c) */ - if (rarp_getipaddress(netdev_sock)) + if (rarp_getipaddress(sock)) { + printf("net_open: RARP failed\n"); return (EIO); + } #else /* BOOTPARAMS */ /* * Get boot info using BOOTP. (RFC951, RFC1048) * This also gets the server IP address, gateway, * root path, etc. */ - bootp(netdev_sock); /* XXX - Error return? */ + bootp(sock); + if (myip.s_addr == 0) { + printf("net_open: BOOTP failed\n"); + return (EIO); + } #endif /* BOOTPARAMS */ printf("boot: client addr: %s\n", inet_ntoa(myip)); #ifdef SUN_BOOTPARAMS /* Get our hostname, server IP address, gateway. */ - if (bp_whoami(netdev_sock)) + if (bp_whoami(sock)) { + printf("net_open: bootparam/whoami RPC failed\n"); return (EIO); + } #endif /* BOOTPARAMS */ printf("boot: client name: %s\n", hostname); @@ -182,15 +239,14 @@ net_mountroot(f, devname) #ifdef SUN_BOOTPARAMS /* Get the root pathname. */ - if (bp_getfile(netdev_sock, "root", &rootip, rootpath)) + if (bp_getfile(sock, "root", &rootip, rootpath)) { + printf("net_open: bootparam/getfile RPC failed\n"); return (EIO); + } #endif /* BOOTPARAMS */ printf("boot: server addr: %s\n", inet_ntoa(rootip)); printf("boot: server path: %s\n", rootpath); - /* Get the NFS file handle (mount). */ - error = nfs_mount(netdev_sock, rootip, rootpath); - - return (error); + return (0); } diff --git a/sys/arch/sun3/stand/netboot/version.c b/sys/arch/sun3/stand/netboot/version.c index c8f33eb39c9..aa92d773181 100644 --- a/sys/arch/sun3/stand/netboot/version.c +++ b/sys/arch/sun3/stand/netboot/version.c @@ -1,7 +1,7 @@ -/* $NetBSD: version.c,v 1.2 1995/10/13 21:33:09 gwr Exp $ */ +/* $NetBSD: version.c,v 1.5 1996/03/17 02:04:20 thorpej Exp $ */ /* * NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. */ -char *version = "$Revision: 1.2 $"; +char *version = "$Revision: 1.3 $"; diff --git a/sys/arch/sun3/stand/tapeboot/version.c b/sys/arch/sun3/stand/tapeboot/version.c index 37e2abc14ec..8f44b32e7ad 100644 --- a/sys/arch/sun3/stand/tapeboot/version.c +++ b/sys/arch/sun3/stand/tapeboot/version.c @@ -7,4 +7,4 @@ * device access stays strictly on block boundaries. */ -char *version = "$Revision: 1.2 $"; +char *version = "$Revision: 1.3 $"; diff --git a/sys/arch/sun3/sun3/autoconf.c b/sys/arch/sun3/sun3/autoconf.c index c8da822d40f..ce19dabe640 100644 --- a/sys/arch/sun3/sun3/autoconf.c +++ b/sys/arch/sun3/sun3/autoconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.c,v 1.27 1995/09/26 04:02:14 gwr Exp $ */ +/* $NetBSD: autoconf.c,v 1.33 1996/04/07 05:45:08 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -61,51 +61,22 @@ extern int soft1intr(); -void mainbusattach __P((struct device *, struct device *, void *)); void swapgeneric(); void swapconf(), dumpconf(); int cold; -struct mainbus_softc { - struct device mainbus_dev; -}; - -struct cfdriver mainbuscd = -{ NULL, "mainbus", always_match, mainbusattach, DV_DULL, - sizeof(struct mainbus_softc), 0}; - -void mainbusattach(parent, self, args) - struct device *parent; - struct device *self; - void *args; -{ - struct cfdata *new_match; - - printf("\n"); - while (1) { - new_match = config_search(NULL, self, NULL); - if (!new_match) break; - config_attach(self, new_match, NULL, NULL); - } -} - void configure() { - int root_found; - - /* Install non-device interrupt handlers. */ - isr_config(); + struct device *mainbus; /* General device autoconfiguration. */ - root_found = config_rootfound("mainbus", NULL); - if (!root_found) + mainbus = config_rootfound("mainbus", NULL); + if (mainbus == NULL) panic("configure: mainbus not found"); -#ifdef GENERIC /* Choose root and swap devices. */ swapgeneric(); -#endif swapconf(); dumpconf(); cold = 0; @@ -137,25 +108,30 @@ swapconf() } } -int always_match(parent, cf, args) - struct device *parent; - void *cf; - void *args; -{ - return 1; -} - /* * Generic "bus" support functions. + * + * bus_scan: + * This function is passed to config_search() by the attach function + * for each of the "bus" drivers (obctl, obio, obmem, vmes, vmel). + * The purpose of this function is to copy the "locators" into our + * confargs structure, so child drivers may use the confargs both + * as match parameters and as temporary storage for the defaulted + * locator values determined in the child_match and preserved for + * the child_attach function. If the bus attach functions just + * used config_found, then we would not have an opportunity to + * setup the confargs for each child match and attach call. + * + * bus_print: + * Just prints out the final (non-default) locators. */ -void bus_scan(parent, child, bustype) +int bus_scan(parent, child, aux) struct device *parent; - void *child; - int bustype; + void *child, *aux; { struct cfdata *cf = child; - struct confargs ca; - cfmatch_t match; + struct confargs *ca = aux; + cfmatch_t mf; #ifdef DIAGNOSTIC if (parent->dv_cfdata->cf_driver->cd_indirect) @@ -164,22 +140,33 @@ void bus_scan(parent, child, bustype) panic("bus_scan: FSTATE_STAR"); #endif - ca.ca_bustype = bustype; - ca.ca_paddr = cf->cf_loc[0]; - ca.ca_intpri = cf->cf_loc[1]; + /* ca->ca_bustype set by parent */ + ca->ca_paddr = cf->cf_loc[0]; + ca->ca_intpri = cf->cf_loc[1]; + ca->ca_intvec = -1; - if ((bustype == BUS_VME16) || (bustype == BUS_VME32)) { - ca.ca_intvec = cf->cf_loc[2]; - } else { - ca.ca_intvec = -1; + if ((ca->ca_bustype == BUS_VME16) || + (ca->ca_bustype == BUS_VME32)) + { + ca->ca_intvec = cf->cf_loc[2]; } - match = cf->cf_driver->cd_match; - if ((*match)(parent, cf, &ca) > 0) { - config_attach(parent, cf, &ca, bus_print); + /* + * Note that this allows the match function to save + * defaulted locators in the confargs that will be + * preserved for the related attach call. + */ + mf = cf->cf_attach->ca_match; + if ((*mf)(parent, cf, ca) > 0) { + config_attach(parent, cf, ca, bus_print); } + return (0); } +/* + * Print out the confargs. The parent name is non-NULL + * when there was no match found by config_found(). + */ int bus_print(args, name) void *args; @@ -187,14 +174,17 @@ bus_print(args, name) { struct confargs *ca = args; + if (name) + printf("%s:", name); + if (ca->ca_paddr != -1) printf(" addr 0x%x", ca->ca_paddr); if (ca->ca_intpri != -1) printf(" level %d", ca->ca_intpri); if (ca->ca_intvec != -1) printf(" vector 0x%x", ca->ca_intvec); - /* XXXX print flags? */ - return(QUIET); + + return(UNCONF); } extern vm_offset_t tmp_vpages[]; @@ -269,7 +259,7 @@ bus_mapin(bustype, paddr, sz) int bustype, paddr, sz; { int off, pa, pgs, pmt; - vm_offset_t va; + vm_offset_t va, retval; if (bustype & ~3) return (NULL); @@ -286,9 +276,19 @@ bus_mapin(bustype, paddr, sz) va = kmem_alloc_wait(kernel_map, sz); if (va == 0) panic("bus_mapin"); + retval = va + off; /* Map it to the specified bus. */ +#if 0 /* XXX */ + /* This has a problem with wrap-around... */ pmap_map((int)va, pa | pmt, pa + sz, VM_PROT_ALL); +#else + do { + pmap_enter(pmap_kernel(), va, pa | pmt, VM_PROT_ALL, FALSE); + va += NBPG; + pa += NBPG; + } while ((sz -= NBPG) > 0); +#endif - return ((char*)(va + off)); + return ((char*)retval); } diff --git a/sys/arch/sun3/sun3/clock.c b/sys/arch/sun3/sun3/clock.c index fdb6dc82c4f..eb53ac66222 100644 --- a/sys/arch/sun3/sun3/clock.c +++ b/sys/arch/sun3/sun3/clock.c @@ -1,4 +1,4 @@ -/* $NetBSD: clock.c,v 1.26 1995/08/21 21:37:36 gwr Exp $ */ +/* $NetBSD: clock.c,v 1.28 1996/03/26 15:16:42 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -65,6 +65,8 @@ #include "intersil7170.h" #include "interreg.h" +#define CLOCK_PRI 5 + extern volatile u_char *interrupt_reg; volatile char *clock_va; @@ -76,40 +78,63 @@ volatile char *clock_va; #define intersil_clear() (void)intersil_clock->clk_intr_reg -int clockmatch __P((struct device *, void *vcf, void *args)); -void clockattach __P((struct device *, struct device *, void *)); +static int clock_match __P((struct device *, void *vcf, void *args)); +static void clock_attach __P((struct device *, struct device *, void *)); + +struct cfattach clock_ca = { + sizeof(struct device), clock_match, clock_attach +}; -struct cfdriver clockcd = { - NULL, "clock", clockmatch, clockattach, - DV_DULL, sizeof(struct device), 0 }; +struct cfdriver clock_cd = { + NULL, "clock", DV_DULL +}; -int clockmatch(parent, vcf, args) +static int +clock_match(parent, vcf, args) struct device *parent; void *vcf, *args; { struct cfdata *cf = vcf; struct confargs *ca = args; + int pa; /* This driver only supports one unit. */ if (cf->cf_unit != 0) return (0); - if (ca->ca_paddr == -1) - ca->ca_paddr = OBIO_CLOCK; - if (ca->ca_intpri == -1) - ca->ca_intpri = 5; + + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_CLOCK; + } else { + /* Validate the given PA. */ + if (pa != OBIO_CLOCK) + panic("clock: wrong address"); + } + if (pa != ca->ca_paddr) + return (0); + return (1); } -void clockattach(parent, self, args) +static void +clock_attach(parent, self, args) struct device *parent; struct device *self; void *args; { + struct cfdata *cf = self->dv_cfdata; struct confargs *ca = args; + int pri; + + if ((pri = cf->cf_intpri) == -1) { + pri = CLOCK_PRI; + } else { + if (pri != CLOCK_PRI) + panic("clock: level != %d", CLOCK_PRI); + } + + printf(" level %d\n", pri); - printf("\n"); - if (ca->ca_intpri != 5) - panic("clock: level != 5"); /* * Can not hook up the ISR until cpu_initclock() * because hardclock is not ready until then. diff --git a/sys/arch/sun3/sun3/conf.c b/sys/arch/sun3/sun3/conf.c index 63be5b4b7c4..f7e6e088c3d 100644 --- a/sys/arch/sun3/sun3/conf.c +++ b/sys/arch/sun3/sun3/conf.c @@ -1,4 +1,4 @@ -/* $NetBSD: conf.c,v 1.46 1996/01/24 22:40:58 gwr Exp $ */ +/* $NetBSD: conf.c,v 1.48 1996/03/14 21:35:47 christos Exp $ */ /*- * Copyright (c) 1994 Adam Glass, Gordon W. Ross @@ -125,7 +125,7 @@ cdev_decl(ctty); #define mmwrite mmrw cdev_decl(mm); -#include "zs.h" +#define NZS 2 /* XXX: temporary hack */ cdev_decl(zs); cdev_decl(kd); cdev_decl(ms); @@ -164,6 +164,8 @@ cdev_decl(bpf); #include "tun.h" cdev_decl(tun); +dev_decl(filedesc,open); + struct cdevsw cdevsw[] = { @@ -190,7 +192,7 @@ struct cdevsw cdevsw[] = cdev_tty_init(NPTY,pts), /* 20: pseudo-tty slave */ cdev_ptc_init(NPTY,ptc), /* 21: pseudo-tty master */ cdev_fb_init(1,fb), /* 22: /dev/fb indirect driver */ - cdev_fd_init(1,fd), /* 23: file descriptor pseudo-device */ + cdev_fd_init(1,filedesc), /* 23: file descriptor pseudo-device */ cdev_bpftun_init(NTUN,tun), /* 24: network tunnel */ cdev_notdef(), /* 25: sun pi? */ cdev_notdef(), /* 26: bwone */ diff --git a/sys/arch/sun3/sun3/db_machdep.c b/sys/arch/sun3/sun3/db_machdep.c index b8fc34692e4..bcccb93b70c 100644 --- a/sys/arch/sun3/sun3/db_machdep.c +++ b/sys/arch/sun3/sun3/db_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: db_machdep.c,v 1.6 1995/10/23 18:40:35 gwr Exp $ */ +/* $NetBSD: db_machdep.c,v 1.7 1996/02/16 20:08:44 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -44,149 +44,6 @@ #include <machine/pte.h> -#undef DEBUG - -#ifdef DEBUG -int db_machdep_debug; -#endif - -/* - * Interface to the debugger for virtual memory read/write. - * - * To write in the text segment, we have to first make - * the page writable, do the write, then restore the PTE. - * For writes outside the text segment, and all reads, - * just do the access -- if it causes a fault, the debugger - * will recover with a longjmp to an appropriate place. - * - * ALERT! If you want to access device registers with a - * specific size, then the read/write functions have to - * make sure to do the correct sized pointer access. - */ - -/* - * Read bytes from kernel address space for debugger. - * This used to check for valid PTEs, but now that - * traps in DDB work correctly, "Just Do It!" - */ -void -db_read_bytes(addr, size, data) - vm_offset_t addr; - register int size; - register char *data; -{ - register char *src; - register char incr; - -#ifdef DEBUG - if (db_machdep_debug) - printf("db_read_bytes: addr=0x%x, size=%d\n", addr, size); -#endif - - if (size == 4) { - *((int*)data) = *((int*)addr); - return; - } - - if (size == 2) { - *((short*)data) = *((short*)addr); - return; - } - - src = (char *)addr; - while (size > 0) { - --size; - *data++ = *src++; - } -} - -/* - * Write one byte somewhere in kernel text. - * It does not matter if this is slow. - */ -static void -db_write_text(dst, ch) - char *dst; - int ch; -{ - int oldpte, tmppte; - vm_offset_t pgva = sun3_trunc_page((long)dst); - extern int cache_size; - - /* Flush read-only VAC entry so we'll see the new one. */ -#ifdef HAVECACHE - if (cache_size) - cache_flush_page(pgva); -#endif - oldpte = get_pte(pgva); - if ((oldpte & PG_VALID) == 0) { - db_printf(" address 0x%x not a valid page\n", dst); - return; - } - tmppte = oldpte | PG_WRITE | PG_NC; - - set_pte(pgva, tmppte); - - /* Now we can write in this page of kernel text... */ - *dst = (char) ch; - - /* Temporary PTE was non-cacheable; no flush needed. */ - set_pte(pgva, oldpte); - ICIA(); -} - -/* - * Write bytes to kernel address space for debugger. - */ -void -db_write_bytes(addr, size, data) - vm_offset_t addr; - int size; - char *data; -{ - extern char kernel_text[], etext[] ; - register char *dst = (char *)addr; - -#ifdef DEBUG - if (db_machdep_debug) - printf("db_write_bytes: addr=0x%x, size=%d ", addr, size); -#endif - - /* If any part is in kernel text, use db_write_text() */ - if ((dst < etext) && ((dst + size) > kernel_text)) { - /* This is slow, but is only used for breakpoints. */ -#ifdef DEBUG - if (db_machdep_debug) - printf("(in text)\n"); -#endif - while (size > 0) { - --size; - db_write_text(dst, *data); - dst++; data++; - } - return; - } - -#ifdef DEBUG - if (db_machdep_debug) - printf("(in data)\n"); -#endif - - if (size == 4) { - *((int*)addr) = *((int*)data); - return; - } - - if (size == 2) { - *((short*)addr) = *((short*)data); - return; - } - - while (size > 0) { - --size; - *dst++ = *data++; - } -} static char *pgt_names[] = { "MEM", "OBIO", "VMES", "VMEL" }; diff --git a/sys/arch/sun3/sun3/db_memrw.c b/sys/arch/sun3/sun3/db_memrw.c new file mode 100644 index 00000000000..59db0e08a79 --- /dev/null +++ b/sys/arch/sun3/sun3/db_memrw.c @@ -0,0 +1,187 @@ +/* $NetBSD: db_memrw.c,v 1.11 1996/02/20 02:42:55 gwr Exp $ */ + +/* + * Copyright (c) 1996 Gordon W. Ross + * 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. 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. + */ + +/* + * Interface to the debugger for virtual memory read/write. + * + * To write in the text segment, we have to first make + * the page writable, do the write, then restore the PTE. + * For writes outside the text segment, and all reads, + * just do the access -- if it causes a fault, the debugger + * will recover with a longjmp to an appropriate place. + * + * ALERT! If you want to access device registers with a + * specific size, then the read/write functions have to + * make sure to do the correct sized pointer access. + */ + +#include <sys/param.h> +#include <sys/proc.h> + +#include <vm/vm.h> + +#include <machine/pte.h> +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> + +#include "cache.h" + +/* + * Read bytes from kernel address space for debugger. + * This used to check for valid PTEs, but now that + * traps in DDB work correctly, "Just Do It!" + */ +void +db_read_bytes(addr, size, data) + vm_offset_t addr; + register size_t size; + register char *data; +{ + register char *src = (char*)addr; + + if (size == 4) { + *((int*)data) = *((int*)src); + return; + } + + if (size == 2) { + *((short*)data) = *((short*)src); + return; + } + + while (size > 0) { + --size; + *data++ = *src++; + } +} + +/* + * Write bytes somewhere in kernel text. + * Makes text page writable temporarily. + */ +static void +db_write_text(addr, size, data) + vm_offset_t addr; + register size_t size; + register char *data; +{ + register char *dst; + int ch, oldpte, tmppte; + vm_offset_t pgva, prevpg; + + /* Prevent restoring a garbage PTE. */ + if (size <= 0) + return; + + dst = (char*)addr; + pgva = sun3_trunc_page((long)dst); + + goto firstpage; + do { + + /* + * If we are on a new page, restore the PTE + * for the previous page, and make the new + * page writable. + */ + pgva = sun3_trunc_page((long)dst); + if (pgva != prevpg) { + /* + * Restore old PTE. No cache flush, + * because the tmp PTE has no-cache. + */ + set_pte(prevpg, oldpte); + + firstpage: + /* + * Flush the VAC to prevent a cache hit + * on the old, read-only PTE. + */ +#ifdef HAVECACHE + if (cache_size) + cache_flush_page(pgva); +#endif + oldpte = get_pte(pgva); + if ((oldpte & PG_VALID) == 0) { + db_printf(" address 0x%x not a valid page\n", dst); + return; + } + tmppte = oldpte | PG_WRITE | PG_NC; + set_pte(pgva, tmppte); + + prevpg = pgva; + } + + /* Now we can write in this page of kernel text... */ + *dst++ = *data++; + + } while (--size > 0); + + /* Restore old PTE for the last page touched. */ + set_pte(prevpg, oldpte); + + /* Finally, clear the instruction cache. */ + ICIA(); +} + +/* + * Write bytes to kernel address space for debugger. + */ +extern char kernel_text[], etext[]; +void +db_write_bytes(addr, size, data) + vm_offset_t addr; + register size_t size; + register char *data; +{ + register char *dst = (char *)addr; + + /* If any part is in kernel text, use db_write_text() */ + if ((dst < etext) && ((dst + size) > kernel_text)) { + db_write_text(dst, size, data); + return; + } + + if (size == 4) { + *((int*)dst) = *((int*)data); + return; + } + + if (size == 2) { + *((short*)dst) = *((short*)data); + return; + } + + while (size > 0) { + --size; + *dst++ = *data++; + } +} + diff --git a/sys/arch/sun3/sun3/disksubr.c b/sys/arch/sun3/sun3/disksubr.c index baa89a823ba..fb78c2014e9 100644 --- a/sys/arch/sun3/sun3/disksubr.c +++ b/sys/arch/sun3/sun3/disksubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: disksubr.c,v 1.11 1995/11/17 23:30:19 gwr Exp $ */ +/* $NetBSD: disksubr.c,v 1.12 1996/04/26 18:37:58 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -273,12 +273,21 @@ bad: return(-1); } -/* XXX - What is this for? Where does it belong? -gwr */ +/* + * This function appears to be called by each disk driver. + * Aparently this is to give this MD code a chance to do + * additional "device registration" types of work. (?) + * For example, the sparc port uses this to record the + * device node for the PROM-specified boot device. + * + * XXX: return value not documented (ignored everywhere) + */ void dk_establish(dk, dev) - struct dkdevice *dk; + struct disk *dk; struct device *dev; { + return; } /************************************************************************ diff --git a/sys/arch/sun3/sun3/dvma.c b/sys/arch/sun3/sun3/dvma.c index 0cf422efea9..a2e510d9897 100644 --- a/sys/arch/sun3/sun3/dvma.c +++ b/sys/arch/sun3/sun3/dvma.c @@ -1,4 +1,4 @@ -/* $NetBSD: dvma.c,v 1.3 1995/10/10 21:37:29 gwr Exp $ */ +/* $NetBSD: dvma.c,v 1.4 1996/02/20 22:05:32 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -56,36 +56,44 @@ #include "cache.h" /* Resource map used by dvma_mapin/dvma_mapout */ -#define NUM_DVMA_SEGS ((DVMA_SEGMAP_SIZE / NBSG) + 1) +#define NUM_DVMA_SEGS 10 struct map dvma_segmap[NUM_DVMA_SEGS]; -/* DVMA page map managed with help from the VM system. */ -vm_map_t dvma_pgmap; +/* XXX: Might need to tune this... */ +vm_size_t dvma_segmap_size = 6 * NBSG; + +/* Using phys_map to manage DVMA scratch-memory pages. */ /* Note: Could use separate pagemap for obio if needed. */ void dvma_init() { - int size; + vm_offset_t segmap_addr; /* - * Create the map used for small, permanent DVMA page - * allocations, such as may be needed by drivers for - * control structures shared with the device. + * Create phys_map covering the entire DVMA space, + * then allocate the segment pool from that. The + * remainder will be used as the DVMA page pool. */ - dvma_pgmap = vm_map_create(pmap_kernel(), - DVMA_PAGEMAP_BASE, DVMA_PAGEMAP_END, TRUE); - if (dvma_pgmap == NULL) - panic("dvma_init: unable to create DVMA page map."); + phys_map = vm_map_create(pmap_kernel(), + DVMA_SPACE_START, DVMA_SPACE_END, 1); + if (phys_map == NULL) + panic("unable to create DVMA map"); + + /* + * Reserve the DVMA space used for segment remapping. + * The remainder of phys_map is used for DVMA scratch + * memory pages (i.e. driver control blocks, etc.) + */ + segmap_addr = kmem_alloc_wait(phys_map, dvma_segmap_size); + if (segmap_addr != DVMA_SPACE_START) + panic("dvma_init: unable to allocate DVMA segments"); /* * Create the VM pool used for mapping whole segments * into DVMA space for the purpose of data transfer. */ - rminit(dvma_segmap, - DVMA_SEGMAP_SIZE, - DVMA_SEGMAP_BASE, - "dvma_segmap", - NUM_DVMA_SEGS); + rminit(dvma_segmap, dvma_segmap_size, segmap_addr, + "dvma_segmap", NUM_DVMA_SEGS); } /* @@ -101,9 +109,9 @@ caddr_t dvma_malloc(bytes) if (!bytes) return NULL; new_size = sun3_round_page(bytes); - new_mem = (caddr_t) kmem_alloc(dvma_pgmap, new_size); + new_mem = (caddr_t) kmem_alloc(phys_map, new_size); if (!new_mem) - panic("dvma_malloc: no space in dvma_pgmap"); + panic("dvma_malloc: no space in phys_map"); /* The pmap code always makes DVMA pages non-cached. */ return new_mem; } @@ -115,7 +123,9 @@ void dvma_free(addr, size) caddr_t addr; size_t size; { - kmem_free(dvma_pgmap, (vm_offset_t)addr, (vm_size_t)size); + vm_size_t sz = sun3_round_page(size); + + kmem_free(phys_map, (vm_offset_t)addr, sz); } /* diff --git a/sys/arch/sun3/sun3/fpu.c b/sys/arch/sun3/sun3/fpu.c index f19a1de509c..c6023af3b45 100644 --- a/sys/arch/sun3/sun3/fpu.c +++ b/sys/arch/sun3/sun3/fpu.c @@ -1,4 +1,4 @@ -/* $NetBSD: fpu.c,v 1.2 1995/06/27 14:40:14 gwr Exp $ */ +/* $NetBSD: fpu.c,v 1.6 1996/03/26 15:16:45 gwr Exp $ */ /* * Copyright (c) 1995 Gordon W. Ross @@ -41,42 +41,19 @@ #include <sys/kernel.h> #include <sys/device.h> -#include <machine/autoconf.h> #include <machine/psl.h> #include <machine/cpu.h> #include <machine/frame.h> #include <machine/mon.h> #include <machine/control.h> -#include <setjmp.h> - #include "interreg.h" extern int fpu_type; extern long *nofault; -int fpu_match __P((struct device *, void *vcf, void *args)); -void fpu_attach __P((struct device *, struct device *, void *)); int fpu_probe(); -struct cfdriver fpucd = { - NULL, "fpu", fpu_match, fpu_attach, - DV_DULL, sizeof(struct device), 0 }; - -int fpu_match(parent, vcf, args) - struct device *parent; - void *vcf, *args; -{ - struct cfdata *cf = vcf; - struct confargs *ca = args; - - /* This driver only supports one unit. */ - if (cf->cf_unit != 0) - return (0); - - return (1); -} - static char *fpu_descr[] = { #ifdef FPU_EMULATE "emulator", /* 0 */ @@ -87,12 +64,8 @@ static char *fpu_descr[] = { "mc68882", /* 2 */ "?" }; -void fpu_attach(parent, self, args) - struct device *parent; - struct device *self; - void *args; +void initfpu() { - struct confargs *ca = args; char *descr; int enab_reg; @@ -107,7 +80,7 @@ void fpu_attach(parent, self, args) else descr = "unknown type"; - printf(" (%s)\n", descr); + printf("fpu: %s\n", descr); if (fpu_type == 0) { /* Might as well turn the enable bit back off. */ @@ -119,11 +92,11 @@ void fpu_attach(parent, self, args) int fpu_probe() { - jmp_buf faultbuf; + label_t faultbuf; int null_fpframe[2]; nofault = (long *) &faultbuf; - if (setjmp(nofault)) { + if (setjmp(&faultbuf)) { nofault = NULL; return(0); } diff --git a/sys/arch/sun3/sun3/genassym.c b/sys/arch/sun3/sun3/genassym.c index eb690871edd..a8f40b82db9 100644 --- a/sys/arch/sun3/sun3/genassym.c +++ b/sys/arch/sun3/sun3/genassym.c @@ -1,4 +1,4 @@ -/* $NetBSD: genassym.c,v 1.29 1995/09/26 04:02:19 gwr Exp $ */ +/* $NetBSD: genassym.c,v 1.31 1996/02/16 23:36:52 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -38,8 +38,6 @@ * from: genassym.c,v 1.9 1994/05/23 06:14:19 mycroft */ -#define _KERNEL - #include <sys/param.h> #include <sys/types.h> #include <sys/cdefs.h> @@ -171,6 +169,7 @@ main() def("FR_SP", &fp->f_regs[15]); def("FR_HW", &fp->f_sr); def("FR_ADJ", &fp->f_stackadj); + def("FR_SIZE", sizeof(struct trapframe)); /* FP frame offsets */ def("FPF_REGS", &fpf->fpf_regs[0]); diff --git a/sys/arch/sun3/sun3/intreg.c b/sys/arch/sun3/sun3/intreg.c new file mode 100644 index 00000000000..63e4eb1cbb6 --- /dev/null +++ b/sys/arch/sun3/sun3/intreg.c @@ -0,0 +1,217 @@ +/* $NetBSD: intreg.c,v 1.1 1996/03/26 15:03:11 gwr Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * 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 Adam Glass. + * 4. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * This handles multiple attach of autovectored interrupts, + * and the handy software interrupt request register. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/vmmeter.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/mon.h> +#include <machine/obio.h> +#include <machine/isr.h> + +#include "interreg.h" + +struct intreg_softc { + struct device sc_dev; + volatile u_char *sc_reg; +}; + +static int intreg_match __P((struct device *, void *vcf, void *args)); +static void intreg_attach __P((struct device *, struct device *, void *)); +static int soft1intr(); + +struct cfattach intreg_ca = { + sizeof(struct intreg_softc), intreg_match, intreg_attach +}; + +struct cfdriver intreg_cd = { + NULL, "intreg", DV_DULL +}; + +volatile u_char *interrupt_reg; + + +/* called early (by internal_configure) */ +void intreg_init() +{ + interrupt_reg = obio_find_mapping(OBIO_INTERREG, 1); + if (!interrupt_reg) + mon_panic("interrupt reg VA not found\n"); + /* Turn off all interrupts until clock_attach */ + *interrupt_reg = 0; +} + + +static int +intreg_match(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + int pa; + + /* This driver only supports one unit. */ + if (cf->cf_unit != 0) + return (0); + + if ((pa = cf->cf_paddr) == -1) { + /* Use our default PA. */ + pa = OBIO_INTERREG; + } else { + /* Validate the given PA. */ + if (pa != OBIO_INTERREG) + panic("clock: wrong address"); + } + if (pa != ca->ca_paddr) + return (0); + + return (1); +} + + +static void +intreg_attach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + struct intreg_softc *sc = (void *)self; + struct cfdata *cf = self->dv_cfdata; + + printf("\n"); + + sc->sc_reg = interrupt_reg; + + /* Install handler for our "soft" interrupt. */ + isr_add_autovect(soft1intr, (void *)sc, 1); +} + + +/* + * Level 1 software interrupt. + * Possible reasons: + * Network software interrupt + * Soft clock interrupt + */ +int soft1intr(arg) + void *arg; +{ + union sun3sir sir; + int n, s; + + s = splhigh(); + sir.sir_any = sun3sir.sir_any; + sun3sir.sir_any = 0; + isr_soft_clear(1); + splx(s); + + if (sir.sir_any) { + cnt.v_soft++; + if (sir.sir_which[SIR_NET]) { + sir.sir_which[SIR_NET] = 0; + netintr(); + } + if (sir.sir_which[SIR_CLOCK]) { + sir.sir_which[SIR_CLOCK] = 0; + softclock(); + } + if (sir.sir_which[SIR_SPARE2]) { + sir.sir_which[SIR_SPARE2] = 0; + /* spare2intr(); */ + } + if (sir.sir_which[SIR_SPARE3]) { + sir.sir_which[SIR_SPARE3] = 0; + /* spare3intr(); */ + } + return (1); + } + return(0); +} + + +static int isr_soft_pending; +void isr_soft_request(level) + int level; +{ + u_char bit, reg_val; + int s; + + if ((level < 1) || (level > 3)) + panic("isr_soft_request"); + + bit = 1 << level; + + /* XXX - Should do this in the callers... */ + if (isr_soft_pending & bit) + return; + + s = splhigh(); + isr_soft_pending |= bit; + reg_val = *interrupt_reg; + *interrupt_reg &= ~IREG_ALL_ENAB; + + *interrupt_reg |= bit; + *interrupt_reg |= IREG_ALL_ENAB; + splx(s); +} + +void isr_soft_clear(level) + int level; +{ + u_char bit, reg_val; + int s; + + if ((level < 1) || (level > 3)) + panic("isr_soft_clear"); + + bit = 1 << level; + + s = splhigh(); + isr_soft_pending &= ~bit; + reg_val = *interrupt_reg; + *interrupt_reg &= ~IREG_ALL_ENAB; + + *interrupt_reg &= ~bit; + *interrupt_reg |= IREG_ALL_ENAB; + splx(s); +} + diff --git a/sys/arch/sun3/sun3/isr.c b/sys/arch/sun3/sun3/isr.c index de638e7b7e9..6a7312d45c9 100644 --- a/sys/arch/sun3/sun3/isr.c +++ b/sys/arch/sun3/sun3/isr.c @@ -1,4 +1,4 @@ -/* $NetBSD: isr.c,v 1.21 1995/10/08 23:47:34 gwr Exp $ */ +/* $NetBSD: isr.c,v 1.22 1996/03/26 15:16:47 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -49,7 +49,6 @@ #include <machine/isr.h> #include "vector.h" -#include "interreg.h" #include "ether.h" /* for NETHER */ @@ -64,30 +63,8 @@ struct isr { int isr_ipl; }; - void set_vector_entry __P((int, void (*handler)())); unsigned int get_vector_entry __P((int)); -static int nmi_intr(); -static int soft1intr(); - -volatile u_char *interrupt_reg; - -/* called early (by internal_configure) */ -void isr_init() -{ - interrupt_reg = obio_find_mapping(OBIO_INTERREG, 1); - if (!interrupt_reg) - mon_panic("interrupt reg VA not found\n"); - /* Turn off all interrupts until clock_attach */ - *interrupt_reg = 0; -} - -/* called later, by configure */ -void isr_config() -{ - isr_add_autovect(nmi_intr, 0, 7); - isr_add_autovect(soft1intr, 0, 1); -} void isr_add_custom(level, handler) int level; @@ -96,53 +73,6 @@ void isr_add_custom(level, handler) set_vector_entry(AUTOVEC_BASE + level, handler); } -static int isr_soft_pending; -void isr_soft_request(level) - int level; -{ - u_char bit, reg_val; - int s; - - if ((level < 1) || (level > 3)) - panic("isr_soft_request"); - - bit = 1 << level; - - /* XXX - Should do this in the callers... */ - if (isr_soft_pending & bit) - return; - - s = splhigh(); - isr_soft_pending |= bit; - reg_val = *interrupt_reg; - *interrupt_reg &= ~IREG_ALL_ENAB; - - *interrupt_reg |= bit; - *interrupt_reg |= IREG_ALL_ENAB; - splx(s); -} - -void isr_soft_clear(level) - int level; -{ - u_char bit, reg_val; - int s; - - if ((level < 1) || (level > 3)) - panic("isr_soft_clear"); - - bit = 1 << level; - - s = splhigh(); - isr_soft_pending &= ~bit; - reg_val = *interrupt_reg; - *interrupt_reg &= ~IREG_ALL_ENAB; - - *interrupt_reg &= ~bit; - *interrupt_reg |= IREG_ALL_ENAB; - splx(s); -} - /* * XXX - This really belongs in some common file, * i.e. src/sys/net/netisr.c @@ -188,63 +118,6 @@ void netintr() } -/* - * Level 1 software interrupt. - * Possible reasons: - * Network software interrupt - * Soft clock interrupt - */ -int soft1intr(arg) - void *arg; -{ - union sun3sir sir; - int n, s; - - s = splhigh(); - sir.sir_any = sun3sir.sir_any; - sun3sir.sir_any = 0; - isr_soft_clear(1); - splx(s); - - if (sir.sir_any) { - cnt.v_soft++; - if (sir.sir_which[SIR_NET]) { - sir.sir_which[SIR_NET] = 0; - netintr(); - } - if (sir.sir_which[SIR_CLOCK]) { - sir.sir_which[SIR_CLOCK] = 0; - softclock(); - } - if (sir.sir_which[SIR_SPARE2]) { - sir.sir_which[SIR_SPARE2] = 0; - /* spare2intr(); */ - } - if (sir.sir_which[SIR_SPARE3]) { - sir.sir_which[SIR_SPARE3] = 0; - /* spare3intr(); */ - } - return (1); - } - return(0); -} - -/* - * Generic handler for the non-maskable interrupt. - * XXX: Should check memory error register here! - */ -int nmi_intr(arg) - void *arg; -{ - static int nmi_cnt; - if (!nmi_cnt++) { - printf("nmi interrupt received\n"); - Debugger(); - } - return 1; -} - - static struct isr *isr_autovec_list[NUM_LEVELS]; /* diff --git a/sys/arch/sun3/sun3/locore.s b/sys/arch/sun3/sun3/locore.s index f4a66acd68f..b7f384f7d59 100644 --- a/sys/arch/sun3/sun3/locore.s +++ b/sys/arch/sun3/sun3/locore.s @@ -1,4 +1,4 @@ -/* $NetBSD: locore.s,v 1.34 1995/12/11 02:38:13 thorpej Exp $ */ +/* $NetBSD: locore.s,v 1.38 1996/04/07 05:42:17 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -43,7 +43,7 @@ * @(#)locore.s 8.6 (Berkeley) 5/27/94 */ -#include "assym.s" +#include "assym.h" #include <machine/trap.h> | Remember this is a fun project. (Thanks, Adam. I try! 8^) @@ -421,6 +421,9 @@ _badtrap: addql #4, sp | stack adjust count jra rei | all done +/* + * Trap 0 is for system calls + */ .globl _syscall _trap0: clrl sp@- | stack adjust count @@ -437,69 +440,16 @@ _trap0: jra rei | all done /* - * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2 - * as a breakpoint trap. + * Trap 1 is either: + * sigreturn (native NetBSD executable) + * breakpoint (HPUX executable) */ _trap1: - jra sigreturn - -_trap2: - jra _trace - -/* - * Trap 12 is the entry point for the cachectl "syscall" - * cachectl(command, addr, length) - * command in d0, addr in a1, length in d1 - */ - .globl _cachectl -_trap12: - movl d1,sp@- | push length - movl a1,sp@- | push addr - movl d0,sp@- | push command - jbsr _cachectl | do it - lea sp@(12),sp | pop args - jra rei | all done - -/* - * Trap 15 is used for: - * - KGDB traps - * - trace traps for SUN binaries (not fully supported yet) - * We just pass it on and let trap() sort it all out - */ -_trap15: - clrl sp@- - moveml #0xFFFF,sp@- -#ifdef KGDB - moveq #T_TRAP15,d0 - movw sp@(FR_HW),d1 | get PSW - andw #PSL_S,d1 | from user mode? - jeq fault | yes, just a regular fault - movl d0,sp@- - .globl _kgdb_trap_glue - jbsr _kgdb_trap_glue | returns if no debugger - addl #4,sp +#if 0 /* COMPAT_HPUX */ + /* If process is HPUX, this is a user breakpoint. */ + jne trap15 | breakpoint #endif - moveq #T_TRAP15,d0 - jra fault - -/* - * Hit a breakpoint (trap 1 or 2) instruction. - * Push the code and treat as a normal fault. - */ -_trace: - clrl sp@- - moveml #0xFFFF,sp@- -#ifdef KGDB - moveq #T_TRACE,d0 - movw sp@(FR_HW),d1 | get SSW - andw #PSL_S,d1 | from user mode? - jeq fault | no, regular fault - movl d0,sp@- - jbsr _kgdb_trap_glue | returns if no debugger - addl #4,sp -#endif - moveq #T_TRACE,d0 - jra fault + /* fall into sigreturn */ /* * The sigreturn() syscall comes here. It requires special handling @@ -539,6 +489,104 @@ Lsigr1: jra rei | all done /* + * Trap 2 is one of: + * NetBSD: not used (ignore) + * SunOS: Some obscure FPU operation + * HPUX: sigreturn + */ +_trap2: +#if 0 /* COMPAT_HPUX */ + /* XXX: If HPUX, this is a user breakpoint. */ + jne sigreturn +#endif + /* fall into trace (NetBSD or SunOS) */ + +/* + * Trace (single-step) trap. Kernel-mode is special. + * User mode traps are simply passed on to trap(). + */ +_trace: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- + moveq #T_TRACE,d0 + movw sp@(FR_HW),d1 | get PSW + andw #PSL_S,d1 | from system mode? + jne kbrkpt | yes, kernel breakpoint + jra fault | no, user-mode fault + +/* + * Trap 15 is used for: + * - GDB breakpoints (in user programs) + * - KGDB breakpoints (in the kernel) + * - trace traps for SUN binaries (not fully supported yet) + * User mode traps are passed simply passed to trap() + */ +_trap15: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- + moveq #T_TRAP15,d0 + movw sp@(FR_HW),d1 | get PSW + andw #PSL_S,d1 | from system mode? + jne kbrkpt | yes, kernel breakpoint + jra fault | no, user-mode fault + +kbrkpt: | Kernel-mode breakpoint or trace trap. + | Save system sp rather than user sp. + lea sp@(FR_SIZE),a6 | Save stack pointer + movl a6,sp@(FR_SP) | from before trap + + | If we are not on tmpstk switch to it. + | (allows debugger to frob the stack) + movl a6,d1 + cmpl #tmpstk,d1 + jls Lbrkpt2 | already on tmpstk + | Copy frame to the temporary stack + movl sp,a0 | a0=src + lea tmpstk-96,a1 | a1=dst + movl a1,sp | sp=new frame + moveq #FR_SIZE,d1 +Lbrkpt1: + movl a0@+,a1@+ + subql #4,d1 + bgt Lbrkpt1 + +Lbrkpt2: + | Now call the trap handler as usual. + clrl sp@- | no VA arg + clrl sp@- | or code arg + movl d0,sp@- | push trap type + jbsr _trap | handle trap + lea sp@(12),sp | pop value args + + | The stack pointer may have been modified, or + | data below it modified (by kgdb push call), + | so push the hardware frame at the current sp + | before restoring registers and returning. + + movl sp@(FR_SP),a0 | modified sp + lea sp@(FR_SIZE),a1 | end of our frame + movl a1@-,a0@- | copy 2 longs with + movl a1@-,a0@- | ... predecrement + movl a0,sp@(FR_SP) | sp = h/w frame + moveml sp@+,#0x7FFF | restore all but sp + movl sp@,sp | ... and sp + rte | all done + +/* + * Trap 12 is the entry point for the cachectl "syscall" + * cachectl(command, addr, length) + * command in d0, addr in a1, length in d1 + */ + .globl _cachectl +_trap12: + movl d1,sp@- | push length + movl a1,sp@- | push addr + movl d0,sp@- | push command + jbsr _cachectl | do it + lea sp@(12),sp | pop args + jra rei | all done + +/* * Interrupt handlers. Most are auto-vectored, * and hard-wired the same way on all sun3 models. */ @@ -1182,26 +1230,23 @@ Lm68881rdone: frestore a0@ | restore state rts -| delay(int usecs) -| Delay for "usec" microseconds. Minimum delay is about 5 uS. -| -| This routine depends on the variable "cpuspeed" -| which should be set based on the CPU clock rate. -| XXX - Currently this is set in sun3_startup.c based on the -| CPU model but this should be determined at run time... -| - .globl _delay -_delay: - | d0 = (cpuspeed * usecs) - movel _cpuspeed,d0 - mulsl sp@(4),d0 - | subtract some overhead - moveq #80,d1 +/* + * _delay(unsigned N) + * Delay for at least (N/256) microseconds. + * This routine depends on the variable: delay_divisor + * which should be set based on the CPU clock rate. + * XXX: Currently this is set in sun3_startup.c based on the + * XXX: CPU model but this should be determined at run time... + */ + .globl __delay +__delay: + | d0 = arg = (usecs << 8) + movl sp@(4),d0 + | d1 = delay_divisor; + movl _delay_divisor,d1 +L_delay: subl d1,d0 -| This loop takes 8 clocks per cycle. -Ldelay: - subql #8,d0 - jgt Ldelay + jgt L_delay rts diff --git a/sys/arch/sun3/sun3/machdep.c b/sys/arch/sun3/sun3/machdep.c index 073f777b290..156c0e117be 100644 --- a/sys/arch/sun3/sun3/machdep.c +++ b/sys/arch/sun3/sun3/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.67 1996/01/04 22:22:54 jtc Exp $ */ +/* $NetBSD: machdep.c,v 1.71 1996/03/26 15:16:53 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -92,14 +92,13 @@ #include <net/netisr.h> -#include <setjmp.h> - #include "cache.h" extern char *cpu_string; extern char version[]; extern short exframesize[]; extern vm_offset_t vmmap; /* XXX - poor name. See mem.c */ +extern int cold; int physmem; int fpu_type; @@ -221,7 +220,8 @@ allocsys(v) * kernel memory allocator is ready for use, but before * the creation of processes 1,2, and mountroot, etc. */ -void cpu_startup() +void +cpu_startup() { caddr_t v; int sz, i; @@ -239,6 +239,8 @@ void cpu_startup() */ printf(version); identifycpu(); + initfpu(); /* also prints FPU type */ + printf("real mem = %d\n", ctob(physmem)); /* @@ -293,10 +295,11 @@ void cpu_startup() 16*NCARGS, TRUE); /* - * Allocate a submap for physio + * We don't use a submap for physio, and use a separate map + * for DVMA allocations. Our vmapbuf just maps pages into + * the kernel map (any kernel mapping is OK) and then the + * device drivers clone the kernel mappings into DVMA space. */ - phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, - VM_PHYS_SIZE, TRUE); /* * Finally, allocate mbuf pool. Since mclrefcnt is an off-size @@ -379,6 +382,7 @@ setregs(p, pack, stack, retval) */ char machine[] = "sun3"; /* cpu "architecture" */ char cpu_model[120]; +extern long hostid; void identifycpu() @@ -393,7 +397,7 @@ identifycpu() /* should eventually include whether it has a VAC, mc6888x version, etc */ strcat(cpu_model, cpu_string); - printf("Model: %s\n", cpu_model); + printf("Model: %s (hostid %x)\n", cpu_model, hostid); } /* @@ -760,6 +764,8 @@ static void reboot_sync() vfs_shutdown(); } +struct pcb dumppcb; + /* * Common part of the BSD and SunOS reboot system calls. */ @@ -770,9 +776,9 @@ int reboot2(howto, user_boot_string) char *bs, *p; char default_boot_string[8]; - /* take a snap shot before clobbering any registers */ - if (curproc && curproc->p_addr) - savectx(curproc->p_addr); + /* If system is cold, just halt. (early panic?) */ + if (cold) + goto haltsys; if ((howto & RB_NOSYNC) == 0) { reboot_sync(); @@ -787,12 +793,20 @@ int reboot2(howto, user_boot_string) /* resettodr(); */ } - /* Write out a crash dump if asked. */ + /* Disable interrupts. */ splhigh(); - if (howto & RB_DUMP) + + /* Write out a crash dump if asked. */ + if (howto & RB_DUMP) { + savectx(&dumppcb); dumpsys(); + } + + /* run any shutdown hooks */ + doshutdownhooks(); if (howto & RB_HALT) { + haltsys: printf("Kernel halted.\n"); sun3_mon_halt(); } @@ -839,6 +853,8 @@ void boot(howto) int howto; { (void) reboot2(howto, NULL); + for(;;); + /* NOTREACHED */ } /* @@ -936,11 +952,11 @@ int peek_word(addr) register caddr_t addr; { - jmp_buf faultbuf; + label_t faultbuf; register int x; nofault = (long*)&faultbuf; - if (setjmp(nofault)) { + if (setjmp(&faultbuf)) { nofault = NULL; return(-1); } @@ -954,11 +970,11 @@ int peek_byte(addr) register caddr_t addr; { - jmp_buf faultbuf; + label_t faultbuf; register int x; nofault = (long*)&faultbuf; - if (setjmp(nofault)) { + if (setjmp(&faultbuf)) { nofault = NULL; return(-1); } diff --git a/sys/arch/sun3/sun3/mainbus.c b/sys/arch/sun3/sun3/mainbus.c new file mode 100644 index 00000000000..1565d6fc36e --- /dev/null +++ b/sys/arch/sun3/sun3/mainbus.c @@ -0,0 +1,91 @@ +/* $NetBSD: mainbus.c,v 1.1 1996/03/26 15:03:58 gwr Exp $ */ + +/* + * Copyright (c) 1996 Gordon W. Ross + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> + +static int main_match __P((struct device *, void *, void *)); +static void main_attach __P((struct device *, struct device *, void *)); + +struct cfattach mainbus_ca = { + sizeof(struct device), main_match, main_attach +}; + +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL +}; + +/* + * Probe for the mainbus; always succeeds. + */ +static int +main_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + + return 1; +} + +/* + * Do "direct" configuration for the bus types on mainbus. + * This controls the order of autoconfig for important things + * used early. For example, idprom is used by Ether drivers. + */ +static int bus_order[] = { + BUS_OBIO, /* eeprom, clock */ + BUS_OBMEM, + BUS_VME16, + BUS_VME32 +}; +#define BUS_ORDER_SZ (sizeof(bus_order)/sizeof(bus_order[0])) + +static void +main_attach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + struct confargs ca; + struct cfdata *new_match; + int i; + + printf("\n"); + + for (i = 0; i < BUS_ORDER_SZ; i++) { + ca.ca_bustype = bus_order[i]; + (void) config_found(self, &ca, NULL); + } +} diff --git a/sys/arch/sun3/sun3/pmap.c b/sys/arch/sun3/sun3/pmap.c index b2823c593a8..8395d0e08cc 100644 --- a/sys/arch/sun3/sun3/pmap.c +++ b/sys/arch/sun3/sun3/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.58 1995/10/10 21:39:04 gwr Exp $ */ +/* $NetBSD: pmap.c,v 1.60 1996/02/28 22:51:05 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -110,6 +110,8 @@ struct pmap_stats { int ps_changewire; /* useless wiring changes */ int ps_npg_prot_all; /* of active pages protected */ int ps_npg_prot_actual; /* pages actually affected */ + int ps_vac_uncached; /* non-cached due to bad alias */ + int ps_vac_recached; /* re-cached when bad alias gone */ } pmap_stats; struct context_state { @@ -1279,6 +1281,7 @@ pv_link(pmap, pa, va, flags) if (BADALIAS(va, npv->pv_va)) { head->pv_flags |= PV_NC; pv_changepte(head, PG_NC, 0); + pmap_stats.ps_vac_uncached++; break; } } @@ -1370,6 +1373,7 @@ pv_unlink(pmap, pa, va) return; head->pv_flags &= ~PV_NC; pv_changepte(head, 0, PG_NC); + pmap_stats.ps_vac_recached++; } } @@ -1546,7 +1550,7 @@ pmap_next_page(paddr) * * XXX - Should make this a macro in pmap.h */ -u_long +int pmap_page_index(pa) vm_offset_t pa; { @@ -3196,6 +3200,26 @@ pmap_collect(pmap) { } +/* + * Find first virtual address >= *va that is + * least likely to cause cache aliases. + * (This will just seg-align mappings.) + */ +void +pmap_prefer(fo, va) + register vm_offset_t fo; + register vm_offset_t *va; +{ + register long d; + + d = fo - *va; + d &= SEGOFSET; + *va += d; +} + +/* + * Helper functions for changing unloaded PMEGs + */ static int temp_seg_inuse; static int diff --git a/sys/arch/sun3/sun3/stub.c b/sys/arch/sun3/sun3/stub.c index a2201823da5..fda67bc9b24 100644 --- a/sys/arch/sun3/sun3/stub.c +++ b/sys/arch/sun3/sun3/stub.c @@ -1,7 +1,7 @@ -/* $NetBSD: stub.c,v 1.10 1994/11/23 08:16:26 gwr Exp $ */ +/* $NetBSD: stub.c,v 1.11 1996/03/26 15:16:55 gwr Exp $ */ /* - * Copyright (c) 1993 Adam Glass + * Copyright (c) 1996 Gordon W. Ross * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,31 +12,50 @@ * 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 Adam Glass. - * 4. The name of the Author may not be used to endorse or promote products + * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon Ross * - * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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. + * 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. + */ + +/* + * Stubs to supply things needed when some options are OFF. + */ + + +/* Called by autoconf.c */ +#ifndef GENERIC +void swapgeneric() {} +#endif + +/* + * XXX: isr.c:netintr() - move to conf.c? */ -char *memcpy(dst, src, cnt) - char *dst; - const char *src; - unsigned cnt; +/* sun3_startup.c */ +#if !defined(DDB) && !defined(KGDB) +/* + * When DDB is included, Debugger() comes from db_interface.c + * otherwise provide this function. This will just stop in + * the Sun PROM monitor. (You can look around, or continue.) + */ +void Debugger() { - bcopy(src, dst, cnt); - return dst; + sun3_mon_abort(); } +#endif /* !DDB && !KGDB */ +/* sys_machdep.c */ +/* trap.c */ diff --git a/sys/arch/sun3/sun3/sun3_startup.c b/sys/arch/sun3/sun3/sun3_startup.c index d6fa52d8ddd..d0ce50b7dc0 100644 --- a/sys/arch/sun3/sun3/sun3_startup.c +++ b/sys/arch/sun3/sun3/sun3_startup.c @@ -1,4 +1,4 @@ -/* $NetBSD: sun3_startup.c,v 1.48 1995/10/17 23:16:40 gwr Exp $ */ +/* $NetBSD: sun3_startup.c,v 1.51 1996/03/26 15:16:59 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -192,18 +192,6 @@ void sun3_mon_reboot(bootstring) /*NOTREACHED*/ } -#ifndef DDB -/* - * When DDB is included, Debugger() comes from db_interface.c - * otherwise provide this function. This will just stop in - * the Sun PROM monitor. (You can look around, or continue.) - */ -void Debugger() -{ - sun3_mon_abort(); -} -#endif /* DDB */ - /* * Duplicate all mappings in the current context into * every other context. We have to let the PROM do the @@ -489,9 +477,11 @@ void sun3_vm_init(kehp) /* * Clear-out pmegs left in DVMA space by the PROM. + * DO NOT kill the last one! (owned by the PROM!) */ - va = sun3_trunc_seg(DVMA_SEGMAP_BASE); - while (va < DVMA_SEGMAP_END) { + va = sun3_trunc_seg(DVMA_SPACE_START); + eva = sun3_trunc_seg(DVMA_SPACE_END); /* Yes trunc! */ + while (va < eva) { set_segmap(va, SEGINV); va += NBSG; } @@ -591,8 +581,13 @@ void sun3_vm_init(kehp) } -/* XXX - Should just estimate this instead... */ -int cpuspeed = 25; /* initial guess */ +/* + * XXX - Should empirically estimate the divisor... + * Note that the value of delay_divisor is roughly + * 2048 / cpuclock (where cpuclock is in MHz). + */ +int delay_divisor = 82; /* assume the fastest (3/260) */ + void sun3_verify_hardware() { unsigned char machtype; @@ -613,33 +608,33 @@ void sun3_verify_hardware() hole_start = OBMEM_BW50_ADDR; hole_size = OBMEM_BW2_SIZE; cpu_string = "50"; - cpuspeed = 16; /* MHz */ + delay_divisor = 128; /* 16 MHz */ break; case SUN3_MACH_60 : cpu_match++; cpu_string = "60"; - cpuspeed = 20; /* MHz */ + delay_divisor = 102; /* 20 MHz */ break; case SUN3_MACH_110: cpu_match++; cpu_string = "110"; - cpuspeed = 17; /* MHz */ + delay_divisor = 120; /* 17 MHz */ cpu_has_vme = TRUE; break; case SUN3_MACH_160: cpu_match++; cpu_string = "160"; - cpuspeed = 17; /* MHz */ + delay_divisor = 120; /* 17 MHz */ cpu_has_vme = TRUE; break; case SUN3_MACH_260: cpu_match++; cpu_string = "260"; - cpuspeed = 25; /* MHz */ + delay_divisor = 82; /* 25 MHz */ cpu_has_vme = TRUE; #ifdef HAVECACHE cache_size = 0x10000; /* 64K */ @@ -649,7 +644,7 @@ void sun3_verify_hardware() case SUN3_MACH_E : cpu_match++; cpu_string = "E"; - cpuspeed = 20; /* MHz */ /* XXX - Correct? */ + delay_divisor = 102; /* 20 MHz XXX: Correct? */ cpu_has_vme = TRUE; break; @@ -822,7 +817,7 @@ void internal_configure() /* Drivers that use those OBIO mappings from the PROM */ zs_init(); eeprom_init(); - isr_init(); + intreg_init(); clock_init(); } diff --git a/sys/arch/sun3/sun3/trap.c b/sys/arch/sun3/sun3/trap.c index 24702194758..1baf0879435 100644 --- a/sys/arch/sun3/sun3/trap.c +++ b/sys/arch/sun3/sun3/trap.c @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.55 1995/10/10 21:33:33 gwr Exp $ */ +/* $NetBSD: trap.c,v 1.56 1996/03/21 23:03:49 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -78,7 +78,7 @@ extern struct emul emul_sunos; */ extern int fubail(), subail(); -extern int *nofault; +extern label_t *nofault; /* XXX - put these in some header file? */ extern vm_offset_t virtual_avail; @@ -522,7 +522,7 @@ trap(type, code, v, frame) goto dopanic; } ucode = v; - sig = SIGSEGV; + sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; break; } /* T_MMUFLT */ } /* switch */ diff --git a/sys/arch/sun3/sun3/vector.c b/sys/arch/sun3/sun3/vector.c index a362866de57..7fb819d3c9a 100644 --- a/sys/arch/sun3/sun3/vector.c +++ b/sys/arch/sun3/sun3/vector.c @@ -1,4 +1,4 @@ -/* $NetBSD: vector.c,v 1.13 1995/08/21 21:37:41 gwr Exp $ */ +/* $NetBSD: vector.c,v 1.14 1996/02/16 20:17:58 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -66,7 +66,7 @@ void (*vector_table[NVECTORS])() = { chkinst, /* 6: CHK instruction */ trapvinst, /* 7: TRAPV instruction */ privinst, /* 8: privilege violation */ - trace, /* 9: trace */ + trace, /* 9: trace (single-step) */ illinst, /* 10: line 1010 emulator */ fpfline, /* 11: line 1111 emulator */ badtrap, /* 12: unassigned, reserved */ @@ -90,8 +90,8 @@ void (*vector_table[NVECTORS])() = { _isr_autovec, /* 30: level 6 interrupt autovector */ _isr_autovec, /* 31: level 7 interrupt autovector */ trap0, /* 32: syscalls (at least on hp300) */ - trap1, /* 33: sigreturn syscall or breakpoi */ - trap2, /* 34: breakpoint or sigreturn sysca */ + trap1, /* 33: sigreturn syscall */ + trap2, /* 34: HPUX breakpoint */ illinst, /* 35: TRAP instruction vector */ illinst, /* 36: TRAP instruction vector */ illinst, /* 37: TRAP instruction vector */ @@ -101,10 +101,10 @@ void (*vector_table[NVECTORS])() = { illinst, /* 41: TRAP instruction vector */ illinst, /* 42: TRAP instruction vector */ illinst, /* 43: TRAP instruction vector */ - trap12, /* 44: TRAP instruction vector */ + trap12, /* 44: TRAP 12: cachectl */ illinst, /* 45: TRAP instruction vector */ illinst, /* 46: TRAP instruction vector */ - trap15, /* 47: TRAP instruction vector */ + trap15, /* 47: TRAP 15: breakpoint */ fpbsun, /* 48: FPCP branch/set on unordered */ fpinex, /* 49: FPCP inexact result */ fpdz, /* 50: FPCP divide by zero */ diff --git a/sys/arch/sun3/sun3/vm_machdep.c b/sys/arch/sun3/sun3/vm_machdep.c index d23fbfb3541..b6d2fcbdc2f 100644 --- a/sys/arch/sun3/sun3/vm_machdep.c +++ b/sys/arch/sun3/sun3/vm_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: vm_machdep.c,v 1.32 1995/12/09 04:37:58 mycroft Exp $ */ +/* $NetBSD: vm_machdep.c,v 1.35 1996/04/26 18:38:06 gwr Exp $ */ /* * Copyright (c) 1994, 1995 Gordon W. Ross @@ -66,9 +66,6 @@ extern int fpu_type; -/* XXX - Put this in some header file? */ -void cpu_set_kpc __P((struct proc *p, u_long func)); - /* * Finish a fork operation, with process p2 nearly set up. @@ -131,7 +128,7 @@ cpu_fork(p1, p2) * onto the stack of p2, very much like signal delivery. * When p2 runs, it will find itself in child_return(). */ - cpu_set_kpc(p2, (long)child_return); + cpu_set_kpc(p2, child_return); } /* @@ -158,14 +155,14 @@ cpu_fork(p1, p2) void cpu_set_kpc(proc, func) struct proc *proc; - u_long func; + void (*func)(struct proc *); { struct pcb *pcbp; struct switchframe *sf; extern void proc_trampoline(); struct ksigframe { struct switchframe sf; - u_long func; + void (*func)(struct proc *); void *proc; } *ksfp; @@ -282,9 +279,10 @@ cpu_coredump(p, vp, cred, chdr) * Both addresses are assumed to reside in the kernel map, * and size must be a multiple of CLSIZE. */ +void pagemove(from, to, size) register caddr_t from, to; - int size; + size_t size; { register vm_offset_t pa; @@ -309,8 +307,6 @@ pagemove(from, to, size) } } -extern vm_map_t phys_map; - /* * Map an IO request into kernel virtual address space. * Requests fall into one of five catagories: @@ -326,8 +322,7 @@ extern vm_map_t phys_map; * B_PHYS: User "raw" IO request. * Address is VA in user's address space. * - * All requests are (re)mapped into kernel VA space via the phys_map - * (a name with only slightly more meaning than "kernelmap") + * All requests are (re)mapped into kernel VA space via the kernel_map * * This routine has user context and can sleep * (called only by physio). @@ -337,28 +332,33 @@ extern vm_map_t phys_map; * is a total crock, the multiple mappings of these physical pages should * be reflected in the higher-level VM structures to avoid problems. */ -vmapbuf(bp) +void +vmapbuf(bp, sz) register struct buf *bp; + vm_size_t sz; { + register vm_offset_t addr, kva, pa; + register vm_size_t size, off; register int npf; - register caddr_t addr; - register long flags = bp->b_flags; struct proc *p; - int off; - vm_offset_t kva; - register vm_offset_t pa; + register struct vm_map *map; - if ((flags & B_PHYS) == 0) + if ((bp->b_flags & B_PHYS) == 0) panic("vmapbuf"); - addr = bp->b_saveaddr = bp->b_data; - off = (int)addr & PGOFSET; p = bp->b_proc; - npf = btoc(round_page(bp->b_bcount + off)); - kva = kmem_alloc_wait(phys_map, ctob(npf)); - bp->b_data = (caddr_t) (kva + off); + map = &p->p_vmspace->vm_map; + bp->b_saveaddr = bp->b_data; + addr = (vm_offset_t)bp->b_saveaddr; + off = addr & PGOFSET; + addr = trunc_page(addr); + size = round_page(bp->b_bcount + off); + kva = kmem_alloc_wait(kernel_map, size); + bp->b_data = (caddr_t)(kva + off); + + npf = btoc(size); while (npf--) { - pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), - (vm_offset_t)addr); + pa = pmap_extract(vm_map_pmap(map), (vm_offset_t)addr); + pa = trunc_page(pa); /* page type in low bits? */ if (pa == 0) panic("vmapbuf: null page frame"); #ifdef HAVECACHE @@ -366,16 +366,16 @@ vmapbuf(bp) if (cache_size) cache_flush_page((vm_offset_t)addr); #endif - pmap_enter(vm_map_pmap(phys_map), kva, - trunc_page(pa) | PMAP_NC, + pmap_enter(pmap_kernel(), kva, + pa | PMAP_NC, VM_PROT_READ|VM_PROT_WRITE, TRUE); - addr += PAGE_SIZE; - kva += PAGE_SIZE; + addr += NBPG; + kva += NBPG; } } /* - * Free the io map PTEs associated with this I/O operation. + * Free the io mappings associated with this I/O operation. * The mappings in the I/O map (phys_map) were non-cached, * so there are no write-back modifications to flush. * Also note, kmem_free_wakeup will remove the mappings. @@ -383,21 +383,31 @@ vmapbuf(bp) * This routine has user context and can sleep * (called only by physio). */ -vunmapbuf(bp) +void +vunmapbuf(bp, sz) register struct buf *bp; + vm_size_t sz; { - register caddr_t addr; - vm_offset_t pgva; - register int off, npf; + register vm_offset_t kva, pgva; + register vm_size_t size, off; if ((bp->b_flags & B_PHYS) == 0) panic("vunmapbuf"); - addr = bp->b_data; - off = (int)addr & PGOFSET; - pgva = (vm_offset_t)((int)addr & ~PGOFSET); - npf = btoc(round_page(bp->b_bcount + off)); - kmem_free_wakeup(phys_map, pgva, ctob(npf)); + kva = (vm_offset_t)bp->b_data; + off = kva & PGOFSET; + pgva = trunc_page(kva); + size = round_page(bp->b_bcount + off); + + /* Actually remove mappings, which does cache flush. */ + pmap_remove(pmap_kernel(), pgva, pgva + size); + + /* + * Now remove the map entry, which may also call + * pmap_remove but that will do nothing since we + * already removed the actual mappings. + */ + kmem_free_wakeup(kernel_map, pgva, size); bp->b_data = bp->b_saveaddr; bp->b_saveaddr = NULL; } |