-/* $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
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 */
{
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);
}
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));
}
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);
-/* $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
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();
{
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);
}
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));
}
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)
-/* $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
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();
{
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);
}
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));
}
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)
-/* $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
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()
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;
-/* $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
*/
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;
struct idprom *idp;
char *src, *dst;
int len, x, xorsum;
+ union {
+ long l;
+ char c[4];
+ } hid;
idp = &identity_prom;
dst = (char*)idp;
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;
}
-/* $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.
#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;
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 *));
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
* 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");
* 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;
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;
/*
* 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:
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;
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;
-/* $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?)
- */
-
--- /dev/null
+/* $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);
+}
+
-/* $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;
-}
-/* $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 *);
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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?)
+ */
+
--- /dev/null
+/* $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 *));
-/* $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.
#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;
}
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);
}
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>
-/* $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
-};
-/* $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 */
-}
-/* $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 *);
-/* $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.
* @(#)if_lereg.h 7.1 (Berkeley) 5/8/90
*/
-#define MEMSIZE 0x4000
-
/*
* LANCE registers.
*/
-/* $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
s = spltty();
tp->t_state &= ~TS_BUSY;
- if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
- else
- kdstart(tp);
splx(s);
}
}
/*
- * 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)
if ((tp->t_state & TS_ISOPEN) == 0)
return;
- ttyinput(c, kd->kd_tty);
+ (*linesw[tp->t_line].l_rint)(c, tp);
}
--- /dev/null
+/* $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... */
+}
--- /dev/null
+/* $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"
+
-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.
-
-/* $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 */
-/* $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 */
-/* $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
-/* $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;
-}
-
-/* $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 */
-
-/* $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
* 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>
#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)
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);
}
-/* $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
#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
-/* $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
* 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.
*/
/*
#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)
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);
}
-/* $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);
-}
-/* $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
-/* $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 */
-
-/* $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
-/* $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 */
-
-/* $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
* 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
}
#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;
-}
--- /dev/null
+/* $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;
+}
+
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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 */
+
--- /dev/null
+/* $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 *));
-/* $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
#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);
}
-/* $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 $ */
/*
*
* 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.
* 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 */
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 */
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);
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 */
/* 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);
/* 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 */
/* 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;
/* 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);
-/* $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 $ */
/*
*
-/* $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 $ */
/*
*
-/* $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 $ */
/*
*
* 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.
* 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 */
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 */
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);
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 */
/* 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);
/* 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 */
/* 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;
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);
}
/* Instrumentation. */
disk_busy(&xysc->sc_dk);
+ /* Instrumentation. */
+ disk_busy(&xysc->sc_dk);
+
return (XY_ERR_AOK);
}
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;
-/* $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
#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 {
****************************************************************/
/* 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 *);
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.
*
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)
* so just do it on the A channel.
*/
if (channel == 0) {
- ZS_WRITE(cs, 9, 0);
+ zs_write_reg(cs, 9, 0);
}
/*
*/
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);
}
}
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;
/* 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);
}
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);
}
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!)
****************************************************************/
/*
* 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>
/* 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;
* 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;
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) {
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);
}
{
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);
}
-/* $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
#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.
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));
+
-/* $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
* when calculating the alias address for slave access.
*/
-/*
- * 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 */
#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);
-/* $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
#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 */
-/* $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
/*
* 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
/* 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 */
-/* $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
#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)
-/* $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
/* 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 */
#define splhigh() spl7()
#define splsched() spl7()
-#endif /* KERNEL && !LOCORE */
+#endif /* KERNEL && !_LOCORE */
#endif /* PSL_C */
-/* $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
#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.
-/* $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
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();
* This is called by SRT0.S
* to do final prep for main
*/
-void
+__dead void
_start()
{
register int *p;
-/* $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
#include "dvma.h"
#include "promdev.h"
+#define RETRY_COUNT 5
+
+extern int debug;
+int disk_opencount;
struct saioreq disk_ioreq;
int
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;
{
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;
}
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)
-/* $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
#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()
{
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 */
}
-/* $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
#include "stand.h"
extern int debug;
+int errno;
/*ARGSUSED*/
int
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");
#include "iodesc.h"
struct netif {
- void *devdata;
+ void *nif_devdata;
};
ssize_t netif_get __P((struct iodesc *, void *, size_t, time_t));
-/* $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
#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).
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",
}
#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;
}
/*
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));
}
#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);
-}
-
#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();
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.:
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");
+ }
}
-/* $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
#include "dvma.h"
extern void set_pte __P((int, int));
+extern int debug;
static int promdev_inuse;
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) {
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
}
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
}
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++;
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;
}
-/* $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>
};
int ndevs = 1;
-/* XXX */
-int netif_debug;
-int debug;
-int errno;
-/* $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
* for use by the NFS open code (NFS/lookup).
*/
+#include <stdarg.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#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() */
/*
* 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);
}
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
}
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.
#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);
#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);
}
-/* $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 $";
* device access stays strictly on block boundaries.
*/
-char *version = "$Revision: 1.2 $";
+char *version = "$Revision: 1.3 $";
-/* $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
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;
}
}
-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)
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;
{
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[];
int bustype, paddr, sz;
{
int off, pa, pgs, pmt;
- vm_offset_t va;
+ vm_offset_t va, retval;
if (bustype & ~3)
return (NULL);
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);
}
-/* $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
#include "intersil7170.h"
#include "interreg.h"
+#define CLOCK_PRI 5
+
extern volatile u_char *interrupt_reg;
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.
-/* $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
#define mmwrite mmrw
cdev_decl(mm);
-#include "zs.h"
+#define NZS 2 /* XXX: temporary hack */
cdev_decl(zs);
cdev_decl(kd);
cdev_decl(ms);
#include "tun.h"
cdev_decl(tun);
+dev_decl(filedesc,open);
+
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 */
-/* $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
#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" };
--- /dev/null
+/* $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++;
+ }
+}
+
-/* $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
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;
}
/************************************************************************
-/* $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
#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);
}
/*
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;
}
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);
}
/*
-/* $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
#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 */
"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;
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. */
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);
}
-/* $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
* 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>
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]);
--- /dev/null
+/* $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);
+}
+
-/* $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
#include <machine/isr.h>
#include "vector.h"
-#include "interreg.h"
#include "ether.h" /* for NETHER */
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;
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
}
-/*
- * 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];
/*
-/* $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
* @(#)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^)
addql #4, sp | stack adjust count
jra rei | all done
+/*
+ * Trap 0 is for system calls
+ */
.globl _syscall
_trap0:
clrl sp@- | stack adjust count
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
movl sp@,sp | and our SP
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.
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
-/* $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
#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;
* 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;
*/
printf(version);
identifycpu();
+ initfpu(); /* also prints FPU type */
+
printf("real mem = %d\n", ctob(physmem));
/*
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
*/
char machine[] = "sun3"; /* cpu "architecture" */
char cpu_model[120];
+extern long hostid;
void
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);
}
/*
vfs_shutdown();
}
+struct pcb dumppcb;
+
/*
* Common part of the BSD and SunOS reboot system calls.
*/
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();
/* 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();
}
int howto;
{
(void) reboot2(howto, NULL);
+ for(;;);
+ /* NOTREACHED */
}
/*
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);
}
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);
}
--- /dev/null
+/* $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);
+ }
+}
-/* $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
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 {
if (BADALIAS(va, npv->pv_va)) {
head->pv_flags |= PV_NC;
pv_changepte(head, PG_NC, 0);
+ pmap_stats.ps_vac_uncached++;
break;
}
}
return;
head->pv_flags &= ~PV_NC;
pv_changepte(head, 0, PG_NC);
+ pmap_stats.ps_vac_recached++;
}
}
*
* XXX - Should make this a macro in pmap.h
*/
-u_long
+int
pmap_page_index(pa)
vm_offset_t pa;
{
{
}
+/*
+ * 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
-/* $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
* 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 */
-/* $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
/*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
/*
* 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;
}
}
-/* 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;
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 */
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;
/* Drivers that use those OBIO mappings from the PROM */
zs_init();
eeprom_init();
- isr_init();
+ intreg_init();
clock_init();
}
-/* $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
*/
extern int fubail(), subail();
-extern int *nofault;
+extern label_t *nofault;
/* XXX - put these in some header file? */
extern vm_offset_t virtual_avail;
goto dopanic;
}
ucode = v;
- sig = SIGSEGV;
+ sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
break;
} /* T_MMUFLT */
} /* switch */
-/* $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
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 */
_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 */
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 */
-/* $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
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.
* 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);
}
/*
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;
* 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;
}
}
-extern vm_map_t phys_map;
-
/*
* Map an IO request into kernel virtual address space.
* Requests fall into one of five catagories:
* 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).
* 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
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.
* 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;
}