summaryrefslogtreecommitdiff
path: root/sys/arch/wgrisc/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/wgrisc/dev')
-rw-r--r--sys/arch/wgrisc/dev/ace.c1653
-rw-r--r--sys/arch/wgrisc/dev/asc.c2096
-rw-r--r--sys/arch/wgrisc/dev/ascreg.h326
-rw-r--r--sys/arch/wgrisc/dev/com_risc.c195
-rw-r--r--sys/arch/wgrisc/dev/dma.h147
-rw-r--r--sys/arch/wgrisc/dev/if_sn.c1288
-rw-r--r--sys/arch/wgrisc/dev/if_sn.h347
-rw-r--r--sys/arch/wgrisc/dev/scsi.h559
8 files changed, 6611 insertions, 0 deletions
diff --git a/sys/arch/wgrisc/dev/ace.c b/sys/arch/wgrisc/dev/ace.c
new file mode 100644
index 00000000000..d577033f2c7
--- /dev/null
+++ b/sys/arch/wgrisc/dev/ace.c
@@ -0,0 +1,1653 @@
+/* $OpenBSD: ace.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+/* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995, 1996
+ * Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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 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.
+ *
+ * @(#)com.c 7.5 (Berkeley) 5/16/91
+ */
+
+/*
+ * ACE driver, based on HP dca driver
+ * uses National Semiconductor NS16450/NS16550AF UART
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/device.h>
+
+#include <wgrisc/wgrisc/wgrisctype.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#include <dev/ic/ns16550reg.h>
+#ifdef COM_HAYESP
+#include <dev/ic/hayespreg.h>
+#endif
+#define com_lcr com_cfcr
+
+#include "ace.h"
+
+
+#define COM_IBUFSIZE (2 * 512)
+#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
+
+struct com_softc {
+ struct device sc_dev;
+ void *sc_ih;
+ bus_chipset_tag_t sc_bc;
+ struct tty *sc_tty;
+
+ int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+
+ int sc_halt;
+
+ int sc_iobase;
+#ifdef COM_HAYESP
+ int sc_hayespbase;
+#endif
+
+ bus_io_handle_t sc_ioh;
+ bus_io_handle_t sc_hayespioh;
+
+ u_char sc_hwflags;
+#define COM_HW_NOIEN 0x01
+#define COM_HW_FIFO 0x02
+#define COM_HW_HAYESP 0x04
+#define COM_HW_ABSENT_PENDING 0x08 /* reattached, awaiting close/reopen */
+#define COM_HW_ABSENT 0x10 /* configure actually failed, or removed */
+#define COM_HW_REATTACH 0x20 /* reattaching */
+#define COM_HW_CONSOLE 0x40
+ u_char sc_swflags;
+#define COM_SW_SOFTCAR 0x01
+#define COM_SW_CLOCAL 0x02
+#define COM_SW_CRTSCTS 0x04
+#define COM_SW_MDMBUF 0x08
+ u_char sc_msr, sc_mcr, sc_lcr, sc_ier;
+ u_char sc_dtr;
+
+ u_char sc_cua;
+
+ u_char sc_initialize; /* force initialization */
+
+ u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+ u_char sc_ibufs[2][COM_IBUFSIZE];
+};
+
+#ifdef COM_HAYESP
+int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc));
+#endif
+void comdiag __P((void *));
+int comspeed __P((long));
+int comparam __P((struct tty *, struct termios *));
+void comstart __P((struct tty *));
+void compoll __P((void *));
+
+/* XXX: These belong elsewhere */
+cdev_decl(com);
+bdev_decl(com);
+
+struct consdev;
+void acecnprobe __P((struct consdev *));
+void acecninit __P((struct consdev *));
+int acecngetc __P((dev_t));
+void acecnputc __P((dev_t, int));
+void acecnpollc __P((dev_t, int));
+
+static u_char tiocm_xxx2mcr __P((int));
+
+/*
+ * XXX the following two cfattach structs should be different, and possibly
+ * XXX elsewhere.
+ */
+int comprobe __P((struct device *, void *, void *));
+void comattach __P((struct device *, struct device *, void *));
+void com_absent_notify __P((struct com_softc *sc));
+void comstart_pending __P((void *));
+
+#if NACE_ISA
+struct cfattach ace_isa_ca = {
+ sizeof(struct com_softc), comprobe, comattach
+};
+#endif
+
+#if NACE_COMMULTI
+struct cfattach ace_commulti_ca = {
+ sizeof(struct com_softc), comprobe, comattach
+};
+#endif
+
+#if NACE_RISCBUS
+#undef CONADDR /* This is stupid but using devs before config .. */
+#define CONADDR 0xae400000
+
+struct cfattach ace_riscbus_ca = {
+ sizeof(struct com_softc), comprobe, comattach
+};
+#endif
+
+
+struct cfdriver ace_cd = {
+ NULL, "ace", DV_TTY
+};
+
+void cominit __P((bus_chipset_tag_t, bus_io_handle_t, int));
+
+#ifndef CONSPEED
+#define CONSPEED B9600
+#endif
+
+#ifdef COMCONSOLE
+int comdefaultrate = CONSPEED; /* XXX why set default? */
+#else
+int comdefaultrate = TTYDEF_SPEED;
+#endif
+int comconsaddr;
+int comconsinit;
+int comconsattached;
+bus_chipset_tag_t comconsbc;
+bus_io_handle_t comconsioh;
+tcflag_t comconscflag = TTYDEF_CFLAG;
+
+int commajor;
+int comsopen = 0;
+int comevents = 0;
+
+#ifdef KGDB
+#include <machine/remote-sl.h>
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+#define DEVUNIT(x) (minor(x) & 0x7f)
+#define DEVCUA(x) (minor(x) & 0x80)
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+/*
+ * must be called at spltty() or higher.
+ */
+void
+com_absent_notify(sc)
+ struct com_softc *sc;
+{
+ struct tty *tp = sc->sc_tty;
+
+ if (tp) {
+ CLR(tp->t_state, TS_CARR_ON|TS_BUSY);
+ ttyflush(tp, FREAD|FWRITE);
+ }
+}
+
+int
+comspeed(speed)
+ long speed;
+{
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+
+ int x, err;
+
+ if (speed == 0)
+ return 0;
+ if (speed < 0)
+ return -1;
+ x = divrnd((COM_FREQ / 16), speed);
+ if (x <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+ return x;
+
+#undef divrnd(n, q)
+}
+
+int
+comprobe1(bc, ioh, iobase)
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ int iobase;
+{
+ int i, k;
+
+ /* force access to id reg */
+ bus_io_write_1(bc, ioh, com_lcr, 0);
+ bus_io_write_1(bc, ioh, com_iir, 0);
+ for (i = 0; i < 32; i++) {
+ k = bus_io_read_1(bc, ioh, com_iir);
+ if (k & 0x38) {
+ bus_io_read_1(bc, ioh, com_data); /* cleanup */
+ } else
+ break;
+ }
+ if (i >= 32)
+ return 0;
+
+ return 1;
+}
+
+#ifdef COM_HAYESP
+int
+comprobeHAYESP(hayespioh, sc)
+ bus_io_handle_t hayespioh;
+ struct com_softc *sc;
+{
+ char val, dips;
+ int combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+ bus_chipset_tag_t bc = sc->sc_bc;
+
+ /*
+ * Hayes ESP cards have two iobases. One is for compatibility with
+ * 16550 serial chips, and at the same ISA PC base addresses. The
+ * other is for ESP-specific enhanced features, and lies at a
+ * different addressing range entirely (0x140, 0x180, 0x280, or 0x300).
+ */
+
+ /* Test for ESP signature */
+ if ((bus_io_read_1(bc, hayespioh, 0) & 0xf3) == 0)
+ return 0;
+
+ /*
+ * ESP is present at ESP enhanced base address; unknown com port
+ */
+
+ /* Get the dip-switch configurations */
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETDIPS);
+ dips = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1);
+
+ /* Determine which com port this ESP card services: bits 0,1 of */
+ /* dips is the port # (0-3); combaselist[val] is the com_iobase */
+ if (sc->sc_iobase != combaselist[dips & 0x03])
+ return 0;
+
+ printf(": ESP");
+
+ /* Check ESP Self Test bits. */
+ /* Check for ESP version 2.0: bits 4,5,6 == 010 */
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETTEST);
+ val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1); /* Clear reg 1 */
+ val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS2);
+ if ((val & 0x70) < 0x20) {
+ printf("-old (%o)", val & 0x70);
+ /* we do not support the necessary features */
+ return 0;
+ }
+
+ /* Check for ability to emulate 16550: bit 8 == 1 */
+ if ((dips & 0x80) == 0) {
+ printf(" slave");
+ /* XXX Does slave really mean no 16550 support?? */
+ return 0;
+ }
+
+ /*
+ * If we made it this far, we are a full-featured ESP v2.0 (or
+ * better), at the correct com port address.
+ */
+
+ SET(sc->sc_hwflags, COM_HW_HAYESP);
+ printf(", 1024 byte fifo\n");
+ return 1;
+}
+#endif
+
+int
+comprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ int iobase, needioh;
+ int rv = 1;
+
+#if NACE_ISA
+#define IS_ISA(parent) \
+ (!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") || \
+ !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pcmcia"))
+#elif NACE_ISA
+#define IS_ISA(parent) \
+ !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa")
+#endif
+#if NACE_RISCBUS
+#define IS_RISCBUS(parent) \
+ !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "riscbus")
+#endif
+ /*
+ * XXX should be broken out into functions for isa probe and
+ * XXX for commulti probe, with a helper function that contains
+ * XXX most of the interesting stuff.
+ */
+#if NACE_ISA
+ if (IS_ISA(parent)) {
+ struct isa_attach_args *ia = aux;
+
+ bc = ia->ia_bc;
+ iobase = ia->ia_iobase;
+ needioh = 1;
+ } else
+#endif
+#if NACE_RISCBUS
+ if(IS_RISCBUS(parent)) {
+ struct confargs *ca = aux;
+ if(!BUS_MATCHNAME(ca, "com"))
+ return(0);
+ iobase = (long)BUS_CVTADDR(ca);
+ bc = 0;
+ needioh = 1;
+ } else
+#endif
+#if NACE_COMMULTI
+ if (1) {
+ struct cfdata *cf = match;
+ struct commulti_attach_args *ca = aux;
+
+ if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave)
+ return (0);
+
+ bc = ca->ca_bc;
+ iobase = ca->ca_iobase;
+ ioh = ca->ca_ioh;
+ needioh = 0;
+ } else
+#endif
+ return(0); /* This cannot happen */
+
+ /* if it's in use as console, it's there. */
+ if (iobase == comconsaddr && !comconsattached)
+ goto out;
+
+ if (needioh && bus_io_map(bc, iobase, COM_NPORTS, &ioh)) {
+ rv = 0;
+ goto out;
+ }
+ rv = comprobe1(bc, ioh, iobase);
+ if (needioh)
+ bus_io_unmap(bc, ioh, COM_NPORTS);
+
+out:
+#if NACE_ISA
+ if (rv && IS_ISA(parent)) {
+ struct isa_attach_args *ia = aux;
+
+ ia->ia_iosize = COM_NPORTS;
+ ia->ia_msize = 0;
+ }
+#endif
+ return (rv);
+}
+
+void
+comattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct com_softc *sc = (void *)self;
+ int iobase, irq;
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+#ifdef COM_HAYESP
+ int hayesp_ports[] = { 0x140, 0x180, 0x280, 0x300, 0 };
+ int *hayespp;
+#endif
+
+ /*
+ * XXX should be broken out into functions for isa attach and
+ * XXX for commulti attach, with a helper function that contains
+ * XXX most of the interesting stuff.
+ */
+ if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) {
+ int s;
+ s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+ } else
+ sc->sc_hwflags = 0;
+ sc->sc_swflags = 0;
+#if NACE_ISA
+ if (IS_ISA(parent)) {
+ struct isa_attach_args *ia = aux;
+
+ /*
+ * We're living on an isa.
+ */
+ iobase = ia->ia_iobase;
+ bc = ia->ia_bc;
+ if (iobase != comconsaddr) {
+ if (bus_io_map(bc, iobase, COM_NPORTS, &ioh))
+ panic("comattach: io mapping failed");
+ } else
+ ioh = comconsioh;
+ irq = ia->ia_irq;
+ } else
+#endif
+#if NACE_RISCBUS
+ if(IS_RISCBUS(parent)) {
+ struct confargs *ca = aux;
+ iobase = (long)BUS_CVTADDR(ca);
+ bc = 0;
+ irq = 0;
+ ioh = iobase;
+ } else
+#endif
+#if NACE_COMMULTI
+ if (1) {
+ struct commulti_attach_args *ca = aux;
+
+ /*
+ * We're living on a commulti.
+ */
+ iobase = ca->ca_iobase;
+ bc = ca->ca_bc;
+ ioh = ca->ca_ioh;
+ irq = IRQUNK;
+
+ if (ca->ca_noien)
+ SET(sc->sc_hwflags, COM_HW_NOIEN);
+ } else
+#endif
+ panic("comattach: impossible");
+
+ sc->sc_bc = bc;
+ sc->sc_ioh = ioh;
+ sc->sc_iobase = iobase;
+
+ if (iobase == comconsaddr) {
+ comconsattached = 1;
+
+ /*
+ * Need to reset baud rate, etc. of next print so reset
+ * comconsinit. Also make sure console is always "hardwired".
+ */
+ delay(1000); /* wait for output to finish */
+ comconsinit = 0;
+ SET(sc->sc_hwflags, COM_HW_CONSOLE);
+ SET(sc->sc_swflags, COM_SW_SOFTCAR);
+ }
+
+#ifdef COM_HAYESP
+ /* Look for a Hayes ESP board. */
+ for (hayespp = hayesp_ports; *hayespp != 0; hayespp++) {
+ bus_io_handle_t hayespioh;
+
+#define HAYESP_NPORTS 8 /* XXX XXX XXX ??? ??? ??? */
+ if (bus_io_map(bc, *hayespp, HAYESP_NPORTS, &hayespioh))
+ continue;
+ if (comprobeHAYESP(hayespioh, sc)) {
+ sc->sc_hayespbase = *hayespp;
+ sc->sc_hayespioh = hayespioh;
+ break;
+ }
+ bus_io_unmap(bc, hayespioh, HAYESP_NPORTS);
+ }
+ /* No ESP; look for other things. */
+ if (*hayespp == 0) {
+#endif
+
+ /* look for a NS 16550AF UART with FIFOs */
+ bus_io_write_1(bc, ioh, com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ delay(100);
+ if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_FIFO_MASK) ==
+ IIR_FIFO_MASK)
+ if (ISSET(bus_io_read_1(bc, ioh, com_fifo), FIFO_TRIGGER_14) ==
+ FIFO_TRIGGER_14) {
+ SET(sc->sc_hwflags, COM_HW_FIFO);
+ printf(": ns16550a, working fifo\n");
+ } else
+ printf(": ns16550, broken fifo\n");
+ else
+ printf(": ns8250 or ns16450, no fifo\n");
+ bus_io_write_1(bc, ioh, com_fifo, 0);
+#ifdef COM_HAYESP
+ }
+#endif
+
+ /* disable interrupts */
+ bus_io_write_1(bc, ioh, com_ier, 0);
+ bus_io_write_1(bc, ioh, com_mcr, 0);
+
+ if (irq != IRQUNK) {
+#if NACE_ISA
+ if (IS_ISA(parent)) {
+ struct isa_attach_args *ia = aux;
+
+ sc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
+ IST_EDGE, IPL_TTY, comintr, sc,
+ sc->sc_dev.dv_xname);
+ } else
+#endif
+#if NACE_RISCBUS
+ if (IS_RISCBUS(parent)) {
+ struct confargs *ca = aux;
+ BUS_INTR_ESTABLISH(ca, comintr, (void *)(long)sc);
+ } else
+#endif
+ panic("comattach: IRQ but can't have one");
+ }
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ cominit(bc, ioh, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("%s: ", sc->sc_dev.dv_xname);
+ kgdb_connect(1);
+ } else
+ printf("%s: kgdb enabled\n",
+ sc->sc_dev.dv_xname);
+ }
+ }
+#endif
+
+ /* XXX maybe move up some? */
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ printf("%s: console\n", sc->sc_dev.dv_xname);
+}
+
+int
+aceopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = DEVUNIT(dev);
+ struct com_softc *sc;
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ struct tty *tp;
+ int s;
+ int error = 0;
+
+ if (unit >= ace_cd.cd_ndevs)
+ return ENXIO;
+ sc = ace_cd.cd_devs[unit];
+ if (!sc || ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING))
+ return ENXIO;
+
+ s = spltty();
+ if (!sc->sc_tty) {
+ tp = sc->sc_tty = ttymalloc();
+ tty_attach(tp);
+ } else
+ tp = sc->sc_tty;
+ splx(s);
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ tp->t_cflag = comconscflag;
+ else
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+
+ s = spltty();
+
+ sc->sc_initialize = 1;
+ comparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ if (comsopen++ == 0)
+ timeout(compoll, NULL, 1);
+
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ bc = sc->sc_bc;
+ ioh = sc->sc_ioh;
+#ifdef COM_HAYESP
+ /* Setup the ESP board */
+ if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) {
+ bus_io_handle_t hayespioh = sc->sc_hayespioh;
+
+ bus_io_write_1(bc, ioh, com_fifo,
+ FIFO_DMA_MODE|FIFO_ENABLE|
+ FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_8);
+
+ /* Set 16550 compatibility mode */
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETMODE);
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2,
+ HAYESP_MODE_FIFO|HAYESP_MODE_RTS|
+ HAYESP_MODE_SCALE);
+
+ /* Set RTS/CTS flow control */
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETFLOWTYPE);
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_RTS);
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_CTS);
+
+ /* Set flow control levels */
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETRXFLOW);
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2,
+ HAYESP_HIBYTE(HAYESP_RXHIWMARK));
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2,
+ HAYESP_LOBYTE(HAYESP_RXHIWMARK));
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2,
+ HAYESP_HIBYTE(HAYESP_RXLOWMARK));
+ bus_io_write_1(bc, hayespioh, HAYESP_CMD2,
+ HAYESP_LOBYTE(HAYESP_RXLOWMARK));
+ } else
+#endif
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
+ /*
+ * (Re)enable and drain FIFOs.
+ *
+ * Certain SMC chips cause problems if the FIFOs are
+ * enabled while input is ready. Turn off the FIFO
+ * if necessary to clear the input. Test the input
+ * ready bit after enabling the FIFOs to handle races
+ * between enabling and fresh input.
+ *
+ * Set the FIFO threshold based on the receive speed.
+ */
+ for (;;) {
+ bus_io_write_1(bc, ioh, com_fifo, 0);
+ delay(100);
+ (void) bus_io_read_1(bc, ioh, com_data);
+ bus_io_write_1(bc, ioh, com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
+ (tp->t_ispeed <= 1200 ?
+ FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ delay(100);
+ if(!ISSET(bus_io_read_1(bc, ioh,
+ com_lsr), LSR_RXRDY))
+ break;
+ }
+ }
+
+ /* flush any pending I/O */
+ while (ISSET(bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY))
+ (void) bus_io_read_1(bc, ioh, com_data);
+ /* you turn me on, baby */
+ sc->sc_mcr = MCR_DTR | MCR_RTS;
+ if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN))
+ SET(sc->sc_mcr, MCR_IENABLE);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC;
+ bus_io_write_1(bc, ioh, com_ier, sc->sc_ier);
+
+ sc->sc_msr = bus_io_read_1(bc, ioh, com_msr);
+ if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) || DEVCUA(dev) ||
+ ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
+ SET(tp->t_state, TS_CARR_ON);
+ else
+ CLR(tp->t_state, TS_CARR_ON);
+ } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ else
+ s = spltty();
+
+ if (DEVCUA(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ /* Ah, but someone already is dialed in... */
+ splx(s);
+ return EBUSY;
+ }
+ sc->sc_cua = 1; /* We go into CUA mode */
+ }
+
+ /* wait for carrier if necessary */
+ if (ISSET(flag, O_NONBLOCK)) {
+ if (!DEVCUA(dev) && sc->sc_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ splx(s);
+ return EBUSY;
+ }
+ } else {
+ while (!(DEVCUA(dev) && sc->sc_cua) &&
+ !ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON)) {
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error) {
+ /* XXX should turn off chip if we're the
+ only waiter */
+ if (DEVCUA(dev))
+ sc->sc_cua = 0;
+ splx(s);
+ return error;
+ }
+ }
+ }
+ splx(s);
+
+ return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+aceclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = DEVUNIT(dev);
+ struct com_softc *sc = ace_cd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ s = spltty();
+ if (!ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ /* can't do any of this stuff .... */
+ CLR(sc->sc_lcr, LCR_SBREAK);
+ bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
+ bus_io_write_1(bc, ioh, com_ier, 0);
+ if (ISSET(tp->t_cflag, HUPCL) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
+ /* XXX perhaps only clear DTR */
+ bus_io_write_1(bc, ioh, com_mcr, 0);
+ }
+ }
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+ if (--comsopen == 0)
+ untimeout(compoll, NULL);
+ sc->sc_cua = 0;
+ splx(s);
+ ttyclose(tp);
+#ifdef COM_DEBUG
+ /* mark it ready for more use if reattached earlier */
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) {
+ printf("aceclose pending cleared\n");
+ }
+#endif
+ CLR(sc->sc_hwflags, COM_HW_ABSENT_PENDING);
+
+#ifdef notyet /* XXXX */
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
+ ttyfree(tp);
+ sc->sc_tty = 0;
+ }
+#endif
+ return 0;
+}
+
+int
+aceread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ int s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+ return EIO;
+ }
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+acewrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ int s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+ return EIO;
+ }
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+acetty(dev)
+ dev_t dev;
+{
+ struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (tp);
+}
+
+static u_char
+tiocm_xxx2mcr(data)
+ int data;
+{
+ u_char m = 0;
+
+ if (ISSET(data, TIOCM_DTR))
+ SET(m, MCR_DTR);
+ if (ISSET(data, TIOCM_RTS))
+ SET(m, MCR_RTS);
+ return m;
+}
+
+int
+aceioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = DEVUNIT(dev);
+ struct com_softc *sc = ace_cd.cd_devs[unit];
+ struct tty *tp = sc->sc_tty;
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+ int error;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ int s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+ return EIO;
+ }
+
+ 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;
+
+ switch (cmd) {
+ case TIOCSBRK:
+ SET(sc->sc_lcr, LCR_SBREAK);
+ bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
+ break;
+ case TIOCCBRK:
+ CLR(sc->sc_lcr, LCR_SBREAK);
+ bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr);
+ break;
+ case TIOCSDTR:
+ SET(sc->sc_mcr, sc->sc_dtr);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ break;
+ case TIOCCDTR:
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMSET:
+ CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
+ case TIOCMBIS:
+ SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMBIC:
+ CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ break;
+ case TIOCMGET: {
+ u_char m;
+ int bits = 0;
+
+ m = sc->sc_mcr;
+ if (ISSET(m, MCR_DTR))
+ SET(bits, TIOCM_DTR);
+ if (ISSET(m, MCR_RTS))
+ SET(bits, TIOCM_RTS);
+ m = sc->sc_msr;
+ if (ISSET(m, MSR_DCD))
+ SET(bits, TIOCM_CD);
+ if (ISSET(m, MSR_CTS))
+ SET(bits, TIOCM_CTS);
+ if (ISSET(m, MSR_DSR))
+ SET(bits, TIOCM_DSR);
+ if (ISSET(m, MSR_RI | MSR_TERI))
+ SET(bits, TIOCM_RI);
+ if (bus_io_read_1(bc, ioh, com_ier))
+ SET(bits, TIOCM_LE);
+ *(int *)data = bits;
+ break;
+ }
+ case TIOCGFLAGS: {
+ int driverbits, userbits = 0;
+
+ driverbits = sc->sc_swflags;
+ if (ISSET(driverbits, COM_SW_SOFTCAR))
+ SET(userbits, TIOCFLAG_SOFTCAR);
+ if (ISSET(driverbits, COM_SW_CLOCAL))
+ SET(userbits, TIOCFLAG_CLOCAL);
+ if (ISSET(driverbits, COM_SW_CRTSCTS))
+ SET(userbits, TIOCFLAG_CRTSCTS);
+ if (ISSET(driverbits, COM_SW_MDMBUF))
+ SET(userbits, TIOCFLAG_MDMBUF);
+
+ *(int *)data = userbits;
+ break;
+ }
+ case TIOCSFLAGS: {
+ int userbits, driverbits = 0;
+
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ userbits = *(int *)data;
+ if (ISSET(userbits, TIOCFLAG_SOFTCAR) ||
+ ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ SET(driverbits, COM_SW_SOFTCAR);
+ if (ISSET(userbits, TIOCFLAG_CLOCAL))
+ SET(driverbits, COM_SW_CLOCAL);
+ if (ISSET(userbits, TIOCFLAG_CRTSCTS))
+ SET(driverbits, COM_SW_CRTSCTS);
+ if (ISSET(userbits, TIOCFLAG_MDMBUF))
+ SET(driverbits, COM_SW_MDMBUF);
+
+ sc->sc_swflags = driverbits;
+ break;
+ }
+ default:
+ return ENOTTY;
+ }
+
+ return 0;
+}
+
+int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+ int ospeed = comspeed(t->c_ospeed);
+ u_char lcr;
+ tcflag_t oldcflag;
+ int s;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ int s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+ return EIO;
+ }
+
+ /* check requested parameters */
+ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return EINVAL;
+
+ lcr = ISSET(sc->sc_lcr, LCR_SBREAK);
+
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ SET(lcr, LCR_5BITS);
+ break;
+ case CS6:
+ SET(lcr, LCR_6BITS);
+ break;
+ case CS7:
+ SET(lcr, LCR_7BITS);
+ break;
+ case CS8:
+ SET(lcr, LCR_8BITS);
+ break;
+ }
+ if (ISSET(t->c_cflag, PARENB)) {
+ SET(lcr, LCR_PENAB);
+ if (!ISSET(t->c_cflag, PARODD))
+ SET(lcr, LCR_PEVEN);
+ }
+ if (ISSET(t->c_cflag, CSTOPB))
+ SET(lcr, LCR_STOPB);
+
+ sc->sc_lcr = lcr;
+
+ s = spltty();
+
+ if (ospeed == 0) {
+ CLR(sc->sc_mcr, MCR_DTR);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ }
+
+ /*
+ * Set the FIFO threshold based on the receive speed, if we are
+ * changing it.
+ */
+ if (sc->sc_initialize || (tp->t_ispeed != t->c_ispeed)) {
+ sc->sc_initialize = 0;
+
+ if (ospeed != 0) {
+ /*
+ * Make sure the transmit FIFO is empty before
+ * proceeding. If we don't do this, some revisions
+ * of the UART will hang. Interestingly enough,
+ * even if we do this will the last character is
+ * still being pushed out, they don't hang. This
+ * seems good enough.
+ */
+ while (ISSET(tp->t_state, TS_BUSY)) {
+ int error;
+
+ ++sc->sc_halt;
+ error = ttysleep(tp, &tp->t_outq,
+ TTOPRI | PCATCH, "comprm", 0);
+ --sc->sc_halt;
+ if (error) {
+ splx(s);
+ comstart(tp);
+ return (error);
+ }
+ }
+
+ bus_io_write_1(bc, ioh, com_lcr, lcr | LCR_DLAB);
+ bus_io_write_1(bc, ioh, com_dlbl, ospeed);
+ bus_io_write_1(bc, ioh, com_dlbh, ospeed >> 8);
+ bus_io_write_1(bc, ioh, com_lcr, lcr);
+ SET(sc->sc_mcr, MCR_DTR);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ } else
+ bus_io_write_1(bc, ioh, com_lcr, lcr);
+
+ if (!ISSET(sc->sc_hwflags, COM_HW_HAYESP) &&
+ ISSET(sc->sc_hwflags, COM_HW_FIFO))
+ bus_io_write_1(bc, ioh, com_fifo,
+ FIFO_ENABLE |
+ (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+ } else
+ bus_io_write_1(bc, ioh, com_lcr, lcr);
+
+ /* When not using CRTSCTS, RTS follows DTR. */
+ if (!ISSET(t->c_cflag, CRTSCTS)) {
+ if (ISSET(sc->sc_mcr, MCR_DTR)) {
+ if (!ISSET(sc->sc_mcr, MCR_RTS)) {
+ SET(sc->sc_mcr, MCR_RTS);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ }
+ } else {
+ if (ISSET(sc->sc_mcr, MCR_RTS)) {
+ CLR(sc->sc_mcr, MCR_RTS);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ }
+ }
+ sc->sc_dtr = MCR_DTR | MCR_RTS;
+ } else
+ sc->sc_dtr = MCR_DTR;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
+ tp->t_cflag = t->c_cflag;
+
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ if (!ISSET(sc->sc_msr, MSR_DCD) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
+ ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) &&
+ (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ }
+
+ /* Just to be sure... */
+ splx(s);
+ comstart(tp);
+ return 0;
+}
+
+void
+comstart_pending(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int s;
+
+ s = spltty();
+ com_absent_notify(sc);
+ splx(s);
+}
+
+void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+ int s;
+
+ s = spltty();
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) {
+ /*
+ * not quite good enough: if caller is ttywait() it will
+ * go to sleep immediately, so hang out a bit and then
+ * prod caller again.
+ */
+ com_absent_notify(sc);
+ timeout(comstart_pending, sc, 1);
+ goto out;
+ }
+ if (ISSET(tp->t_state, TS_BUSY))
+ goto out;
+ if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) ||
+ sc->sc_halt > 0)
+ goto stopped;
+ if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS))
+ goto stopped;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto stopped;
+ selwakeup(&tp->t_wsel);
+ }
+ SET(tp->t_state, TS_BUSY);
+
+ if (!ISSET(sc->sc_ier, IER_ETXRDY)) {
+ SET(sc->sc_ier, IER_ETXRDY);
+ bus_io_write_1(bc, ioh, com_ier, sc->sc_ier);
+ }
+#ifdef COM_HAYESP
+ if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) {
+ u_char buffer[1024], *cp = buffer;
+ int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
+ do
+ bus_io_write_1(bc, ioh, com_data, *cp++);
+ while (--n);
+ }
+ else
+#endif
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
+ u_char buffer[16], *cp = buffer;
+ int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
+ do {
+ bus_io_write_1(bc, ioh, com_data, *cp++);
+ } while (--n);
+ } else
+ bus_io_write_1(bc, ioh, com_data, getc(&tp->t_outq));
+out:
+ splx(s);
+ return;
+stopped:
+ if (ISSET(sc->sc_ier, IER_ETXRDY)) {
+ CLR(sc->sc_ier, IER_ETXRDY);
+ bus_io_write_1(bc, ioh, com_ier, sc->sc_ier);
+ }
+ splx(s);
+}
+
+/*
+ * Stop output on a line.
+ */
+int
+acestop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY))
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ splx(s);
+ return 0;
+}
+
+void
+comdiag(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = spltty();
+ sc->sc_errors = 0;
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+compoll(arg)
+ void *arg;
+{
+ int unit;
+ struct com_softc *sc;
+ struct tty *tp;
+ register u_char *ibufp;
+ u_char *ibufend;
+ register int c;
+ int s;
+ static int lsrmap[8] = {
+ 0, TTY_PE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE,
+ TTY_FE, TTY_PE|TTY_FE
+ };
+
+ s = spltty();
+ if (comevents == 0) {
+ splx(s);
+ goto out;
+ }
+ comevents = 0;
+ splx(s);
+
+ for (unit = 0; unit < ace_cd.cd_ndevs; unit++) {
+ sc = ace_cd.cd_devs[unit];
+ if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
+ continue;
+
+ tp = sc->sc_tty;
+
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ if (ibufp == ibufend) {
+ splx(s);
+ continue;
+ }
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
+
+ if (tp == 0 || !ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ continue;
+ }
+
+ if (ISSET(tp->t_cflag, CRTSCTS) &&
+ !ISSET(sc->sc_mcr, MCR_RTS)) {
+ /* XXX */
+ SET(sc->sc_mcr, MCR_RTS);
+ bus_io_write_1(sc->sc_bc, sc->sc_ioh, com_mcr,
+ sc->sc_mcr);
+ }
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ if (*ibufp & LSR_OE) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ }
+ /* This is ugly, but fast. */
+ c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+
+out:
+ timeout(compoll, NULL, 1);
+}
+
+int
+comintr(arg)
+ void *arg;
+{
+ struct com_softc *sc = arg;
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+ struct tty *tp;
+ u_char lsr, data, msr, delta;
+#ifdef COM_DEBUG
+ int n;
+ struct {
+ u_char iir, lsr, msr;
+ } iter[32];
+#endif
+
+ if (ISSET(sc->sc_hwflags, COM_HW_ABSENT) || !sc->sc_tty)
+ return 0; /* can't do squat. */
+
+#ifdef COM_DEBUG
+ n = 0;
+ if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
+ return (0);
+#else
+ if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
+ return (0);
+#endif
+
+ tp = sc->sc_tty;
+
+ for (;;) {
+#ifdef COM_DEBUG
+ iter[n].lsr =
+#endif
+ lsr = bus_io_read_1(bc, ioh, com_lsr);
+
+ if (ISSET(lsr, LSR_RXRDY)) {
+ register u_char *p = sc->sc_ibufp;
+
+ comevents = 1;
+ do {
+ data = bus_io_read_1(bc, ioh, com_data);
+ if (ISSET(lsr, LSR_BI)) {
+#ifdef notdef
+ printf("break %02x %02x %02x %02x\n",
+ sc->sc_msr, sc->sc_mcr, sc->sc_lcr,
+ sc->sc_dtr);
+#endif
+#ifdef DDB
+ if (ISSET(sc->sc_hwflags,
+ COM_HW_CONSOLE)) {
+ Debugger();
+ goto next;
+ }
+#endif
+ }
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout(comdiag, sc, 60 * hz);
+ } else {
+ *p++ = data;
+ *p++ = lsr;
+ if (p == sc->sc_ibufhigh &&
+ ISSET(tp->t_cflag, CRTSCTS)) {
+ /* XXX */
+ CLR(sc->sc_mcr, MCR_RTS);
+ bus_io_write_1(bc, ioh, com_mcr,
+ sc->sc_mcr);
+ }
+ }
+#ifdef DDB
+ next:
+#endif
+#ifdef COM_DEBUG
+ if (++n >= 32)
+ goto ohfudge;
+ iter[n].lsr =
+#endif
+ lsr = bus_io_read_1(bc, ioh, com_lsr);
+ } while (ISSET(lsr, LSR_RXRDY));
+
+ sc->sc_ibufp = p;
+ }
+#ifdef COM_DEBUG
+ else if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE))
+ printf("weird lsr %02x\n", lsr);
+#endif
+
+#ifdef COM_DEBUG
+ iter[n].msr =
+#endif
+ msr = bus_io_read_1(bc, ioh, com_msr);
+
+ if (msr != sc->sc_msr) {
+ delta = msr ^ sc->sc_msr;
+ sc->sc_msr = msr;
+ if (ISSET(delta, MSR_DCD) &&
+ !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
+ (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) {
+ CLR(sc->sc_mcr, sc->sc_dtr);
+ bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr);
+ }
+ if (ISSET(delta & msr, MSR_CTS) &&
+ ISSET(tp->t_cflag, CRTSCTS)) {
+ /* the line is up and we want to do rts/cts flow control */
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+ }
+
+ if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) {
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+ if (sc->sc_halt > 0)
+ wakeup(&tp->t_outq);
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+
+#ifdef COM_DEBUG
+ if (++n >= 32)
+ goto ohfudge;
+ if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
+ return (1);
+#else
+ if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND))
+ return (1);
+#endif
+ }
+#ifdef COM_DEBUG
+ohfudge:
+ printf("comintr: too many iterations");
+ for (n = 0; n < 32; n++) {
+ if ((n % 4) == 0)
+ printf("\ncomintr: iter[%02d]", n);
+ printf(" %02x %02x %02x", iter[n].iir, iter[n].lsr, iter[n].msr);
+ }
+ printf("\n");
+ printf("comintr: msr %02x mcr %02x lcr %02x ier %02x\n",
+ sc->sc_msr, sc->sc_mcr, sc->sc_lcr, sc->sc_ier);
+ printf("comintr: state %08x cc %d\n", sc->sc_tty->t_state,
+ sc->sc_tty->t_outq.c_cc);
+#endif
+}
+
+/*
+ * Following are all routines needed for COM to act as console
+ */
+#include <dev/cons.h>
+
+void
+acecnprobe(cp)
+ struct consdev *cp;
+{
+ /* XXX NEEDS TO BE FIXED XXX */
+ extern int cputype;
+ bus_chipset_tag_t bc = 0;
+ bus_io_handle_t ioh;
+ int found;
+
+ cp->cn_pri = CN_DEAD;
+
+ if (bus_io_map(bc, CONADDR, COM_NPORTS, &ioh)) {
+ cp->cn_pri = CN_DEAD;
+ return;
+ }
+ ioh = CONADDR;
+ found = comprobe1(bc, ioh, CONADDR);
+ if (!found) {
+ return;
+ }
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == aceopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, CONUNIT);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+acecninit(cp)
+ struct consdev *cp;
+{
+
+#if 0
+ XXX NEEDS TO BE FIXED XXX
+ comconsbc = ???;
+#endif
+ if (bus_io_map(comconsbc, CONADDR, COM_NPORTS, &comconsioh))
+ panic("acecninit: mapping failed");
+
+ cominit(comconsbc, comconsioh, comdefaultrate);
+ comconsaddr = CONADDR;
+ comconsinit = 0;
+}
+
+void
+cominit(bc, ioh, rate)
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ int rate;
+{
+ int s = splhigh();
+ u_char stat;
+
+ bus_io_write_1(bc, ioh, com_lcr, LCR_DLAB);
+ rate = comspeed(comdefaultrate);
+ bus_io_write_1(bc, ioh, com_dlbl, rate);
+ bus_io_write_1(bc, ioh, com_dlbh, rate >> 8);
+ bus_io_write_1(bc, ioh, com_lcr, LCR_8BITS);
+ bus_io_write_1(bc, ioh, com_ier, IER_ERXRDY | IER_ETXRDY);
+ bus_io_write_1(bc, ioh, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
+ stat = bus_io_read_1(bc, ioh, com_iir);
+ splx(s);
+}
+
+int
+acecngetc(dev)
+ dev_t dev;
+{
+ int s = splhigh();
+ bus_chipset_tag_t bc = comconsbc;
+ bus_io_handle_t ioh = comconsioh;
+ u_char stat, c;
+
+ while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY))
+ ;
+ c = bus_io_read_1(bc, ioh, com_data);
+ stat = bus_io_read_1(bc, ioh, com_iir);
+ splx(s);
+ return c;
+}
+
+/*
+ * Console kernel output character routine.
+ */
+void
+acecnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s = splhigh();
+ bus_chipset_tag_t bc = comconsbc;
+ bus_io_handle_t ioh = comconsioh;
+ u_char stat;
+ register int timo;
+
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (comconsinit == 0) {
+ cominit(bc, ioh, comdefaultrate);
+ comconsinit = 1;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo)
+ ;
+ bus_io_write_1(bc, ioh, com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ stat = bus_io_read_1(bc, ioh, com_iir);
+ splx(s);
+}
+
+void
+acecnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+
+}
diff --git a/sys/arch/wgrisc/dev/asc.c b/sys/arch/wgrisc/dev/asc.c
new file mode 100644
index 00000000000..13785ab9c0f
--- /dev/null
+++ b/sys/arch/wgrisc/dev/asc.c
@@ -0,0 +1,2096 @@
+/* $OpenBSD: asc.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+/* $NetBSD: asc.c,v 1.10 1994/12/05 19:11:12 dean Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)asc.c 8.3 (Berkeley) 7/3/94
+ */
+
+/*
+ * 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
+ * Log: scsi_53C94_hdw.c,v
+ * Revision 2.5 91/02/05 17:45:07 mrt
+ * Added author notices
+ * [91/02/04 11:18:43 mrt]
+ *
+ * Changed to use new Mach copyright
+ * [91/02/02 12:17:20 mrt]
+ *
+ * Revision 2.4 91/01/08 15:48:24 rpd
+ * Added continuation argument to thread_block.
+ * [90/12/27 rpd]
+ *
+ * Revision 2.3 90/12/05 23:34:48 af
+ * Recovered from pmax merge.. and from the destruction of a disk.
+ * [90/12/03 23:40:40 af]
+ *
+ * Revision 2.1.1.1 90/11/01 03:39:09 af
+ * Created, from the DEC specs:
+ * "PMAZ-AA TURBOchannel SCSI Module Functional Specification"
+ * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
+ * And from the NCR data sheets
+ * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller"
+ * [90/09/03 af]
+ */
+
+/*
+ * File: scsi_53C94_hdw.h
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 9/90
+ *
+ * Bottom layer of the SCSI driver: chip-dependent functions
+ *
+ * This file contains the code that is specific to the NCR 53C94
+ * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start
+ * operation, and interrupt routine.
+ */
+
+/*
+ * This layer works based on small simple 'scripts' that are installed
+ * at the start of the command and drive the chip to completion.
+ * The idea comes from the specs of the NCR 53C700 'script' processor.
+ *
+ * There are various reasons for this, mainly
+ * - Performance: identify the common (successful) path, and follow it;
+ * at interrupt time no code is needed to find the current status
+ * - Code size: it should be easy to compact common operations
+ * - Adaptability: the code skeleton should adapt to different chips without
+ * terrible complications.
+ * - Error handling: and it is easy to modify the actions performed
+ * by the scripts to cope with strange but well identified sequences
+ *
+ */
+
+#include <asc.h>
+#if NASC > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/pio.h>
+
+#include <wgrisc/dev/scsi.h>
+#include <wgrisc/dev/ascreg.h>
+#include <wgrisc/dev/dma.h>
+
+#include <wgrisc/riscbus/riscbus.h>
+#include <wgrisc/wgrisc/wgrisctype.h>
+
+#define readback(a) { register int foo; foo = (a); }
+extern int cputype;
+
+/*
+ * In 4ns ticks.
+ */
+int asc_to_scsi_period[] = {
+ 32,
+ 33,
+ 34,
+ 35,
+ 5,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+};
+
+/*
+ * Internal forward declarations.
+ */
+static void asc_reset();
+static void asc_startcmd();
+
+#ifdef DEBUG
+int asc_debug = 1;
+int asc_debug_cmd;
+int asc_debug_bn;
+int asc_debug_sz;
+#define NLOG 16
+struct asc_log {
+ u_int status;
+ u_char state;
+ u_char msg;
+ int target;
+ int resid;
+} asc_log[NLOG], *asc_logp = asc_log;
+#define PACK(unit, status, ss, ir) \
+ ((unit << 24) | (status << 16) | (ss << 8) | ir)
+#endif
+
+/*
+ * Scripts are entries in a state machine table.
+ * A script has four parts: a pre-condition, an action, a command to the chip,
+ * and an index into asc_scripts for the next state. The first triggers error
+ * handling if not satisfied and in our case it is formed by the
+ * values of the interrupt register and status register, this
+ * basically captures the phase of the bus and the TC and BS
+ * bits. The action part is just a function pointer, and the
+ * command is what the 53C94 should be told to do at the end
+ * of the action processing. This command is only issued and the
+ * script proceeds if the action routine returns TRUE.
+ * See asc_intr() for how and where this is all done.
+ */
+typedef struct script {
+ int condition; /* expected state at interrupt time */
+ int (*action)(); /* extra operations */
+ int command; /* command to the chip */
+ struct script *next; /* index into asc_scripts for next state */
+} script_t;
+
+/* Matching on the condition value */
+#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8))
+
+/* forward decls of script actions */
+static int script_nop(); /* when nothing needed */
+static int asc_end(); /* all come to an end */
+static int asc_get_status(); /* get status from target */
+static int asc_dma_in(); /* start reading data from target */
+static int asc_last_dma_in(); /* cleanup after all data is read */
+static int asc_resume_in(); /* resume data in after a message */
+static int asc_resume_dma_in(); /* resume DMA after a disconnect */
+static int asc_dma_out(); /* send data to target via dma */
+static int asc_last_dma_out(); /* cleanup after all data is written */
+static int asc_resume_out(); /* resume data out after a message */
+static int asc_resume_dma_out(); /* resume DMA after a disconnect */
+static int asc_sendsync(); /* negotiate sync xfer */
+static int asc_replysync(); /* negotiate sync xfer */
+static int asc_msg_in(); /* process a message byte */
+static int asc_disconnect(); /* process an expected disconnect */
+
+/* Define the index into asc_scripts for various state transitions */
+#define SCRIPT_DATA_IN 0
+#define SCRIPT_CONTINUE_IN 2
+#define SCRIPT_DATA_OUT 3
+#define SCRIPT_CONTINUE_OUT 5
+#define SCRIPT_SIMPLE 6
+#define SCRIPT_GET_STATUS 7
+#define SCRIPT_DONE 8
+#define SCRIPT_MSG_IN 9
+#define SCRIPT_REPLY_SYNC 11
+#define SCRIPT_TRY_SYNC 12
+#define SCRIPT_DISCONNECT 15
+#define SCRIPT_RESEL 16
+#define SCRIPT_RESUME_IN 17
+#define SCRIPT_RESUME_DMA_IN 18
+#define SCRIPT_RESUME_OUT 19
+#define SCRIPT_RESUME_DMA_OUT 20
+#define SCRIPT_RESUME_NO_DATA 21
+
+/*
+ * Scripts
+ */
+script_t asc_scripts[] = {
+ /* start data in */
+ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */
+ asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_IN + 1]},
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */
+ asc_last_dma_in, ASC_CMD_I_COMPLETE,
+ &asc_scripts[SCRIPT_GET_STATUS]},
+
+ /* continue data in after a chunk is finished */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */
+ asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_IN + 1]},
+
+ /* start data out */
+ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */
+ asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_OUT + 1]},
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */
+ asc_last_dma_out, ASC_CMD_I_COMPLETE,
+ &asc_scripts[SCRIPT_GET_STATUS]},
+
+ /* continue data out after a chunk is finished */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */
+ asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_OUT + 1]},
+
+ /* simple command with no data transfer */
+ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */
+ script_nop, ASC_CMD_I_COMPLETE,
+ &asc_scripts[SCRIPT_GET_STATUS]},
+
+ /* get status and finish command */
+ {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */
+ asc_get_status, ASC_CMD_MSG_ACPT,
+ &asc_scripts[SCRIPT_DONE]},
+ {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */
+ asc_end, ASC_CMD_NOP,
+ &asc_scripts[SCRIPT_DONE]},
+
+ /* message in */
+ {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */
+ asc_msg_in, ASC_CMD_MSG_ACPT,
+ &asc_scripts[SCRIPT_MSG_IN + 1]},
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */
+ script_nop, ASC_CMD_XFER_INFO,
+ &asc_scripts[SCRIPT_MSG_IN]},
+
+ /* send synchonous negotiation reply */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */
+ asc_replysync, ASC_CMD_XFER_INFO,
+ &asc_scripts[SCRIPT_REPLY_SYNC]},
+
+ /* try to negotiate synchonous transfer parameters */
+ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */
+ asc_sendsync, ASC_CMD_XFER_INFO,
+ &asc_scripts[SCRIPT_TRY_SYNC + 1]},
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */
+ script_nop, ASC_CMD_XFER_INFO,
+ &asc_scripts[SCRIPT_MSG_IN]},
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */
+ script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_RESUME_NO_DATA]},
+
+ /* handle a disconnect */
+ {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */
+ asc_disconnect, ASC_CMD_ENABLE_SEL,
+ &asc_scripts[SCRIPT_RESEL]},
+
+ /* reselect sequence: this is just a placeholder so match fails */
+ {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */
+ script_nop, ASC_CMD_MSG_ACPT,
+ &asc_scripts[SCRIPT_RESEL]},
+
+ /* resume data in after a message */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */
+ asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_IN + 1]},
+
+ /* resume partial DMA data in after a message */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */
+ asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_IN + 1]},
+
+ /* resume data out after a message */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */
+ asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_OUT + 1]},
+
+ /* resume partial DMA data out after a message */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */
+ asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA,
+ &asc_scripts[SCRIPT_DATA_OUT + 1]},
+
+ /* resume after a message when there is no more data */
+ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */
+ script_nop, ASC_CMD_I_COMPLETE,
+ &asc_scripts[SCRIPT_GET_STATUS]},
+};
+
+/*
+ * State kept for each active SCSI device.
+ */
+typedef struct scsi_state {
+ script_t *script; /* saved script while processing error */
+ struct scsi_generic cmd;/* storage for scsi command */
+ int statusByte; /* status byte returned during STATUS_PHASE */
+ u_int dmaBufSize; /* DMA buffer size */
+ int dmalen; /* amount to transfer in this chunk */
+ int dmaresid; /* amount not transfered if chunk suspended */
+ int cmdlen; /* length of command in cmd */
+ int buflen; /* total remaining amount of data to transfer */
+ vm_offset_t buf; /* current pointer within scsicmd->buf */
+ int flags; /* see below */
+ int msglen; /* number of message bytes to read */
+ int msgcnt; /* number of message bytes received */
+ u_char sync_period; /* DMA synchronous period */
+ u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */
+ u_char msg_out; /* next MSG_OUT byte to send */
+ u_char msg_in[16]; /* buffer for multibyte messages */
+} State;
+
+/* state flags */
+#define DISCONN 0x001 /* true if currently disconnected from bus */
+#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */
+#define DMA_IN 0x004 /* true if reading from SCSI device */
+#define DMA_OUT 0x010 /* true if writing to SCSI device */
+#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */
+#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */
+#define PARITY_ERR 0x080 /* true if parity error seen */
+#define CHECK_SENSE 0x100 /* true if doing sense command */
+
+struct dma_softc_t;
+/*
+ * State kept for each active SCSI host interface (53C94).
+ */
+struct asc_softc {
+ struct device sc_dev; /* use as a device */
+ asc_regmap_t *regs; /* chip address */
+ dma_softc_t dma; /* dma control structure */
+ int sc_id; /* SCSI ID of this interface */
+ int myidmask; /* ~(1 << myid) */
+ int state; /* current SCSI connection state */
+ int target; /* target SCSI ID if busy */
+ script_t *script; /* next expected interrupt & action */
+ struct scsi_xfer *cmdq[ASC_NCMD];/* Pointer to queued commands */
+ struct scsi_xfer *cmd[ASC_NCMD];/* Pointer to current active command */
+ State st[ASC_NCMD]; /* state info for each active command */
+ int min_period; /* Min transfer period clk/byte */
+ int max_period; /* Max transfer period clk/byte */
+ int ccf; /* CCF, whatever that really is? */
+ int timeout_250; /* 250ms timeout */
+ int tb_ticks; /* 4ns. ticks/tb channel ticks */
+ struct scsi_link sc_link; /* scsi link struct */
+};
+
+#define ASC_STATE_IDLE 0 /* idle state */
+#define ASC_STATE_BUSY 1 /* selecting or currently connected */
+#define ASC_STATE_TARGET 2 /* currently selected as target */
+#define ASC_STATE_RESEL 3 /* currently waiting for reselect */
+
+typedef struct asc_softc *asc_softc_t;
+
+static char dma_buffer[MAXPHYS]; /*yieek*/ /*XXX*/
+
+/*
+ * Autoconfiguration data for config.
+ */
+int ascmatch __P((struct device *, void *, void *));
+void ascattach __P((struct device *, struct device *, void *));
+int ascprint(void *, const char *);
+
+struct cfattach asc_ca = {
+ sizeof(struct asc_softc), ascmatch, ascattach
+};
+struct cfdriver asc_cd = {
+ NULL, "asc", DV_DULL, NULL, 0
+};
+
+/*
+ * Glue to the machine dependent scsi
+ */
+int asc_scsi_cmd __P((struct scsi_xfer *));
+void asc_minphys __P((struct buf *));
+
+struct scsi_adapter asc_switch = {
+ asc_scsi_cmd,
+ asc_minphys,
+ NULL,
+ NULL,
+};
+
+struct scsi_device asc_dev = {
+/*XXX*/ NULL, /* Use default error handler */
+/*XXX*/ NULL, /* have a queue, served by this */
+/*XXX*/ NULL, /* have no async handler */
+/*XXX*/ NULL, /* Use default 'done' routine */
+};
+
+static void asc_start();
+static int asc_intr();
+
+/*
+ * Match driver based on name
+ */
+int
+ascmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct confargs *ca = aux;
+
+ if(!BUS_MATCHNAME(ca, "asc"))
+ return(0);
+ return(1);
+}
+
+void
+ascattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ register struct confargs *ca = aux;
+ register asc_softc_t asc = (void *)self;
+ register asc_regmap_t *regs;
+ int id, s, i;
+ int bufsiz;
+
+ /*
+ * Initialize hw descriptor, cache some pointers
+ */
+ asc->regs = (asc_regmap_t *)BUS_CVTADDR(ca);
+
+ /*
+ * Set up machine dependencies.
+ * 1) how to do dma
+ * 2) timing based on chip clock frequency
+ */
+ switch (cputype) {
+ case WGRISC9100:
+ bufsiz = MAXPHYS; /* Scatter gather in software */
+ break;
+ default:
+ bufsiz = 64 * 1024;
+ };
+ /*
+ * Now for timing. WGRISC has a 20Mhz
+ */
+ switch (cputype) {
+ case WGRISC9100:
+ asc->min_period = ASC_MIN_PERIOD20;
+ asc->max_period = ASC_MAX_PERIOD20;
+ asc->ccf = ASC_CCF(20);
+ asc->timeout_250 = ASC_TIMEOUT_250(20, asc->ccf);
+ asc->tb_ticks = 10;
+ asc->dma.dma_ch = DMA_CH0;
+ break;
+ default:
+ asc->min_period = ASC_MIN_PERIOD12;
+ asc->max_period = ASC_MAX_PERIOD12;
+ asc->ccf = ASC_CCF(13);
+ asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);
+ asc->tb_ticks = 20;
+ break;
+ };
+
+ asc->state = ASC_STATE_IDLE;
+ asc->target = -1;
+
+ regs = asc->regs;
+
+ /*
+ * Reset chip, fully. Note that interrupts are already enabled.
+ */
+ s = splbio();
+
+ /* preserve our ID for now */
+#if 0
+ asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
+#else
+ asc->sc_id = 7; /* XXX Until boot roms set up scsi id */
+#endif
+ asc->myidmask = ~(1 << asc->sc_id);
+
+ asc_reset(asc, regs);
+
+ /*
+ * Our SCSI id on the bus.
+ * The user can set this via the prom on 3maxen/picaen.
+ * If this changes it is easy to fix: make a default that
+ * can be changed as boot arg.
+ */
+#ifdef unneeded
+ regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |
+ (scsi_initiator_id[unit] & 0x7);
+ asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;
+#endif
+ id = asc->sc_id;
+ splx(s);
+
+ /*
+ * Give each target its DMA buffer region.
+ * The buffer address is the same for all targets,
+ * the allocated dma viritual scatter/gather space.
+ */
+ for (i = 0; i < ASC_NCMD; i++) {
+ asc->st[i].dmaBufSize = bufsiz;
+ }
+
+ /*
+ * Set up interrupt handler.
+ */
+ BUS_INTR_ESTABLISH(ca, asc_intr, (void *)asc);
+
+ printf(": NCR53C94, target %d\n", id);
+
+ /*
+ * Fill in the prototype scsi link.
+ */
+ asc->sc_link.adapter_softc = asc;
+ asc->sc_link.adapter_target = asc->sc_id;
+ asc->sc_link.adapter = &asc_switch;
+ asc->sc_link.device = &asc_dev;
+ asc->sc_link.openings = 2;
+
+ /*
+ * Now try to attach all the sub devices.
+ */
+ config_found(self, &asc->sc_link, ascprint);
+}
+
+int
+ascprint(aux, name)
+ void *aux;
+ const char *name;
+{
+}
+
+/*
+ * Driver breaks down request transfer size.
+ */
+void
+asc_minphys(bp)
+ struct buf *bp;
+{
+ minphys(bp);
+}
+
+/*
+ * Start activity on a SCSI device.
+ * We maintain information on each device separately since devices can
+ * connect/disconnect during an operation.
+ */
+int
+asc_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct asc_softc *asc = sc_link->adapter_softc;
+ State *state = &asc->st[sc_link->target];
+
+ int flags, s;
+
+ flags = xs->flags;
+
+ /*
+ * Flush caches for any data buffer
+ */
+ if(xs->datalen != 0) {
+#ifdef R4K
+ R4K_HitFlushDCache(xs->data, xs->datalen);
+#else
+ R3K_FlushDCache();
+#endif
+ }
+ /*
+ * The hack on the next few lines are to avoid buffers
+ * mapped to UADDR. Realloc to the kva uarea address.
+ */
+ if((u_int)(xs->data) >= UADDR) {
+ xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curproc->p_addr);
+ }
+
+ /*
+ * Check if another command is already in progress.
+ * We may have to change this if we allow SCSI devices with
+ * separate LUNs.
+ */
+ s = splbio();
+ if (asc->cmd[sc_link->target]) {
+ if (asc->cmdq[sc_link->target]) {
+ splx(s);
+ printf("asc_scsi_cmd: called when target busy");
+ xs->error = XS_DRIVER_STUFFUP;
+ return TRY_AGAIN_LATER;
+ }
+ asc->cmdq[sc_link->target] = xs;
+ splx(s);
+ return SUCCESSFULLY_QUEUED;
+ }
+ asc->cmd[sc_link->target] = xs;
+
+ /*
+ * Going to launch.
+ * Make a local copy of the command and some pointers.
+ */
+ asc_startcmd(asc, sc_link->target);
+
+ /*
+ * If in startup, interrupts not usable yet.
+ */
+ if(flags & SCSI_POLL) {
+ return(asc_poll(asc,sc_link->target));
+ }
+ splx(s);
+ return SUCCESSFULLY_QUEUED;
+}
+
+int
+asc_poll(asc, target)
+ struct asc_softc *asc;
+ int target;
+{
+ struct scsi_xfer *scsicmd = asc->cmd[target];
+ int count = scsicmd->timeout * 10;
+
+ while(count) {
+ if(asc->regs->asc_status &ASC_CSR_INT) {
+ asc_intr(asc);
+ }
+ if(scsicmd->flags & ITSDONE)
+ break;
+ DELAY(5);
+ count--;
+ }
+ if(count == 0) {
+ scsicmd->error = XS_TIMEOUT;
+ asc_end(asc, 0, 0, 0);
+ }
+ return COMPLETE;
+}
+
+static void
+asc_reset(asc, regs)
+ asc_softc_t asc;
+ asc_regmap_t *regs;
+{
+ int i;
+
+ /*
+ * Reset chip and SCSI bus. Put everything in a known state.
+ */
+ regs->asc_cmd = ASC_CMD_RESET;
+ wbflush(); DELAY(25);
+ regs->asc_cmd = ASC_CMD_NOP;
+ wbflush(); DELAY(25);
+ regs->asc_cmd = ASC_CMD_BUS_RESET;
+ wbflush();
+ while(!(regs->asc_status & ASC_CSR_INT)) {
+ /*void*/
+ }
+ regs->asc_cmd = ASC_CMD_RESET;
+ wbflush(); DELAY(25);
+ regs->asc_cmd = ASC_CMD_NOP;
+ wbflush(); DELAY(25);
+
+ /*
+ * Set up various chip parameters
+ */
+ regs->asc_ccf = asc->ccf;
+ wbflush(); DELAY(25);
+ regs->asc_sel_timo = asc->timeout_250;
+ /* restore our ID */
+ regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK;
+ /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */
+ regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;
+ regs->asc_cnfg3 = 0;
+ /* zero anything else */
+ ASC_TC_PUT(regs, 0);
+ regs->asc_syn_p = asc->min_period;
+ regs->asc_syn_o = 0; /* async for now */
+ wbflush();
+}
+
+/*
+ * Start a SCSI command on a target.
+ */
+static void
+asc_startcmd(asc, target)
+ asc_softc_t asc;
+ int target;
+{
+ asc_regmap_t *regs;
+ State *state;
+ struct scsi_xfer *scsicmd;
+ int i, len;
+
+ /*
+ * See if another target is currently selected on this SCSI bus.
+ */
+ if (asc->target >= 0)
+ return;
+
+ regs = asc->regs;
+
+ /*
+ * If a reselection is in progress, it is Ok to ignore it since
+ * the ASC will automatically cancel the command and flush
+ * the FIFO if the ASC is reselected before the command starts.
+ * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if
+ * a reselect occurs before starting the command.
+ */
+
+ asc->state = ASC_STATE_BUSY;
+ asc->target = target;
+
+ /* cache some pointers */
+ scsicmd = asc->cmd[target];
+ state = &asc->st[target];
+
+ /*
+ * Init the chip and target state.
+ */
+ state->flags = state->flags & (DID_SYNC | CHECK_SENSE);
+ state->script = (script_t *)0;
+ state->msg_out = SCSI_NO_OP;
+
+ /*
+ * Set up for DMA of command output. Also need to flush cache.
+ */
+ if(!(state->flags & CHECK_SENSE)) {
+ bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen);
+ state->cmdlen = scsicmd->cmdlen;
+ state->buf = (vm_offset_t)scsicmd->data;
+ state->buflen = scsicmd->datalen;
+ }
+ len = state->cmdlen;
+ state->dmalen = len;
+
+#ifdef DEBUG
+ if (asc_debug > 1) {
+ printf("asc_startcmd: %s target %d cmd %x len %d\n",
+ asc->sc_dev.dv_xname, target,
+ state->cmd.opcode, state->buflen);
+ }
+#endif
+
+ /* check for simple SCSI command with no data transfer */
+ if(state->flags & CHECK_SENSE) {
+ asc->script = &asc_scripts[SCRIPT_DATA_IN];
+ state->flags |= DMA_IN;
+ }
+ else if (scsicmd->flags & SCSI_DATA_OUT) {
+ asc->script = &asc_scripts[SCRIPT_DATA_OUT];
+ state->flags |= DMA_OUT;
+ }
+ else if (scsicmd->flags & SCSI_DATA_IN) {
+ asc->script = &asc_scripts[SCRIPT_DATA_IN];
+ state->flags |= DMA_IN;
+ }
+ else if (state->buflen == 0) {
+ /* check for sync negotiation */
+ if ((scsicmd->flags & /* SCSICMD_USE_SYNC */ 0) &&
+ !(state->flags & DID_SYNC)) {
+ asc->script = &asc_scripts[SCRIPT_TRY_SYNC];
+ state->flags |= TRY_SYNC;
+ } else
+ asc->script = &asc_scripts[SCRIPT_SIMPLE];
+ state->buf = (vm_offset_t)0;
+ }
+
+#ifdef DEBUG
+ asc_debug_cmd = state->cmd.opcode;
+ if (state->cmd.opcode == SCSI_READ_EXT) {
+ asc_debug_bn = (state->cmd.bytes[1] << 24) |
+ (state->cmd.bytes[2] << 16) |
+ (state->cmd.bytes[3] << 8) |
+ state->cmd.bytes[4];
+ asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7];
+ }
+ asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd);
+ asc_logp->target = asc->target;
+ asc_logp->state = asc->script - asc_scripts;
+ asc_logp->msg = SCSI_DIS_REC_IDENTIFY;
+ asc_logp->resid = scsicmd->datalen;
+ if (++asc_logp >= &asc_log[NLOG])
+ asc_logp = asc_log;
+#endif
+
+ /* preload the FIFO with the message and command to be sent */
+ regs->asc_fifo = SCSI_DIS_REC_IDENTIFY | (scsicmd->sc_link->lun & 0x07);
+
+ for( i = 0; i < len; i++ ) {
+ regs->asc_fifo = ((caddr_t)&state->cmd)[i];
+ }
+ ASC_TC_PUT(regs, 0);
+ readback(regs->asc_cmd);
+ regs->asc_cmd = ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+
+ regs->asc_dbus_id = target;
+ readback(regs->asc_dbus_id);
+ regs->asc_syn_p = state->sync_period;
+ readback(regs->asc_syn_p);
+ regs->asc_syn_o = state->sync_offset;
+ readback(regs->asc_syn_o);
+
+/*XXX PEFO */
+/* we are not using sync transfer now, need to check this if we will */
+
+ if (state->flags & TRY_SYNC)
+ regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;
+ else
+ regs->asc_cmd = ASC_CMD_SEL_ATN;
+ readback(regs->asc_cmd);
+}
+
+/*
+ * Interrupt routine
+ * Take interrupts from the chip
+ *
+ * Implementation:
+ * Move along the current command's script if
+ * all is well, invoke error handler if not.
+ */
+int
+asc_intr(sc)
+ void *sc;
+{
+ asc_softc_t asc = sc;
+ asc_regmap_t *regs = asc->regs;
+ State *state;
+ script_t *scpt;
+ int ss, ir, status;
+
+ /* collect ephemeral information */
+ status = regs->asc_status;
+ ss = regs->asc_ss;
+
+ if ((status & ASC_CSR_INT) == 0) /* Make sure it's a real interrupt */
+ return;
+
+ ir = regs->asc_intr; /* this resets the previous two */
+ scpt = asc->script;
+
+#ifdef DEBUG
+ asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir);
+ asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;
+ asc_logp->state = scpt - asc_scripts;
+ asc_logp->msg = -1;
+ asc_logp->resid = 0;
+ if (++asc_logp >= &asc_log[NLOG])
+ asc_logp = asc_log;
+ if (asc_debug > 2)
+ printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",
+ status, ss, ir, scpt - asc_scripts, scpt->condition);
+#endif
+
+ /* check the expected state */
+ if (SCRIPT_MATCH(ir, status) == scpt->condition) {
+ /*
+ * Perform the appropriate operation, then proceed.
+ */
+ if ((*scpt->action)(asc, status, ss, ir)) {
+ regs->asc_cmd = scpt->command;
+ readback(regs->asc_cmd);
+ asc->script = scpt->next;
+ }
+ goto done;
+ }
+
+ /*
+ * Check for parity error.
+ * Hardware will automatically set ATN
+ * to request the device for a MSG_OUT phase.
+ */
+ if (status & ASC_CSR_PE) {
+ printf("%s: SCSI device %d: incomming parity error seen\n",
+ asc->sc_dev.dv_xname, asc->target);
+ asc->st[asc->target].flags |= PARITY_ERR;
+ }
+
+ /*
+ * Check for gross error.
+ * Probably a bug in a device driver.
+ */
+ if (status & ASC_CSR_GE) {
+ printf("%s: SCSI device %d: gross error\n",
+ asc->sc_dev.dv_xname, asc->target);
+ goto abort;
+ }
+
+ /* check for message in or out */
+ if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {
+ register int len, fifo;
+
+ state = &asc->st[asc->target];
+ switch (ASC_PHASE(status)) {
+ case ASC_PHASE_DATAI:
+ case ASC_PHASE_DATAO:
+ ASC_TC_GET(regs, len);
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+ printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",
+ state->buflen, state->dmalen, len, fifo);
+ goto abort;
+
+ case ASC_PHASE_MSG_IN:
+ break;
+
+ case ASC_PHASE_MSG_OUT:
+ /*
+ * Check for parity error.
+ * Hardware will automatically set ATN
+ * to request the device for a MSG_OUT phase.
+ */
+ if (state->flags & PARITY_ERR) {
+ state->flags &= ~PARITY_ERR;
+ state->msg_out = SCSI_MESSAGE_PARITY_ERROR;
+ /* reset message in counter */
+ state->msglen = 0;
+ } else
+ state->msg_out = SCSI_NO_OP;
+ regs->asc_fifo = state->msg_out;
+ regs->asc_cmd = ASC_CMD_XFER_INFO;
+ readback(regs->asc_cmd);
+ goto done;
+
+ case ASC_PHASE_STATUS:
+ /* probably an error in the SCSI command */
+ asc->script = &asc_scripts[SCRIPT_GET_STATUS];
+ regs->asc_cmd = ASC_CMD_I_COMPLETE;
+ readback(regs->asc_cmd);
+ goto done;
+
+ default:
+ goto abort;
+ }
+
+ if (state->script)
+ goto abort;
+
+ /*
+ * OK, message coming in clean up whatever is going on.
+ * Get number of bytes left to transfered from byte counter
+ * counter decrements when data is trf on the SCSI bus
+ */
+ ASC_TC_GET(regs, len);
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+ /* flush any data in the FIFO */
+ if (fifo && !(state->flags & DMA_IN_PROGRESS)) {
+printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo);
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ DELAY(2);
+ }
+ else if (fifo && state->flags & DMA_IN_PROGRESS) {
+ if (state->flags & DMA_OUT) {
+ len += fifo; /* Bytes dma'ed but not sent */
+ }
+ else if (state->flags & DMA_IN) {
+ u_char *cp;
+
+ printf("asc_intr: IN: dmalen %d len %d fifo %d\n",
+ state->dmalen, len, fifo); /* XXX */
+ }
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ DELAY(2);
+ }
+ if (len && (state->flags & DMA_IN_PROGRESS)) {
+ /* save number of bytes still to be sent or received */
+ state->dmaresid = len;
+ state->flags &= ~DMA_IN_PROGRESS;
+ ASC_TC_PUT(regs, 0);
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ /* setup state to resume to */
+ if (state->flags & DMA_IN) {
+ /*
+ * Since the ASC_CNFG3_SRB bit of the
+ * cnfg3 register bit is not set,
+ * we just transferred an extra byte.
+ * Since we can't resume on an odd byte
+ * boundary, we copy the valid data out
+ * and resume DMA at the start address.
+ */
+ if (len & 1) {
+ printf("asc_intr: msg in len %d (fifo %d)\n",
+ len, fifo); /* XXX */
+ len = state->dmalen - len;
+ goto do_in;
+ }
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_DMA_IN];
+ } else if (state->flags & DMA_OUT)
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_DMA_OUT];
+ else
+ state->script = asc->script;
+ } else if (state->flags & DMA_IN) {
+ if (len) {
+#ifdef DEBUG
+ printf("asc_intr: 1: bn %d len %d (fifo %d)\n",
+ asc_debug_bn, len, fifo); /* XXX */
+#endif
+ goto abort;
+ }
+ /* setup state to resume to */
+ if (state->flags & DMA_IN_PROGRESS) {
+ len = state->dmalen;
+ state->flags &= ~DMA_IN_PROGRESS;
+ do_in:
+ DMA_END(&asc->dma);
+ state->buf += len;
+ state->buflen -= len;
+ }
+ if (state->buflen)
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_IN];
+ else
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_NO_DATA];
+ } else if (state->flags & DMA_OUT) {
+ if (len) {
+ printf("asc_intr: 2: len %d (fifo %d)\n", len,
+ fifo); /* XXX */
+/* XXX THEO */
+#if 1
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ DELAY(2);
+ len = 0;
+#else
+ goto abort;
+#endif
+ }
+ /*
+ * If this is the last chunk, the next expected
+ * state is to get status.
+ */
+ if (state->flags & DMA_IN_PROGRESS) {
+ state->flags &= ~DMA_IN_PROGRESS;
+ DMA_END(&asc->dma);
+ len = state->dmalen;
+ state->buf += len;
+ state->buflen -= len;
+ }
+ if (state->buflen)
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_OUT];
+ else
+ state->script =
+ &asc_scripts[SCRIPT_RESUME_NO_DATA];
+ } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])
+ state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];
+ else
+ state->script = asc->script;
+
+ /* setup to receive a message */
+ asc->script = &asc_scripts[SCRIPT_MSG_IN];
+ state->msglen = 0;
+ regs->asc_cmd = ASC_CMD_XFER_INFO;
+ readback(regs->asc_cmd);
+ goto done;
+ }
+
+ /* check for SCSI bus reset */
+ if (ir & ASC_INT_RESET) {
+ register int i;
+
+ printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname);
+ /* need to flush any pending commands */
+ for (i = 0; i < ASC_NCMD; i++) {
+ if (!asc->cmd[i])
+ continue;
+ asc->cmd[i]->error = XS_DRIVER_STUFFUP;
+ asc_end(asc, 0, 0, 0);
+ }
+ /* rearbitrate synchronous offset */
+ for (i = 0; i < ASC_NCMD; i++) {
+ asc->st[i].sync_offset = 0;
+ asc->st[i].flags = 0;
+ }
+ asc->target = -1;
+ return;
+ }
+
+ /* check for command errors */
+ if (ir & ASC_INT_ILL)
+ goto abort;
+
+ /* check for disconnect */
+ if (ir & ASC_INT_DISC) {
+ state = &asc->st[asc->target];
+ switch (asc->script - asc_scripts) {
+ case SCRIPT_DONE:
+ case SCRIPT_DISCONNECT:
+ /*
+ * Disconnects can happen normally when the
+ * command is complete with the phase being
+ * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN.
+ * The SCRIPT_MATCH() only checks for one phase
+ * so we can wind up here.
+ * Perform the appropriate operation, then proceed.
+ */
+ if ((*scpt->action)(asc, status, ss, ir)) {
+ regs->asc_cmd = scpt->command;
+ readback(regs->asc_cmd);
+ asc->script = scpt->next;
+ }
+ goto done;
+
+ case SCRIPT_TRY_SYNC:
+ case SCRIPT_SIMPLE:
+ case SCRIPT_DATA_IN:
+ case SCRIPT_DATA_OUT: /* one of the starting scripts */
+ if (ASC_SS(ss) == 0) {
+ /* device did not respond */
+ if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ }
+ asc->cmd[asc->target]->error = XS_DRIVER_STUFFUP;
+ asc_end(asc, status, ss, ir);
+ return;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ printf("%s: SCSI device %d: unexpected disconnect\n",
+ asc->sc_dev.dv_xname, asc->target);
+#ifdef DEBUG
+ asc_DumpLog("asc_disc");
+#endif
+ /*
+ * On rare occasions my RZ24 does a disconnect during
+ * data in phase and the following seems to keep it
+ * happy.
+ * XXX Should a scsi disk ever do this??
+ */
+ asc->script = &asc_scripts[SCRIPT_RESEL];
+ asc->state = ASC_STATE_RESEL;
+ state->flags |= DISCONN;
+ regs->asc_cmd = ASC_CMD_ENABLE_SEL;
+ readback(regs->asc_cmd);
+ return;
+ }
+ }
+
+ /* check for reselect */
+ if (ir & ASC_INT_RESEL) {
+ unsigned fifo, id, msg;
+
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+ if (fifo < 2)
+ goto abort;
+ /* read unencoded SCSI ID and convert to binary */
+ msg = regs->asc_fifo & asc->myidmask;
+ for (id = 0; (msg & 1) == 0; id++)
+ msg >>= 1;
+ /* read identify message */
+ msg = regs->asc_fifo;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].msg = msg;
+ else
+ asc_logp[-1].msg = msg;
+#endif
+ asc->state = ASC_STATE_BUSY;
+ asc->target = id;
+ state = &asc->st[id];
+ asc->script = state->script;
+ state->script = (script_t *)0;
+ if (!(state->flags & DISCONN))
+ goto abort;
+ state->flags &= ~DISCONN;
+ regs->asc_syn_p = state->sync_period;
+ regs->asc_syn_o = state->sync_offset;
+ regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(regs->asc_cmd);
+ goto done;
+ }
+
+ /* check if we are being selected as a target */
+ if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))
+ goto abort;
+
+ /*
+ * 'ir' must be just ASC_INT_FC.
+ * This is normal if canceling an ASC_ENABLE_SEL.
+ */
+
+done:
+ wbflush();
+ /*
+ * If the next interrupt comes in immediatly the interrupt
+ * dispatcher (which we are returning to) will catch it
+ * before returning to the interrupted code.
+ */
+ return;
+
+abort:
+#ifdef DEBUG
+ asc_DumpLog("asc_intr");
+#endif
+#if 0
+ panic("asc_intr");
+#else
+ boot(4); /* XXX */
+#endif
+}
+
+/*
+ * All the many little things that the interrupt
+ * routine might switch to.
+ */
+
+/* ARGSUSED */
+static int
+script_nop(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_get_status(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register int data;
+
+ /*
+ * Get the last two bytes in the FIFO.
+ */
+ if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {
+ printf("asc_get_status: cmdreg %x, fifo cnt %d\n",
+ regs->asc_cmd, data); /* XXX */
+#ifdef DEBUG
+ asc_DumpLog("get_status"); /* XXX */
+#endif
+ if (data < 2) {
+ asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(asc->regs->asc_cmd);
+ return (0);
+ }
+ do {
+ data = regs->asc_fifo;
+ } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);
+ }
+
+ /* save the status byte */
+ asc->st[asc->target].statusByte = data = regs->asc_fifo;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].msg = data;
+ else
+ asc_logp[-1].msg = data;
+#endif
+
+ /* get the (presumed) command_complete message */
+ if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)
+ return (1);
+
+#ifdef DEBUG
+ printf("asc_get_status: status %x cmd %x\n",
+ asc->st[asc->target].statusByte, data);
+ asc_DumpLog("asc_get_status");
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+asc_end(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ struct scsi_xfer *scsicmd;
+ struct scsi_link *sc_link;
+ State *state;
+ int i, target;
+
+ asc->state = ASC_STATE_IDLE;
+ target = asc->target;
+ asc->target = -1;
+ scsicmd = asc->cmd[target];
+ sc_link = scsicmd->sc_link;
+ asc->cmd[target] = (struct scsi_xfer *)0;
+ state = &asc->st[target];
+
+#ifdef DEBUG
+ if (asc_debug > 1) {
+ printf("asc_end: %s target %d cmd %x err %d resid %d\n",
+ asc->sc_dev.dv_xname, target,
+ state->cmd.opcode, scsicmd->error, state->buflen);
+ }
+#endif
+#ifdef DIAGNOSTIC
+ if (target < 0 || !scsicmd)
+ panic("asc_end");
+#endif
+
+ /* look for disconnected devices */
+ for (i = 0; i < ASC_NCMD; i++) {
+ if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))
+ continue;
+ asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;
+ readback(asc->regs->asc_cmd);
+ asc->state = ASC_STATE_RESEL;
+ asc->script = &asc_scripts[SCRIPT_RESEL];
+ break;
+ }
+
+ if(scsicmd->error == XS_NOERROR && !(state->flags & CHECK_SENSE)) {
+ if((state->statusByte & ST_MASK) == SCSI_CHECK) {
+ struct scsi_sense *ss = (void *)&state->cmd;
+ /* Save return values */
+ scsicmd->resid = state->buflen;
+ scsicmd->status = state->statusByte;
+ /* Set up sense request command */
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = sc_link->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ state->cmdlen = sizeof(*ss);
+ state->buf = (vm_offset_t)&scsicmd->sense;
+ state->buflen = sizeof(struct scsi_sense_data);
+ state->flags |= CHECK_SENSE;
+#ifdef R4K
+ R4K_HitFlushDCache(state->buf, state->buflen);
+#else
+ R3K_FlushDCache();
+#endif
+ asc->cmd[target] = scsicmd;
+ asc_startcmd(asc, target);
+ return(0);
+ }
+ }
+
+ if(scsicmd->error == XS_NOERROR && (state->flags & CHECK_SENSE)) {
+ scsicmd->error = XS_SENSE;
+ }
+ else {
+ scsicmd->resid = state->buflen;
+ }
+ state->flags &= ~CHECK_SENSE;
+
+ /*
+ * Look for another device that is ready.
+ * May want to keep last one started and increment for fairness
+ * rather than always starting at zero.
+ */
+ for (i = 0; i < ASC_NCMD; i++) {
+ if (asc->cmd[i] == 0 && asc->cmdq[i] != 0) {
+ asc->cmd[i] = asc->cmdq[i];
+ asc->cmdq[i] = 0;
+ }
+ }
+ for (i = 0; i < ASC_NCMD; i++) {
+ /* don't restart a disconnected command */
+ if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))
+ continue;
+ asc_startcmd(asc, i);
+ break;
+ }
+
+ /* signal device driver that the command is done */
+ scsicmd->flags |= ITSDONE;
+ scsi_done(scsicmd);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+asc_dma_in(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len;
+
+ /* check for previous chunk in buffer */
+ if (state->flags & DMA_IN_PROGRESS) {
+ /*
+ * Only count bytes that have been copied to memory.
+ * There may be some bytes in the FIFO if synchonous transfers
+ * are in progress.
+ */
+ DMA_END(&asc->dma);
+ ASC_TC_GET(regs, len);
+ len = state->dmalen - len;
+ state->buf += len;
+ state->buflen -= len;
+ }
+
+ /* setup to start reading the next chunk */
+ len = state->buflen;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ if (len > state->dmaBufSize)
+ len = state->dmaBufSize;
+ state->dmalen = len;
+ DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (len != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_last_dma_in(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len, fifo;
+
+ DMA_END(&asc->dma);
+ ASC_TC_GET(regs, len);
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",
+ state->buflen, state->dmalen, len, fifo);
+#endif
+ if (fifo) {
+ /* device must be trying to send more than we expect */
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ }
+ state->flags &= ~DMA_IN_PROGRESS;
+ len = state->dmalen - len;
+ state->buflen -= len;
+
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_resume_in(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len;
+
+ /* setup to start reading the next chunk */
+ len = state->buflen;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ if (len > state->dmaBufSize)
+ len = state->dmaBufSize;
+ state->dmalen = len;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_resume_in: buflen %d, len %d\n", state->buflen,
+ len);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (len != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_resume_dma_in(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len, off;
+
+ /* setup to finish reading the current chunk */
+ len = state->dmaresid;
+ off = state->dmalen - len;
+ if ((off & 1) && state->sync_offset) {
+ printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",
+ state->dmalen, len, off); /* XXX */
+ regs->asc_res_fifo = ((u_char *)state->buf)[off];
+/*XXX Need to flush cache ? */
+ }
+ DMA_START(&asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",
+ state->dmalen, state->buflen, len, off);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (state->dmalen != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_dma_out(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len, fifo;
+
+ if (state->flags & DMA_IN_PROGRESS) {
+ /* check to be sure previous chunk was finished */
+ ASC_TC_GET(regs, len);
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+ if (len || fifo)
+ printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
+ state->buflen, state->dmalen, len, fifo); /* XXX */
+ len += fifo;
+ len = state->dmalen - len;
+ state->buf += len;
+ state->buflen -= len;
+ }
+
+ /* setup for this chunk */
+ len = state->buflen;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ if (len > state->dmaBufSize)
+ len = state->dmaBufSize;
+ state->dmalen = len;
+ DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (len != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_last_dma_out(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len, fifo;
+
+ ASC_TC_GET(regs, len);
+ fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",
+ state->buflen, state->dmalen, len, fifo);
+#endif
+ if (fifo) {
+ len += fifo;
+ regs->asc_cmd = ASC_CMD_FLUSH;
+ readback(regs->asc_cmd);
+ }
+ state->flags &= ~DMA_IN_PROGRESS;
+ len = state->dmalen - len;
+ state->buflen -= len;
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_resume_out(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len;
+
+ /* setup for this chunk */
+ len = state->buflen;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ if (len > state->dmaBufSize)
+ len = state->dmaBufSize;
+ state->dmalen = len;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].resid = len;
+ else
+ asc_logp[-1].resid = len;
+#endif
+ DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_resume_out: buflen %d, len %d\n", state->buflen,
+ len);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (len != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_resume_dma_out(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int len, off;
+
+ /* setup to finish writing this chunk */
+ len = state->dmaresid;
+ off = state->dmalen - len;
+ if (off & 1) {
+ printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n",
+ state->dmalen, len, off); /* XXX */
+ regs->asc_fifo = ((u_char *)state->buf)[off];
+/*XXX Need to flush Cache ? */
+ off++;
+ len--;
+ }
+ DMA_START(&asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV);
+ ASC_TC_PUT(regs, len);
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n",
+ state->dmalen, state->buflen, len, off);
+#endif
+
+ /* check for next chunk */
+ state->flags |= DMA_IN_PROGRESS;
+ if (state->dmalen != state->buflen) {
+ regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];
+ return (0);
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_sendsync(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+
+ /* send the extended synchronous negotiation message */
+ regs->asc_fifo = SCSI_EXTENDED_MSG;
+ wbflush();
+ regs->asc_fifo = 3;
+ wbflush();
+ regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
+ wbflush();
+ regs->asc_fifo = SCSI_MIN_PERIOD;
+ wbflush();
+ regs->asc_fifo = ASC_MAX_OFFSET;
+ /* state to resume after we see the sync reply message */
+ state->script = asc->script + 2;
+ state->msglen = 0;
+ return (1);
+}
+
+/* ARGSUSED */
+static int
+asc_replysync(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_replysync: %x %x\n",
+ asc_to_scsi_period[state->sync_period] * asc->tb_ticks,
+ state->sync_offset);
+#endif
+ /* send synchronous transfer in response to a request */
+ regs->asc_fifo = SCSI_EXTENDED_MSG;
+ wbflush();
+ regs->asc_fifo = 3;
+ wbflush();
+ regs->asc_fifo = SCSI_SYNCHRONOUS_XFER;
+ wbflush();
+ regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks;
+ wbflush();
+ regs->asc_fifo = state->sync_offset;
+ regs->asc_cmd = ASC_CMD_XFER_INFO;
+ readback(regs->asc_cmd);
+
+ /* return to the appropriate script */
+ if (!state->script) {
+#ifdef DEBUG
+ asc_DumpLog("asc_replsync");
+#endif
+ panic("asc_replysync");
+ }
+ asc->script = state->script;
+ state->script = (script_t *)0;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+asc_msg_in(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register asc_regmap_t *regs = asc->regs;
+ register State *state = &asc->st[asc->target];
+ register int msg;
+ int i;
+
+ /* read one message byte */
+ msg = regs->asc_fifo;
+#ifdef DEBUG
+ if (asc_logp == asc_log)
+ asc_log[NLOG - 1].msg = msg;
+ else
+ asc_logp[-1].msg = msg;
+#endif
+
+ /* check for multi-byte message */
+ if (state->msglen != 0) {
+ /* first byte is the message length */
+ if (state->msglen < 0) {
+ state->msglen = msg;
+ return (1);
+ }
+ if (state->msgcnt >= state->msglen)
+ goto abort;
+ state->msg_in[state->msgcnt++] = msg;
+
+ /* did we just read the last byte of the message? */
+ if (state->msgcnt != state->msglen)
+ return (1);
+
+ /* process an extended message */
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_msg_in: msg %x %x %x\n",
+ state->msg_in[0],
+ state->msg_in[1],
+ state->msg_in[2]);
+#endif
+ switch (state->msg_in[0]) {
+ case SCSI_SYNCHRONOUS_XFER:
+ state->flags |= DID_SYNC;
+ state->sync_offset = state->msg_in[2];
+
+ /* convert SCSI period to ASC period */
+ i = state->msg_in[1] / asc->tb_ticks;
+ if (i < asc->min_period)
+ i = asc->min_period;
+ else if (i >= asc->max_period) {
+ /* can't do sync transfer, period too long */
+ printf("%s: SCSI device %d: sync xfer period too long (%d)\n",
+ asc->sc_dev.dv_xname, asc->target, i);
+ i = asc->max_period;
+ state->sync_offset = 0;
+ }
+ if ((i * asc->tb_ticks) != state->msg_in[1])
+ i++;
+ state->sync_period = i & 0x1F;
+
+ /*
+ * If this is a request, check minimums and
+ * send back an acknowledge.
+ */
+ if (!(state->flags & TRY_SYNC)) {
+ regs->asc_cmd = ASC_CMD_SET_ATN;
+ readback(regs->asc_cmd);
+
+ if (state->sync_period < asc->min_period)
+ state->sync_period =
+ asc->min_period;
+ if (state->sync_offset > ASC_MAX_OFFSET)
+ state->sync_offset =
+ ASC_MAX_OFFSET;
+ asc->script = &asc_scripts[SCRIPT_REPLY_SYNC];
+ regs->asc_syn_p = state->sync_period;
+ readback(regs->asc_syn_p);
+ regs->asc_syn_o = state->sync_offset;
+ readback(regs->asc_syn_o);
+ regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(regs->asc_cmd);
+ return (0);
+ }
+
+ regs->asc_syn_p = state->sync_period;
+ readback(regs->asc_syn_p);
+ regs->asc_syn_o = state->sync_offset;
+ readback(regs->asc_syn_o);
+ goto done;
+
+ default:
+ printf("%s: SCSI device %d: rejecting extended message 0x%x\n",
+ asc->sc_dev.dv_xname, asc->target,
+ state->msg_in[0]);
+ goto reject;
+ }
+ }
+
+ /* process first byte of a message */
+#ifdef DEBUG
+ if (asc_debug > 2)
+ printf("asc_msg_in: msg %x\n", msg);
+#endif
+ switch (msg) {
+#if 0
+ case SCSI_MESSAGE_REJECT:
+ printf(" did not like SYNCH xfer "); /* XXX */
+ state->flags |= DID_SYNC;
+ regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(regs->asc_cmd);
+ status = asc_wait(regs, ASC_CSR_INT);
+ ir = regs->asc_intr;
+ /* some just break out here, some dont */
+ if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) {
+ regs->asc_fifo = SCSI_ABORT;
+ regs->asc_cmd = ASC_CMD_XFER_INFO;
+ readback(regs->asc_cmd);
+ status = asc_wait(regs, ASC_CSR_INT);
+ ir = regs->asc_intr;
+ }
+ if (ir & ASC_INT_DISC) {
+ asc_end(asc, status, 0, ir);
+ return (0);
+ }
+ goto status;
+#endif /* 0 */
+
+ case SCSI_EXTENDED_MSG: /* read an extended message */
+ /* setup to read message length next */
+ state->msglen = -1;
+ state->msgcnt = 0;
+ return (1);
+
+ case SCSI_NO_OP:
+ break;
+
+ case SCSI_SAVE_DATA_POINTER:
+ /* expect another message */
+ return (1);
+
+ case SCSI_RESTORE_POINTERS:
+ /*
+ * Need to do the following if resuming synchonous data in
+ * on an odd byte boundary.
+ regs->asc_cnfg2 |= ASC_CNFG2_RFB;
+ */
+ break;
+
+ case SCSI_DISCONNECT:
+ if (state->flags & DISCONN)
+ goto abort;
+ state->flags |= DISCONN;
+ regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(regs->asc_cmd);
+ asc->script = &asc_scripts[SCRIPT_DISCONNECT];
+ return (0);
+
+ default:
+ printf("%s: SCSI device %d: rejecting message 0x%x\n",
+ asc->sc_dev.dv_xname, asc->target, msg);
+ reject:
+ /* request a message out before acknowledging this message */
+ state->msg_out = SCSI_MESSAGE_REJECT;
+ regs->asc_cmd = ASC_CMD_SET_ATN;
+ readback(regs->asc_cmd);
+ }
+
+done:
+ /* return to original script */
+ regs->asc_cmd = ASC_CMD_MSG_ACPT;
+ readback(regs->asc_cmd);
+ if (!state->script) {
+ abort:
+#ifdef DEBUG
+ asc_DumpLog("asc_msg_in");
+#endif
+ panic("asc_msg_in");
+ }
+ asc->script = state->script;
+ state->script = (script_t *)0;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+asc_disconnect(asc, status, ss, ir)
+ register asc_softc_t asc;
+ register int status, ss, ir;
+{
+ register State *state = &asc->st[asc->target];
+
+#ifdef DIAGNOSTIC
+ if (!(state->flags & DISCONN)) {
+ printf("asc_disconnect: device %d: DISCONN not set!\n",
+ asc->target);
+ }
+#endif /* DIAGNOSTIC */
+ asc->target = -1;
+ asc->state = ASC_STATE_RESEL;
+ return (1);
+}
+
+#ifdef DEBUG
+/*
+ * Dump the log buffer.
+ */
+asc_DumpLog(str)
+ char *str;
+{
+ register struct asc_log *lp;
+ register u_int status;
+
+ printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd,
+ asc_debug_bn, asc_debug_sz);
+ lp = asc_logp;
+ do {
+ status = lp->status;
+ printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n",
+ status >> 24,
+ lp->target,
+ (status >> 16) & 0xFF,
+ (status >> 8) & 0xFF,
+ status & 0XFF,
+ lp->state,
+ asc_scripts[lp->state].condition,
+ lp->msg, lp->resid);
+ if (++lp >= &asc_log[NLOG])
+ lp = asc_log;
+ } while (lp != asc_logp);
+}
+#endif /* DEBUG */
+
+#endif /* NASC > 0 */
diff --git a/sys/arch/wgrisc/dev/ascreg.h b/sys/arch/wgrisc/dev/ascreg.h
new file mode 100644
index 00000000000..3a5a213ba36
--- /dev/null
+++ b/sys/arch/wgrisc/dev/ascreg.h
@@ -0,0 +1,326 @@
+/* $OpenBSD: ascreg.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ascreg.h 8.1 (Berkeley) 6/10/93
+ * $Id: ascreg.h,v 1.1 1997/02/06 16:02:42 pefo 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
+ * Log: scsi_53C94.h,v
+ * Revision 2.4 91/02/05 17:44:59 mrt
+ * Added author notices
+ * [91/02/04 11:18:32 mrt]
+ *
+ * Changed to use new Mach copyright
+ * [91/02/02 12:17:11 mrt]
+ *
+ * Revision 2.3 90/12/05 23:34:46 af
+ * Documented max DMA xfer size.
+ * [90/12/03 23:39:36 af]
+ *
+ * Revision 2.1.1.1 90/11/01 03:38:54 af
+ * Created, from the DEC specs:
+ * "PMAZ-AA TURBOchannel SCSI Module Functional Specification"
+ * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990.
+ * And from the NCR data sheets
+ * "NCR 53C94, 53C95, 53C96 Advanced SCSI Controller"
+ * [90/09/03 af]
+ */
+
+/*
+ * File: scsi_53C94.h
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 9/90
+ *
+ * Defines for the NCR 53C94 ASC (SCSI interface)
+ * Some gotcha came from the "86C01/53C94 DMA lab work" written
+ * by Ken Stewart (NCR MED Logic Products Applications Engineer)
+ * courtesy of NCR. Thanks Ken !
+ */
+
+#define ASC_OFFSET_53C94 0x0 /* from module base */
+
+#define ASC_NCMD 7 /* Number of simultaneous cmds */
+
+/*
+ * Synch xfer parameters, and timing conversions
+ */
+#define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */
+#define ASC_MIN_PERIOD40 8 /* in CLKS/BYTE, 1 CLK = 25nsecs */
+#define ASC_MIN_PERIOD25 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */
+#define ASC_MIN_PERIOD20 4 /* in CLKS/BYTE, 1 CLK = 50nsecs */
+#define ASC_MIN_PERIOD12 3 /* in CLKS/BYTE, 1 CLK = 80nsecs */
+#define ASC_MAX_PERIOD40 56 /* in CLKS/BYTE, 1 CLK = 25nsecs */
+#define ASC_MAX_PERIOD25 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */
+#define ASC_MAX_PERIOD20 28 /* in CLKS/BYTE, 1 CLK = 50nsecs */
+#define ASC_MAX_PERIOD12 18 /* in CLKS/BYTE, 1 CLK = 80nsecs */
+#define ASC_MAX_OFFSET 15 /* pure number */
+/*
+ * Register map, padded as needed
+ */
+
+typedef volatile struct {
+ u_char asc_tc_lsb; /* 00 rw: Transfer Counter LSB */
+ u_char asc_tc_msb; /* 01 rw: Transfer Counter MSB */
+ u_char asc_fifo; /* 02 rw: FIFO top */
+ u_char asc_cmd; /* 03 rw: Command */
+ u_char asc_status; /* 04 r: Status */
+#define asc_dbus_id asc_status /* 04 w: Destination Bus ID */
+ u_char asc_intr; /* 05 r: Interrupt */
+#define asc_sel_timo asc_intr /* 05 w: (re)select timeout */
+ u_char asc_ss; /* 06 r: Sequence Step */
+#define asc_syn_p asc_ss /* 06 w: synchronous period */
+ u_char asc_flags; /* 07 r: FIFO flags + seq step */
+#define asc_syn_o asc_flags /* 07 w: synchronous offset */
+ u_char asc_cnfg1; /* 08 rw: Configuration 1 */
+ u_char asc_ccf; /* 09 w: Clock Conv. Factor */
+ u_char asc_test; /* 0a w: Test Mode */
+ u_char asc_cnfg2; /* 0b rw: Configuration 2 */
+ u_char asc_cnfg3; /* 0c rw: Configuration 3 */
+ u_char asc_res_fifo; /* 0d w: Reserve FIFO byte */
+ u_char asc_tc_xsb; /* 0e rw: Transfer Counter Xtended */
+} asc_regmap_t;
+
+/*
+ * Transfer Count: access macros
+ * That a NOP is required after loading the dma counter
+ * I learned on the NCR test code. Sic.
+ */
+
+#define ASC_TC_MAX 0x10000
+
+#define ASC_TC_GET(ptr, val) \
+ val = (ptr)->asc_tc_lsb | ((ptr)->asc_tc_msb << 8) | ((ptr)->asc_tc_xsb << 16)
+#define ASC_TC_PUT(ptr, val) \
+ (ptr)->asc_tc_lsb = (val); \
+ (ptr)->asc_tc_msb = (val) >> 8; \
+ (ptr)->asc_tc_xsb = (val) >> 16; \
+ (ptr)->asc_cmd = ASC_CMD_NOP | ASC_CMD_DMA;
+
+/*
+ * Command register (command codes)
+ */
+
+#define ASC_CMD_DMA 0x80
+ /* Miscellaneous */
+#define ASC_CMD_NOP 0x00
+#define ASC_CMD_FLUSH 0x01
+#define ASC_CMD_RESET 0x02
+#define ASC_CMD_BUS_RESET 0x03
+ /* Initiator state */
+#define ASC_CMD_XFER_INFO 0x10
+#define ASC_CMD_I_COMPLETE 0x11
+#define ASC_CMD_MSG_ACPT 0x12
+#define ASC_CMD_XFER_PAD 0x18
+#define ASC_CMD_SET_ATN 0x1a
+#define ASC_CMD_CLR_ATN 0x1b
+ /* Target state */
+#define ASC_CMD_SND_MSG 0x20
+#define ASC_CMD_SND_STATUS 0x21
+#define ASC_CMD_SND_DATA 0x22
+#define ASC_CMD_DISC_SEQ 0x23
+#define ASC_CMD_TERM 0x24
+#define ASC_CMD_T_COMPLETE 0x25
+#define ASC_CMD_DISC 0x27
+#define ASC_CMD_RCV_MSG 0x28
+#define ASC_CMD_RCV_CDB 0x29
+#define ASC_CMD_RCV_DATA 0x2a
+#define ASC_CMD_RCV_CMD 0x2b
+#define ASC_CMD_ABRT_DMA 0x04
+ /* Disconnected state */
+#define ASC_CMD_RESELECT 0x40
+#define ASC_CMD_SEL 0x41
+#define ASC_CMD_SEL_ATN 0x42
+#define ASC_CMD_SEL_ATN_STOP 0x43
+#define ASC_CMD_ENABLE_SEL 0x44
+#define ASC_CMD_DISABLE_SEL 0x45
+#define ASC_CMD_SEL_ATN3 0x46
+
+/*
+ * Status register, and phase encoding
+ */
+
+#define ASC_CSR_INT 0x80
+#define ASC_CSR_GE 0x40
+#define ASC_CSR_PE 0x20
+#define ASC_CSR_TC 0x10
+#define ASC_CSR_VGC 0x08
+#define ASC_CSR_MSG 0x04
+#define ASC_CSR_CD 0x02
+#define ASC_CSR_IO 0x01
+
+#define ASC_PHASE(csr) ((csr) & 0x7)
+#define ASC_PHASE_DATAO 0x0
+#define ASC_PHASE_DATAI 0x1
+#define ASC_PHASE_COMMAND 0x2
+#define ASC_PHASE_STATUS 0x3
+ /* 4..5 ANSI reserved */
+#define ASC_PHASE_MSG_OUT 0x6
+#define ASC_PHASE_MSG_IN 0x7
+
+/*
+ * Destination Bus ID
+ */
+
+#define ASC_DEST_ID_MASK 0x07
+
+/*
+ * Interrupt register
+ */
+
+#define ASC_INT_RESET 0x80
+#define ASC_INT_ILL 0x40
+#define ASC_INT_DISC 0x20
+#define ASC_INT_BS 0x10
+#define ASC_INT_FC 0x08
+#define ASC_INT_RESEL 0x04
+#define ASC_INT_SEL_ATN 0x02
+#define ASC_INT_SEL 0x01
+
+/*
+ * Timeout register:
+ *
+ * val = (timeout * CLK_freq) / (8192 * CCF);
+ */
+
+#define ASC_TIMEOUT_250(clk, ccf) (((clk) * 31) / (ccf))
+
+/*
+ * Sequence Step register
+ */
+
+#define ASC_SS_RESERVED 0xf0
+#define ASC_SS_SOM 0x08
+#define ASC_SS_MASK 0x07
+#define ASC_SS(ss) ((ss) & ASC_SS_MASK)
+
+/*
+ * Synchronous Transfer Period
+ */
+
+#define ASC_STP_MASK 0x1f
+#define ASC_STP_MIN 0x05 /* 5 clk per byte */
+#define ASC_STP_MAX 0x04 /* after ovfl, 35 clk/byte */
+
+/*
+ * FIFO flags
+ */
+
+#define ASC_FLAGS_SEQ_STEP 0xe0
+#define ASC_FLAGS_FIFO_CNT 0x1f
+
+/*
+ * Synchronous offset
+ */
+
+#define ASC_SYNO_MASK 0x0f /* 0 -> asyn */
+
+/*
+ * Configuration 1
+ */
+
+#define ASC_CNFG1_SLOW 0x80
+#define ASC_CNFG1_SRD 0x40
+#define ASC_CNFG1_P_TEST 0x20
+#define ASC_CNFG1_P_CHECK 0x10
+#define ASC_CNFG1_TEST 0x08
+#define ASC_CNFG1_MY_BUS_ID 0x07
+
+/*
+ * CCF register
+ */
+
+#define ASC_CCF(clk) ((((clk) - 1) / 5) + 1)
+
+/*
+ * Test register
+ */
+
+#define ASC_TEST_XXXX 0xf8
+#define ASC_TEST_HI_Z 0x04
+#define ASC_TEST_I 0x02
+#define ASC_TEST_T 0x01
+
+/*
+ * Configuration 2
+ */
+
+#define ASC_CNFG2_RFB 0x80
+#define ASC_CNFG2_EPL 0x40
+#define ASC_CNFG2_EBC 0x20
+#define ASC_CNFG2_DREQ_HIZ 0x10
+#define ASC_CNFG2_SCSI2 0x08
+#define ASC_CNFG2_BPA 0x04
+#define ASC_CNFG2_RPE 0x02
+#define ASC_CNFG2_DPE 0x01
+
+/*
+ * Configuration 3
+ */
+
+#define ASC_CNFG3_RESERVED 0xf8
+#define ASC_CNFG3_SRB 0x04
+#define ASC_CNFG3_ALT_DMA 0x02
+#define ASC_CNFG3_T8 0x01
+
+#define ST_MASK 0x3e
diff --git a/sys/arch/wgrisc/dev/com_risc.c b/sys/arch/wgrisc/dev/com_risc.c
new file mode 100644
index 00000000000..557179e6642
--- /dev/null
+++ b/sys/arch/wgrisc/dev/com_risc.c
@@ -0,0 +1,195 @@
+/* $OpenBSD: com_risc.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+
+/*
+ * Copyright (c) 1993, 1994 Charles Hannum.
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * 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 software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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.
+ */
+
+/*
+ * Device Driver for AT parallel printer port
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/isa/isavar.h> /* XXX for isa_chipset_tag_t in com_softc */
+
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#include <dev/ic/ns16550reg.h>
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+#undef CONADDR /* This is stupid but using devs before config .. */
+#define CONADDR 0xae400000
+
+int com_risc_probe __P((struct device *, void *, void *));
+void com_risc_attach __P((struct device *, struct device *, void *));
+
+struct cfattach com_risc_ca = {
+ sizeof(struct com_softc), com_risc_probe, com_risc_attach
+};
+
+int
+com_risc_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int iobase, needioh;
+ int rv = 1;
+ struct confargs *ca = aux;
+
+ if(!BUS_MATCHNAME(ca, "com"))
+ return(0);
+ iobase = (long)BUS_CVTADDR(ca);
+ iot = 0;
+ needioh = 1;
+
+ /* if it's in use as console, it's there. */
+ if (iobase == comconsaddr && !comconsattached)
+ goto out;
+
+ if (needioh && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
+ rv = 0;
+ goto out;
+ }
+ rv = comprobe1(iot, ioh, iobase);
+ if (needioh)
+ bus_space_unmap(iot, ioh, COM_NPORTS);
+
+out:
+ return (rv);
+}
+
+void
+com_risc_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct com_softc *sc = (void *)self;
+ int iobase;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct confargs *ca = aux;
+
+ sc->sc_hwflags = 0;
+ sc->sc_swflags = 0;
+ sc->sc_iobase = iobase = (bus_addr_t)BUS_CVTADDR(ca);
+ sc->sc_ioh = ioh = (bus_space_handle_t)iobase;
+ sc->sc_iot = iot = 0;
+
+ if (iobase == comconsaddr) {
+ comconsattached = 1;
+
+ /*
+ * Need to reset baud rate, etc. of next print so reset
+ * comconsinit. Also make sure console is always "hardwired".
+ */
+ delay(1000); /* wait for output to finish */
+ comconsinit = 0;
+ SET(sc->sc_hwflags, COM_HW_CONSOLE);
+ SET(sc->sc_swflags, COM_SW_SOFTCAR);
+ }
+
+
+ /* look for a NS 16550AF UART with FIFOs */
+ bus_space_write_1(iot, ioh, com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ delay(100);
+ if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_FIFO_MASK) ==
+ IIR_FIFO_MASK)
+ if (ISSET(bus_space_read_1(iot, ioh, com_fifo),
+ FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
+ SET(sc->sc_hwflags, COM_HW_FIFO);
+ printf(": ns16550a, working fifo\n");
+ } else
+ printf(": ns16550, broken fifo\n");
+ else
+ printf(": ns8250 or ns16450, no fifo\n");
+ bus_space_write_1(iot, ioh, com_fifo, 0);
+
+ /* disable interrupts */
+ bus_space_write_1(iot, ioh, com_ier, 0);
+ bus_space_write_1(iot, ioh, com_mcr, 0);
+
+ BUS_INTR_ESTABLISH(ca, comintr, (void *)(long)sc);
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ cominit(iot, ioh, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("%s: ", sc->sc_dev.dv_xname);
+ kgdb_connect(1);
+ } else
+ printf("%s: kgdb enabled\n",
+ sc->sc_dev.dv_xname);
+ }
+ }
+#endif
+
+ /* XXX maybe move up some? */
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ printf("%s: console\n", sc->sc_dev.dv_xname);
+}
diff --git a/sys/arch/wgrisc/dev/dma.h b/sys/arch/wgrisc/dev/dma.h
new file mode 100644
index 00000000000..dd5fb4c51b2
--- /dev/null
+++ b/sys/arch/wgrisc/dev/dma.h
@@ -0,0 +1,147 @@
+/* $OpenBSD: dma.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+
+/*
+ * Copyright (c) 1996 Per Fogelstrom
+ *
+ * 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 under OpenBSD by
+ * Per Fogelstrom.
+ * 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.
+ *
+ */
+
+extern vm_map_t phys_map;
+
+/*
+ * Structure used to control dma.
+ */
+
+typedef struct dma_softc {
+ struct device sc_dev; /* use as a device */
+ struct esp_softc *sc_esp;
+ int dma_ch;
+ vm_offset_t dma_va; /* Viritual address for transfer */
+ vm_offset_t req_va; /* Original request va */
+ int req_size; /* Request size */
+ int mode; /* Mode register value and direction */
+ int sc_active; /* Active flag */
+ char **sc_dmaaddr; /* Pointer to dma address in dev */
+ int *sc_dmalen; /* Pointer to len counter in dev */
+} dma_softc_t;
+
+#define DMA_TO_DEV 0
+#define DMA_FROM_DEV 1
+
+#define DMA_CH0 0
+#define DMA_CH1 1
+
+#define DMA_RESET(r)
+#if 0
+#define DMA_START(a, b, c, d) \
+ { \
+ int dcmd; \
+ int xcmd; \
+ int pa; \
+ int sz; \
+ if((vm_offset_t)(b) < VM_MIN_KERNEL_ADDRESS) { \
+ pa = CACHED_TO_PHYS(b); \
+ } \
+ else { \
+ pa = pmap_extract(vm_map_pmap(phys_map), (vm_offset_t)(b));\
+ } \
+ sz = c; \
+ if(sz + (pa & (NBPG - 1)) > NBPG) { \
+ sz = NBPG - (pa & (NBPG - 1)); \
+ } \
+ dcmd = ((d) == DMA_FROM_DEV) ? 0x30 : 0x10; \
+ if((a)->dma_ch == DMA_CH0) { \
+ out32(R3715_DMA_ADR0, pa); \
+ out32(R3715_DMA_CNT0, sz - 1); \
+ xcmd = ~0x30; \
+ } \
+ else { \
+ out32(R3715_DMA_ADR1, pa); \
+ out32(R3715_DMA_CNT1, sz - 1); \
+ dcmd = dcmd << 6; \
+ xcmd = ~(0x30 << 6); \
+ } \
+ dcmd |= (1 << 26); \
+ out32(R3715_IO_TIMING, (in32(R3715_IO_TIMING) & xcmd) | dcmd);\
+ }
+#else
+#define DMA_START(a, b, c, d) \
+ { \
+ int dcmd; \
+ int xcmd; \
+ int pa; \
+ int sz; \
+ pa = CACHED_TO_PHYS(dma_buffer); \
+ (a)->req_va = (vm_offset_t)(b); \
+ (a)->req_size = c; \
+ (a)->mode = d; \
+ sz = c; \
+ if((d) == DMA_TO_DEV) { \
+ int *_p = (int *)PHYS_TO_UNCACHED(pa); \
+ int *_v = (int *)b; \
+ int _n = sz; \
+ while(_n > 0) { \
+ *_p = htonl(*_v); \
+ _p++; _v++; _n -= 4; \
+ } \
+ } \
+ dcmd = ((d) == DMA_FROM_DEV) ? 0x30 : 0x10; \
+ if((a)->dma_ch == DMA_CH0) { \
+ out32(R3715_DMA_ADR0, pa); \
+ out32(R3715_DMA_CNT0, sz - 1); \
+ xcmd = ~0x30; \
+ } \
+ else { \
+ out32(R3715_DMA_ADR1, pa); \
+ out32(R3715_DMA_CNT1, sz - 1); \
+ dcmd = dcmd << 6; \
+ xcmd = ~(0x30 << 6); \
+ } \
+ dcmd |= (1 << 26); \
+ out32(R3715_IO_TIMING, (in32(R3715_IO_TIMING) & xcmd) | dcmd);\
+ }
+#endif
+#define DMA_MAP(a, b, c, d)
+#define DMA_INTR(r)
+#define DMA_DRAIN(r)
+#define DMA_END(c) \
+ { \
+ int dcmd; \
+ dcmd = ((c)->dma_ch == DMA_CH0) ? 0x10 : 0x10000; \
+ out32(R3715_IO_TIMING, in32(R3715_IO_TIMING) & ~dcmd); \
+ if((c)->mode == DMA_FROM_DEV) { \
+ int *_v = (int *)(c)->req_va; \
+ int *_p = (int *)PHYS_TO_UNCACHED(CACHED_TO_PHYS(dma_buffer)); \
+ int _n = (c)->req_size; \
+ while(_n > 0) { \
+ *_v = htonl(*_p); \
+ _p++; _v++; _n -= 4; \
+ } \
+ } \
+ }
diff --git a/sys/arch/wgrisc/dev/if_sn.c b/sys/arch/wgrisc/dev/if_sn.c
new file mode 100644
index 00000000000..b31ed2e0911
--- /dev/null
+++ b/sys/arch/wgrisc/dev/if_sn.c
@@ -0,0 +1,1288 @@
+/* $OpenBSD: if_sn.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+/*
+ * National Semiconductor SONIC Driver
+ * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
+ * You may use, copy, and modify this program so long as you retain the
+ * copyright line.
+ *
+ * This driver has been substantially modified since Algorithmics donated
+ * it.
+ */
+
+#include "sn.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.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 <vm/vm.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#define SONICDW 32
+typedef unsigned char uchar;
+
+#include <wgrisc/dev/if_sn.h>
+#define SWR(a, x) (a) = (x)
+#define SRD(a) ((a) & 0xffff)
+
+#include <machine/cpu.h>
+#include <wgrisc/riscbus/riscbus.h>
+
+/*
+ * Statistics collected over time
+ */
+struct sn_stats {
+ int ls_opacks; /* packets transmitted */
+ int ls_ipacks; /* packets received */
+ int ls_tdr; /* contents of tdr after collision */
+ int ls_tdef; /* packets where had to wait */
+ int ls_tone; /* packets with one retry */
+ int ls_tmore; /* packets with more than one retry */
+ int ls_tbuff; /* transmit buff errors */
+ int ls_tuflo; /* " uflo " */
+ int ls_tlcol;
+ int ls_tlcar;
+ int ls_trtry;
+ int ls_rbuff; /* receive buff errors */
+ int ls_rfram; /* framing */
+ int ls_roflo; /* overflow */
+ int ls_rcrc;
+ int ls_rrng; /* rx ring sequence error */
+ int ls_babl; /* chip babl error */
+ int ls_cerr; /* collision error */
+ int ls_miss; /* missed packet */
+ int ls_merr; /* memory error */
+ int ls_copies; /* copies due to out of range mbufs */
+ int ls_maxmbufs; /* max mbufs on transmit */
+ int ls_maxslots; /* max ring slots on transmit */
+};
+
+struct sn_softc {
+ struct device sc_dev;
+ struct arpcom sc_ac;
+#define sc_if sc_ac.ac_if /* network visible interface */
+#define sc_enaddr sc_ac.ac_enaddr /* hardware ethernet address */
+
+ struct sonic_reg *sc_csr; /* hardware pointer */
+ int sc_rxmark; /* position in rx ring for reading buffs */
+
+ int sc_rramark; /* index into rra of wp */
+
+ int sc_txhead; /* index of first TDA passed to chip */
+ int sc_missed; /* missed packet counter */
+ struct RXpkt *sc_lrxp; /* last RDA available to chip */
+ struct sn_stats sc_sum;
+ short sc_iflags;
+} sn_softc;
+
+int snmatch __P((struct device *, void *, void *));
+void snattach __P((struct device *, struct device *, void *));
+
+struct cfattach sn_ca = {
+ sizeof(struct sn_softc), snmatch, snattach
+};
+struct cfdriver sn_cd = {
+ NULL, "sn", DV_IFNET, NULL, 0
+};
+
+#undef assert
+#undef _assert
+
+#ifdef NDEBUG
+#define assert(e) ((void)0)
+#define _assert(e) ((void)0)
+#else
+#define _assert(e) assert(e)
+#ifdef __STDC__
+#define assert(e) ((e) ? (void)0 : __assert("sn ", __FILE__, __LINE__, #e))
+#else /* PCC */
+#define assert(e) ((e) ? (void)0 : __assert("sn "__FILE__, __LINE__, "e"))
+#endif
+#endif
+
+void
+m_check(m)
+ struct mbuf *m;
+{
+ if (m->m_flags & M_EXT) {
+ assert(m->m_len >= 0);
+ assert(m->m_len <= m->m_ext.ext_size);
+ assert(m->m_data >= &m->m_ext.ext_buf[0]);
+ assert(m->m_data <= &m->m_ext.ext_buf[m->m_ext.ext_size]);
+ assert(m->m_data + m->m_len <= &m->m_ext.ext_buf[m->m_ext.ext_size]);
+ } else if (m->m_flags & M_PKTHDR) {
+ assert(m->m_len >= 0);
+ assert(m->m_len <= MHLEN);
+ assert(m->m_data >= m->m_pktdat);
+ assert(m->m_data <= &m->m_pktdat[MHLEN]);
+ assert(m->m_data + m->m_len <= &m->m_pktdat[MHLEN]);
+ } else {
+ assert(m->m_len >= 0);
+ assert(m->m_len <= MLEN);
+ assert(m->m_data >= m->m_dat);
+ assert(m->m_data <= &m->m_dat[MLEN]);
+ assert(m->m_data + m->m_len <= &m->m_dat[MLEN]);
+ }
+}
+
+void
+m_checkm(m)
+ struct mbuf *m;
+{
+ while (m) {
+ m_check(m);
+ m = m->m_next;
+ }
+}
+
+int ethdebug = 0;
+
+int snintr __P((struct sn_softc *));
+int snioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+void snstart __P((struct ifnet *ifp));
+void snwatchdog __P((struct ifnet *ifp));
+void snreset __P((struct sn_softc *sc));
+
+/*
+ * SONIC buffers need to be aligned 16 or 32 bit aligned.
+ * These macros calculate and verify alignment.
+ */
+#if SONICDW == 32
+#define SONICALIGN 4
+#else
+#define SONICALIGN 2
+#endif
+#define SOALIGN(array) (((int)array+SONICALIGN-1) & ~(SONICALIGN-1))
+#define SOALIGNED(p) (!(((uint)p)&(SONICALIGN-1)))
+
+#define UPPER(x) ((unsigned)(x) >> 16)
+#define LOWER(x) ((unsigned)(x) & 0xffff)
+
+#define NRRA 32 /* # receive resource descriptors */
+#define RRAMASK 0x1f /* why it must be poer of two */
+
+#define NRBA 16 /* # receive buffers < NRRA */
+#define NRDA NRBA /* # receive descriptors */
+#define NTDA 4 /* # transmit descriptors */
+
+#define CDASIZE sizeof(struct CDA)
+#define RRASIZE (NRRA*sizeof(struct RXrsrc))
+#define RDASIZE (NRDA*sizeof(struct RXpkt))
+#define TDASIZE (NTDA*sizeof(struct TXpkt))
+
+#define FCSSIZE 4 /* size of FCS append te received packets */
+
+/*
+ * maximum recieve packet size plus 2 byte pad to make each
+ * one aligned. 4 byte slop (required for eobc)
+ */
+#define RBASIZE (sizeof(struct ether_header) + ETHERMTU + FCSSIZE + 2 + 4)
+
+/*
+ * space requiered for descriptors
+ */
+#define DESC_SIZE (RRASIZE + CDASIZE + RDASIZE + TDASIZE + SONICALIGN - 1)
+
+/*
+ * Nicely aligned pointers into the sonicbuffers
+ * p_ points at physical (K1_SEG) addresses.
+ * v_ is sonic local address used by sonic.
+ */
+struct RXrsrc *p_rra; /* receiver resource descriptors */
+struct RXrsrc *v_rra;
+struct RXpkt *p_rda; /* receiver desriptors */
+struct RXpkt *v_rda;
+struct TXpkt *p_tda; /* transmitter descriptors */
+struct TXpkt *v_tda;
+struct CDA *p_cda; /* CAM descriptors */
+struct CDA *v_cda;
+char *p_rba; /* receive buffer area base */
+char *v_rba;
+
+/* Meta transmit descriptors */
+struct mtd {
+ struct mtd *mtd_link;
+ struct TXpkt *mtd_txp;
+ struct mbuf *mtd_mbuf;
+} mtda[NTDA];
+
+struct mtd *mtdfree; /* list of free meta transmit descriptors */
+struct mtd *mtdhead; /* head of descriptors assigned to chip */
+struct mtd *mtdtail; /* tail of descriptors assigned to chip */
+struct mtd *mtdnext; /* next descriptor to give to chip */
+
+void mtd_free __P((struct mtd *));
+struct mtd *mtd_alloc __P((void));
+
+int sngetaddr __P((struct sn_softc *sc));
+int sninit __P((struct sn_softc *sc));
+int snstop __P((struct sn_softc *sc));
+int sonicput __P((struct sn_softc *sc, struct mbuf *m0));
+
+void camdump __P((struct sn_softc *sc));
+
+int
+snmatch(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+ struct confargs *ca = aux;
+
+ /* XXX CHECK BUS */
+ /* make sure that we're looking for this type of device. */
+ if (!BUS_MATCHNAME(ca, "sonic"))
+ return (0);
+
+ return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
+void
+snattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct sn_softc *sc = (void *)self;
+ struct confargs *ca = aux;
+ struct ifnet *ifp = &sc->sc_if;
+ struct cfdata *cf = sc->sc_dev.dv_cfdata;
+ int p, pp;
+
+ sc->sc_csr = (struct sonic_reg *)BUS_CVTADDR(ca);
+
+/*
+ * because the sonic is basicly 16bit device it 'concatenates'
+ * a higher buffer address to a 16 bit offset this will cause wrap
+ * around problems near the end of 64k !!
+ */
+ p = RISC_SONIC_SRAM;
+ pp = RISC_SONIC_SRAM - (FRAGMAX * NTDA * 4096);
+
+ if ((p ^ (p + TDASIZE)) & 0x10000)
+ p = (p + 0x10000) & ~0xffff;
+ p_tda = (struct TXpkt *) p;
+ v_tda = (struct TXpkt *)(p - pp);
+ p += TDASIZE;
+
+ if ((p ^ (p + RRASIZE + CDASIZE)) & 0x10000)
+ p = (p + 0x10000) & ~0xffff;
+ p_rra = (struct RXrsrc *) p;
+ v_rra = (struct RXrsrc *)(p - pp);
+ p += RRASIZE;
+
+ if ((p ^ (p + RDASIZE)) & 0x10000)
+ p = (p + 0x10000) & ~0xffff;
+ p_rda = (struct RXpkt *) p;
+ v_rda = (struct RXpkt *)(p - pp);
+ p += RDASIZE;
+
+ p_cda = (struct CDA *) p;
+ v_cda = (struct CDA *)(p - pp);
+ p += CDASIZE;
+
+ p += 4096 - (p & (4095));
+ p_rba = (char *)p;
+ v_rba = (char *)(p - pp);
+ p += NRBA * RBASIZE;
+
+ printf(": bufsize %d",p - RISC_SONIC_SRAM);
+
+#if 0
+ camdump(sc);
+#endif
+ sngetaddr(sc);
+ printf(" address %s\n", ether_sprintf(sc->sc_enaddr));
+
+#if 0
+printf("\nsonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n",
+ p_rra, p_cda, p_rda, p_tda, p_rba);
+printf("sonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n",
+ v_rra, v_cda, v_rda, v_tda, v_rba);
+printf("mapped to offset 0x%x size 0x%x\n", SONICBUF - pp, p - SONICBUF);
+#endif
+
+ BUS_INTR_ESTABLISH(ca, (intr_handler_t)snintr, (void *)sc);
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_ioctl = snioctl;
+ ifp->if_start = snstart;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_watchdog = snwatchdog;
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ if_attach(ifp);
+ ether_ifattach(ifp);
+}
+
+int
+snioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa;
+ struct sn_softc *sc = ifp->if_softc;
+ int s = splnet(), err = 0;
+ int temp;
+ int error;
+
+ if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
+ splx(s);
+ return error;
+ }
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ (void)sninit(ifp->if_softc);
+ arp_ifinit(&sc->sc_ac, ifa);
+ break;
+#endif
+ default:
+ (void)sninit(ifp->if_softc);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ ifp->if_flags & IFF_RUNNING) {
+ snstop(ifp->if_softc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if (ifp->if_flags & IFF_UP &&
+ (ifp->if_flags & IFF_RUNNING) == 0)
+ (void)sninit(ifp->if_softc);
+ /*
+ * If the state of the promiscuous bit changes, the interface
+ * must be reset to effect the change.
+ */
+ if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ sc->sc_iflags = ifp->if_flags;
+ printf("change in flags\n");
+ temp = sc->sc_if.if_flags & IFF_UP;
+ snreset(sc);
+ sc->sc_if.if_flags |= temp;
+ snstart(ifp);
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if(cmd == SIOCADDMULTI)
+ err = ether_addmulti((struct ifreq *)data, &sc->sc_ac);
+ else
+ err = ether_delmulti((struct ifreq *)data, &sc->sc_ac);
+
+ if (err == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly. But remember UP flag!
+ */
+ temp = sc->sc_if.if_flags & IFF_UP;
+ snreset(sc);
+ sc->sc_if.if_flags |= temp;
+ err = 0;
+ }
+ break;
+ default:
+ err = EINVAL;
+ }
+ splx(s);
+ return (err);
+}
+
+/*
+ * Encapsulate a packet of type family for the local net.
+ * Use trailer local net encapsulation if enough data in first
+ * packet leaves a multiple of 512 bytes of data in remainder.
+ */
+void
+snstart(ifp)
+ struct ifnet *ifp;
+{
+ struct sn_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+ int len;
+
+ if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
+ return;
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
+ if (m == 0)
+ return;
+
+ /*
+ * If there is nothing in the o/p queue, and there is room in
+ * the Tx ring, then send the packet directly. Otherwise append
+ * it to the o/p queue.
+ */
+ if (!sonicput(sc, m)) { /* not enough space */
+ IF_PREPEND(&sc->sc_if.if_snd, m);
+ }
+#if NBPFILTER > 0
+ /*
+ * If bpf is listening on this interface, let it
+ * see the packet before we commit it to the wire.
+ */
+ if (sc->sc_if.if_bpf)
+ bpf_mtap(sc->sc_if.if_bpf, m);
+#endif
+
+ sc->sc_if.if_opackets++; /* # of pkts */
+ sc->sc_sum.ls_opacks++; /* # of pkts */
+}
+
+/*
+ * This is called from sonicioctl() when /etc/ifconfig is run to set
+ * the address or switch the i/f on.
+ */
+void caminitialise __P((void));
+void camentry __P((int, u_char *ea));
+void camprogram __P((struct sn_softc *));
+void initialise_tda __P((struct sn_softc *));
+void initialise_rda __P((struct sn_softc *));
+void initialise_rra __P((struct sn_softc *));
+
+/*
+ * reset and restart the SONIC. Called in case of fatal
+ * hardware/software errors.
+ */
+void
+snreset(sc)
+ struct sn_softc *sc;
+{
+ snstop(sc);
+ sninit(sc);
+}
+
+int
+sninit(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr = sc->sc_csr;
+ int s, error;
+
+ if (sc->sc_if.if_flags & IFF_RUNNING)
+ /* already running */
+ return (0);
+
+ s = splnet();
+
+ csr->s_cr = CR_RST; /* s_dcr only accessable reset mode! */
+
+ /* config it */
+ csr->s_dcr = DCR_LBR | DCR_SYNC | DCR_WAIT0 | DCR_DW32 | DCR_DMABLOCK |
+ DCR_RFT16 | DCR_TFT16;
+ csr->s_rcr = RCR_BRD | RCR_LBNONE;
+ csr->s_imr = IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_HBLEN | IMR_LCDEN;
+
+ /* clear pending interrupts */
+ csr->s_isr = 0x7fff;
+
+ /* clear tally counters */
+ csr->s_crct = -1;
+ csr->s_faet = -1;
+ csr->s_mpt = -1;
+
+ initialise_tda(sc);
+ initialise_rda(sc);
+ initialise_rra(sc);
+
+ /* enable the chip */
+ csr->s_cr = 0;
+ wbflush();
+
+ /* program the CAM with our address */
+ caminitialise();
+ camentry(0, sc->sc_enaddr);
+ camprogram(sc);
+
+ /* get it to read resource descriptors */
+ csr->s_cr = CR_RRRA;
+ wbflush();
+ while (csr->s_cr & CR_RRRA)
+ continue;
+
+ /* enable rx */
+ csr->s_cr = CR_RXEN;
+ wbflush();
+
+ /* flag interface as "running" */
+ sc->sc_if.if_flags |= IFF_RUNNING;
+
+ splx(s);
+ return (0);
+
+bad:
+ snstop(sc);
+ return (error);
+}
+
+/*
+ * close down an interface and free its buffers
+ * Called on final close of device, or if sninit() fails
+ * part way through.
+ */
+int
+snstop(sc)
+ struct sn_softc *sc;
+{
+ struct mtd *mtd;
+ int s = splnet();
+
+ /* stick chip in reset */
+ sc->sc_csr->s_cr = CR_RST;
+ wbflush();
+
+ /* free all receive buffers (currently static so nothing to do) */
+
+ /* free all pending transmit mbufs */
+ while (mtd = mtdhead) {
+ mtdhead = mtdhead->mtd_link;
+ if (mtd->mtd_mbuf)
+ m_freem(mtd->mtd_mbuf);
+ mtd->mtd_mbuf = 0;
+ mtd_free(mtd);
+ }
+ mtdnext = mtd_alloc();
+
+ sc->sc_if.if_timer = 0;
+ sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * Called if any Tx packets remain unsent after 5 seconds,
+ * In all cases we just reset the chip, and any retransmission
+ * will be handled by higher level protocol timeouts.
+ */
+void
+snwatchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct sn_softc *sc = ifp->if_softc;
+ int temp;
+
+ if (mtdhead && mtdhead->mtd_mbuf) {
+ /* something still pending for transmit */
+ if (mtdhead->mtd_txp->status == 0)
+ log(LOG_ERR, "%s: Tx - timeout\n",
+ sc->sc_if.if_xname);
+ else
+ log(LOG_ERR, "%s: Tx - lost interrupt\n",
+ sc->sc_if.if_xname);
+ temp = sc->sc_if.if_flags & IFF_UP;
+ snreset(sc);
+ sc->sc_if.if_flags |= temp;
+ }
+}
+/*
+ * stuff packet into sonic (at splnet)
+*/
+int
+sonicput(sc, m0)
+ struct sn_softc *sc;
+ struct mbuf *m0;
+{
+ struct sonic_reg *csr = sc->sc_csr;
+ struct TXpkt *txp;
+ struct mtd *mtdnew;
+ struct mbuf *m;
+ int len = 0, fr = 0;
+ int i;
+ int fragoffset; /* Offset in viritual dma space for fragment */
+
+ /* grab the replacement mtd */
+ if ((mtdnew = mtd_alloc()) == 0)
+ return (0);
+
+ /* this packet goes to mdtnext fill in the TDA */
+ mtdnext->mtd_mbuf = m0;
+ txp = mtdnext->mtd_txp;
+ SWR(txp->config, 0);
+ fragoffset = (txp - p_tda) * FRAGMAX * 4096;
+
+ /*
+ * Now fill in the fragments. Each fragment maps to it's
+ * own dma page. Fragments crossing a dma page boundary
+ * are split up in two fragments. This is somewhat stupid
+ * because the dma mapper can do the work, but it helps
+ * keeping the fragments in order. (read lazy programmer).
+ */
+ for (m = m0; m; m = m->m_next) {
+ unsigned va = (unsigned) mtod(m, caddr_t);
+ int resid = m->m_len;
+
+#if has_to_be_fixed
+ if(resid != 0) {
+ R4K_HitFlushDCache(va, resid);
+ }
+#endif
+ len += resid;
+
+ while (resid) {
+ unsigned pa;
+ unsigned n;
+
+ pa = (va & PGOFSET) + fragoffset;
+ n = resid;
+ if (n > NBPG - (va & PGOFSET)) {
+ n = NBPG - (va & PGOFSET);
+ }
+ if (fr < FRAGMAX) {
+ SWR(txp->u[fr].frag_ptrlo, LOWER(pa));
+ SWR(txp->u[fr].frag_ptrhi, UPPER(pa));
+ SWR(txp->u[fr].frag_size, n);
+ }
+ fr++;
+ va += n;
+ resid -= n;
+ fragoffset += 4096;
+ }
+ }
+ /*
+ * pad out last fragment for minimum size
+ */
+ if (len < ETHERMIN + sizeof(struct ether_header) && fr < FRAGMAX) {
+ int pad = ETHERMIN + sizeof(struct ether_header) - len;
+ static char zeros[64];
+ unsigned pa;
+
+ pa = ((unsigned)zeros & PGOFSET) + fragoffset;
+ SWR(txp->u[fr].frag_ptrlo, LOWER(pa));
+ SWR(txp->u[fr].frag_ptrhi, UPPER(pa));
+ SWR(txp->u[fr].frag_size, pad);
+ fr++;
+ len = ETHERMIN + sizeof(struct ether_header);
+ }
+
+ if (fr > FRAGMAX) {
+ mtd_free(mtdnew);
+ m_freem(m0);
+ log(LOG_ERR, "%s: tx too many fragments %d\n",
+ sc->sc_if.if_xname, fr);
+ sc->sc_if.if_oerrors++;
+ return (len);
+ }
+
+ SWR(txp->frag_count, fr);
+ SWR(txp->pkt_size, len);
+
+ /* link onto the next mtd that will be used */
+ SWR(txp->u[fr].tlink, LOWER(v_tda + (mtdnew->mtd_txp - p_tda)) | EOL);
+
+ if (mtdhead == 0) {
+ /* no current transmit list start with this one */
+ mtdtail = mtdhead = mtdnext;
+ csr->s_ctda = LOWER(v_tda + (txp - p_tda));
+ } else {
+ /*
+ * have a transmit list append it to end note
+ * mtdnext is already physicaly linked to mtdtail in
+ * mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink
+ */
+ SWR(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink,
+ SRD(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink) & ~EOL);
+ mtdtail = mtdnext;
+ }
+ mtdnext->mtd_link = mtdnew;
+ mtdnext = mtdnew;
+
+ /* make sure chip is running */
+ wbflush();
+ csr->s_cr = CR_TXP;
+ wbflush();
+ sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
+ return (len);
+}
+
+/*
+ * Read out the ethernet address from the cam. It is stored
+ * there by the boot when doing a loopback test. Thus we don't
+ * have to fetch it from nv ram.
+ */
+int
+sngetaddr(sc)
+ struct sn_softc *sc;
+{
+ unsigned i, x, y;
+ char *cp, *ea;
+
+#if 0
+ sc->sc_csr->s_cr = CR_RST;
+ wbflush();
+ sc->sc_csr->s_cep = 0;
+ i = sc->sc_csr->s_cap2;
+ wbflush();
+ sc->sc_enaddr[5] = i >> 8;
+ sc->sc_enaddr[4] = i;
+ i = sc->sc_csr->s_cap1;
+ wbflush();
+ sc->sc_enaddr[3] = i >> 8;
+ sc->sc_enaddr[2] = i;
+ i = sc->sc_csr->s_cap0;
+ wbflush();
+ sc->sc_enaddr[1] = i >> 8;
+ sc->sc_enaddr[0] = i;
+
+ sc->sc_csr->s_cr = 0;
+ wbflush();
+#else
+ sc->sc_enaddr[0] = 0x08;
+ sc->sc_enaddr[1] = 0x00;
+ sc->sc_enaddr[2] = 0x20;
+ sc->sc_enaddr[3] = 0xa0;
+ sc->sc_enaddr[4] = 0x66;
+ sc->sc_enaddr[5] = 0x54;
+#endif
+ return (0);
+}
+
+void sonictxint __P((struct sn_softc *));
+void sonicrxint __P((struct sn_softc *));
+
+int sonic_read __P((struct sn_softc *, struct RXpkt *));
+struct mbuf *sonic_get __P((struct sn_softc *, struct ether_header *, int));
+
+void
+mtd_free(mtd)
+ struct mtd *mtd;
+{
+ mtd->mtd_link = mtdfree;
+ mtdfree = mtd;
+}
+
+struct mtd *
+mtd_alloc()
+{
+ struct mtd *mtd = mtdfree;
+
+ if (mtd) {
+ mtdfree = mtd->mtd_link;
+ mtd->mtd_link = 0;
+ }
+ return (mtd);
+}
+
+/*
+ * CAM support
+ */
+void
+caminitialise()
+{
+ int i;
+
+ for (i = 0; i < MAXCAM; i++)
+ SWR(p_cda->desc[i].cam_ep, i);
+ SWR(p_cda->enable, 0);
+}
+
+void
+camentry(entry, ea)
+ int entry;
+ u_char *ea;
+{
+ SWR(p_cda->desc[entry].cam_ep, entry);
+ SWR(p_cda->desc[entry].cam_ap2, (ea[5] << 8) | ea[4]);
+ SWR(p_cda->desc[entry].cam_ap1, (ea[3] << 8) | ea[2]);
+ SWR(p_cda->desc[entry].cam_ap0, (ea[1] << 8) | ea[0]);
+ SWR(p_cda->enable, SRD(p_cda->enable) | (1 << entry));
+}
+
+void
+camprogram(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr;
+ int timeout;
+ int i;
+
+ csr = sc->sc_csr;
+ csr->s_cdp = LOWER(v_cda);
+ csr->s_cdc = MAXCAM;
+ csr->s_cr = CR_LCAM;
+ wbflush();
+
+ timeout = 10000;
+ while (csr->s_cr & CR_LCAM && timeout--)
+ continue;
+ if (timeout == 0) {
+ /* XXX */
+ panic("sonic: CAM initialisation failed\n");
+ }
+ timeout = 10000;
+ while ((csr->s_isr & ISR_LCD) == 0 && timeout--)
+ continue;
+
+ if (csr->s_isr & ISR_LCD)
+ csr->s_isr = ISR_LCD;
+ else
+ printf("sonic: CAM initialisation without interrupt\n");
+}
+
+#if 0
+void
+camdump(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr = sc->sc_csr;
+ int i;
+
+ printf("CAM entries:\n");
+ csr->s_cr = CR_RST;
+ wbflush();
+
+ for (i = 0; i < 16; i++) {
+ ushort ap2, ap1, ap0;
+ csr->s_cep = i;
+ wbflush();
+ ap2 = csr->s_cap2;
+ ap1 = csr->s_cap1;
+ ap0 = csr->s_cap0;
+ printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);
+ }
+ printf("CAM enable 0x%x\n", csr->s_cep);
+
+ csr->s_cr = 0;
+ wbflush();
+}
+#endif
+
+void
+initialise_tda(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr;
+ struct mtd *mtd;
+ int i;
+
+ csr = sc->sc_csr;
+
+ mtdfree = mtdhead = mtdtail = (struct mtd *) 0;
+
+ for (i = 0; i < NTDA; i++) {
+ mtd = &mtda[i];
+ mtd->mtd_txp = &p_tda[i];
+ mtd->mtd_mbuf = (struct mbuf *) 0;
+ mtd_free(mtd);
+ }
+ mtdnext = mtd_alloc();
+
+ csr->s_utda = UPPER(v_tda);
+}
+
+void
+initialise_rda(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr;
+ int i;
+
+ csr = sc->sc_csr;
+
+ /* link the RDA's together into a circular list */
+ for (i = 0; i < (NRDA - 1); i++) {
+ SWR(p_rda[i].rlink, LOWER(&v_rda[i + 1]));
+ SWR(p_rda[i].in_use, 1);
+ }
+ SWR(p_rda[NRDA - 1].rlink, LOWER(&v_rda[0]) | EOL);
+ SWR(p_rda[NRDA - 1].in_use, 1);
+
+ /* mark end of receive descriptor list */
+ sc->sc_lrxp = &p_rda[NRDA - 1];
+
+ sc->sc_rxmark = 0;
+
+ csr->s_urda = UPPER(&v_rda[0]);
+ csr->s_crda = LOWER(&v_rda[0]);
+ wbflush();
+}
+
+void
+initialise_rra(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr;
+ int i;
+
+ csr = sc->sc_csr;
+
+ csr->s_eobc = RBASIZE / 2 - 2; /* must be >= MAXETHERPKT */
+ csr->s_urra = UPPER(v_rra);
+ csr->s_rsa = LOWER(v_rra);
+ csr->s_rea = LOWER(&v_rra[NRRA]);
+ csr->s_rrp = LOWER(v_rra);
+ csr->s_rsc = 0;
+
+ /* fill up SOME of the rra with buffers */
+ for (i = 0; i < NRBA; i++) {
+ SWR(p_rra[i].buff_ptrhi, UPPER(&v_rba[i * RBASIZE]));
+ SWR(p_rra[i].buff_ptrlo, LOWER(&v_rba[i * RBASIZE]));
+ SWR(p_rra[i].buff_wchi, UPPER(RBASIZE / 2));
+ SWR(p_rra[i].buff_wclo, LOWER(RBASIZE / 2));
+ }
+ sc->sc_rramark = NRBA;
+ csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]);
+ wbflush();
+}
+
+int
+snintr(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr = sc->sc_csr;
+ int isr;
+
+ while (isr = (csr->s_isr & ISR_ALL)) {
+ /* scrub the interrupts that we are going to service */
+ csr->s_isr = isr;
+ wbflush();
+
+ if (isr & (ISR_BR | ISR_LCD | ISR_PINT | ISR_TC))
+ printf("sonic: unexpected interrupt status 0x%x\n", isr);
+
+ if (isr & (ISR_TXDN | ISR_TXER))
+ sonictxint(sc);
+
+ if (isr & ISR_PKTRX)
+ sonicrxint(sc);
+
+ if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) {
+ if (isr & ISR_HBL)
+ printf("sonic: no heartbeat\n");
+ if (isr & ISR_RDE)
+ printf("sonic: receive descriptors exhausted\n");
+ if (isr & ISR_RBE)
+ printf("sonic: receive buffers exhausted\n");
+ if (isr & ISR_RBAE)
+ printf("sonic: receive buffer area exhausted\n");
+ if (isr & ISR_RFO)
+ printf("sonic: receive FIFO overrun\n");
+ }
+ if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) {
+#ifdef notdef
+ if (isr & ISR_CRC)
+ sc->sc_crctally++;
+ if (isr & ISR_FAE)
+ sc->sc_faetally++;
+ if (isr & ISR_MP)
+ sc->sc_mptally++;
+#endif
+ }
+ }
+ return (1);
+}
+
+/*
+ * Transmit interrupt routine
+ */
+void
+sonictxint(sc)
+ struct sn_softc *sc;
+{
+ struct TXpkt *txp;
+ struct sonic_reg *csr;
+ struct mtd *mtd;
+
+ if (mtdhead == (struct mtd *) 0)
+ return;
+
+ csr = sc->sc_csr;
+
+ while (mtd = mtdhead) {
+ struct mbuf *m = mtd->mtd_mbuf;
+
+ if (m == 0)
+ break;
+
+ txp = mtd->mtd_txp;
+
+ if (SRD(txp->status) == 0) /* it hasn't really gone yet */
+ return;
+
+ if (ethdebug) {
+ struct ether_header *eh = mtod(m, struct ether_header *);
+ printf("xmit status=0x%x len=%d type=0x%x from %s",
+ txp->status,
+ txp->pkt_size,
+ htons(eh->ether_type),
+ ether_sprintf(eh->ether_shost));
+ printf(" (to %s)\n", ether_sprintf(eh->ether_dhost));
+ }
+ m_freem(m);
+ mtd->mtd_mbuf = 0;
+ mtdhead = mtd->mtd_link;
+
+ mtd_free(mtd);
+
+ if ((SRD(txp->status) & TCR_PTX) == 0) {
+ printf("sonic: Tx packet status=0x%x\n", txp->status);
+
+ if (mtdhead != mtdnext) {
+ printf("resubmitting remaining packets\n");
+ csr->s_ctda = LOWER(v_tda + (mtdhead->mtd_txp - p_tda));
+ csr->s_cr = CR_TXP;
+ wbflush();
+ return;
+ }
+ }
+ }
+ /* mtdhead should be at mtdnext (go) */
+ assert(mtdhead == mtdnext);
+ assert(mtdhead->mtd_link == 0);
+ mtdhead = 0;
+
+ /* and start feeding any queued packets to chip */
+ while (1) {
+ struct mbuf *m;
+
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
+ if (m == 0) /* nothing left to send */
+ break;
+ if (!sonicput(sc, m)) { /* not enough space */
+ IF_PREPEND(&sc->sc_if.if_snd, m);
+ break;
+ }
+ }
+}
+
+/*
+ * Receive interrupt routine
+ */
+void
+sonicrxint(sc)
+ struct sn_softc *sc;
+{
+ struct sonic_reg *csr = sc->sc_csr;
+ struct RXpkt *rxp;
+ u_long addr;
+ int orra;
+
+ rxp = &p_rda[sc->sc_rxmark];
+
+ while (SRD(rxp->in_use) == 0) {
+ unsigned status = SRD(rxp->status);
+ if ((status & RCR_LPKT) == 0)
+ printf("sonic: more than one packet in RBA!\n");
+ assert(PSNSEQ(SRD(rxp->seq_no)) == 0);
+
+ if (status & RCR_PRX) {
+ if (sonic_read(sc, rxp)) {
+ sc->sc_if.if_ipackets++;
+ sc->sc_sum.ls_ipacks++;
+ sc->sc_missed = 0;
+ }
+ } else
+ sc->sc_if.if_ierrors++;
+
+ /*
+ * give receive buffer area back to chip XXX what buffer
+ * did the sonic use for this descriptor answer look at
+ * the rba sequence number !!
+ */
+ orra = RBASEQ(SRD(rxp->seq_no)) & RRAMASK;
+
+ assert(SRD(rxp->pkt_ptrhi) == SRD(p_rra[orra].buff_ptrhi));
+ assert(SRD(rxp->pkt_ptrlo) == SRD(p_rra[orra].buff_ptrlo));
+if(SRD(rxp->pkt_ptrlo) != SRD(p_rra[orra].buff_ptrlo))
+printf("%x,%x\n",SRD(rxp->pkt_ptrlo),SRD(p_rra[orra].buff_ptrlo));
+ assert(SRD(p_rra[orra].buff_wclo));
+
+ /*
+ * orra is now empty of packets and can be freed if
+ * sonic read didnt copy it out then we would have to
+ * wait !!
+ * (dont bother add it back in again straight away)
+ */
+ p_rra[sc->sc_rramark] = p_rra[orra];
+
+ /* zap old rra for fun */
+ p_rra[orra].buff_wchi = 0;
+ p_rra[orra].buff_wclo = 0;
+
+ sc->sc_rramark = (sc->sc_rramark + 1) & RRAMASK;
+ csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]);
+ wbflush();
+
+ /*
+ * give recieve descriptor back to chip simple
+ * list is circular
+ */
+ SWR(rxp->in_use, 1);
+ SWR(rxp->rlink, SRD(rxp->rlink) | EOL);
+ SWR(sc->sc_lrxp->rlink, SRD(sc->sc_lrxp->rlink) & ~EOL);
+ sc->sc_lrxp = rxp;
+
+ if (++sc->sc_rxmark >= NRDA)
+ sc->sc_rxmark = 0;
+ rxp = &p_rda[sc->sc_rxmark];
+ }
+}
+
+/*
+ * sonic_read -- pull packet off interface and forward to
+ * appropriate protocol handler
+ */
+int
+sonic_read(sc, rxp)
+ struct sn_softc *sc;
+ struct RXpkt *rxp;
+{
+ struct ifnet *ifp = &sc->sc_if;
+ /*extern char *ether_sprintf();*/
+ struct ether_header *et;
+ struct mbuf *m;
+ int len, off, i;
+ caddr_t pkt;
+
+ /*
+ * Get input data length.
+ * Get pointer to ethernet header (in input buffer).
+ * Deal with trailer protocol: if type is PUP trailer
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+
+ len = SRD(rxp->byte_count) - sizeof(struct ether_header) - FCSSIZE;
+ pkt = (caddr_t)((SRD(rxp->pkt_ptrhi) << 16) | SRD(rxp->pkt_ptrlo));
+ pkt = pkt - v_rba + p_rba;
+ et = (struct ether_header *)pkt;
+
+ if (ethdebug) {
+ printf("rcvd 0x%x status=0x%x, len=%d type=0x%x from %s",
+ et, rxp->status, len, htons(et->ether_type),
+ ether_sprintf(et->ether_shost));
+ printf(" (to %s)\n", ether_sprintf(et->ether_dhost));
+ }
+ if (len < ETHERMIN || len > ETHERMTU) {
+ printf("sonic: invalid packet length %d bytes\n", len);
+ return (0);
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a bpf filter listening on this interface.
+ * If so, hand off the raw packet to enet, then discard things
+ * not destined for us (but be sure to keep broadcast/multicast).
+ */
+ if (sc->sc_if.if_bpf) {
+ bpf_tap(sc->sc_if.if_bpf, pkt,
+ len + sizeof(struct ether_header));
+ if ((ifp->if_flags & IFF_PROMISC) != 0 &&
+ (et->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
+ bcmp(et->ether_dhost, sc->sc_enaddr,
+ sizeof(et->ether_dhost)) != 0)
+ return;
+ }
+#endif
+ m = sonic_get(sc, et, len);
+ if (m == NULL)
+ return (0);
+ ether_input(ifp, et, m);
+ return(1);
+}
+
+#define sonicdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
+
+/*
+ * munge the recieved packet into an mbuf chain
+ * because we are using stupif buffer management this
+ * is slow.
+*/
+struct mbuf *
+sonic_get(sc, eh, datalen)
+ struct sn_softc *sc;
+ struct ether_header *eh;
+ int datalen;
+{
+ struct mbuf *m;
+ struct mbuf *top = 0, **mp = &top;
+ int len;
+ char *spkt = sonicdataaddr(eh, 0, caddr_t);
+ char *epkt = spkt + datalen;
+ char *cp = spkt;
+
+ epkt = cp + datalen;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ m->m_pkthdr.len = datalen;
+ m->m_len = MHLEN;
+
+ while (datalen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ m->m_len = MLEN;
+ }
+ len = min(datalen, epkt - cp);
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = len = min(len, MCLBYTES);
+ else
+ len = m->m_len;
+ } else {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (len < m->m_len) {
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+ }
+ bcopy(cp, mtod(m, caddr_t), (unsigned) len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ datalen -= len;
+ if (cp == epkt)
+ cp = spkt;
+ }
+ return (top);
+}
diff --git a/sys/arch/wgrisc/dev/if_sn.h b/sys/arch/wgrisc/dev/if_sn.h
new file mode 100644
index 00000000000..4139a1c7850
--- /dev/null
+++ b/sys/arch/wgrisc/dev/if_sn.h
@@ -0,0 +1,347 @@
+/* $OpenBSD: if_sn.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */
+/*
+ * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk)
+ * You may use, copy, and modify this program so long as you retain the
+ * copyright line.
+ */
+
+/*
+ * if_sonic.h -- National Semiconductor DP83932BVF (SONIC)
+ */
+
+/*
+ * Accessing SONIC data structures and registers as 32 bit values
+ * makes code endianess independent. The SONIC is however always in
+ * bigendian mode so it is necessary to ensure that data structures shared
+ * between the CPU and the SONIC are always in bigendian order.
+ */
+
+/*
+ * Receive Resource Descriptor
+ * This structure describes the buffers into which packets
+ * will be received. Note that more than one packet may be
+ * packed into a single buffer if constraints permit.
+ */
+#if SONICDW == 32
+struct RXrsrc {
+ u_long buff_ptrlo; /* buffer address LO */
+ u_long buff_ptrhi; /* buffer address HI */
+ u_long buff_wclo; /* buffer size (16bit words) LO */
+ u_long buff_wchi; /* buffer size (16bit words) HI */
+};
+#endif
+
+/*
+ * Receive Descriptor
+ * This structure holds information about packets received.
+ */
+#if SONICDW == 32
+struct RXpkt {
+ u_long status; /* + receive status */
+ u_long byte_count; /* + packet byte count (including FCS) */
+ u_long pkt_ptrlo; /* + packet data LO (in RBA) */
+ u_long pkt_ptrhi; /* + packet data HI (in RBA) */
+ u_long seq_no; /* + RBA sequence numbers */
+ u_long rlink; /* link to next receive descriptor */
+ u_long in_use; /* + packet available to SONIC */
+ u_long pad; /* pad to multiple of 16 bytes */
+};
+#endif
+#define RBASEQ(x) (((x)>>8)&0xff)
+#define PSNSEQ(x) ((x) & 0xff)
+
+/*
+ * Transmit Descriptor
+ * This structure holds information about packets to be transmitted.
+ */
+#define FRAGMAX 31 /* maximum number of fragments in a packet */
+#if SONICDW == 32
+struct TXpkt {
+ u_long status; /* + transmitted packet status */
+ u_long config; /* transmission configuration */
+ u_long pkt_size; /* entire packet size in bytes */
+ u_long frag_count; /* # fragments in packet */
+ union {
+ struct {
+ u_long _frag_ptrlo; /* pointer to packet fragment LO */
+ u_long _frag_ptrhi; /* pointer to packet fragment HI */
+ u_long _frag_size; /* fragment size */
+ } u_frag;
+ struct {
+ u_long _tlink; /* link to next transmit descriptor */
+ } u_link;
+ } u[FRAGMAX+1]; /* +1 makes tcp->u[FRAGMAX].u_link.link valid! */
+};
+#endif
+
+#define frag_ptrlo u_frag._frag_ptrlo
+#define frag_ptrhi u_frag._frag_ptrhi
+#define frag_size u_frag._frag_size
+#define tlink u_link._tlink
+
+#define EOL 0x0001 /* end of list marker for link fields */
+
+#define MAXCAM 16 /* number of user entries in CAM */
+#if SONICDW == 32
+struct CDA {
+ struct {
+ u_long cam_ep; /* CAM Entry Pointer */
+ u_long cam_ap0; /* CAM Address Port 0 xx-xx-xx-xx-YY-YY */
+ u_long cam_ap1; /* CAM Address Port 1 xx-xx-YY-YY-xxxx */
+ u_long cam_ap2; /* CAM Address Port 2 YY-YY-xx-xx-xx-xx */
+ } desc[MAXCAM];
+ u_long enable; /* mask enabling CAM entries */
+};
+#endif
+
+/*
+ * SONIC registers as seen by the processor
+ */
+struct sonic_reg {
+ volatile u_long s_cr; /* 00: Command */
+ volatile u_long s_dcr; /* 01: Data Configuration */
+ volatile u_long s_rcr; /* 02: Receive Control */
+ volatile u_long s_tcr; /* 03: Transmit Control */
+ volatile u_long s_imr; /* 04: Interrupt Mask */
+ volatile u_long s_isr; /* 05: Interrupt Status */
+ volatile u_long s_utda; /* 06: Upper Transmit Descriptor Address */
+ volatile u_long s_ctda; /* 07: Current Transmit Descriptor Address */
+ volatile u_long _s_tps; /* 08* Transmit Packet Size */
+ volatile u_long _s_tfc; /* 09* Transmit Fragment Count */
+ volatile u_long _s_tsa0; /* 0a* Transmit Start Address 0 */
+ volatile u_long _s_tsa1; /* 0b* Transmit Start Address 1 */
+ volatile u_long _s_tfs; /* 0c* Transmit Fragment Size */
+ volatile u_long s_urda; /* 0d: Upper Receive Descriptor Address */
+ volatile u_long s_crda; /* 0e: Current Receive Descriptor Address */
+ volatile u_long _s_crba0; /* 0f* Current Receive Buffer Address 0 */
+ volatile u_long _s_crba1; /* 10* Current Receive Buffer Address 1 */
+ volatile u_long _s_rbwc0; /* 11* Remaining Buffer Word Count 0 */
+ volatile u_long _s_rbwc1; /* 12* Remaining Buffer Word Count 1 */
+ volatile u_long s_eobc; /* 13: End Of Buffer Word Count */
+ volatile u_long s_urra; /* 14: Upper Receive Resource Address */
+ volatile u_long s_rsa; /* 15: Resource Start Address */
+ volatile u_long s_rea; /* 16: Resource End Address */
+ volatile u_long s_rrp; /* 17: Resource Read Pointer */
+ volatile u_long s_rwp; /* 18: Resource Write Pointer */
+ volatile u_long _s_trba0; /* 19* Temporary Receive Buffer Address 0 */
+ volatile u_long _s_trba1; /* 1a* Temporary Receive Buffer Address 1 */
+ volatile u_long _s_tbwc0; /* 1b* Temporary Buffer Word Count 0 */
+ volatile u_long _s_tbwc1; /* 1c* Temporary Buffer Word Count 1 */
+ volatile u_long _s_addr0; /* 1d* Address Generator 0 */
+ volatile u_long _s_addr1; /* 1e* Address Generator 1 */
+ volatile u_long _s_llfa; /* 1f* Last Link Field Address */
+ volatile u_long _s_ttda; /* 20* Temp Transmit Descriptor Address */
+ volatile u_long s_cep; /* 21: CAM Entry Pointer */
+ volatile u_long s_cap2; /* 22: CAM Address Port 2 */
+ volatile u_long s_cap1; /* 23: CAM Address Port 1 */
+ volatile u_long s_cap0; /* 24: CAM Address Port 0 */
+ volatile u_long s_ce; /* 25: CAM Enable */
+ volatile u_long s_cdp; /* 26: CAM Descriptor Pointer */
+ volatile u_long s_cdc; /* 27: CAM Descriptor Count */
+ volatile u_long s_sr; /* 28: Silicon Revision */
+ volatile u_long s_wt0; /* 29: Watchdog Timer 0 */
+ volatile u_long s_wt1; /* 2a: Watchdog Timer 1 */
+ volatile u_long s_rsc; /* 2b: Receive Sequence Counter */
+ volatile u_long s_crct; /* 2c: CRC Error Tally */
+ volatile u_long s_faet; /* 2d: FAE Tally */
+ volatile u_long s_mpt; /* 2e: Missed Packet Tally */
+ volatile u_long _s_mdt; /* 2f* Maximum Deferral Timer */
+ volatile u_long _s_rtc; /* 30* Receive Test Control */
+ volatile u_long _s_ttc; /* 31* Transmit Test Control */
+ volatile u_long _s_dtc; /* 32* DMA Test Control */
+ volatile u_long _s_cc0; /* 33* CAM Comparison 0 */
+ volatile u_long _s_cc1; /* 34* CAM Comparison 1 */
+ volatile u_long _s_cc2; /* 35* CAM Comparison 2 */
+ volatile u_long _s_cm; /* 36* CAM Match */
+ volatile u_long :32; /* 37* reserved */
+ volatile u_long :32; /* 38* reserved */
+ volatile u_long _s_rbc; /* 39* Receiver Byte Count */
+ volatile u_long :32; /* 3a* reserved */
+ volatile u_long _s_tbo; /* 3b* Transmitter Backoff Counter */
+ volatile u_long _s_trc; /* 3c* Transmitter Random Counter */
+ volatile u_long _s_tbm; /* 3d* Transmitter Backoff Mask */
+ volatile u_long :32; /* 3e* Reserved */
+ volatile u_long s_dcr2; /* 3f Data Configuration 2 (AVF) */
+};
+
+/*
+ * Register Interpretations
+ */
+
+/*
+ * The command register is used for issuing commands to the SONIC.
+ * With the exception of CR_RST, the bit is reset when the operation
+ * completes.
+ */
+#define CR_LCAM 0x0200 /* load CAM with descriptor at s_cdp */
+#define CR_RRRA 0x0100 /* read next RRA descriptor at s_rrp */
+#define CR_RST 0x0080 /* software reset */
+#define CR_ST 0x0020 /* start timer */
+#define CR_STP 0x0010 /* stop timer */
+#define CR_RXEN 0x0008 /* receiver enable */
+#define CR_RXDIS 0x0004 /* receiver disable */
+#define CR_TXP 0x0002 /* transmit packets */
+#define CR_HTX 0x0001 /* halt transmission */
+
+/*
+ * The data configuration register establishes the SONIC's bus cycle
+ * operation. This register can only be accessed when the SONIC is in
+ * reset mode (s_cr.CR_RST is set.)
+ */
+#define DCR_EXBUS 0x8000 /* extended bus mode (AVF) */
+#define DCR_LBR 0x2000 /* latched bus retry */
+#define DCR_PO1 0x1000 /* programmable output 1 */
+#define DCR_PO0 0x0800 /* programmable output 0 */
+#define DCR_STERM 0x0400 /* synchronous termination */
+#define DCR_USR1 0x0200 /* reflects USR1 input pin */
+#define DCR_USR0 0x0100 /* reflects USR0 input pin */
+#define DCR_WC1 0x0080 /* wait state control 1 */
+#define DCR_WC0 0x0040 /* wait state control 0 */
+#define DCR_DW 0x0020 /* data width select */
+#define DCR_BMS 0x0010 /* DMA block mode select */
+#define DCR_RFT1 0x0008 /* receive FIFO threshold control 1 */
+#define DCR_RFT0 0x0004 /* receive FIFO threshold control 0 */
+#define DCR_TFT1 0x0002 /* transmit FIFO threshold control 1 */
+#define DCR_TFT0 0x0001 /* transmit FIFO threshold control 0 */
+
+/* data configuration register aliases */
+#define DCR_SYNC DCR_STERM /* synchronous (memory cycle 2 clocks) */
+#define DCR_ASYNC 0 /* asynchronous (memory cycle 3 clocks) */
+
+#define DCR_WAIT0 0 /* 0 wait states added */
+#define DCR_WAIT1 DCR_WC0 /* 1 wait state added */
+#define DCR_WAIT2 DCR_WC1 /* 2 wait states added */
+#define DCR_WAIT3 (DCR_WC1|DCR_WC0) /* 3 wait states added */
+
+#define DCR_DW16 0 /* use 16-bit DMA accesses */
+#define DCR_DW32 DCR_DW /* use 32-bit DMA accesses */
+
+#define DCR_DMAEF 0 /* DMA until TX/RX FIFO has emptied/filled */
+#define DCR_DMABLOCK DCR_BMS /* DMA until RX/TX threshold crossed */
+
+#define DCR_RFT4 0 /* receive threshold 4 bytes */
+#define DCR_RFT8 DCR_RFT0 /* receive threshold 8 bytes */
+#define DCR_RFT16 DCR_RFT1 /* receive threshold 16 bytes */
+#define DCR_RFT24 (DCR_RFT1|DCR_RFT0) /* receive threshold 24 bytes */
+
+#define DCR_TFT8 0 /* transmit threshold 8 bytes */
+#define DCR_TFT16 DCR_TFT0 /* transmit threshold 16 bytes */
+#define DCR_TFT24 DCR_TFT1 /* transmit threshold 24 bytes */
+#define DCR_TFT28 (DCR_TFT1|DCR_TFT0) /* transmit threshold 28 bytes */
+
+/*
+ * The receive control register is used to filter incoming packets and
+ * provides status information on packets received.
+ * The contents of the register are copied into the RXpkt.status field
+ * when a packet is received. RCR_MC - RCR_PRX are then reset.
+ */
+#define RCR_ERR 0x8000 /* accept packets with CRC errors */
+#define RCR_RNT 0x4000 /* accept runt (length < 64) packets */
+#define RCR_BRD 0x2000 /* accept broadcast packets */
+#define RCR_PRO 0x1000 /* accept all physical address packets */
+#define RCR_AMC 0x0800 /* accept all multicast packets */
+#define RCR_LB1 0x0400 /* loopback control 1 */
+#define RCR_LB0 0x0200 /* loopback control 0 */
+#define RCR_MC 0x0100 /* multicast packet received */
+#define RCR_BC 0x0080 /* broadcast packet received */
+#define RCR_LPKT 0x0040 /* last packet in RBA (RBWC < EOBC) */
+#define RCR_CRS 0x0020 /* carrier sense activity */
+#define RCR_COL 0x0010 /* collision activity */
+#define RCR_CRC 0x0008 /* CRC error */
+#define RCR_FAE 0x0004 /* frame alignment error */
+#define RCR_LBK 0x0002 /* loopback packet received */
+#define RCR_PRX 0x0001 /* packet received without errors */
+
+/* receiver control register aliases */
+/* the loopback control bits provide the following options */
+#define RCR_LBNONE 0 /* no loopback - normal operation */
+#define RCR_LBMAC RCR_LB0 /* MAC loopback */
+#define RCR_LBENDEC RCR_LB1 /* ENDEC loopback */
+#define RCR_LBTRANS (RCR_LB1|RCR_LB0) /* transceiver loopback */
+
+/*
+ * The transmit control register controls the SONIC's transmit operations.
+ * TCR_PINT - TCR_EXDIS are loaded from the TXpkt.config field at the
+ * start of transmission. TCR_EXD-TCR_PTX are cleared at the beginning
+ * of transmission and updated when the transmission is completed.
+ */
+#define TCR_PINT 0x8000 /* interrupt when transmission starts */
+#define TCR_POWC 0x4000 /* program out of window collision timer */
+#define TCR_CRCI 0x2000 /* transmit packet without 4 byte FCS */
+#define TCR_EXDIS 0x1000 /* disable excessive deferral timer */
+#define TCR_EXD 0x0400 /* excessive deferrals occurred (>3.2ms) */
+#define TCR_DEF 0x0200 /* deferred transmissions occurred */
+#define TCR_NCRS 0x0100 /* carrier not present during transmission */
+#define TCR_CRSL 0x0080 /* carrier lost during transmission */
+#define TCR_EXC 0x0040 /* excessive collisions (>16) detected */
+#define TCR_OWC 0x0020 /* out of window (bad) collision occurred */
+#define TCR_PMB 0x0008 /* packet monitored bad - the tansmitted
+ * packet had a bad source address or CRC */
+#define TCR_FU 0x0004 /* FIFO underrun (memory access failed) */
+#define TCR_BCM 0x0002 /* byte count mismatch (TXpkt.pkt_size
+ * != sum(TXpkt.frag_size) */
+#define TCR_PTX 0x0001 /* packet transmitted without errors */
+
+/* transmit control register aliases */
+#define TCR_OWCSFD 0 /* start after start of frame delimiter */
+#define TCR_OWCPRE TCR_POWC /* start after first bit of preamble */
+
+
+/*
+ * The interrupt mask register masks the interrupts that
+ * are generated from the interrupt status register.
+ * All reserved bits should be written with 0.
+ */
+#define IMR_BREN 0x4000 /* bus retry occurred enable */
+#define IMR_HBLEN 0x2000 /* heartbeat lost enable */
+#define IMR_LCDEN 0x1000 /* load CAM done interrupt enable */
+#define IMR_PINTEN 0x0800 /* programmable interrupt enable */
+#define IMR_PRXEN 0x0400 /* packet received enable */
+#define IMR_PTXEN 0x0200 /* packet transmitted enable */
+#define IMR_TXEREN 0x0100 /* transmit error enable */
+#define IMR_TCEN 0x0080 /* timer complete enable */
+#define IMR_RDEEN 0x0040 /* receive descriptors exhausted enable */
+#define IMR_RBEEN 0x0020 /* receive buffers exhausted enable */
+#define IMR_RBAEEN 0x0010 /* receive buffer area exceeded enable */
+#define IMR_CRCEN 0x0008 /* CRC tally counter rollover enable */
+#define IMR_FAEEN 0x0004 /* FAE tally counter rollover enable */
+#define IMR_MPEN 0x0002 /* MP tally counter rollover enable */
+#define IMR_RFOEN 0x0001 /* receive FIFO overrun enable */
+
+
+/*
+ * The interrupt status register indicates the source of an interrupt when
+ * the INT pin goes active. The interrupt is acknowledged by writing
+ * the appropriate bit(s) in this register.
+ */
+#define ISR_ALL 0xffff /* all interrupts */
+#define ISR_BR 0x4000 /* bus retry occurred */
+#define ISR_HBL 0x2000 /* CD heartbeat lost */
+#define ISR_LCD 0x1000 /* load CAM command has completed */
+#define ISR_PINT 0x0800 /* programmed interrupt from TXpkt.config */
+#define ISR_PKTRX 0x0400 /* packet received */
+#define ISR_TXDN 0x0200 /* no remaining packets to be transmitted */
+#define ISR_TXER 0x0100 /* packet transmission caused error */
+#define ISR_TC 0x0080 /* timer complete */
+#define ISR_RDE 0x0040 /* receive descriptors exhausted */
+#define ISR_RBE 0x0020 /* receive buffers exhausted */
+#define ISR_RBAE 0x0010 /* receive buffer area exceeded */
+#define ISR_CRC 0x0008 /* CRC tally counter rollover */
+#define ISR_FAE 0x0004 /* FAE tally counter rollover */
+#define ISR_MP 0x0002 /* MP tally counter rollover */
+#define ISR_RFO 0x0001 /* receive FIFO overrun */
+
+/*
+ * The second data configuration register allows additional user defined
+ * pins to be controlled. These bits are only available if s_dcr.DCR_EXBUS
+ * is set.
+ */
+#define DCR2_EXPO3 0x8000 /* EXUSR3 output */
+#define DCR2_EXPO2 0x4000 /* EXUSR2 output */
+#define DCR2_EXPO1 0x2000 /* EXUSR1 output */
+#define DCR2_EXPO0 0x1000 /* EXUSR0 output */
+#define DCR2_PHL 0x0010 /* extend HOLD signal by 1/2 clock */
+#define DCR2_LRDY 0x0008 /* set latched ready mode */
+#define DCR2_PCM 0x0004 /* packet compress on match */
+#define DCR2_PCNM 0x0002 /* packet compress on mismatch */
+#define DCR2_RJM 0x0001 /* reject on match */
diff --git a/sys/arch/wgrisc/dev/scsi.h b/sys/arch/wgrisc/dev/scsi.h
new file mode 100644
index 00000000000..79f6886db9f
--- /dev/null
+++ b/sys/arch/wgrisc/dev/scsi.h
@@ -0,0 +1,559 @@
+/* $OpenBSD: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $ */
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * 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.
+ *
+ * from: @(#)scsi.h 8.1 (Berkeley) 6/10/93
+ * $Id: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $
+ *
+ * scsi.h --
+ *
+ * Common declarations for SCSI command formaters. This file only covers
+ * definitions pertaining to the SCSI common command set that are
+ * common to all SCSI device types (ie disk, tapes, WORM, printers, etc).
+ * Some of the references from the proceedings of the
+ * 1984 Mini/Micro Northeast conference might help in understanding SCSI.
+ *
+ * from: Header: /sprite/src/kernel/dev/RCS/scsi.h,
+ * v 9.1 90/02/13 23:11:24 jhh Exp SPRITE (Berkeley)
+ * $Id: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $
+ */
+
+#ifndef _SCSI_H
+#define _SCSI_H
+
+/*
+ * "Standard" SCSI Commands.
+ * SCSI commands are divided into 8 groups as follows:
+ * Group0 (0x00 - 0x1f). Basic commands. 6 bytes long
+ * Group1 (0x20 - 0x3f). Extended command. 10 bytes.
+ * Group2 (0x40 - 0x5f). Reserved.
+ * Group2 (0x60 - 0x7f). Reserved.
+ * Group2 (0x80 - 0x9f). Reserved.
+ * Group2 (0xa0 - 0xbf). Reserved.
+ * Group6 (0xc0 - 0xdf). Vendor Unique
+ * Group7 (0xe0 - 0xff). Vendor Unique
+ */
+
+/*
+ * Scsi Group0 commands all are 6 bytes and have a format according to
+ * struct ScsiGroup0Cmd.
+ */
+#define SCSI_TEST_UNIT_READY 0x00
+#define SCSI_REZERO_UNIT 0x01
+#define SCSI_REWIND 0x01
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_FORMAT_UNIT 0x04
+#define SCSI_READ_BLOCK_LIMITS 0x05
+#define SCSI_REASSIGN_BLOCKS 0x07
+#define SCSI_READ 0x08
+#define SCSI_WRITE 0x0a
+#define SCSI_SEEK 0x0b
+#define SCSI_TRACK_SELECT 0x0b
+#define SCSI_READ_REVERSE 0x0f
+#define SCSI_WRITE_EOF 0x10
+#define SCSI_SPACE 0x11
+#define SCSI_INQUIRY 0x12
+#define SCSI_VERIFY 0x13
+#define SCSI_READ_BUFFER 0x14
+#define SCSI_MODE_SELECT 0x15
+#define SCSI_RESERVE_UNIT 0x16
+#define SCSI_RELEASE_UNIT 0x17
+#define SCSI_COPY 0x18
+#define SCSI_ERASE_TAPE 0x19
+#define SCSI_MODE_SENSE 0x1a
+#define SCSI_START_STOP 0x1b
+#define SCSI_LOAD_UNLOAD 0x1b
+#define SCSI_RECV_DIAG_RESULTS 0x1c
+#define SCSI_SEND_DIAGNOSTIC 0x1d
+#define SCSI_PREVENT_ALLOW 0x1e
+
+/*
+ * Group1 commands are all 10 bytes and have a format according to
+ * struct ScsiGroup1Cmd.
+ */
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ_EXT 0x28
+#define SCSI_WRITE_EXT 0x2a
+#define SCSI_SEEK_EXT 0x2b
+#define SCSI_WRITE_VERIFY 0x2e
+#define SCSI_VERIFY_EXT 0x2f
+#define SCSI_SEARCH_HIGH 0x30
+#define SCSI_SEARCH_EQUAL 0x31
+#define SCSI_SEARCH_LOW 0x32
+#define SCSI_SET_LIMITS 0x33
+#define SCSI_COMPARE 0x39
+#define SCSI_COPY_VERIFY 0x3a
+
+/*
+ * Control byte flags for Group0 and Group1 commands.
+ *
+ * SCSI_CTRL_LINK - This is used to prevent a bus free phase between commands.
+ * If the command terminates successfully, a SCSI_LINKED_CMD_COMPLETE
+ * message is returned instead of the normal SCSI_COMMAND_COMPLETE message. * The last command in a chain should not have this bit set
+ * (and consequently gets a normal SCSI_COMMAND_COMPLETE message).
+ * SCSI_CTRL_LINK_FLAG - This bit should only set when SCSI_CTRL_LINK is set and
+ * causes a SCSI_LINKED_FLAGED_CMD_COMPLETE to be returned instead of
+ * a SCSI_LINKED_CMD_COMPLETE.
+ */
+#define SCSI_CTRL_LINK 0x01 /* Link commands (no bus free phase) */
+#define SCSI_CTRL_LINK_INTR 0x02 /* Interrupt after linked command */
+
+/*
+ * The standard group0 6-byte SCSI control block. Note that the
+ * fields between highAddr and blockCount inclusive are command dependent.
+ * The definitions Addr and BlockCount cover most of the commands we will
+ * use.
+ */
+typedef struct ScsiGroup0Cmd {
+ u_char command; /* command code, defined below. The
+ * upper three bits of this are zero
+ * to indicate the control block is
+ * only 6 bytes long */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+ u_char highAddr :5; /* High bits of address */
+#else
+ u_char highAddr :5; /* High bits of address */
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+#endif
+ u_char midAddr; /* Middle bits of address */
+ u_char lowAddr; /* Low bits of address */
+ u_char blockCount; /* Blocks to transfer */
+ u_char control; /* See flags for common bits */
+} ScsiGroup0Cmd;
+
+/*
+ * Format of a SCSI_START_STOP command. This is a group 0 command, but
+ * the command contents are different.
+ */
+typedef struct ScsiStartStopCmd {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char command; /* command code, defined below. The
+ * upper three bits of this are zero
+ * to indicate the control block is
+ * only 6 bytes long */
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+ u_char pad1 :4; /* Reserved */
+ u_char immed :1; /* Immediate status bit */
+ u_char pad2; /* Reserved */
+ u_char pad3; /* Reserved */
+ u_char pad4 :6; /* Reserved */
+ u_char loadEject :1; /* Load or eject medium */
+ u_char start :1; /* Start or stop medium */
+ u_char control; /* See flags for common bits */
+#else
+ u_char command; /* command code, defined below. The
+ * upper three bits of this are zero
+ * to indicate the control block is
+ * only 6 bytes long */
+ u_char immed :1; /* Immediate status bit */
+ u_char pad1 :4; /* Reserved */
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+ u_char pad2; /* Reserved */
+ u_char pad3; /* Reserved */
+ u_char start :1; /* Start or stop medium */
+ u_char loadEject :1; /* Load or eject medium */
+ u_char pad4 :6; /* Reserved */
+ u_char control; /* See flags for common bits */
+#endif
+} ScsiStartStopCmd;
+
+/*
+ * The standard group1 10-byte SCSI control block. Note that the
+ * fields between highAddr and blockCount inclusive are command dependent.
+ * The definitions Addr and BlockCount cover most of the commands we will
+ * use.
+ */
+typedef struct ScsiGroup1Cmd {
+ u_char command; /* command code, defined below. The
+ * upper three bits of this are zero
+ * to indicate the control block is
+ * only 6 bytes long */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+ u_char pad1 :5; /* Reserved */
+#else
+ u_char pad1 :5; /* Reserved */
+ u_char unitNumber :3; /* Logical Unit (LUN) to which to
+ * pass the command. The device
+ * has already been selected using
+ * the "targetID" bit. */
+#endif
+ u_char highAddr; /* High bits of address */
+ u_char midHighAddr; /* Middle high bits of address */
+ u_char midLowAddr; /* Middle low bits of address */
+ u_char lowAddr; /* Low bits of address */
+ u_char pad2; /* Reserved */
+ u_char highBlockCount; /* High bits of blocks to transfer */
+ u_char lowBlockCount; /* Low bits of blocks to transfer */
+ u_char control; /* See flags for common bits */
+} ScsiGroup1Cmd;
+
+/*
+ * SCSI status completion information.
+ * This is returned by the device when a command completes.
+ */
+#define SCSI_STATUS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define SCSI_STATUS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define SCSI_STATUS_BUSY 0x08
+#define SCSI_STATUS_INTERMED 0x10 /* Intermediate status sent */
+#define SCSI_STATUS_EXT 0x80 /* Extended status valid */
+
+/*
+ * Sense information provided after some errors. This is divided into
+ * two kinds, classes 0-6, and class 7. This is 30 bytes big to allow
+ * for the drive specific sense bytes that follow the standard 4 byte header.
+ *
+ * For extended sense, this buffer may be cast into another type. Also
+ * The actual size of the sense data returned is used to detect what
+ * kind of tape drive is out there. Kludgy, but true.
+ */
+typedef struct ScsiClass0Sense {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char valid :1; /* Sense data is valid */
+ u_char error :7; /* 3 bits class and 4 bits code */
+#else
+ u_char error :7; /* 3 bits class and 4 bits code */
+ u_char valid :1; /* Sense data is valid */
+#endif
+ u_char highAddr; /* High byte of block address */
+ u_char midAddr; /* Middle byte of block address */
+ u_char lowAddr; /* Low byte of block address */
+ u_char sense[26]; /* Target specific sense data */
+} ScsiClass0Sense;
+
+/*
+ * Definitions for errors in the sense data. The error field is specified
+ * as a 3 bit class and 4 bit code, but it is easier to treat it as a
+ * single 7 bit field.
+ */
+#define SCSI_NO_SENSE_DATA 0x00
+#define SCSI_NOT_READY 0x04
+#define SCSI_NOT_LOADED 0x09
+#define SCSI_INSUF_CAPACITY 0x0a
+#define SCSI_HARD_DATA_ERROR 0x11
+#define SCSI_WRITE_PROTECT 0x17
+#define SCSI_CORRECTABLE_ERROR 0x18
+#define SCSI_FILE_MARK 0x1c
+#define SCSI_INVALID_COMMAND 0x20
+#define SCSI_UNIT_ATTENTION 0x30
+#define SCSI_END_OF_MEDIA 0x34
+
+/*
+ * The standard "extended" sense data returned by SCSI devices. This
+ * has an error field of 0x70, for a "class 7" error.
+ */
+typedef struct ScsiClass7Sense {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char valid :1; /* Sense data is valid */
+ u_char error7 :7; /* == 0x70 */
+ u_char pad1; /* Also "segment number" for copy */
+ u_char fileMark :1; /* File mark on device */
+ u_char endOfMedia :1; /* End of media reached */
+ u_char badBlockLen :1; /* Block length mis-match (Exabyte) */
+ u_char pad2 :1;
+ u_char key :4; /* Sense keys defined below */
+ u_char info1; /* Information byte 1 */
+ u_char info2; /* Information byte 2 */
+ u_char info3; /* Information byte 3 */
+ u_char info4; /* Information byte 4 */
+ u_char length; /* Number of additional info bytes */
+#else
+ u_char error7 :7; /* == 0x70 */
+ u_char valid :1; /* Sense data is valid */
+ u_char pad1; /* Also "segment number" for copy */
+ u_char key :4; /* Sense keys defined below */
+ u_char pad2 :1;
+ u_char badBlockLen :1; /* Block length mis-match (Exabyte) */
+ u_char endOfMedia :1; /* End of media reached */
+ u_char fileMark :1; /* File mark on device */
+ u_char info1; /* Information byte 1 */
+ u_char info2; /* Information byte 2 */
+ u_char info3; /* Information byte 3 */
+ u_char info4; /* Information byte 4 */
+ u_char length; /* Number of additional info bytes */
+#endif
+} ScsiClass7Sense; /* 8 Bytes */
+
+/*
+ * Key values for standardized sense class 7.
+ */
+#define SCSI_CLASS7_NO_SENSE 0
+#define SCSI_CLASS7_RECOVERABLE 1
+#define SCSI_CLASS7_NOT_READY 2
+#define SCSI_CLASS7_MEDIA_ERROR 3
+#define SCSI_CLASS7_HARDWARE_ERROR 4
+#define SCSI_CLASS7_ILLEGAL_REQUEST 5
+
+/*
+ * These seem to have different meanings to different vendors....
+ */
+#define SCSI_CLASS7_MEDIA_CHANGE 6
+#define SCSI_CLASS7_UNIT_ATTN 6
+
+#define SCSI_CLASS7_WRITE_PROTECT 7
+#define SCSI_CLASS7_BLANK_CHECK 8
+#define SCSI_CLASS7_VENDOR 9
+#define SCSI_CLASS7_POWER_UP_FAILURE 10
+#define SCSI_CLASS7_ABORT 11
+#define SCSI_CLASS7_EQUAL 12
+#define SCSI_CLASS7_OVERFLOW 13
+#define SCSI_CLASS7_RESERVED_14 14
+#define SCSI_CLASS7_RESERVED_15 15
+
+/*
+ * Data return by the SCSI inquiry command.
+ */
+typedef struct ScsiInquiryData {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char type; /* Peripheral Device type. See below. */
+ u_char rmb:1; /* Removable Medium bit. */
+ u_char qualifier:7; /* Device type qualifier. */
+ u_char version; /* Version info. */
+ u_char reserved:4; /* reserved. */
+ u_char format:4; /* Response format. */
+ u_char length; /* length of data returned. */
+ u_char reserved2[2]; /* Reserved */
+ u_char flags; /* SCSI II flags (see below) */
+ u_char vendorID[8]; /* Vendor ID (ASCII) */
+ u_char productID[16]; /* Product ID (ASCII) */
+ u_char revLevel[4]; /* Revision level (ASCII) */
+ u_char revData[8]; /* Revision data (ASCII) */
+#else
+ u_char type; /* Peripheral Device type. See below. */
+ u_char qualifier:7; /* Device type qualifier. */
+ u_char rmb:1; /* Removable Medium bit. */
+ u_char version; /* Version info. */
+ u_char format:4; /* Response format. */
+ u_char reserved:4; /* reserved. */
+ u_char length; /* length of data returned. */
+ u_char reserved2[2]; /* Reserved */
+ u_char flags; /* SCSI II flags (see below) */
+ u_char vendorID[8]; /* Vendor ID (ASCII) */
+ u_char productID[16]; /* Product ID (ASCII) */
+ u_char revLevel[4]; /* Revision level (ASCII) */
+ u_char revData[8]; /* Revision data (ASCII) */
+#endif
+} ScsiInquiryData;
+
+/*
+ * The SCSI Peripheral type ID codes as return by the SCSI_INQUIRY command.
+ *
+ * SCSI_DISK_TYPE - Direct Access Device.
+ * SCSI_TAPE_TYPE - Sequential Access Device.
+ * SCSI_PRINTER_TYPE - Printer Device.
+ * SCSI_HOST_TYPE - Processor Device.
+ * SCSI_WORM_TYPE - Write-Once Read-Multiple Device.
+ * SCSI_ROM_TYPE - Read-Only Direct Access Device.
+ * SCSI_SCANNER_TYPE - Scanner device.
+ * SCSI_OPTICAL_MEM_TYPE - Optical memory device.
+ * SCSI_MEDIUM_CHANGER_TYPE - Medium changer device.
+ * SCSI_COMMUNICATIONS_TYPE - Communications device.
+ * SCSI_NODEVICE_TYPE - Logical Unit not present or implemented.
+ *
+ * Note that codes 0xa-0x7e are reserved and 0x80-0xff are vendor unique.
+ */
+#define SCSI_DISK_TYPE 0
+#define SCSI_TAPE_TYPE 1
+#define SCSI_PRINTER_TYPE 2
+#define SCSI_HOST_TYPE 3
+#define SCSI_WORM_TYPE 4
+#define SCSI_ROM_TYPE 5
+#define SCSI_SCANNER_TYPE 6
+#define SCSI_OPTICAL_MEM_TYPE 7
+#define SCSI_MEDIUM_CHANGER_TYPE 8
+#define SCSI_COMMUNICATIONS_TYPE 9
+#define SCSI_NODEVICE_TYPE 0x7f
+
+/*
+ * The SCSI I & II inquiry flags.
+ *
+ * SCSI_REL_ADR - Relative addressing supported.
+ * SCSI_WIDE_32 - 32 bit wide SCSI bus transfers supported.
+ * SCSI_WIDE_16 - 16 bit wide SCSI bus transfers supported.
+ * SCSI_SYNC - Synchronous data transfers supported.
+ * SCSI_LINKED - Linked commands supported.
+ * SCSI_CMD_QUEUE - Tagged command queuing supported.
+ * SCSI_SOFT_RESET - Soft RESET alternative suported.
+ */
+#define SCSI_REL_ADR 0x80
+#define SCSI_WIDE_32 0x40
+#define SCSI_WIDE_16 0x20
+#define SCSI_SYNC 0x10
+#define SCSI_LINKED 0x08
+#define SCSI_CMD_QUEUE 0x02
+#define SCSI_SOFT_RESET 0x01
+
+/*
+ * Standard header for SCSI_MODE_SENSE and SCSI_MODE_SELECT commands for tapes.
+ */
+typedef struct ScsiTapeModeSelectHdr {
+ u_char len; /* length */
+ u_char media; /* media type */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char writeprot:1; /* Write protected media */
+ u_char bufferedMode:3; /* Type of buffer to be done. */
+ u_char speed:4; /* Drive speed. */
+#else
+ u_char speed:4; /* Drive speed. */
+ u_char bufferedMode:3; /* Type of buffer to be done. */
+ u_char writeprot:1; /* Write protected media */
+#endif
+ u_char length; /* Block descriptor length. */
+ u_char density; /* tape density code */
+ u_char blocks_2; /* number of blocks (MSB) */
+ u_char blocks_1; /* number of blocks */
+ u_char blocks_0; /* number of blocks (LSB) */
+ u_char reserved; /* */
+ u_char block_size2; /* Tape block size (MSB) */
+ u_char block_size1; /* Tape block size */
+ u_char block_size0; /* Tape block size (LSB) */
+ u_char vendor[6]; /* vendor specific data */
+} ScsiTapeModeSelectHdr;
+
+/*
+ * Definitions of SCSI messages.
+ *
+ * SCSI_COMMAND_COMPLETE - After a command has completed, successfully
+ * or not, this is returned to the host from the target.
+ *
+ * SCSI_EXTENDED_MSG - Indicates that a multi-byte message is being sent.
+ *
+ * The following messages are used with connect/disconnect:
+ * SCSI_SAVE_DATA_POINTER - Sent from target to host to request saving
+ * of current DMA address and count. Indicates a pending dis-connect.
+ * SCSI_RESTORE_POINTER - Sent from the target to the host to request
+ * restoring pointers saved before a disconnect
+ * SCSI_DISCONNECT - Sent from the target to the host to disconnect.
+ * SCSI_ABORT - Sent from the host to the target to abort current request.
+ * SCSI_MESSAGE_REJECT - Indicates receipt, by either host or target, of
+ * an unimplemented message.
+ * SCSI_NO_OP - Sent from host to target if it has no real message to send.
+ * SCSI_MESSAGE_PARITY_ERROR - Sent from host to target on message parity error
+ * SCSI_BUS_RESET - Sent from host to target to reset all current I/O
+ *
+ * SCSI_IDENTIFY - The low order two bits of this message type indicate
+ * the Logical Unit of the Target which is requesting a reconnect.
+ * SCSI_DIS_REC_IDENTIFY - Sent from the host to a target to indicate
+ * is supports connect/dis-connect
+ *
+ */
+#define SCSI_COMMAND_COMPLETE 0x00
+#define SCSI_EXTENDED_MSG 0x01
+#define SCSI_SAVE_DATA_POINTER 0x02
+#define SCSI_RESTORE_POINTERS 0x03
+#define SCSI_DISCONNECT 0x04
+#define SCSI_ABORT 0x06
+#define SCSI_MESSAGE_REJECT 0x07
+#define SCSI_NO_OP 0x08
+#define SCSI_MESSAGE_PARITY_ERROR 0x09
+#define SCSI_LINKED_CMD_COMPLETE 0x0A
+#define SCSI_LINKED_FLAGED_CMD_COMPLETE 0x0B
+#define SCSI_BUS_RESET 0x0C
+
+#define SCSI_IDENTIFY 0x80
+#define SCSI_DIS_REC_IDENTIFY 0xc0
+
+/*
+ * Extended message types (2nd byte of SCSI_EXTENDED_MSG).
+ */
+#define SCSI_MODIFY_DATA_PTR 0x00
+#define SCSI_SYNCHRONOUS_XFER 0x01
+#define SCSI_EXTENDED_IDENTIFY 0x02 /* only in SCSI I */
+#define SCSI_WIDE_XFER 0x03
+
+/*
+ * Driver ioctl's for various scsi operations.
+ */
+#ifndef _IOCTL_
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Control for SCSI "format" mode.
+ *
+ * "Format" mode allows a privileged process to issue direct SCSI
+ * commands to a drive (it is intended primarily to allow on-line
+ * formatting). SDIOCSFORMAT with a non-zero arg will put the drive
+ * into format mode; a zero arg will take it out. When in format
+ * mode, only the process that issued the SDIOCFORMAT can read or
+ * write the drive.
+ *
+ * In format mode, process is expected to
+ * - do SDIOCSCSICOMMAND to supply cdb for next SCSI op
+ * - do read or write as appropriate for cdb
+ * - if i/o error, optionally do SDIOCSENSE to get completion
+ * status and sense data from last scsi operation.
+ */
+
+struct scsi_fmt_cdb {
+ int len; /* cdb length (in bytes) */
+ u_char cdb[28]; /* cdb to use on next read/write */
+};
+
+struct scsi_fmt_sense {
+ u_int status; /* completion status of last op */
+ u_char sense[32]; /* sense data (if any) from last op */
+};
+
+#define SDIOCSFORMAT _IOW('S', 0x1, int)
+#define SDIOCGFORMAT _IOR('S', 0x2, int)
+#define SDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb)
+#define SDIOCSENSE _IOR('S', 0x4, struct scsi_fmt_sense)
+
+#ifdef _KERNEL
+/*
+ * Routines.
+ */
+extern void scsiGroup0Cmd();
+extern void scsiGroup1Cmd();
+#endif /* _KERNEL */
+
+#endif /* _SCSI_H */