summaryrefslogtreecommitdiff
path: root/sys/arch/mvme68k/dev
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:44:53 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:44:53 +0000
commit49235ceee0c25492d4ca35194d7c72838a9ec284 (patch)
tree14f77677934d4f4cb9baa428691ace792fd0deed /sys/arch/mvme68k/dev
parentc9328c850e70436131e06a34f73c14cc230c18f9 (diff)
mvme68k port by me. some parts by dale rahn.
Diffstat (limited to 'sys/arch/mvme68k/dev')
-rw-r--r--sys/arch/mvme68k/dev/bug.c248
-rw-r--r--sys/arch/mvme68k/dev/bugtty.c496
-rw-r--r--sys/arch/mvme68k/dev/cd2400reg.h151
-rw-r--r--sys/arch/mvme68k/dev/cl.c1665
-rw-r--r--sys/arch/mvme68k/dev/cl.c.dale1666
-rw-r--r--sys/arch/mvme68k/dev/clock.c393
-rw-r--r--sys/arch/mvme68k/dev/dmavar.h47
-rw-r--r--sys/arch/mvme68k/dev/flash.c360
-rw-r--r--sys/arch/mvme68k/dev/flashreg.h63
-rw-r--r--sys/arch/mvme68k/dev/fooip.c123
-rw-r--r--sys/arch/mvme68k/dev/i82586.h286
-rw-r--r--sys/arch/mvme68k/dev/if_ie.c1958
-rw-r--r--sys/arch/mvme68k/dev/if_ie.h191
-rw-r--r--sys/arch/mvme68k/dev/ipic.c195
-rw-r--r--sys/arch/mvme68k/dev/ipicreg.h114
-rw-r--r--sys/arch/mvme68k/dev/lp.c144
-rw-r--r--sys/arch/mvme68k/dev/mc.c217
-rw-r--r--sys/arch/mvme68k/dev/mcreg.h164
-rw-r--r--sys/arch/mvme68k/dev/memc.c131
-rw-r--r--sys/arch/mvme68k/dev/memcreg.h106
-rw-r--r--sys/arch/mvme68k/dev/memdevs.c76
-rw-r--r--sys/arch/mvme68k/dev/nvram.c416
-rw-r--r--sys/arch/mvme68k/dev/nvramreg.h70
-rw-r--r--sys/arch/mvme68k/dev/pcctwo.c180
-rw-r--r--sys/arch/mvme68k/dev/pcctworeg.h150
-rw-r--r--sys/arch/mvme68k/dev/sbic.c2561
-rw-r--r--sys/arch/mvme68k/dev/sbicdma.c278
-rw-r--r--sys/arch/mvme68k/dev/sbicreg.h424
-rw-r--r--sys/arch/mvme68k/dev/sbicvar.h230
-rw-r--r--sys/arch/mvme68k/dev/siop.c1523
-rw-r--r--sys/arch/mvme68k/dev/siop_script.out175
-rw-r--r--sys/arch/mvme68k/dev/siop_script.ss205
-rw-r--r--sys/arch/mvme68k/dev/siopdma.c223
-rw-r--r--sys/arch/mvme68k/dev/siopreg.h336
-rw-r--r--sys/arch/mvme68k/dev/siopvar.h201
-rw-r--r--sys/arch/mvme68k/dev/sram.c231
-rw-r--r--sys/arch/mvme68k/dev/vme.c557
-rw-r--r--sys/arch/mvme68k/dev/vme.h325
-rw-r--r--sys/arch/mvme68k/dev/vmel.c173
-rw-r--r--sys/arch/mvme68k/dev/vmes.c173
40 files changed, 17225 insertions, 0 deletions
diff --git a/sys/arch/mvme68k/dev/bug.c b/sys/arch/mvme68k/dev/bug.c
new file mode 100644
index 00000000000..808cf6d4413
--- /dev/null
+++ b/sys/arch/mvme68k/dev/bug.c
@@ -0,0 +1,248 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn.
+ * 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * bug routines -- assumes that the necessary sections of memory
+ * are preserved.
+ */
+#include <sys/param.h>
+#include <machine/prom.h>
+
+/* flag to traphandler to signify prom call. presumes splhigh() */
+extern volatile int promcall;
+
+/* tty routines */
+char
+bug_inchr()
+{
+ int s = splhigh();
+ char a;
+
+ promcall = 1;
+ asm volatile ("subql #2,sp");
+ MVMEPROM_CALL(MVMEPROM_INCHR);
+ asm volatile ("nop");
+ asm volatile ("movb sp@+,%0" : "=d" (a));
+ promcall = 0;
+ splx(s);
+ return (a);
+}
+
+/* returns 0 if no characters ready to read */
+int
+bug_instat()
+{
+ int s = splhigh();
+ short ret;
+
+ promcall = 1;
+ MVMEPROM_CALL(MVMEPROM_INSTAT);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ splx(s);
+ return (!(ret & 0x4));
+}
+
+void
+bug_outchr(a)
+ char a;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movb %0,sp@-" :: "d" (a));
+ MVMEPROM_CALL(MVMEPROM_OUTCHR);
+ asm volatile ("nop");
+ promcall = 0;
+ splx(s);
+}
+
+void
+bug_outstr(pstrb, pstre)
+ char *pstrb;
+ char *pstre;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (pstre));
+ asm volatile ("movl %0,sp@-" :: "d" (pstrb));
+ MVMEPROM_CALL(MVMEPROM_OUTSTR);
+ promcall = 0;
+ splx(s);
+}
+
+void
+bug_outln(pstrb, pstre)
+ char *pstrb;
+ char *pstre;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (pstre));
+ asm volatile ("movl %0,sp@-" :: "d" (pstrb));
+ MVMEPROM_CALL(MVMEPROM_OUTSTRCRLF);
+ promcall = 0;
+ splx(s);
+}
+
+/* BUG - disk routines */
+
+#if 0
+/* returns 0: success, nonzero: error */
+u_int bug_drdcnt = 0;
+int
+bug_diskrd(arg)
+ bug_dskio *arg;
+{
+ int ret;
+
+ promcall = 1;
+ bug_drdcnt++;
+ asm volatile ("movl %0, sp@-" :: "d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKRD);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ return (!(ret & 0x4));
+}
+/* returns 0: success, nonzero: error */
+u_int bug_dwrcnt = 0;
+int
+bug_diskwr(arg)
+ bug_dskio *arg;
+{
+ int ret;
+
+ promcall = 1;
+ bug_dwrcnt ++;
+ asm volatile ("movl %0, sp@-" :: "d" (arg));
+ MVMEPROM_CALL(MVMEPROM_DSKWR);
+ asm volatile ("nop");
+ asm volatile ("movw ccr,%0" : "=d" (ret));
+ promcall = 0;
+ return (!(ret & 0x4));
+}
+
+bug_diskcfig()
+{
+}
+
+bug_diskfmt()
+{
+}
+
+bug_diskctrl()
+{
+}
+#endif
+
+/* BUG - timing routine */
+void
+bug_delay(delay_msec)
+ int delay_msec;
+{
+ int s = splhigh();
+
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "d" (delay_msec));
+ MVMEPROM_CALL(MVMEPROM_DELAY);
+ asm volatile ("nop");
+ promcall = 0;
+ splx(s);
+}
+
+/* BUG - return to bug routine */
+void
+bug_return()
+{
+ promcall = 1;
+ MVMEPROM_CALL(MVMEPROM_EXIT);
+ promcall = 0;
+ /*NOTREACHED*/
+}
+
+/* BUG - query board routines */
+struct bug_brdid *
+bug_brdid()
+{
+ struct bug_brdid *pbrd_id;
+
+ promcall = 1;
+ asm volatile ("clrl sp@-");
+ MVMEPROM_CALL(MVMEPROM_GETBRDID);
+ asm volatile ("movl sp@+,%0" : "=d" (pbrd_id):);
+ promcall = 0;
+ return (pbrd_id);
+}
+
+void
+bug_rtc_rd(ptime)
+ struct bug_time *ptime;
+{
+ promcall = 1;
+ asm volatile ("movl %0,sp@-" :: "a" (ptime));
+ MVMEPROM_CALL(MVMEPROM_RTC_RD);
+ asm volatile ("nop");
+ promcall = 0;
+}
+
+int asm_callbuf[4];
+
+void
+bug_stat()
+{
+ char val[] = "|/-\\";
+ static int cnt = 0;
+
+ bug_outchr('\b');
+ bug_outchr(val[cnt]);
+ cnt = (cnt + 1) % (sizeof(val) -1);
+}
+
+void
+asm_bug_stat()
+{
+ asm volatile ("movl a0,_asm_callbuf+0");
+ asm volatile ("movl a1,_asm_callbuf+4");
+ asm volatile ("movl d0,_asm_callbuf+8");
+ asm volatile ("movl d1,_asm_callbuf+12");
+
+ bug_stat();
+
+ asm volatile ("movl _asm_callbuf+0,a0");
+ asm volatile ("movl _asm_callbuf+4,a1");
+ asm volatile ("movl _asm_callbuf+8,d0");
+ asm volatile ("movl _asm_callbuf+12,d1");
+}
diff --git a/sys/arch/mvme68k/dev/bugtty.c b/sys/arch/mvme68k/dev/bugtty.c
new file mode 100644
index 00000000000..367db8f804b
--- /dev/null
+++ b/sys/arch/mvme68k/dev/bugtty.c
@@ -0,0 +1,496 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn.
+ * 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 Dale Rahn.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+#include <dev/cons.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/prom.h>
+
+#include "bugtty.h"
+
+int bugttymatch __P((struct device *parent, void *self, void *aux));
+void bugttyattach __P((struct device *parent, struct device *self, void *aux));
+
+struct cfdriver bugttycd = {
+ NULL, "bugtty", bugttymatch, bugttyattach,
+ DV_TTY, sizeof(struct device)
+};
+
+/* prototypes */
+int bugttycnprobe __P((struct consdev *cp));
+int bugttycninit __P((struct consdev *cp));
+int bugttycngetc __P((dev_t dev));
+int bugttycnputc __P((dev_t dev, char c));
+
+int bugttyopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyread __P((dev_t dev, struct uio *uio, int flag));
+int bugttywrite __P((dev_t dev, struct uio *uio, int flag));
+int bugttyioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int bugttystop __P((struct tty *tp, int flag));
+
+#define DIALOUT(x) ((x) & 0x80)
+#define SWFLAGS(dev) (bugttyswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
+#define BUGTTYUNIT(x) ((x) & 0x7f)
+
+#define BUGBUF 80
+char bugtty_ibuffer[BUGBUF+1];
+volatile char *pinchar = bugtty_ibuffer;
+char bug_obuffer[BUGBUF+1];
+
+struct tty *bugtty_tty[NBUGTTY];
+
+struct tty *
+bugttytty(dev)
+ dev_t dev;
+{
+ int unit;
+
+ unit = BUGTTYUNIT(dev);
+ if (unit >= NBUGTTY)
+ return (NULL);
+ return (bugtty_tty[unit]);
+}
+
+int
+bugttymatch(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ extern int needprom;
+
+ if (needprom == 0)
+ return (0);
+ return (1);
+}
+
+void
+bugttyattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ printf("\n");
+}
+
+void bugttyoutput __P((struct tty *tp));
+
+int bugttydefaultrate = TTYDEF_SPEED;
+int bugttyswflags;
+
+int
+bugttymctl(dev, bits, how)
+ dev_t dev;
+ int bits, how;
+{
+ static int settings = TIOCM_DTR | TIOCM_RTS |
+ TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
+ int s;
+
+ /*printf("mctl: dev %x, bits %x, how %x,",dev, bits, how);*/
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ break;
+ case DMBIC:
+ break;
+ case DMBIS:
+ break;
+ case DMGET:
+ break;
+ }
+ (void)splx(s);
+
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+
+ /* printf("retbits %x\n", bits); */
+ return (bits);
+}
+
+int
+bugttyopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int s, unit = BUGTTYUNIT(dev);
+ struct tty *tp;
+ extern int needprom;
+
+ if (needprom == 0)
+ return (ENODEV);
+
+ s = spltty();
+ if (bugtty_tty[unit]) {
+ tp = bugtty_tty[unit];
+ } else {
+ tp = bugtty_tty[unit] = ttymalloc();
+ }
+ tp->t_oproc = bugttyoutput;
+ tp->t_param = NULL;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = bugttydefaultrate;
+ }
+ /* bugtty does not have carrier */
+ tp->t_cflag |= CLOCAL;
+ /*
+ * do these all the time
+ */
+ if (bugttyswflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (bugttyswflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (bugttyswflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ bugttyparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+ /*
+ if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
+ (bugttymctl(dev, 0, DMGET) & TIOCM_CD))
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ */
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+/*
+ if (flag & O_NONBLOCK)
+ goto done;
+*/
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+bugttyparam()
+{
+ return (0);
+}
+
+void
+bugttyoutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt ;
+
+ /* only supports one unit */
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+ cnt = min(BUGBUF, cc);
+ cnt = q_to_b(&tp->t_outq, bug_obuffer, cnt);
+ bug_outstr(bug_obuffer, &bug_obuffer[cnt]);
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+bugttyclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ ttyclose(tp);
+#if 0
+ bugtty_tty[unit] = NULL;
+#endif
+ return (0);
+}
+
+int
+bugttyread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp;
+
+ if ((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+#if 1
+/* only to be called at splclk() */
+bugtty_chkinput()
+{
+ struct tty *tp;
+
+ tp = bugtty_tty[0]; /* Kinda ugly hack */
+ if (tp == NULL )
+ return;
+
+ if (bug_instat()) {
+ while (bug_instat()) {
+ u_char c = bug_inchr() & 0xff;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+}
+#endif
+
+int
+bugttywrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+#if 0
+ /* bypass tty output routines. */
+ int i, cnt, s;
+ int oldoff;
+
+ s = spltty();
+ oldoff = uio->uio_offset;
+ do {
+ uiomove(bug_obuffer, BUGBUF, uio);
+ bug_outstr(bug_obuffer, &bug_obuffer[uio->uio_offset - oldoff]);
+ oldoff = uio->uio_offset;
+ } while (uio->uio_resid != 0);
+ splx(s);
+
+ return (0);
+#else
+ struct tty *tp;
+ if((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+#endif
+}
+
+int
+bugttyioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+ int error;
+
+ if (!tp)
+ return (ENXIO);
+
+ 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:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) bugttymctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) bugttymctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) bugttymctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = bugttymctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = SWFLAGS(dev);
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ bugttyswflags = *(int *)data;
+ bugttyswflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+bugttystop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * bugtty is the last possible choice for a console device.
+ */
+int
+bugttycnprobe(cp)
+ struct consdev *cp;
+{
+ int maj;
+ extern int needprom;
+
+ if (needprom == 0) {
+ cp->cn_pri = CN_DEAD;
+ return (0);
+ }
+
+ switch (cputyp) {
+ case CPU_147:
+ case CPU_162:
+ cp->cn_pri = CN_NORMAL;
+ return (0);
+ default:
+ break;
+ }
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == bugttyopen)
+ break;
+
+ cp->cn_dev = makedev(maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+bugttycninit(cp)
+ struct consdev *cp;
+{
+}
+
+int
+bugttycngetc(dev)
+ dev_t dev;
+{
+ return (bug_inchr());
+}
+
+int
+bugttycnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ if (c == '\n')
+ bug_outchr('\r');
+ bug_outchr(c);
+}
diff --git a/sys/arch/mvme68k/dev/cd2400reg.h b/sys/arch/mvme68k/dev/cd2400reg.h
new file mode 100644
index 00000000000..d42fe00c7b2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cd2400reg.h
@@ -0,0 +1,151 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * Memory map for CL-CD2400 (CD2401)
+ * NOTE: intel addresses are different than motorola addresss
+ * do we want both here (really is based on endian)
+ * or do we want to put these in a carefully packed structure?
+ */
+
+/* these are mot addresses */
+/* global registers */
+#define CD2400_GFRCR 0x81
+#define CD2400_CAR 0xee
+
+/* option registers */
+#define CD2400_CMR 0x1b
+#define CD2400_COR1 0x10
+#define CD2400_COR2 0x17
+#define CD2400_COR3 0x16
+#define CD2400_COR4 0x15
+#define CD2400_COR5 0x14
+#define CD2400_COR6 0x18
+#define CD2400_COR7 0x07
+#define CD2400_SCHR1 0x1f /* async */
+#define CD2400_SCHR2 0x1e /* async */
+#define CD2400_SCHR3 0x1d /* async */
+#define CD2400_SCHR4 0x1c /* async */
+#define CD2400_SCRl 0x23 /* async */
+#define CD2400_SCRh 0x22 /* async */
+#define CD2400_LNXT 0x2e
+#define CD2400_RFAR1 0x1f /* sync */
+#define CD2400_RFAR2 0x1e /* sync */
+#define CD2400_RFAR3 0x1d /* sync */
+#define CD2400_RFAR4 0x1c /* sync */
+
+#define CD2400_CPSR 0xd6
+
+/* bit rate and clock option registers */
+#define CD2400_RBPR 0xcb
+#define CD2400_RCOR 0xc8
+#define CD2400_TBPR 0xc3
+#define CD2400_TCOR 0xc0
+
+/* channel command and status registers */
+#define CD2400_CCR 0x13
+#define CD2400_STCR 0x12 /* sync */
+#define CD2400_CSR 0x1a
+#define CD2400_MSVR_RTS 0xde
+#define CD2400_MSVR_DTR 0xdf
+
+/* interrupt registers */
+#define CD2400_LIVR 0x09
+#define CD2400_IER 0x11
+#define CD2400_LICR 0x26
+#define CD2400_STK 0xe2
+
+/* receive interrupt registers */
+#define CD2400_RPILR 0xe1
+#define CD2400_RIR 0xeD
+#define CD2400_RISR 0x88
+#define CD2400_RISRl 0x89
+#define CD2400_RISRh 0x88
+#define CD2400_RFOC 0x30
+#define CD2400_RDR 0xf8
+#define CD2400_REOIR 0x84
+
+/* transmit interrupt registers */
+#define CD2400_TPILR 0xe0
+#define CD2400_TIR 0xec
+#define CD2400_TISR 0x8a
+#define CD2400_TFTC 0x80
+#define CD2400_TDR 0xf8
+#define CD2400_TEOIR 0x85
+
+/* modem interrrupt registers */
+#define CD2400_MPILR 0xe3
+#define CD2400_MIR 0xef
+#define CD2400_MISR 0x8B
+#define CD2400_MEOIR 0x86
+
+/* dma registers */
+#define CD2400_DMR 0xf6
+#define CD2400_BERCNT 0x8e
+#define CD2400_DMABSTS 0x19
+
+/* dma receive registers - leave these long names, as in manual */
+#define CD2400_ARBADRL 0x42
+#define CD2400_ARBADRU 0x40
+#define CD2400_BRBADRL 0x46
+#define CD2400_BRBADRU 0x44
+#define CD2400_ARBCNT 0x4a
+#define CD2400_BRBCNT 0x48
+#define CD2400_ARBSTS 0x4f
+#define CD2400_BRBSTS 0x4e
+#define CD2400_RCBADRL 0x3e
+#define CD2400_RCBADRU 0x3c
+
+/* dma transmit registers */
+#define CD2400_ATBADRL 0x52
+#define CD2400_ATBADRU 0x50
+#define CD2400_BTBADRL 0x56
+#define CD2400_BTBADRU 0x54
+#define CD2400_ATBCNT 0x5a
+#define CD2400_BTBCNT 0x58
+#define CD2400_ATBSTS 0x5f
+#define CD2400_BTBSTS 0x5e
+#define CD2400_RTBADRL 0x3a
+#define CD2400_RTBADRU 0x38
+
+/* timer registers */
+#define CD2400_TPR 0xda
+#define CD2400_RTPR 0x24 /* async */
+#define CD2400_RTPRl 0x25 /* async */
+#define CD2400_RTPRh 0x24 /* async */
+#define CD2400_GT1 0x2a /* sync */
+#define CD2400_GT1l 0x2b /* sync */
+#define CD2400_GT1h 0x2a /* sync */
+#define CD2400_GT2 0x29 /* sync */
+#define CD2400_TTR 0x29 /* async */
+
+
+#define CD2400_SIZE 0x200
diff --git a/sys/arch/mvme68k/dev/cl.c b/sys/arch/mvme68k/dev/cl.c
new file mode 100644
index 00000000000..38f0469f53c
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cl.c
@@ -0,0 +1,1665 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+/* #include <sys/queue.h> */
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme68k/dev/cd2400reg.h>
+#include <sys/syslog.h>
+#include "cl.h"
+
+#include "pcctwo.h"
+
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+/* min timeout 0xa, what is a good value */
+#define CL_TIMEOUT 0x10
+#define CL_FIFO_MAX 0x10
+#define CL_FIFO_CNT 0xc
+#define CL_RX_TIMEOUT 0x10
+
+#define CL_DMAMODE 0x1
+#define CL_INTRMODE 0x0
+
+struct cl_cons {
+ u_char *cl_paddr;
+ volatile u_char *cl_vaddr;
+ volatile struct pcctworeg *pcctwoaddr;
+ u_char channel;
+} cl_cons;
+
+struct cl_info {
+ struct tty *tty;
+ u_char cl_swflags;
+ u_char cl_softchar;
+ u_char cl_consio;
+ u_char cl_speed;
+ u_char cl_parstop; /* parity, stop bits. */
+ u_char cl_rxmode;
+ u_char cl_txmode;
+ u_char cl_clen;
+ u_char cl_parity;
+ u_char transmitting;
+ u_long txcnt;
+ u_long rxcnt;
+};
+
+#define CLCD_PORTS_PER_CHIP 4
+struct clsoftc {
+ struct device sc_dev;
+ struct evcnt sc_txintrcnt;
+ struct evcnt sc_rxintrcnt;
+ struct evcnt sc_mxintrcnt;
+ time_t sc_rotime; /* time of last ring overrun */
+ time_t sc_fotime; /* time of last fifo overrun */
+ volatile u_char *vbase;
+ struct cl_info sc_cl[CLCD_PORTS_PER_CHIP];
+ struct intrhand sc_ih_e;
+ struct intrhand sc_ih_m;
+ struct intrhand sc_ih_t;
+ struct intrhand sc_ih_r;
+ struct pcctworeg *sc_pcctwo;
+ int sc_flags;
+};
+
+struct {
+ u_int speed;
+ u_char divisor;
+ u_char clock;
+ u_char rx_timeout;
+} cl_clocks[] = {
+ { 64000, 0x26, 0, 0x01},
+ { 56000, 0x2c, 0, 0x01},
+ { 38400, 0x40, 0, 0x01},
+ { 19200, 0x81, 0, 0x02},
+ { 9600, 0x40, 1, 0x04},
+ { 7200, 0x56, 1, 0x04},
+ { 4800, 0x81, 1, 0x08},
+ { 3600, 0xad, 1, 0x08},
+ { 2400, 0x40, 2, 0x10},
+ { 1200, 0x81, 2, 0x20},
+ { 600, 0x40, 3, 0x40},
+ { 300, 0x81, 3, 0x80},
+ { 150, 0x40, 3, 0x80},
+ { 110, 0x58, 4, 0xff},
+ { 50, 0xC2, 4, 0xff},
+ { 0, 0x00, 0, 0},
+};
+
+/* prototypes */
+int clcnprobe __P((struct consdev *cp));
+int clcninit __P((struct consdev *cp));
+int clcngetc __P((dev_t dev));
+int clcnputc __P((dev_t dev, char c));
+u_char cl_clkdiv __P((int speed));
+u_char cl_clknum __P((int speed));
+u_char cl_clkrxtimeout __P((int speed));
+void clstart __P((struct tty *tp));
+void cl_unblock __P((struct tty *tp));
+int clccparam __P((struct clsoftc *sc, struct termios *par, int channel));
+
+int clparam __P((struct tty *tp, struct termios *t));
+int cl_mintr __P((struct clsoftc *sc));
+int cl_txintr __P((struct clsoftc *sc));
+int cl_rxintr __P((struct clsoftc *sc));
+void cl_overflow __P((struct clsoftc *sc, int channel, long *ptime, char *msg));
+void cl_parity __P((struct clsoftc *sc, int channel));
+void cl_frame __P((struct clsoftc *sc, int channel));
+void cl_break __P(( struct clsoftc *sc, int channel));
+int clmctl __P((dev_t dev, int bits, int how));
+void cl_dumpport __P((int channel));
+
+int clprobe __P((struct device *parent, void *self, void *aux));
+void clattach __P((struct device *parent, struct device *self, void *aux));
+
+int clopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int clclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int clread __P((dev_t dev, struct uio *uio, int flag));
+int clwrite __P((dev_t dev, struct uio *uio, int flag));
+int clioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int clstop __P((struct tty *tp, int flag));
+
+static void cl_initchannel __P((struct clsoftc *sc, int channel));
+static void clputc __P((struct clsoftc *sc, int unit, char c));
+static u_char clgetc __P((struct clsoftc *sc, int *channel));
+static void cloutput __P((struct tty *tp));
+
+struct cfdriver clcd = {
+ NULL, "cl", clprobe, clattach, DV_TTY, sizeof(struct clsoftc), 0
+};
+
+#define CLCDBUF 80
+char cltty_ibuffer[CLCDBUF+1];
+char cl_obuffer[CLCDBUF+1];
+
+int dopoll = 1;
+
+#define CL_UNIT(x) (minor(x) >> 2)
+#define CL_CHANNEL(x) (minor(x) & 3)
+#define CL_TTY(x) (minor(x))
+
+extern int cputyp;
+
+struct tty *
+cltty(dev)
+ dev_t dev;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ channel = CL_CHANNEL(dev);
+ return (sc->sc_cl[channel].tty);
+}
+
+/*
+ * probing onboard 166/167/187 CL-cd2400
+ * should be previously configured,
+ * we can check the value before resetting the chip
+ */
+int
+clprobe(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ volatile u_char *cd_base;
+ struct cfdata *cf = self;
+ struct confargs *ca = aux;
+ int ret;
+
+ if (cputyp != CPU_167 && cputyp != CPU_166)
+ return (0);
+
+ cd_base = ca->ca_vaddr;
+#if 0
+ return (!badvaddr(&cd_base[CD2400_GFRCR], 1));
+#endif
+ return (ret);
+}
+
+void
+clattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clsoftc *sc = (struct clsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+#if 0
+ int size = (CD2400_SIZE + PGOFSET) & ~PGOFSET;
+#endif
+
+ sc->vbase = ca->ca_vaddr;
+ sc->sc_pcctwo = ca->ca_master;
+
+ if (ca->ca_paddr == cl_cons.cl_paddr) {
+ /* if this device is configured as console,
+ * line cl_cons.channel is the console */
+ sc->sc_cl[cl_cons.channel].cl_consio = 1;
+ printf(" console");
+ } else {
+ /* reset chip only if we are not console device */
+ /* wait for GFRCR */
+ }
+ /* set up global registers */
+ sc->vbase[CD2400_TPR] = CL_TIMEOUT;
+ sc->vbase[CD2400_RPILR] = 0x03;
+ sc->vbase[CD2400_TPILR] = 0x02;
+ sc->vbase[CD2400_MPILR] = 0x01;
+
+ for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) {
+#if 0
+ sc->sc_cl[i].cl_rxmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x01));
+ sc->sc_cl[i].cl_txmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x02));
+ sc->sc_cl[i].cl_softchar =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x04));
+#endif
+ cl_initchannel(sc, i);
+ }
+ /* enable interrupts */
+ sc->sc_ih_e.ih_fn = cl_rxintr;
+ sc->sc_ih_e.ih_arg = sc;
+ sc->sc_ih_e.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_e.ih_wantframe = 0;
+
+ sc->sc_ih_m.ih_fn = cl_mintr;
+ sc->sc_ih_m.ih_arg = sc;
+ sc->sc_ih_m.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_m.ih_wantframe = 0;
+
+ sc->sc_ih_t.ih_fn = cl_txintr;
+ sc->sc_ih_t.ih_arg = sc;
+ sc->sc_ih_t.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_t.ih_wantframe = 0;
+
+ sc->sc_ih_r.ih_fn = cl_rxintr;
+ sc->sc_ih_r.ih_arg = sc;
+ sc->sc_ih_r.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_r.ih_wantframe = 0;
+ switch (ca->ca_bustype) {
+ case BUS_PCCTWO:
+ dopoll = 0;
+ pcctwointr_establish(PCC2V_SCC_RXE, &sc->sc_ih_e);
+ pcctwointr_establish(PCC2V_SCC_M, &sc->sc_ih_m);
+ pcctwointr_establish(PCC2V_SCC_TX, &sc->sc_ih_t);
+ pcctwointr_establish(PCC2V_SCC_RX, &sc->sc_ih_r);
+ sc->sc_pcctwo = (void *)ca->ca_master;
+ sc->sc_pcctwo->pcc2_sccerr = 0x01; /* clear errors */
+
+ /* enable all interrupts at ca_ipl */
+ sc->sc_pcctwo->pcc2_sccirq = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_scctx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_sccrx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ break;
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt);
+ printf("\n");
+}
+
+static void
+cl_initchannel(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ int s;
+ volatile u_char *cd_base = sc->vbase;
+
+ /* set up option registers */
+ sc->sc_cl[channel].tty = NULL;
+ s = splhigh();
+ cd_base[CD2400_CAR] = (char)channel;
+ /* async, do we want to try DMA at some point? */
+ cd_base[CD2400_LIVR] = PCC2_VECBASE + 0xc;/* set vector base at 5C */
+ cd_base[CD2400_IER] = 0x88; /* should change XXX */
+ cd_base[CD2400_LICR] = 0x00; /* will change if DMA support XXX */
+ /* if the port is not the console */
+ if (sc->sc_cl[channel].cl_consio != 1) {
+ cd_base[CD2400_CMR] = 0x02;
+ cd_base[CD2400_COR1] = 0x17;
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02;
+ cd_base[CD2400_COR4] = 0xec;
+ cd_base[CD2400_COR5] = 0xec;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_RBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_RCOR] = 0x01;
+ cd_base[CD2400_TBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_TCOR] = 0x01 << 5;
+ /* console port should be 0x88 already */
+ cd_base[CD2400_MSVR_RTS] = 0x00;
+ cd_base[CD2400_MSVR_DTR] = 0x00;
+ cd_base[CD2400_RTPRl] = CL_RX_TIMEOUT;
+ cd_base[CD2400_RTPRh] = 0x00;
+ }
+ splx(s);
+}
+
+int cldefaultrate = TTYDEF_SPEED;
+
+int clmctl(dev, bits, how)
+ dev_t dev;
+ int bits;
+ int how;
+{
+ struct clsoftc *sc = (struct clsoftc *)clcd.cd_devs[CL_UNIT(dev)];
+ int s;
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ } else {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ } else {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIC:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIS:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+ {
+ u_char msvr = sc->vbase[CD2400_MSVR_RTS];
+
+ if (msvr & 0x80)
+ bits |= TIOCM_DSR;
+ if (msvr & 0x40)
+ bits |= TIOCM_CD;
+ if (msvr & 0x20)
+ bits |= TIOCM_CTS;
+ if (msvr & 0x10)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x02)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x01)
+ bits |= TIOCM_RTS;
+ }
+ break;
+ }
+ (void)splx(s);
+#if 0
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+#endif
+
+ /*
+ printf("retbits %x\n", bits);
+ */
+ return (bits);
+}
+
+int
+clopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int s, unit, channel;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ struct tty *tp;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ s = spltty();
+ if (cl->tty) {
+ tp = cl->tty;
+ } else {
+ tp = cl->tty = ttymalloc();
+ }
+ tp->t_oproc = clstart;
+ tp->t_param = clparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = cldefaultrate;
+ }
+ /*
+ * do these all the time
+ */
+ if (cl->cl_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (cl->cl_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (cl->cl_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ clparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+#ifdef XXX
+ if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) ||
+ (clmctl(dev, 0, DMGET) & TIOCM_CD)) {
+ tp->t_state |= TS_CARR_ON;
+ } else {
+ tp->t_state &= ~TS_CARR_ON;
+ }
+#endif
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+#ifdef XXX
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+ if (flag & O_NONBLOCK)
+ goto done;
+#endif
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+clparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+/*
+ t->c_ispeed = tp->t_ispeed;
+ t->c_ospeed = tp->t_ospeed;
+ t->c_cflag = tp->t_cflag;
+*/
+ clccparam(sc, t, channel);
+ s = spltty();
+ cl_unblock(tp);
+ splx(s);
+ return (0);
+}
+
+void
+cloutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt;
+ char *tptr;
+ int channel;
+ struct clsoftc *sc;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+ channel = CL_CHANNEL(dev);
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+/*XXX*/
+ cnt = min(CLCDBUF, cc);
+ cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt);
+ if (cnt == 0) {
+ break;
+ }
+ for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) {
+ clputc(sc, channel, *tptr);
+ }
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+clclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ int s;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (cl->cl_consio == 0 && (tp->t_cflag & HUPCL) != 0) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+
+ splx(s);
+ ttyclose(tp);
+
+#if 0
+ cl->tty = NULL;
+#endif
+#if 0
+ cl_dumpport(channel);
+#endif
+ return (0);
+}
+
+int
+clread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+clwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+int
+clioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+
+ 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:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) clmctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) clmctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) clmctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = clmctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = cl->cl_swflags;
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+clstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+clcnprobe(cp)
+ struct consdev *cp;
+{
+ /* always there ? */
+ /* serial major */
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == clopen)
+ break;
+ cp->cn_dev = makedev (maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+clcninit(cp)
+ struct consdev *cp;
+{
+#ifdef MAP_DOES_WORK
+ int size = (0x1ff + PGOFSET) & ~PGOFSET;
+ int pcc2_size = (0x3C + PGOFSET) & ~PGOFSET;
+#endif
+ volatile u_char *cd_base;
+
+ cl_cons.cl_paddr = (void *)0xfff45000;
+#ifdef MAP_DOES_WORK
+ cl_cons.cl_vaddr = mapiodev(cl_cons.cl_paddr, size);
+ cd_pcc2_base = mapiodev(0xfff42000, pcc2_size);
+#else
+ cl_cons.cl_vaddr = cl_cons.cl_paddr;
+ cl_cons.pcctwoaddr = (void *)0xfff42000;
+#endif
+ cd_base = cl_cons.cl_vaddr;
+ /* reset the chip? */
+#ifdef CLCD_DO_RESET
+#endif
+#ifdef NEW_CLCD_STRUCT
+ /* set up globals */
+ cl->tftc = 0x10;
+ cl->tpr = CL_TIMEOUT; /* is this correct?? */
+ cl->rpilr = 0x03;
+ cl->tpilr = 0x02;
+ cl->mpilr = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cl->car = 0x00;
+ cl->cor1 = 0x17; /* No parity, ignore parity, 8 bit char */
+ cl->cor2 = 0x00;
+ cl->cor3 = 0x02; /* 1 stop bit */
+ cl->cor4 = 0x00;
+ cl->cor5 = 0x00;
+ cl->cor6 = 0x00;
+ cl->cor7 = 0x00;
+ cl->schr1 = 0x00;
+ cl->schr2 = 0x00;
+ cl->schr3 = 0x00;
+ cl->schr4 = 0x00;
+ cl->scrl = 0x00;
+ cl->scrh = 0x00;
+ cl->lnxt = 0x00;
+ cl->cpsr = 0x00;
+#else
+ /* set up globals */
+#ifdef NOT_ALREADY_SETUP
+ cd_base[CD2400_TFTC] = 0x10;
+ cd_base[CD2400_TPR] = CL_TIMEOUT; /* is this correct?? */
+ cd_base[CD2400_RPILR] = 0x03;
+ cd_base[CD2400_TPILR] = 0x02;
+ cd_base[CD2400_MPILR] = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cd_base[CD2400_CAR] = 0x00;
+ cd_base[CD2400_COR1] = 0x17; /* No parity, ignore parity, 8 bit char */
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02; /* 1 stop bit */
+ cd_base[CD2400_COR4] = 0x00;
+ cd_base[CD2400_COR5] = 0x00;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_CPSR] = 0x00;
+#endif
+#endif
+ return (0);
+}
+
+int
+cl_instat(sc)
+ struct clsoftc *sc;
+{
+ volatile u_char *cd_base;
+
+ if ( NULL == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+ return (cd_base[CD2400_RIR] & 0x80);
+}
+
+int
+clcngetc(dev)
+ dev_t dev;
+{
+ u_char val, reoir, licr, isrl, data, status, fifo_cnt;
+ int got_char = 0;
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ volatile struct pcctworeg *pcc2_base = cl_cons.pcctwoaddr;
+
+ while (got_char == 0) {
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ continue;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ if (((licr >> 2) & 0x3) == 0) {
+ /* is the interrupt for us (port 0) */
+ /* the character is for us. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ data = cd_base[CD2400_RDR];
+ got_char = 1;
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ }
+
+ }
+ return (data);
+}
+
+int
+clcnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ /* is this the correct location for the cr -> cr/lf tranlation? */
+ if (c == '\n')
+ clputc(0, 0, '\r');
+
+ clputc(0, 0, c);
+ return (0);
+}
+
+clcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+ if (1 == on) {
+ /* enable polling */
+ } else {
+ /* disable polling */
+ }
+}
+
+static void
+clputc(sc, unit, c)
+ struct clsoftc *sc;
+ int unit;
+ char c;
+{
+ int s;
+ u_char schar;
+ u_char oldchannel;
+ volatile u_char *cd_base;
+ if (0 == sc) {
+ /* output on console */
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+#ifdef NEW_CLCD_STRUCT
+ /* should we disable, flush and all that goo? */
+ cl->car = unit;
+ schar = cl->schr3;
+ cl->schr3 = c;
+ cl->stcr = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cl->stcr) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ cl->schr3 = schar;
+#else
+if (unit == 0) {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ schar = cd_base[CD2400_SCHR3];
+ cd_base[CD2400_SCHR3] = c;
+ cd_base[CD2400_STCR] = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cd_base[CD2400_STCR]) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ DELAY(5);
+ cd_base[CD2400_SCHR3] = schar;
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+} else {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ if (cd_base[CD2400_TFTC] > 0) {
+ cd_base[CD2400_TDR] = c;
+ }
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+}
+#endif
+}
+
+/*
+#ifdef CLCD_DO_POLLED_INPUT
+*/
+#if 1
+void
+cl_chkinput()
+{
+ struct tty *tp;
+ int unit;
+ struct clsoftc *sc;
+ int channel;
+
+ if (dopoll == 0)
+ return;
+ for (unit = 0; unit < clcd.cd_ndevs; unit++) {
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ continue;
+ }
+ if (cl_instat(sc)) {
+ while (cl_instat(sc)){
+ int ch;
+ u_char c;
+ /*
+ *(pinchar++) = clcngetc();
+ */
+ ch = clgetc(sc, &channel) & 0xff;
+ c = ch;
+
+ tp = sc->sc_cl[channel].tty;
+ if (NULL != tp) {
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+ }
+}
+#endif
+
+static u_char
+clgetc(sc, channel)
+ struct clsoftc *sc;
+ int *channel;
+{
+ volatile u_char *cd_base;
+ volatile struct pcctworeg *pcc2_base;
+ u_char val, reoir, licr, isrl, fifo_cnt, data;
+
+ if (0 == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ pcc2_base = cl_cons.pcctwoaddr;
+ } else {
+ cd_base = sc->vbase;
+ pcc2_base = sc->sc_pcctwo;
+ }
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ return (0);
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ *channel = (licr >> 2) & 0x3;
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ if (fifo_cnt > 0) {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = 0;
+ cd_base[CD2400_TEOIR] = 0x08;
+ }
+ return (data);
+}
+
+int
+clccparam(sc, par, channel)
+ struct clsoftc *sc;
+ struct termios *par;
+ int channel;
+{
+ u_int divisor, clk, clen;
+ int s, imask, ints;
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (par->c_ospeed == 0) {
+ /* dont kill the console */
+ if (sc->sc_cl[channel].cl_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ sc->vbase[CD2400_MSVR_RTS] = 0x03;
+ sc->vbase[CD2400_MSVR_DTR] = 0x03;
+
+ divisor = cl_clkdiv(par->c_ospeed);
+ clk = cl_clknum(par->c_ospeed);
+ sc->vbase[CD2400_TBPR] = divisor;
+ sc->vbase[CD2400_TCOR] = clk << 5;
+ divisor = cl_clkdiv(par->c_ispeed);
+ clk = cl_clknum(par->c_ispeed);
+ sc->vbase[CD2400_RBPR] = divisor;
+ sc->vbase[CD2400_RCOR] = clk;
+ sc->vbase[CD2400_RTPRl] = cl_clkrxtimeout(par->c_ispeed);
+ sc->vbase[CD2400_RTPRh] = 0x00;
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ clen = 4; /* this is the mask for the chip. */
+ imask = 0x1F;
+ break;
+ case CS6:
+ clen = 5;
+ imask = 0x3F;
+ break;
+ case CS7:
+ clen = 6;
+ imask = 0x7F;
+ break;
+ default:
+ clen = 7;
+ imask = 0xFF;
+ }
+ sc->vbase[CD2400_COR3] = par->c_cflag & PARENB ? 4 : 2;
+
+ if (par->c_cflag & PARENB) {
+ if (par->c_cflag & PARODD) {
+ sc->vbase[CD2400_COR1] = 0xE0 | clen ; /* odd */
+ } else {
+ sc->vbase[CD2400_COR1] = 0x40 | clen ; /* even */
+ }
+ } else {
+ sc->vbase[CD2400_COR1] = 0x10 | clen; /* ignore parity */
+ }
+
+ if (sc->sc_cl[channel].cl_consio == 0 &&
+ (par->c_cflag & CREAD) == 0 ) {
+/*
+ sc->vbase[CD2400_CSR] = 0x08;
+*/
+ sc->vbase[CD2400_CCR] = 0x08;
+ } else {
+ sc->vbase[CD2400_CCR] = 0x0a;
+ }
+ ints = 0;
+#define SCC_DSR 0x80
+#define SCC_DCD 0x40
+#define SCC_CTS 0x20
+ if ((par->c_cflag & CLOCAL) == 0) {
+ ints |= SCC_DCD;
+ }
+ if ((par->c_cflag & CCTS_OFLOW) != 0) {
+ ints |= SCC_CTS;
+ }
+ if ((par->c_cflag & CRTSCTS) != 0) {
+ ints |= SCC_CTS;
+ }
+#ifdef DONT_LET_HARDWARE
+ if ((par->c_cflag & CCTS_IFLOW) != 0) {
+ ints |= SCC_DSR;
+ }
+#endif
+ sc->vbase[CD2400_COR4] = ints | CL_FIFO_CNT;
+ sc->vbase[CD2400_COR5] = ints | CL_FIFO_CNT;
+ return (imask);
+}
+
+static int clknum = 0;
+
+u_char
+cl_clkdiv(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].divisor);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].divisor);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].divisor);
+}
+
+u_char
+cl_clknum(speed)
+ int speed;
+{
+ int found = 0;
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].clock);
+ }
+ for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[clknum].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].clock);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].clock);
+}
+
+u_char
+cl_clkrxtimeout(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].rx_timeout);
+}
+
+void
+cl_unblock(tp)
+ struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ clstart(tp);
+}
+
+void
+clstart(tp)
+ struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct clsoftc *sc;
+ int channel, unit, s, cnt;
+
+ dev = tp->t_dev;
+ channel = CL_CHANNEL(dev);
+/* hack to test output on non console only */
+#if 0
+ if (channel == 0) {
+ cloutput(tp);
+ return;
+ }
+#endif
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+#if 0
+ if (sc->sc_cl[channel].transmitting == 1) {
+ /* i'm busy, go away, I will get to it later. */
+ splx(s);
+ return;
+ }
+ cnt = q_to_b(&tp->t_outq, &cbuf, 1);
+ if (cnt != 0) {
+ sc->sc_cl[channel].transmitting = 1;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_TDR] = cbuf;
+ } else {
+ sc->sc_cl[channel].transmitting = 0;
+ }
+#else
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) {
+ tp->t_state |= TS_BUSY;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_IER] = 0xb;
+ }
+#endif
+ splx(s);
+}
+
+int
+cl_mintr(sc)
+ struct clsoftc *sc;
+{
+ u_char mir, misr, msvr;
+ int channel;
+ struct tty *tp;
+
+ mir = sc->vbase[CD2400_MIR];
+ if ((mir & 0x40) == 0x0) {
+ /* only if intr is not shared? */
+ printf("cl_mintr extra intr\n");
+ return (0);
+ }
+ sc->sc_mxintrcnt.ev_count++;
+
+ channel = mir & 0x03;
+ misr = sc->vbase[CD2400_MISR];
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if (misr & 0x01) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 1 unexpected\n", channel);
+ }
+ if (misr & 0x02) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 2 unexpected\n", channel);
+ }
+ if (misr & 0x20) {
+ printf("cl_mintr: channel %x cts %x\n", channel,
+ (msvr & 0x20) != 0x0);
+ }
+ if (misr & 0x40) {
+ struct tty *tp = sc->sc_cl[channel].tty;
+
+ printf("cl_mintr: channel %x cd %x\n", channel,
+ (msvr & 0x40) != 0x0);
+ ttymodem(tp, (msvr & 0x40) != 0x0);
+ }
+ if (misr & 0x80) {
+ printf("cl_mintr: channel %x dsr %x\n", channel,
+ (msvr & 0x80) != 0x0);
+ }
+ sc->vbase[CD2400_MEOIR] = 0x00;
+ return (1);
+}
+
+int
+cl_txintr(sc)
+ struct clsoftc *sc;
+{
+ static empty = 0;
+ u_char tir, licr, teoir;
+ u_char max;
+ int channel;
+ struct tty *tp;
+ int cnt;
+ u_char buffer[CL_FIFO_MAX +1];
+ u_char *tptr;
+
+ tir = sc->vbase[CD2400_TIR];
+ if ((tir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_txintr extra intr\n");
+ return (0);
+ }
+ sc->sc_txintrcnt.ev_count++;
+
+ channel = tir & 0x03;
+ licr = sc->vbase[CD2400_LICR];
+
+ sc->sc_cl[channel].txcnt ++;
+
+ tp = sc->sc_cl[channel].tty;
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+ sc->vbase[CD2400_TEOIR] = 0x08;
+ return (1);
+ }
+ switch ((licr >> 4) & 0x3) {
+ case CL_DMAMODE:
+ teoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ max = sc->vbase[CD2400_TFTC];
+ cnt = min((int)max, tp->t_outq.c_cc);
+ if (cnt != 0) {
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ empty = 0;
+ for (tptr = buffer; tptr < &buffer[cnt]; tptr++) {
+ sc->vbase[CD2400_TDR]= *tptr;
+ }
+ teoir = 0x00;
+ } else {
+ if (empty > 5 && (empty % 20000 ) == 0) {
+ printf("cl_txintr: too many empty intr %d chan %d\n",
+ empty, channel);
+ }
+ empty++;
+ teoir = 0x08;
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] & ~0x3;
+ }
+ break;
+ default:
+ printf("cl_txintr unknown mode %x\n", (licr >> 4) & 0x3);
+ /* we probably will go to hell quickly now */
+ teoir = 0x08;
+ }
+ sc->vbase[CD2400_TEOIR] = teoir;
+ return (1);
+}
+
+int
+cl_rxintr(sc)
+ struct clsoftc *sc;
+{
+ u_char rir, channel, licr, risrl;
+ u_char c;
+ u_char fifocnt;
+ struct tty *tp;
+ int i;
+ u_char reoir;
+
+ rir = sc->vbase[CD2400_RIR];
+ if ((rir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_rxintr extra intr\n");
+ return (0);
+ }
+ sc->sc_rxintrcnt.ev_count++;
+ channel = rir & 0x3;
+ licr = sc->vbase[CD2400_LICR];
+ reoir = 0x08;
+
+ sc->sc_cl[channel].rxcnt ++;
+
+ switch (licr & 0x03) {
+ case CL_DMAMODE:
+ reoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ risrl = sc->vbase[CD2400_RISRl];
+ if (risrl & 0x80) {
+ /* timeout, no characters */
+ reoir = 0x08;
+ } else
+ /* We don't need no sinkin special characters */
+ if (risrl & 0x08) {
+ cl_overflow (sc, channel, &sc->sc_fotime, "fifo");
+ reoir = 0x08;
+ } else
+ if (risrl & 0x04) {
+ cl_parity(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x02) {
+ cl_frame(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x01) {
+ cl_break(sc, channel);
+ reoir = 0x08;
+ } else {
+ fifocnt = sc->vbase[CD2400_RFOC];
+ tp = sc->sc_cl[channel].tty;
+ for (i = 0; i < fifocnt; i++) {
+ c = sc->vbase[CD2400_RDR];
+#if USE_BUFFER
+ cl_appendbuf(sc, channel, c);
+#else
+ /* does any restricitions exist on spl
+ * for this call
+ */
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ reoir = 0x00;
+#endif
+ }
+ }
+ break;
+ default:
+ printf("cl_rxintr unknown mode %x\n", licr & 0x03);
+ /* we probably will go to hell quickly now */
+ reoir = 0x08;
+ }
+ sc->vbase[CD2400_REOIR] = reoir;
+ return (1);
+}
+
+void
+cl_overflow(sc, channel, ptime, msg)
+ struct clsoftc *sc;
+ int channel;
+ long *ptime;
+ char *msg;
+{
+/*
+ if (*ptime != time.tv_sec) {
+*/
+ {
+/*
+ *ptime = time.tv_sec);
+*/
+ log(LOG_WARNING, "%s%d[%d]: %s overrun", clcd.cd_name,
+ 0 /* fix */, channel, msg);
+ }
+}
+
+void
+cl_parity(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: parity error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_frame(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: frame error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_break(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: break detected", clcd.cd_name, 0, channel);
+}
+
+void
+cl_dumpport0()
+{
+ cl_dumpport(0);
+}
+
+void
+cl_dumpport1()
+{
+ cl_dumpport(1);
+}
+
+void
+cl_dumpport2()
+{
+ cl_dumpport(2);
+}
+
+void
+cl_dumpport3()
+{
+ cl_dumpport(3);
+}
+
+void
+cl_dumpport(channel)
+ int channel;
+{
+ u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7;
+ u_char schr1, schr2, schr3, schr4, scrl, scrh, lnxt;
+ u_char rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr;
+ u_char csr, rts, dtr, rtprl, rtprh;
+ struct clsoftc *sc = (struct clsoftc *) clcd.cd_devs[0];
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ int s;
+
+ s = spltty();
+ cd_base[CD2400_CAR] = (char) channel;
+ livr = cd_base[CD2400_LIVR];
+ cmr = cd_base[CD2400_CMR];
+ cor1 = cd_base[CD2400_COR1];
+ cor2 = cd_base[CD2400_COR2];
+ cor3 = cd_base[CD2400_COR3];
+ cor4 = cd_base[CD2400_COR4];
+ cor5 = cd_base[CD2400_COR5];
+ cor6 = cd_base[CD2400_COR6];
+ cor7 = cd_base[CD2400_COR7];
+ schr1 = cd_base[CD2400_SCHR1];
+ schr2 = cd_base[CD2400_SCHR2];
+ schr3 = cd_base[CD2400_SCHR3];
+ schr4 = cd_base[CD2400_SCHR4];
+ scrl = cd_base[CD2400_SCRl];
+ scrh = cd_base[CD2400_SCRh];
+ lnxt = cd_base[CD2400_LNXT];
+ rbpr = cd_base[CD2400_RBPR];
+ rcor = cd_base[CD2400_RCOR];
+ tbpr = cd_base[CD2400_TBPR];
+ rpilr = cd_base[CD2400_RPILR];
+ ier = cd_base[CD2400_IER];
+ ccr = cd_base[CD2400_CCR];
+ tcor = cd_base[CD2400_TCOR];
+ csr = cd_base[CD2400_CSR];
+ tpr = cd_base[CD2400_TPR];
+ rts = cd_base[CD2400_MSVR_RTS];
+ dtr = cd_base[CD2400_MSVR_DTR];
+ rtprl = cd_base[CD2400_RTPRl];
+ rtprh = cd_base[CD2400_RTPRh];
+ splx(s);
+
+ printf("{ port %x livr %x cmr %x\n", channel, livr, cmr);
+ printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n",
+ cor1, cor2, cor3, cor4, cor5, cor6, cor7);
+ printf("schr1 %x schr2 %x schr3 %x schr4 %x\n", schr1, schr2, schr3,
+ schr4);
+ printf("scrl %x scrh %x lnxt %x\n", scrl, scrh, lnxt);
+ printf("rbpr %x rcor %x tbpr %x tcor %x\n", rbpr, rcor, tbpr, tcor);
+ printf("rpilr %x rir %x ier %x ccr %x\n", rpilr, rir, ier, ccr);
+ printf("tpr %x csr %x rts %x dtr %x\n", tpr, csr, rts, dtr);
+ printf("rtprl %x rtprh %x\n", rtprl, rtprh);
+ printf("rxcnt %x txcnt %x\n", sc->sc_cl[channel].rxcnt,
+ sc->sc_cl[channel].txcnt);
+ printf("}\n");
+}
diff --git a/sys/arch/mvme68k/dev/cl.c.dale b/sys/arch/mvme68k/dev/cl.c.dale
new file mode 100644
index 00000000000..c59ad812a10
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cl.c.dale
@@ -0,0 +1,1666 @@
+/* $NetBSD$ */
+/*
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+/* #include <sys/queue.h> */
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme68k/dev/cd2400reg.h>
+#include <sys/syslog.h>
+#include "cl.h"
+
+#include "pcctwo.h"
+
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+#define splcl() spl3()
+
+/* min timeout 0xa, what is a good value */
+#define CL_TIMEOUT 0x10
+#define CL_FIFO_MAX 0x10
+#define CL_FIFO_CNT 0xc
+#define CL_RX_TIMEOUT 0x10
+
+#define CL_DMAMODE 0x1
+#define CL_INTRMODE 0x0
+
+struct cl_cons {
+ u_char *cl_paddr;
+ volatile u_char *cl_vaddr;
+ volatile struct pcctworeg *pcctwoaddr;
+ u_char channel;
+} cl_cons;
+
+struct cl_info {
+ struct tty *tty;
+ u_char cl_swflags;
+ u_char cl_softchar;
+ u_char cl_consio;
+ u_char cl_speed;
+ u_char cl_parstop; /* parity, stop bits. */
+ u_char cl_rxmode;
+ u_char cl_txmode;
+ u_char cl_clen;
+ u_char cl_parity;
+ u_char transmitting;
+ u_long txcnt;
+ u_long rxcnt;
+};
+#define CLCD_PORTS_PER_CHIP 4
+struct clsoftc {
+ struct device sc_dev;
+ struct evcnt sc_txintrcnt;
+ struct evcnt sc_rxintrcnt;
+ struct evcnt sc_mxintrcnt;
+ time_t sc_rotime; /* time of last ring overrun */
+ time_t sc_fotime; /* time of last fifo overrun */
+ u_char *pbase;
+ volatile u_char *vbase;
+ struct cl_info sc_cl[CLCD_PORTS_PER_CHIP];
+ struct intrhand sc_ih_e;
+ struct intrhand sc_ih_m;
+ struct intrhand sc_ih_t;
+ struct intrhand sc_ih_r;
+ struct pcctworeg *sc_pcctwo;
+ int sc_flags;
+};
+struct {
+ u_int speed;
+ u_char divisor;
+ u_char clock;
+ u_char rx_timeout;
+} cl_clocks[] = {
+ { 64000, 0x26, 0, 0x01},
+ { 56000, 0x2c, 0, 0x01},
+ { 38400, 0x40, 0, 0x01},
+ { 19200, 0x81, 0, 0x02},
+ { 9600, 0x40, 1, 0x04},
+ { 7200, 0x56, 1, 0x04},
+ { 4800, 0x81, 1, 0x08},
+ { 3600, 0xad, 1, 0x08},
+ { 2400, 0x40, 2, 0x10},
+ { 1200, 0x81, 2, 0x20},
+ { 600, 0x40, 3, 0x40},
+ { 300, 0x81, 3, 0x80},
+ { 150, 0x40, 3, 0x80},
+ { 110, 0x58, 4, 0xff},
+ { 50, 0xC2, 4, 0xff},
+ { 0, 0x00, 0, 0},
+};
+
+/* prototypes */
+int clcnprobe __P((struct consdev *cp));
+int clcninit __P((struct consdev *cp));
+int clcngetc __P((dev_t dev));
+int clcnputc __P((dev_t dev, char c));
+u_char cl_clkdiv __P((int speed));
+u_char cl_clknum __P((int speed));
+u_char cl_clkrxtimeout __P((int speed));
+void clstart __P((struct tty *tp));
+void cl_unblock __P((struct tty *tp));
+int clccparam __P((struct clsoftc *sc, struct termios *par, int channel));
+
+int clparam __P((struct tty *tp, struct termios *t));
+int cl_mintr __P((struct clsoftc *sc));
+int cl_txintr __P((struct clsoftc *sc));
+int cl_rxintr __P((struct clsoftc *sc));
+void cl_overflow __P((struct clsoftc *sc, int channel, long *ptime, char *msg));
+void cl_parity __P((struct clsoftc *sc, int channel));
+void cl_frame __P((struct clsoftc *sc, int channel));
+void cl_break __P(( struct clsoftc *sc, int channel));
+int clmctl __P((dev_t dev, int bits, int how));
+void cl_dumpport __P((int channel));
+
+int clprobe __P((struct device *parent, void *self, void *aux));
+void clattach __P((struct device *parent, struct device *self, void *aux));
+
+int clopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int clclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int clread __P((dev_t dev, struct uio *uio, int flag));
+int clwrite __P((dev_t dev, struct uio *uio, int flag));
+int clioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int clstop __P((struct tty *tp, int flag));
+
+static void cl_initchannel __P((struct clsoftc *sc, int channel));
+static void clputc __P((struct clsoftc *sc, int unit, char c));
+static u_char clgetc __P((struct clsoftc *sc, int *channel));
+static void cloutput __P( (struct tty *tp));
+
+struct cfdriver clcd = {
+ NULL, "cl", clprobe, clattach, DV_TTY, sizeof(struct clsoftc), 0
+};
+
+#if 0
+struct {
+ u_char *pbase;
+ u_char *vbase;
+ struct cl_info info[CLCD_PORTS_PER_CHIP];
+} cl[NCL];
+#endif
+
+#define CLCDBUF 80
+
+int dopoll = 1;
+
+#define CL_UNIT(x) (minor(x) >> 2)
+#define CL_CHANNEL(x) (minor(x) & 3)
+#define CL_TTY(x) (minor(x))
+
+extern int cputyp;
+
+struct tty * cltty(dev)
+ dev_t dev;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ channel = CL_CHANNEL(dev);
+ return sc->sc_cl[channel].tty;
+}
+
+int clprobe(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ /* probing onboard 166/167/187 CL-cd2400
+ * should be previously configured,
+ * we can check the value before resetting the chip
+ */
+ volatile u_char *cd_base;
+ struct confargs *ca = aux;
+ int ret;
+ if (cputyp != CPU_167 && cputyp != CPU_166
+#ifdef CPU_187
+ && cputyp != CPU_187
+#endif
+ )
+ {
+ return 0;
+ }
+ cd_base = ca->ca_vaddr;
+
+#if 0
+ ret = !badvaddr(&cd_base[CD2400_GFRCR],1);
+#else
+ ret = 1;
+#endif
+ return ret;
+}
+
+void
+clattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clsoftc *sc = (struct clsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+
+ sc->vbase = ca->ca_vaddr;
+ sc->sc_pcctwo = ca->ca_master;
+
+ if (ca->ca_paddr == cl_cons.cl_paddr) {
+ /* if this device is configured as console,
+ * line cl_cons.channel is the console */
+ sc->sc_cl[cl_cons.channel].cl_consio = 1;
+ printf(" console");
+ } else {
+ /* reset chip only if we are not console device */
+ /* wait for GFRCR */
+ }
+ /* set up global registers */
+ sc->vbase[CD2400_TPR] = CL_TIMEOUT;
+ sc->vbase[CD2400_RPILR] = 0x03;
+ sc->vbase[CD2400_TPILR] = 0x02;
+ sc->vbase[CD2400_MPILR] = 0x01;
+
+ for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) {
+#if 0
+ sc->sc_cl[i].cl_rxmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x01));
+ sc->sc_cl[i].cl_txmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x02));
+ sc->sc_cl[i].cl_softchar =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x04));
+#endif
+ cl_initchannel(sc, i);
+ }
+ /* enable interrupts */
+ sc->sc_ih_e.ih_fn = cl_rxintr;
+ sc->sc_ih_e.ih_arg = sc;
+ sc->sc_ih_e.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_e.ih_wantframe = 0;
+
+ sc->sc_ih_m.ih_fn = cl_mintr;
+ sc->sc_ih_m.ih_arg = sc;
+ sc->sc_ih_m.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_m.ih_wantframe = 0;
+
+ sc->sc_ih_t.ih_fn = cl_txintr;
+ sc->sc_ih_t.ih_arg = sc;
+ sc->sc_ih_t.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_t.ih_wantframe = 0;
+
+ sc->sc_ih_r.ih_fn = cl_rxintr;
+ sc->sc_ih_r.ih_arg = sc;
+ sc->sc_ih_r.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_r.ih_wantframe = 0;
+ switch (ca->ca_bustype) {
+ case BUS_PCCTWO:
+ dopoll = 0;
+ pcctwointr_establish(PCC2V_SCC_RXE,&sc->sc_ih_e);
+ pcctwointr_establish(PCC2V_SCC_M,&sc->sc_ih_m);
+ pcctwointr_establish(PCC2V_SCC_TX,&sc->sc_ih_t);
+ pcctwointr_establish(PCC2V_SCC_RX,&sc->sc_ih_r);
+ sc->sc_pcctwo = (void *)ca->ca_master;
+ sc->sc_pcctwo->pcc2_sccerr = 0x01; /* clear errors */
+
+ /* enable all interrupts at ca_ipl */
+ sc->sc_pcctwo->pcc2_sccirq = 0x10 | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_scctx = 0x10 | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_sccrx = 0x10 | (ca->ca_ipl & 0x7);
+ break;
+ default:
+ /* oops */
+ panic ("cl driver on unknown bus\n");
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt);
+ printf("\n");
+}
+static void
+cl_initchannel(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ int s;
+ volatile u_char *cd_base = sc->vbase;
+ /* set up option registers */
+ sc->sc_cl[channel].tty = NULL;
+ s = splhigh();
+ cd_base[CD2400_CAR] = (char) channel;
+ /* async, do we want to try DMA at some point? */
+ cd_base[CD2400_LIVR] = PCC2_VECBASE + 0xc;/* set vector base at 5C */
+ cd_base[CD2400_IER] = 0x88; /* should change XXX */
+ cd_base[CD2400_LICR] = 0x00; /* will change if DMA support XXX */
+ /* if the port is not the console */
+ if (sc->sc_cl[channel].cl_consio != 1) {
+ cd_base[CD2400_CMR] = 0x02;
+ cd_base[CD2400_COR1] = 0x17;
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02;
+ cd_base[CD2400_COR4] = 0xec;
+ cd_base[CD2400_COR5] = 0xec;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_RBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_RCOR] = 0x01;
+ cd_base[CD2400_TBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_TCOR] = 0x01 << 5;
+ /* console port should be 0x88 already */
+ cd_base[CD2400_MSVR_RTS] = 0x00;
+ cd_base[CD2400_MSVR_DTR] = 0x00;
+ cd_base[CD2400_RTPRl] = CL_RX_TIMEOUT;
+ cd_base[CD2400_RTPRh] = 0x00;
+ }
+
+ splx(s);
+}
+
+
+int cldefaultrate = TTYDEF_SPEED;
+
+int clmctl (dev, bits, how)
+ dev_t dev;
+ int bits;
+ int how;
+{
+ int s;
+ struct clsoftc *sc;
+ /* should only be called with valid device */
+ sc = (struct clsoftc *) clcd.cd_devs[CL_UNIT(dev)];
+ /*
+ printf("mctl: dev %x, bits %x, how %x,\n",dev, bits, how);
+ */
+ /* settings are currently ignored */
+ s = splcl();
+ switch (how) {
+ case DMSET:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ } else {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ } else {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIC:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIS:
+ if( bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ }
+ if( bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+
+ {
+ u_char msvr;
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if( msvr & 0x80) {
+ bits |= TIOCM_DSR;
+ }
+ if( msvr & 0x40) {
+ bits |= TIOCM_CD;
+ }
+ if( msvr & 0x20) {
+ bits |= TIOCM_CTS;
+ }
+ if( msvr & 0x10) {
+ bits |= TIOCM_DTR;
+ }
+ if( msvr & 0x02) {
+ bits |= TIOCM_DTR;
+ }
+ if( msvr & 0x01) {
+ bits |= TIOCM_RTS;
+ }
+
+ }
+ break;
+ }
+ (void)splx(s);
+#if 0
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+#endif
+
+ /*
+ printf("retbits %x\n", bits);
+ */
+ return(bits);
+}
+
+int clopen (dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int s, unit, channel;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ struct tty *tp;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ s = splcl();
+ if (cl->tty) {
+ tp = cl->tty;
+ } else {
+ tp = cl->tty = ttymalloc();
+ }
+ tp->t_oproc = clstart;
+ tp->t_param = clparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = cldefaultrate;
+ }
+ /*
+ * do these all the time
+ */
+ if (cl->cl_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (cl->cl_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (cl->cl_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ clparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+#ifdef XXX
+ if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) ||
+ (clmctl(dev, 0, DMGET) & TIOCM_CD)) {
+ tp->t_state |= TS_CARR_ON;
+ } else {
+ tp->t_state &= ~TS_CARR_ON;
+ }
+#endif
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return(EBUSY);
+ }
+#ifdef XXX
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+ if (flag & O_NONBLOCK)
+ goto done;
+#endif
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+}
+int clparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+ clccparam(sc, t, channel);
+ s = splcl();
+ cl_unblock(tp);
+ splx(s);
+ return 0;
+}
+
+void cloutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt;
+ char *tptr;
+ int channel;
+ struct clsoftc *sc;
+ dev_t dev;
+ char cl_obuffer[CLCDBUF+1];
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+ channel = CL_CHANNEL(dev);
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = splcl();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+/*XXX*/
+ cnt = min (CLCDBUF,cc);
+ cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt);
+ if (cnt == 0) {
+ break;
+ }
+ for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) {
+ clputc(sc, channel, *tptr);
+ }
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int clclose (dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ int s;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = splcl();
+
+ sc->vbase[CD2400_CAR] = channel;
+ if(cl->cl_consio == 0 && (tp->t_cflag & HUPCL) != 0) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+
+ splx(s);
+ ttyclose(tp);
+
+#if 0
+ cl->tty = NULL;
+#endif
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+
+ return 0;
+}
+int clread (dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+int clwrite (dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+int clioctl (dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return ENXIO;
+
+ 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:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) clmctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) clmctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) clmctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = clmctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = cl->cl_swflags;
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return(EPERM);
+
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return(ENOTTY);
+ }
+
+ return 0;
+}
+int
+clstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = splcl();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return 0;
+}
+
+int
+clcnprobe(cp)
+ struct consdev *cp;
+{
+ /* always there ? */
+ /* serial major */
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == clopen)
+ break;
+ cp->cn_dev = makedev (maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return 1;
+}
+
+int
+clcninit(cp)
+struct consdev *cp;
+{
+#ifdef MAP_DOES_WORK
+ int size = (0x1ff + PGOFSET) & ~PGOFSET;
+ int pcc2_size = (0x3C + PGOFSET) & ~PGOFSET;
+#endif
+ volatile u_char *cd_base;
+
+ cl_cons.cl_paddr = (void *)0xfff45000;
+#ifdef MAP_DOES_WORK
+ cl_cons.cl_vaddr = mapiodev(cl_cons.cl_paddr,size);
+ cd_pcc2_base = mapiodev(0xfff42000,pcc2_size);
+#else
+ cl_cons.cl_vaddr = cl_cons.cl_paddr;
+ cl_cons.pcctwoaddr = (void *)0xfff42000;
+#endif
+ cd_base = cl_cons.cl_vaddr;
+ /* reset the chip? */
+#ifdef CLCD_DO_RESET
+#endif
+#ifdef NEW_CLCD_STRUCT
+ /* set up globals */
+ cl->tftc = 0x10;
+ cl->tpr = CL_TIMEOUT; /* is this correct?? */
+ cl->rpilr = 0x03;
+ cl->tpilr = 0x02;
+ cl->mpilr = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cl->car = 0x00;
+ cl->cor1 = 0x17; /* No parity, ignore parity, 8 bit char */
+ cl->cor2 = 0x00;
+ cl->cor3 = 0x02; /* 1 stop bit */
+ cl->cor4 = 0x00;
+ cl->cor5 = 0x00;
+ cl->cor6 = 0x00;
+ cl->cor7 = 0x00;
+ cl->schr1 = 0x00;
+ cl->schr2 = 0x00;
+ cl->schr3 = 0x00;
+ cl->schr4 = 0x00;
+ cl->scrl = 0x00;
+ cl->scrh = 0x00;
+ cl->lnxt = 0x00;
+ cl->cpsr = 0x00;
+#else
+ /* set up globals */
+#ifdef NOT_ALREADY_SETUP
+ cd_base[CD2400_TFTC] = 0x10;
+ cd_base[CD2400_TPR] = CL_TIMEOUT; /* is this correct?? */
+ cd_base[CD2400_RPILR] = 0x03;
+ cd_base[CD2400_TPILR] = 0x02;
+ cd_base[CD2400_MPILR] = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cd_base[CD2400_CAR] = 0x00;
+ cd_base[CD2400_COR1] = 0x17; /* No parity, ignore parity, 8 bit char */
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02; /* 1 stop bit */
+ cd_base[CD2400_COR4] = 0x00;
+ cd_base[CD2400_COR5] = 0x00;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_CPSR] = 0x00;
+#endif
+#endif
+ return 0;
+}
+
+int
+cl_instat(sc)
+ struct clsoftc *sc;
+{
+ volatile u_char *cd_base;
+ if ( NULL == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+ return (cd_base[CD2400_RIR] & 0x80);
+}
+int
+clcngetc(dev)
+ dev_t dev;
+{
+ u_char val, reoir, licr, isrl, data, status, fifo_cnt;
+ int got_char = 0;
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ volatile struct pcctworeg *pcc2_base = cl_cons.pcctwoaddr;
+ while (got_char == 0) {
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ continue;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ if (((licr >> 2) & 0x3) == 0) {
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ data = cd_base[CD2400_RDR];
+ got_char = 1;
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ }
+
+ }
+
+ return data;
+}
+
+int
+clcnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ /* is this the correct location for the cr -> cr/lf tranlation? */
+ if (c == '\n')
+ clputc(0, 0, '\r');
+
+ clputc(0, 0, c);
+ return 0;
+}
+clcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+ if (1 == on) {
+ /* enable polling */
+ } else {
+ /* disable polling */
+ }
+ return;
+}
+static void
+clputc(sc, unit, c)
+ struct clsoftc *sc;
+ int unit;
+ char c;
+{
+ int s;
+ u_char schar;
+ u_char oldchannel;
+ volatile u_char *cd_base;
+ if (0 == sc) {
+ /* output on console */
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+#ifdef NEW_CLCD_STRUCT
+ /* should we disable, flush and all that goo? */
+ cl->car = unit;
+ schar = cl->schr3;
+ cl->schr3 = c;
+ cl->stcr = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cl->stcr) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ cl->schr3 = schar;
+#else
+if (unit == 0) {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ schar = cd_base[CD2400_SCHR3];
+ cd_base[CD2400_SCHR3] = c;
+ cd_base[CD2400_STCR] = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cd_base[CD2400_STCR]) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ DELAY(5);
+ cd_base[CD2400_SCHR3] = schar;
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+} else {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ if (cd_base[CD2400_TFTC] > 0) {
+ cd_base[CD2400_TDR] = c;
+ }
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+}
+#endif
+ return;
+}
+
+/*
+#ifdef CLCD_DO_POLLED_INPUT
+*/
+#if 1
+void
+cl_chkinput()
+{
+ struct tty *tp;
+ int unit;
+ struct clsoftc *sc;
+ int channel;
+
+ if (dopoll == 0)
+ return;
+ for (unit = 0; unit < clcd.cd_ndevs; unit++) {
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ continue;
+ }
+ if (cl_instat(sc)) {
+ while (cl_instat(sc)){
+ int ch;
+ u_char c;
+ /*
+ *(pinchar++) = clcngetc();
+ */
+ ch = clgetc(sc,&channel) & 0xff;
+ c = ch;
+
+ tp = sc->sc_cl[channel].tty;
+ if (NULL != tp) {
+ (*linesw[tp->t_line].l_rint)(c,tp);
+ }
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+ }
+}
+#endif
+static u_char
+clgetc(sc, channel)
+ struct clsoftc *sc;
+ int *channel;
+{
+ volatile u_char *cd_base;
+ volatile struct pcctworeg *pcc2_base;
+ u_char val, reoir, licr, isrl, fifo_cnt, data;
+ if (0 == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ pcc2_base = cl_cons.pcctwoaddr;
+ } else {
+ cd_base = sc->vbase;
+ pcc2_base = sc->sc_pcctwo;
+ }
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ return 0;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ *channel = (licr >> 2) & 0x3;
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ if (fifo_cnt > 0) {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = 0;
+ cd_base[CD2400_TEOIR] = 0x08;
+ }
+ return data;
+}
+int
+clccparam(sc, par, channel)
+ struct clsoftc *sc;
+ struct termios *par;
+ int channel;
+{
+ u_int divisor, clk, clen;
+ int s, imask, ints;
+
+ s = splcl();
+ sc->vbase[CD2400_CAR] = channel;
+ if (par->c_ospeed == 0) {
+ /* dont kill the console */
+ if(sc->sc_cl[channel].cl_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ sc->vbase[CD2400_MSVR_RTS] = 0x03;
+ sc->vbase[CD2400_MSVR_DTR] = 0x03;
+
+ divisor = cl_clkdiv(par->c_ospeed);
+ clk = cl_clknum(par->c_ospeed);
+ sc->vbase[CD2400_TBPR] = divisor;
+ sc->vbase[CD2400_TCOR] = clk << 5;
+ divisor = cl_clkdiv(par->c_ispeed);
+ clk = cl_clknum(par->c_ispeed);
+ sc->vbase[CD2400_RBPR] = divisor;
+ sc->vbase[CD2400_RCOR] = clk;
+ sc->vbase[CD2400_RTPRl] = cl_clkrxtimeout(par->c_ispeed);
+ sc->vbase[CD2400_RTPRh] = 0x00;
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ clen = 4; /* this is the mask for the chip. */
+ imask = 0x1F;
+ break;
+ case CS6:
+ clen = 5;
+ imask = 0x3F;
+ break;
+ case CS7:
+ clen = 6;
+ imask = 0x7F;
+ break;
+ default:
+ clen = 7;
+ imask = 0xFF;
+ }
+ sc->vbase[CD2400_COR3] = par->c_cflag & PARENB ? 4 : 2;
+
+ if (par->c_cflag & PARENB) {
+ if (par->c_cflag & PARODD) {
+ sc->vbase[CD2400_COR1] = 0xE0 | clen ; /* odd */
+ } else {
+ sc->vbase[CD2400_COR1] = 0x40 | clen ; /* even */
+ }
+ } else {
+ sc->vbase[CD2400_COR1] = 0x10 | clen; /* ignore parity */
+ }
+
+ if (sc->sc_cl[channel].cl_consio == 0
+ && (par->c_cflag & CREAD) == 0 )
+ {
+ sc->vbase[CD2400_CCR] = 0x08;
+ } else {
+ sc->vbase[CD2400_CCR] = 0x0a;
+ }
+ ints = 0;
+#define SCC_DSR 0x80
+#define SCC_DCD 0x40
+#define SCC_CTS 0x20
+ if ((par->c_cflag & CLOCAL) == 0) {
+ ints |= SCC_DCD;
+ }
+ if ((par->c_cflag & CCTS_OFLOW) != 0) {
+ ints |= SCC_CTS;
+ }
+ if ((par->c_cflag & CRTSCTS) != 0) {
+ ints |= SCC_CTS;
+ }
+#ifdef DONT_LET_HARDWARE
+ if ((par->c_cflag & CCTS_IFLOW) != 0) {
+ ints |= SCC_DSR;
+ }
+#endif
+ sc->vbase[CD2400_COR4] = ints | CL_FIFO_CNT;
+ sc->vbase[CD2400_COR5] = ints | CL_FIFO_CNT;
+
+ return imask;
+}
+static int clknum = 0;
+u_char
+cl_clkdiv(speed)
+ int speed;
+{
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].divisor;
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].divisor;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].divisor;
+}
+u_char
+cl_clknum(speed)
+ int speed;
+{
+ int found = 0;
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].clock;
+ }
+ for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[clknum].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].clock;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].clock;
+}
+u_char
+cl_clkrxtimeout(speed)
+ int speed;
+{
+ int i = 0;
+ if (cl_clocks[clknum].speed == speed) {
+ return cl_clocks[clknum].rx_timeout;
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return cl_clocks[clknum].rx_timeout;
+ }
+ }
+ /* return some sane value if unknown speed */
+ return cl_clocks[4].rx_timeout;
+}
+void
+cl_unblock(tp)
+ struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ clstart(tp);
+}
+void
+clstart(tp)
+ struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct clsoftc *sc;
+ int channel, unit, s, cnt;
+
+ dev = tp->t_dev;
+ channel = CL_CHANNEL(dev);
+/* hack to test output on non console only */
+#if 0
+ if (channel == 0) {
+ cloutput(tp);
+ return;
+ }
+#endif
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = splcl();
+#if 0
+ if (sc->sc_cl[channel].transmitting == 1) {
+ /* i'm busy, go away, I will get to it later. */
+ splx(s);
+ return;
+ }
+ cnt = q_to_b(&tp->t_outq, &cbuf, 1);
+ if ( cnt != 0 ) {
+ sc->sc_cl[channel].transmitting = 1;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_TDR] = cbuf;
+ } else {
+ sc->sc_cl[channel].transmitting = 0;
+ }
+#else
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0)
+ {
+ tp->t_state |= TS_BUSY;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] | 0x3;
+ }
+#endif
+ splx(s);
+ return;
+}
+int
+cl_mintr(sc)
+ struct clsoftc *sc;
+{
+ u_char mir, misr, msvr;
+ int channel;
+ struct tty *tp;
+ if(((mir = sc->vbase[CD2400_MIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared? */
+ printf("cl_mintr extra intr\n");
+ return 0;
+ }
+ sc->sc_mxintrcnt.ev_count++;
+
+ channel = mir & 0x03;
+ misr = sc->vbase[CD2400_MISR];
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if (misr & 0x01) {
+ /* timers are not currently used?? */
+ printf ("cl_mintr: channel %x timer 1 unexpected\n",channel);
+ }
+ if (misr & 0x02) {
+ /* timers are not currently used?? */
+ printf ("cl_mintr: channel %x timer 2 unexpected\n",channel);
+ }
+ if (misr & 0x20) {
+ printf ("cl_mintr: channel %x cts %x\n",channel,
+ ((msvr & 0x20) != 0x0)
+ );
+ }
+ if (misr & 0x40) {
+ struct tty *tp = sc->sc_cl[channel].tty;
+ printf ("cl_mintr: channel %x cd %x\n",channel,
+ ((msvr & 0x40) != 0x0)
+ );
+ ttymodem(tp, ((msvr & 0x40) != 0x0) );
+ }
+ if (misr & 0x80) {
+ printf ("cl_mintr: channel %x dsr %x\n",channel,
+ ((msvr & 0x80) != 0x0)
+ );
+ }
+ sc->vbase[CD2400_MEOIR] = 0x00;
+ return 1;
+}
+
+int
+cl_txintr(sc)
+ struct clsoftc *sc;
+{
+ static empty = 0;
+ u_char tir, licr, teoir;
+ u_char max;
+ int channel;
+ struct tty *tp;
+ int cnt;
+ u_char buffer[CL_FIFO_MAX +1];
+ u_char *tptr;
+ if(((tir = sc->vbase[CD2400_TIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf ("cl_txintr extra intr\n");
+ return 0;
+ }
+ sc->sc_txintrcnt.ev_count++;
+
+ channel = tir & 0x03;
+ licr = sc->vbase[CD2400_LICR];
+
+ sc->sc_cl[channel].txcnt ++;
+
+ tp = sc->sc_cl[channel].tty;
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+ sc->vbase[CD2400_TEOIR] = 0x08;
+ return 1;
+ }
+ switch ((licr >> 4)& 0x3) {
+ case CL_DMAMODE:
+ teoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ max = sc->vbase[CD2400_TFTC];
+ cnt = min ((int)max,tp->t_outq.c_cc);
+ if (cnt != 0) {
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ empty = 0;
+ for (tptr = buffer; tptr < &buffer[cnt]; tptr++) {
+ sc->vbase[CD2400_TDR]= *tptr;
+ }
+ teoir = 0x00;
+ } else {
+ if (empty > 5 && ((empty % 20000 )== 0)) {
+ printf("cl_txintr to many empty intr %d channel %d\n",
+ empty, channel);
+ }
+ empty++;
+ teoir = 0x08;
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t) &tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] & ~0x3;
+ }
+ break;
+ default:
+ printf("cl_txintr unknown mode %x\n", ((licr >> 4) & 0x3));
+ /* we probably will go to hell quickly now */
+ teoir = 0x08;
+ }
+ sc->vbase[CD2400_TEOIR] = teoir;
+ return 1;
+}
+
+int
+cl_rxintr(sc)
+ struct clsoftc *sc;
+{
+ u_char rir, channel, licr, risrl;
+ u_char c;
+ u_char fifocnt;
+ struct tty *tp;
+ int i;
+ u_char reoir;
+
+ if(((rir = sc->vbase[CD2400_RIR]) & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf ("cl_rxintr extra intr\n");
+ return 0;
+ }
+ sc->sc_rxintrcnt.ev_count++;
+ channel = rir & 0x3;
+ licr = sc->vbase[CD2400_LICR];
+ reoir = 0x08;
+
+ sc->sc_cl[channel].rxcnt ++;
+
+ switch (licr & 0x03) {
+ case CL_DMAMODE:
+ reoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ risrl = sc->vbase[CD2400_RISRl];
+ if (risrl & 0x80) {
+ /* timeout, no characters */
+ reoir = 0x08;
+ } else
+ /* We don't need no sinkin special characters */
+ if (risrl & 0x08) {
+ cl_overflow (sc, channel, &sc->sc_fotime, "fifo");
+ reoir = 0x08;
+ } else
+ if (risrl & 0x04) {
+ cl_parity(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x02) {
+ cl_frame(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x01) {
+ cl_break(sc, channel);
+ reoir = 0x08;
+ } else {
+ fifocnt = sc->vbase[CD2400_RFOC];
+ tp = sc->sc_cl[channel].tty;
+ for (i = 0; i < fifocnt; i++) {
+ c = sc->vbase[CD2400_RDR];
+#if USE_BUFFER
+ cl_appendbuf(sc, channel, c);
+#else
+ /* does any restricitions exist on spl
+ * for this call
+ */
+ (*linesw[tp->t_line].l_rint)(c,tp);
+ reoir = 0x00;
+#endif
+ }
+ }
+ break;
+ default:
+ printf("cl_rxintr unknown mode %x\n",licr & 0x03);
+ /* we probably will go to hell quickly now */
+ reoir = 0x08;
+ }
+ sc->vbase[CD2400_REOIR] = reoir;
+ return 1;
+}
+
+void
+cl_overflow (sc, channel, ptime, msg)
+struct clsoftc *sc;
+int channel;
+long *ptime;
+char *msg;
+{
+/*
+ if (*ptime != time.tv_sec) {
+*/
+ {
+/*
+ *ptime = time.tv_sec);
+*/
+ log(LOG_WARNING, "%s%d[%d]: %s overrun", clcd.cd_name,
+ 0 /* fix */, channel, msg);
+ }
+ return;
+}
+void
+cl_parity (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: parity error", clcd.cd_name, 0, channel);
+ return;
+}
+void
+cl_frame (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: frame error", clcd.cd_name, 0, channel);
+ return;
+}
+void
+cl_break (sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: break detected", clcd.cd_name, 0, channel);
+ return;
+}
+
+void
+cl_dumpport0()
+{
+ cl_dumpport(0);
+ return;
+}
+void
+cl_dumpport1()
+{
+ cl_dumpport(1);
+ return;
+}
+void
+cl_dumpport2()
+{
+ cl_dumpport(2);
+ return;
+}
+void
+cl_dumpport3()
+{
+ cl_dumpport(3);
+ return;
+}
+
+void
+cl_dumpport(channel)
+ int channel;
+{
+ u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7,
+ schr1, schr2, schr3, schr4, scrl, scrh, lnxt,
+ rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr,
+ csr, rts, dtr, rtprl, rtprh;
+ struct clsoftc *sc;
+
+ volatile u_char *cd_base;
+ int s;
+
+ cd_base = cl_cons.cl_vaddr;
+
+ sc = (struct clsoftc *) clcd.cd_devs[0];
+
+ s = splcl();
+ cd_base[CD2400_CAR] = (char) channel;
+ livr = cd_base[CD2400_LIVR];
+ cmr = cd_base[CD2400_CMR];
+ cor1 = cd_base[CD2400_COR1];
+ cor2 = cd_base[CD2400_COR2];
+ cor3 = cd_base[CD2400_COR3];
+ cor4 = cd_base[CD2400_COR4];
+ cor5 = cd_base[CD2400_COR5];
+ cor6 = cd_base[CD2400_COR6];
+ cor7 = cd_base[CD2400_COR7];
+ schr1 = cd_base[CD2400_SCHR1];
+ schr2 = cd_base[CD2400_SCHR2];
+ schr3 = cd_base[CD2400_SCHR3];
+ schr4 = cd_base[CD2400_SCHR4];
+ scrl = cd_base[CD2400_SCRl];
+ scrh = cd_base[CD2400_SCRh];
+ lnxt = cd_base[CD2400_LNXT];
+ rbpr = cd_base[CD2400_RBPR];
+ rcor = cd_base[CD2400_RCOR];
+ tbpr = cd_base[CD2400_TBPR];
+ rpilr = cd_base[CD2400_RPILR];
+ ier = cd_base[CD2400_IER];
+ ccr = cd_base[CD2400_CCR];
+ tcor = cd_base[CD2400_TCOR];
+ csr = cd_base[CD2400_CSR];
+ tpr = cd_base[CD2400_TPR];
+ rts = cd_base[CD2400_MSVR_RTS];
+ dtr = cd_base[CD2400_MSVR_DTR];
+ rtprl = cd_base[CD2400_RTPRl];
+ rtprh = cd_base[CD2400_RTPRh];
+ splx(s);
+
+ printf("{ port %x livr %x cmr %x\n",
+ channel,livr, cmr);
+ printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n",
+ cor1, cor2, cor3, cor4, cor5, cor6, cor7);
+ printf("schr1 %x schr2 %x schr3 %x schr4 %x\n",
+ schr1, schr2, schr3, schr4);
+ printf("scrl %x scrh %x lnxt %x\n",
+ scrl, scrh, lnxt);
+ printf("rbpr %x rcor %x tbpr %x tcor %x\n",
+ rbpr, rcor, tbpr, tcor);
+ printf("rpilr %x rir %x ier %x ccr %x\n",
+ rpilr, rir, ier, ccr);
+ printf("tpr %x csr %x rts %x dtr %x\n",
+ tpr, csr, rts, dtr);
+ printf("rtprl %x rtprh %x\n",
+ rtprl, rtprh);
+ printf("rxcnt %x txcnt %x\n",
+ sc->sc_cl[channel].rxcnt, sc->sc_cl[channel].txcnt);
+ printf("}\n");
+ return;
+}
diff --git a/sys/arch/mvme68k/dev/clock.c b/sys/arch/mvme68k/dev/clock.c
new file mode 100644
index 00000000000..e4871cc2db3
--- /dev/null
+++ b/sys/arch/mvme68k/dev/clock.c
@@ -0,0 +1,393 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <machine/psl.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include "pcc.h"
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NPCC > 0
+#include <mvme68k/dev/pccreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#if defined(GPROF)
+#include <sys/gmon.h>
+#endif
+
+/*
+ * Statistics clock interval and variance, in usec. Variance must be a
+ * power of two. Since this gives us an even number, not an odd number,
+ * we discard one case and compensate. That is, a variance of 8192 would
+ * give us offsets in [0..8191]. Instead, we take offsets in [1..8191].
+ * This is symmetric about the point 2048, or statvar/2, and thus averages
+ * to that value (assuming uniform random numbers).
+ */
+int statvar = 8192;
+int statmin; /* statclock interval - 1/2*variance */
+
+struct clocksoftc {
+ struct device sc_dev;
+ struct intrhand sc_profih;
+ struct intrhand sc_statih;
+};
+
+void clockattach __P((struct device *, struct device *, void *));
+int clockmatch __P((struct device *, void *, void *));
+
+struct cfdriver clockcd = {
+ NULL, "clock", clockmatch, clockattach,
+ DV_DULL, sizeof(struct clocksoftc), 0
+};
+
+int clockintr __P((void *));
+int statintr __P((void *));
+
+int clockbus;
+u_char stat_reset, prof_reset;
+
+/*
+ * Every machine must have a clock tick device of some sort; for this
+ * platform this file manages it, no matter what form it takes.
+ */
+int
+clockmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ return (1);
+}
+
+void
+clockattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct clocksoftc *sc = (struct clocksoftc *)self;
+
+ sc->sc_profih.ih_fn = clockintr;
+ sc->sc_profih.ih_arg = 0;
+ sc->sc_profih.ih_wantframe = 1;
+ sc->sc_profih.ih_ipl = ca->ca_ipl;
+
+ sc->sc_statih.ih_fn = statintr;
+ sc->sc_statih.ih_arg = 0;
+ sc->sc_statih.ih_wantframe = 1;
+ sc->sc_statih.ih_ipl = ca->ca_ipl;
+
+ clockbus = ca->ca_bustype;
+ switch (ca->ca_bustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ prof_reset = ca->ca_ipl | PCC_IRQ_IEN | PCC_TIMERACK;
+ stat_reset = ca->ca_ipl | PCC_IRQ_IEN | PCC_TIMERACK;
+ pccintr_establish(PCCV_TIMER1, &sc->sc_profih);
+ pccintr_establish(PCCV_TIMER2, &sc->sc_statih);
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ prof_reset = ca->ca_ipl | MC_IRQ_IEN | MC_IRQ_ICLR;
+ stat_reset = ca->ca_ipl | MC_IRQ_IEN | MC_IRQ_ICLR;
+ mcintr_establish(MCV_TIMER1, &sc->sc_profih);
+ mcintr_establish(MCV_TIMER2, &sc->sc_statih);
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ prof_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ stat_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ pcctwointr_establish(PCC2V_TIMER1, &sc->sc_profih);
+ pcctwointr_establish(PCC2V_TIMER2, &sc->sc_statih);
+ break;
+#endif
+ }
+
+ printf("\n");
+}
+
+/*
+ * clockintr: ack intr and call hardclock
+ */
+int
+clockintr(arg)
+ void *arg;
+{
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t1irq = prof_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t1irq = prof_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t1irq = prof_reset;
+ break;
+#endif
+ }
+ hardclock(arg);
+ return (1);
+}
+
+/*
+ * Set up real-time clock; we don't have a statistics clock at
+ * present.
+ */
+cpu_initclocks()
+{
+ register int statint, minint;
+
+ if (1000000 % hz) {
+ printf("cannot get %d Hz clock; using 100 Hz\n", hz);
+ hz = 100;
+ tick = 1000000 / hz;
+ }
+ if (stathz == 0)
+ stathz = hz;
+ if (1000000 % stathz) {
+ printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
+ stathz = 100;
+ }
+ profhz = stathz; /* always */
+
+ statint = 1000000 / stathz;
+ minint = statint / 2 + 100;
+ while (statvar > minint)
+ statvar >>= 1;
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t1pload = pcc_timer_us2lim(tick);
+ sys_pcc->pcc_t1ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t1ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t1irq = prof_reset;
+
+ sys_pcc->pcc_t2pload = pcc_timer_us2lim(statint);
+ sys_pcc->pcc_t2ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t2ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ /* profclock */
+ sys_mc->mc_t1ctl = 0;
+ sys_mc->mc_t1cmp = mc_timer_us2lim(tick);
+ sys_mc->mc_t1count = 0;
+ sys_mc->mc_t1ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF;
+ sys_mc->mc_t1irq = prof_reset;
+
+ /* statclock */
+ sys_mc->mc_t2ctl = 0;
+ sys_mc->mc_t2cmp = mc_timer_us2lim(statint);
+ sys_mc->mc_t2count = 0;
+ sys_mc->mc_t2ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF;
+ sys_mc->mc_t2irq = stat_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ /* profclock */
+ sys_pcc2->pcc2_t1ctl = 0;
+ sys_pcc2->pcc2_t1cmp = pcc2_timer_us2lim(tick);
+ sys_pcc2->pcc2_t1count = 0;
+ sys_pcc2->pcc2_t1ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC |
+ PCC2_TCTL_COVF;
+ sys_pcc2->pcc2_t1irq = prof_reset;
+
+ /* statclock */
+ sys_pcc2->pcc2_t2ctl = 0;
+ sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(statint);
+ sys_pcc2->pcc2_t2count = 0;
+ sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC |
+ PCC2_TCTL_COVF;
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ break;
+#endif
+ }
+ statmin = statint - (statvar >> 1);
+}
+
+void
+setstatclockrate(newhz)
+ int newhz;
+{
+}
+
+int
+statintr(cap)
+ void *cap;
+{
+ register u_long newint, r, var;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t2irq = stat_reset;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ break;
+#endif
+ }
+
+ statclock((struct clockframe *)cap);
+
+ /*
+ * Compute new randomized interval. The intervals are uniformly
+ * distributed on [statint - statvar / 2, statint + statvar / 2],
+ * and therefore have mean statint, giving a stathz frequency clock.
+ */
+ var = statvar;
+ do {
+ r = random() & (var - 1);
+ } while (r == 0);
+ newint = statmin + r;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ sys_pcc->pcc_t2pload = pcc_timer_us2lim(newint);
+ sys_pcc->pcc_t2ctl = PCC_TIMERCLEAR;
+ sys_pcc->pcc_t2ctl = PCC_TIMERSTART;
+ sys_pcc->pcc_t2irq = stat_reset;
+ break;
+#endif
+#if NMC > 0
+ case BUS_MC:
+ sys_mc->mc_t2ctl = 0;
+ sys_mc->mc_t2cmp = mc_timer_us2lim(newint);
+ sys_mc->mc_t2count = 0; /* should I? */
+ sys_mc->mc_t2irq = stat_reset;
+ sys_mc->mc_t2ctl = MC_TCTL_CEN | MC_TCTL_COC;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sys_pcc2->pcc2_t2ctl = 0;
+ sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(newint);
+ sys_pcc2->pcc2_t2count = 0; /* should I? */
+ sys_pcc2->pcc2_t2irq = stat_reset;
+ sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC;
+ break;
+#endif
+ }
+ return (1);
+}
+
+delay(us)
+ register int us;
+{
+ volatile register int c;
+
+ switch (clockbus) {
+#if NPCC > 0
+ case BUS_PCC:
+ /*
+ * XXX MVME147 doesn't have a 3rd free-running timer,
+ * so we use a stupid loop. Fix the code to watch t1:
+ * the profiling timer.
+ */
+ c = 2 * us;
+ while (--c > 0)
+ ;
+ return (0);
+#endif
+#if NMC > 0
+ case BUS_MC:
+ /*
+ * Reset and restart a free-running timer 1MHz, watch
+ * for it to reach the required count.
+ */
+ sys_mc->mc_t3irq = 0;
+ sys_mc->mc_t3ctl = 0;
+ sys_mc->mc_t3count = 0;
+ sys_mc->mc_t3ctl = MC_TCTL_CEN | MC_TCTL_COVF;
+
+ while (sys_mc->mc_t3count < us)
+ ;
+ return (0);
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ /*
+ * XXX MVME167 doesn't have a 3rd free-running timer,
+ * so we use a stupid loop. Fix the code to watch t1:
+ * the profiling timer.
+ */
+ c = 4 * us;
+ while (--c > 0)
+ ;
+ return (0);
+#endif
+ }
+}
diff --git a/sys/arch/mvme68k/dev/dmavar.h b/sys/arch/mvme68k/dev/dmavar.h
new file mode 100644
index 00000000000..99da32b62c1
--- /dev/null
+++ b/sys/arch/mvme68k/dev/dmavar.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1982, 1990 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.
+ *
+ * @(#)dmavar.h 7.2 (Berkeley) 11/4/90
+ * $Id: dmavar.h,v 1.1 1995/10/18 10:43:06 deraadt Exp $
+ */
+
+/* dmago flags */
+#define DMAGO_READ 0x08 /* transfer is a read */
+#define DMAGO_NOINT 0x80 /* don't interrupt on completion */
+
+#ifdef KERNEL
+typedef void (*dmafree_t) __P((void *dev));
+typedef int (*dmago_t) __P((void *dev, char *, int, int));
+typedef int (*dmanext_t) __P((void *dev));
+typedef void (*dmastop_t) __P((void *dev));
+#endif
+
diff --git a/sys/arch/mvme68k/dev/flash.c b/sys/arch/mvme68k/dev/flash.c
new file mode 100644
index 00000000000..933b2a199a6
--- /dev/null
+++ b/sys/arch/mvme68k/dev/flash.c
@@ -0,0 +1,360 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/mioctl.h>
+
+#include "mc.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#include <mvme68k/dev/flashreg.h>
+
+struct flashsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ volatile u_char * sc_vaddr;
+ u_char sc_manu;
+ u_char sc_ii;
+ int sc_len;
+ int sc_zonesize;
+};
+
+void flashattach __P((struct device *, struct device *, void *));
+int flashmatch __P((struct device *, void *, void *));
+
+struct cfdriver flashcd = {
+ NULL, "flash", flashmatch, flashattach,
+ DV_DULL, sizeof(struct flashsoftc), 0
+};
+
+int flashwritebyte __P((struct flashsoftc *sc, int addr, u_char val));
+int flasherasezone __P((struct flashsoftc *sc, int addr));
+
+struct flashii intel_flashii[] = {
+ { "28F008SA", FLII_INTEL_28F008SA, 1024*1024, 64*1024 },
+ { "28F008SA-L", FLII_INTEL_28F008SA_L, 1024*1024, 64*1024 },
+ { NULL },
+};
+
+struct flashmanu {
+ char *name;
+ u_char manu;
+ struct flashii *flashii;
+} flashmanu[] = {
+ { "intel", FLMANU_INTEL, intel_flashii },
+ { NULL }
+};
+
+int
+flashmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+
+#ifdef MVME147
+ if (cputyp == CPU_147)
+ return (0);
+#endif
+#ifdef MVME167
+ /*
+ * XXX: 166 has 4 byte-wide flash rams side-by-side, and
+ * isn't supported (yet).
+ */
+ if (cputyp == CPU_166)
+ return (0);
+#endif
+
+ if (badpaddr(ca->ca_paddr, 1))
+ return (0);
+
+ /*
+ * XXX: need to determine if it is flash or rom
+ */
+ return (1);
+}
+
+void
+flashattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct flashsoftc *sc = (struct flashsoftc *)self;
+ struct confargs *ca = args;
+ int manu, ident;
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = mapiodev(sc->sc_paddr, NBPG);
+
+ switch (cputyp) {
+#ifdef MVME162
+ case CPU_162:
+ mc_enableflashwrite(1);
+ break;
+#endif
+ }
+
+ /* read manufacturer and product identifier from flash */
+ sc->sc_vaddr[0] = FLCMD_RESET;
+ sc->sc_vaddr[0] = FLCMD_READII;
+ sc->sc_manu = sc->sc_vaddr[0];
+ sc->sc_ii = sc->sc_vaddr[1];
+ sc->sc_vaddr[0] = FLCMD_RESET;
+
+ for (manu = 0; flashmanu[manu].name; manu++)
+ if (flashmanu[manu].manu == sc->sc_manu)
+ break;
+ if (flashmanu[manu].name == NULL) {
+ printf(": unknown manu 0x%02x ident %02x\n",
+ sc->sc_manu, sc->sc_ii);
+ return;
+ }
+ for (ident = 0; flashmanu[manu].flashii[ident].name; ident++)
+ if (flashmanu[manu].flashii[ident].ii == sc->sc_ii)
+ break;
+ if (flashmanu[manu].flashii[ident].name == NULL) {
+ printf(": unknown manu %s ident 0x%02x\n",
+ flashmanu[manu].name, sc->sc_ii);
+ return;
+ }
+ sc->sc_len = flashmanu[manu].flashii[ident].size;
+ sc->sc_zonesize = flashmanu[manu].flashii[ident].zonesize;
+ printf(": %s %s len %d", flashmanu[manu].name,
+ flashmanu[manu].flashii[ident].name, sc->sc_len);
+
+ unmapiodev(sc->sc_vaddr, NBPG);
+ sc->sc_vaddr = mapiodev(sc->sc_paddr, sc->sc_len);
+ if (sc->sc_vaddr == NULL) {
+ sc->sc_len = 0;
+ printf(" -- failed to map");
+ }
+ printf("\n");
+}
+
+/*ARGSUSED*/
+int
+flashopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= flashcd.cd_ndevs ||
+ flashcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+flashclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+flashioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+flashread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+ register vm_offset_t v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("flashrw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (v + c > sc->sc_len)
+ c = sc->sc_len - v; /* till end of FLASH */
+ if (c == 0)
+ return (0);
+ error = uiomove((caddr_t)sc->sc_vaddr + v, c, uio);
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+flashwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ return (ENXIO);
+}
+
+int
+flashmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct flashsoftc *sc = (struct flashsoftc *) flashcd.cd_devs[unit];
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
+
+int
+flasherasezone(sc, addr)
+ struct flashsoftc *sc;
+ int addr;
+{
+ u_char sr;
+
+ sc->sc_vaddr[addr] = FLCMD_ESETUP;
+ sc->sc_vaddr[addr] = FLCMD_ECONFIRM;
+
+ /* XXX should use sleep/wakeup/timeout combination */
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_ES)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Should add some light retry code. If a write fails see if an
+ * erase helps the situation... eventually flash rams become
+ * useless but perhaps we can get just one more cycle out of it.
+ */
+int
+flashwritebyte(sc, addr, val)
+ struct flashsoftc *sc;
+ int addr;
+ u_char val;
+{
+ u_char sr;
+
+ /*
+ * If a zero'd bit in the flash memory needs to become set,
+ * then the zone must be erased and rebuilt.
+ */
+ if (val & ~sc->sc_vaddr[addr]) {
+ int faddr = addr & ~(sc->sc_zonesize - 1);
+ u_char *zone;
+ int i;
+
+ zone = (u_char *)malloc(sc->sc_zonesize, M_TEMP, M_WAITOK);
+ if (!zone)
+ return (-1);
+ bcopy((caddr_t)&sc->sc_vaddr[faddr], zone, sc->sc_zonesize);
+
+ if (flasherasezone(sc, faddr) == -1)
+ return (-1);
+
+ zone[addr - faddr] = val;
+ for (i = 0; i < sc->sc_zonesize; i++) {
+ sc->sc_vaddr[faddr + i] = FLCMD_WSETUP;
+ sc->sc_vaddr[faddr + i] = zone[i];
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_BWS)
+ return (-1); /* write failed! */
+ }
+ free(zone, M_TEMP);
+ return (0);
+ }
+
+ sc->sc_vaddr[addr] = FLCMD_WSETUP;
+ sc->sc_vaddr[addr] = val;
+ do {
+ sc->sc_vaddr[0] = FLCMD_READSTAT;
+ sr = sc->sc_vaddr[0];
+ } while (sr & FLSR_WSMS == 0);
+ if (sr & FLSR_BWS)
+ return (-1); /* write failed! */
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/flashreg.h b/sys/arch/mvme68k/dev/flashreg.h
new file mode 100644
index 00000000000..d9d82c5e492
--- /dev/null
+++ b/sys/arch/mvme68k/dev/flashreg.h
@@ -0,0 +1,63 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define FLCMD_RESET 0xff
+#define FLCMD_READII 0x90
+#define FLCMD_READSTAT 0x70
+#define FLCMD_CLEARSTAT 0x50
+#define FLCMD_ESETUP 0x20
+#define FLCMD_ECONFIRM 0xd0
+#define FLCMD_ESUSPEND 0xb0
+#define FLCMD_ERESUME 0xd0
+#define FLCMD_WSETUP 0x40
+#define FLCMD_AWSETUP 0x10
+
+#define FLSR_WSMS 0x80
+#define FLSR_ESS 0x40
+#define FLSR_ES 0x20
+#define FLSR_BWS 0x10
+#define FLSR_VPPS 0x08
+
+/* manufacturers */
+#define FLMANU_INTEL 0x89
+
+/* intel parts */
+#define FLII_INTEL_28F020 0xbd
+#define FLII_INTEL_28F008SA 0xa1
+#define FLII_INTEL_28F008SA_L 0xa2
+
+struct flashii {
+ char *name;
+ u_char ii;
+ int size;
+ int zonesize;
+};
diff --git a/sys/arch/mvme68k/dev/fooip.c b/sys/arch/mvme68k/dev/fooip.c
new file mode 100644
index 00000000000..f0217ba369a
--- /dev/null
+++ b/sys/arch/mvme68k/dev/fooip.c
@@ -0,0 +1,123 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * A sample framework for writing an IP module driver.
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/ipicreg.h>
+
+struct fooipregs {
+ volatile u_char fooip_reg1;
+ volatile u_char fooip_vec;
+};
+
+struct fooipsoftc {
+ struct device sc_dev;
+ struct ipicsoftc *sc_ipicsc;
+ struct intrhand sc_ih;
+
+ int sc_slot;
+ struct fooipregs *sc_regs;
+};
+
+void fooipattach __P((struct device *, struct device *, void *));
+int fooipmatch __P((struct device *, void *, void *));
+
+struct cfdriver fooipcd = {
+ NULL, "fooip", fooipmatch, fooipattach,
+ DV_DULL, sizeof(struct fooipsoftc), 0
+};
+
+int fooipintr __P((void *));
+
+int
+fooipmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ return (1);
+}
+
+void
+fooipattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct fooipsoftc *sc = (struct fooipsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_ipicsc = (struct ipicsoftc *)ca->ca_master;
+ sc->sc_regs = (struct fooipregs *)(ca->ca_vaddr +
+ IPIC_IP_REGOFFSET);
+ sc->sc_slot = ca->ca_offset;
+
+ /* this device uses only one interrupt */
+ sc->sc_ih.ih_fn = fooipintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ ipicintr_establish(ca->ca_vec, &sc->sc_ih);
+
+ sc->sc_regs->fooip_vec = ca->ca_vec;
+ sc->sc_ipicsc->sc_ipic->ipic_irq[sc->sc_slot][0] = ca->ca_ipl |
+ IPIC_IRQ_ICLR | IPIC_IRQ_IEN;
+
+ printf("\n");
+}
+
+int
+fooipintr(arg)
+ void *arg;
+{
+ struct fooipsoftc *sc = arg;
+
+ if (sc->sc_ipicsc->sc_ipic->ipic_irq[sc->sc_slot][0] & IPIC_IRQ_INT) {
+ /* clear interrupt on device */
+ return (1);
+ }
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/i82586.h b/sys/arch/mvme68k/dev/i82586.h
new file mode 100644
index 00000000000..cb40672da90
--- /dev/null
+++ b/sys/arch/mvme68k/dev/i82586.h
@@ -0,0 +1,286 @@
+/* $NetBSD: i82586.h,v 1.3 1995/01/27 09:49:55 pk Exp $ */
+
+/*-
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ *
+ * Sun support added by Charles D. Cranor, 25-Oct-94
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_char mbz1[3]; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[4]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char mbz1[1];
+ u_char ie_busy; /* zeroed after init */
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND SWAP(0x0070) /* mask for RU command */
+#define IE_RU_NOP SWAP(0) /* for completeness */
+#define IE_RU_START SWAP(0x0010) /* start receive unit command */
+#define IE_RU_ENABLE SWAP(0x0020) /* enable receiver command */
+#define IE_RU_DISABLE SWAP(0x0030) /* disable receiver command */
+#define IE_RU_ABORT SWAP(0x0040) /* abort current receive operation */
+
+#define IE_CU_COMMAND SWAP(0x0700) /* mask for CU command */
+#define IE_CU_NOP SWAP(0) /* included for completeness */
+#define IE_CU_START SWAP(0x0100) /* do-command command */
+#define IE_CU_RESUME SWAP(0x0200) /* resume a suspended cmd list */
+#define IE_CU_STOP SWAP(0x0300) /* SUSPEND was already taken */
+#define IE_CU_ABORT SWAP(0x0400) /* abort current command */
+
+#define IE_ACK_COMMAND SWAP(0xf000) /* mask for ACK command */
+#define IE_ACK_CX SWAP(0x8000) /* ack IE_ST_DONE */
+#define IE_ACK_FR SWAP(0x4000) /* ack IE_ST_RECV */
+#define IE_ACK_CNA SWAP(0x2000) /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR SWAP(0x1000) /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE SWAP(0xf000) /* mask for cause of interrupt */
+#define IE_ST_DONE SWAP(0x8000) /* command with I bit completed */
+#define IE_ST_RECV SWAP(0x4000) /* frame received */
+#define IE_ST_ALLDONE SWAP(0x2000) /* all commands completed */
+#define IE_ST_RNR SWAP(0x1000) /* receive not ready */
+
+#define IE_CU_STATUS SWAP(0x700) /* mask for command unit status */
+#define IE_CU_ACTIVE SWAP(0x200) /* command unit is active */
+#define IE_CU_SUSPEND SWAP(0x100) /* command unit is suspended */
+
+#define IE_RU_STATUS SWAP(0x70) /* mask for receiver unit status */
+#define IE_RU_SUSPEND SWAP(0x10) /* receiver is suspended */
+#define IE_RU_NOSPACE SWAP(0x20) /* receiver has no resources */
+#define IE_RU_READY SWAP(0x40) /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST SWAP(0x8000) /* last rfd in list */
+#define IE_FD_SUSP SWAP(0x4000) /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE SWAP(0x8000) /* frame is complete */
+#define IE_FD_BUSY SWAP(0x4000) /* frame is busy */
+#define IE_FD_OK SWAP(0x2000) /* frame is bad */
+#define IE_FD_RNR SWAP(0x0200) /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST SWAP(0x8000) /* last buffer */
+#define IE_RBD_USED SWAP(0x4000) /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL SWAP(0x8000) /* command is completed */
+#define IE_STAT_BUSY SWAP(0x4000) /* command is running now */
+#define IE_STAT_OK SWAP(0x2000) /* command completed successfully */
+#define IE_STAT_ABORT SWAP(0x1000) /* command was aborted */
+
+
+#define IE_CMD_NOP SWAP(0x0000) /* NOP */
+#define IE_CMD_IASETUP SWAP(0x0001) /* initial address setup */
+#define IE_CMD_CONFIG SWAP(0x0002) /* configure command */
+#define IE_CMD_MCAST SWAP(0x0003) /* multicast setup command */
+#define IE_CMD_XMIT SWAP(0x0004) /* transmit command */
+#define IE_CMD_TDR SWAP(0x0005) /* time-domain reflectometer command */
+#define IE_CMD_DUMP SWAP(0x0006) /* dump command */
+#define IE_CMD_DIAGNOSE SWAP(0x0007) /* diagnostics command */
+
+#define IE_CMD_LAST SWAP(0x8000) /* this is the last command in the list */
+#define IE_CMD_SUSPEND SWAP(0x4000) /* suspend CU after this command */
+#define IE_CMD_INTR SWAP(0x2000) /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL SWAP(0x000f) /* number of collisions during transmit */
+#define IE_XS_EXCMAX SWAP(0x0020) /* exceeded maximum number of collisions */
+#define IE_XS_SQE SWAP(0x0040) /* SQE positive */
+#define IE_XS_DEFERRED SWAP(0x0080) /* transmission deferred */
+#define IE_XS_UNDERRUN SWAP(0x0100) /* DMA underrun */
+#define IE_XS_LOSTCTS SWAP(0x0200) /* Lost CTS */
+#define IE_XS_NOCARRIER SWAP(0x0400) /* No Carrier */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST SWAP(0x8000) /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 250 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS SWAP(0x8000) /* TDR succeeded without error */
+#define IE_TDR_XCVR SWAP(0x4000) /* detected a transceiver problem */
+#define IE_TDR_OPEN SWAP(0x2000) /* detected an open */
+#define IE_TDR_SHORT SWAP(0x1000) /* TDR detected a short */
+#define IE_TDR_TIME SWAP(0x07ff) /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
diff --git a/sys/arch/mvme68k/dev/if_ie.c b/sys/arch/mvme68k/dev/if_ie.c
new file mode 100644
index 00000000000..e24a121d0e9
--- /dev/null
+++ b/sys/arch/mvme68k/dev/if_ie.c
@@ -0,0 +1,1958 @@
+/* $NetBSD: if_ie.c,v 1.15 1995/04/11 09:18:09 pk Exp $ */
+
+/*-
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1993, 1994, 1995 Charles Hannum.
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1994, 1995, Rafal K. Boni
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, 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 Charles Hannum, by the
+ * University of Vermont and State Agricultural College and Garrett A.
+ * Wollman, by William F. Jolitz, and by the University of California,
+ * Berkeley, Lawrence Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * 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 UNIVERSITY OR AUTHORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Original StarLAN driver written by Garrett Wollman with reference to the
+ * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
+ *
+ * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
+ *
+ * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
+ *
+ * Majorly cleaned up and 3C507 code merged by Charles Hannum.
+ *
+ * Converted to SUN ie driver by Charles D. Cranor,
+ * October 1994, January 1995.
+ * This sun version based on i386 version 1.30.
+ */
+
+extern void *etherbuf;
+extern int etherlen;
+
+/*
+Mode of operation:
+
+ We run the 82586 in a standard Ethernet mode. We keep NFRAMES
+ received frame descriptors around for the receiver to use, and
+ NRXBUF associated receive buffer descriptors, both in a circular
+ list. Whenever a frame is received, we rotate both lists as
+ necessary. (The 586 treats both lists as a simple queue.) We also
+ keep a transmit command around so that packets can be sent off
+ quickly.
+
+ We configure the adapter in AL-LOC = 1 mode, which means that the
+ Ethernet/802.3 MAC header is placed at the beginning of the receive
+ buffer rather than being split off into various fields in the RFD.
+ This also means that we must include this header in the transmit
+ buffer as well.
+
+ By convention, all transmit commands, and only transmit commands,
+ shall have the I (IE_CMD_INTR) bit set in the command. This way,
+ when an interrupt arrives at ieintr(), it is immediately possible
+ to tell what precisely caused it. ANY OTHER command-sending
+ routines should run at splimp(), and should post an acknowledgement
+ to every interrupt they generate.
+
+*/
+
+#include "bpfilter.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/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#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
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <vm/vm.h>
+
+/*
+ * ugly byte-order hack for SUNs
+ */
+
+#define SWAP(x) (x)
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+#include <mvme68k/dev/if_ie.h>
+#include <mvme68k/dev/i82586.h>
+
+static struct mbuf *last_not_for_us;
+vm_map_t ie_map; /* for obio */
+
+#define IED_RINT 0x01
+#define IED_TINT 0x02
+#define IED_RNR 0x04
+#define IED_CNA 0x08
+#define IED_READFRAME 0x10
+#define IED_ALL 0x1f
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+#define B_PER_F 3 /* recv buffers per frame */
+#define MXFRAMES 300 /* max number of recv frames */
+#define MXRXBUF (MXFRAMES*B_PER_F) /* number of buffers to allocate */
+#define IE_RBUF_SIZE 256 /* size of each receive buffer;
+ MUST BE POWER OF TWO */
+#define NTXBUF 2 /* number of transmit commands */
+#define IE_TBUF_SIZE ETHER_MAX_LEN /* length of transmit buffer */
+
+
+/*
+ * Ethernet status, per interface.
+ *
+ * hardware addresses/sizes to know (all KVA):
+ * sc_iobase = base of chip's 24 bit address space
+ * sc_maddr = base address of chip RAM as stored in ie_base of iscp
+ * sc_msize = size of chip's RAM
+ * sc_reg = address of card dependent registers
+ *
+ * the chip uses two types of pointers: 16 bit and 24 bit
+ * 16 bit pointers are offsets from sc_maddr/ie_base
+ * KVA(16 bit offset) = offset + sc_maddr
+ * 24 bit pointers are offset from sc_iobase in KVA
+ * KVA(24 bit address) = address + sc_iobase
+ *
+ * on the vme/multibus we have the page map to control where ram appears
+ * in the address space. we choose to have RAM start at 0 in the
+ * 24 bit address space. this means that sc_iobase == sc_maddr!
+ * to get the phyiscal address of the board's RAM you must take the
+ * top 12 bits of the physical address of the register address
+ * and or in the 4 bits from the status word as bits 17-20 (remember that
+ * the board ignores the chip's top 4 address lines).
+ * For example:
+ * if the register is @ 0xffe88000, then the top 12 bits are 0xffe00000.
+ * to get the 4 bits from the the status word just do status & IEVME_HADDR.
+ * suppose the value is "4". Then just shift it left 16 bits to get
+ * it into bits 17-20 (e.g. 0x40000). Then or it to get the
+ * address of RAM (in our example: 0xffe40000). see the attach routine!
+ *
+ * on the onboard ie interface the 24 bit address space is hardwired
+ * to be 0xff000000 -> 0xffffffff of KVA. this means that sc_iobase
+ * will be 0xff000000. sc_maddr will be where ever we allocate RAM
+ * in KVA. note that since the SCP is at a fixed address it means
+ * that we have to allocate a fixed KVA for the SCP.
+ */
+
+struct ie_softc {
+ struct device sc_dev; /* device structure */
+ struct intrhand sc_ih, sc_failih; /* interrupt info */
+ struct evcnt sc_intrcnt; /* # of interrupts, per ie */
+
+ caddr_t sc_iobase; /* KVA of base of 24 bit addr space */
+ caddr_t sc_maddr; /* KVA of base of chip's RAM (16bit addr sp.)*/
+ u_int sc_msize; /* how much RAM we have/use */
+ caddr_t sc_reg; /* KVA of car's register */
+ int sc_bustype;
+
+ struct arpcom sc_arpcom;/* system arpcom structure */
+
+ void (*reset_586)(); /* card dependent reset function */
+ void (*chan_attn)(); /* card dependent attn function */
+ void (*run_586)(); /* card depenent "go on-line" function */
+ void (*memcopy) __P((const void *, void *, u_int));
+ /* card dependent memory copy function */
+ void (*memzero) __P((void *, u_int));
+ /* card dependent memory zero function */
+
+
+ int want_mcsetup; /* mcsetup flag */
+ int promisc; /* are we in promisc mode? */
+
+ /*
+ * pointers to the 3 major control structures
+ */
+
+ volatile struct ie_sys_conf_ptr *scp;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+
+ /*
+ * pointer and size of a block of KVA where the buffers
+ * are to be allocated from
+ */
+
+ caddr_t buf_area;
+ int buf_area_sz;
+
+ /*
+ * the actual buffers (recv and xmit)
+ */
+
+ volatile struct ie_recv_frame_desc *rframes[MXFRAMES];
+ volatile struct ie_recv_buf_desc *rbuffs[MXRXBUF];
+ volatile char *cbuffs[MXRXBUF];
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF];
+ volatile struct ie_xmit_buf *xmit_buffs[NTXBUF];
+ u_char *xmit_cbuffs[NTXBUF];
+ int xmit_busy;
+ int xmit_free;
+ int xchead, xctail;
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+ int nframes; /* number of frames in use */
+ int nrxbuf; /* number of recv buffs in use */
+
+#ifdef IEDEBUG
+ int sc_debug;
+#endif
+#if NMC > 0
+ struct mcreg *sc_mc;
+#endif
+#if NPCCTWO > 0
+ struct pcctworeg *sc_pcc2;
+#endif
+};
+
+static void ie_obreset __P((struct ie_softc *));
+static void ie_obattend __P((struct ie_softc *));
+static void ie_obrun __P((struct ie_softc *));
+
+void iewatchdog __P((/* short */));
+int ieintr __P((void *));
+int iefailintr __P((void *));
+int ieinit __P((struct ie_softc *));
+int ieioctl __P((struct ifnet *, u_long, caddr_t));
+void iestart __P((struct ifnet *));
+void iereset __P((struct ie_softc *));
+static void ie_readframe __P((struct ie_softc *, int));
+static void ie_drop_packet_buffer __P((struct ie_softc *));
+static int command_and_wait __P((struct ie_softc *, int,
+ void volatile *, int));
+/*static*/ void ierint __P((struct ie_softc *));
+/*static*/ void ietint __P((struct ie_softc *));
+static int ieget __P((struct ie_softc *, struct mbuf **,
+ struct ether_header *, int *));
+static void setup_bufs __P((struct ie_softc *));
+static int mc_setup __P((struct ie_softc *, void *));
+static void mc_reset __P((struct ie_softc *));
+
+#ifdef IEDEBUG
+void print_rbd __P((volatile struct ie_recv_buf_desc *));
+
+int in_ierint = 0;
+int in_ietint = 0;
+#endif
+
+int iematch();
+void ieattach();
+
+struct cfdriver iecd = {
+ NULL, "ie", iematch, ieattach, DV_IFNET, sizeof(struct ie_softc)
+};
+
+/*
+ * address generation macros
+ * MK_24 = KVA -> 24 bit address in SUN byte order
+ * MK_16 = KVA -> 16 bit address in INTEL byte order
+ * ST_24 = store a 24 bit address in SUN byte order to INTEL byte order
+ */
+#define MK_24(base, ptr) ((caddr_t)((u_long)ptr))
+#define MK_16(base, ptr) SWAP((u_short)( ((u_long)(ptr)) - ((u_long)(base)) ))
+#define ST_24(to, from) { \
+ u_long fval = (u_long)(from); \
+ u_char *t = (u_char *)&(to), *f = (u_char *)&fval; \
+ t[0] = f[2]; t[1] = f[3]; /*t[2] = f[0]*/; t[3] = f[1]; \
+ }
+/*
+ * Here are a few useful functions. We could have done these as macros, but
+ * since we have the inline facility, it makes sense to use that instead.
+ */
+static inline void
+ie_setup_config(cmd, promiscuous, manchester)
+ volatile struct ie_config_cmd *cmd;
+ int promiscuous, manchester;
+{
+
+ cmd->ie_config_count = 0x0c;
+ cmd->ie_fifo = 8;
+ cmd->ie_save_bad = 0x40;
+ cmd->ie_addr_len = 0x2e;
+ cmd->ie_priority = 0;
+ cmd->ie_ifs = 0x60;
+ cmd->ie_slot_low = 0;
+ cmd->ie_slot_high = 0xf2;
+ cmd->ie_promisc = !!promiscuous | manchester << 2;
+ cmd->ie_crs_cdt = 0;
+ cmd->ie_min_len = 64;
+ cmd->ie_junk = 0xff;
+}
+
+static inline void
+ie_ack(sc, mask)
+ struct ie_softc *sc;
+ u_int mask;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+
+ command_and_wait(sc, scb->ie_status & mask, 0, 0);
+}
+
+int
+iematch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ return (!badvaddr(ca->ca_vaddr, 4));
+}
+
+/*
+ * Deep Magic: reset it, then set SCP address again. Pray.
+ */
+void
+ie_obreset(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ieob *ieo = (struct ieob *) sc->sc_reg;
+ volatile int t;
+ u_long a;
+
+ a = IE_PORT_RESET;
+ ieo->porthigh = a & 0xffff;
+ t = 0; t = 1;
+ ieo->portlow = a >> 16;
+ delay(1000);
+
+ a = (u_long)pmap_extract(pmap_kernel(), (vm_offset_t)sc->scp) |
+ IE_PORT_NEWSCPADDR;
+ ieo->porthigh = a & 0xffff;
+ t = 0; t = 1;
+ ieo->portlow = a >> 16;
+ delay(1000);
+}
+
+void
+ie_obattend(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ieob *ieo = (struct ieob *) sc->sc_reg;
+
+ ieo->attn = 1;
+}
+
+void
+ie_obrun(sc)
+ struct ie_softc *sc;
+{
+}
+
+/*
+ * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
+ */
+void
+ieattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct ie_softc *sc = (void *) self;
+ struct confargs *ca = aux;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ extern void myetheraddr(u_char *); /* should be elsewhere */
+ register struct bootpath *bp;
+ int pri = ca->ca_ipl;
+ volatile struct ieob *ieo;
+ vm_offset_t pa;
+
+ sc->reset_586 = ie_obreset;
+ sc->chan_attn = ie_obattend;
+ sc->run_586 = ie_obrun;
+ sc->memcopy = bcopy;
+ sc->memzero = bzero;
+ sc->sc_msize = etherlen;
+ sc->sc_reg = ca->ca_vaddr;
+ ieo = (volatile struct ieob *) sc->sc_reg;
+
+ sc->sc_maddr = etherbuf; /* maddr = vaddr */
+ pa = pmap_extract(pmap_kernel(), (vm_offset_t)sc->sc_maddr);
+ if (pa == 0) panic("ie pmap_extract");
+ sc->sc_iobase = (caddr_t)pa; /* iobase = paddr (24 bit) */
+
+ /*printf("maddrP %x iobaseV %x\n", sc->sc_maddr, sc->sc_iobase);*/
+
+ (sc->memzero)(sc->sc_maddr, sc->sc_msize);
+ sc->iscp = (volatile struct ie_int_sys_conf_ptr *)
+ sc->sc_maddr; /* @ location zero */
+ sc->scb = (volatile struct ie_sys_ctl_block *)
+ roundup((int)sc->iscp + sizeof(struct ie_int_sys_conf_ptr), 16);
+ sc->scp = (struct ie_sys_conf_ptr *)
+ roundup((int)sc->scb + sizeof(struct ie_sys_ctl_block), 16);
+ /*printf("scpV %x iscpV %x scbV %x\n", sc->scp, sc->iscp, sc->scb);*/
+
+ sc->scp->ie_bus_use = 0; /* 16-bit */
+ ST_24(sc->scp->ie_iscp_ptr,
+ pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp));
+
+ /*printf("iscpV(%x) = iscpP(%x) -> scp.ptr@%x = val:%x\n",
+ sc->iscp, pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp),
+ &sc->scp->ie_iscp_ptr, sc->scp->ie_iscp_ptr);*/
+
+ /*
+ * rest of first page is unused (wasted!), rest of ram
+ * for buffers
+ */
+ sc->buf_area = sc->sc_maddr + NBPG;
+ sc->buf_area_sz = sc->sc_msize - NBPG;
+ myetheraddr(sc->sc_arpcom.ac_enaddr);
+
+ if (ie_setupram(sc) == 0) {
+ printf(": RAM CONFIG FAILED!\n");
+ /* XXX should reclaim resources? */
+ return;
+ }
+ ifp->if_unit = sc->sc_dev.dv_unit;
+ ifp->if_name = iecd.cd_name;
+ ifp->if_start = iestart;
+ ifp->if_ioctl = ieioctl;
+ ifp->if_watchdog = iewatchdog;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+
+ sc->sc_bustype = ca->ca_bustype;
+
+ sc->sc_ih.ih_fn = ieintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = pri;
+ sc->sc_failih.ih_fn = iefailintr;
+ sc->sc_failih.ih_arg = sc;
+ sc->sc_failih.ih_ipl = pri;
+
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ mcintr_establish(MCV_IE, &sc->sc_ih);
+ sc->sc_mc = (struct mcreg *)ca->ca_master;
+ sc->sc_mc->mc_ieirq = pri | MC_SC_SNOOP | MC_IRQ_IEN |
+ MC_IRQ_ICLR;
+ mcintr_establish(MCV_IEFAIL, &sc->sc_failih);
+ sc->sc_mc->mc_iefailirq = pri | MC_IRQ_IEN | MC_IRQ_ICLR;
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ pcctwointr_establish(PCC2V_IE, &sc->sc_ih);
+ sc->sc_pcc2 = (struct pcctworeg *)ca->ca_master;
+ sc->sc_pcc2->pcc2_ieirq = pri | PCC2_SC_SNOOP |
+ PCC2_IRQ_IEN | PCC2_IRQ_ICLR;
+ pcctwointr_establish(PCC2V_IEFAIL, &sc->sc_failih);
+ sc->sc_pcc2->pcc2_iefailirq = pri | PCC2_IRQ_IEN |
+ PCC2_IRQ_ICLR;
+ break;
+#endif
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to generate
+ * an interrupt after a transmit has been started on it.
+ */
+void
+iewatchdog(unit)
+ short unit;
+{
+ struct ie_softc *sc = iecd.cd_devs[unit];
+
+ log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+ ++sc->sc_arpcom.ac_if.if_oerrors;
+
+ iereset(sc);
+}
+
+int
+iefailintr(v)
+void *v;
+{
+ struct ie_softc *sc = v;
+
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ sc->sc_mc->mc_ieirq |= MC_IRQ_ICLR; /* safe: clear irq */
+ sc->sc_mc->mc_iefailirq |= MC_IRQ_ICLR; /* clear failure */
+ sc->sc_mc->mc_ieerr = MC_IEERR_SCLR; /* reset error */
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sc->sc_pcc2->pcc2_ieirq |= PCC2_IRQ_ICLR; /* safe: clear irq */
+ sc->sc_pcc2->pcc2_iefailirq |= PCC2_IRQ_ICLR; /* clear failure */
+ sc->sc_pcc2->pcc2_ieerr = PCC2_IEERR_SCLR; /* reset error */
+ break;
+#endif
+ }
+
+ iereset(sc);
+ return (1);
+}
+
+/*
+ * What to do upon receipt of an interrupt.
+ */
+int
+ieintr(v)
+void *v;
+{
+ struct ie_softc *sc = v;
+ register u_short status;
+
+ status = sc->scb->ie_status;
+/*printf("I");*/
+
+loop:
+ /* Ack interrupts FIRST in case we receive more during the ISR. */
+ ie_ack(sc, IE_ST_WHENCE & status);
+ switch (sc->sc_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ sc->sc_mc->mc_ieirq |= MC_IRQ_ICLR; /* clear irq */
+ break;
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ sc->sc_pcc2->pcc2_ieirq |= PCC2_IRQ_ICLR; /* clear irq */
+ break;
+#endif
+ }
+
+ if (status & (IE_ST_RECV | IE_ST_RNR)) {
+#ifdef IEDEBUG
+ in_ierint++;
+ if (sc->sc_debug & IED_RINT)
+ printf("%s: rint\n", sc->sc_dev.dv_xname);
+#endif
+ ierint(sc);
+#ifdef IEDEBUG
+ in_ierint--;
+#endif
+ }
+
+ if (status & IE_ST_DONE) {
+#ifdef IEDEBUG
+ in_ietint++;
+ if (sc->sc_debug & IED_TINT)
+ printf("%s: tint\n", sc->sc_dev.dv_xname);
+#endif
+ ietint(sc);
+#ifdef IEDEBUG
+ in_ietint--;
+#endif
+ }
+
+ if (status & IE_ST_RNR) {
+ printf("%s: receiver not ready\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ iereset(sc);
+ }
+
+#ifdef IEDEBUG
+ if ((status & IE_ST_ALLDONE) && (sc->sc_debug & IED_CNA))
+ printf("%s: cna\n", sc->sc_dev.dv_xname);
+#endif
+
+ if ((status = sc->scb->ie_status) & IE_ST_WHENCE)
+ goto loop;
+
+ sc->sc_intrcnt.ev_count++;
+ return 1;
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+void
+ierint(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ int i, status;
+ static int timesthru = 1024;
+
+ i = sc->rfhead;
+ for (;;) {
+ status = sc->rframes[i]->ie_fd_status;
+
+ if ((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
+ sc->sc_arpcom.ac_if.if_ipackets++;
+ if (!--timesthru) {
+ sc->sc_arpcom.ac_if.if_ierrors +=
+ SWAP(scb->ie_err_crc) +
+ SWAP(scb->ie_err_align) +
+ SWAP(scb->ie_err_resource) +
+ SWAP(scb->ie_err_overrun);
+ scb->ie_err_crc = scb->ie_err_align =
+ scb->ie_err_resource = scb->ie_err_overrun =
+ 0;
+ timesthru = 1024;
+ }
+ ie_readframe(sc, i);
+ } else {
+ if ((status & IE_FD_RNR) != 0 &&
+ (scb->ie_status & IE_RU_READY) == 0) {
+ sc->rframes[0]->ie_fd_buf_desc =
+ MK_16(sc->sc_maddr, sc->rbuffs[0]);
+ scb->ie_recv_list =
+ MK_16(sc->sc_maddr, sc->rframes[0]);
+ command_and_wait(sc, IE_RU_START, 0, 0);
+ }
+ break;
+ }
+ i = (i + 1) % sc->nframes;
+ }
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by the
+ * transmission of frames. This routine is deceptively simple, since most of
+ * the real work is done by iestart().
+ */
+void
+ietint(sc)
+ struct ie_softc *sc;
+{
+ int status;
+
+ sc->sc_arpcom.ac_if.if_timer = 0;
+ sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ status = sc->xmit_cmds[sc->xctail]->ie_xmit_status;
+
+ if (!(status & IE_STAT_COMPL) || (status & IE_STAT_BUSY))
+ printf("ietint: command still busy!\n");
+
+ if (status & IE_STAT_OK) {
+ sc->sc_arpcom.ac_if.if_opackets++;
+ sc->sc_arpcom.ac_if.if_collisions +=
+ SWAP(status & IE_XS_MAXCOLL);
+ } else if (status & IE_STAT_ABORT) {
+ printf("%s: send aborted\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_NOCARRIER) {
+ printf("%s: no carrier\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_LOSTCTS) {
+ printf("%s: lost CTS\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_UNDERRUN) {
+ printf("%s: DMA underrun\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ } else if (status & IE_XS_EXCMAX) {
+ printf("%s: too many collisions\n", sc->sc_dev.dv_xname);
+ sc->sc_arpcom.ac_if.if_collisions += 16;
+ sc->sc_arpcom.ac_if.if_oerrors++;
+ }
+
+ /*
+ * If multicast addresses were added or deleted while transmitting,
+ * mc_reset() set the want_mcsetup flag indicating that we should do
+ * it.
+ */
+ if (sc->want_mcsetup) {
+ mc_setup(sc, (caddr_t)sc->xmit_cbuffs[sc->xctail]);
+ sc->want_mcsetup = 0;
+ }
+
+ /* Done with the buffer. */
+ sc->xmit_free++;
+ sc->xmit_busy = 0;
+ sc->xctail = (sc->xctail + 1) % NTXBUF;
+
+ iestart(&sc->sc_arpcom.ac_if);
+}
+
+/*
+ * Compare two Ether/802 addresses for equality, inlined and unrolled for
+ * speed. I'd love to have an inline assembler version of this...
+ */
+static inline int
+ether_equal(one, two)
+ u_char *one, *two;
+{
+
+ if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] ||
+ one[3] != two[3] || one[4] != two[4] || one[5] != two[5])
+ return 0;
+ return 1;
+}
+
+/*
+ * Check for a valid address. to_bpf is filled in with one of the following:
+ * 0 -> BPF doesn't get this packet
+ * 1 -> BPF does get this packet
+ * 2 -> BPF does get this packet, but we don't
+ * Return value is true if the packet is for us, and false otherwise.
+ *
+ * This routine is a mess, but it's also critical that it be as fast
+ * as possible. It could be made cleaner if we can assume that the
+ * only client which will fiddle with IFF_PROMISC is BPF. This is
+ * probably a good assumption, but we do not make it here. (Yet.)
+ */
+static inline int
+check_eh(sc, eh, to_bpf)
+ struct ie_softc *sc;
+ struct ether_header *eh;
+ int *to_bpf;
+{
+ int i;
+
+ switch(sc->promisc) {
+ case IFF_ALLMULTI:
+ /*
+ * Receiving all multicasts, but no unicasts except those
+ * destined for us.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0); /* BPF gets this packet if anybody cares */
+#endif
+ if (eh->ether_dhost[0] & 1)
+ return 1;
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) return 1;
+ return 0;
+
+ case IFF_PROMISC:
+ /*
+ * Receiving all packets. These need to be passed on to BPF.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ /* If for us, accept and hand up to BPF */
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) return 1;
+
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 2; /* we don't need to see it */
+#endif
+
+ /*
+ * Not a multicast, so BPF wants to see it but we don't.
+ */
+ if (!(eh->ether_dhost[0] & 1))
+ return 1;
+
+ /*
+ * If it's one of our multicast groups, accept it and pass it
+ * up.
+ */
+ for (i = 0; i < sc->mcast_count; i++) {
+ if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) {
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 1;
+#endif
+ return 1;
+ }
+ }
+ return 1;
+
+ case IFF_ALLMULTI | IFF_PROMISC:
+ /*
+ * Acting as a multicast router, and BPF running at the same
+ * time. Whew! (Hope this is a fast machine...)
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ /* We want to see multicasts. */
+ if (eh->ether_dhost[0] & 1)
+ return 1;
+
+ /* We want to see our own packets */
+ if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
+ return 1;
+
+ /* Anything else goes to BPF but nothing else. */
+#if NBPFILTER > 0
+ if (*to_bpf)
+ *to_bpf = 2;
+#endif
+ return 1;
+
+ default:
+ /*
+ * Only accept unicast packets destined for us, or multicasts
+ * for groups that we belong to. For now, we assume that the
+ * '586 will only return packets that we asked it for. This
+ * isn't strictly true (it uses hashing for the multicast
+ * filter), but it will do in this case, and we want to get out
+ * of here as quickly as possible.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (sc->sc_arpcom.ac_if.if_bpf != 0);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * We want to isolate the bits that have meaning... This assumes that
+ * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
+ * the size of the buffer, then we are screwed anyway.
+ */
+static inline int
+ie_buflen(sc, head)
+ struct ie_softc *sc;
+ int head;
+{
+
+ return (SWAP(sc->rbuffs[head]->ie_rbd_actual)
+ & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
+}
+
+static inline int
+ie_packet_len(sc)
+ struct ie_softc *sc;
+{
+ int i;
+ int head = sc->rbhead;
+ int acc = 0;
+
+ do {
+ if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef IEDEBUG
+ print_rbd(sc->rbuffs[sc->rbhead]);
+#endif
+ log(LOG_ERR, "%s: receive descriptors out of sync at %d\n",
+ sc->sc_dev.dv_xname, sc->rbhead);
+ iereset(sc);
+ return -1;
+ }
+
+ i = sc->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
+
+ acc += ie_buflen(sc, head);
+ head = (head + 1) % sc->nrxbuf;
+ } while (!i);
+
+ return acc;
+}
+
+/*
+ * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
+ * command to the chip to be executed. On the way, if we have a BPF listener
+ * also give him a copy.
+ */
+inline static void
+iexmit(sc)
+ struct ie_softc *sc;
+{
+
+#if NBPFILTER > 0
+ /*
+ * If BPF is listening on this interface, let it see the packet before
+ * we push it on the wire.
+ */
+ if (sc->sc_arpcom.ac_if.if_bpf)
+ bpf_tap(sc->sc_arpcom.ac_if.if_bpf,
+ sc->xmit_cbuffs[sc->xctail],
+ SWAP(sc->xmit_buffs[sc->xctail]->ie_xmit_flags));
+#endif
+
+/*printf("iexmit base %x cmd %x bfd %x to %x\n",
+sc->sc_maddr,
+sc->xmit_cmds[sc->xctail],
+sc->xmit_buffs[sc->xctail],
+sc->xmit_cbuffs[sc->xctail]);*/
+ sc->xmit_buffs[sc->xctail]->ie_xmit_flags |= IE_XMIT_LAST;
+ sc->xmit_buffs[sc->xctail]->ie_xmit_next = SWAP(0xffff);
+ ST_24(sc->xmit_buffs[sc->xctail]->ie_xmit_buf,
+ MK_24(sc->sc_iobase, sc->xmit_cbuffs[sc->xctail]));
+
+ sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = SWAP(0xffff);
+ sc->xmit_cmds[sc->xctail]->com.ie_cmd_cmd =
+ IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
+
+ sc->xmit_cmds[sc->xctail]->ie_xmit_status = SWAP(0);
+ sc->xmit_cmds[sc->xctail]->ie_xmit_desc =
+ MK_16(sc->sc_maddr, sc->xmit_buffs[sc->xctail]);
+
+ sc->scb->ie_command_list =
+ MK_16(sc->sc_maddr, sc->xmit_cmds[sc->xctail]);
+ command_and_wait(sc, IE_CU_START, 0, 0);
+
+ sc->xmit_busy = 1;
+ sc->sc_arpcom.ac_if.if_timer = 5;
+}
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static inline int
+ieget(sc, mp, ehp, to_bpf)
+ struct ie_softc *sc;
+ struct mbuf **mp;
+ struct ether_header *ehp;
+ int *to_bpf;
+{
+ struct mbuf *m, *top, **mymp;
+ int i;
+ int offset;
+ int totlen, resid;
+ int thismboff;
+ int head;
+
+ totlen = ie_packet_len(sc);
+ if (totlen <= 0)
+ return -1;
+
+ i = sc->rbhead;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ (sc->memcopy)((caddr_t)sc->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
+
+ /*
+ * As quickly as possible, check if this packet is for us.
+ * If not, don't waste a single cycle copying the rest of the
+ * packet in.
+ * This is only a consideration when FILTER is defined; i.e., when
+ * we are either running BPF or doing multicasting.
+ */
+ if (!check_eh(sc, ehp, to_bpf)) {
+ ie_drop_packet_buffer(sc);
+ sc->sc_arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
+ return -1;
+ }
+ totlen -= (offset = sizeof *ehp);
+
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ if (!*mp) {
+ ie_drop_packet_buffer(sc);
+ return -1;
+ }
+
+ m = *mp;
+ m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
+ m->m_len = MHLEN;
+ resid = m->m_pkthdr.len = totlen;
+ top = 0;
+ mymp = &top;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ do { /* while (resid > 0) */
+ /*
+ * Try to allocate an mbuf to hold the data that we have. If
+ * we already allocated one, just get another one and stick it
+ * on the end (eventually). If we don't already have one, try
+ * to allocate an mbuf cluster big enough to hold the whole
+ * packet, if we think it's reasonable, or a single mbuf which
+ * may or may not be big enough.
+ * Got that?
+ */
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (!m) {
+ m_freem(top);
+ ie_drop_packet_buffer(sc);
+ return -1;
+ }
+ m->m_len = MLEN;
+ }
+
+ if (resid >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = min(resid, MCLBYTES);
+ } else {
+ if (resid < m->m_len) {
+ if (!top && resid + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = resid;
+ }
+ }
+ resid -= m->m_len;
+ *mymp = m;
+ mymp = &m->m_next;
+ } while (resid > 0);
+
+ resid = totlen;
+ m = top;
+ thismboff = 0;
+ head = sc->rbhead;
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures at
+ * or after this point.
+ */
+ while (resid > 0) { /* while there's stuff left */
+ int thislen = ie_buflen(sc, head) - offset;
+
+ /*
+ * If too much data for the current mbuf, then fill the current
+ * one up, go to the next one, and try again.
+ */
+ if (thislen > m->m_len - thismboff) {
+ int newlen = m->m_len - thismboff;
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)newlen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, so no offset */
+ offset += newlen; /* we are now this far
+ into the packet */
+ resid -= newlen; /* so there is this much
+ left to get */
+ continue;
+ }
+
+ /*
+ * If there is more than enough space in the mbuf to hold the
+ * contents of this buffer, copy everything in, advance
+ * pointers and so on.
+ */
+ if (thislen < m->m_len - thismboff) {
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)thislen);
+ thismboff += thislen; /* we are this far into the mbuf */
+ resid -= thislen; /* and this much is left */
+ goto nextbuf;
+ }
+
+ /*
+ * Otherwise, there is exactly enough space to put this
+ * buffer's contents into the current mbuf. Do the combination
+ * of the above actions.
+ */
+ (sc->memcopy)((caddr_t)(sc->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (u_int)thislen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, start at the beginning */
+ resid -= thislen; /* and we are this far through */
+
+ /*
+ * Advance all the pointers. We can get here from either of
+ * the last two cases, but never the first.
+ */
+ nextbuf:
+ offset = 0;
+ sc->rbuffs[head]->ie_rbd_actual = SWAP(0);
+ sc->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
+ sc->rbhead = head = (head + 1) % sc->nrxbuf;
+ sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy, we
+ * have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return 0;
+}
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from the list
+ * of RBD, then rotates the RBD and RFD lists so that the receiver doesn't
+ * start complaining. Trailers are DROPPED---there's no point in wasting time
+ * on confusing code to deal with them. Hopefully, this machine will never ARP
+ * for trailers anyway.
+ */
+static void
+ie_readframe(sc, num)
+ struct ie_softc *sc;
+ int num; /* frame number to read */
+{
+ int status;
+ struct mbuf *m = 0;
+ struct ether_header eh;
+#if NBPFILTER > 0
+ int bpf_gets_it = 0;
+#endif
+
+ status = sc->rframes[num]->ie_fd_status;
+
+ /* Immediately advance the RFD list, since we have copied ours now. */
+ sc->rframes[num]->ie_fd_status = SWAP(0);
+ sc->rframes[num]->ie_fd_last |= IE_FD_LAST;
+ sc->rframes[sc->rftail]->ie_fd_last &= ~IE_FD_LAST;
+ sc->rftail = (sc->rftail + 1) % sc->nframes;
+ sc->rfhead = (sc->rfhead + 1) % sc->nframes;
+
+ if (status & IE_FD_OK) {
+#if NBPFILTER > 0
+ if (ieget(sc, &m, &eh, &bpf_gets_it)) {
+#else
+ if (ieget(sc, &m, &eh, 0)) {
+#endif
+ sc->sc_arpcom.ac_if.if_ierrors++;
+ return;
+ }
+ }
+
+#ifdef IEDEBUG
+ if (sc->sc_debug & IED_READFRAME)
+ printf("%s: frame from ether %s type %x\n", sc->sc_dev.dv_xname,
+ ether_sprintf(eh.ether_shost), (u_int)eh.ether_type);
+#endif
+
+ if (!m)
+ return;
+
+ if (last_not_for_us) {
+ m_freem(last_not_for_us);
+ last_not_for_us = 0;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check for a BPF filter; if so, hand it up.
+ * Note that we have to stick an extra mbuf up front, because bpf_mtap
+ * expects to have the ether header at the front.
+ * It doesn't matter that this results in an ill-formatted mbuf chain,
+ * since BPF just looks at the data. (It doesn't try to free the mbuf,
+ * tho' it will make a copy for tcpdump.)
+ */
+ if (bpf_gets_it) {
+ struct mbuf m0;
+ m0.m_len = sizeof eh;
+ m0.m_data = (caddr_t)&eh;
+ m0.m_next = m;
+
+ /* Pass it up. */
+ bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, &m0);
+ }
+ /*
+ * A signal passed up from the filtering code indicating that the
+ * packet is intended for BPF but not for the protocol machinery.
+ * We can save a few cycles by not handing it off to them.
+ */
+ if (bpf_gets_it == 2) {
+ last_not_for_us = m;
+ return;
+ }
+#endif /* NBPFILTER > 0 */
+
+ /*
+ * In here there used to be code to check destination addresses upon
+ * receipt of a packet. We have deleted that code, and replaced it
+ * with code to check the address much earlier in the cycle, before
+ * copying the data in; this saves us valuable cycles when operating
+ * as a multicast router or when using BPF.
+ */
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input(&sc->sc_arpcom.ac_if, &eh, m);
+}
+
+static void
+ie_drop_packet_buffer(sc)
+ struct ie_softc *sc;
+{
+ int i;
+
+ do {
+ /*
+ * This means we are somehow out of sync. So, we reset the
+ * adapter.
+ */
+ if (!(sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef IEDEBUG
+ print_rbd(sc->rbuffs[sc->rbhead]);
+#endif
+ log(LOG_ERR, "%s: receive descriptors out of sync at %d\n",
+ sc->sc_dev.dv_xname, sc->rbhead);
+ iereset(sc);
+ return;
+ }
+
+ i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST;
+
+ sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST;
+ sc->rbuffs[sc->rbhead]->ie_rbd_actual = SWAP(0);
+ sc->rbhead = (sc->rbhead + 1) % sc->nrxbuf;
+ sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
+ } while (!i);
+}
+
+
+/*
+ * Start transmission on an interface.
+ */
+void
+iestart(ifp)
+ struct ifnet *ifp;
+{
+ struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct mbuf *m0, *m;
+ u_char *buffer;
+ u_short len;
+
+/*printf("iestart\n");*/
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return;
+
+ if (sc->xmit_free == 0) {
+ ifp->if_flags |= IFF_OACTIVE;
+ if (!sc->xmit_busy)
+ iexmit(sc);
+ return;
+ }
+
+ do {
+ IF_DEQUEUE(&sc->sc_arpcom.ac_if.if_snd, m);
+ if (!m)
+ break;
+
+ len = 0;
+ buffer = sc->xmit_cbuffs[sc->xchead];
+
+ for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE;
+ m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+ if (m)
+ printf("%s: tbuf overflow\n", sc->sc_dev.dv_xname);
+
+ m_freem(m0);
+ len = max(len, ETHER_MIN_LEN);
+ sc->xmit_buffs[sc->xchead]->ie_xmit_flags = SWAP(len);
+
+ sc->xmit_free--;
+ sc->xchead = (sc->xchead + 1) % NTXBUF;
+ } while (sc->xmit_free > 0);
+
+ /* If we stuffed any packets into the card's memory, send now. */
+ if ((sc->xmit_free < NTXBUF) && (!sc->xmit_busy))
+ iexmit(sc);
+
+ return;
+}
+
+/*
+ * set up IE's ram space
+ */
+int
+ie_setupram(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ int s;
+
+ s = splimp();
+
+ iscp = sc->iscp;
+ (sc->memzero)((char *) iscp, sizeof *iscp);
+
+ scb = sc->scb;
+ (sc->memzero)((char *) scb, sizeof *scb);
+
+ iscp->ie_busy = 1; /* ie_busy == char */
+ iscp->ie_scb_offset = MK_16(sc->sc_maddr, scb);
+ ST_24(iscp->ie_base, sc->sc_iobase);
+
+ (sc->reset_586) (sc);
+ (sc->chan_attn) (sc);
+
+ delay(100); /* wait a while... */
+
+ if (iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+ /*
+ * Acknowledge any interrupts we may have caused...
+ */
+ ie_ack(sc, IE_ST_WHENCE);
+ splx(s);
+
+ return 1;
+}
+
+void
+iereset(sc)
+ struct ie_softc *sc;
+{
+ int s = splimp();
+
+ printf("%s: reset\n", sc->sc_dev.dv_xname);
+
+ /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
+ sc->sc_arpcom.ac_if.if_flags &= ~(IFF_UP | IFF_OACTIVE);
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if (command_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
+ printf("%s: abort commands timed out\n", sc->sc_dev.dv_xname);
+
+ if (command_and_wait(sc, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
+ printf("%s: disable commands timed out\n", sc->sc_dev.dv_xname);
+
+#ifdef notdef
+ if (!check_ie_present(sc, sc->sc_maddr, sc->sc_msize))
+ panic("ie disappeared!\n");
+#endif
+
+ sc->sc_arpcom.ac_if.if_flags |= IFF_UP;
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ splx(s);
+}
+
+/*
+ * This is called if we time out.
+ */
+static void
+chan_attn_timeout(rock)
+ caddr_t rock;
+{
+
+ *(int *)rock = 1;
+}
+
+/*
+ * Send a command to the controller and wait for it to either complete
+ * or be accepted, depending on the command. If the command pointer
+ * is null, then pretend that the command is not an action command.
+ * If the command pointer is not null, and the command is an action
+ * command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
+ */
+static int
+command_and_wait(sc, cmd, pcmd, mask)
+ struct ie_softc *sc;
+ int cmd;
+ volatile void *pcmd;
+ int mask;
+{
+ volatile struct ie_cmd_common *cc = pcmd;
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ volatile int timedout = 0;
+ extern int hz;
+
+ scb->ie_command = (u_short)cmd;
+
+ if (IE_ACTION_COMMAND(cmd) && pcmd) {
+ (sc->chan_attn)(sc);
+
+#if 0
+ /*
+ * XXX
+ * I don't think this timeout works on suns.
+ * we are at splimp() in the loop, and the timeout
+ * stuff runs at software spl (so it is masked off?).
+ */
+
+ /*
+ * According to the packet driver, the minimum timeout should
+ * be .369 seconds, which we round up to .4.
+ */
+ timeout(chan_attn_timeout, (caddr_t)&timedout, 2 * hz / 5);
+#endif
+
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, but I haven't figured out how, or indeed if, we
+ * can put the process waiting for action to sleep. (We may
+ * be getting called through some other timeout running in the
+ * kernel.)
+ */
+ for (;;)
+ if ((cc->ie_cmd_status & mask) || timedout)
+ break;
+#if 0
+ untimeout(chan_attn_timeout, (caddr_t)&timedout);
+#endif
+
+ return timedout;
+ } else {
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ (sc->chan_attn)(sc);
+
+ while (scb->ie_command)
+ ; /* XXX spin lock */
+
+ return 0;
+ }
+}
+
+/*
+ * Run the time-domain reflectometer.
+ */
+static void
+run_tdr(sc, cmd)
+ struct ie_softc *sc;
+ struct ie_tdr_cmd *cmd;
+{
+ int result;
+
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->ie_tdr_time = SWAP(0);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK))
+ result = 0x10000; /* XXX */
+ else
+ result = cmd->ie_tdr_time;
+
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if (result & IE_TDR_SUCCESS)
+ return;
+
+ if (result & 0x10000)
+ printf("%s: TDR command failed\n", sc->sc_dev.dv_xname);
+ else if (result & IE_TDR_XCVR)
+ printf("%s: transceiver problem\n", sc->sc_dev.dv_xname);
+ else if (result & IE_TDR_OPEN)
+ printf("%s: TDR detected an open %d clocks away\n",
+ sc->sc_dev.dv_xname, result & IE_TDR_TIME);
+ else if (result & IE_TDR_SHORT)
+ printf("%s: TDR detected a short %d clocks away\n",
+ sc->sc_dev.dv_xname, result & IE_TDR_TIME);
+ else
+ printf("%s: TDR returned unknown status %x\n",
+ sc->sc_dev.dv_xname, result);
+}
+
+#ifdef notdef
+/* ALIGN works on 8 byte boundaries.... but 4 byte boundaries are ok for sun */
+#define _ALLOC(p, n) (bzero(p, n), p += n, p - n)
+#define ALLOC(p, n) _ALLOC(p, ALIGN(n)) /* XXX convert to this? */
+#endif
+
+static inline caddr_t
+Align(ptr)
+ caddr_t ptr;
+{
+ u_long l = (u_long)ptr;
+
+ l = (l + 3) & ~3L;
+ return (caddr_t)l;
+}
+
+/*
+ * setup_bufs: set up the buffers
+ *
+ * we have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
+ * this is to be used for the buffers. the chip indexs its control data
+ * structures with 16 bit offsets, and it indexes actual buffers with
+ * 24 bit addresses. so we should allocate control buffers first so that
+ * we don't overflow the 16 bit offset field. The number of transmit
+ * buffers is fixed at compile time.
+ *
+ * note: this function was written to be easy to understand, rather than
+ * highly efficient (it isn't in the critical path).
+ */
+static void
+setup_bufs(sc)
+ struct ie_softc *sc;
+{
+ caddr_t ptr = sc->buf_area; /* memory pool */
+ volatile struct ie_recv_frame_desc *rfd = (void *) ptr;
+ volatile struct ie_recv_buf_desc *rbd;
+ int n, r;
+
+ /*
+ * step 0: zero memory and figure out how many recv buffers and
+ * frames we can have. XXX CURRENTLY HARDWIRED AT MAX
+ */
+ (sc->memzero)(ptr, sc->buf_area_sz);
+ ptr = Align(ptr); /* set alignment and stick with it */
+
+ n = (int)Align(sizeof(struct ie_xmit_cmd)) +
+ (int)Align(sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE;
+ n *= NTXBUF; /* n = total size of xmit area */
+
+ n = sc->buf_area_sz - n;/* n = free space for recv stuff */
+
+ r = (int)Align(sizeof(struct ie_recv_frame_desc)) +
+ (((int)Align(sizeof(struct ie_recv_buf_desc)) + IE_RBUF_SIZE) * B_PER_F);
+
+ /* r = size of one R frame */
+
+ sc->nframes = n / r;
+ if (sc->nframes <= 0)
+ panic("ie: bogus buffer calc\n");
+ if (sc->nframes > MXFRAMES)
+ sc->nframes = MXFRAMES;
+
+ sc->nrxbuf = sc->nframes * B_PER_F;
+
+#ifdef IEDEBUG
+ printf("IEDEBUG: %d frames %d bufs\n", sc->nframes, sc->nrxbuf);
+#endif
+
+ /*
+ * step 1a: lay out and zero frame data structures for transmit and recv
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_cmds[n] = (volatile struct ie_xmit_cmd *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_xmit_cmd));
+ }
+
+ for (n = 0; n < sc->nframes; n++) {
+ sc->rframes[n] = (volatile struct ie_recv_frame_desc *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_recv_frame_desc));
+ }
+
+ /*
+ * step 1b: link together the recv frames and set EOL on last one
+ */
+ for (n = 0; n < sc->nframes; n++) {
+ sc->rframes[n]->ie_fd_next =
+ MK_16(sc->sc_maddr, sc->rframes[(n + 1) % sc->nframes]);
+ }
+ sc->rframes[sc->nframes - 1]->ie_fd_last |= IE_FD_LAST;
+
+ /*
+ * step 2a: lay out and zero frame buffer structures for xmit and recv
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_buffs[n] = (volatile struct ie_xmit_buf *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_xmit_buf));
+ }
+
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->rbuffs[n] = (volatile struct ie_recv_buf_desc *) ptr;
+ ptr = Align(ptr + sizeof(struct ie_recv_buf_desc));
+ }
+
+ /*
+ * step 2b: link together recv bufs and set EOL on last one
+ */
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->rbuffs[n]->ie_rbd_next =
+ MK_16(sc->sc_maddr, sc->rbuffs[(n + 1) % sc->nrxbuf]);
+ }
+ sc->rbuffs[sc->nrxbuf - 1]->ie_rbd_length |= IE_RBD_LAST;
+
+ /*
+ * step 3: allocate the actual data buffers for xmit and recv
+ * recv buffer gets linked into recv_buf_desc list here
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->xmit_cbuffs[n] = (u_char *) ptr;
+ ptr = Align(ptr + IE_TBUF_SIZE);
+ }
+
+ /* Pointers to last packet sent and next available transmit buffer. */
+ sc->xchead = sc->xctail = 0;
+
+ /* Clear transmit-busy flag and set number of free transmit buffers. */
+ sc->xmit_busy = 0;
+ sc->xmit_free = NTXBUF;
+
+ for (n = 0; n < sc->nrxbuf; n++) {
+ sc->cbuffs[n] = (char *) ptr; /* XXX why char vs uchar? */
+ sc->rbuffs[n]->ie_rbd_length = SWAP(IE_RBUF_SIZE);
+ ST_24(sc->rbuffs[n]->ie_rbd_buffer, MK_24(sc->sc_iobase, ptr));
+ ptr = Align(ptr + IE_RBUF_SIZE);
+ }
+
+ /*
+ * step 4: set the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used. link in recv frames
+ * and buffer into the scb.
+ */
+
+ sc->rfhead = 0;
+ sc->rftail = sc->nframes - 1;
+ sc->rbhead = 0;
+ sc->rbtail = sc->nrxbuf - 1;
+
+ sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]);
+ sc->rframes[0]->ie_fd_buf_desc = MK_16(sc->sc_maddr, sc->rbuffs[0]);
+
+#ifdef IEDEBUG
+ printf("IE_DEBUG: reserved %d bytes\n", ptr - sc->buf_area);
+#endif
+}
+
+/*
+ * Run the multicast setup command.
+ * Called at splimp().
+ */
+static int
+mc_setup(sc, ptr)
+ struct ie_softc *sc;
+ void *ptr;
+{
+ volatile struct ie_mcast_cmd *cmd = ptr;
+
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ (sc->memcopy)((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
+ sc->mcast_count * sizeof *sc->mcast_addrs);
+
+ cmd->ie_mcast_bytes =
+ SWAP(sc->mcast_count * ETHER_ADDR_LEN); /* grrr... */
+
+ sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: multicast address setup command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present() and adds
+ * to it all the other structures we need to operate the adapter. This
+ * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
+ * the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
+ */
+int
+ieinit(sc)
+ struct ie_softc *sc;
+{
+ volatile struct ie_sys_ctl_block *scb = sc->scb;
+ void *ptr;
+ int n;
+
+ ptr = sc->buf_area;
+
+ /*
+ * Send the configure command first.
+ */
+ {
+ volatile struct ie_config_cmd *cmd = ptr;
+
+ scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ ie_setup_config(cmd, sc->promisc, 0);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: configure command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ }
+
+ /*
+ * Now send the Individual Address Setup command.
+ */
+ {
+ volatile struct ie_iasetup_cmd *cmd = ptr;
+
+ scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
+ cmd->com.ie_cmd_status = SWAP(0);
+ cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = SWAP(0xffff);
+
+ (sc->memcopy)(sc->sc_arpcom.ac_enaddr,
+ (caddr_t)&cmd->ie_address, sizeof cmd->ie_address);
+
+ if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
+ !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("%s: individual address setup command failed\n",
+ sc->sc_dev.dv_xname);
+ return 0;
+ }
+ }
+
+ /*
+ * Now run the time-domain reflectometer.
+ */
+ run_tdr(sc, ptr);
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(sc, IE_ST_WHENCE);
+
+ /*
+ * Set up the transmit and recv buffers.
+ */
+ setup_bufs(sc);
+
+ sc->sc_arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
+
+ sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]);
+ command_and_wait(sc, IE_RU_START, 0, 0);
+
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if (sc->run_586)
+ (sc->run_586)(sc);
+
+ return 0;
+}
+
+static void
+iestop(sc)
+ struct ie_softc *sc;
+{
+
+ command_and_wait(sc, IE_RU_DISABLE, 0, 0);
+}
+
+int
+ieioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ieinit(sc);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif
+#ifdef NS
+ /* XXX - This code is probably wrong. */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ ieinit(sc);
+ break;
+ }
+#endif /* NS */
+ default:
+ ieinit(sc);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ iestop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ ieinit(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect hardware registers.
+ */
+ iestop(sc);
+ ieinit(sc);
+ }
+#ifdef IEDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ sc->sc_debug = IED_ALL;
+ else
+ sc->sc_debug = 0;
+#endif
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom):
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ mc_reset(sc);
+ error = 0;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return error;
+}
+
+static void
+mc_reset(sc)
+ struct ie_softc *sc;
+{
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Step through the list of addresses.
+ */
+ sc->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
+ while (enm) {
+ if (sc->mcast_count >= MAXMCAST ||
+ bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
+ goto setflag;
+ }
+
+ bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6);
+ sc->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+setflag:
+ sc->want_mcsetup = 1;
+}
+
+#ifdef IEDEBUG
+void
+print_rbd(rbd)
+ volatile struct ie_recv_buf_desc *rbd;
+{
+
+ printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
+ "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
+ rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
+ rbd->mbz);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/if_ie.h b/sys/arch/mvme68k/dev/if_ie.h
new file mode 100644
index 00000000000..a17de666905
--- /dev/null
+++ b/sys/arch/mvme68k/dev/if_ie.h
@@ -0,0 +1,191 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * XXX where else is this from?
+ * if_sunie.h
+ *
+ * sun's ie interface
+ */
+
+/*
+ * programming notes:
+ *
+ * the ie chip operates in a 24 bit address space.
+ *
+ * most ie interfaces appear to be divided into two parts:
+ * - generic 586 stuff
+ * - board specific
+ *
+ * generic:
+ * the generic stuff of the ie chip is all done with data structures
+ * that live in the chip's memory address space. the chip expects
+ * its main data structure (the sys conf ptr -- SCP) to be at a fixed
+ * address in its 24 bit space: 0xfffff4
+ *
+ * the SCP points to another structure called the ISCP.
+ * the ISCP points to another structure called the SCB.
+ * the SCB has a status field, a linked list of "commands", and
+ * a linked list of "receive buffers". these are data structures that
+ * live in memory, not registers.
+ *
+ * board:
+ * to get the chip to do anything, you first put a command in the
+ * command data structure list. then you have to signal "attention"
+ * to the chip to get it to look at the command. how you
+ * signal attention depends on what board you have... on PC's
+ * there is an i/o port number to do this, on sun's there is a
+ * register bit you toggle.
+ *
+ * to get data from the chip you program it to interrupt...
+ *
+ *
+ * sun issues:
+ *
+ * there are 3 kinds of sun "ie" interfaces:
+ * 1 - a VME/multibus card
+ * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's)
+ * 3 - another VME board called the 3E
+ *
+ * the VME boards lives in vme16 space. only 16 and 8 bit accesses
+ * are allowed, so functions that copy data must be aware of this.
+ *
+ * the chip is an intel chip. this means that the byte order
+ * on all the "short"s in the chip's data structures is wrong.
+ * so, constants described in the intel docs are swapped for the sun.
+ * that means that any buffer pointers you give the chip must be
+ * swapped to intel format. yuck.
+ *
+ * VME/multibus interface:
+ * for the multibus interface the board ignores the top 4 bits
+ * of the chip address. the multibus interface seems to have its
+ * own MMU like page map (without protections or valid bits, etc).
+ * there are 256 pages of physical memory on the board (each page
+ * is 1024 bytes). there are 1024 slots in the page map. so,
+ * a 1024 byte page takes up 10 bits of address for the offset,
+ * and if there are 1024 slots in the page that is another 10 bits
+ * of the address. that makes a 20 bit address, and as stated
+ * earlier the board ignores the top 4 bits, so that accounts
+ * for all 24 bits of address.
+ *
+ * note that the last entry of the page map maps the top of the
+ * 24 bit address space and that the SCP is supposed to be at
+ * 0xfffff4 (taking into account allignment). so,
+ * for multibus, that entry in the page map has to be used for the SCP.
+ *
+ * the page map effects BOTH how the ie chip sees the
+ * memory, and how the host sees it.
+ *
+ * the page map is part of the "register" area of the board
+ *
+ * on-board interface:
+ *
+ * <fill in useful info later>
+ *
+ *
+ * VME3E interface:
+ *
+ * <fill in useful info later>
+ *
+ */
+
+/*
+ * PART 1: VME/multibus defs
+ */
+#define IEVME_PAGESIZE 1024 /* bytes */
+#define IEVME_PAGSHIFT 10 /* bits */
+#define IEVME_NPAGES 256 /* number of pages on chip */
+#define IEVME_MAPSZ 1024 /* number of entries in the map */
+
+/*
+ * PTE for the page map
+ */
+#define IEVME_SBORDR 0x8000 /* sun byte order */
+#define IEVME_IBORDR 0x0000 /* intel byte ordr */
+
+#define IEVME_P2MEM 0x2000 /* memory is on P2 */
+#define IEVME_OBMEM 0x0000 /* memory is on board */
+
+#define IEVME_PGMASK 0x0fff /* gives the physical page frame number */
+
+struct ievme {
+ u_short pgmap[IEVME_MAPSZ];
+ u_short xxx[32]; /* prom */
+ u_short status; /* see below for bits */
+ u_short xxx2; /* filler */
+ u_short pectrl; /* parity control (see below) */
+ u_short peaddr; /* low 16 bits of address */
+};
+
+/*
+ * status bits
+ */
+#define IEVME_RESET 0x8000 /* reset board */
+#define IEVME_ONAIR 0x4000 /* go out of loopback 'on-air' */
+#define IEVME_ATTEN 0x2000 /* attention */
+#define IEVME_IENAB 0x1000 /* interrupt enable */
+#define IEVME_PEINT 0x0800 /* parity error interrupt enable */
+#define IEVME_PERR 0x0200 /* parity error flag */
+#define IEVME_INT 0x0100 /* interrupt flag */
+#define IEVME_P2EN 0x0020 /* enable p2 bus */
+#define IEVME_256K 0x0010 /* 256kb rams */
+#define IEVME_HADDR 0x000f /* mask for bits 17-20 of address */
+
+/*
+ * parity control
+ */
+#define IEVME_PARACK 0x0100 /* parity error ack */
+#define IEVME_PARSRC 0x0080 /* parity error source */
+#define IEVME_PAREND 0x0040 /* which end of the data got the error */
+#define IEVME_PARADR 0x000f /* mask to get bits 17-20 of parity address */
+
+
+/*
+ * PART 2: the on-board interface
+ */
+struct ieob {
+ u_short porthigh;
+ u_short portlow;
+ u_long attn;
+};
+#define IE_PORT_NEWSCPADDR 0x00000002
+#define IE_PORT_RESET 0x00000000
+
+#define IEOB_ADBASE 0xff000000 /* KVA base addr of 24 bit address space */
+
+/*
+ * PART 3: the 3E board
+ */
+
+/*
+ * not supported (yet?)
+ */
diff --git a/sys/arch/mvme68k/dev/ipic.c b/sys/arch/mvme68k/dev/ipic.c
new file mode 100644
index 00000000000..400f57b25ba
--- /dev/null
+++ b/sys/arch/mvme68k/dev/ipic.c
@@ -0,0 +1,195 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/ipicreg.h>
+#include <mvme68k/dev/mcreg.h>
+
+void ipicattach __P((struct device *, struct device *, void *));
+int ipicmatch __P((struct device *, void *, void *));
+
+struct cfdriver ipiccd = {
+ NULL, "ipic", ipicmatch, ipicattach,
+ DV_DULL, sizeof(struct ipicsoftc), 0
+};
+
+int
+ipicmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct ipicreg *ipic = (struct ipicreg *)ca->ca_vaddr;
+
+ if (badvaddr(ipic, 1) || ipic->ipic_chipid != IPIC_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+ipicprint(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ printf(" slot %d", ca->ca_offset);
+ if (ca->ca_vec > 0)
+ printf(" vec %d", ca->ca_vec);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+ipicscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct ipicsoftc *sc = (struct ipicsoftc *)parent;
+ register struct confargs *ca = args;
+ struct confargs oca;
+ int slot, n = 0;
+ caddr_t ipv, ipp;
+ struct ipid *ipid;
+
+#if 0
+/* XXX all these are indirect!! how to fix? */
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+#endif
+
+ /* XXX can we determing IPIC_IPSPACE automatically? */
+ for (slot = 0; slot < sc->sc_nip; slot++) {
+ ipp = sc->sc_ipspace + (slot * IPIC_IP_MODSIZE);
+ if (badpaddr(ipp + IPIC_IP_IDOFFSET, 2))
+ continue;
+
+ ipv = mapiodev(ipp, NBPG);
+ if (ipv == NULL)
+ continue;
+
+ ipid = (struct ipid *)(ipv + IPIC_IP_IDOFFSET);
+ if (ipid->ipid_A != 'A' || ipid->ipid_P != 'P' ||
+ ipid->ipid_I != 'I' || ipid->ipid_C != 'C' ||
+ (u_char)cf->cf_loc[0] != ipid->ipid_manu ||
+ (u_char)cf->cf_loc[1] != ipid->ipid_prod) {
+ unmapiodev(ipv, NBPG);
+ continue;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_bustype = BUS_IP;
+ oca.ca_offset = slot; /* slot number */
+ oca.ca_paddr = ipp;
+ oca.ca_vaddr = ipv;
+ oca.ca_len = NBPG;
+ oca.ca_ipl = cf->cf_loc[2];
+ oca.ca_vec = cf->cf_loc[3];
+ if (oca.ca_ipl > 0 && oca.ca_vec == -1)
+ oca.ca_vec = intr_freevec();
+
+ oca.ca_master = (void *)sc;
+ oca.ca_name = cf->cf_driver->cd_name;
+
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) {
+ unmapiodev(ipv, NBPG);
+ continue;
+ }
+ config_attach(parent, cf, &oca, ipicprint);
+ n++;
+ }
+ return (n);
+}
+
+void
+ipicattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct ipicsoftc *sc = (struct ipicsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_ipic = (struct ipicreg *)ca->ca_vaddr;
+ sc->sc_ipspace = (caddr_t)IPIC_IPSPACE;
+ sc->sc_nip = 2;
+
+ printf(": rev %d\n", sc->sc_ipic->ipic_chiprev);
+
+ sc->sc_ipic->ipic_reset = IPIC_RESET;
+ delay(2);
+
+ config_search(ipicscan, self, args);
+}
+
+caddr_t
+ipicmap(sc, addr, len)
+ struct ipicsoftc *sc;
+ caddr_t addr;
+ int len;
+{
+ return (NULL);
+}
+
+void
+ipicunmap(sc, addr, len)
+ struct ipicsoftc *sc;
+ caddr_t addr;
+ int len;
+{
+}
+
+int
+ipicintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ return (intr_establish(vec, ih));
+}
diff --git a/sys/arch/mvme68k/dev/ipicreg.h b/sys/arch/mvme68k/dev/ipicreg.h
new file mode 100644
index 00000000000..b329a7342f9
--- /dev/null
+++ b/sys/arch/mvme68k/dev/ipicreg.h
@@ -0,0 +1,114 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct ipicreg {
+ volatile u_char ipic_chipid;
+#define IPIC_CHIPID 0x23
+ volatile u_char ipic_chiprev;
+ volatile u_char x0[2];
+ volatile u_short ipic_base[4]; /* [slot] */
+ volatile u_char ipic_size[4]; /* [slot] */
+ volatile u_char ipic_irq[4][2]; /* [slot][irq#] */
+#define IPIC_IRQ_PLTY 0x80 /* 1 = rising edge activated */
+#define IPIC_IRQ_EL 0x40 /* 1 = edge, 0 = level sensitive */
+#define IPIC_IRQ_INT 0x20 /* interrupt is active */
+#define IPIC_IRQ_IEN 0x10 /* enable interrupt */
+#define IPIC_IRQ_ICLR 0x08 /* clear interrupt */
+#define IPIC_IRQ_IPLMASK 0x07
+ volatile u_char ipic_ctl[4]; /* [slot] */
+#define IPIC_CTL_ERR 0x80 /* error from IP module */
+#define IPIC_CTL_RTMASK 0x30 /* recovery time, measured in ms */
+#define IPIC_CTL_RT0MS 0x00
+#define IPIC_CTL_RT2MS 0x10
+#define IPIC_CTL_RT4MS 0x20
+#define IPIC_CTL_RT8MS 0x30
+#define IPIC_CTL_WIDTHMASK 0x0c /* bus width */
+#define IPIC_CTL_WIDTH32 0x00
+#define IPIC_CTL_WIDTH8 0x04
+#define IPIC_CTL_WIDTH16 0x08
+#define IPIC_CTL_MEN 0x01 /* ??? */
+ volatile u_char x1[3];
+ volatile u_char ipic_reset;
+#define IPIC_RESET 0x01 /* bit clears automatically after 1ms */
+};
+
+/*
+ * the following macros convert the size in bytes to/from the
+ * ipic_Xsize reg values. you should ensure your size in bytes
+ * is a legal value, which are 16K, or all the powers of 2 from
+ * 64K to 8M.
+ */
+#define IPIC_SIZE_BTOR(x) \
+ (((x) == 16*1024) ? (0xff) : (((x) / 64*1024) - 1))
+#define IPIC_SIZE_RTOB(x) \
+ (((x) == 0xff) ? (16*1024) : (((x) + 1) * 64*1024))
+
+struct ipid {
+ volatile u_char ipid_I; /* must be 'I' */
+ volatile u_char :8;
+ volatile u_char ipid_P; /* must be 'P' */
+ volatile u_char :8;
+ volatile u_char ipid_A; /* must be 'A' */
+ volatile u_char :8;
+ volatile u_char ipid_C; /* must be 'C' */
+ volatile u_char :8;
+ volatile u_char ipid_manu;
+ volatile u_char :8;
+ volatile u_char ipid_prod;
+ volatile u_char :8;
+ volatile u_char ipid_rev;
+ volatile u_char :8;
+ volatile u_char ipid_zero;
+ volatile u_char :8;
+ volatile u_char ipid_didl;
+ volatile u_char :8;
+ volatile u_char ipid_didh;
+ volatile u_char :8;
+ volatile u_char ipid_pspecn; /* # shorts in pack-spec id */
+ volatile u_char :8;
+ volatile u_char ipid_crc;
+ volatile u_char :8;
+ volatile u_char ipic_pspecbase; /* start of pack-spec id */
+};
+
+#define IPIC_IPSPACE 0xfff58000
+#define IPIC_IP_MODSIZE 0x00000100
+#define IPIC_IP_IDOFFSET 0x80
+#define IPIC_IP_REGOFFSET 0x00
+
+struct ipicsoftc {
+ struct device sc_dev;
+ struct ipicreg *sc_ipic;
+
+ caddr_t sc_ipspace;
+ int sc_nip;
+};
diff --git a/sys/arch/mvme68k/dev/lp.c b/sys/arch/mvme68k/dev/lp.c
new file mode 100644
index 00000000000..77f02834c2a
--- /dev/null
+++ b/sys/arch/mvme68k/dev/lp.c
@@ -0,0 +1,144 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/pccreg.h>
+
+struct lpsoftc {
+ struct device sc_dev;
+ struct intrhand sc_ih;
+ struct pccreg *sc_pcc;
+};
+
+void lpattach __P((struct device *, struct device *, void *));
+int lpmatch __P((struct device *, void *, void *));
+
+struct cfdriver lpcd = {
+ NULL, "lp", lpmatch, lpattach,
+ DV_DULL, sizeof(struct lpsoftc), 0
+};
+
+int lpintr __P((void *));
+
+/*
+ * a PCC chip always has an lp attached to it.
+ */
+int
+lpmatch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ return (1);
+}
+
+void
+lpattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct lpsoftc *sc = (struct lpsoftc *)self;
+ struct confargs *ca = args;
+
+ sc->sc_pcc = (struct pccreg *)ca->ca_master;
+
+ printf(": unsupported\n");
+
+ sc->sc_ih.ih_fn = lpintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_PRINTER, &sc->sc_ih);
+
+ sc->sc_pcc->pcc_lpirq = ca->ca_ipl | PCC_IRQ_IEN | PCC_LPIRQ_ACK;
+}
+
+int
+lpintr(dev)
+ void *dev;
+{
+ struct lpsoftc *sc = dev;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+lpwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+}
+
+lpioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+}
+
diff --git a/sys/arch/mvme68k/dev/mc.c b/sys/arch/mvme68k/dev/mc.c
new file mode 100644
index 00000000000..1c7dc2889d1
--- /dev/null
+++ b/sys/arch/mvme68k/dev/mc.c
@@ -0,0 +1,217 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME162 MCchip
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/mcreg.h>
+
+struct mcsoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ caddr_t sc_paddr;
+ struct mcreg *sc_mc;
+ struct intrhand sc_nmiih;
+};
+
+void mcattach __P((struct device *, struct device *, void *));
+int mcmatch __P((struct device *, void *, void *));
+int mcabort __P((struct frame *));
+
+struct cfdriver mccd = {
+ NULL, "mc", mcmatch, mcattach,
+ DV_DULL, sizeof(struct mcsoftc), 0
+};
+
+struct mcreg *sys_mc = NULL;
+
+int
+mcmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct mcreg *mc = (struct mcreg *)(IIOV(ca->ca_paddr) + MC_MCCHIP_OFF);
+
+ if (cputyp != CPU_162 || badvaddr(mc, 1) ||
+ mc->mc_chipid != MC_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+mc_print(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ if (ca->ca_offset != -1)
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+mc_scan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct mcsoftc *sc = (struct mcsoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_offset = cf->cf_loc[0];
+ oca.ca_ipl = cf->cf_loc[1];
+ if (oca.ca_offset != -1 && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) {
+ oca.ca_paddr = sc->sc_paddr + oca.ca_offset;
+ oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset;
+ } else {
+ oca.ca_paddr = (caddr_t)-1;
+ oca.ca_vaddr = (caddr_t)-1;
+ }
+ oca.ca_bustype = BUS_MC;
+ oca.ca_master = (void *)sc->sc_mc;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0)
+ return (0);
+ config_attach(parent, cf, &oca, mc_print);
+ return (1);
+}
+
+void
+mcattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct mcsoftc *sc = (struct mcsoftc *)self;
+ int i;
+
+ if (sys_mc)
+ panic("mc already attached!");
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = (caddr_t)IIOV(sc->sc_paddr);
+ sc->sc_mc = (struct mcreg *)(sc->sc_vaddr + MC_MCCHIP_OFF);
+ sys_mc = sc->sc_mc;
+
+ printf(": rev %d\n", sc->sc_mc->mc_chiprev);
+
+ sc->sc_nmiih.ih_fn = mcabort;
+ sc->sc_nmiih.ih_arg = 0;
+ sc->sc_nmiih.ih_ipl = 7;
+ sc->sc_nmiih.ih_wantframe = 1;
+ mcintr_establish(MCV_ABORT, &sc->sc_nmiih);
+
+ sc->sc_mc->mc_abortirq = 7 | MC_IRQ_IEN | MC_IRQ_ICLR;
+ sc->sc_mc->mc_vecbase = MC_VECBASE;
+
+ sc->sc_mc->mc_genctl |= MC_GENCTL_IEN; /* global irq enable */
+
+ config_search(mc_scan, self, args);
+}
+
+/*
+ * MC interrupts land in a MC_NVEC sized hole starting at MC_VECBASE
+ */
+int
+mcintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ if (vec >= MC_NVEC) {
+ printf("mc: illegal vector: 0x%x\n", vec);
+ panic("mcintr_establish");
+ }
+ return (intr_establish(MC_VECBASE+vec, ih));
+}
+
+int
+mcabort(frame)
+ struct frame *frame;
+{
+ /* wait for it to debounce */
+ while (sys_mc->mc_abortirq & MC_ABORT_ABS)
+ ;
+
+ sys_mc->mc_abortirq = sys_mc->mc_abortirq | MC_IRQ_ICLR;
+
+ nmihand(frame);
+ return (1);
+}
+
+#include "flash.h"
+
+#if NFLASH > 0
+void
+mc_enableflashwrite(on)
+ int on;
+{
+ struct mcsoftc *sc = (struct mcsoftc *) mccd.cd_devs[0];
+ volatile char *ena, x;
+
+ ena = sc->sc_vaddr +
+ (on ? MC_ENAFLASHWRITE_OFFSET : MC_DISFLASHWRITE_OFFSET);
+ x = *ena;
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/mcreg.h b/sys/arch/mvme68k/dev/mcreg.h
new file mode 100644
index 00000000000..ead6d812d0f
--- /dev/null
+++ b/sys/arch/mvme68k/dev/mcreg.h
@@ -0,0 +1,164 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME162 MCchip
+ */
+struct mcreg {
+ volatile u_char mc_chipid;
+ volatile u_char mc_chiprev;
+ volatile u_char mc_genctl;
+ volatile u_char mc_vecbase;
+ volatile u_long mc_t1cmp;
+ volatile u_long mc_t1count;
+ volatile u_long mc_t2cmp;
+ volatile u_long mc_t2count;
+ volatile u_char mc_lsbprescale;
+ volatile u_char mc_adjprescale;
+ volatile u_char mc_t2ctl;
+ volatile u_char mc_t1ctl;
+ volatile u_char mc_t4irq;
+ volatile u_char mc_t3irq;
+ volatile u_char mc_t2irq;
+ volatile u_char mc_t1irq;
+ volatile u_char mc_parity;
+ volatile u_char mc_zsirq;
+ volatile u_char mc_t4ctl;
+ volatile u_char mc_t3ctl;
+ volatile u_short mc_drambase;
+ volatile u_short mc_srambase;
+ volatile u_char mc_dramsize;
+ volatile u_char mc_memoptions;
+#define MC_MEMOPTIONS_SRAMMASK 0x18
+#define MC_MEMOPTIONS_SRAM128K 0x00
+#define MC_MEMOPTIONS_SRAM512K 0x08
+#define MC_MEMOPTIONS_SRAM1M 0x10
+#define MC_MEMOPTIONS_SRAM2M 0x18
+#define MC_MEMOPTIONS_DRAMMASK 0x07
+#define MC_MEMOPTIONS_DRAM1M 0x00
+#define MC_MEMOPTIONS_DRAM2M 0x01
+#define MC_MEMOPTIONS_DRAM4M 0x03
+#define MC_MEMOPTIONS_DRAM4M2 0x04
+#define MC_MEMOPTIONS_DRAM8M 0x05
+#define MC_MEMOPTIONS_DRAM16M 0x07
+ volatile u_char mc_sramsize;
+ volatile u_char mc_resv1;
+ volatile u_char mc_ieerr;
+ volatile u_char mc_resv2;
+ volatile u_char mc_ieirq;
+ volatile u_char mc_iefailirq;
+ volatile u_char mc_ncrerr;
+ volatile u_char mc_input;
+ volatile u_char mc_ver;
+ volatile u_char mc_ncrirq;
+ volatile u_long mc_t3cmp;
+ volatile u_long mc_t3count;
+ volatile u_long mc_t4cmp;
+ volatile u_long mc_t4count;
+ volatile u_char mc_busclock;
+ volatile u_char mc_promtime;
+ volatile u_char mc_flashctl;
+ volatile u_char mc_abortirq;
+ volatile u_char mc_resetctl;
+ volatile u_char mc_watchdogctl;
+ volatile u_char mc_watchdogtime;
+ volatile u_char mc_resv3;
+ volatile u_char mc_dramctl;
+ volatile u_char mc_resv4;
+ volatile u_char mc_mpustat;
+ volatile u_char mc_resv5;
+ volatile u_long mc_prescale;
+};
+#define MC_MCCHIP_OFF 0x42000
+#define MC_CHIPID 0x84
+
+/*
+ * points to system's MCchip registers
+ */
+extern struct mcreg *sys_mc;
+
+/*
+ * for the console we need zs phys addr
+ */
+#define ZS0_PHYS_162 (0xfff45000)
+#define ZS1_PHYS_162 (0xfff45801)
+
+/*
+ * We lock off our interrupt vector at 0x50.
+ */
+#define MC_VECBASE 0x50
+#define MC_NVEC 16
+
+#define MCV_ZS 0x00
+#define MCV_TIMER4 0x03
+#define MCV_TIMER3 0x04
+#define MCV_NCR 0x05
+#define MCV_IEFAIL 0x06
+#define MCV_IE 0x07
+#define MCV_TIMER2 0x08
+#define MCV_TIMER1 0x09
+#define MCV_PARITY 0x0b
+#define MCV_ABORT 0x0e
+
+#define MC_TCTL_CEN 0x01
+#define MC_TCTL_COC 0x02
+#define MC_TCTL_COVF 0x04
+#define MC_TCTL_OVF 0xf0
+
+#define MC_ABORT_ABS 0x40
+
+#define mc_timer_us2lim(us) (us) /* timer increments in "us" */
+
+#define MC_IRQ_IPL 0x07
+#define MC_IRQ_ICLR 0x08
+#define MC_IRQ_IEN 0x10
+#define MC_IRQ_INT 0x20
+
+#define MC_GENCTL_IEN 0x02
+
+#define MC_IEERR_SCLR 0x01
+
+#define MC_SC_INHIBIT (0 << 6)
+#define MC_SC_SNOOP (1 << 6)
+#define MC_SC_INVAL (2 << 6)
+#define MC_SC_RESV (3 << 6)
+
+#define MC_VER_ISLX 0x40
+#define MC_VER_REAL040 0x10
+#define MC_VER_NOIE 0x08
+#define MC_VER_NONCR 0x04
+#define MC_VER_NOVME 0x02
+#define MC_VER_33MHZ 0x01
+
+void mc_enableflashwrite __P((int on));
+#define MC_ENAFLASHWRITE_OFFSET 0xcc000
+#define MC_DISFLASHWRITE_OFFSET 0xc8000
diff --git a/sys/arch/mvme68k/dev/memc.c b/sys/arch/mvme68k/dev/memc.c
new file mode 100644
index 00000000000..9a16dd2a393
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memc.c
@@ -0,0 +1,131 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * MEMC/MCECC chips
+ * these chips are rather similar in appearance except that the MEMC
+ * does parity while the MCECC does ECC.
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/memcreg.h>
+
+struct memcsoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ struct memcreg *sc_memc;
+ struct intrhand sc_ih;
+};
+
+void memcattach __P((struct device *, struct device *, void *));
+int memcmatch __P((struct device *, void *, void *));
+
+struct cfdriver memccd = {
+ NULL, "memc", memcmatch, memcattach,
+ DV_DULL, sizeof(struct memcsoftc), 0
+};
+
+int memcintr __P((struct frame *frame));
+
+int
+memcmatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct memcreg *memc = (struct memcreg *)ca->ca_vaddr;
+
+ if (badvaddr(memc, 1))
+ return (0);
+ if (memc->memc_chipid==MEMC_CHIPID || memc->memc_chipid==MCECC_CHIPID)
+ return (1);
+ return (0);
+}
+
+void
+memcattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct memcsoftc *sc = (struct memcsoftc *)self;
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_memc = (struct memcreg *)ca->ca_vaddr;
+
+ printf(": %s rev %d",
+ (sc->sc_memc->memc_chipid == MEMC_CHIPID) ? "MEMC040" : "MCECC",
+ sc->sc_memc->memc_chiprev);
+
+#if 0
+ sc->sc_ih.ih_fn = memcintr;
+ sc->sc_ih.ih_arg = 0;
+ sc->sc_ih.ih_ipl = 7;
+ sc->sc_ih.ih_wantframe = 1;
+ mcintr_establish(xxx, &sc->sc_ih);
+#endif
+
+ switch (sc->sc_memc->memc_chipid) {
+ case MEMC_CHIPID:
+ break;
+ case MCECC_CHIPID:
+ break;
+ }
+
+ printf("\n");
+}
+
+int
+memcintr(frame)
+ struct frame *frame;
+{
+ return (0);
+}
diff --git a/sys/arch/mvme68k/dev/memcreg.h b/sys/arch/mvme68k/dev/memcreg.h
new file mode 100644
index 00000000000..6bb7b901dec
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memcreg.h
@@ -0,0 +1,106 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * the MEMC's registers are a subset of the MCECC chip
+ */
+struct memcreg {
+ volatile u_char memc_chipid;
+ volatile u_char xx0[3];
+ volatile u_char memc_chiprev;
+ volatile u_char xx1[3];
+ volatile u_char memc_memconf;
+#define MEMC_MEMCONF_MSIZ 0x07
+#define MEMC_MEMCONF_RTOB(x) ((4*1024*1024) << ((x) & MEMC_MEMCONF_MSIZ))
+ volatile u_char xx2[3];
+ volatile u_char memc_x0;
+ volatile u_char xx3[3];
+ volatile u_char memc_x1;
+ volatile u_char xx4[3];
+ volatile u_char memc_baseaddr;
+ volatile u_char xx5[3];
+ volatile u_char memc_control;
+ volatile u_char xx6[3];
+ volatile u_char memc_bclk;
+ volatile u_char xx7[3];
+
+ /* the following registers only exist on the MCECC */
+ volatile u_char memc_datactl;
+ volatile u_char xx8[3];
+ volatile u_char memc_scrubctl;
+ volatile u_char xx9[3];
+ volatile u_char memc_scrubperh;
+ volatile u_char xx10[3];
+ volatile u_char memc_scrubperl;
+ volatile u_char xx11[3];
+ volatile u_char memc_chipprescale;
+ volatile u_char xx12[3];
+ volatile u_char memc_scrubtime;
+ volatile u_char xx13[3];
+ volatile u_char memc_scrubprescaleh;
+ volatile u_char xx14[3];
+ volatile u_char memc_scrubprescalem;
+ volatile u_char xx15[3];
+ volatile u_char memc_scrubprescalel;
+ volatile u_char xx16[3];
+ volatile u_char memc_scrubtimeh;
+ volatile u_char xx17[3];
+ volatile u_char memc_scrubtimel;
+ volatile u_char xx18[3];
+ volatile u_char memc_scrubaddrhh;
+ volatile u_char xx19[3];
+ volatile u_char memc_scrubaddrhm;
+ volatile u_char xx20[3];
+ volatile u_char memc_scrubaddrlm;
+ volatile u_char xx21[3];
+ volatile u_char memc_scrubaddrll;
+ volatile u_char xx22[3];
+ volatile u_char memc_errlog;
+ volatile u_char xx23[3];
+ volatile u_char memc_errloghh;
+ volatile u_char xx24[3];
+ volatile u_char memc_errloghm;
+ volatile u_char xx25[3];
+ volatile u_char memc_errloglm;
+ volatile u_char xx26[3];
+ volatile u_char memc_errlogll;
+ volatile u_char xx27[3];
+ volatile u_char memc_errsyndrome;
+ volatile u_char xx28[3];
+ volatile u_char memc_defaults1;
+ volatile u_char xx29[3];
+ volatile u_char memc_defaults2;
+ volatile u_char xx30[3];
+};
+
+#define MEMC_CHIPID 0x80
+#define MCECC_CHIPID 0x81
diff --git a/sys/arch/mvme68k/dev/memdevs.c b/sys/arch/mvme68k/dev/memdevs.c
new file mode 100644
index 00000000000..a966b8778cc
--- /dev/null
+++ b/sys/arch/mvme68k/dev/memdevs.c
@@ -0,0 +1,76 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+/*ARGSUSED*/
+int
+memdevrw(base, len, uio, flags)
+ caddr_t base;
+ int len;
+ struct uio *uio;
+ int flags;
+{
+ register vm_offset_t o, v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("memdevrw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (v + c > len)
+ c = len - v; /* till end of dev */
+ if (c == 0)
+ return (0);
+ error = uiomove(base + v, c, uio);
+ }
+ return (error);
+}
diff --git a/sys/arch/mvme68k/dev/nvram.c b/sys/arch/mvme68k/dev/nvram.c
new file mode 100644
index 00000000000..93f484542a6
--- /dev/null
+++ b/sys/arch/mvme68k/dev/nvram.c
@@ -0,0 +1,416 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <machine/psl.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/mioctl.h>
+#include <mvme68k/dev/nvramreg.h>
+
+#if defined(GPROF)
+#include <sys/gmon.h>
+#endif
+
+struct nvramsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ caddr_t sc_vaddr;
+ int sc_len;
+ struct clockreg *sc_regs;
+};
+
+void nvramattach __P((struct device *, struct device *, void *));
+int nvrammatch __P((struct device *, void *, void *));
+
+struct cfdriver nvramcd = {
+ NULL, "nvram", nvrammatch, nvramattach,
+ DV_DULL, sizeof(struct nvramsoftc), 0
+};
+
+int
+nvrammatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+/*X*/ if (ca->ca_vaddr == (caddr_t)-1)
+/*X*/ return (1);
+ return (!badvaddr(ca->ca_vaddr, 1));
+}
+
+void
+nvramattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct nvramsoftc *sc = (struct nvramsoftc *)self;
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = ca->ca_vaddr;
+
+ sc->sc_len = MK48T08_SIZE;
+ if (cputyp == CPU_147)
+ sc->sc_len = MK48T02_SIZE;
+
+/*X*/ if (sc->sc_vaddr == (caddr_t)-1)
+/*X*/ sc->sc_vaddr = mapiodev((caddr_t)sc->sc_paddr,
+/*X*/ max(sc->sc_len, NBPG));
+/*X*/ if (sc->sc_vaddr == NULL)
+/*X*/ panic("failed to map!\n");
+
+ sc->sc_regs = (struct clockreg *)(sc->sc_vaddr + sc->sc_len -
+ sizeof(struct clockreg));
+
+ printf(": MK48T0%d len %d\n", sc->sc_len / 1024, sc->sc_len);
+}
+
+/*
+ * Return the best possible estimate of the time in the timeval
+ * to which tvp points. We do this by returning the current time
+ * plus the amount of time since the last clock interrupt (clock.c:clkread).
+ *
+ * Check that this time is no less than any previously-reported time,
+ * which could happen around the time of a clock adjustment. Just for fun,
+ * we guarantee that the time will be greater than the value obtained by a
+ * previous call.
+ */
+void
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+ static struct timeval lasttime;
+
+ *tvp = time;
+ tvp->tv_usec;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ if (tvp->tv_sec == lasttime.tv_sec &&
+ tvp->tv_usec <= lasttime.tv_usec &&
+ (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ lasttime = *tvp;
+ splx(s);
+}
+
+/*
+ * BCD to decimal and decimal to BCD.
+ */
+#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
+#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
+
+#define SECDAY (24 * 60 * 60)
+#define SECYR (SECDAY * 365)
+#define LEAPYEAR(y) (((y) & 3) == 0)
+
+/*
+ * This code is defunct after 2068.
+ * Will Unix still be here then??
+ */
+const short dayyr[12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+static u_long
+chiptotime(sec, min, hour, day, mon, year)
+ register int sec, min, hour, day, mon, year;
+{
+ register int days, yr;
+
+ sec = FROMBCD(sec);
+ min = FROMBCD(min);
+ hour = FROMBCD(hour);
+ day = FROMBCD(day);
+ mon = FROMBCD(mon);
+ year = FROMBCD(year) + YEAR0;
+
+ /* simple sanity checks */
+ if (year < 70 || year > 164 || mon < 1 || mon > 12 || day < 1 || day > 31)
+ return (0);
+ days = 0;
+ for (yr = 70; yr < year; yr++)
+ days += LEAPYEAR(yr) ? 366 : 365;
+ days += dayyr[mon - 1] + day - 1;
+ if (LEAPYEAR(yr) && mon > 2)
+ days++;
+ /* now have days since Jan 1, 1970; the rest is easy... */
+ return (days * SECDAY + hour * 3600 + min * 60 + sec);
+}
+
+struct chiptime {
+ int sec;
+ int min;
+ int hour;
+ int wday;
+ int day;
+ int mon;
+ int year;
+};
+
+timetochip(c)
+ register struct chiptime *c;
+{
+ register int t, t2, t3, now = time.tv_sec;
+
+ /* compute the year */
+ t2 = now / SECDAY;
+ t3 = (t2 + 2) % 7; /* day of week */
+ c->wday = TOBCD(t3 + 1);
+
+ t = 69;
+ while (t2 >= 0) { /* whittle off years */
+ t3 = t2;
+ t++;
+ t2 -= LEAPYEAR(t) ? 366 : 365;
+ }
+ c->year = t;
+
+ /* t3 = month + day; separate */
+ t = LEAPYEAR(t);
+ for (t2 = 1; t2 < 12; t2++)
+ if (t3 < dayyr[t2] + (t && t2 > 1))
+ break;
+
+ /* t2 is month */
+ c->mon = t2;
+ c->day = t3 - dayyr[t2 - 1] + 1;
+ if (t && t2 > 2)
+ c->day--;
+
+ /* the rest is easy */
+ t = now % SECDAY;
+ c->hour = t / 3600;
+ t %= 3600;
+ c->min = t / 60;
+ c->sec = t % 60;
+
+ c->sec = TOBCD(c->sec);
+ c->min = TOBCD(c->min);
+ c->hour = TOBCD(c->hour);
+ c->day = TOBCD(c->day);
+ c->mon = TOBCD(c->mon);
+ c->year = TOBCD(c->year - YEAR0);
+}
+
+/*
+ * Set up the system's time, given a `reasonable' time value.
+ */
+inittodr(base)
+ time_t base;
+{
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[0];
+ register struct clockreg *cl = sc->sc_regs;
+ int sec, min, hour, day, mon, year;
+ int badbase = 0, waszero = base == 0;
+
+ if (base < 5 * SECYR) {
+ /*
+ * If base is 0, assume filesystem time is just unknown
+ * instead of preposterous. Don't bark.
+ */
+ if (base != 0)
+ printf("WARNING: preposterous time in file system\n");
+ /* not going to use it anyway, if the chip is readable */
+ base = 21*SECYR + 186*SECDAY + SECDAY/2;
+ badbase = 1;
+ }
+ cl->cl_csr |= CLK_READ; /* enable read (stop time) */
+ sec = cl->cl_sec;
+ min = cl->cl_min;
+ hour = cl->cl_hour;
+ day = cl->cl_mday;
+ mon = cl->cl_month;
+ year = cl->cl_year;
+ cl->cl_csr &= ~CLK_READ; /* time wears on */
+ if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
+ printf("WARNING: bad date in nvram");
+ /*
+ * Believe the time in the file system for lack of
+ * anything better, resetting the clock.
+ */
+ time.tv_sec = base;
+ if (!badbase)
+ resettodr();
+ } else {
+ int deltat = time.tv_sec - base;
+
+ if (deltat < 0)
+ deltat = -deltat;
+ if (waszero || deltat < 2 * SECDAY)
+ return;
+ printf("WARNING: clock %s %d days",
+ time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
+ }
+ printf(" -- CHECK AND RESET THE DATE!\n");
+}
+
+/*
+ * Reset the clock based on the current time.
+ * Used when the current clock is preposterous, when the time is changed,
+ * and when rebooting. Do nothing if the time is not yet known, e.g.,
+ * when crashing during autoconfig.
+ */
+resettodr()
+{
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[0];
+ register struct clockreg *cl = sc->sc_regs;
+ struct chiptime c;
+
+ if (!time.tv_sec || cl == NULL)
+ return;
+ timetochip(&c);
+ cl->cl_csr |= CLK_WRITE; /* enable write */
+ cl->cl_sec = c.sec;
+ cl->cl_min = c.min;
+ cl->cl_hour = c.hour;
+ cl->cl_wday = c.wday;
+ cl->cl_mday = c.day;
+ cl->cl_month = c.mon;
+ cl->cl_year = c.year;
+ cl->cl_csr &= ~CLK_WRITE; /* load them up */
+}
+
+/*ARGSUSED*/
+int
+nvramopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= nvramcd.cd_ndevs ||
+ nvramcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nvramclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+nvramioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+nvramread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*ARGSUSED*/
+int
+nvramwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*
+ * If the NVRAM is of the 2K variety, an extra 2K of who-knows-what
+ * will also be mmap'd, due to NBPG being 4K. On the MVME147 the NVRAM
+ * repeats, so userland gets two copies back-to-back.
+ */
+int
+nvrammmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct nvramsoftc *sc = (struct nvramsoftc *) nvramcd.cd_devs[unit];
+
+ if (minor(dev) != 0)
+ return (-1);
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
diff --git a/sys/arch/mvme68k/dev/nvramreg.h b/sys/arch/mvme68k/dev/nvramreg.h
new file mode 100644
index 00000000000..ec804e1e049
--- /dev/null
+++ b/sys/arch/mvme68k/dev/nvramreg.h
@@ -0,0 +1,70 @@
+/* $NetBSD: clockreg.h,v 1.5 1994/11/20 20:54:07 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Mostek MK48T02 clock.
+ */
+struct clockreg {
+ volatile u_char cl_csr; /* control register */
+ volatile u_char cl_sec; /* seconds (0..59; BCD) */
+ volatile u_char cl_min; /* minutes (0..59; BCD) */
+ volatile u_char cl_hour; /* hour (0..23; BCD) */
+ volatile u_char cl_wday; /* weekday (1..7) */
+ volatile u_char cl_mday; /* day in month (1..31; BCD) */
+ volatile u_char cl_month; /* month (1..12; BCD) */
+ volatile u_char cl_year; /* year (0..99; BCD) */
+};
+
+/* bits in cl_csr */
+#define CLK_WRITE 0x80 /* want to write */
+#define CLK_READ 0x40 /* want to read (freeze clock) */
+
+/*
+ * Motorola chose the year `1900' as their base count.
+ * XXX what happens when it wraps?
+ */
+#define YEAR0 0
+
+#define MK48T02_SIZE 2*1024
+#define MK48T08_SIZE 8*1024
diff --git a/sys/arch/mvme68k/dev/pcctwo.c b/sys/arch/mvme68k/dev/pcctwo.c
new file mode 100644
index 00000000000..6b694606f3b
--- /dev/null
+++ b/sys/arch/mvme68k/dev/pcctwo.c
@@ -0,0 +1,180 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * VME16x PCC2 chip
+ */
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+
+#include <mvme68k/dev/pcctworeg.h>
+
+struct pcctwosoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr; /* PCC2 space */
+ caddr_t sc_paddr;
+ struct pcctworeg *sc_pcc2; /* the actual registers */
+};
+
+void pcctwoattach __P((struct device *, struct device *, void *));
+int pcctwomatch __P((struct device *, void *, void *));
+
+struct cfdriver pcctwocd = {
+ NULL, "pcctwo", pcctwomatch, pcctwoattach,
+ DV_DULL, sizeof(struct pcctwosoftc), 0
+};
+
+struct pcctworeg *sys_pcc2 = NULL;
+
+int
+pcctwomatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+ struct pcctworeg *pcc2;
+
+ /* the PCC2 only exists on MVME16x's except the 162, right? */
+ if (cputyp == CPU_162 || cputyp == CPU_147)
+ return (0);
+ pcc2 = (struct pcctworeg *)(IIOV(ca->ca_paddr) + PCC2_PCC2CHIP_OFF);
+ if (badvaddr(pcc2, 1) || pcc2->pcc2_chipid != PCC2_CHIPID)
+ return (0);
+ return (1);
+}
+
+int
+pcctwo_print(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ if (ca->ca_offset != -1)
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+pcctwo_scan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ struct cfdata *cf = child;
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_offset = cf->cf_loc[0];
+ oca.ca_ipl = cf->cf_loc[1];
+ if (oca.ca_offset != -1 && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) {
+ oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset;
+ oca.ca_paddr = sc->sc_paddr + oca.ca_offset;
+ } else {
+ oca.ca_vaddr = (caddr_t)-1;
+ oca.ca_paddr = (caddr_t)-1;
+ }
+ oca.ca_bustype = BUS_PCCTWO;
+ oca.ca_master = (void *)sc->sc_pcc2;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0)
+ return (0);
+ config_attach(parent, cf, &oca, pcctwo_print);
+ return (1);
+}
+
+void
+pcctwoattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)self;
+ int i;
+
+ if (sys_pcc2)
+ panic("pcc2 already attached!");
+
+ /*
+ * since we know ourself to land in intiobase land,
+ * we must adjust our address
+ */
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = (caddr_t)IIOV(sc->sc_paddr);
+ sc->sc_pcc2 = (struct pcctworeg *)(sc->sc_vaddr + PCC2_PCC2CHIP_OFF);
+ sys_pcc2 = sc->sc_pcc2;
+
+ printf(": rev %d\n", sc->sc_pcc2->pcc2_chiprev);
+
+ sc->sc_pcc2->pcc2_vecbase = PCC2_VECBASE;
+ sc->sc_pcc2->pcc2_genctl |= PCC2_GENCTL_IEN; /* global irq enable */
+
+ config_search(pcctwo_scan, self, args);
+}
+
+/*
+ * PCC2 interrupts land in a PCC2_NVEC sized hole starting at PCC2_VECBASE
+ */
+int
+pcctwointr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ if (vec >= PCC2_NVEC) {
+ printf("pcctwo: illegal vector: 0x%x\n", vec);
+ panic("pcctwointr_establish");
+ }
+ return (intr_establish(PCC2_VECBASE+vec, ih));
+}
diff --git a/sys/arch/mvme68k/dev/pcctworeg.h b/sys/arch/mvme68k/dev/pcctworeg.h
new file mode 100644
index 00000000000..4c02c246797
--- /dev/null
+++ b/sys/arch/mvme68k/dev/pcctworeg.h
@@ -0,0 +1,150 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 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.
+ */
+
+/*
+ * MVME16x PCC2 chip: sort of a confused mish-mash of the MC in the 162
+ * and the PCC in the 147
+ */
+struct pcctworeg {
+ volatile u_char pcc2_chipid;
+ volatile u_char pcc2_chiprev;
+ volatile u_char pcc2_genctl;
+ volatile u_char pcc2_vecbase; /* irq vector base */
+ volatile u_long pcc2_t1cmp; /* timer1 compare */
+ volatile u_long pcc2_t1count; /* timer1 count */
+ volatile u_long pcc2_t2cmp; /* timer2 compare */
+ volatile u_long pcc2_t2count; /* timer2 count */
+ volatile u_char pcc2_pscalecnt; /* timer prescaler counter */
+ volatile u_char pcc2_pscaleadj; /* timer prescaler adjust */
+ volatile u_char pcc2_t2ctl; /* timer2 ctrl reg */
+ volatile u_char pcc2_t1ctl; /* timer1 ctrl reg */
+ volatile u_char pcc2_gpioirq; /* gpio irq */
+ volatile u_char pcc2_gpio; /* gpio i/o */
+ volatile u_char pcc2_t2irq;
+ volatile u_char pcc2_t1irq;
+ volatile u_char pcc2_sccerr;
+ volatile u_char pcc2_sccirq;
+ volatile u_char pcc2_scctx;
+ volatile u_char pcc2_sccrx;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char pcc2_sccmoiack;
+ volatile u_char :8;
+ volatile u_char pcc2_scctxiack;
+ volatile u_char :8;
+ volatile u_char pcc2_sccrxiack;
+ volatile u_char pcc2_ieerr;
+ volatile u_char :8;
+ volatile u_char pcc2_ieirq;
+ volatile u_char pcc2_iefailirq;
+ volatile u_char pcc2_ncrerr;
+ volatile u_char :8;
+ volatile u_char :8;
+ volatile u_char pcc2_ncrirq;
+ volatile u_char pcc2_prtairq;
+ volatile u_char pcc2_prtfirq;
+ volatile u_char pcc2_prtsirq;
+ volatile u_char pcc2_prtpirq;
+ volatile u_char pcc2_prtbirq;
+ volatile u_char :8;
+ volatile u_char pcc2_prtstat;
+ volatile u_char pcc2_prtctl;
+ volatile u_short pcc2_speed; /* DO NOT USE */
+ volatile u_short pcc2_prtdat;
+ volatile u_short :16;
+ volatile u_char pcc2_ipl;
+ volatile u_char pcc2_mask;
+};
+#define PCC2_PCC2CHIP_OFF 0x42000
+#define PCC2_CHIPID 0x20
+
+/*
+ * points to system's PCCTWO. This is not active until the pcctwo0
+ * device has been attached.
+ */
+extern struct pcctworeg *sys_pcc2;
+
+/*
+ * We lock off our interrupt vector at 0x50.
+ */
+#define PCC2_VECBASE 0x50
+#define PCC2_NVEC 16
+
+/*
+ * Vectors we use
+ */
+#define PCC2V_NCR 0x05
+#define PCC2V_IEFAIL 0x06
+#define PCC2V_IE 0x07
+#define PCC2V_TIMER2 0x08
+#define PCC2V_TIMER1 0x09
+#define PCC2V_GPIO 0x0a
+#define PCC2V_SCC_RXE 0x0c
+#define PCC2V_SCC_M 0x0d
+#define PCC2V_SCC_TX 0x0e
+#define PCC2V_SCC_RX 0x0f
+
+#define PCC2_TCTL_CEN 0x01
+#define PCC2_TCTL_COC 0x02
+#define PCC2_TCTL_COVF 0x04
+#define PCC2_TCTL_OVF 0xf0
+
+#define PCC2_GPIO_PLTY 0x80
+#define PCC2_GPIO_EL 0x40
+
+#define PCC2_GPIOCR_OE 0x2
+#define PCC2_GPIOCR_O 0x1
+
+#define PCC2_SCC_AVEC 0x08
+#define PCC2_SCCRX_INHIBIT (0 << 6)
+#define PCC2_SCCRX_SNOOP (1 << 6)
+#define PCC2_SCCRX_INVAL (2 << 6)
+#define PCC2_SCCRX_RESV (3 << 6)
+
+#define pcc2_timer_us2lim(us) (us) /* timer increments in "us" */
+
+#define PCC2_IRQ_IPL 0x07
+#define PCC2_IRQ_ICLR 0x08
+#define PCC2_IRQ_IEN 0x10
+#define PCC2_IRQ_INT 0x20
+
+#define PCC2_IEERR_SCLR 0x01
+
+#define PCC2_GENCTL_FAST 0x01
+#define PCC2_GENCTL_IEN 0x02
+#define PCC2_GENCTL_C040 0x03
+
+#define PCC2_SC_INHIBIT (0 << 6)
+#define PCC2_SC_SNOOP (1 << 6)
+#define PCC2_SC_INVAL (2 << 6)
+#define PCC2_SC_RESV (3 << 6)
diff --git a/sys/arch/mvme68k/dev/sbic.c b/sys/arch/mvme68k/dev/sbic.c
new file mode 100644
index 00000000000..b871cdd95a2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbic.c
@@ -0,0 +1,2561 @@
+/* $NetBSD: sbic.c,v 1.14 1995/08/18 15:28:03 chopps Exp $ */
+
+/*
+ * Copyright (c) 1994 Christian E. Hopps
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsi.c 7.5 (Berkeley) 5/4/91
+ */
+
+/*
+ * AMD 33C93 scsi adaptor driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h> /* For hz */
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <machine/pmap.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/dmavar.h>
+#include <mvme68k/dev/sbicreg.h>
+#include <mvme68k/dev/sbicvar.h>
+
+#include <vm/pmap.h>
+
+/* Since I can't find this in any other header files */
+#define SCSI_PHASE(reg) (reg&0x07)
+
+/*
+ * SCSI delays
+ * In u-seconds, primarily for state changes on the SPC.
+ */
+#define SBIC_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
+#define SBIC_DATA_WAIT 50000 /* wait per data in/out step */
+#define SBIC_INIT_WAIT 50000 /* wait per step (both) during init */
+
+#define b_cylin b_resid
+#define SBIC_WAIT(regs, until, timeo) sbicwait(regs, until, timeo, __LINE__)
+
+extern u_int kvtop();
+
+int sbicicmd __P((struct sbic_softc *, int, int, void *, int, void *, int));
+int sbicgo __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicdmaok __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicwait __P((sbic_regmap_p, char, int , int));
+int sbiccheckdmap __P((void *, u_long, u_long));
+int sbicselectbus __P((struct sbic_softc *, sbic_regmap_p, u_char, u_char, u_char));
+int sbicxfstart __P((sbic_regmap_p, int, u_char, int));
+int sbicxfout __P((sbic_regmap_p regs, int, void *, int));
+int sbicfromscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
+int sbictoscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
+int sbicintr __P((struct sbic_softc *));
+int sbicpoll __P((struct sbic_softc *));
+int sbicnextstate __P((struct sbic_softc *, u_char, u_char));
+int sbicmsgin __P((struct sbic_softc *));
+int sbicxfin __P((sbic_regmap_p regs, int, void *));
+int sbicabort __P((struct sbic_softc *, sbic_regmap_p, char *));
+void sbicxfdone __P((struct sbic_softc *, sbic_regmap_p, int));
+void sbicerror __P((struct sbic_softc *, sbic_regmap_p, u_char));
+void sbicstart __P((struct sbic_softc *));
+void sbicreset __P((struct sbic_softc *));
+void sbic_scsidone __P((struct sbic_acb *, int));
+void sbic_sched __P((struct sbic_softc *));
+void sbic_save_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
+void sbic_load_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
+
+/*
+ * Synch xfer parameters, and timing conversions
+ */
+int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */
+int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */
+
+int sbic_cmd_wait = SBIC_CMD_WAIT;
+int sbic_data_wait = SBIC_DATA_WAIT;
+int sbic_init_wait = SBIC_INIT_WAIT;
+
+/*
+ * was broken before.. now if you want this you get it for all drives
+ * on sbic controllers.
+ */
+int sbic_inhibit_sync = 1;
+int sbic_enable_reselect = 1;
+int sbic_clock_override = 0;
+int sbic_no_dma = 0;
+int sbic_parallel_operations = 1;
+
+#ifdef DEBUG
+sbic_regmap_p debug_sbic_regs;
+int sbicdma_ops = 0; /* total DMA operations */
+int sbicdma_bounces = 0; /* number operations using bounce buffer */
+int sbicdma_hits = 0; /* number of DMA chains that were contiguous */
+int sbicdma_misses = 0; /* number of DMA chains that were not contiguous */
+int sbicdma_saves = 0;
+#define QPRINTF(a) if (sbic_debug > 1) printf a
+int sbic_debug = 0;
+int sync_debug = 0;
+int sbic_dma_debug = 0;
+int reselect_debug = 0;
+int report_sense = 0;
+int data_pointer_debug = 0;
+int sbic_timeout = 0;
+u_char debug_asr, debug_csr, timeout_active=0, routine;
+void sbictimeout __P((struct sbic_softc *dev));
+#else
+#define QPRINTF
+#endif
+
+/*
+ * default minphys routine for sbic based controllers
+ */
+void
+sbic_minphys(bp)
+ struct buf *bp;
+{
+
+ /*
+ * No max transfer at this level.
+ */
+ minphys(bp);
+}
+
+/*
+ * Save DMA pointers. Take into account partial transfer. Shut down DMA.
+ */
+void
+sbic_save_ptrs(dev, regs, target, lun)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target, lun;
+{
+ int count, asr, csr, s;
+ unsigned long ptr;
+ char *vptr;
+ struct sbic_acb* acb;
+
+ extern vm_offset_t vm_first_phys;
+
+ if( !dev->sc_cur ) return;
+ if( !(dev->sc_flags & SBICF_INDMA) ) return; /* DMA not active */
+
+ s = splbio();
+
+ acb = dev->sc_nexus;
+ count = -1;
+ do {
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR ) {
+ printf("sbic_save_ptrs: asr %02x canceled!\n", asr);
+ splx(s);
+ return;
+ }
+ } while( asr & (SBIC_ASR_BSY|SBIC_ASR_CIP) );
+
+ /* Save important state */
+ /* must be done before dmastop */
+ acb->sc_dmacmd = dev->sc_dmacmd;
+ SBIC_TC_GET(regs, count);
+
+ /* Shut down DMA ====CAREFUL==== */
+ dev->sc_dmastop(dev);
+ dev->sc_flags &= ~SBICF_INDMA;
+ SBIC_TC_PUT(regs, 0);
+
+#ifdef DEBUG
+ if(!count && sbic_debug) printf("%dcount0",target);
+ if(data_pointer_debug == -1)
+ printf("SBIC saving target %d data pointers from (%x,%x)%xASR:%02x",
+ target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
+ acb->sc_dmacmd, asr);
+#endif
+
+ /* Fixup partial xfers */
+ acb->sc_kv.dc_addr += (dev->sc_tcnt - count);
+ acb->sc_kv.dc_count -= (dev->sc_tcnt - count);
+ acb->sc_pa.dc_addr += (dev->sc_tcnt - count);
+ acb->sc_pa.dc_count -= ((dev->sc_tcnt - count)>>1);
+
+ acb->sc_tcnt = dev->sc_tcnt = count;
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf(" at (%x,%x):%x\n",
+ dev->sc_cur->dc_addr, dev->sc_cur->dc_count,count);
+ sbicdma_saves++;
+#endif
+ splx(s);
+}
+
+
+/*
+ * DOES NOT RESTART DMA!!!
+ */
+void sbic_load_ptrs(dev, regs, target, lun)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target, lun;
+{
+ int i, s, asr, count;
+ char* vaddr, * paddr;
+ struct sbic_acb *acb;
+
+ acb = dev->sc_nexus;
+ if( !acb->sc_kv.dc_count )
+ /* No data to xfer */
+ return;
+
+ s = splbio();
+
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
+ dev->sc_tcnt = acb->sc_tcnt;
+ dev->sc_dmacmd = acb->sc_dmacmd;
+
+#ifdef DEBUG
+ sbicdma_ops++;
+#endif
+ if( !dev->sc_tcnt ) {
+ /* sc_tcnt == 0 implies end of segment */
+
+ /* do kvm to pa mappings */
+ paddr = acb->sc_pa.dc_addr =
+ (char *) kvtop(acb->sc_kv.dc_addr);
+
+ vaddr = acb->sc_kv.dc_addr;
+ count = acb->sc_kv.dc_count;
+ for(count = (NBPG - ((int)vaddr & PGOFSET));
+ count < acb->sc_kv.dc_count
+ && (char*)kvtop(vaddr + count + 4) == paddr + count + 4;
+ count += NBPG);
+ /* If it's all contiguous... */
+ if(count > acb->sc_kv.dc_count ) {
+ count = acb->sc_kv.dc_count;
+#ifdef DEBUG
+ sbicdma_hits++;
+#endif
+ } else {
+#ifdef DEBUG
+ sbicdma_misses++;
+#endif
+ }
+ acb->sc_tcnt = count;
+ acb->sc_pa.dc_count = count >> 1;
+
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("DMA recalc:kv(%x,%x)pa(%x,%x)\n",
+ acb->sc_kv.dc_addr,
+ acb->sc_kv.dc_count,
+ acb->sc_pa.dc_addr,
+ acb->sc_tcnt);
+#endif
+ }
+ splx(s);
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("SBIC restoring target %d data pointers at (%x,%x)%x\n",
+ target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
+ dev->sc_dmacmd);
+#endif
+}
+
+/*
+ * used by specific sbic controller
+ *
+ * it appears that the higher level code does nothing with LUN's
+ * so I will too. I could plug it in, however so could they
+ * in scsi_scsi_cmd().
+ */
+int
+sbic_scsicmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct sbic_acb *acb;
+ struct sbic_softc *dev;
+ struct scsi_link *slp;
+ int flags, s, stat;
+
+ slp = xs->sc_link;
+ dev = slp->adapter_softc;
+ flags = xs->flags;
+
+ if (flags & SCSI_DATA_UIO)
+ panic("sbic: scsi data uio requested");
+
+ if (dev->sc_nexus && flags & SCSI_POLL)
+ panic("sbic_scsicmd: busy");
+
+ if (slp->target == slp->adapter_target)
+ return ESCAPE_NOT_SUPPORTED;
+
+ s = splbio();
+ acb = dev->free_list.tqh_first;
+ if (acb)
+ TAILQ_REMOVE(&dev->free_list, acb, chain);
+ splx(s);
+
+ if (acb == NULL) {
+#ifdef DEBUG
+ printf("sbic_scsicmd: unable to queue request for target %d\n",
+ slp->target);
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ acb->flags = ACB_ACTIVE;
+ if (flags & SCSI_DATA_IN)
+ acb->flags |= ACB_DATAIN;
+ acb->xs = xs;
+ bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
+ acb->clen = xs->cmdlen;
+ acb->sc_kv.dc_addr = xs->data;
+ acb->sc_kv.dc_count = xs->datalen;
+ acb->pa_addr = xs->data ? (char *)kvtop(xs->data) : 0; /* XXXX check */
+
+ if (flags & SCSI_POLL) {
+ s = splbio();
+ /*
+ * This has major side effects -- it locks up the machine
+ */
+
+ dev->sc_flags |= SBICF_ICMD;
+ do {
+ while(dev->sc_nexus)
+ sbicpoll(dev);
+ dev->sc_nexus = acb;
+ dev->sc_stat[0] = -1;
+ dev->sc_xs = xs;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+ stat = sbicicmd(dev, slp->target, slp->lun,
+ &acb->cmd, acb->clen,
+ acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+ } while (dev->sc_nexus != acb);
+ sbic_scsidone(acb, stat);
+
+ splx(s);
+ return(COMPLETE);
+ }
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&dev->ready_list, acb, chain);
+
+ if (dev->sc_nexus) {
+ splx(s);
+ return(SUCCESSFULLY_QUEUED);
+ }
+
+ /*
+ * nothing is active, try to start it now.
+ */
+ sbic_sched(dev);
+ splx(s);
+
+/* TODO: add sbic_poll to do SCSI_POLL operations */
+#if 0
+ if (flags & SCSI_POLL)
+ return(COMPLETE);
+#endif
+ return(SUCCESSFULLY_QUEUED);
+}
+
+/*
+ * attempt to start the next available command
+ */
+void
+sbic_sched(dev)
+ struct sbic_softc *dev;
+{
+ struct scsi_xfer *xs;
+ struct scsi_link *slp;
+ struct sbic_acb *acb;
+ int flags, /*phase,*/ stat, i;
+
+ if (dev->sc_nexus)
+ return; /* a command is current active */
+
+ for (acb = dev->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
+ slp = acb->xs->sc_link;
+ i = slp->target;
+ if (!(dev->sc_tinfo[i].lubusy & (1 << slp->lun))) {
+ struct sbic_tinfo *ti = &dev->sc_tinfo[i];
+
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ dev->sc_nexus = acb;
+ slp = acb->xs->sc_link;
+ ti = &dev->sc_tinfo[slp->target];
+ ti->lubusy |= (1 << slp->lun);
+ acb->sc_pa.dc_addr = acb->pa_addr; /* XXXX check */
+ break;
+ }
+ }
+
+ if (acb == NULL)
+ return; /* did not find an available command */
+
+ dev->sc_xs = xs = acb->xs;
+ slp = xs->sc_link;
+ flags = xs->flags;
+
+ if (flags & SCSI_RESET)
+ sbicreset(dev);
+
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("sbic_sched(%d,%d)\n",slp->target,slp->lun);
+#endif
+ dev->sc_stat[0] = -1;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+ if ( flags & SCSI_POLL || ( !sbic_parallel_operations
+ && (/*phase == STATUS_PHASE ||*/
+ sbicdmaok(dev, xs) == 0) ) )
+ stat = sbicicmd(dev, slp->target, slp->lun, &acb->cmd,
+ acb->clen, acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+ else if (sbicgo(dev, xs) == 0)
+ return;
+ else
+ stat = dev->sc_stat[0];
+
+ sbic_scsidone(acb, stat);
+}
+
+void
+sbic_scsidone(acb, stat)
+ struct sbic_acb *acb;
+ int stat;
+{
+ struct scsi_xfer *xs;
+ struct scsi_link *slp;
+ struct sbic_softc *dev;
+ int s, dosched = 0;
+
+ xs = acb->xs;
+ slp = xs->sc_link;
+ dev = slp->adapter_softc;
+#ifdef DIAGNOSTIC
+ if (acb == NULL || xs == NULL) {
+ printf("sbic_scsidone -- (%d,%d) no scsi_xfer\n",
+ dev->target, dev->lun);
+#ifdef DDB
+ Debugger();
+#endif
+ return;
+ }
+#endif
+#if 1
+ if (((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
+ ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+#endif
+ /*
+ * is this right?
+ */
+ xs->status = stat;
+
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("scsidone: (%d,%d)->(%d,%d)%02x\n",
+ slp->target, slp->lun,
+ dev->target, dev->lun, stat);
+ if( xs->sc_link->target == dev->sc_link.adapter_target )
+ panic("target == hostid");
+#endif
+
+ if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
+ if (stat == SCSI_CHECK) {
+ /* Schedule a REQUEST SENSE */
+ struct scsi_sense *ss = (void *)&acb->cmd;
+#ifdef DEBUG
+ if (report_sense)
+ printf("sbic_scsidone: autosense %02x targ %d lun %d",
+ acb->cmd.opcode, slp->target, slp->lun);
+#endif
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = slp->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ acb->clen = sizeof(*ss);
+ acb->sc_kv.dc_addr = (char *)&xs->sense;
+ acb->sc_kv.dc_count = sizeof(struct scsi_sense_data);
+ acb->pa_addr = (char *)kvtop(&xs->sense); /* XXX check */
+ acb->flags = ACB_ACTIVE | ACB_CHKSENSE | ACB_DATAIN;
+ TAILQ_INSERT_HEAD(&dev->ready_list, acb, chain);
+ dev->sc_tinfo[slp->target].lubusy &=
+ ~(1 << slp->lun);
+ dev->sc_tinfo[slp->target].senses++;
+ if (dev->sc_nexus == acb) {
+ dev->sc_nexus = NULL;
+ sbic_sched(dev);
+ }
+ return;
+ }
+ }
+ if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
+ xs->error = XS_SENSE;
+#ifdef DEBUG
+ if (report_sense)
+ printf(" => %02x %02x\n", xs->sense.extended_flags,
+ xs->sense.extended_extra_bytes[3]);
+#endif
+ } else {
+ xs->resid = 0; /* XXXX */
+ }
+#if whataboutthisone
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+#endif
+ xs->flags |= ITSDONE;
+
+ /*
+ * Remove the ACB from whatever queue it's on. We have to do a bit of
+ * a hack to figure out which queue it's on. Note that it is *not*
+ * necessary to cdr down the ready queue, but we must cdr down the
+ * nexus queue and see if it's there, so we can mark the unit as no
+ * longer busy. This code is sickening, but it works.
+ */
+ if (acb == dev->sc_nexus) {
+ dev->sc_nexus = NULL;
+ dev->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
+ if (dev->ready_list.tqh_first)
+ dosched = 1; /* start next command */
+ } else if (dev->ready_list.tqh_last == &acb->chain.tqe_next) {
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ } else {
+ register struct sbic_acb *acb2;
+ for (acb2 = dev->nexus_list.tqh_first; acb2;
+ acb2 = acb2->chain.tqe_next)
+ if (acb2 == acb) {
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+ dev->sc_tinfo[slp->target].lubusy
+ &= ~(1<<slp->lun);
+ break;
+ }
+ if (acb2)
+ ;
+ else if (acb->chain.tqe_next) {
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ } else {
+ printf("%s: can't find matching acb\n",
+ dev->sc_dev.dv_xname);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+ }
+ /* Put it on the free list. */
+ acb->flags = ACB_FREE;
+ TAILQ_INSERT_HEAD(&dev->free_list, acb, chain);
+
+ dev->sc_tinfo[slp->target].cmds++;
+
+ scsi_done(xs);
+
+ if (dosched)
+ sbic_sched(dev);
+}
+
+int
+sbicdmaok(dev, xs)
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
+{
+ if (sbic_no_dma || xs->datalen & 0x1 || (u_int)xs->data & 0x3)
+ return(0);
+ /*
+ * controller supports dma to any addresses?
+ */
+ else if ((dev->sc_flags & SBICF_BADDMA) == 0)
+ return(1);
+ /*
+ * this address is ok for dma?
+ */
+ else if (sbiccheckdmap(xs->data, xs->datalen, dev->sc_dmamask) == 0)
+ return(1);
+#if 0
+ /*
+ * we have a bounce buffer?
+ */
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ return(1);
+ /*
+ * try to get one
+ */
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce
+ = (char *)alloc_z2mem(MAXPHYS)) {
+ if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
+ printf("alloc ZII target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ printf("alloc CHIP target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
+ return(1);
+ }
+#endif
+
+ return(0);
+}
+
+
+int
+sbicwait(regs, until, timeo, line)
+ sbic_regmap_p regs;
+ char until;
+ int timeo;
+ int line;
+{
+ u_char val;
+ int csr;
+
+ if (timeo == 0)
+ timeo = 10000; /* some large value.. */
+
+ GET_SBIC_asr(regs,val);
+ while ((val & until) == 0) {
+ if (timeo-- == 0) {
+ GET_SBIC_csr(regs, csr);
+ printf("sbicwait TIMEO @%d with asr=x%x csr=x%x\n",
+ line, val, csr);
+#if defined(DDB) && defined(DEBUG)
+ Debugger();
+#endif
+ return(val); /* Maybe I should abort */
+ break;
+ }
+ DELAY(1);
+ GET_SBIC_asr(regs,val);
+ }
+ return(val);
+}
+
+int
+sbicabort(dev, regs, where)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ char *where;
+{
+ u_char csr, asr;
+
+ GET_SBIC_csr(regs, csr);
+ GET_SBIC_asr(regs, asr);
+
+ printf ("%s: abort %s: csr = 0x%02x, asr = 0x%02x\n",
+ dev->sc_dev.dv_xname, where, csr, asr);
+
+
+#if 0
+ /* Clean up running command */
+ if (dev->sc_nexus != NULL) {
+ dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
+ }
+ while (acb = dev->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(acb, -1 /*acb->stat[0]*/);
+ }
+#endif
+
+ /* Clean up chip itself */
+ if (dev->sc_flags & SBICF_SELECTED) {
+ while( asr & SBIC_ASR_DBR ) {
+ /* sbic is jammed w/data. need to clear it */
+ /* But we don't know what direction it needs to go */
+ GET_SBIC_data(regs, asr);
+ printf("%s: abort %s: clearing data buffer 0x%02x\n",
+ dev->sc_dev.dv_xname, where, asr);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR ) /* Not the read direction, then */
+ SET_SBIC_data(regs, asr);
+ GET_SBIC_asr(regs, asr);
+ }
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+
+ GET_SBIC_asr(regs, asr);
+ if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) {
+ /* ok, get more drastic.. */
+
+ sbicreset(dev);
+ dev->sc_flags &= ~SBICF_SELECTED;
+ return -1;
+ }
+ SET_SBIC_cmd(regs, SBIC_CMD_DISC);
+
+ do {
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_CMD_INVALID));
+
+ /* lets just hope it worked.. */
+ dev->sc_flags &= ~SBICF_SELECTED;
+ }
+ return -1;
+}
+
+
+/*
+ * Initialize driver-private structures
+ */
+
+void
+sbicinit(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_int my_id, i, s;
+ u_char csr;
+ struct sbic_acb *acb;
+
+ regs = dev->sc_sbicp;
+
+ if ((dev->sc_flags & SBICF_ALIVE) == 0) {
+ TAILQ_INIT(&dev->ready_list);
+ TAILQ_INIT(&dev->nexus_list);
+ TAILQ_INIT(&dev->free_list);
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ acb = dev->sc_acb;
+ bzero(acb, sizeof(dev->sc_acb));
+ for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
+ acb++;
+ }
+ bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
+ } else panic("sbic: reinitializing driver!");
+
+ dev->sc_flags |= SBICF_ALIVE;
+ dev->sc_flags &= ~SBICF_SELECTED;
+
+ sbicreset(dev);
+}
+
+void
+sbicreset(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_int my_id, i, s;
+ u_char csr;
+ struct sbic_acb *acb;
+
+ regs = dev->sc_sbicp;
+#if 0
+ if (dev->sc_flags & SBICF_ALIVE) {
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+ }
+#else
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+#endif
+ s = splbio();
+ my_id = dev->sc_link.adapter_target & SBIC_ID_MASK;
+
+ /* Enable advanced mode */
+ my_id |= SBIC_ID_EAF /*| SBIC_ID_EHP*/ ;
+ SET_SBIC_myid(regs, my_id);
+
+ /*
+ * Disable interrupts (in dmainit) then reset the chip
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_RESET);
+ DELAY(25);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr); /* clears interrupt also */
+
+ if (dev->sc_clkfreq < 110)
+ my_id |= SBIC_ID_FS_8_10;
+ else if (dev->sc_clkfreq < 160)
+ my_id |= SBIC_ID_FS_12_15;
+ else if (dev->sc_clkfreq < 210)
+ my_id |= SBIC_ID_FS_16_20;
+
+ SET_SBIC_myid(regs, my_id);
+
+ /*
+ * Set up various chip parameters
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /* | SBIC_CTL_HSP */
+ | SBIC_MACHINE_DMA_MODE);
+ /*
+ * don't allow (re)selection (SBIC_RID_ES)
+ * until we can handle target mode!!
+ */
+ SET_SBIC_rselid(regs, SBIC_RID_ER);
+ SET_SBIC_syn(regs, 0); /* asynch for now */
+
+ /*
+ * anything else was zeroed by reset
+ */
+ splx(s);
+
+#if 0
+ if ((dev->sc_flags & SBICF_ALIVE) == 0) {
+ TAILQ_INIT(&dev->ready_list);
+ TAILQ_INIT(&dev->nexus_list);
+ TAILQ_INIT(&dev->free_list);
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ acb = dev->sc_acb;
+ bzero(acb, sizeof(dev->sc_acb));
+ for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
+ acb++;
+ }
+ bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
+ } else {
+ if (dev->sc_nexus != NULL) {
+ dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
+ }
+ while (acb = dev->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ sbic_scsidone(acb, -1 /*acb->stat[0]*/);
+ }
+ }
+
+ dev->sc_flags |= SBICF_ALIVE;
+#endif
+ dev->sc_flags &= ~SBICF_SELECTED;
+}
+
+void
+sbicerror(dev, regs, csr)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ u_char csr;
+{
+ struct scsi_xfer *xs;
+
+ xs = dev->sc_xs;
+
+#ifdef DIAGNOSTIC
+ if (xs == NULL)
+ panic("sbicerror");
+#endif
+ if (xs->flags & SCSI_SILENT)
+ return;
+
+ printf("%s: ", dev->sc_dev.dv_xname);
+ printf("csr == 0x%02x\n", csr); /* XXX */
+}
+
+/*
+ * select the bus, return when selected or error.
+ */
+int
+sbicselectbus(dev, regs, target, lun, our_addr)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ u_char target, lun, our_addr;
+{
+ u_char asr, csr, id;
+
+ QPRINTF(("sbicselectbus %d\n", target));
+
+ /*
+ * if we're already selected, return (XXXX panic maybe?)
+ */
+ if (dev->sc_flags & SBICF_SELECTED)
+ return(1);
+
+ SET_SBIC_rselid (regs, 0);
+#if 0
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
+ /* This means we got ourselves reselected upon */
+/* printf("sbicselectbus: weird asr %02x\n", asr);*/
+#ifdef DDB
+/* Debugger();*/
+#endif
+ SET_SBIC_rselid (regs, SBIC_RID_ER);
+ return 1;
+ }
+#endif
+ /*
+ * issue select
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_selid(regs, target);
+ SET_SBIC_timeo(regs, SBIC_TIMEOUT(250,dev->sc_clkfreq));
+
+ /*
+ * set sync or async
+ */
+ if (dev->sc_sync[target].state == SYNC_DONE)
+ SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[target].offset,
+ dev->sc_sync[target].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
+
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
+ /* This means we got ourselves reselected upon */
+/* printf("sbicselectbus: INT/BSY asr %02x\n", asr);*/
+#ifdef DDB
+/* Debugger();*/
+#endif
+ return 1;
+ }
+
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN);
+
+ /*
+ * wait for select (merged from seperate function may need
+ * cleanup)
+ */
+ WAIT_CIP(regs);
+#if 0
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_LCI ) {
+ /* This means we got ourselves reselected upon */
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("sbicselectbus: LCI asr %02x\n", asr);
+/* Debugger();*/
+#endif
+ return 1;
+ }
+#endif
+ do {
+ asr = SBIC_WAIT(regs, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
+ if (asr & SBIC_ASR_LCI) {
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("sbicselectbus: late LCI asr %02x\n", asr);
+#endif
+ return 1;
+ }
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("%02x ", csr));
+ if( csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) {
+#ifdef DEBUG
+ if( reselect_debug || 1 )
+ printf("sbicselectbus: reselected asr %02x\n", asr);
+#endif
+ /* We need to handle this now so we don't lock up later */
+ sbicnextstate(dev, csr, asr);
+ return 1;
+ }
+ if( csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) {
+ panic("sbicselectbus: target issued select!");
+ return 1;
+ }
+ } while (csr != (SBIC_CSR_MIS_2|MESG_OUT_PHASE)
+ && csr != (SBIC_CSR_MIS_2|CMD_PHASE) && csr != SBIC_CSR_SEL_TIMEO);
+
+ /* Enable (or not) reselection */
+ if( (dev->sc_xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_enable_reselect)
+ && dev->nexus_list.tqh_first == NULL )
+ SET_SBIC_rselid (regs, 0);
+ else
+ SET_SBIC_rselid (regs, SBIC_RID_ER);
+
+ if (csr == (SBIC_CSR_MIS_2|CMD_PHASE)) {
+ dev->sc_flags |= SBICF_SELECTED; /* device ignored ATN */
+ GET_SBIC_selid(regs, id);
+ dev->target = id;
+ GET_SBIC_tlun(regs,dev->lun);
+ if( dev->lun & SBIC_TLUN_VALID )
+ dev->lun &= SBIC_TLUN_MASK;
+ else
+ dev->lun = lun;
+ } else if (csr == (SBIC_CSR_MIS_2|MESG_OUT_PHASE)) {
+ /*
+ * Send identify message
+ * (SCSI-2 requires an identify msg (?))
+ */
+ GET_SBIC_selid(regs, id);
+ dev->target = id;
+ GET_SBIC_tlun(regs,dev->lun);
+ if( dev->lun & SBIC_TLUN_VALID )
+ dev->lun &= SBIC_TLUN_MASK;
+ else
+ dev->lun = lun;
+ /*
+ * handle drives that don't want to be asked
+ * whether to go sync at all.
+ */
+ if (sbic_inhibit_sync && dev->sc_sync[id].state == SYNC_START) {
+#ifdef DEBUG
+ if (sync_debug)
+ printf("Forcing target %d asynchronous.\n", id);
+#endif
+ dev->sc_sync[id].offset = 0;
+ dev->sc_sync[id].period = sbic_min_period;
+ dev->sc_sync[id].state = SYNC_DONE;
+ }
+
+
+ if (dev->sc_sync[id].state != SYNC_START){
+ if( dev->sc_xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_enable_reselect )
+ SEND_BYTE (regs, MSG_IDENTIFY | lun);
+ else
+ SEND_BYTE (regs, MSG_IDENTIFY_DR | lun);
+ } else {
+ /*
+ * try to initiate a sync transfer.
+ * So compose the sync message we're going
+ * to send to the target
+ */
+
+#ifdef DEBUG
+ if (sync_debug)
+ printf("Sending sync request to target %d ... ",
+ id);
+#endif
+ /*
+ * setup scsi message sync message request
+ */
+ dev->sc_msg[0] = MSG_IDENTIFY | lun;
+ dev->sc_msg[1] = MSG_EXT_MESSAGE;
+ dev->sc_msg[2] = 3;
+ dev->sc_msg[3] = MSG_SYNC_REQ;
+ dev->sc_msg[4] = sbictoscsiperiod(dev, regs,
+ sbic_min_period);
+ dev->sc_msg[5] = sbic_max_offset;
+
+ if (sbicxfstart(regs, 6, MESG_OUT_PHASE, sbic_cmd_wait))
+ sbicxfout(regs, 6, dev->sc_msg, MESG_OUT_PHASE);
+
+ dev->sc_sync[id].state = SYNC_SENT;
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("sent\n");
+#endif
+ }
+
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("[%02x]", csr));
+#ifdef DEBUG
+ if (sync_debug && dev->sc_sync[id].state == SYNC_SENT)
+ printf("csr-result of last msgout: 0x%x\n", csr);
+#endif
+
+ if (csr != SBIC_CSR_SEL_TIMEO)
+ dev->sc_flags |= SBICF_SELECTED;
+ }
+ if (csr == SBIC_CSR_SEL_TIMEO)
+ dev->sc_xs->error = XS_SELTIMEOUT;
+
+ QPRINTF(("\n"));
+
+ return(csr == SBIC_CSR_SEL_TIMEO);
+}
+
+int
+sbicxfstart(regs, len, phase, wait)
+ sbic_regmap_p regs;
+ int len, wait;
+ u_char phase;
+{
+ u_char id;
+
+ switch (phase) {
+ case DATA_IN_PHASE:
+ case MESG_IN_PHASE:
+ GET_SBIC_selid (regs, id);
+ id |= SBIC_SID_FROM_SCSI;
+ SET_SBIC_selid (regs, id);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ break;
+ case DATA_OUT_PHASE:
+ case MESG_OUT_PHASE:
+ case CMD_PHASE:
+ GET_SBIC_selid (regs, id);
+ id &= ~SBIC_SID_FROM_SCSI;
+ SET_SBIC_selid (regs, id);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ break;
+ default:
+ SBIC_TC_PUT (regs, 0);
+ }
+ QPRINTF(("sbicxfstart %d, %d, %d\n", len, phase, wait));
+
+ return(1);
+}
+
+int
+sbicxfout(regs, len, bp, phase)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+ int phase;
+{
+ u_char orig_csr, csr, asr, *buf;
+ int wait;
+
+ buf = bp;
+ wait = sbic_data_wait;
+
+ QPRINTF(("sbicxfout {%d} %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2],
+ buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]));
+
+ GET_SBIC_csr (regs, orig_csr);
+
+ /*
+ * sigh.. WD-PROTO strikes again.. sending the command in one go
+ * causes the chip to lock up if talking to certain (misbehaving?)
+ * targets. Anyway, this procedure should work for all targets, but
+ * it's slightly slower due to the overhead
+ */
+ WAIT_CIP (regs);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+ for (;len > 0; len--) {
+ GET_SBIC_asr (regs, asr);
+ while ((asr & SBIC_ASR_DBR) == 0) {
+ if ((asr & SBIC_ASR_INT) || --wait < 0) {
+#ifdef DEBUG
+ if (sbic_debug)
+ printf("sbicxfout fail: l%d i%x w%d\n",
+ len, asr, wait);
+#endif
+ return (len);
+ }
+/* DELAY(1);*/
+ GET_SBIC_asr (regs, asr);
+ }
+
+ SET_SBIC_data (regs, *buf);
+ buf++;
+ }
+ SBIC_TC_GET(regs, len);
+ QPRINTF(("sbicxfout done %d bytes\n", len));
+ /*
+ * this leaves with one csr to be read
+ */
+ return(0);
+}
+
+/* returns # bytes left to read */
+int
+sbicxfin(regs, len, bp)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+{
+ int wait, read;
+ u_char *obp, *buf;
+ u_char orig_csr, csr, asr;
+
+ wait = sbic_data_wait;
+ obp = bp;
+ buf = bp;
+
+ GET_SBIC_csr (regs, orig_csr);
+
+ QPRINTF(("sbicxfin %d, csr=%02x\n", len, orig_csr));
+
+ WAIT_CIP (regs);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+ for (;len > 0; len--) {
+ GET_SBIC_asr (regs, asr);
+ if((asr & SBIC_ASR_PE)) {
+#ifdef DEBUG
+ printf("sbicxfin parity error: l%d i%x w%d\n",
+ len, asr, wait);
+/* return ((unsigned long)buf - (unsigned long)bp); */
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ }
+ while ((asr & SBIC_ASR_DBR) == 0) {
+ if ((asr & SBIC_ASR_INT) || --wait < 0) {
+#ifdef DEBUG
+ if (sbic_debug) {
+ QPRINTF(("sbicxfin fail:{%d} %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
+ obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
+ printf("sbicxfin fail: l%d i%x w%d\n",
+ len, asr, wait);
+}
+#endif
+ return len;
+ }
+
+ if( ! asr & SBIC_ASR_BSY ) {
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("[CSR%02xASR%02x]", csr, asr));
+ }
+
+/* DELAY(1);*/
+ GET_SBIC_asr (regs, asr);
+ }
+
+ GET_SBIC_data (regs, *buf);
+/* QPRINTF(("asr=%02x, csr=%02x, data=%02x\n", asr, csr, *buf));*/
+ buf++;
+ }
+
+ QPRINTF(("sbicxfin {%d} %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
+ obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
+
+ /* this leaves with one csr to be read */
+ return len;
+}
+
+/*
+ * SCSI 'immediate' command: issue a command to some SCSI device
+ * and get back an 'immediate' response (i.e., do programmed xfer
+ * to get the response data). 'cbuf' is a buffer containing a scsi
+ * command of length clen bytes. 'buf' is a buffer of length 'len'
+ * bytes for data. The transfer direction is determined by the device
+ * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the
+ * command must supply no data.
+ */
+int
+sbicicmd(dev, target, lun, cbuf, clen, buf, len)
+ struct sbic_softc *dev;
+ void *cbuf, *buf;
+ int clen, len;
+{
+ sbic_regmap_p regs;
+ u_char phase, csr, asr;
+ int wait, newtarget, cmd_sent, parity_err;
+ struct sbic_acb *acb;
+
+ int discon;
+ int i;
+
+#define CSR_LOG_BUF_SIZE 0
+#if CSR_LOG_BUF_SIZE
+ int bufptr;
+ int csrbuf[CSR_LOG_BUF_SIZE];
+ bufptr=0;
+#endif
+
+ regs = dev->sc_sbicp;
+ acb = dev->sc_nexus;
+
+ /* Make sure pointers are OK */
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
+ dev->sc_tcnt = acb->sc_tcnt = 0;
+ acb->sc_pa.dc_count = 0; /* No DMA */
+ acb->sc_kv.dc_addr = buf;
+ acb->sc_kv.dc_count = len;
+
+#ifdef DEBUG
+ routine = 3;
+ debug_sbic_regs = regs; /* store this to allow debug calls */
+ if( data_pointer_debug > 1 )
+ printf("sbicicmd(%d,%d):%d\n", target, lun,
+ acb->sc_kv.dc_count);
+#endif
+
+ /*
+ * set the sbic into non-DMA mode
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /*| SBIC_CTL_HSP*/);
+
+ dev->sc_stat[0] = 0xff;
+ dev->sc_msg[0] = 0xff;
+ i = 1; /* pre-load */
+
+ /* We're stealing the SCSI bus */
+ dev->sc_flags |= SBICF_ICMD;
+
+ do {
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if (!( dev->sc_flags & SBICF_SELECTED )
+ && sbicselectbus(dev, regs, target, lun, dev->sc_scsiaddr)) {
+ /*printf("sbicicmd trying to select busy bus!\n");*/
+ dev->sc_flags &= ~SBICF_ICMD;
+ return(-1);
+ }
+
+ /*
+ * Wait for a phase change (or error) then let the device sequence
+ * us through the various SCSI phases.
+ */
+
+ wait = sbic_cmd_wait;
+
+ GET_SBIC_asr (regs, asr);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF((">ASR:%02xCSR:%02x<", asr, csr));
+
+#if CSR_LOG_BUF_SIZE
+ csrbuf[bufptr++] = csr;
+#endif
+
+
+ switch (csr) {
+ case SBIC_CSR_S_XFERRED:
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ dev->sc_flags &= ~SBICF_SELECTED;
+ GET_SBIC_cmd_phase (regs, phase);
+ if (phase == 0x60) {
+ GET_SBIC_tlun (regs, dev->sc_stat[0]);
+ i = 0; /* done */
+/* break; /* Bypass all the state gobldygook */
+ } else {
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicicmd: handling disconnect\n");
+#endif
+ i = SBIC_STATE_DISCONNECT;
+ }
+ break;
+
+ case SBIC_CSR_XFERRED|CMD_PHASE:
+ case SBIC_CSR_MIS|CMD_PHASE:
+ case SBIC_CSR_MIS_1|CMD_PHASE:
+ case SBIC_CSR_MIS_2|CMD_PHASE:
+ if (sbicxfstart(regs, clen, CMD_PHASE, sbic_cmd_wait))
+ if (sbicxfout(regs, clen,
+ cbuf, CMD_PHASE))
+ i = sbicabort(dev, regs,"icmd sending cmd");
+#if 0
+ GET_SBIC_csr(regs, csr); /* Lets us reload tcount */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
+ printf("next: cmd sent asr %02x, csr %02x\n",
+ asr, csr);
+#endif
+ break;
+
+#if 0
+ case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
+ case SBIC_CSR_XFERRED|DATA_IN_PHASE:
+ case SBIC_CSR_MIS|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2|DATA_IN_PHASE:
+ if (acb->sc_kv.dc_count <= 0)
+ i = sbicabort(dev, regs, "icmd out of data");
+ else {
+ wait = sbic_data_wait;
+ if (sbicxfstart(regs,
+ acb->sc_kv.dc_count,
+ SBIC_PHASE(csr), wait))
+ if (csr & 0x01)
+ /* data in? */
+ i=sbicxfin(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+ else
+ i=sbicxfout(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr,
+ SBIC_PHASE(csr));
+ acb->sc_kv.dc_addr +=
+ (acb->sc_kv.dc_count - i);
+ acb->sc_kv.dc_count = i;
+ i = 1;
+ }
+ break;
+
+#endif
+ case SBIC_CSR_XFERRED|STATUS_PHASE:
+ case SBIC_CSR_MIS|STATUS_PHASE:
+ case SBIC_CSR_MIS_1|STATUS_PHASE:
+ case SBIC_CSR_MIS_2|STATUS_PHASE:
+ /*
+ * the sbic does the status/cmd-complete reading ok,
+ * so do this with its hi-level commands.
+ */
+#ifdef DEBUG
+ if(sbic_debug)
+ printf("SBICICMD status phase\n");
+#endif
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+ break;
+
+#if THIS_IS_A_RESERVED_STATE
+ case BUS_FREE_PHASE: /* This is not legal */
+ if( dev->sc_stat[0] != 0xff )
+ goto out;
+ break;
+#endif
+
+ default:
+ i = sbicnextstate(dev, csr, asr);
+ }
+
+ /*
+ * make sure the last command was taken,
+ * ie. we're not hunting after an ignored command..
+ */
+ GET_SBIC_asr(regs, asr);
+
+ /* tapes may take a loooong time.. */
+ while (asr & SBIC_ASR_BSY){
+ if(asr & SBIC_ASR_DBR) {
+ printf("sbicicmd: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
+ csr,asr);
+#ifdef DDB
+ Debugger();
+#endif
+ /* SBIC is jammed */
+ /* DUNNO which direction */
+ /* Try old direction */
+ GET_SBIC_data(regs,i);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR) /* Wants us to write */
+ SET_SBIC_data(regs,i);
+ }
+ GET_SBIC_asr(regs, asr);
+ }
+
+ /*
+ * wait for last command to complete
+ */
+ if (asr & SBIC_ASR_LCI) {
+ printf("sbicicmd: last command ignored\n");
+ }
+ else if( i == 1 ) /* Bsy */
+ SBIC_WAIT (regs, SBIC_ASR_INT, wait);
+
+ /*
+ * do it again
+ */
+ } while ( i > 0 && dev->sc_stat[0] == 0xff);
+
+ /* Sometimes we need to do an extra read of the CSR */
+ GET_SBIC_csr(regs, csr);
+
+#if CSR_LOG_BUF_SIZE
+ if(reselect_debug>1)
+ for(i=0; i<bufptr; i++)
+ printf("CSR:%02x", csrbuf[i]);
+#endif
+
+#ifdef DEBUG
+ if(data_pointer_debug > 1)
+ printf("sbicicmd done(%d,%d):%d =%d=\n",
+ dev->target, lun,
+ acb->sc_kv.dc_count,
+ dev->sc_stat[0]);
+#endif
+
+ QPRINTF(("=STS:%02x=", dev->sc_stat[0]));
+ dev->sc_flags &= ~SBICF_ICMD;
+
+ return(dev->sc_stat[0]);
+}
+
+/*
+ * Finish SCSI xfer command: After the completion interrupt from
+ * a read/write operation, sequence through the final phases in
+ * programmed i/o. This routine is a lot like sbicicmd except we
+ * skip (and don't allow) the select, cmd out and data in/out phases.
+ */
+void
+sbicxfdone(dev, regs, target)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int target;
+{
+ u_char phase, csr;
+ int s;
+
+ QPRINTF(("{"));
+ s = splbio();
+
+ /*
+ * have the sbic complete on its own
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+
+ do {
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("%02x:", csr));
+ } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_S_XFERRED));
+
+ dev->sc_flags &= ~SBICF_SELECTED;
+
+ GET_SBIC_cmd_phase (regs, phase);
+ QPRINTF(("}%02x", phase));
+ if (phase == 0x60)
+ GET_SBIC_tlun(regs, dev->sc_stat[0]);
+ else
+ sbicerror(dev, regs, csr);
+
+ QPRINTF(("=STS:%02x=\n", dev->sc_stat[0]));
+ splx(s);
+}
+
+ /*
+ * No DMA chains
+ */
+
+int
+sbicgo(dev, xs)
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
+{
+ int i, dmaflags, count, wait, usedma;
+ u_char csr, asr, cmd, *addr;
+ sbic_regmap_p regs;
+ struct sbic_acb *acb;
+
+ dev->target = xs->sc_link->target;
+ dev->lun = xs->sc_link->lun;
+ acb = dev->sc_nexus;
+ regs = dev->sc_sbicp;
+
+ usedma = sbicdmaok(dev, xs);
+#ifdef DEBUG
+ routine = 1;
+ debug_sbic_regs = regs; /* store this to allow debug calls */
+ if( data_pointer_debug > 1 )
+ printf("sbicgo(%d,%d)\n", dev->target, dev->lun);
+#endif
+
+ /*
+ * set the sbic into DMA mode
+ */
+ if( usedma )
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ SBIC_MACHINE_DMA_MODE);
+ else
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if (sbicselectbus(dev, regs, dev->target, dev->lun,
+ dev->sc_scsiaddr)) {
+/* printf("sbicgo: Trying to select busy bus!\n"); */
+ return(0); /* Not done: needs to be rescheduled */
+ }
+ dev->sc_stat[0] = 0xff;
+
+ /*
+ * Calculate DMA chains now
+ */
+
+ dmaflags = 0;
+ if (acb->flags & ACB_DATAIN)
+ dmaflags |= DMAGO_READ;
+
+
+ /*
+ * Deal w/bounce buffers.
+ */
+
+ addr = acb->sc_kv.dc_addr;
+ count = acb->sc_kv.dc_count;
+ if (count && (char *)kvtop(addr) != acb->sc_pa.dc_addr) { /* XXXX check */
+ printf("sbic: DMA buffer mapping changed %x->%x\n",
+ acb->sc_pa.dc_addr, kvtop(addr));
+#ifdef DDB
+ Debugger();
+#endif
+ }
+
+#ifdef DEBUG
+ ++sbicdma_ops; /* count total DMA operations */
+#endif
+ if (count && usedma && dev->sc_flags & SBICF_BADDMA &&
+ sbiccheckdmap(addr, count, dev->sc_dmamask)) {
+ /*
+ * need to bounce the dma.
+ */
+ if (dmaflags & DMAGO_READ) {
+ acb->flags |= ACB_BBUF;
+ acb->sc_dmausrbuf = addr;
+ acb->sc_dmausrlen = count;
+ acb->sc_usrbufpa = (u_char *)kvtop(addr);
+ if(!dev->sc_tinfo[dev->target].bounce) {
+ printf("sbicgo: HELP! no bounce allocated for %d\n",
+ dev->target);
+ printf("xfer: (%x->%x,%x)\n", acb->sc_dmausrbuf,
+ acb->sc_usrbufpa, acb->sc_dmausrlen);
+#if 0
+ dev->sc_tinfo[xs->sc_link->target].bounce
+ = (char *)alloc_z2mem(MAXPHYS);
+ if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
+ printf("alloc ZII target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
+ else if (dev->sc_tinfo[xs->sc_link->target].bounce)
+ printf("alloc CHIP target %d bounce pa 0x%x\n",
+ xs->sc_link->target,
+ PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
+#endif
+
+ printf("Allocating %d bounce at %x\n",
+ dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+ }
+ } else { /* write: copy to dma buffer */
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("sbicgo: copying %x bytes to target %d bounce %x\n",
+ count, dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+#endif
+ bcopy (addr, dev->sc_tinfo[dev->target].bounce, count);
+ }
+ addr = dev->sc_tinfo[dev->target].bounce;/* and use dma buffer */
+ acb->sc_kv.dc_addr = addr;
+#ifdef DEBUG
+ ++sbicdma_bounces; /* count number of bounced */
+#endif
+ }
+
+ /*
+ * Allocate the DMA chain
+ */
+
+ /* Set start KVM addresses */
+#if 0
+ acb->sc_kv.dc_addr = addr;
+ acb->sc_kv.dc_count = count;
+#endif
+
+ /* Mark end of segment */
+ acb->sc_tcnt = dev->sc_tcnt = 0;
+ acb->sc_pa.dc_count = 0;
+
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+ /* Enable interrupts but don't do any DMA */
+ dev->sc_tcnt = dev->sc_dmago(dev, acb->sc_pa.dc_addr,
+ acb->sc_pa.dc_count,
+ dmaflags);
+ dev->sc_flags |= SBICF_INDMA;
+ if( !usedma )
+ dev->sc_dmacmd = 0; /* Don't use DMA */
+/* SBIC_TC_PUT(regs, dev->sc_tcnt); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+
+ /*
+ * push the data cache ( I think this won't work (EH))
+ */
+#if defined(M68040)
+ if (mmutype == MMU_68040 && usedma && count) {
+ dma_cachectl(addr, count);
+ if (((u_int)addr & 0xF) || (((u_int)addr + count) & 0xF))
+ dev->sc_flags |= SBICF_DCFLUSH;
+ }
+#endif
+
+ /*
+ * dmago() also enables interrupts for the sbic
+ */
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("sbicgo dmago:%d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+ if( sbic_timeout && !timeout_active ) {
+ timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
+ timeout_active = 1;
+ }
+ debug_asr = asr;
+ debug_csr = csr;
+#endif
+
+ /*
+ * Lets cycle a while then let the interrupt handler take over
+ */
+
+ GET_SBIC_asr(regs, asr);
+ do {
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 1;
+#endif
+ QPRINTF(("go[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+ if(asr & SBIC_ASR_LCI) printf("sbicgo: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+ } while( i == SBIC_STATE_RUNNING
+ && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
+
+ if (i == SBIC_STATE_DONE && dev->sc_stat[0] != 0xff) {
+ /* Did we really finish that fast? */
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+sbicintr(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ struct dma_chain *df, *dl;
+ u_char asr, csr, *tmpaddr;
+ struct sbic_acb *acb;
+ int i, newtarget, newlun;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+
+ /*
+ * pending interrupt?
+ */
+ GET_SBIC_asr (regs, asr);
+ if ((asr & SBIC_ASR_INT) == 0)
+ return(0);
+
+ do {
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 2;
+#endif
+ QPRINTF(("intr[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+#if 0
+ if(asr & SBIC_ASR_LCI) printf("sbicintr: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+#endif
+ } while(i == SBIC_STATE_RUNNING &&
+ asr & (SBIC_ASR_INT|SBIC_ASR_LCI));
+ return(1);
+}
+
+/*
+ * Run commands and wait for disconnect
+ */
+int
+sbicpoll(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ u_char asr, csr;
+ struct sbic_pending* pendp;
+ int i;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+
+ do {
+ GET_SBIC_asr (regs, asr);
+#ifdef DEBUG
+ debug_asr = asr;
+#endif
+ GET_SBIC_csr(regs, csr);
+#ifdef DEBUG
+ debug_csr = csr;
+ routine = 2;
+#endif
+ QPRINTF(("poll[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
+
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ /* tapes may take a loooong time.. */
+ while (asr & SBIC_ASR_BSY){
+ if(asr & SBIC_ASR_DBR) {
+ printf("sbipoll: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
+ csr,asr);
+#ifdef DDB
+ Debugger();
+#endif
+ /* SBIC is jammed */
+ /* DUNNO which direction */
+ /* Try old direction */
+ GET_SBIC_data(regs,i);
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR) /* Wants us to write */
+ SET_SBIC_data(regs,i);
+ }
+ GET_SBIC_asr(regs, asr);
+ }
+
+ if(asr & SBIC_ASR_LCI) printf("sbicpoll: LCI asr:%02x csr:%02x\n",
+ asr,csr);
+ else if( i == 1 ) /* BSY */
+ SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
+ } while(i == SBIC_STATE_RUNNING);
+ return(1);
+}
+
+/*
+ * Handle a single msgin
+ */
+
+int
+sbicmsgin(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs;
+ int recvlen;
+ u_char asr, csr, *tmpaddr;
+
+ regs = dev->sc_sbicp;
+
+ dev->sc_msg[0] = 0xff;
+ dev->sc_msg[1] = 0xff;
+
+ GET_SBIC_asr(regs, asr);
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicmsgin asr=%02x\n", asr);
+#endif
+
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+
+ GET_SBIC_selid (regs, csr);
+ SET_SBIC_selid (regs, csr | SBIC_SID_FROM_SCSI);
+
+ SBIC_TC_PUT(regs, 0);
+ tmpaddr = dev->sc_msg;
+ recvlen = 1;
+ do {
+ while( recvlen-- ) {
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin ready to go (csr,asr)=(%02x,%02x)\n",
+ csr, asr));
+
+ RECV_BYTE(regs, *tmpaddr);
+#if 1
+ /*
+ * get the command completion interrupt, or we
+ * can't send a new command (LCI)
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+#else
+ WAIT_CIP(regs);
+ do {
+ GET_SBIC_asr(regs, asr);
+ csr = 0xff;
+ GET_SBIC_csr(regs, csr);
+ if( csr == 0xff )
+ printf("sbicmsgin waiting: csr %02x asr %02x\n", csr, asr);
+ } while( csr == 0xff );
+#endif
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicmsgin: got %02x csr %02x asr %02x\n",
+ *tmpaddr, csr, asr);
+#endif
+#if do_parity_check
+ if( asr & SBIC_ASR_PE ) {
+ printf ("Parity error");
+ /* This code simply does not work. */
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ WAIT_CIP(regs);
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ WAIT_CIP(regs);
+ if( !(asr & SBIC_ASR_LCI) )
+ /* Target wants to send garbled msg*/
+ continue;
+ printf("--fixing\n");
+ /* loop until a msgout phase occurs on target */
+ while(csr & 0x07 != MESG_OUT_PHASE) {
+ while( asr & SBIC_ASR_BSY &&
+ !(asr & SBIC_ASR_DBR|SBIC_ASR_INT) )
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR )
+ panic("msgin: jammed again!\n");
+ GET_SBIC_csr(regs, csr);
+ if( csr & 0x07 != MESG_OUT_PHASE ) {
+ sbicnextstate(dev, csr, asr);
+ sbic_save_ptrs(dev, regs,
+ dev->target,
+ dev->lun);
+ }
+ }
+ /* Should be msg out by now */
+ SEND_BYTE(regs, MSG_PARITY_ERROR);
+ }
+ else
+#endif
+ tmpaddr++;
+
+ if(recvlen) {
+ /* Clear ACK */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin pre byte CLR_ACK (csr,asr)=(%02x,%02x)\n",
+ csr, asr));
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ }
+
+ };
+
+ if(dev->sc_msg[0] == 0xff) {
+ printf("sbicmsgin: sbic swallowed our message\n");
+ break;
+ }
+#ifdef DEBUG
+ if (sync_debug)
+ printf("msgin done csr 0x%x asr 0x%x msg 0x%x\n",
+ csr, asr, dev->sc_msg[0]);
+#endif
+ /*
+ * test whether this is a reply to our sync
+ * request
+ */
+ if (MSG_ISIDENTIFY(dev->sc_msg[0])) {
+ QPRINTF(("IFFY"));
+#if 0
+ /* There is an implied load-ptrs here */
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+#endif
+ /* Got IFFY msg -- ack it */
+ } else if (dev->sc_msg[0] == MSG_REJECT
+ && dev->sc_sync[dev->target].state == SYNC_SENT) {
+ QPRINTF(("REJECT of SYN"));
+#ifdef DEBUG
+ if (sync_debug)
+ printf("target %d rejected sync, going async\n",
+ dev->target);
+#endif
+ dev->sc_sync[dev->target].period = sbic_min_period;
+ dev->sc_sync[dev->target].offset = 0;
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+ SET_SBIC_syn(regs,
+ SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+ } else if ((dev->sc_msg[0] == MSG_REJECT)) {
+ QPRINTF(("REJECT"));
+ /*
+ * we'll never REJECt a REJECT message..
+ */
+ } else if ((dev->sc_msg[0] == MSG_SAVE_DATA_PTR)) {
+ QPRINTF(("MSG_SAVE_DATA_PTR"));
+ /*
+ * don't reject this either.
+ */
+ } else if ((dev->sc_msg[0] == MSG_DISCONNECT)) {
+ QPRINTF(("DISCONNECT"));
+#ifdef DEBUG
+ if( reselect_debug>1 && dev->sc_msg[0] == MSG_DISCONNECT )
+ printf("sbicmsgin: got disconnect msg %s\n",
+ (dev->sc_flags & SBICF_ICMD)?"rejecting":"");
+#endif
+ if( dev->sc_flags & SBICF_ICMD ) {
+ /* We're in immediate mode. Prevent disconnects. */
+ /* prepare to reject the message, NACK */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+ } else if (dev->sc_msg[0] == MSG_CMD_COMPLETE ) {
+ QPRINTF(("CMD_COMPLETE"));
+ /* !! KLUDGE ALERT !! quite a few drives don't seem to
+ * really like the current way of sending the
+ * sync-handshake together with the ident-message, and
+ * they react by sending command-complete and
+ * disconnecting right after returning the valid sync
+ * handshake. So, all I can do is reselect the drive,
+ * and hope it won't disconnect again. I don't think
+ * this is valid behavior, but I can't help fixing a
+ * problem that apparently exists.
+ *
+ * Note: we should not get here on `normal' command
+ * completion, as that condition is handled by the
+ * high-level sel&xfer resume command used to walk
+ * thru status/cc-phase.
+ */
+
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("GOT MSG %d! target %d acting weird.."
+ " waiting for disconnect...\n",
+ dev->sc_msg[0], dev->target);
+#endif
+ /* Check to see if sbic is handling this */
+ GET_SBIC_asr(regs, asr);
+ if(asr & SBIC_ASR_BSY)
+ return SBIC_STATE_RUNNING;
+
+ /* Let's try this: Assume it works and set status to 00 */
+ dev->sc_stat[0] = 0;
+ } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE
+ && tmpaddr == &dev->sc_msg[1]) {
+ QPRINTF(("ExtMSG\n"));
+ /* Read in whole extended message */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("CLR ACK asr %02x, csr %02x\n", asr, csr));
+ RECV_BYTE(regs, *tmpaddr);
+ /* Wait for command completion IRQ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ recvlen = *tmpaddr++;
+ QPRINTF(("Recving ext msg, asr %02x csr %02x len %02x\n",
+ asr, csr, recvlen));
+ } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE && dev->sc_msg[1] == 3
+ && dev->sc_msg[2] == MSG_SYNC_REQ) {
+ QPRINTF(("SYN"));
+ dev->sc_sync[dev->target].period =
+ sbicfromscsiperiod(dev,
+ regs, dev->sc_msg[3]);
+ dev->sc_sync[dev->target].offset = dev->sc_msg[4];
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+ SET_SBIC_syn(regs,
+ SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+ printf("%s: target %d now synchronous,"
+ " period=%dns, offset=%d.\n",
+ dev->sc_dev.dv_xname, dev->target,
+ dev->sc_msg[3] * 4, dev->sc_msg[4]);
+ } else {
+#ifdef DEBUG
+ if (sbic_debug || sync_debug)
+ printf ("sbicmsgin: Rejecting message 0x%02x\n",
+ dev->sc_msg[0]);
+#endif
+ /* prepare to reject the message, NACK */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+ /* Clear ACK */
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+ QPRINTF(("sbicmsgin pre CLR_ACK (csr,asr)=(%02x,%02x)%d\n",
+ csr, asr, recvlen));
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ }
+#if 0
+ while((csr == SBIC_CSR_MSGIN_W_ACK)
+ || (SBIC_PHASE(csr) == MESG_IN_PHASE));
+#else
+ while (recvlen>0);
+#endif
+
+ QPRINTF(("sbicmsgin finished: csr %02x, asr %02x\n",csr, asr));
+
+ /* Should still have one CSR to read */
+ return SBIC_STATE_RUNNING;
+}
+
+
+/*
+ * sbicnextstate()
+ * return:
+ * 0 == done
+ * 1 == working
+ * 2 == disconnected
+ * -1 == error
+ */
+int
+sbicnextstate(dev, csr, asr)
+ struct sbic_softc *dev;
+ u_char csr, asr;
+{
+ sbic_regmap_p regs;
+ struct dma_chain *df, *dl;
+ struct sbic_acb *acb;
+ int i, newtarget, newlun, wait;
+ unsigned tcnt;
+
+ regs = dev->sc_sbicp;
+ acb = dev->sc_nexus;
+
+ QPRINTF(("next[%02x,%02x]",asr,csr));
+
+ switch (csr) {
+ case SBIC_CSR_XFERRED|CMD_PHASE:
+ case SBIC_CSR_MIS|CMD_PHASE:
+ case SBIC_CSR_MIS_1|CMD_PHASE:
+ case SBIC_CSR_MIS_2|CMD_PHASE:
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ if (sbicxfstart(regs, acb->clen, CMD_PHASE, sbic_cmd_wait))
+ if (sbicxfout(regs, acb->clen,
+ &acb->cmd, CMD_PHASE))
+ goto abort;
+ break;
+
+ case SBIC_CSR_XFERRED|STATUS_PHASE:
+ case SBIC_CSR_MIS|STATUS_PHASE:
+ case SBIC_CSR_MIS_1|STATUS_PHASE:
+ case SBIC_CSR_MIS_2|STATUS_PHASE:
+ /*
+ * this should be the normal i/o completion case.
+ * get the status & cmd complete msg then let the
+ * device driver look at what happened.
+ */
+ sbicxfdone(dev,regs,dev->target);
+ /*
+ * check for overlapping cache line, flush if so
+ */
+#ifdef M68040
+ if (dev->sc_flags & SBICF_DCFLUSH) {
+#if 0
+ printf("sbic: 68040 DMA cache flush needs fixing? %x:%x\n",
+ dev->sc_xs->data, dev->sc_xs->datalen);
+#endif
+ }
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev); /* was dmafree */
+ if (acb->flags & ACB_BBUF) {
+ if ((u_char *)kvtop(acb->sc_dmausrbuf) != acb->sc_usrbufpa)
+ printf("%s: WARNING - buffer mapping changed %x->%x\n",
+ dev->sc_dev.dv_xname, acb->sc_usrbufpa,
+ kvtop(acb->sc_dmausrbuf));
+#ifdef DEBUG
+ if(data_pointer_debug)
+ printf("sbicgo:copying %x bytes from target %d bounce %x\n",
+ acb->sc_dmausrlen,
+ dev->target,
+ kvtop(dev->sc_tinfo[dev->target].bounce));
+#endif
+ bcopy(dev->sc_tinfo[dev->target].bounce,
+ acb->sc_dmausrbuf,
+ acb->sc_dmausrlen);
+ }
+ dev->sc_flags &= ~(SBICF_INDMA | SBICF_DCFLUSH);
+ sbic_scsidone(acb, dev->sc_stat[0]);
+ return SBIC_STATE_DONE;
+
+ case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
+ case SBIC_CSR_XFERRED|DATA_IN_PHASE:
+ case SBIC_CSR_MIS|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1|DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2|DATA_IN_PHASE:
+ if( dev->sc_xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD
+ || acb->sc_dmacmd == 0 ) {
+ /* Do PIO */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ if (acb->sc_kv.dc_count <= 0) {
+ printf("sbicnextstate:xfer count %d asr%x csr%x\n",
+ acb->sc_kv.dc_count, asr, csr);
+ goto abort;
+ }
+ wait = sbic_data_wait;
+ if( sbicxfstart(regs,
+ acb->sc_kv.dc_count,
+ SBIC_PHASE(csr), wait))
+ if( SBIC_PHASE(csr) == DATA_IN_PHASE )
+ /* data in? */
+ i=sbicxfin(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+ else
+ i=sbicxfout(regs,
+ acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr,
+ SBIC_PHASE(csr));
+ acb->sc_kv.dc_addr +=
+ (acb->sc_kv.dc_count - i);
+ acb->sc_kv.dc_count = i;
+ } else {
+ /*
+ * do scatter-gather dma
+ * hacking the controller chip, ouch..
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ SBIC_MACHINE_DMA_MODE);
+ /*
+ * set next dma addr and dec count
+ */
+#if 0
+ SBIC_TC_GET(regs, tcnt);
+ dev->sc_cur->dc_count -= ((dev->sc_tcnt - tcnt) >> 1);
+ dev->sc_cur->dc_addr += (dev->sc_tcnt - tcnt);
+ dev->sc_tcnt = acb->sc_tcnt = tcnt;
+#else
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ sbic_load_ptrs(dev, regs, dev->target, dev->lun);
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmanext: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
+#endif
+ dev->sc_tcnt = dev->sc_dmanext(dev);
+ SBIC_TC_PUT(regs, (unsigned)dev->sc_tcnt);
+ SET_SBIC_cmd(regs, SBIC_CMD_XFER_INFO);
+ dev->sc_flags |= SBICF_INDMA;
+ }
+ break;
+
+ case SBIC_CSR_XFERRED|MESG_IN_PHASE:
+ case SBIC_CSR_MIS|MESG_IN_PHASE:
+ case SBIC_CSR_MIS_1|MESG_IN_PHASE:
+ case SBIC_CSR_MIS_2|MESG_IN_PHASE:
+ return sbicmsgin(dev);
+
+ case SBIC_CSR_MSGIN_W_ACK:
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK); /* Dunno what I'm ACKing */
+ printf("Acking unknown msgin CSR:%02x",csr);
+ break;
+
+ case SBIC_CSR_XFERRED|MESG_OUT_PHASE:
+ case SBIC_CSR_MIS|MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_1|MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_2|MESG_OUT_PHASE:
+#ifdef DEBUG
+ if (sync_debug)
+ printf ("sending REJECT msg to last msg.\n");
+#endif
+
+ sbic_save_ptrs(dev, regs, dev->target, dev->lun);
+ /*
+ * should only get here on reject,
+ * since it's always US that
+ * initiate a sync transfer
+ */
+ SEND_BYTE(regs, MSG_REJECT);
+ WAIT_CIP(regs);
+ if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
+ printf("next: REJECT sent asr %02x\n", asr);
+ return SBIC_STATE_RUNNING;
+
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ dev->sc_flags &= ~(SBICF_INDMA|SBICF_SELECTED);
+
+ /* Try to schedule another target */
+#ifdef DEBUG
+ if(reselect_debug>1)
+ printf("sbicnext target %d disconnected\n", dev->target);
+#endif
+ TAILQ_INSERT_HEAD(&dev->nexus_list, acb, chain);
+ ++dev->sc_tinfo[dev->target].dconns;
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+
+ if( acb->xs->flags & SCSI_POLL
+ || (dev->sc_flags & SBICF_ICMD)
+ || !sbic_parallel_operations )
+ return SBIC_STATE_DISCONNECT;
+ sbic_sched(dev);
+ return SBIC_STATE_DISCONNECT;
+
+ case SBIC_CSR_RSLT_NI:
+ case SBIC_CSR_RSLT_IFY:
+ GET_SBIC_rselid(regs, newtarget);
+ /* check SBIC_RID_SIV? */
+ newtarget &= SBIC_RID_MASK;
+ if (csr == SBIC_CSR_RSLT_IFY) {
+ /* Read IFY msg to avoid lockup */
+ GET_SBIC_data(regs, newlun);
+ WAIT_CIP(regs);
+ newlun &= SBIC_TLUN_MASK;
+ } else {
+ /* Need to get IFY message */
+ for (newlun = 256; newlun; --newlun) {
+ GET_SBIC_asr(regs, asr);
+ if (asr & SBIC_ASR_INT)
+ break;
+ delay(1);
+ }
+ newlun = 0; /* XXXX */
+ if ((asr & SBIC_ASR_INT) == 0) {
+#ifdef DEBUG
+ if (reselect_debug)
+ printf("RSLT_NI - no IFFY message? asr %x\n", asr);
+#endif
+ } else {
+ GET_SBIC_csr(regs,csr);
+ if (csr == SBIC_CSR_MIS|MESG_IN_PHASE ||
+ csr == SBIC_CSR_MIS_1|MESG_IN_PHASE ||
+ csr == SBIC_CSR_MIS_2|MESG_IN_PHASE) {
+ sbicmsgin(dev);
+ newlun = dev->sc_msg[0] & 7;
+ } else {
+ printf("RSLT_NI - not MESG_IN_PHASE %x\n",
+ csr);
+ }
+ }
+ }
+#ifdef DEBUG
+ if(reselect_debug>1 || (reselect_debug && csr==SBIC_CSR_RSLT_NI))
+ printf("sbicnext: reselect %s from targ %d lun %d\n",
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY",
+ newtarget, newlun);
+#endif
+ if (dev->sc_nexus) {
+#ifdef DEBUG
+ if (reselect_debug > 1)
+ printf("%s: reselect %s with active command\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY");
+#ifdef DDB
+/* Debugger();*/
+#endif
+#endif
+ TAILQ_INSERT_HEAD(&dev->ready_list, dev->sc_nexus, chain);
+ dev->sc_tinfo[dev->target].lubusy &= ~(1 << dev->lun);
+ }
+ /* Reload sync values for this target */
+ if (dev->sc_sync[newtarget].state == SYNC_DONE)
+ SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[newtarget].offset,
+ dev->sc_sync[newtarget].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
+ for (acb = dev->nexus_list.tqh_first; acb;
+ acb = acb->chain.tqe_next) {
+ if (acb->xs->sc_link->target != newtarget ||
+ acb->xs->sc_link->lun != newlun)
+ continue;
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+ dev->sc_nexus = acb;
+ dev->sc_xs = acb->xs;
+ dev->sc_flags |= SBICF_SELECTED;
+ dev->target = newtarget;
+ dev->lun = newlun;
+ break;
+ }
+ if (acb == NULL) {
+ printf("%s: reselect %s targ %d not in nexus_list %x\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget,
+ &dev->nexus_list.tqh_first);
+ panic("bad reselect in sbic");
+ }
+ if (csr == SBIC_CSR_RSLT_IFY)
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ break;
+
+ default:
+ abort:
+ /*
+ * Something unexpected happened -- deal with it.
+ */
+ printf("sbicnextstate: aborting csr %02x asr %02x\n", csr, asr);
+#ifdef DDB
+ Debugger();
+#endif
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev);
+ sbicerror(dev, regs, csr);
+ sbicabort(dev, regs, "next");
+ if (dev->sc_flags & SBICF_INDMA) {
+ /*
+ * check for overlapping cache line, flush if so
+ */
+#ifdef M68040
+ if (dev->sc_flags & SBICF_DCFLUSH) {
+#if 0
+ printf("sibc: 68040 DMA cache flush needs fixing? %x:%x\n",
+ dev->sc_xs->data, dev->sc_xs->datalen);
+#endif
+ }
+#endif
+ dev->sc_flags &=
+ ~(SBICF_INDMA | SBICF_DCFLUSH);
+#ifdef DEBUG
+ if( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n",
+ dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+#endif
+ dev->sc_dmastop(dev);
+ sbic_scsidone(acb, -1);
+ }
+ return SBIC_STATE_ERROR;
+ }
+
+ return(SBIC_STATE_RUNNING);
+}
+
+
+/*
+ * Check if DMA can not be used with specified buffer
+ */
+
+int
+sbiccheckdmap(bp, len, mask)
+ void *bp;
+ u_long len, mask;
+{
+ u_char *buffer;
+ u_long phy_buf;
+ u_long phy_len;
+
+ buffer = bp;
+
+ if (len == 0)
+ return(0);
+
+ while (len) {
+ phy_buf = kvtop(buffer);
+ if (len < (phy_len = NBPG - ((int) buffer & PGOFSET)))
+ phy_len = len;
+ if (phy_buf & mask)
+ return(1);
+ buffer += phy_len;
+ len -= phy_len;
+ }
+ return(0);
+}
+
+int
+sbictoscsiperiod(dev, regs, a)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int a;
+{
+ unsigned int fs;
+
+ /*
+ * cycle = DIV / (2*CLK)
+ * DIV = FS+2
+ * best we can do is 200ns at 20Mhz, 2 cycles
+ */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
+ if (a < 2) a = 8; /* map to Cycles */
+ return ((fs*a)>>2); /* in 4 ns units */
+}
+
+int
+sbicfromscsiperiod(dev, regs, p)
+ struct sbic_softc *dev;
+ sbic_regmap_p regs;
+ int p;
+{
+ register unsigned int fs, ret;
+
+ /* Just the inverse of the above */
+
+ GET_SBIC_myid(regs,fs);
+ fs = (fs >>6) + 2; /* DIV */
+ fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
+
+ ret = p << 2; /* in ns units */
+ ret = ret / fs; /* in Cycles */
+ if (ret < sbic_min_period)
+ return(sbic_min_period);
+
+ /* verify rounding */
+ if (sbictoscsiperiod(dev, regs, ret) < p)
+ ret++;
+ return (ret >= 8) ? 0 : ret;
+}
+
+#ifdef DEBUG
+
+void sbicdumpstate()
+{
+ u_char csr, asr;
+
+ GET_SBIC_asr(debug_sbic_regs,asr);
+ GET_SBIC_csr(debug_sbic_regs,csr);
+ printf("%s: asr:csr(%02x:%02x)->(%02x:%02x)\n",
+ (routine==1)?"sbicgo":
+ (routine==2)?"sbicintr":
+ (routine==3)?"sbicicmd":
+ (routine==4)?"sbicnext":"unknown",
+ debug_asr, debug_csr, asr, csr);
+
+}
+
+void sbictimeout(dev)
+ struct sbic_softc *dev;
+{
+ int s, asr;
+
+ /* Dump this every second while there's an active command */
+ if( dev->sc_nexus ) {
+ s = splbio();
+ GET_SBIC_asr(dev->sc_sbicp, asr);
+ if( asr & SBIC_ASR_INT ) {
+ /* We need to service a missed IRQ */
+ printf("Servicing a missed int:(%02x,%02x)->(%02x,??)\n",
+ debug_asr, debug_csr, asr);
+ sbicintr(dev);
+ }
+ splx(s);
+ sbicdumpstate();
+ timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
+ } else timeout_active = 0;
+}
+
+#endif
diff --git a/sys/arch/mvme68k/dev/sbicdma.c b/sys/arch/mvme68k/dev/sbicdma.c
new file mode 100644
index 00000000000..193cc674efa
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicdma.c
@@ -0,0 +1,278 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1995 Dale Rahn. 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 Dale Rahn.
+ * 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.
+ */
+
+/*
+ * as you may guess by some of the routines in this file,
+ * dma is not yet working. - its on the TODO list
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <vm/vm.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <machine/autoconf.h>
+#include <mvme68k/dev/pccreg.h>
+#include <mvme68k/dev/sbicreg.h>
+#include <mvme68k/dev/sbicvar.h>
+#include <mvme68k/dev/dmavar.h>
+
+void sbicdmaattach __P((struct device *, struct device *, void *));
+int sbicdmamatch __P((struct device *, void *, void *));
+int sbicdmaprint __P((void *auxp, char *));
+
+void sbicdma_dmafree __P((struct sbic_softc *));
+void sbicdma_dmastop __P((struct sbic_softc *));
+int sbicdma_dmanext __P((struct sbic_softc *));
+int sbicdma_dmago __P((struct sbic_softc *, char *, int, int));
+int sbicdma_dmaintr __P((struct sbic_softc *));
+int sbicdma_scintr __P((struct sbic_softc *));
+
+struct scsi_adapter sbicdma_scsiswitch = {
+ sbic_scsicmd,
+ sbic_minphys,
+ 0, /* no lun support */
+ 0, /* no lun support */
+};
+
+struct scsi_device sbicdma_scsidev = {
+ NULL, /* use default error handler */
+ NULL, /* have a queue served by this ??? */
+ NULL, /* have no async handler ??? */
+ NULL, /* Use default done routine */
+};
+
+#ifdef DEBUG
+int sbicdma_debug = 1;
+#endif
+
+int sbicdma_maxdma = 0; /* Maximum size per DMA transfer */
+int sbicdma_dmamask = 0;
+int sbicdma_dmabounce = 0;
+
+struct cfdriver sbiccd = {
+ NULL, "sbic", sbicdmamatch, sbicdmaattach,
+ DV_DULL, sizeof(struct sbic_softc),
+};
+
+int
+sbicdmamatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ /*
+ * XXX finish to properly probe
+ */
+ return (1);
+}
+
+void
+sbicdmaattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct sbic_softc *sc = (struct sbic_softc *)self;
+ struct pccreg *pcc;
+ struct confargs *ca = args;
+
+ sc->sc_cregs = (struct pccreg *)ca->ca_master;
+ sc->sc_dmafree = sbicdma_dmafree;
+ sc->sc_dmago = sbicdma_dmago;
+ sc->sc_dmanext = sbicdma_dmanext;
+ sc->sc_dmastop = sbicdma_dmastop;
+ sc->sc_dmacmd = 0;
+
+ sc->sc_flags |= SBICF_BADDMA;
+ sc->sc_dmamask = 0;
+ sc->sc_sbicp = (sbic_regmap_p)ca->ca_vaddr;
+ sc->sc_clkfreq = 100;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = 7;
+ sc->sc_link.adapter = &sbicdma_scsiswitch;
+ sc->sc_link.device = &sbicdma_scsidev;
+ sc->sc_link.openings = 1;
+
+ printf(": target %d\n", sc->sc_link.adapter_target);
+
+ /* connect the interrupts */
+ sc->sc_ih.ih_fn = sbicdma_scintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_SBIC, &sc->sc_ih);
+
+ sc->sc_dmaih.ih_fn = sbicdma_dmaintr;
+ sc->sc_dmaih.ih_arg = sc;
+ sc->sc_dmaih.ih_ipl = ca->ca_ipl;
+ pccintr_establish(PCCV_DMA, &sc->sc_dmaih);
+
+ pcc = (struct pccreg *)sc->sc_cregs;
+ pcc->pcc_dmairq = sc->sc_dmaih.ih_ipl | PCC_IRQ_INT;
+ pcc->pcc_sbicirq = sc->sc_ih.ih_ipl | PCC_SBIC_RESETIRQ;
+
+ sbicreset(sc);
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_dmaintrcnt);
+
+ config_found(self, &sc->sc_link, sbicdmaprint);
+}
+
+/*
+ * print diag if pnp is NULL else just extra
+ */
+int
+sbicdmaprint(auxp, pnp)
+ void *auxp;
+ char *pnp;
+{
+ if (pnp == NULL)
+ return (UNCONF);
+ return (QUIET);
+}
+
+int
+sbicdma_dmago(sc, va, count, flags)
+ struct sbic_softc *sc;
+ char *va;
+ int count, flags;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char csr;
+ u_long pa;
+
+ pa = (u_long)pmap_extract(pmap_kernel(), (vm_offset_t)va);
+#ifdef DEBUG
+ if (sbicdma_debug)
+ printf("%s: dmago: va 0x%x pa 0x%x cnt %d flags %x\n",
+ sc->sc_dev.dv_xname, va, pa, count, flags);
+#endif
+
+ sc->sc_flags |= SBICF_INTR;
+ pcc->pcc_dmadaddr = (u_long)pa;
+ if (count & PCC_DMABCNT_CNTMASK) {
+ printf("%s: dma count 0x%x too large\n",
+ sc->sc_dev.dv_xname, count);
+ return (0);
+ }
+ pcc->pcc_dmabcnt = (PCC_DMABCNT_MAKEFC(FC_USERD)) |
+ (count & PCC_DMABCNT_CNTMASK);
+
+ /* make certain interupts are disabled first, and reset */
+ pcc->pcc_dmairq = sc->sc_dmaih.ih_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+ pcc->pcc_sbicirq = sc->sc_ih.ih_ipl | PCC_SBIC_RESETIRQ | PCC_IRQ_IEN;
+ pcc->pcc_dmacsr = 0;
+ pcc->pcc_dmacsr = PCC_DMACSR_DEN |
+ ((flags & DMAGO_READ) == 0) ? PCC_DMACSR_TOSCSI : 0;
+
+ return (sc->sc_tcnt);
+}
+
+int
+sbicdma_dmaintr(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char stat;
+ int ret = 0;
+
+ /* DMA done */
+ stat = pcc->pcc_dmacsr;
+printf("dmaintr%d ", stat);
+ if (stat & PCC_DMACSR_DONE) {
+ pcc->pcc_dmacsr = 0;
+ pcc->pcc_dmairq = 0; /* ack and remove intr */
+ if (stat & PCC_DMACSR_ERR8BIT) {
+ printf("%s: 8 bit error\n", sc->sc_dev.dv_xname);
+ }
+ if (stat & PCC_DMACSR_DMAERRDATA) {
+ printf("%s: DMA bus error\n", sc->sc_dev.dv_xname);
+ }
+ sc->sc_dmaintrcnt.ev_count++;
+ return (1);
+ }
+ return (0);
+}
+
+int
+sbicdma_scintr(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+ u_char stat;
+ int ret = 0;
+
+printf("scintr%d ", stat);
+ stat = pcc->pcc_sbicirq;
+ if (stat & PCC_SBIC_RESETIRQ) {
+ printf("%s: scintr: a scsi device pulled reset\n",
+ sc->sc_dev.dv_xname);
+ pcc->pcc_sbicirq = pcc->pcc_sbicirq | PCC_SBIC_RESETIRQ;
+ } else if (stat & PCC_IRQ_INT) {
+ pcc->pcc_sbicirq = 0;
+ sbicintr(sc);
+ ret = 1;
+ sc->sc_intrcnt.ev_count++;
+ }
+ return (ret);
+}
+
+void
+sbicdma_dmastop(sc)
+ struct sbic_softc *sc;
+{
+ printf("sbicdma_dmastop called\n");
+ /* XXX do nothing */
+}
+
+int
+sbicdma_dmanext(sc)
+ struct sbic_softc *sc;
+{
+ printf("sbicdma_dmanext called\n");
+}
+
+void
+sbicdma_dmafree(sc)
+ struct sbic_softc *sc;
+{
+ struct pccreg *pcc = (struct pccreg *)sc->sc_cregs;
+
+ printf("sbicdma_dmafree called\n");
+ /* make certain interupts are disabled first, reset */
+ pcc->pcc_dmairq = 0;
+}
diff --git a/sys/arch/mvme68k/dev/sbicreg.h b/sys/arch/mvme68k/dev/sbicreg.h
new file mode 100644
index 00000000000..f3844dcd246
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicreg.h
@@ -0,0 +1,424 @@
+/* $NetBSD: sbicreg.h,v 1.2 1994/10/26 02:04:40 cgd Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsireg.h 7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * AMD AM33C93A SCSI interface hardware description.
+ *
+ * Using parts of the Mach scsi driver for the 33C93
+ */
+
+#define SBIC_myid 0
+#define SBIC_cdbsize 0
+#define SBIC_control 1
+#define SBIC_timeo 2
+#define SBIC_cdb1 3
+#define SBIC_tsecs 3
+#define SBIC_cdb2 4
+#define SBIC_theads 4
+#define SBIC_cdb3 5
+#define SBIC_tcyl_hi 5
+#define SBIC_cdb4 6
+#define SBIC_tcyl_lo 6
+#define SBIC_cdb5 7
+#define SBIC_addr_hi 7
+#define SBIC_cdb6 8
+#define SBIC_addr_2 8
+#define SBIC_cdb7 9
+#define SBIC_addr_3 9
+#define SBIC_cdb8 10
+#define SBIC_addr_lo 10
+#define SBIC_cdb9 11
+#define SBIC_secno 11
+#define SBIC_cdb10 12
+#define SBIC_headno 12
+#define SBIC_cdb11 13
+#define SBIC_cylno_hi 13
+#define SBIC_cdb12 14
+#define SBIC_cylno_lo 14
+#define SBIC_tlun 15
+#define SBIC_cmd_phase 16
+#define SBIC_syn 17
+#define SBIC_count_hi 18
+#define SBIC_count_med 19
+#define SBIC_count_lo 20
+#define SBIC_selid 21
+#define SBIC_rselid 22
+#define SBIC_csr 23
+#define SBIC_cmd 24
+#define SBIC_data 25
+/* sbic_asr is addressed directly */
+
+/*
+ * Register defines
+ */
+
+/*
+ * Auxiliary Status Register
+ */
+
+#define SBIC_ASR_INT 0x80 /* Interrupt pending */
+#define SBIC_ASR_LCI 0x40 /* Last command ignored */
+#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */
+#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */
+#define SBIC_ASR_xxx 0x0c
+#define SBIC_ASR_PE 0x02 /* Parity error (even) */
+#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */
+
+/*
+ * My ID register, and/or CDB Size
+ */
+
+#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */
+ /* 11 Mhz is invalid */
+#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */
+#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */
+#define SBIC_ID_EHP 0x10 /* Enable host parity */
+#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */
+#define SBIC_ID_MASK 0x07
+#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */
+
+/*
+ * Control register
+ */
+
+#define SBIC_CTL_DMA 0x80 /* Single byte dma */
+#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer acces (bus master)*/
+#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */
+#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */
+#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */
+#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */
+#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/
+#define SBIC_CTL_HA 0x02 /* Halt on ATN */
+#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */
+
+/*
+ * Timeout period register
+ * [val in msecs, input clk in 0.1 Mhz]
+ */
+
+#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1)
+
+/*
+ * CDBn registers, note that
+ * cdb11 is used for status byte in target mode (send-status-and-cc)
+ * cdb12 sez if linked command complete, and w/flag if so
+ */
+
+/*
+ * Target LUN register
+ * [holds target status when select-and-xfer]
+ */
+
+#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */
+#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */
+#define SBIC_TLUN_xxx 0x38
+#define SBIC_TLUN_MASK 0x07
+
+/*
+ * Command Phase register
+ */
+
+#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */
+#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK)
+
+/*
+ * FIFO register
+ */
+
+#define SBIC_FIFO_DEEP 12
+
+/*
+ * maximum possible size in TC registers. Since this is 24 bit, it's easy
+ */
+#define SBIC_TC_MAX ((1 << 24) - 1)
+
+/*
+ * Synchronous xfer register
+ */
+
+#define SBIC_SYN_OFF_MASK 0x0f
+#define SBIC_SYN_MAX_OFFSET SBIC_FIFO_DEEP
+#define SBIC_SYN_PER_MASK 0x70
+#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */
+
+#define SBIC_SYN(o,p) \
+ (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK))
+
+/*
+ * Transfer count register
+ * optimal access macros depend on addressing
+ */
+
+/*
+ * Destination ID (selid) register
+ */
+
+#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */
+#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */
+#define SBIC_SID_FROM_SCSI 0x40
+#define SBIC_SID_TO_SCSI 0x00
+#define SBIC_SID_xxx 0x38
+#define SBIC_SID_IDMASK 0x07
+
+/*
+ * Source ID (rselid) register
+ */
+
+#define SBIC_RID_ER 0x80 /* Enable reselection */
+#define SBIC_RID_ES 0x40 /* Enable selection */
+#define SBIC_RID_DSP 0x20 /* Disable select parity */
+#define SBIC_RID_SIV 0x08 /* Source ID valid */
+#define SBIC_RID_MASK 0x07
+
+/*
+ * Status register
+ */
+
+#define SBIC_CSR_CAUSE 0xf0
+#define SBIC_CSR_RESET 0x00 /* chip was reset */
+#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */
+#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/
+#define SBIC_CSR_CMD_ERR 0x40 /* end with error */
+#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */
+
+
+#define SBIC_CSR_QUALIFIER 0x0f
+/* Reset State Interrupts */
+#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/
+#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/
+/* Successful Completion Interrupts */
+#define SBIC_CSR_TARGET 0x10 /* reselect complete */
+#define SBIC_CSR_INITIATOR 0x11 /* select complete */
+#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */
+#define SBIC_CSR_W_ATN 0x14 /* ditto */
+#define SBIC_CSR_XLATED 0x15 /* translate address cmd */
+#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/
+#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */
+/* Paused or Aborted Interrupts */
+#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/
+#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */
+#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */
+#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */
+#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */
+#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */
+#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */
+/* Terminated Interrupts */
+#define SBIC_CSR_CMD_INVALID 0x40
+#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */
+#define SBIC_CSR_SEL_TIMEO 0x42
+#define SBIC_CSR_PE 0x43 /* parity error */
+#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */
+#define SBIC_CSR_XLATE_TOOBIG 0x45
+#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */
+#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */
+#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */
+/* Service Required Interrupts */
+#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */
+#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */
+#define SBIC_CSR_SLT 0x82 /* selected, no ATN */
+#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */
+#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */
+#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */
+#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */
+#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */
+
+#define SBIC_PHASE(csr) SCSI_PHASE(csr)
+
+/*
+ * Command register (command codes)
+ */
+
+#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */
+#define SBIC_CMD_MASK 0x7f
+
+ /* Miscellaneous */
+#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */
+#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */
+#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */
+#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */
+#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */
+#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */
+
+ /* Initiator state */
+#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */
+#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */
+#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */
+#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */
+
+ /* Target state */
+#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */
+#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */
+#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */
+#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */
+#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */
+#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */
+#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */
+#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */
+#define SBIC_CMD_SND 0x17 /* ( T ) lev II */
+
+ /* Disconnected state */
+#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */
+#define SBIC_CMD_SEL 0x07 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */
+#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */
+#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */
+#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */
+#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */
+
+/* approximate, but we won't do SBT on selects */
+#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
+
+#define PAD(n) char n;
+#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA
+
+typedef struct {
+ volatile unsigned char sbic_asr; /* r : Aux Status Register */
+#define sbic_address sbic_asr /* w : desired register no */
+ /* PAD(pad1); */
+ volatile unsigned char sbic_value; /* rw: register value */
+} sbic_padded_ind_regmap_t;
+typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
+
+#define sbic_read_reg(regs,regno,val) do { \
+ (regs)->sbic_address = (regno); \
+ (val) = (regs)->sbic_value; \
+ } while (0)
+
+#define sbic_write_reg(regs,regno,val) do { \
+ (regs)->sbic_address = (regno); \
+ (regs)->sbic_value = (val); \
+ } while (0)
+
+#define SET_SBIC_myid(regs,val) sbic_write_reg(regs,SBIC_myid,val)
+#define GET_SBIC_myid(regs,val) sbic_read_reg(regs,SBIC_myid,val)
+#define SET_SBIC_cdbsize(regs,val) sbic_write_reg(regs,SBIC_cdbsize,val)
+#define GET_SBIC_cdbsize(regs,val) sbic_read_reg(regs,SBIC_cdbsize,val)
+#define SET_SBIC_control(regs,val) sbic_write_reg(regs,SBIC_control,val)
+#define GET_SBIC_control(regs,val) sbic_read_reg(regs,SBIC_control,val)
+#define SET_SBIC_timeo(regs,val) sbic_write_reg(regs,SBIC_timeo,val)
+#define GET_SBIC_timeo(regs,val) sbic_read_reg(regs,SBIC_timeo,val)
+#define SET_SBIC_cdb1(regs,val) sbic_write_reg(regs,SBIC_cdb1,val)
+#define GET_SBIC_cdb1(regs,val) sbic_read_reg(regs,SBIC_cdb1,val)
+#define SET_SBIC_cdb2(regs,val) sbic_write_reg(regs,SBIC_cdb2,val)
+#define GET_SBIC_cdb2(regs,val) sbic_read_reg(regs,SBIC_cdb2,val)
+#define SET_SBIC_cdb3(regs,val) sbic_write_reg(regs,SBIC_cdb3,val)
+#define GET_SBIC_cdb3(regs,val) sbic_read_reg(regs,SBIC_cdb3,val)
+#define SET_SBIC_cdb4(regs,val) sbic_write_reg(regs,SBIC_cdb4,val)
+#define GET_SBIC_cdb4(regs,val) sbic_read_reg(regs,SBIC_cdb4,val)
+#define SET_SBIC_cdb5(regs,val) sbic_write_reg(regs,SBIC_cdb5,val)
+#define GET_SBIC_cdb5(regs,val) sbic_read_reg(regs,SBIC_cdb5,val)
+#define SET_SBIC_cdb6(regs,val) sbic_write_reg(regs,SBIC_cdb6,val)
+#define GET_SBIC_cdb6(regs,val) sbic_read_reg(regs,SBIC_cdb6,val)
+#define SET_SBIC_cdb7(regs,val) sbic_write_reg(regs,SBIC_cdb7,val)
+#define GET_SBIC_cdb7(regs,val) sbic_read_reg(regs,SBIC_cdb7,val)
+#define SET_SBIC_cdb8(regs,val) sbic_write_reg(regs,SBIC_cdb8,val)
+#define GET_SBIC_cdb8(regs,val) sbic_read_reg(regs,SBIC_cdb8,val)
+#define SET_SBIC_cdb9(regs,val) sbic_write_reg(regs,SBIC_cdb9,val)
+#define GET_SBIC_cdb9(regs,val) sbic_read_reg(regs,SBIC_cdb9,val)
+#define SET_SBIC_cdb10(regs,val) sbic_write_reg(regs,SBIC_cdb10,val)
+#define GET_SBIC_cdb10(regs,val) sbic_read_reg(regs,SBIC_cdb10,val)
+#define SET_SBIC_cdb11(regs,val) sbic_write_reg(regs,SBIC_cdb11,val)
+#define GET_SBIC_cdb11(regs,val) sbic_read_reg(regs,SBIC_cdb11,val)
+#define SET_SBIC_cdb12(regs,val) sbic_write_reg(regs,SBIC_cdb12,val)
+#define GET_SBIC_cdb12(regs,val) sbic_read_reg(regs,SBIC_cdb12,val)
+#define SET_SBIC_tlun(regs,val) sbic_write_reg(regs,SBIC_tlun,val)
+#define GET_SBIC_tlun(regs,val) sbic_read_reg(regs,SBIC_tlun,val)
+#define SET_SBIC_cmd_phase(regs,val) sbic_write_reg(regs,SBIC_cmd_phase,val)
+#define GET_SBIC_cmd_phase(regs,val) sbic_read_reg(regs,SBIC_cmd_phase,val)
+#define SET_SBIC_syn(regs,val) sbic_write_reg(regs,SBIC_syn,val)
+#define GET_SBIC_syn(regs,val) sbic_read_reg(regs,SBIC_syn,val)
+#define SET_SBIC_count_hi(regs,val) sbic_write_reg(regs,SBIC_count_hi,val)
+#define GET_SBIC_count_hi(regs,val) sbic_read_reg(regs,SBIC_count_hi,val)
+#define SET_SBIC_count_med(regs,val) sbic_write_reg(regs,SBIC_count_med,val)
+#define GET_SBIC_count_med(regs,val) sbic_read_reg(regs,SBIC_count_med,val)
+#define SET_SBIC_count_lo(regs,val) sbic_write_reg(regs,SBIC_count_lo,val)
+#define GET_SBIC_count_lo(regs,val) sbic_read_reg(regs,SBIC_count_lo,val)
+#define SET_SBIC_selid(regs,val) sbic_write_reg(regs,SBIC_selid,val)
+#define GET_SBIC_selid(regs,val) sbic_read_reg(regs,SBIC_selid,val)
+#define SET_SBIC_rselid(regs,val) sbic_write_reg(regs,SBIC_rselid,val)
+#define GET_SBIC_rselid(regs,val) sbic_read_reg(regs,SBIC_rselid,val)
+#define SET_SBIC_csr(regs,val) sbic_write_reg(regs,SBIC_csr,val)
+#define GET_SBIC_csr(regs,val) sbic_read_reg(regs,SBIC_csr,val)
+#define SET_SBIC_cmd(regs,val) sbic_write_reg(regs,SBIC_cmd,val)
+#define GET_SBIC_cmd(regs,val) sbic_read_reg(regs,SBIC_cmd,val)
+#define SET_SBIC_data(regs,val) sbic_write_reg(regs,SBIC_data,val)
+#define GET_SBIC_data(regs,val) sbic_read_reg(regs,SBIC_data,val)
+
+#define SBIC_TC_PUT(regs,val) do { \
+ sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \
+ (regs)->sbic_value = (val)>>8; \
+ (regs)->sbic_value = (val); \
+} while (0)
+#define SBIC_TC_GET(regs,val) do { \
+ sbic_read_reg(regs,SBIC_count_hi,(val)); \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+} while (0)
+
+#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) do { \
+ int n=(cmdsize)-1; \
+ char *ptr = (char*)(cmd); \
+ sbic_write_reg(regs,SBIC_cdb1,*ptr++); \
+ while (n-- > 0) (regs)->sbic_value = *ptr++; \
+} while (0)
+
+#define GET_SBIC_asr(regs,val) (val) = (regs)->sbic_asr
+
+#define WAIT_CIP(regs) do { \
+ while ((regs)->sbic_asr & SBIC_ASR_CIP) \
+ ; \
+} while (0)
+
+/* transmit a byte in programmed I/O mode */
+#define SEND_BYTE(regs, ch) do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ SET_SBIC_data(regs, ch); \
+ } while (0)
+
+/* receive a byte in programmed I/O mode */
+#define RECV_BYTE(regs, ch) do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ GET_SBIC_data(regs, ch); \
+ } while (0)
diff --git a/sys/arch/mvme68k/dev/sbicvar.h b/sys/arch/mvme68k/dev/sbicvar.h
new file mode 100644
index 00000000000..339d5f73c39
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sbicvar.h
@@ -0,0 +1,230 @@
+/* $NetBSD: sbicvar.h,v 1.8 1995/08/18 15:28:05 chopps Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsivar.h 7.1 (Berkeley) 5/8/90
+ */
+#ifndef _SBICVAR_H_
+#define _SBICVAR_H_
+#include <sys/malloc.h>
+
+/*
+ * The largest single request will be MAXPHYS bytes which will require
+ * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
+ * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
+ * buffer is not page aligned (+1).
+ */
+#define DMAMAXIO (MAXPHYS/NBPG+1)
+
+struct dma_chain {
+ int dc_count;
+ char *dc_addr;
+};
+
+/*
+ * ACB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basicly, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
+ */
+struct sbic_acb {
+ TAILQ_ENTRY(sbic_acb) chain;
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
+#define ACB_FREE 0x00
+#define ACB_ACTIVE 0x01
+#define ACB_DONE 0x04
+#define ACB_CHKSENSE 0x08
+#define ACB_BBUF 0x10 /* DMA input needs to be copied from bounce */
+#define ACB_DATAIN 0x20 /* DMA direction flag */
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ struct dma_chain sc_kv; /* Virtual address of whole DMA */
+ struct dma_chain sc_pa; /* Physical address of DMA segment */
+ u_long sc_tcnt; /* number of bytes for this DMA */
+ u_char *sc_dmausrbuf; /* user buffer kva - for bounce copy */
+ u_long sc_dmausrlen; /* length of bounce copy */
+ u_short sc_dmacmd; /* Internal data for this DMA */
+ char *pa_addr; /* XXXX initial phys addr */
+ u_char *sc_usrbufpa; /* user buffer phys addr */
+};
+
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
+ * this for now. Is there a way to reliably hook it up to sc->fordriver??
+ */
+struct sbic_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ u_char* bounce; /* Bounce buffer for this device */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
+
+struct sbic_softc {
+ struct device sc_dev;
+ struct intrhand sc_ih, sc_dmaih;
+ struct evcnt sc_intrcnt, sc_dmaintrcnt;
+ struct target_sync {
+ u_char state;
+ u_char period;
+ u_char offset;
+ } sc_sync[8];
+ u_char target; /* Currently active target */
+ u_char lun;
+ struct scsi_link sc_link; /* proto for sub devices */
+ sbic_regmap_p sc_sbicp; /* the SBIC */
+ volatile void *sc_cregs; /* driver specific regs */
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, sbic_acb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct sbic_acb *sc_nexus; /* current command */
+ struct sbic_acb sc_acb[8]; /* the real command blocks */
+ struct sbic_tinfo sc_tinfo[8];
+
+ struct scsi_xfer *sc_xs; /* transfer from high level code */
+ u_char sc_flags;
+ u_char sc_scsiaddr;
+ u_char sc_stat[2];
+ u_char sc_msg[7];
+ u_long sc_clkfreq;
+ u_long sc_tcnt; /* number of bytes transfered */
+ u_short sc_dmacmd; /* used by dma drivers */
+ u_short sc_dmatimo; /* dma timeout */
+ u_long sc_dmamask; /* dma valid mem mask */
+ struct dma_chain *sc_cur;
+ struct dma_chain *sc_last;
+ int (*sc_dmago) __P((struct sbic_softc *, char *, int, int));
+ int (*sc_dmanext) __P((struct sbic_softc *));
+ void (*sc_dmafree) __P((struct sbic_softc *));
+ void (*sc_dmastop) __P((struct sbic_softc *));
+ u_short gtsc_bankmask; /* GVP specific bank selected */
+};
+
+/* sc_flags */
+#define SBICF_ALIVE 0x01 /* controller initialized */
+#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */
+#define SBICF_SELECTED 0x04 /* bus is in selected state. */
+#define SBICF_ICMD 0x08 /* Immediate command in execution */
+#define SBICF_BADDMA 0x10 /* controller can only DMA to ztwobus space */
+#define SBICF_INTR 0x40 /* SBICF interrupt expected */
+#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */
+
+/* sync states */
+#define SYNC_START 0 /* no sync handshake started */
+#define SYNC_SENT 1 /* we sent sync request, no answer yet */
+#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
+ or it rejected the request and we stay async */
+#ifdef DEBUG
+#define DDB_FOLLOW 0x04
+#define DDB_IO 0x08
+#endif
+extern int sbic_inhibit_sync;
+extern int sbic_no_dma;
+extern int sbic_clock_override;
+
+#define PHASE 0x07 /* mask for psns/pctl phase */
+#define DATA_OUT_PHASE 0x00
+#define DATA_IN_PHASE 0x01
+#define CMD_PHASE 0x02
+#define STATUS_PHASE 0x03
+#define BUS_FREE_PHASE 0x04
+#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */
+#define MESG_OUT_PHASE 0x06
+#define MESG_IN_PHASE 0x07
+
+#define MSG_CMD_COMPLETE 0x00
+#define MSG_EXT_MESSAGE 0x01
+#define MSG_SAVE_DATA_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INIT_DETECT_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_BUS_DEVICE_RESET 0x0C
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
+#define MSG_SYNC_REQ 0x01
+
+#define MSG_ISIDENTIFY(x) (x&MSG_IDENTIFY)
+#define IFY_TRN 0x20
+#define IFY_LUNTRN(x) (x&0x07)
+#define IFY_LUN(x) (!(x&0x20))
+
+/* Check if high bit set */
+
+#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define STS_BUSY 0x08
+#define STS_INTERMED 0x10 /* Intermediate status sent */
+#define STS_EXT 0x80 /* Extended status valid */
+
+
+/* States returned by our state machine */
+
+#define SBIC_STATE_ERROR -1
+#define SBIC_STATE_DONE 0
+#define SBIC_STATE_RUNNING 1
+#define SBIC_STATE_DISCONNECT 2
+
+/*
+ * XXXX
+ */
+struct scsi_fmt_cdb {
+ int len; /* cdb length (in bytes) */
+ u_char cdb[28]; /* cdb to use on next read/write */
+};
+
+struct buf;
+struct scsi_xfer;
+
+void sbic_minphys __P((struct buf *bp));
+int sbic_scsicmd __P((struct scsi_xfer *));
+
+#endif /* _SBICVAR_H_ */
diff --git a/sys/arch/mvme68k/dev/siop.c b/sys/arch/mvme68k/dev/siop.c
new file mode 100644
index 00000000000..be0b8b32d9f
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop.c
@@ -0,0 +1,1523 @@
+/* $NetBSD: siop.c,v 1.23 1995/08/18 15:28:08 chopps Exp $ */
+
+/*
+ * Copyright (c) 1994 Michael L. Hitch
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)siop.c 7.5 (Berkeley) 5/4/91
+ */
+
+/*
+ * 53C710 scsi adaptor driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/dkstat.h>
+#include <sys/buf.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/siopreg.h>
+#include <mvme68k/dev/siopvar.h>
+
+extern u_int kvtop();
+
+/*
+ * SCSI delays
+ * In u-seconds, primarily for state changes on the SPC.
+ */
+#define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */
+#define SCSI_DATA_WAIT 500000 /* wait per data in/out step */
+#define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */
+
+void siop_select __P((struct siop_softc *));
+void siopabort __P((struct siop_softc *, siop_regmap_p, char *));
+void sioperror __P((struct siop_softc *, siop_regmap_p, u_char));
+void siopstart __P((struct siop_softc *));
+void siopreset __P((struct siop_softc *));
+void siopsetdelay __P((int));
+void siop_scsidone __P((struct siop_acb *, int));
+void siop_sched __P((struct siop_softc *));
+int siop_poll __P((struct siop_softc *, struct siop_acb *));
+int siopintr __P((struct siop_softc *));
+
+/* 53C710 script */
+const
+#include <mvme68k/dev/siop_script.out>
+
+/* default to not inhibit sync negotiation on any drive */
+u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
+u_char siop_allow_disc[8] = { 3, 3, 3, 3, 3, 3, 3, 3 };
+int siop_no_dma = 0;
+
+int siop_reset_delay = 250; /* delay after reset, in milleseconds */
+
+int siop_cmd_wait = SCSI_CMD_WAIT;
+int siop_data_wait = SCSI_DATA_WAIT;
+int siop_init_wait = SCSI_INIT_WAIT;
+
+#ifdef DEBUG
+/*
+ * 0x01 - full debug
+ * 0x02 - DMA chaining
+ * 0x04 - siopintr
+ * 0x08 - phase mismatch
+ * 0x10 - <not used>
+ * 0x20 - panic on unhandled exceptions
+ * 0x100 - disconnect/reselect
+ */
+int siop_debug = 0;
+int siopsync_debug = 0;
+int siopdma_hits = 0;
+int siopdma_misses = 0;
+int siopchain_ints = 0;
+int siopstarts = 0;
+int siopints = 0;
+int siopphmm = 0;
+#define SIOP_TRACE_SIZE 128
+#define SIOP_TRACE(a,b,c,d) \
+ siop_trbuf[siop_trix] = (a); \
+ siop_trbuf[siop_trix+1] = (b); \
+ siop_trbuf[siop_trix+2] = (c); \
+ siop_trbuf[siop_trix+3] = (d); \
+ siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1);
+u_char siop_trbuf[SIOP_TRACE_SIZE];
+int siop_trix;
+#else
+#define SIOP_TRACE(a,b,c,d)
+#endif
+
+
+/*
+ * default minphys routine for siop based controllers
+ */
+void
+siop_minphys(bp)
+ struct buf *bp;
+{
+
+ /*
+ * No max transfer at this level.
+ */
+ minphys(bp);
+}
+
+/*
+ * used by specific siop controller
+ *
+ */
+int
+siop_scsicmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct siop_acb *acb;
+ struct siop_softc *sc;
+ struct scsi_link *slp;
+ int flags, s, i;
+
+ slp = xs->sc_link;
+ sc = slp->adapter_softc;
+ flags = xs->flags;
+
+ /* XXXX ?? */
+ if (flags & SCSI_DATA_UIO)
+ panic("siop: scsi data uio requested");
+
+ /* XXXX ?? */
+ if (sc->sc_nexus && flags & SCSI_POLL)
+ panic("siop_scsicmd: busy");
+
+ s = splbio();
+ acb = sc->free_list.tqh_first;
+ if (acb) {
+ TAILQ_REMOVE(&sc->free_list, acb, chain);
+ }
+ splx(s);
+
+ if (acb == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ acb->flags = ACB_ACTIVE;
+ acb->xs = xs;
+ bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
+ acb->clen = xs->cmdlen;
+ acb->daddr = xs->data;
+ acb->dleft = xs->datalen;
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
+
+ if (sc->sc_nexus == NULL)
+ siop_sched(sc);
+
+ splx(s);
+
+ if (flags & SCSI_POLL || siop_no_dma)
+ return(siop_poll(sc, acb));
+ return(SUCCESSFULLY_QUEUED);
+}
+
+int
+siop_poll(sc, acb)
+ struct siop_softc *sc;
+ struct siop_acb *acb;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ struct scsi_xfer *xs = acb->xs;
+ int i;
+ int status;
+ u_char istat;
+ u_char dstat;
+ u_char sstat0;
+ int s;
+ int to;
+
+ s = splbio();
+ to = xs->timeout / 1000;
+ if (sc->nexus_list.tqh_first)
+ printf("%s: siop_poll called with disconnected device\n",
+ sc->sc_dev.dv_xname);
+ for (;;) {
+ /* use cmd_wait values? */
+ i = 50000;
+ spl0();
+ while (((istat = rp->siop_istat) &
+ (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
+ if (--i <= 0) {
+#ifdef DEBUG
+ printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %x (+%x) dcmd %x ds %x timeout %d\n",
+ xs->sc_link->target, acb->cmd.opcode,
+ rp->siop_sbcl, rp->siop_dsp,
+ rp->siop_dsp - sc->sc_scriptspa,
+ *((long *)&rp->siop_dcmd), &acb->ds, acb->xs->timeout);
+#endif
+ i = 50000;
+ --to;
+ if (to <= 0) {
+ siopreset(sc);
+ return(COMPLETE);
+ }
+ }
+ delay(10);
+ }
+ sstat0 = rp->siop_sstat0;
+ dstat = rp->siop_dstat;
+ if (siop_checkintr(sc, istat, dstat, sstat0, &status)) {
+ if (acb != sc->sc_nexus)
+ printf("%s: siop_poll disconnected device completed\n",
+ sc->sc_dev.dv_xname);
+ else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
+ sc->sc_flags &= ~SIOP_INTSOFF;
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+ siop_scsidone(sc->sc_nexus, status);
+ }
+ if (xs->flags & ITSDONE)
+ break;
+ }
+ splx(s);
+ return (COMPLETE);
+}
+
+/*
+ * start next command that's ready
+ */
+void
+siop_sched(sc)
+ struct siop_softc *sc;
+{
+ struct scsi_link *slp;
+ struct siop_acb *acb;
+ int stat, i;
+
+#ifdef DEBUG
+ if (sc->sc_nexus) {
+ printf("%s: siop_sched- nexus %x/%d ready %x/%d\n",
+ sc->sc_dev.dv_xname, sc->sc_nexus,
+ sc->sc_nexus->xs->sc_link->target,
+ sc->ready_list.tqh_first,
+ sc->ready_list.tqh_first->xs->sc_link->target);
+ return;
+ }
+#endif
+ for (acb = sc->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
+ slp = acb->xs->sc_link;
+ i = slp->target;
+ if(!(sc->sc_tinfo[i].lubusy & (1 << slp->lun))) {
+ struct siop_tinfo *ti = &sc->sc_tinfo[i];
+
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ sc->sc_nexus = acb;
+ slp = acb->xs->sc_link;
+ ti = &sc->sc_tinfo[slp->target];
+ ti->lubusy |= (1 << slp->lun);
+ break;
+ }
+ }
+
+ if (acb == NULL) {
+#ifdef DEBUGXXX
+ printf("%s: siop_sched didn't find ready command\n",
+ sc->sc_dev.dv_xname);
+#endif
+ return;
+ }
+
+ if (acb->xs->flags & SCSI_RESET)
+ siopreset(sc);
+
+#if 0
+ acb->cmd.bytes[0] |= slp->lun << 5; /* XXXX */
+#endif
+ ++sc->sc_active;
+ siop_select(sc);
+}
+
+void
+siop_scsidone(acb, stat)
+ struct siop_acb *acb;
+ int stat;
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *slp = xs->sc_link;
+ struct siop_softc *sc = slp->adapter_softc;
+ int s, dosched = 0;
+
+#ifdef DIAGNOSTIC
+ if (acb == NULL || xs == NULL)
+ panic("siop_scsidone");
+#endif
+#if 0
+ if (((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
+ ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+#endif
+ /*
+ * is this right?
+ */
+ xs->status = stat;
+
+ if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
+ if (stat == SCSI_CHECK) {
+ struct scsi_sense *ss = (void *)&acb->cmd;
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = slp->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ acb->clen = sizeof(*ss);
+ acb->daddr = (char *)&xs->sense;
+ acb->dleft = sizeof(struct scsi_sense_data);
+ acb->flags = ACB_ACTIVE | ACB_CHKSENSE;
+ TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
+ --sc->sc_active;
+ sc->sc_tinfo[slp->target].lubusy &=
+ ~(1 << slp->lun);
+ sc->sc_tinfo[slp->target].senses++;
+ if (sc->sc_nexus == acb) {
+ sc->sc_nexus = NULL;
+ siop_sched(sc);
+ }
+ SIOP_TRACE('d','s',0,0)
+ return;
+ }
+ }
+ if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
+ xs->error = XS_SENSE;
+ } else {
+ xs->resid = 0; /* XXXX */
+ }
+#if whataboutthisone
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+#endif
+ xs->flags |= ITSDONE;
+
+ /*
+ * Remove the ACB from whatever queue it's on. We have to do a bit of
+ * a hack to figure out which queue it's on. Note that it is *not*
+ * necessary to cdr down the ready queue, but we must cdr down the
+ * nexus queue and see if it's there, so we can mark the unit as no
+ * longer busy. This code is sickening, but it works.
+ */
+ if (acb == sc->sc_nexus) {
+ sc->sc_nexus = NULL;
+ sc->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
+ if (sc->ready_list.tqh_first)
+ dosched = 1; /* start next command */
+ --sc->sc_active;
+ SIOP_TRACE('d','a',stat,0)
+ } else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ SIOP_TRACE('d','r',stat,0)
+ } else {
+ register struct siop_acb *acb2;
+ for (acb2 = sc->nexus_list.tqh_first; acb2;
+ acb2 = acb2->chain.tqe_next)
+ if (acb2 == acb) {
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ sc->sc_tinfo[slp->target].lubusy
+ &= ~(1<<slp->lun);
+ --sc->sc_active;
+ break;
+ }
+ if (acb2)
+ ;
+ else if (acb->chain.tqe_next) {
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ --sc->sc_active;
+ } else {
+ printf("%s: can't find matching acb\n",
+ sc->sc_dev.dv_xname);
+#ifdef DDB
+/* Debugger(); */
+#endif
+ }
+ SIOP_TRACE('d','n',stat,0);
+ }
+ /* Put it on the free list. */
+ acb->flags = ACB_FREE;
+ TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
+
+ sc->sc_tinfo[slp->target].cmds++;
+
+ scsi_done(xs);
+
+ if (dosched && sc->sc_nexus == NULL)
+ siop_sched(sc);
+}
+
+void
+siopabort(sc, rp, where)
+ register struct siop_softc *sc;
+ siop_regmap_p rp;
+ char *where;
+{
+ int i;
+
+ printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
+ sc->sc_dev.dv_xname,
+ where, rp->siop_dstat, rp->siop_sstat0, rp->siop_sbcl);
+
+ if (sc->sc_active > 0) {
+#ifdef TODO
+ SET_SBIC_cmd (rp, SBIC_CMD_ABORT);
+ WAIT_CIP (rp);
+
+ GET_SBIC_asr (rp, asr);
+ if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI))
+ {
+ /* ok, get more drastic.. */
+
+ SET_SBIC_cmd (rp, SBIC_CMD_RESET);
+ delay(25);
+ SBIC_WAIT(rp, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (rp, csr); /* clears interrupt also */
+
+ return;
+ }
+
+ do
+ {
+ SBIC_WAIT (rp, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (rp, csr);
+ }
+ while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
+ && (csr != SBIC_CSR_CMD_INVALID));
+#endif
+
+ /* lets just hope it worked.. */
+#ifdef fix_this
+ for (i = 0; i < 2; ++i) {
+ if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] !=
+ sc->sc_cur) {
+ printf ("siopabort: cleanup!\n");
+ sc->sc_iob[i].sc_xs = NULL;
+ }
+ }
+#endif /* fix_this */
+/* sc->sc_active = 0; */
+ }
+}
+
+void
+siopinitialize(sc)
+ struct siop_softc *sc;
+{
+ /*
+ * Need to check that scripts is on a long word boundary
+ * and that DS is on a long word boundary.
+ * Also should verify that dev doesn't span non-contiguous
+ * physical pages.
+ */
+ sc->sc_scriptspa = kvtop(scripts);
+ sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
+ sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
+ sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
+ sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */
+ if (sc->sc_minsync < 25)
+ sc->sc_minsync = 25;
+#if not_used
+ if (sc->sc_clock_freq <= 25)
+ sc->sc_tcp[0] = sc->sc_tcp[1];
+ else if (sc->sc_clock_freq <= 37)
+ sc->sc_tcp[0] = sc->sc_tcp[2];
+ else if (sc->sc_clock_freq <= 50)
+ sc->sc_tcp[0] = sc->sc_tcp[3];
+ else
+ sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
+#endif
+
+ siopreset (sc);
+}
+
+void
+siopreset(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ u_int i, s;
+ u_char dummy;
+ struct siop_acb *acb;
+
+ rp = sc->sc_siopp;
+
+ if (sc->sc_flags & SIOP_ALIVE)
+ siopabort(sc, rp, "reset");
+
+ s = splbio();
+
+ /*
+ * Reset the chip
+ * XXX - is this really needed?
+ */
+ rp->siop_istat |= SIOP_ISTAT_ABRT; /* abort current script */
+ rp->siop_istat |= SIOP_ISTAT_RST; /* reset chip */
+ rp->siop_istat &= ~SIOP_ISTAT_RST;
+ /*
+ * Reset SCSI bus (do we really want this?)
+ */
+ rp->siop_sien = 0;
+ rp->siop_scntl1 |= SIOP_SCNTL1_RST;
+ delay(1);
+ rp->siop_scntl1 &= ~SIOP_SCNTL1_RST;
+
+ /*
+ * Set up various chip parameters
+ */
+ rp->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG;
+ rp->siop_scntl1 = SIOP_SCNTL1_ESR;
+ rp->siop_dcntl = sc->sc_dcntl;
+ rp->siop_dmode = 0x80; /* burst length = 4 */
+ rp->siop_sien = 0x00; /* don't enable interrupts yet */
+ rp->siop_dien = 0x00; /* don't enable interrupts yet */
+ rp->siop_scid = 1 << sc->sc_link.adapter_target;
+ rp->siop_dwt = 0x00;
+ rp->siop_ctest0 |= SIOP_CTEST0_BTD | SIOP_CTEST0_EAN;
+ rp->siop_ctest7 = sc->sc_ctest7;
+
+ /* will need to re-negotiate sync xfers */
+ bzero(&sc->sc_sync, sizeof (sc->sc_sync));
+
+ i = rp->siop_istat;
+ if (i & SIOP_ISTAT_SIP)
+ dummy = rp->siop_sstat0;
+ if (i & SIOP_ISTAT_DIP)
+ dummy = rp->siop_dstat;
+
+ splx(s);
+
+ delay(siop_reset_delay * 1000);
+ printf(": version %d target %d\n", rp->siop_ctest8 >> 4,
+ sc->sc_link.adapter_target);
+
+ if ((sc->sc_flags & SIOP_ALIVE) == 0) {
+ TAILQ_INIT(&sc->ready_list);
+ TAILQ_INIT(&sc->nexus_list);
+ TAILQ_INIT(&sc->free_list);
+ sc->sc_nexus = NULL;
+ acb = sc->sc_acb;
+ bzero(acb, sizeof(sc->sc_acb));
+ for (i = 0; i < sizeof(sc->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
+ acb++;
+ }
+ bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ } else {
+ if (sc->sc_nexus != NULL) {
+ sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
+ siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
+ }
+ while (acb = sc->nexus_list.tqh_first) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ siop_scsidone(acb, acb->stat[0]);
+ }
+ }
+
+ sc->sc_flags |= SIOP_ALIVE;
+ sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF);
+ /* enable SCSI and DMA interrupts */
+ sc->sc_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE |
+ SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR;
+ sc->sc_dien = SIOP_DIEN_BF | SIOP_DIEN_ABRT | SIOP_DIEN_SIR |
+ /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID;
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+}
+
+/*
+ * Setup Data Storage for 53C710 and start SCRIPTS processing
+ */
+
+void
+siop_start (sc, target, lun, cbuf, clen, buf, len)
+ struct siop_softc *sc;
+ int target;
+ int lun;
+ u_char *cbuf;
+ int clen;
+ u_char *buf;
+ int len;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ int i;
+ int nchain;
+ int count, tcount;
+ char *addr, *dmaend;
+ struct siop_acb *acb = sc->sc_nexus;
+
+#ifdef DEBUG
+ if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy: rp %x script %x dsa %x active %d\n",
+ rp, &scripts, &acb->ds, sc->sc_active);
+ printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
+ rp->siop_istat, rp->siop_sfbr, rp->siop_lcrc,
+ rp->siop_sien, rp->siop_dien);
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+#endif
+ acb->msgout[0] = MSG_IDENTIFY | lun;
+ if (siop_allow_disc[target] & 2 ||
+ (siop_allow_disc[target] && len == 0))
+ acb->msgout[0] = MSG_IDENTIFY_DR | lun;
+ acb->status = 0;
+ acb->stat[0] = -1;
+ acb->msg[0] = -1;
+ acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8);
+ acb->ds.idlen = 1;
+ acb->ds.idbuf = (char *) kvtop(&acb->msgout[0]);
+ acb->ds.cmdlen = clen;
+ acb->ds.cmdbuf = (char *) kvtop(cbuf);
+ acb->ds.stslen = 1;
+ acb->ds.stsbuf = (char *) kvtop(&acb->stat[0]);
+ acb->ds.msglen = 1;
+ acb->ds.msgbuf = (char *) kvtop(&acb->msg[0]);
+ acb->msg[1] = -1;
+ acb->ds.msginlen = 1;
+ acb->ds.extmsglen = 1;
+ acb->ds.synmsglen = 3;
+ acb->ds.msginbuf = (char *) kvtop(&acb->msg[1]);
+ acb->ds.extmsgbuf = (char *) kvtop(&acb->msg[2]);
+ acb->ds.synmsgbuf = (char *) kvtop(&acb->msg[3]);
+ bzero(&acb->ds.chain, sizeof (acb->ds.chain));
+
+ if (sc->sc_sync[target].state == SYNC_START) {
+ if (siop_inhibit_sync[target]) {
+ sc->sc_sync[target].state = SYNC_DONE;
+ sc->sc_sync[target].sbcl = 0;
+ sc->sc_sync[target].sxfer = 0;
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("Forcing target %d asynchronous\n", target);
+#endif
+ }
+ else {
+ acb->msg[2] = -1;
+ acb->msgout[1] = MSG_EXT_MESSAGE;
+ acb->msgout[2] = 3;
+ acb->msgout[3] = MSG_SYNC_REQ;
+#ifdef MAXTOR_SYNC_KLUDGE
+ acb->msgout[4] = 50 / 4; /* ask for ridiculous period */
+#else
+ acb->msgout[4] = sc->sc_minsync;
+#endif
+ acb->msgout[5] = SIOP_MAX_OFFSET;
+ acb->ds.idlen = 6;
+ sc->sc_sync[target].state = SYNC_SENT;
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("Sending sync request to target %d\n", target);
+#endif
+ }
+ }
+
+/*
+ * Build physical DMA addresses for scatter/gather I/O
+ */
+ acb->iob_buf = buf;
+ acb->iob_len = len;
+ acb->iob_curbuf = acb->iob_curlen = 0;
+ nchain = 0;
+ count = len;
+ addr = buf;
+ dmaend = NULL;
+ while (count > 0) {
+ acb->ds.chain[nchain].databuf = (char *) kvtop (addr);
+ if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
+ tcount = count;
+ acb->ds.chain[nchain].datalen = tcount;
+ addr += tcount;
+ count -= tcount;
+ if (acb->ds.chain[nchain].databuf == dmaend) {
+ dmaend += acb->ds.chain[nchain].datalen;
+ acb->ds.chain[nchain].datalen = 0;
+ acb->ds.chain[--nchain].datalen += tcount;
+#ifdef DEBUG
+ ++siopdma_hits;
+#endif
+ }
+ else {
+ dmaend = acb->ds.chain[nchain].databuf +
+ acb->ds.chain[nchain].datalen;
+ acb->ds.chain[nchain].datalen = tcount;
+#ifdef DEBUG
+ if (nchain) /* Don't count miss on first one */
+ ++siopdma_misses;
+#endif
+ }
+ ++nchain;
+ }
+#ifdef DEBUG
+ if (nchain != 1 && len != 0 && siop_debug & 3) {
+ printf ("DMA chaining set: %d\n", nchain);
+ for (i = 0; i < nchain; ++i) {
+ printf (" [%d] %8x %4x\n", i, acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+ }
+ }
+#endif
+
+ /* push data cache for all data the 53c710 needs to access */
+ dma_cachectl (sc, sizeof (struct siop_softc));
+ dma_cachectl (cbuf, clen);
+ if (buf != NULL && len != 0)
+ dma_cachectl (buf, len);
+#ifdef DEBUG
+ if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy at start: rp %x script %x dsa %x active %d\n",
+ rp, &scripts, &acb->ds, sc->sc_active);
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+#endif
+ if (sc->nexus_list.tqh_first == NULL) {
+ if (rp->siop_istat & SIOP_ISTAT_CON)
+ printf("%s: siop_select while connected?\n",
+ sc->sc_dev.dv_xname);
+ rp->siop_temp = 0;
+ rp->siop_sbcl = sc->sc_sync[target].sbcl;
+ rp->siop_dsa = kvtop(&acb->ds);
+ rp->siop_dsp = sc->sc_scriptspa;
+ SIOP_TRACE('s',1,0,0)
+ } else {
+ if ((rp->siop_istat & SIOP_ISTAT_CON) == 0) {
+ rp->siop_istat = SIOP_ISTAT_SIGP;
+ SIOP_TRACE('s',2,0,0);
+ }
+ else {
+ SIOP_TRACE('s',3,rp->siop_istat,0);
+ }
+ }
+#ifdef DEBUG
+ ++siopstarts;
+#endif
+}
+
+/*
+ * Process a DMA or SCSI interrupt from the 53C710 SIOP
+ */
+
+int
+siop_checkintr(sc, istat, dstat, sstat0, status)
+ struct siop_softc *sc;
+ u_char istat;
+ u_char dstat;
+ u_char sstat0;
+ int *status;
+{
+ siop_regmap_p rp = sc->sc_siopp;
+ struct siop_acb *acb = sc->sc_nexus;
+ int target;
+ int dfifo, dbc, sstat1;
+
+ dfifo = rp->siop_dfifo;
+ dbc = rp->siop_dbc0;
+ sstat1 = rp->siop_sstat1;
+ rp->siop_ctest8 |= SIOP_CTEST8_CLF;
+ while ((rp->siop_ctest1 & SIOP_CTEST1_FMT) != SIOP_CTEST1_FMT)
+ ;
+ rp->siop_ctest8 &= ~SIOP_CTEST8_CLF;
+#ifdef DEBUG
+ ++siopints;
+#if 0
+ if (siop_debug & 0x100) {
+ DCIAS(&acb->stat[0]); /* XXX */
+ printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
+ istat, dstat, sstat0, rp->siop_dsps, rp->siop_sbcl, acb->stat[0], acb->msg[0]);
+ printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
+ acb->msg[0], acb->msg[1], acb->msg[2],
+ acb->msg[3], acb->msg[4], acb->msg[5]);
+ }
+#endif
+ if (rp->siop_dsp && (rp->siop_dsp < sc->sc_scriptspa ||
+ rp->siop_dsp >= sc->sc_scriptspa + sizeof(scripts))) {
+ printf ("%s: dsp not within script dsp %x scripts %x:%x",
+ sc->sc_dev.dv_xname, rp->siop_dsp, sc->sc_scriptspa,
+ sc->sc_scriptspa + sizeof(scripts));
+ printf(" istat %x dstat %x sstat0 %x\n",
+ istat, dstat, sstat0);
+ Debugger();
+ }
+#endif
+ SIOP_TRACE('i',dstat,istat,(istat&SIOP_ISTAT_DIP)?rp->siop_dsps&0xff:sstat0);
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff00) {
+ /* Normal completion status, or check condition */
+#ifdef DEBUG
+ if (rp->siop_dsa != kvtop(&acb->ds)) {
+ printf ("siop: invalid dsa: %x %x\n", rp->siop_dsa,
+ kvtop(&acb->ds));
+ panic("*** siop DSA invalid ***");
+ }
+#endif
+ target = acb->xs->sc_link->target;
+ if (sc->sc_sync[target].state == SYNC_SENT) {
+#ifdef DEBUG
+ if (siopsync_debug)
+ printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
+ acb->msg[0], acb->msg[1], acb->msg[2],
+ acb->msg[3], acb->msg[4], acb->msg[5]);
+#endif
+ if (acb->msg[1] == 0xff)
+ printf ("%s: target %d ignored sync request\n",
+ sc->sc_dev.dv_xname, target);
+ else if (acb->msg[1] == MSG_REJECT)
+ printf ("%s: target %d rejected sync request\n",
+ sc->sc_dev.dv_xname, target);
+ sc->sc_sync[target].state = SYNC_DONE;
+ sc->sc_sync[target].sxfer = 0;
+ sc->sc_sync[target].sbcl = 0;
+ if (acb->msg[2] == 3 &&
+ acb->msg[3] == MSG_SYNC_REQ &&
+ acb->msg[5] != 0) {
+#ifdef MAXTOR_KLUDGE
+ /*
+ * Kludge for my Maxtor XT8580S
+ * It accepts whatever we request, even
+ * though it won't work. So we ask for
+ * a short period than we can handle. If
+ * the device says it can do it, use 208ns.
+ * If the device says it can do less than
+ * 100ns, then we limit it to 100ns.
+ */
+ if (acb->msg[4] && acb->msg[4] < 100 / 4) {
+#ifdef DEBUG
+ printf ("%d: target %d wanted %dns period\n",
+ sc->sc_dev.dv_xname, target,
+ acb->msg[4] * 4);
+#endif
+ if (acb->msg[4] == 50 / 4)
+ acb->msg[4] = 208 / 4;
+ else
+ acb->msg[4] = 100 / 4;
+ }
+#endif /* MAXTOR_KLUDGE */
+ printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
+ sc->sc_dev.dv_xname, target,
+ acb->msg[4] * 4, acb->msg[5]);
+ scsi_period_to_siop (sc, target);
+ }
+ }
+ dma_cachectl(&acb->stat[0], 1);
+ *status = acb->stat[0];
+#ifdef DEBUG
+ if (rp->siop_sbcl & SIOP_BSY) {
+ /*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n",
+ rp, &scripts, &acb->ds);*/
+#ifdef DDB
+ /*Debugger();*/
+#endif
+ }
+ if (acb->msg[0] != 0x00)
+ printf("%s: message was not COMMAND COMPLETE: %x\n",
+ sc->sc_dev.dv_xname, acb->msg[0]);
+#endif
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return 1;
+ }
+ if (sstat0 & SIOP_SSTAT0_M_A) { /* Phase mismatch */
+#ifdef DEBUG
+ ++siopphmm;
+ if (acb == NULL)
+ printf("%s: Phase mismatch with no active command?\n",
+ sc->sc_dev.dv_xname);
+#endif
+ if (acb->iob_len) {
+ int adjust;
+ adjust = ((dfifo - (dbc & 0x7f)) & 0x7f);
+ if (sstat1 & SIOP_SSTAT1_ORF)
+ ++adjust;
+ if (sstat1 & SIOP_SSTAT1_OLF)
+ ++adjust;
+ acb->iob_curlen = *((long *)&rp->siop_dcmd) & 0xffffff;
+ acb->iob_curlen += adjust;
+ acb->iob_curbuf = *((long *)&rp->siop_dnad) - adjust;
+#ifdef DEBUG
+ if (siop_debug & 0x100) {
+ int i;
+ printf ("Phase mismatch: curbuf %x curlen %x dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %x\n",
+ acb->iob_curbuf, acb->iob_curlen, dfifo,
+ dbc, sstat1, adjust, rp->siop_sbcl, siopstarts, acb);
+ if (acb->ds.chain[1].datalen) {
+ for (i = 0; acb->ds.chain[i].datalen; ++i)
+ printf("chain[%d] addr %x len %x\n",
+ i, acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+ }
+ }
+#endif
+ dma_cachectl (acb, sizeof(*acb));
+ }
+#ifdef DEBUG
+ SIOP_TRACE('m',rp->siop_sbcl,(rp->siop_dsp>>8),rp->siop_dsp);
+ if (siop_debug & 9)
+ printf ("Phase mismatch: %x dsp +%x dcmd %x\n",
+ rp->siop_sbcl,
+ rp->siop_dsp - sc->sc_scriptspa,
+ *((long *)&rp->siop_dcmd));
+#endif
+ if ((rp->siop_sbcl & SIOP_REQ) == 0) {
+ printf ("Phase mismatch: REQ not asserted! %02x dsp %x\n",
+ rp->siop_sbcl, rp->siop_dsp);
+#ifdef DEBUG
+ Debugger();
+#endif
+ }
+ switch (rp->siop_sbcl & 7) {
+ case 0: /* data out */
+ case 1: /* data in */
+ case 2: /* status */
+ case 3: /* command */
+ case 6: /* message in */
+ case 7: /* message out */
+ rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
+ break;
+ default:
+ goto bad_phase;
+ }
+ return 0;
+ }
+ if (sstat0 & SIOP_SSTAT0_STO) { /* Select timed out */
+#ifdef DEBUG
+ if (acb == NULL)
+ printf("%s: Select timeout with no active command?\n",
+ sc->sc_dev.dv_xname);
+ if (rp->siop_sbcl & SIOP_BSY) {
+ printf ("ACK! siop was busy at timeout: rp %x script %x dsa %x\n",
+ rp, &scripts, &acb->ds);
+ printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
+ rp->siop_sbcl, rp->siop_sdid, istat, dstat, sstat0);
+ if (!(rp->siop_sbcl & SIOP_BSY)) {
+ printf ("Yikes, it's not busy now!\n");
+#if 0
+ *status = -1;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+#endif
+ }
+/* rp->siop_dcntl |= SIOP_DCNTL_STD;*/
+ return (0);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+#endif
+ *status = -1;
+ acb->xs->error = XS_SELTIMEOUT;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+ }
+ if (acb)
+ target = acb->xs->sc_link->target;
+ else
+ target = 7;
+ if (sstat0 & SIOP_SSTAT0_UDC) {
+#ifdef DEBUG
+ if (acb == NULL)
+ printf("%s: Unexpected disconnect with no active command?\n",
+ sc->sc_dev.dv_xname);
+ printf ("%s: target %d disconnected unexpectedly\n",
+ sc->sc_dev.dv_xname, target);
+#endif
+#if 0
+ siopabort (sc, rp, "siopchkintr");
+#endif
+ *status = STS_BUSY;
+ if (sc->nexus_list.tqh_first)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+ return 1;
+ }
+ if (dstat & SIOP_DSTAT_SIR && (rp->siop_dsps == 0xff01 ||
+ rp->siop_dsps == 0xff02)) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: ID %02x disconnected TEMP %x (+%x) curbuf %x curlen %x buf %x len %x dfifo %x dbc %x sstat1 %x starts %d acb %x\n",
+ sc->sc_dev.dv_xname, 1 << target, rp->siop_temp,
+ rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0,
+ acb->iob_curbuf, acb->iob_curlen,
+ acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb);
+#endif
+ if (acb == NULL) {
+ printf("%s: Disconnect with no active command?\n",
+ sc->sc_dev.dv_xname);
+ return (0);
+ }
+ /*
+ * XXXX need to update iob_curbuf/iob_curlen to reflect
+ * current data transferred. If device disconnected in
+ * the middle of a DMA block, they should already be set
+ * by the phase change interrupt. If the disconnect
+ * occurs on a DMA block boundary, we have to figure out
+ * which DMA block it was.
+ */
+ if (acb->iob_len && rp->siop_temp) {
+ int n = rp->siop_temp - sc->sc_scriptspa;
+
+ if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen)
+ printf("%s: iob_curbuf/len already set? n %x iob %x/%x chain[0] %x/%x\n",
+ sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen,
+ acb->ds.chain[0].databuf, acb->ds.chain[0].datalen);
+ if (n < Ent_datain)
+ n = (n - Ent_dataout) / 16;
+ else
+ n = (n - Ent_datain) / 16;
+ if (n <= 0 && n > DMAMAXIO)
+ printf("TEMP invalid %d\n", n);
+ else {
+ acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf;
+ acb->iob_curlen = acb->ds.chain[n].datalen;
+ }
+#ifdef DEBUG
+ if (siop_debug & 0x100) {
+ printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n);
+ printf(" curbuf %x curlen %x\n", acb->iob_curbuf,
+ acb->iob_curlen);
+ }
+#endif
+ }
+ /*
+ * If data transfer was interrupted by disconnect, iob_curbuf
+ * and iob_curlen should reflect the point of interruption.
+ * Adjust the DMA chain so that the data transfer begins
+ * at the appropriate place upon reselection.
+ * XXX This should only be done on save data pointer message?
+ */
+ if (acb->iob_curlen) {
+ int i, j;
+
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: adjusting DMA chain\n",
+ sc->sc_dev.dv_xname);
+ if (rp->siop_dsps == 0xff02)
+ printf ("%s: ID %02x disconnected without Save Data Pointers\n",
+ sc->sc_dev.dv_xname, 1 << target);
+#endif
+ for (i = 0; i < DMAMAXIO; ++i) {
+ if (acb->ds.chain[i].datalen == 0)
+ break;
+ if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf &&
+ acb->iob_curbuf < (long)(acb->ds.chain[i].databuf +
+ acb->ds.chain[i].datalen))
+ break;
+ }
+ if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0)
+ printf("couldn't find saved data pointer\n");
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf(" chain[0]: %x/%x -> %x/%x\n",
+ acb->ds.chain[0].databuf,
+ acb->ds.chain[0].datalen,
+ acb->iob_curbuf,
+ acb->iob_curlen);
+#endif
+ acb->ds.chain[0].databuf = (char *)acb->iob_curbuf;
+ acb->ds.chain[0].datalen = acb->iob_curlen;
+ for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf(" chain[%d]: %x/%x -> %x/%x\n", j,
+ acb->ds.chain[j].databuf,
+ acb->ds.chain[j].datalen,
+ acb->ds.chain[i].databuf,
+ acb->ds.chain[i].datalen);
+#endif
+ acb->ds.chain[j].databuf = acb->ds.chain[i].databuf;
+ acb->ds.chain[j].datalen = acb->ds.chain[i].datalen;
+ }
+ if (j < DMAMAXIO)
+ acb->ds.chain[j].datalen = 0;
+ DCIAS(kvtop(&acb->ds.chain));
+ }
+ ++sc->sc_tinfo[target].dconns;
+ /*
+ * add nexus to waiting list
+ * clear nexus
+ * try to start another command for another target/lun
+ */
+ acb->status = sc->sc_flags & SIOP_INTSOFF;
+ TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
+ sc->sc_nexus = NULL; /* no current device */
+ /* start script to wait for reselect */
+ if (sc->sc_nexus == NULL)
+ rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
+/* XXXX start another command ? */
+ if (sc->ready_list.tqh_first)
+ siop_sched(sc);
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff03) {
+ int reselid = rp->siop_scratch & 0x7f;
+ int reselun = rp->siop_sfbr & 0x07;
+
+ sc->sc_sstat1 = rp->siop_sbcl; /* XXXX save current SBCL */
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: target ID %02x reselected dsps %x\n",
+ sc->sc_dev.dv_xname, reselid,
+ rp->siop_dsps);
+ if ((rp->siop_sfbr & 0x80) == 0)
+ printf("%s: Reselect message in was not identify: %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sfbr);
+#endif
+ if (sc->sc_nexus) {
+#ifdef DEBUG
+ if (siop_debug & 0x100)
+ printf ("%s: reselect ID %02x w/active\n",
+ sc->sc_dev.dv_xname, reselid);
+#endif
+ TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
+ sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target].lubusy
+ &= ~(1 << sc->sc_nexus->xs->sc_link->lun);
+ --sc->sc_active;
+ }
+ /*
+ * locate acb of reselecting device
+ * set sc->sc_nexus to acb
+ */
+ for (acb = sc->nexus_list.tqh_first; acb;
+ acb = acb->chain.tqe_next) {
+ if (reselid != (acb->ds.scsi_addr >> 16) ||
+ reselun != (acb->msgout[0] & 0x07))
+ continue;
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ sc->sc_nexus = acb;
+ sc->sc_flags |= acb->status;
+ acb->status = 0;
+ DCIAS(kvtop(&acb->stat[0]));
+ rp->siop_dsa = kvtop(&acb->ds);
+ rp->siop_sxfer = sc->sc_sync[acb->xs->sc_link->target].sxfer;
+ rp->siop_sbcl = sc->sc_sync[acb->xs->sc_link->target].sbcl;
+ break;
+ }
+ if (acb == NULL) {
+ printf("%s: target ID %02x reselect nexus_list %x\n",
+ sc->sc_dev.dv_xname, reselid,
+ sc->nexus_list.tqh_first);
+ panic("unable to find reselecting device");
+ }
+ dma_cachectl (acb, sizeof(*acb));
+ rp->siop_temp = 0;
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff04) {
+ u_short ctest2 = rp->siop_ctest2;
+
+ /* reselect was interrupted (by Sig_P or select) */
+#ifdef DEBUG
+ if (siop_debug & 0x100 ||
+ (ctest2 & SIOP_CTEST2_SIGP) == 0)
+ printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
+ sc->sc_dev.dv_xname, rp->siop_scntl1,
+ ctest2, rp->siop_sfbr, istat, rp->siop_istat);
+#endif
+ /* XXX assumes it was not select */
+ if (sc->sc_nexus == NULL) {
+ printf("%s: reselect interrupted, sc_nexus == NULL\n",
+ sc->sc_dev.dv_xname);
+#if 0
+ siop_dump(sc);
+#ifdef DDB
+ Debugger();
+#endif
+#endif
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return(0);
+ }
+ target = sc->sc_nexus->xs->sc_link->target;
+ rp->siop_temp = 0;
+ rp->siop_dsa = kvtop(&sc->sc_nexus->ds);
+ rp->siop_sxfer = sc->sc_sync[target].sxfer;
+ rp->siop_sbcl = sc->sc_sync[target].sbcl;
+ rp->siop_dsp = sc->sc_scriptspa;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff06) {
+ if (acb == NULL)
+ printf("%s: Bad message-in with no active command?\n",
+ sc->sc_dev.dv_xname);
+ /* Unrecognized message in byte */
+ dma_cachectl (&acb->msg[1],1);
+ printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sfbr, acb->msg[1], rp->siop_sbcl);
+ /* what should be done here? */
+ DCIAS(kvtop(&acb->msg[1]));
+ rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
+ return (0);
+ }
+ if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0a) {
+ /* Status phase wasn't followed by message in phase? */
+ printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
+ sc->sc_dev.dv_xname, rp->siop_sbcl, rp->siop_sbdl);
+ if (rp->siop_sbcl == 0xa7) {
+ /* It is now, just continue the script? */
+ rp->siop_dcntl |= SIOP_DCNTL_STD;
+ return (0);
+ }
+ }
+ if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) {
+ dma_cachectl (&acb->stat[0], 1);
+ dma_cachectl (&acb->msg[0], 1);
+ printf ("SIOP interrupt: %x sts %x msg %x %x sbcl %x\n",
+ rp->siop_dsps, acb->stat[0], acb->msg[0], acb->msg[1],
+ rp->siop_sbcl);
+ siopreset (sc);
+ *status = -1;
+ return 0; /* siopreset has cleaned up */
+ }
+ if (sstat0 & SIOP_SSTAT0_SGE)
+ printf ("SIOP: SCSI Gross Error\n");
+ if (sstat0 & SIOP_SSTAT0_PAR)
+ printf ("SIOP: Parity Error\n");
+ if (dstat & SIOP_DSTAT_IID)
+ printf ("SIOP: Invalid instruction detected\n");
+bad_phase:
+ /*
+ * temporary panic for unhandled conditions
+ * displays various things about the 53C710 status and registers
+ * then panics.
+ * XXXX need to clean this up to print out the info, reset, and continue
+ */
+ printf ("siopchkintr: target %x ds %x\n", target, &acb->ds);
+ printf ("scripts %x ds %x rp %x dsp %x dcmd %x\n", sc->sc_scriptspa,
+ kvtop(&acb->ds), kvtop(rp), rp->siop_dsp,
+ *((long *)&rp->siop_dcmd));
+ printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n",
+ istat, dstat, sstat0, rp->siop_dsps, rp->siop_dsa,
+ rp->siop_sbcl, acb->stat[0], acb->msg[0], acb->msg[1], rp->siop_sfbr);
+#ifdef DEBUG
+ if (siop_debug & 0x20)
+ panic("siopchkintr: **** temp ****");
+#endif
+#ifdef DDB
+ Debugger ();
+#endif
+ siopreset (sc); /* hard reset */
+ *status = -1;
+ return 0; /* siopreset cleaned up */
+}
+
+void
+siop_select(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ struct siop_acb *acb = sc->sc_nexus;
+
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("%s: select ", sc->sc_dev.dv_xname);
+#endif
+
+ rp = sc->sc_siopp;
+ if (acb->xs->flags & SCSI_POLL || siop_no_dma) {
+ sc->sc_flags |= SIOP_INTSOFF;
+ sc->sc_flags &= ~SIOP_INTDEFER;
+ if ((rp->siop_istat & 0x08) == 0) {
+ rp->siop_sien = 0;
+ rp->siop_dien = 0;
+ }
+#if 0
+ } else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
+ sc->sc_flags &= ~SIOP_INTSOFF;
+ if ((rp->siop_istat & 0x08) == 0) {
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+#endif
+ }
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("siop_select: target %x cmd %02x ds %x\n",
+ acb->xs->sc_link->target, acb->cmd.opcode,
+ &sc->sc_nexus->ds);
+#endif
+
+ siop_start(sc, acb->xs->sc_link->target, acb->xs->sc_link->lun,
+ &acb->cmd, acb->clen, acb->daddr, acb->dleft);
+
+ return;
+}
+
+/*
+ * 53C710 interrupt handler
+ */
+
+int
+siopintr (sc)
+ register struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ register u_char istat, dstat, sstat0;
+ int status;
+ int s = splbio();
+
+ istat = sc->sc_istat;
+ if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
+ splx(s);
+ return;
+ }
+
+ /* Got a valid interrupt on this device */
+ rp = sc->sc_siopp;
+ dstat = sc->sc_dstat;
+ sstat0 = sc->sc_sstat0;
+ if (dstat & SIOP_DSTAT_SIR)
+ sc->sc_intcode = rp->siop_dsps;
+ sc->sc_istat = 0;
+#ifdef DEBUG
+ if (siop_debug & 1)
+ printf ("%s: intr istat %x dstat %x sstat0 %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0);
+ if (!sc->sc_active) {
+ printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x status %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus->stat[0]);
+ }
+#endif
+
+#ifdef DEBUG
+ if (siop_debug & 5) {
+ DCIAS(kvtop(&sc->sc_nexus->stat[0]));
+ printf ("%s: intr istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
+ sc->sc_dev.dv_xname, istat, dstat, sstat0,
+ rp->siop_dsps, rp->siop_sbcl,
+ sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]);
+ }
+#endif
+ if (sc->sc_flags & SIOP_INTDEFER) {
+ sc->sc_flags &= ~(SIOP_INTDEFER | SIOP_INTSOFF);
+ rp->siop_sien = sc->sc_sien;
+ rp->siop_dien = sc->sc_dien;
+ }
+ if (siop_checkintr (sc, istat, dstat, sstat0, &status)) {
+#if 1
+ if (status == 0xff)
+ printf ("siopintr: status == 0xff\n");
+#endif
+ if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) {
+#if 0
+ if (rp->siop_sbcl & SIOP_BSY) {
+ printf ("%s: SCSI bus busy at completion",
+ sc->sc_dev.dv_xname);
+ printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
+ sc->sc_nexus->xs->sc_link->target,
+ rp->siop_sbcl, rp->siop_sfbr, rp->siop_lcrc,
+ rp->siop_dsp - sc->sc_scriptspa);
+ }
+#endif
+ siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
+ }
+ }
+ splx(s);
+}
+
+/*
+ * This is based on the Progressive Peripherals 33Mhz Zeus driver and will
+ * not be correct for other 53c710 boards.
+ *
+ */
+scsi_period_to_siop (sc, target)
+ struct siop_softc *sc;
+{
+ int period, offset, i, sxfer, sbcl;
+
+ period = sc->sc_nexus->msg[4];
+ offset = sc->sc_nexus->msg[5];
+ for (sbcl = 1; sbcl < 4; ++sbcl) {
+ sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
+ if (sxfer >= 0 && sxfer <= 7)
+ break;
+ }
+ if (sbcl > 3) {
+ printf("siop_sync: unable to compute sync params for period %dns\n",
+ period * 4);
+ /*
+ * XXX need to pick a value we can do and renegotiate
+ */
+ sxfer = sbcl = 0;
+ } else
+ sxfer = (sxfer << 4) | ((offset <= SIOP_MAX_OFFSET) ?
+ offset : SIOP_MAX_OFFSET);
+ sc->sc_sync[target].sxfer = sxfer;
+ sc->sc_sync[target].sbcl = sbcl;
+#ifdef DEBUG
+ printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
+#endif
+}
+
+#ifdef DEBUG
+
+#if SIOP_TRACE_SIZE
+void
+siop_dump_trace()
+{
+ int i;
+
+ printf("siop trace: next index %d\n", siop_trix);
+ i = siop_trix;
+ do {
+ printf("%3d: '%c' %02x %02x %02x\n", i, siop_trbuf[i],
+ siop_trbuf[i + 1], siop_trbuf[i + 2], siop_trbuf[i + 3]);
+ i = (i + 4) & (SIOP_TRACE_SIZE - 1);
+ } while (i != siop_trix);
+}
+#endif
+
+void
+siop_dump_acb(acb)
+ struct siop_acb *acb;
+{
+ u_char *b = (u_char *) &acb->cmd;
+ int i;
+
+#if SIOP_TRACE_SIZE
+ siop_dump_trace();
+#endif
+ printf("acb@%x ", acb);
+ if (acb->xs == NULL) {
+ printf("<unused>\n");
+ return;
+ }
+ printf("(%d:%d) flags %2x clen %2d cmd ", acb->xs->sc_link->target,
+ acb->xs->sc_link->lun, acb->flags, acb->clen);
+ for (i = acb->clen; i; --i)
+ printf(" %02x", *b++);
+ printf("\n");
+ printf(" xs: %08x data %8x:%04x ", acb->xs, acb->xs->data,
+ acb->xs->datalen);
+ printf("va %8x:%04x ", acb->iob_buf, acb->iob_len);
+ printf("cur %8x:%04x\n", acb->iob_curbuf, acb->iob_curlen);
+ }
+
+void
+siop_dump(sc)
+ struct siop_softc *sc;
+{
+ struct siop_acb *acb;
+ siop_regmap_p rp = sc->sc_siopp;
+ int s;
+ int i;
+
+ s = splbio();
+ printf("%s@%x regs %x istat %x\n",
+ sc->sc_dev.dv_xname, sc, rp, rp->siop_istat);
+ if (acb = sc->free_list.tqh_first) {
+ printf("Free list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (acb = sc->ready_list.tqh_first) {
+ printf("Ready list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (acb = sc->nexus_list.tqh_first) {
+ printf("Nexus list:\n");
+ while (acb) {
+ siop_dump_acb(acb);
+ acb = acb->chain.tqe_next;
+ }
+ }
+ if (sc->sc_nexus) {
+ printf("Nexus:\n");
+ siop_dump_acb(sc->sc_nexus);
+ }
+ for (i = 0; i < 8; ++i) {
+ if (sc->sc_tinfo[i].cmds > 2) {
+ printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n",
+ i, sc->sc_tinfo[i].cmds,
+ sc->sc_tinfo[i].dconns,
+ sc->sc_tinfo[i].senses,
+ sc->sc_tinfo[i].lubusy);
+ }
+ }
+ splx(s);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/siop_script.out b/sys/arch/mvme68k/dev/siop_script.out
new file mode 100644
index 00000000000..c6a91178fc8
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop_script.out
@@ -0,0 +1,175 @@
+unsigned long scripts[] = {
+ 0x47000000, 0x00000118, /* 000 - 0 */
+ 0x878b0000, 0x00000030, /* 008 - 8 */
+ 0x868a0000, 0x00000168, /* 010 - 16 */
+ 0x828a0000, 0x00000170, /* 018 - 24 */
+ 0x808a0000, 0x00000180, /* 020 - 32 */
+ 0x818a0000, 0x00000288, /* 028 - 40 */
+ 0x838a0000, 0x00000390, /* 030 - 48 */
+ 0x98080000, 0x0000ff05, /* 038 - 56 */
+ 0x1f000024, 0x00000024, /* 040 - 64 */
+ 0x808c0001, 0x00000040, /* 048 - 72 */
+ 0x808c0004, 0x00000078, /* 050 - 80 */
+ 0x808c0002, 0x00000088, /* 058 - 88 */
+ 0x808c0007, 0x00000010, /* 060 - 96 */
+ 0x808c0003, 0x00000008, /* 068 - 104 */
+ 0x98080000, 0x0000ff06, /* 070 - 112 */
+ 0x60000040, 0x00000000, /* 078 - 120 */
+ 0x60000008, 0x00000000, /* 080 - 128 */
+ 0x80880000, 0xffffff78, /* 088 - 136 */
+ 0x60000040, 0x00000000, /* 090 - 144 */
+ 0x1f00002c, 0x0000002c, /* 098 - 152 */
+ 0x808c0003, 0x00000008, /* 0a0 - 160 */
+ 0x98080000, 0x0000ff07, /* 0a8 - 168 */
+ 0x60000040, 0x00000000, /* 0b0 - 176 */
+ 0x1f000034, 0x00000034, /* 0b8 - 184 */
+ 0x60000040, 0x00000000, /* 0c0 - 192 */
+ 0x80880000, 0xffffff38, /* 0c8 - 200 */
+ 0x60000040, 0x00000000, /* 0d0 - 208 */
+ 0x48000000, 0x00000000, /* 0d8 - 216 */
+ 0x98080000, 0x0000ff02, /* 0e0 - 224 */
+ 0x60000040, 0x00000000, /* 0e8 - 232 */
+ 0x87830000, 0xffffff10, /* 0f0 - 240 */
+ 0x1f00002c, 0x0000002c, /* 0f8 - 248 */
+ 0x98040004, 0x0000ff08, /* 100 - 256 */
+ 0x60000040, 0x00000000, /* 108 - 264 */
+ 0x48000000, 0x00000000, /* 110 - 272 */
+ 0x98080000, 0x0000ff01, /* 118 - 280 */
+ 0x54000000, 0x00000038, /* 120 - 288 */
+ 0x72230000, 0x00000000, /* 128 - 296 */
+ 0x6a340000, 0x00000000, /* 130 - 304 */
+ 0x9f030000, 0x0000ff09, /* 138 - 312 */
+ 0x1f00001c, 0x0000001c, /* 140 - 320 */
+ 0x98080000, 0x0000ff03, /* 148 - 328 */
+ 0x60000040, 0x00000000, /* 150 - 336 */
+ 0x80880000, 0xfffffea8, /* 158 - 344 */
+ 0x74011000, 0x00000000, /* 160 - 352 */
+ 0x980c0000, 0x0000ff04, /* 168 - 360 */
+ 0x74164000, 0x00000000, /* 170 - 368 */
+ 0x80880000, 0xffffffa0, /* 178 - 376 */
+ 0x1e000004, 0x00000004, /* 180 - 384 */
+ 0x80880000, 0xfffffe78, /* 188 - 392 */
+ 0x60000008, 0x00000000, /* 190 - 400 */
+ 0x1a00000c, 0x0000000c, /* 198 - 408 */
+ 0x80880000, 0xfffffe60, /* 1a0 - 416 */
+ 0x1800003c, 0x0000003c, /* 1a8 - 424 */
+ 0x88830000, 0xfffffe50, /* 1b0 - 432 */
+ 0x18000044, 0x00000044, /* 1b8 - 440 */
+ 0x88830000, 0xfffffe40, /* 1c0 - 448 */
+ 0x1800004c, 0x0000004c, /* 1c8 - 456 */
+ 0x88830000, 0xfffffe30, /* 1d0 - 464 */
+ 0x18000054, 0x00000054, /* 1d8 - 472 */
+ 0x88830000, 0xfffffe20, /* 1e0 - 480 */
+ 0x1800005c, 0x0000005c, /* 1e8 - 488 */
+ 0x88830000, 0xfffffe10, /* 1f0 - 496 */
+ 0x18000064, 0x00000064, /* 1f8 - 504 */
+ 0x88830000, 0xfffffe00, /* 200 - 512 */
+ 0x1800006c, 0x0000006c, /* 208 - 520 */
+ 0x88830000, 0xfffffdf0, /* 210 - 528 */
+ 0x18000074, 0x00000074, /* 218 - 536 */
+ 0x88830000, 0xfffffde0, /* 220 - 544 */
+ 0x1800007c, 0x0000007c, /* 228 - 552 */
+ 0x88830000, 0xfffffdd0, /* 230 - 560 */
+ 0x18000084, 0x00000084, /* 238 - 568 */
+ 0x88830000, 0xfffffdc0, /* 240 - 576 */
+ 0x1800008c, 0x0000008c, /* 248 - 584 */
+ 0x88830000, 0xfffffdb0, /* 250 - 592 */
+ 0x18000094, 0x00000094, /* 258 - 600 */
+ 0x88830000, 0xfffffda0, /* 260 - 608 */
+ 0x1800009c, 0x0000009c, /* 268 - 616 */
+ 0x88830000, 0xfffffd90, /* 270 - 624 */
+ 0x180000a4, 0x000000a4, /* 278 - 632 */
+ 0x88830000, 0xfffffd80, /* 280 - 640 */
+ 0x180000ac, 0x000000ac, /* 288 - 648 */
+ 0x88830000, 0xfffffd70, /* 290 - 656 */
+ 0x180000b4, 0x000000b4, /* 298 - 664 */
+ 0x88830000, 0xfffffd60, /* 2a0 - 672 */
+ 0x180000bc, 0x000000bc, /* 2a8 - 680 */
+ 0x88880000, 0xfffffd50, /* 2b0 - 688 */
+ 0x1900003c, 0x0000003c, /* 2b8 - 696 */
+ 0x89830000, 0xfffffd40, /* 2c0 - 704 */
+ 0x19000044, 0x00000044, /* 2c8 - 712 */
+ 0x89830000, 0xfffffd30, /* 2d0 - 720 */
+ 0x1900004c, 0x0000004c, /* 2d8 - 728 */
+ 0x89830000, 0xfffffd20, /* 2e0 - 736 */
+ 0x19000054, 0x00000054, /* 2e8 - 744 */
+ 0x89830000, 0xfffffd10, /* 2f0 - 752 */
+ 0x1900005c, 0x0000005c, /* 2f8 - 760 */
+ 0x89830000, 0xfffffd00, /* 300 - 768 */
+ 0x19000064, 0x00000064, /* 308 - 776 */
+ 0x89830000, 0xfffffcf0, /* 310 - 784 */
+ 0x1900006c, 0x0000006c, /* 318 - 792 */
+ 0x89830000, 0xfffffce0, /* 320 - 800 */
+ 0x19000074, 0x00000074, /* 328 - 808 */
+ 0x89830000, 0xfffffcd0, /* 330 - 816 */
+ 0x1900007c, 0x0000007c, /* 338 - 824 */
+ 0x89830000, 0xfffffcc0, /* 340 - 832 */
+ 0x19000084, 0x00000084, /* 348 - 840 */
+ 0x89830000, 0xfffffcb0, /* 350 - 848 */
+ 0x1900008c, 0x0000008c, /* 358 - 856 */
+ 0x89830000, 0xfffffca0, /* 360 - 864 */
+ 0x19000094, 0x00000094, /* 368 - 872 */
+ 0x89830000, 0xfffffc90, /* 370 - 880 */
+ 0x1900009c, 0x0000009c, /* 378 - 888 */
+ 0x89830000, 0xfffffc80, /* 380 - 896 */
+ 0x190000a4, 0x000000a4, /* 388 - 904 */
+ 0x89830000, 0xfffffc70, /* 390 - 912 */
+ 0x190000ac, 0x000000ac, /* 398 - 920 */
+ 0x89830000, 0xfffffc60, /* 3a0 - 928 */
+ 0x190000b4, 0x000000b4, /* 3a8 - 936 */
+ 0x89830000, 0xfffffc50, /* 3b0 - 944 */
+ 0x190000bc, 0x000000bc, /* 3b8 - 952 */
+ 0x88880000, 0xfffffc40, /* 3c0 - 960 */
+ 0x1b000014, 0x00000014, /* 3c8 - 968 */
+ 0x9f030000, 0x0000ff0a, /* 3d0 - 976 */
+ 0x1f00001c, 0x0000001c, /* 3d8 - 984 */
+ 0x60000040, 0x00000000, /* 3e0 - 992 */
+ 0x48000000, 0x00000000, /* 3e8 - 1000 */
+ 0x98080000, 0x0000ff00, /* 3f0 - 1008 */
+ 0x80880000, 0xfffffd20, /* 3f8 - 1016 */
+};
+
+#define A_ds_Device 0x00000000
+#define A_ds_MsgOut 0x00000004
+#define A_ds_Cmd 0x0000000c
+#define A_ds_Status 0x00000014
+#define A_ds_Msg 0x0000001c
+#define A_ds_MsgIn 0x00000024
+#define A_ds_ExtMsg 0x0000002c
+#define A_ds_SyncMsg 0x00000034
+#define A_ds_Data1 0x0000003c
+#define A_ds_Data2 0x00000044
+#define A_ds_Data3 0x0000004c
+#define A_ds_Data4 0x00000054
+#define A_ds_Data5 0x0000005c
+#define A_ds_Data6 0x00000064
+#define A_ds_Data7 0x0000006c
+#define A_ds_Data8 0x00000074
+#define A_ds_Data9 0x0000007c
+#define A_ds_Data10 0x00000084
+#define A_ds_Data11 0x0000008c
+#define A_ds_Data12 0x00000094
+#define A_ds_Data13 0x0000009c
+#define A_ds_Data14 0x000000a4
+#define A_ds_Data15 0x000000ac
+#define A_ds_Data16 0x000000b4
+#define A_ds_Data17 0x000000bc
+#define A_ok 0x0000ff00
+#define A_err1 0x0000ff01
+#define A_err2 0x0000ff02
+#define A_err3 0x0000ff03
+#define A_err4 0x0000ff04
+#define A_err5 0x0000ff05
+#define A_err6 0x0000ff06
+#define A_err7 0x0000ff07
+#define A_err8 0x0000ff08
+#define A_err9 0x0000ff09
+#define A_err10 0x0000ff0a
+#define Ent_scripts 0x00000000
+#define Ent_switch 0x00000008
+#define Ent_wait_reselect 0x00000120
+#define Ent_dataout 0x000001a8
+#define Ent_datain 0x000002b8
+
+unsigned long INSTRUCTIONS = 0x00000080;
+unsigned long PATCHES = 0x00000000;
diff --git a/sys/arch/mvme68k/dev/siop_script.ss b/sys/arch/mvme68k/dev/siop_script.ss
new file mode 100644
index 00000000000..f43c74bfe10
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siop_script.ss
@@ -0,0 +1,205 @@
+; $NetBSD: siop_script.ss,v 1.3 1995/08/18 15:28:11 chopps Exp $
+
+;
+; Copyright (c) 1995 Michael L. Hitch
+; 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 Michael L. Hitch.
+; 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.
+;
+
+; NCR 53c710 script
+;
+ABSOLUTE ds_Device = 0
+ABSOLUTE ds_MsgOut = ds_Device + 4
+ABSOLUTE ds_Cmd = ds_MsgOut + 8
+ABSOLUTE ds_Status = ds_Cmd + 8
+ABSOLUTE ds_Msg = ds_Status + 8
+ABSOLUTE ds_MsgIn = ds_Msg + 8
+ABSOLUTE ds_ExtMsg = ds_MsgIn + 8
+ABSOLUTE ds_SyncMsg = ds_ExtMsg + 8
+ABSOLUTE ds_Data1 = ds_SyncMsg + 8
+ABSOLUTE ds_Data2 = ds_Data1 + 8
+ABSOLUTE ds_Data3 = ds_Data2 + 8
+ABSOLUTE ds_Data4 = ds_Data3 + 8
+ABSOLUTE ds_Data5 = ds_Data4 + 8
+ABSOLUTE ds_Data6 = ds_Data5 + 8
+ABSOLUTE ds_Data7 = ds_Data6 + 8
+ABSOLUTE ds_Data8 = ds_Data7 + 8
+ABSOLUTE ds_Data9 = ds_Data8 + 8
+
+ABSOLUTE ok = 0xff00
+ABSOLUTE err1 = 0xff01
+ABSOLUTE err2 = 0xff02
+ABSOLUTE err3 = 0xff03
+ABSOLUTE err4 = 0xff04
+ABSOLUTE err5 = 0xff05
+ABSOLUTE err6 = 0xff06
+ABSOLUTE err7 = 0xff07
+ABSOLUTE err8 = 0xff08
+ABSOLUTE err9 = 0xff09
+ABSOLUTE err10 = 0xff0a
+
+ENTRY scripts
+ENTRY switch
+ENTRY wait_reselect
+ENTRY dataout
+ENTRY datain
+
+PROC scripts:
+
+scripts:
+
+ SELECT ATN FROM ds_Device, REL(reselect)
+;
+switch:
+ JUMP REL(msgin), WHEN MSG_IN
+ JUMP REL(msgout), IF MSG_OUT
+ JUMP REL(command_phase), IF CMD
+ JUMP REL(dataout), IF DATA_OUT
+ JUMP REL(datain), IF DATA_IN
+ JUMP REL(end), IF STATUS
+
+ INT err5 ; Unrecognized phase
+
+msgin:
+ MOVE FROM ds_MsgIn, WHEN MSG_IN
+ JUMP REL(ext_msg), IF 0x01 ; extended message
+ JUMP REL(disc), IF 0x04 ; disconnect message
+ JUMP REL(msg_sdp), IF 0x02 ; save data pointers
+ JUMP REL(msg_rej), IF 0x07 ; message reject
+ JUMP REL(msg_rdp), IF 0x03 ; restore data pointers
+ INT err6 ; unrecognized message
+
+msg_rdp:
+msg_rej:
+ CLEAR ACK
+ CLEAR ATN
+ JUMP REL(switch)
+
+ext_msg:
+ CLEAR ACK
+ MOVE FROM ds_ExtMsg, WHEN MSG_IN
+ JUMP REL(sync_msg), IF 0x03
+ int err7 ; extended message not SDTR
+
+sync_msg:
+ CLEAR ACK
+ MOVE FROM ds_SyncMsg, WHEN MSG_IN
+ CLEAR ACK
+ JUMP REL(switch)
+
+disc:
+ CLEAR ACK
+ WAIT DISCONNECT
+
+ int err2 ; signal disconnect w/o save DP
+
+msg_sdp:
+ CLEAR ACK ; acknowledge message
+ JUMP REL(switch), WHEN NOT MSG_IN
+ MOVE FROM ds_ExtMsg, WHEN MSG_IN
+ INT err8, IF NOT 0x04 ; interrupt if not disconnect
+ CLEAR ACK
+ WAIT DISCONNECT
+
+ INT err1 ; signal disconnect
+
+reselect:
+wait_reselect:
+ WAIT RESELECT REL(select_adr)
+ MOVE LCRC to SFBR ; Save reselect ID
+ MOVE SFBR to SCRATCH0
+
+ INT err9, WHEN NOT MSG_IN ; didn't get IDENTIFY
+ MOVE FROM ds_Msg, WHEN MSG_IN
+ INT err3 ; let host know about reconnect
+ CLEAR ACK ; acknowlege the message
+ JUMP REL(switch)
+
+
+select_adr:
+ MOVE SCNTL1 & 0x10 to SFBR ; get connected status
+ INT err4, IF 0x00 ; tell host if not connected
+ MOVE CTEST2 & 0x40 to SFBR ; clear Sig_P
+ JUMP REL(wait_reselect) ; and try reselect again
+
+msgout:
+ MOVE FROM ds_MsgOut, WHEN MSG_OUT
+ JUMP REL(switch)
+
+command_phase:
+ CLEAR ATN
+ MOVE FROM ds_Cmd, WHEN CMD
+ JUMP REL(switch)
+
+dataout:
+ MOVE FROM ds_Data1, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data2, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data3, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data4, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data5, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data6, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data7, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data8, WHEN DATA_OUT
+ CALL REL(switch), WHEN NOT DATA_OUT
+ MOVE FROM ds_Data9, WHEN DATA_OUT
+ CALL REL(switch)
+
+datain:
+ MOVE FROM ds_Data1, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data2, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data3, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data4, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data5, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data6, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data7, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data8, WHEN DATA_IN
+ CALL REL(switch), WHEN NOT DATA_IN
+ MOVE FROM ds_Data9, WHEN DATA_IN
+ CALL REL(switch)
+
+end:
+ MOVE FROM ds_Status, WHEN STATUS
+ int err10, WHEN NOT MSG_IN ; status not followed by msg
+ MOVE FROM ds_Msg, WHEN MSG_IN
+ CLEAR ACK
+ WAIT DISCONNECT
+ INT ok ; signal completion
+ JUMP REL(wait_reselect)
diff --git a/sys/arch/mvme68k/dev/siopdma.c b/sys/arch/mvme68k/dev/siopdma.c
new file mode 100644
index 00000000000..439c4a9d3ea
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopdma.c
@@ -0,0 +1,223 @@
+/* $NetBSD: afsc.c,v 1.6 1995/02/12 19:19:00 chopps Exp $ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1994 Michael L. Hitch
+ * Copyright (c) 1982, 1990 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.
+ *
+ * @(#)dma.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/siopreg.h>
+#include <mvme68k/dev/siopvar.h>
+
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+int afscmatch __P((struct device *, void *, void *));
+void afscattach __P((struct device *, struct device *, void *));
+
+int afscprint __P((void *auxp, char *));
+int siopintr __P((struct siop_softc *));
+int afsc_dmaintr __P((struct siop_softc *));
+
+struct scsi_adapter afsc_scsiswitch = {
+ siop_scsicmd,
+ siop_minphys,
+ 0, /* no lun support */
+ 0, /* no lun support */
+};
+
+struct scsi_device afsc_scsidev = {
+ NULL, /* use default error handler */
+ NULL, /* do not have a start function */
+ NULL, /* have no async handler */
+ NULL, /* Use default done routine */
+};
+
+struct cfdriver siopcd = {
+ NULL, "siop", afscmatch, afscattach,
+ DV_DULL, sizeof(struct siop_softc), NULL, 0 };
+
+int
+afscmatch(pdp, vcf, args)
+ struct device *pdp;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ return (!badvaddr(ca->ca_vaddr, 4));
+}
+
+void
+afscattach(parent, self, auxp)
+ struct device *parent, *self;
+ void *auxp;
+{
+ struct siop_softc *sc = (struct siop_softc *)self;
+ struct confargs *ca = auxp;
+ siop_regmap_p rp;
+ extern int cpuspeed;
+
+ sc->sc_siopp = rp = ca->ca_vaddr;
+
+ /*
+ * siop uses sc_clock_freq to define the dcntl & ctest7 reg values
+ * (was 0x0221, but i added SIOP_CTEST7_SC0 for snooping control)
+ * XXX does the clock frequency change for the 33MHz processors?
+ */
+ sc->sc_clock_freq = cpuspeed * 2;
+#ifdef MVME177
+ /* XXX this is a guess! */
+ if (cputyp == CPU_177)
+ sc->sc_clock_freq = cpuspeed;
+#endif
+ sc->sc_dcntl = SIOP_DCNTL_EA;
+/*X*/ if (sc->sc_clock_freq <= 25)
+/*X*/ sc->sc_dcntl |= (2 << 6);
+/*X*/ else if (sc->sc_clock_freq <= 37)
+/*X*/ sc->sc_dcntl |= (1 << 6);
+/*X*/ else if (sc->sc_clock_freq <= 50)
+/*X*/ sc->sc_dcntl |= (0 << 6);
+/*X*/ else
+/*X*/ sc->sc_dcntl |= (3 << 6);
+
+ sc->sc_ctest7 = SIOP_CTEST7_SNOOP | SIOP_CTEST7_TT1;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = 7; /* XXXX should ask ROM */
+ sc->sc_link.adapter = &afsc_scsiswitch;
+ sc->sc_link.device = &afsc_scsidev;
+ sc->sc_link.openings = 1;
+
+ sc->sc_ih.ih_fn = afsc_dmaintr;
+ sc->sc_ih.ih_arg = sc;
+ sc->sc_ih.ih_ipl = ca->ca_ipl;
+
+ siopinitialize(sc);
+
+ switch (ca->ca_bustype) {
+#if NMC > 0
+ case BUS_MC:
+ {
+ struct mcreg *mc = (struct mcreg *)ca->ca_master;
+
+ mcintr_establish(MCV_NCR, &sc->sc_ih);
+ mc->mc_ncrirq = ca->ca_ipl | MC_IRQ_IEN;
+ break;
+ }
+#endif
+#if NPCCTWO > 0
+ case BUS_PCCTWO:
+ {
+ struct pcctworeg *pcc2 = (struct pcctworeg *)ca->ca_master;
+
+ pcctwointr_establish(PCC2V_NCR, &sc->sc_ih);
+ pcc2->pcc2_ncrirq = ca->ca_ipl | PCC2_IRQ_IEN;
+ break;
+ }
+#endif
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
+
+ /*
+ * attach all scsi units on us
+ */
+ config_found(self, &sc->sc_link, afscprint);
+}
+
+/*
+ * print diag if pnp is NULL else just extra
+ */
+int
+afscprint(auxp, pnp)
+ void *auxp;
+ char *pnp;
+{
+ if (pnp == NULL)
+ return (UNCONF);
+ return (QUIET);
+}
+
+int
+afsc_dmaintr(sc)
+ struct siop_softc *sc;
+{
+ siop_regmap_p rp;
+ u_char istat;
+
+ rp = sc->sc_siopp;
+ istat = rp->siop_istat;
+ if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0)
+ return (0);
+ if ((rp->siop_sien | rp->siop_dien) == 0)
+ return (0); /* no interrupts enabled */
+
+ /*
+ * save interrupt status, DMA status, and SCSI status 0
+ * (may need to deal with stacked interrupts?)
+ */
+ sc->sc_istat = istat;
+ sc->sc_dstat = rp->siop_dstat;
+ sc->sc_sstat0 = rp->siop_sstat0;
+ siopintr(sc);
+ sc->sc_intrcnt.ev_count++;
+ return (1);
+}
+
+#ifdef DEBUG
+void
+afsc_dump()
+{
+ int i;
+
+ for (i = 0; i < afsccd.cd_ndevs; ++i)
+ if (afsccd.cd_devs[i])
+ siop_dump(afsccd.cd_devs[i]);
+}
+#endif
diff --git a/sys/arch/mvme68k/dev/siopreg.h b/sys/arch/mvme68k/dev/siopreg.h
new file mode 100644
index 00000000000..0fce258fbc5
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopreg.h
@@ -0,0 +1,336 @@
+/* $NetBSD: siopreg.h,v 1.7 1995/08/18 15:28:13 chopps Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)siopreg.h 7.3 (Berkeley) 2/5/91
+ */
+
+/*
+ * NCR 53C710 SCSI interface hardware description.
+ *
+ * From the Mach scsi driver for the 53C700
+ */
+
+typedef struct {
+/*00*/ volatile unsigned char siop_sien; /* rw: SCSI Interrupt Enable */
+/*01*/ volatile unsigned char siop_sdid; /* rw: SCSI Destination ID */
+/*02*/ volatile unsigned char siop_scntl1; /* rw: SCSI control reg 1 */
+/*03*/ volatile unsigned char siop_scntl0; /* rw: SCSI control reg 0 */
+/*04*/ volatile unsigned char siop_socl; /* rw: SCSI Output Control Latch */
+/*05*/ volatile unsigned char siop_sodl; /* rw: SCSI Output Data Latch */
+/*06*/ volatile unsigned char siop_sxfer; /* rw: SCSI Transfer reg */
+/*07*/ volatile unsigned char siop_scid; /* rw: SCSI Chip ID reg */
+/*08*/ volatile unsigned char siop_sbcl; /* ro: SCSI Bus Control Lines */
+/*09*/ volatile unsigned char siop_sbdl; /* ro: SCSI Bus Data Lines */
+/*0a*/ volatile unsigned char siop_sidl; /* ro: SCSI Input Data Latch */
+/*0b*/ volatile unsigned char siop_sfbr; /* ro: SCSI First Byte Received */
+/*0c*/ volatile unsigned char siop_sstat2; /* ro: SCSI status reg 2 */
+/*0d*/ volatile unsigned char siop_sstat1; /* ro: SCSI status reg 1 */
+/*0e*/ volatile unsigned char siop_sstat0; /* ro: SCSI status reg 0 */
+/*0f*/ volatile unsigned char siop_dstat; /* ro: DMA status */
+/*10*/ volatile unsigned long siop_dsa; /* rw: Data Structure Address */
+/*14*/ volatile unsigned char siop_ctest3; /* ro: Chip test register 3 */
+/*15*/ volatile unsigned char siop_ctest2; /* ro: Chip test register 2 */
+/*16*/ volatile unsigned char siop_ctest1; /* ro: Chip test register 1 */
+/*17*/ volatile unsigned char siop_ctest0; /* ro: Chip test register 0 */
+/*18*/ volatile unsigned char siop_ctest7; /* rw: Chip test register 7 */
+/*19*/ volatile unsigned char siop_ctest6; /* rw: Chip test register 6 */
+/*1a*/ volatile unsigned char siop_ctest5; /* rw: Chip test register 5 */
+/*1b*/ volatile unsigned char siop_ctest4; /* rw: Chip test register 4 */
+/*1c*/ volatile unsigned long siop_temp; /* rw: Temporary Stack reg */
+/*20*/ volatile unsigned char siop_lcrc; /* rw: LCRC value */
+/*21*/ volatile unsigned char siop_ctest8; /* rw: Chip test register 8 */
+/*22*/ volatile unsigned char siop_istat; /* rw: Interrupt Status reg */
+/*23*/ volatile unsigned char siop_dfifo; /* rw: DMA FIFO */
+/*24*/ volatile unsigned char siop_dcmd; /* rw: DMA Command Register */
+/*25*/ volatile unsigned char siop_dbc2; /* rw: DMA Byte Counter reg */
+/*26*/ volatile unsigned char siop_dbc1;
+/*27*/ volatile unsigned char siop_dbc0;
+/*28*/ volatile unsigned long siop_dnad; /* rw: DMA Next Address */
+/*2c*/ volatile unsigned long siop_dsp; /* rw: DMA SCRIPTS Pointer reg */
+/*30*/ volatile unsigned long siop_dsps; /* rw: DMA SCRIPTS Pointer Save reg */
+/*34*/ volatile unsigned long siop_scratch; /* rw: Scratch Register */
+/*38*/ volatile unsigned char siop_dcntl; /* rw: DMA Control reg */
+/*39*/ volatile unsigned char siop_dwt; /* rw: DMA Watchdog Timer */
+/*3a*/ volatile unsigned char siop_dien; /* rw: DMA Interrupt Enable */
+/*3b*/ volatile unsigned char siop_dmode; /* rw: DMA Mode reg */
+/*3c*/ volatile unsigned long siop_adder;
+
+} siop_regmap_t;
+typedef volatile siop_regmap_t *siop_regmap_p;
+
+/*
+ * Register defines
+ */
+
+/* Scsi control register 0 (scntl0) */
+
+#define SIOP_SCNTL0_ARB 0xc0 /* Arbitration mode */
+# define SIOP_ARB_SIMPLE 0x00
+# define SIOP_ARB_FULL 0xc0
+#define SIOP_SCNTL0_START 0x20 /* Start Sequence */
+#define SIOP_SCNTL0_WATN 0x10 /* (Select) With ATN */
+#define SIOP_SCNTL0_EPC 0x08 /* Enable Parity Checking */
+#define SIOP_SCNTL0_EPG 0x04 /* Enable Parity Generation */
+#define SIOP_SCNTL0_AAP 0x02 /* Assert ATN on Parity Error */
+#define SIOP_SCNTL0_TRG 0x01 /* Target Mode */
+
+/* Scsi control register 1 (scntl1) */
+
+#define SIOP_SCNTL1_EXC 0x80 /* Extra Clock Cycle of data setup */
+#define SIOP_SCNTL1_ADB 0x40 /* Assert Data Bus */
+#define SIOP_SCNTL1_ESR 0x20 /* Enable Selection/Reselection */
+#define SIOP_SCNTL1_CON 0x10 /* Connected */
+#define SIOP_SCNTL1_RST 0x08 /* Assert RST */
+#define SIOP_SCNTL1_AESP 0x04 /* Assert even SCSI parity */
+#define SIOP_SCNTL1_RES0 0x02 /* Reserved */
+#define SIOP_SCNTL1_RES1 0x01 /* Reserved */
+
+/* Scsi interrupt enable register (sien) */
+
+#define SIOP_SIEN_M_A 0x80 /* Phase Mismatch or ATN active */
+#define SIOP_SIEN_FCMP 0x40 /* Function Complete */
+#define SIOP_SIEN_STO 0x20 /* (Re)Selection timeout */
+#define SIOP_SIEN_SEL 0x10 /* (Re)Selected */
+#define SIOP_SIEN_SGE 0x08 /* SCSI Gross Error */
+#define SIOP_SIEN_UDC 0x04 /* Unexpected Disconnect */
+#define SIOP_SIEN_RST 0x02 /* RST asserted */
+#define SIOP_SIEN_PAR 0x01 /* Parity Error */
+
+/* Scsi chip ID (scid) */
+
+#define SIOP_SCID_VALUE(i) (1<<i)
+
+/* Scsi transfer register (sxfer) */
+
+#define SIOP_SXFER_DHP 0x80 /* Disable Halt on Parity error/ ATN asserted */
+#define SIOP_SXFER_TP 0x70 /* Synch Transfer Period */
+ /* see specs for formulas:
+ Period = TCP * (4 + XFERP )
+ TCP = 1 + CLK + 1..2;
+ */
+#define SIOP_SXFER_MO 0x0f /* Synch Max Offset */
+# define SIOP_MAX_OFFSET 8
+
+/* Scsi output data latch register (sodl) */
+
+/* Scsi output control latch register (socl) */
+
+#define SIOP_REQ 0x80 /* SCSI signal <x> asserted */
+#define SIOP_ACK 0x40
+#define SIOP_BSY 0x20
+#define SIOP_SEL 0x10
+#define SIOP_ATN 0x08
+#define SIOP_MSG 0x04
+#define SIOP_CD 0x02
+#define SIOP_IO 0x01
+
+#define SIOP_PHASE(socl) SCSI_PHASE(socl)
+
+/* Scsi first byte received register (sfbr) */
+
+/* Scsi input data latch register (sidl) */
+
+/* Scsi bus data lines register (sbdl) */
+
+/* Scsi bus control lines register (sbcl). Same as socl */
+
+/* DMA status register (dstat) */
+
+#define SIOP_DSTAT_DFE 0x80 /* DMA FIFO empty */
+#define SIOP_DSTAT_RES 0x40
+#define SIOP_DSTAT_BF 0x20 /* Bus fault */
+#define SIOP_DSTAT_ABRT 0x10 /* Aborted */
+#define SIOP_DSTAT_SSI 0x08 /* SCRIPT Single Step */
+#define SIOP_DSTAT_SIR 0x04 /* SCRIPT Interrupt Instruction */
+#define SIOP_DSTAT_WTD 0x02 /* Watchdog Timeout Detected */
+#define SIOP_DSTAT_IID 0x01 /* Invalid Instruction Detected */
+
+/* Scsi status register 0 (sstat0) */
+
+#define SIOP_SSTAT0_M_A 0x80 /* Phase Mismatch or ATN active */
+#define SIOP_SSTAT0_FCMP 0x40 /* Function Complete */
+#define SIOP_SSTAT0_STO 0x20 /* (Re)Selection timeout */
+#define SIOP_SSTAT0_SEL 0x10 /* (Re)Selected */
+#define SIOP_SSTAT0_SGE 0x08 /* SCSI Gross Error */
+#define SIOP_SSTAT0_UDC 0x04 /* Unexpected Disconnect */
+#define SIOP_SSTAT0_RST 0x02 /* RST asserted */
+#define SIOP_SSTAT0_PAR 0x01 /* Parity Error */
+
+/* Scsi status register 1 (sstat1) */
+
+#define SIOP_SSTAT1_ILF 0x80 /* Input latch (sidl) full */
+#define SIOP_SSTAT1_ORF 0x40 /* output reg (sodr) full */
+#define SIOP_SSTAT1_OLF 0x20 /* output latch (sodl) full */
+#define SIOP_SSTAT1_AIP 0x10 /* Arbitration in progress */
+#define SIOP_SSTAT1_LOA 0x08 /* Lost arbitration */
+#define SIOP_SSTAT1_WOA 0x04 /* Won arbitration */
+#define SIOP_SSTAT1_RST 0x02 /* SCSI RST current value */
+#define SIOP_SSTAT1_SDP 0x01 /* SCSI SDP current value */
+
+/* Scsi status register 2 (sstat2) */
+
+#define SIOP_SSTAT2_FF 0xf0 /* SCSI FIFO flags (bytecount) */
+# define SIOP_SCSI_FIFO_DEEP 8
+#define SIOP_SSTAT2_SDP 0x08 /* Latched (on REQ) SCSI SDP */
+#define SIOP_SSTAT2_MSG 0x04 /* Latched SCSI phase */
+#define SIOP_SSTAT2_CD 0x02
+#define SIOP_SSTAT2_IO 0x01
+
+/* Chip test register 0 (ctest0) */
+
+#define SIOP_CTEST0_RES0 0x80
+#define SIOP_CTEST0_BTD 0x40 /* Byte-to-byte Timer Disable */
+#define SIOP_CTEST0_GRP 0x20 /* Generate Receive Parity for Passthrough */
+#define SIOP_CTEST0_EAN 0x10 /* Enable Active Negation */
+#define SIOP_CTEST0_HSC 0x08 /* Halt SCSI clock */
+#define SIOP_CTEST0_ERF 0x04 /* Extend REQ/ACK Filtering */
+#define SIOP_CTEST0_RES1 0x02
+#define SIOP_CTEST0_DDIR 0x01 /* Xfer direction (1-> from SCSI bus) */
+
+/* Chip test register 1 (ctest1) */
+
+#define SIOP_CTEST1_FMT 0xf0 /* Byte empty in DMA FIFO bottom (high->byte3) */
+#define SIOP_CTEST1_FFL 0x0f /* Byte full in DMA FIFO top, same */
+
+/* Chip test register 2 (ctest2) */
+
+#define SIOP_CTEST2_RES 0x80
+#define SIOP_CTEST2_SIGP 0x40 /* Signal process */
+#define SIOP_CTEST2_SOFF 0x20 /* Synch Offset compare (1-> zero Init, max Tgt */
+#define SIOP_CTEST2_SFP 0x10 /* SCSI FIFO Parity */
+#define SIOP_CTEST2_DFP 0x08 /* DMA FIFO Parity */
+#define SIOP_CTEST2_TEOP 0x04 /* True EOP (a-la 5380) */
+#define SIOP_CTEST2_DREQ 0x02 /* DREQ status */
+#define SIOP_CTEST2_DACK 0x01 /* DACK status */
+
+/* Chip test register 3 (ctest3) read-only, top of SCSI FIFO */
+
+/* Chip test register 4 (ctest4) */
+
+#define SIOP_CTEST4_MUX 0x80 /* Host bus multiplex mode */
+#define SIOP_CTEST4_ZMOD 0x40 /* High-impedance outputs */
+#define SIOP_CTEST4_SZM 0x20 /* ditto, SCSI "outputs" */
+#define SIOP_CTEST4_SLBE 0x10 /* SCSI loobpack enable */
+#define SIOP_CTEST4_SFWR 0x08 /* SCSI FIFO write enable (from sodl) */
+#define SIOP_CTEST4_FBL 0x07 /* DMA FIFO Byte Lane select (from ctest6)
+ 4->0, .. 7->3 */
+
+/* Chip test register 5 (ctest5) */
+
+#define SIOP_CTEST5_ADCK 0x80 /* Clock Address Incrementor */
+#define SIOP_CTEST5_BBCK 0x40 /* Clock Byte counter */
+#define SIOP_CTEST5_ROFF 0x20 /* Reset SCSI offset */
+#define SIOP_CTEST5_MASR 0x10 /* Master set/reset pulses (of bits 3-0) */
+#define SIOP_CTEST5_DDIR 0x08 /* (re)set internal DMA direction */
+#define SIOP_CTEST5_EOP 0x04 /* (re)set internal EOP */
+#define SIOP_CTEST5_DREQ 0x02 /* (re)set internal REQ */
+#define SIOP_CTEST5_DACK 0x01 /* (re)set internal ACK */
+
+/* Chip test register 6 (ctest6) DMA FIFO access */
+
+/* Chip test register 7 (ctest7) */
+
+#define SIOP_CTEST7_CDIS 0x80 /* Cache burst disable */
+#define SIOP_CTEST7_SC1 0x40 /* Snoop control 1 */
+#define SIOP_CTEST7_SC0 0x20 /* Snoop contorl 0 */
+#define SIOP_CTEST7_INHIBIT (0 << 5)
+#define SIOP_CTEST7_SNOOP (1 << 5)
+#define SIOP_CTEST7_INVAL (2 << 5)
+#define SIOP_CTEST7_RESV (3 << 5)
+#define SIOP_CTEST7_STD 0x10 /* Selection timeout disable */
+#define SIOP_CTEST7_DFP 0x08 /* DMA FIFO parity bit */
+#define SIOP_CTEST7_EVP 0x04 /* Even parity (to host bus) */
+#define SIOP_CTEST7_TT1 0x02 /* Transfer type bit */
+#define SIOP_CTEST7_DIFF 0x01 /* Differential mode */
+
+/* DMA FIFO register (dfifo) */
+
+#define SIOP_DFIFO_RES 0x80
+#define SIOP_DFIFO_BO 0x7f /* FIFO byte offset counter */
+
+/* Interrupt status register (istat) */
+
+#define SIOP_ISTAT_ABRT 0x80 /* Abort operation */
+#define SIOP_ISTAT_RST 0x40 /* Software reset */
+#define SIOP_ISTAT_SIGP 0x20 /* Signal process */
+#define SIOP_ISTAT_RES 0x10
+#define SIOP_ISTAT_CON 0x08 /* Connected */
+#define SIOP_ISTAT_RES1 0x04
+#define SIOP_ISTAT_SIP 0x02 /* SCSI Interrupt pending */
+#define SIOP_ISTAT_DIP 0x01 /* DMA Interrupt pending */
+
+/* Chip test register 8 (ctest8)
+
+#define SIOP_CTEST8_V 0xf0 /* Chip revision level */
+#define SIOP_CTEST8_FLF 0x08 /* Flush DMA FIFO */
+#define SIOP_CTEST8_CLF 0x04 /* Clear DMA and SCSI FIFOs */
+#define SIOP_CTEST8_FM 0x02 /* Fetch pin mode */
+#define SIOP_CTEST8_SM 0x01 /* Snoop pins mode */
+
+/* DMA Mode register (dmode) */
+
+#define SIOP_DMODE_BL_MASK 0xc0 /* 0->1 1->2 2->4 3->8 */
+#define SIOP_DMODE_FC 0x30 /* Function code */
+#define SIOP_DMODE_PD 0x08 /* Program/data */
+#define SIOP_DMODE_FAM 0x04 /* Fixed address mode */
+#define SIOP_DMODE_U0 0x02 /* User programmable transfer type */
+#define SIOP_DMODE_MAN 0x01 /* Manual start mode */
+
+/* DMA interrupt enable register (dien) */
+
+#define SIOP_DIEN_RES 0xc0
+#define SIOP_DIEN_BF 0x20 /* On Bus Fault */
+#define SIOP_DIEN_ABRT 0x10 /* On Abort */
+#define SIOP_DIEN_SSI 0x08 /* On SCRIPTS sstep */
+#define SIOP_DIEN_SIR 0x04 /* On SCRIPTS intr instruction */
+#define SIOP_DIEN_WTD 0x02 /* On watchdog timeout */
+#define SIOP_DIEN_IID 0x01 /* On illegal instruction detected */
+
+/* DMA control register (dcntl) */
+
+#define SIOP_DCNTL_CF_MASK 0xc0 /* Clock frequency dividers:
+ 0 --> 37.51..50.00 Mhz, div=2
+ 1 --> 25.01..37.50 Mhz, div=1.5
+ 2 --> 16.67..25.00 Mhz, div=1
+ 3 --> 50.01..66.67 Mhz, div=3
+ */
+#define SIOP_DCNTL_EA 0x20 /* Enable ack */
+#define SIOP_DCNTL_SSM 0x10 /* Single step mode */
+#define SIOP_DCNTL_LLM 0x08 /* Enable SCSI Low-level mode */
+#define SIOP_DCNTL_STD 0x04 /* Start DMA operation */
+#define SIOP_DCNTL_FA 0x02 /* Fast arbitration */
+#define SIOP_DCNTL_COM 0x01 /* 53C700 compatibility */
diff --git a/sys/arch/mvme68k/dev/siopvar.h b/sys/arch/mvme68k/dev/siopvar.h
new file mode 100644
index 00000000000..af0b3c2fc22
--- /dev/null
+++ b/sys/arch/mvme68k/dev/siopvar.h
@@ -0,0 +1,201 @@
+/* $NetBSD: siopvar.h,v 1.11 1995/08/18 15:28:14 chopps Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)siopvar.h 7.1 (Berkeley) 5/8/90
+ */
+#ifndef _SIOPVAR_H_
+#define _SIOPVAR_H_
+
+/*
+ * The largest single request will be MAXPHYS bytes which will require
+ * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
+ * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
+ * buffer is not page aligned (+1).
+ */
+#define DMAMAXIO (MAXPHYS/NBPG+1)
+
+/*
+ * Data Structure for SCRIPTS program
+ */
+struct siop_ds {
+/*00*/ long scsi_addr; /* SCSI ID & sync */
+/*04*/ long idlen; /* Identify message */
+/*08*/ char *idbuf;
+/*0c*/ long cmdlen; /* SCSI command */
+/*10*/ char *cmdbuf;
+/*14*/ long stslen; /* Status */
+/*18*/ char *stsbuf;
+/*1c*/ long msglen; /* Message */
+/*20*/ char *msgbuf;
+/*24*/ long msginlen; /* Message in */
+/*28*/ char *msginbuf;
+/*2c*/ long extmsglen; /* Extended message in */
+/*30*/ char *extmsgbuf;
+/*34*/ long synmsglen; /* Sync transfer request */
+/*38*/ char *synmsgbuf;
+ struct {
+/*3c*/ long datalen;
+/*40*/ char *databuf;
+ } chain[DMAMAXIO];
+};
+
+/*
+ * ACB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basicly, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
+ */
+struct siop_acb {
+/*00*/ TAILQ_ENTRY(siop_acb) chain;
+/*08*/ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+/*0c*/ int flags; /* Status */
+#define ACB_FREE 0x00
+#define ACB_ACTIVE 0x01
+#define ACB_DONE 0x04
+#define ACB_CHKSENSE 0x08
+/*10*/ struct scsi_generic cmd; /* SCSI command block */
+/*1c*/ struct siop_ds ds;
+/*a0*/ void *iob_buf;
+/*a4*/ u_long iob_curbuf;
+/*a8*/ u_long iob_len, iob_curlen;
+/*b0*/ u_char msgout[6];
+/*b6*/ u_char msg[6];
+/*bc*/ u_char stat[1];
+/*bd*/ u_char status;
+/*be*/ u_char dummy[2];
+/*c0*/ int clen;
+/*c4*/ char *daddr; /* Saved data pointer */
+/*c8*/ int dleft; /* Residue */
+};
+
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
+ * this for now. Is there a way to reliably hook it up to sc->fordriver??
+ */
+struct siop_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
+
+struct siop_softc {
+ struct device sc_dev;
+ struct intrhand sc_ih;
+ struct evcnt sc_intrcnt;
+
+ u_char sc_istat;
+ u_char sc_dstat;
+ u_char sc_sstat0;
+ u_char sc_sstat1;
+ u_long sc_intcode;
+ struct scsi_link sc_link; /* proto for sub devices */
+ u_long sc_scriptspa; /* physical address of scripts */
+ siop_regmap_p sc_siopp; /* the SIOP */
+ u_long sc_active; /* number of active I/O's */
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, siop_acb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct siop_acb *sc_nexus; /* current command */
+ struct siop_acb sc_acb[8]; /* the real command blocks */
+ struct siop_tinfo sc_tinfo[8];
+
+ u_short sc_clock_freq;
+ u_char sc_dcntl;
+ u_char sc_ctest7;
+ u_short sc_tcp[4];
+ u_char sc_flags;
+ u_char sc_sien;
+ u_char sc_dien;
+ u_char sc_minsync;
+ /* one for each target */
+ struct syncpar {
+ u_char state;
+ u_char sxfer;
+ u_char sbcl;
+ } sc_sync[8];
+};
+
+/* sc_flags */
+#define SIOP_INTSOFF 0x80 /* Interrupts turned off */
+#define SIOP_INTDEFER 0x40 /* Level 6 interrupt has been deferred */
+#define SIOP_ALIVE 0x01 /* controller initialized */
+#define SIOP_SELECTED 0x04 /* bus is in selected state. Needed for
+ correct abort procedure. */
+
+/* sync states */
+#define SYNC_START 0 /* no sync handshake started */
+#define SYNC_SENT 1 /* we sent sync request, no answer yet */
+#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
+ or it rejected the request and we stay async */
+
+#define MSG_CMD_COMPLETE 0x00
+#define MSG_EXT_MESSAGE 0x01
+#define MSG_SAVE_DATA_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INIT_DETECT_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_BUS_DEVICE_RESET 0x0C
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
+#define MSG_SYNC_REQ 0x01
+
+#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define STS_BUSY 0x08
+#define STS_INTERMED 0x10 /* Intermediate status sent */
+#define STS_EXT 0x80 /* Extended status valid */
+
+void siop_minphys __P((struct buf *bp));
+int siop_scsicmd __P((struct scsi_xfer *));
+
+#endif /* _SIOPVAR_H */
diff --git a/sys/arch/mvme68k/dev/sram.c b/sys/arch/mvme68k/dev/sram.c
new file mode 100644
index 00000000000..77299175e89
--- /dev/null
+++ b/sys/arch/mvme68k/dev/sram.c
@@ -0,0 +1,231 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/mioctl.h>
+
+#include "mc.h"
+
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+
+#include <vm/vm.h>
+
+struct sramsoftc {
+ struct device sc_dev;
+ caddr_t sc_paddr;
+ caddr_t sc_vaddr;
+ int sc_len;
+};
+
+void sramattach __P((struct device *, struct device *, void *));
+int srammatch __P((struct device *, void *, void *));
+
+struct cfdriver sramcd = {
+ NULL, "sram", srammatch, sramattach,
+ DV_DULL, sizeof(struct sramsoftc), 0
+};
+
+int
+srammatch(parent, vcf, args)
+ struct device *parent;
+ void *vcf, *args;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = args;
+
+ if (cputyp == CPU_147)
+ return (0);
+ if (ca->ca_vaddr == (caddr_t)-1)
+ return (!badpaddr(ca->ca_paddr, 1));
+ return (!badvaddr(ca->ca_vaddr, 1));
+}
+
+void
+sramattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct confargs *ca = args;
+ struct sramsoftc *sc = (struct sramsoftc *)self;
+ struct mcreg *mc;
+ int i;
+
+ switch (cputyp) {
+#ifdef MVME162
+ case CPU_162:
+ /* XXX this code will almost never be used. just in case. */
+ mc = sys_mc;
+ if (!mc)
+ mc = (struct mcreg *)(IIOV(0xfff00000) + MC_MCCHIP_OFF);
+
+ switch (mc->mc_memoptions & MC_MEMOPTIONS_SRAMMASK) {
+ case MC_MEMOPTIONS_SRAM128K:
+ sc->sc_len = 128*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM512K:
+ sc->sc_len = 512*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM1M:
+ sc->sc_len = 1024*1024;
+ break;
+ case MC_MEMOPTIONS_SRAM2M:
+ sc->sc_len = 2048*1024;
+ break;
+ }
+ break;
+#endif
+#ifdef MVME167
+ case CPU_167:
+ case CPU_166:
+ sc->sc_len = 128*1024; /* always 128K */
+ break;
+#endif
+#ifdef MVME177
+ case CPU_177:
+ XXX
+ break;
+#endif
+ default:
+ sc->sc_len = 0;
+ break;
+ }
+
+ printf(": len %d", sc->sc_len);
+
+ sc->sc_paddr = ca->ca_paddr;
+ sc->sc_vaddr = mapiodev((caddr_t)sc->sc_paddr, sc->sc_len);
+ if (sc->sc_vaddr == NULL) {
+ sc->sc_len = 0;
+ printf(" -- failed to map");
+ }
+ printf("\n");
+}
+
+/*ARGSUSED*/
+int
+sramopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= sramcd.cd_ndevs ||
+ sramcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+sramclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+sramioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ case MIOCGSIZ:
+ *(int *)data = sc->sc_len;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sramread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+/*ARGSUSED*/
+int
+sramwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ return (memdevrw(sc->sc_vaddr, sc->sc_len, uio, flags));
+}
+
+int
+srammmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct sramsoftc *sc = (struct sramsoftc *) sramcd.cd_devs[unit];
+
+ if (minor(dev) != 0)
+ return (-1);
+
+ /* allow access only in RAM */
+ if (off > sc->sc_len)
+ return (-1);
+ return (m68k_btop(sc->sc_paddr + off));
+}
diff --git a/sys/arch/mvme68k/dev/vme.c b/sys/arch/mvme68k/dev/vme.c
new file mode 100644
index 00000000000..ddd4099dd63
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vme.c
@@ -0,0 +1,557 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/callout.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+#include "pcc.h"
+#include "mc.h"
+#include "pcctwo.h"
+
+#if NPCC > 0
+#include <mvme68k/dev/pccreg.h>
+#endif
+#if NMC > 0
+#include <mvme68k/dev/mcreg.h>
+#endif
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+int vmematch __P((struct device *, void *, void *));
+void vmeattach __P((struct device *, struct device *, void *));
+
+int vme1chip_init __P((struct vmesoftc *sc));
+int vme2chip_init __P((struct vmesoftc *sc));
+u_long vme2chip_map __P((u_long base, int len, int dwidth));
+int vme2abort __P((struct frame *frame));
+
+static int vmebustype;
+
+struct cfdriver vmecd = {
+ NULL, "vme", vmematch, vmeattach,
+ DV_DULL, sizeof(struct vmesoftc), 0
+};
+
+int
+vmematch(parent, cf, args)
+ struct device *parent;
+ void *cf;
+ void *args;
+{
+ struct confargs *ca = args;
+
+#if NMC > 0
+ if (ca->ca_bustype == BUS_MC) {
+ struct mcreg *mc = (struct mcreg *)ca->ca_master;
+
+ if (mc->mc_ver & MC_VER_NOVME)
+ return (0);
+ }
+#endif
+ return (1);
+}
+
+/*
+ * Returns a physical address mapping for a VME address & length.
+ * Note: on some hardware it is not possible to create certain
+ * mappings, ie. the MVME147 cannot do 32 bit accesses to VME bus
+ * addresses from 0 to physmem.
+ */
+caddr_t
+vmepmap(sc, vmeaddr, len, bustype)
+ struct vmesoftc *sc;
+ caddr_t vmeaddr;
+ int len;
+ int bustype;
+{
+ u_long base = (u_long)vmeaddr;
+
+ len = roundup(len, NBPG);
+ switch (vmebustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ switch (bustype) {
+ case BUS_VMES:
+ if (base > VME1_A16BASE &&
+ (base+len - VME1_A16BASE) < VME1_A16D16LEN)
+ base = base - VME1_A16BASE + VME1_A16D16BASE;
+ else if (base+len < VME1_A32D16LEN)
+ base = base + VME1_A32D16BASE;
+ else {
+ printf("%s: cannot map pa %x len %x\n",
+ sc->sc_dev.dv_xname, base, len);
+ return (NULL);
+ }
+ break;
+ case BUS_VMEL:
+ if (base >= physmem && (base+len) < VME1_A32D32LEN)
+ base = base + VME1_A32D32BASE;
+ else if (base+len < VME1_A32D16LEN) /* HACK! */
+ base = base + VME1_A32D16BASE;
+ else {
+ printf("%s: cannot map pa %x len %x\n",
+ sc->sc_dev.dv_xname, base, len);
+ return (NULL);
+ }
+ break;
+ }
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ switch (bustype) {
+ case BUS_VMES:
+ if (base > VME2_A16BASE &&
+ (base+len-VME2_A16BASE) < VME2_A16D16LEN)
+ base = base - VME2_A16BASE + VME2_A16D16BASE;
+ else if (base > VME2_A24BASE &&
+ (base+len-VME2_A24BASE) < VME2_A24D16LEN)
+ base = base - VME2_A24BASE + VME2_A24D16BASE;
+ else if ((base+len) < VME2_A32D16LEN)
+ base = base + VME2_A32D16BASE;
+ else {
+ base = vme2chip_map(base, len, 16);
+ if (base == NULL)
+ return (NULL);
+ }
+ break;
+ case BUS_VMEL:
+#if 0
+ if (base > VME2_A16BASE &&
+ (base+len-VME2_A16BASE) < VME2_A16D32LEN)
+ base = base - VME2_A16BASE + VME2_A16D32BASE;
+#endif
+ base = vme2chip_map(base, len, 32);
+ if (base == NULL)
+ return (NULL);
+ break;
+ }
+ break;
+#endif
+ }
+ return ((caddr_t)base);
+}
+
+/* if successful, returns the va of a vme bus mapping */
+caddr_t
+vmemap(sc, vmeaddr, len, bustype)
+ struct vmesoftc *sc;
+ caddr_t vmeaddr;
+ int len;
+ int bustype;
+{
+ caddr_t pa, va;
+
+ pa = vmepmap(sc, pa, len, bustype);
+ if (pa == NULL)
+ return (NULL);
+ va = mapiodev(pa, len);
+ return (va);
+}
+
+void
+vmeunmap(va, len)
+ caddr_t va;
+ int len;
+{
+ unmapiodev(va, len);
+}
+
+int
+vmerw(sc, uio, flags, bus)
+ struct vmesoftc *sc;
+ struct uio *uio;
+ int flags;
+ int bus;
+{
+ register vm_offset_t o, v;
+ register int c;
+ register struct iovec *iov;
+ caddr_t vme;
+ int error = 0;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("vmerw");
+ continue;
+ }
+
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if ((v & PGOFSET) + c > NBPG) /* max NBPG at a time */
+ c = NBPG - (v & PGOFSET);
+ if (c == 0)
+ return (0);
+ vme = vmemap(sc, (caddr_t)(v & ~PGOFSET),
+ NBPG, BUS_VMES);
+ if (vme == NULL) {
+ error = EFAULT; /* XXX? */
+ continue;
+ }
+ error = uiomove((caddr_t)vme + (v & PGOFSET), c, uio);
+ vmeunmap(vme, NBPG);
+ }
+ return (error);
+}
+
+int
+vmeprint(args, bus)
+ void *args;
+ char *bus;
+{
+ struct confargs *ca = args;
+
+ printf(" offset 0x%x", ca->ca_offset);
+ if (ca->ca_vec > 0)
+ printf(" vec %d", ca->ca_vec);
+ if (ca->ca_ipl > 0)
+ printf(" ipl %d", ca->ca_ipl);
+ return (UNCONF);
+}
+
+int
+vmescan(parent, child, args, bustype)
+ struct device *parent;
+ void *child, *args;
+ int bustype;
+{
+ struct cfdata *cf = child;
+ struct vmesoftc *sc = (struct vmesoftc *)parent;
+ struct confargs *ca = args;
+ struct confargs oca;
+
+ if (parent->dv_cfdata->cf_driver->cd_indirect) {
+ printf(" indirect devices not supported\n");
+ return 0;
+ }
+
+ bzero(&oca, sizeof oca);
+ oca.ca_bustype = bustype;
+ oca.ca_paddr = (void *)cf->cf_loc[0];
+ oca.ca_len = cf->cf_loc[1];
+ oca.ca_vec = cf->cf_loc[2];
+ oca.ca_ipl = cf->cf_loc[3];
+ if (oca.ca_ipl > 0 && oca.ca_vec == -1)
+ oca.ca_vec = intr_freevec();
+
+ oca.ca_offset = (int)oca.ca_paddr;
+ oca.ca_vaddr = (void *)vmemap(sc, oca.ca_paddr, oca.ca_len,
+ oca.ca_bustype);
+ if (!oca.ca_vaddr)
+ oca.ca_vaddr = (void *)-1;
+ oca.ca_master = (void *)sc;
+ oca.ca_name = cf->cf_driver->cd_name;
+ if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) {
+ if (oca.ca_vaddr != (void *)-1)
+ vmeunmap(oca.ca_vaddr, oca.ca_len);
+ return (0);
+ }
+ config_attach(parent, cf, &oca, vmeprint);
+ return (1);
+}
+
+void
+vmeattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmesoftc *sc = (struct vmesoftc *)self;
+ struct confargs *ca = args;
+ struct vme1reg *vme1;
+ struct vme2reg *vme2;
+ int scon;
+
+ sc->sc_vaddr = ca->ca_vaddr;
+
+ vmebustype = ca->ca_bustype;
+ switch (ca->ca_bustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ vme1 = (struct vme1reg *)sc->sc_vaddr;
+ scon = (vme1->vme1_scon & VME1_SCON_SWITCH);
+ printf(": %sscon\n", scon ? "" : "not ");
+ vme1chip_init(sc);
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ vme2 = (struct vme2reg *)sc->sc_vaddr;
+ scon = (vme2->vme2_tctl & VME2_TCTL_SCON);
+ printf(": %sscon\n", scon ? "" : "not ");
+ vme2chip_init(sc);
+ break;
+#endif
+ }
+
+ while (config_found(self, NULL, NULL))
+ ;
+}
+
+/*
+ * On the VMEbus, only one cpu may be configured to respond to any
+ * particular vme ipl. Therefore, it wouldn't make sense to globally
+ * enable all the interrupts all the time -- it would not be possible
+ * to put two cpu's and one vme card into a single cage. Rather, we
+ * enable each vme interrupt only when we are attaching a device that
+ * uses it. This makes it easier (though not trivial) to put two cpu
+ * cards in one VME cage, and both can have some limited access to vme
+ * interrupts (just can't share the same irq).
+ * Obviously no check is made to see if another cpu is using that
+ * interrupt. If you share you will lose.
+ */
+int
+vmeintr_establish(vec, ih)
+ int vec;
+ struct intrhand *ih;
+{
+ struct vmesoftc *sc = (struct vmesoftc *) vmecd.cd_devs[0];
+#if NPCC > 0
+ struct vme1reg *vme1;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ struct vme2reg *vme2;
+#endif
+ int x;
+
+ x = (intr_establish(vec, ih));
+
+ switch (vmebustype) {
+#if NPCC > 0
+ case BUS_PCC:
+ vme1 = (struct vme1reg *)sc->sc_vaddr;
+ vme1->vme1_irqen = vme1->vme1_irqen |
+ VME1_IRQ_VME(ih->ih_ipl);
+ break;
+#endif
+#if NMC > 0 || NPCCTWO > 0
+ case BUS_MC:
+ case BUS_PCCTWO:
+ vme2 = (struct vme2reg *)sc->sc_vaddr;
+ vme2->vme2_irqen = vme2->vme2_irqen |
+ VME2_IRQ_VME(ih->ih_ipl);
+ break;
+#endif
+ }
+ return (x);
+}
+
+#if defined(MVME147)
+int
+vme1chip_init(sc)
+ struct vmesoftc *sc;
+{
+ struct vme1reg *vme1 = (struct vme1reg *)sc->sc_vaddr;
+
+ vme1->vme1_scon &= ~VME1_SCON_SYSFAIL; /* XXX doesn't work */
+}
+#endif
+
+#if defined(MVME162) || defined(MVME167) || defined(MVME177)
+
+/*
+ * make local addresses 1G-2G correspond to VME addresses 3G-4G,
+ * as D32
+ */
+#define VME2_D32STARTPHYS (1*1024*1024*1024UL)
+#define VME2_D32ENDPHYS (2*1024*1024*1024UL)
+#define VME2_D32STARTVME (3*1024*1024*1024UL)
+#define VME2_D32BITSVME (3*1024*1024*1024UL)
+
+/*
+ * make local addresses 3G-3.75G correspond to VME addresses 3G-3.75G,
+ * as D16
+ */
+#define VME2_D16STARTPHYS (3*1024*1024*1024UL)
+#define VME2_D16ENDPHYS (3*1024*1024*1024UL + 768*1024*1024UL)
+
+/*
+ * XXX what AM bits should be used for the D32/D16 mappings?
+ */
+int
+vme2chip_init(sc)
+ struct vmesoftc *sc;
+{
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
+ u_long ctl;
+
+ /* turn off SYSFAIL LED */
+ vme2->vme2_tctl &= ~VME2_TCTL_SYSFAIL;
+
+ ctl = vme2->vme2_masterctl;
+
+#if 0
+ /* unused decoders 1 & 2 */
+ printf("%s: phys 0x%08x-0x%08x to VMExxx 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000,
+ vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000);
+ printf("%s: phys 0x%08x-0x%08x to VMExxx 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000,
+ vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000);
+#endif
+
+ /* setup a D16 space */
+ vme2->vme2_master3 = ((VME2_D16ENDPHYS-1) & 0xffff0000) |
+ (VME2_D16STARTPHYS >> 16);
+ ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_3SHIFT);
+ ctl |= (VME2_MASTERCTL_AM32SP | VME2_MASTERCTL_D16) <<
+ VME2_MASTERCTL_3SHIFT;
+#if 0
+ printf("%s: phys 0x%08x-0x%08x to VMED16 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ VME2_D16STARTPHYS, VME2_D16ENDPHYS-1,
+ VME2_D16STARTPHYS, VME2_D16ENDPHYS-1);
+#endif
+
+ /* setup a D32 space */
+ vme2->vme2_master4 = ((VME2_D32ENDPHYS-1) & 0xffff0000) |
+ (VME2_D32STARTPHYS >> 16);
+ vme2->vme2_master4mod = (VME2_D32STARTVME & 0xffff0000) |
+ (VME2_D32BITSVME >> 16);
+ ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_4SHIFT);
+ ctl |= (VME2_MASTERCTL_AM32SP) <<
+ VME2_MASTERCTL_4SHIFT;
+#if 0
+ printf("%s: phys 0x%08x-0x%08x to VMED32 0x%08x-0x%08x\n",
+ sc->sc_dev.dv_xname,
+ VME2_D32STARTPHYS, VME2_D32ENDPHYS-1,
+ VME2_D32STARTVME, VME2_D32STARTVME | ~VME2_D32BITSVME);
+#endif
+
+ vme2->vme2_masterctl = ctl;
+
+ ctl = vme2->vme2_gcsrctl;
+
+ /* enable A16 short IO map decoder (0xffffxxxx) */
+ ctl &= ~(VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1WP |
+ VME2_GCSRCTL_I1SU);
+ ctl |= VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1SU;
+
+ /* enable A24D16 (0xf0xxxxxx) and A32D16 (0xf[1-e]xxxxxx) decoders */
+ ctl &= ~(VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2WP | VME2_GCSRCTL_I2SU |
+ VME2_GCSRCTL_I2PD);
+ ctl |= VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2SU | VME2_GCSRCTL_I2PD;
+
+ /* map decoders 3 & 4 which were just configured */
+ ctl &= ~(VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3 | VME2_GCSRCTL_MDEN1 |
+ VME2_GCSRCTL_MDEN2);
+ ctl |= VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3;
+
+ vme2->vme2_gcsrctl = ctl;
+
+ /*
+ * Map the VME irq levels to the cpu levels 1:1.
+ * This is rather inflexible, but much easier.
+ */
+ vme2->vme2_irql4 = (7 << VME2_IRQL4_VME7SHIFT) |
+ (6 << VME2_IRQL4_VME6SHIFT) | (5 << VME2_IRQL4_VME5SHIFT) |
+ (4 << VME2_IRQL4_VME4SHIFT) | (3 << VME2_IRQL4_VME3SHIFT) |
+ (2 << VME2_IRQL4_VME2SHIFT) | (1 << VME2_IRQL4_VME1SHIFT);
+
+#if NPCCTWO > 0
+ if (vmebustype == BUS_PCCTWO) {
+ sc->sc_abih.ih_fn = vme2abort;
+ sc->sc_abih.ih_arg = 0;
+ sc->sc_abih.ih_ipl = 7;
+ sc->sc_abih.ih_wantframe = 1;
+
+ intr_establish(110, &sc->sc_abih); /* XXX 110 */
+ vme2->vme2_irqen |= VME2_IRQ_AB;
+ }
+#endif
+}
+
+/*
+ * A32 accesses on the MVME1[67]x require setting up mappings in
+ * the VME2 chip.
+ * XXX VME address must be between 2G and 4G
+ * XXX We only support D32 at the moment..
+ */
+u_long
+vme2chip_map(base, len, dwidth)
+ u_long base;
+ int len, dwidth;
+{
+ switch (dwidth) {
+ case 16:
+ if (base < VME2_D16STARTPHYS ||
+ base + (u_long)len > VME2_D16ENDPHYS)
+ return (NULL);
+ return (base);
+ case 32:
+ if (base < VME2_D32STARTVME)
+ return (NULL);
+ return (base - VME2_D32STARTVME + VME2_D32STARTPHYS);
+ }
+}
+
+#if NPCCTWO > 0
+int
+vme2abort(frame)
+ struct frame *frame;
+{
+ struct vmesoftc *sc = (struct vmesoftc *)vmecd.cd_devs[0];
+ struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
+
+ if (vme2->vme2_irqstat & VME2_IRQ_AB == 0) {
+ printf("%s: vme2chip irq not set\n", sc->sc_dev.dv_xname);
+ return (0);
+ }
+ vme2->vme2_irqclr = VME2_IRQ_AB;
+ nmihand(frame);
+ return (1);
+}
+#endif
+
+#endif
diff --git a/sys/arch/mvme68k/dev/vme.h b/sys/arch/mvme68k/dev/vme.h
new file mode 100644
index 00000000000..b49918247aa
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vme.h
@@ -0,0 +1,325 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct vmesoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ struct intrhand sc_abih; /* `abort' switch */
+};
+
+/*
+ * MVME147 vme configuration registers.
+*/
+struct vme1reg {
+/*01*/ volatile u_short vme1_scon;
+#define VME1_SCON_SWITCH 0x01 /* SCON jumper is set */
+#define VME1_SCON_SRESET 0x02 /* assert SRESET on bus */
+#define VME1_SCON_SYSFAIL 0x04 /* assert SYSFAIL on bus */
+#define VME1_SCON_ROBIN 0x08 /* round robin bus requests */
+/*03*/ volatile u_short vme1_reqconf;
+#define VME1_REQ_IPLMASK 0x03 /* interrupt level for requester */
+#define VME1_REQ_RNEVER 0x08
+#define VME1_REQ_RWD 0x10
+#define VME1_REQ_DHB 0x40
+#define VME1_REQ_DWB 0x80
+/*05*/ volatile u_short vme1_masconf;
+#define VME1_MAS_D16 0x01 /* force d8/16 accesses only */
+#define VME1_MAS_MASA24 0x02 /* send address mod for A24 access */
+#define VME1_MAS_MASA16 0x04 /* send address mod for A16 access */
+#define VME1_MAS_MASUAT 0x08 /* handle unaligned VME cycles */
+#define VME1_MAS_CFILL 0x10 /* DO NOT USE */
+#define VME1_MAS_MASWP 0x20 /* VME fast mode (DO NOT USE) */
+/*07*/ volatile u_short vme1_slconf;
+#define VME1_SLAVE_SLVD16 0x01 /* DO NOT USE */
+#define VME1_SLAVE_SLVWP 0x20 /* DO NOT USE */
+#define VME1_SLAVE_SLVEN 0x80 /* allow access to onboard DRAM */
+/*09*/ volatile u_short vme1_timerconf;
+#define VME1_TIMER_LOCAL_MASK 0x03
+#define VME1_TIMER_LOCAL_T0 0x00 /* local timeout 102 microsec */
+#define VME1_TIMER_LOCAL_T1 0x01 /* local timeout 205 microsec */
+#define VME1_TIMER_LOCAL_T2 0x02 /* local timeout 410 microsec */
+#define VME1_TIMER_LOCAL_T3 0x03 /* local timeout disabled */
+#define VME1_TIMER_VMEACC_MASK 0x0c
+#define VME1_TIMER_VMEACC_T0 0x00 /* VME access timeout 102 microsec */
+#define VME1_TIMER_VMEACC_T1 0x04 /* VME access timeout 1.6 millisec */
+#define VME1_TIMER_VMEACC_T2 0x08 /* VME access timeout 51 millisec */
+#define VME1_TIMER_VMEACC_T3 0x0c /* VME access timeout disabled */
+#define VME1_TIMER_VMEGLO_MASK 0x30
+#define VME1_TIMER_VMEGLO_T0 0x00 /* VME glob timeout 102 microsec */
+#define VME1_TIMER_VMEGLO_T1 0x10 /* VME glob timeout 205 microsec */
+#define VME1_TIMER_VMEGLO_T2 0x20 /* VME glob timeout 410 microsec */
+#define VME1_TIMER_VMEGLO_T3 0x30 /* VME glob timeout disabled */
+#define VME1_TIMER_ARBTO 0x40 /* enable VME arbitration timer */
+/*0b*/ volatile u_short vme1_sladdrmod;
+#define VME1_SLMOD_DATA 0x01
+#define VME1_SLMOD_PRGRM 0x02
+#define VME1_SLMOD_BLOCK 0x04
+#define VME1_SLMOD_SHORT 0x08
+#define VME1_SLMOD_STND 0x10
+#define VME1_SLMOD_EXTED 0x20
+#define VME1_SLMOD_USER 0x40
+#define VME1_SLMOD_SUPER 0x80
+/*0d*/ volatile u_short vme1_msaddrmod;
+#define VME1_MSMOD_AM_MASK 0x3f
+#define VME1_MSMOD_AMSEL 0x80
+/*0f*/ volatile u_short vme1_irqen;
+#define VME1_IRQ_VME(x) (1 << (x))
+/*11*/ volatile u_short vme1_uirqen;
+/*13*/ volatile u_short vme1_uirq;
+/*15*/ volatile u_short vme1_irq;
+/*17*/ volatile u_short vme1_vmeid;
+/*19*/ volatile u_short vme1_buserr;
+/*1b*/ volatile u_short vme1_gcsr;
+#define VME1_GCSR_OFF 0x0f
+/*1d*/ u_short :16;
+/*1f*/ u_short :16;
+/*21*/ volatile u_short vme1_gcsr_gr0;
+/*23*/ volatile u_short vme1_gcsr_gr1;
+/*25*/ volatile u_short vme1_gcsr_boardid;
+/*27*/ volatile u_short vme1_gcsr_gpr0;
+/*29*/ volatile u_short vme1_gcsr_gpr1;
+/*2b*/ volatile u_short vme1_gcsr_gpr2;
+/*2d*/ volatile u_short vme1_gcsr_gpr3;
+/*2f*/ volatile u_short vme1_gcsr_gpr4;
+};
+
+/*
+ * Basic VME memory layout for the MVME147 follows:
+ * - A32D32 accesses occur at memsize-0xefffffff. This makes it
+ * impossible to do A32D32 accesses before the end of your onboard
+ * memory. If you want to do low address A24D32 accesses, and you
+ * have 16M or more onboard memory you'll find you cannot.
+ * - A32D16 accesses can occur at 0xf0000000-0xff7fffff.
+ * - A16D16 accesses can occur at 0xffff0000-0xffffffff.
+ */
+#define VME1_A32D32BASE 0x00000000UL
+#define VME1_A32D32LEN 0xf0000000UL
+#define VME1_A32D16BASE 0xf0000000UL
+#define VME1_A32D16LEN 0x0f800000UL
+#define VME1_A16D16BASE 0xffff0000UL
+#define VME1_A16D16LEN 0x00010000UL
+#define VME1_A16BASE 0xffff0000UL
+
+/*
+ * XXX: this chip has some rather inane access rules!
+ */
+struct vme2reg {
+/*00*/ volatile u_long vme2_slaveaddr1;
+/*04*/ volatile u_long vme2_slaveaddr2;
+#define VME2_SADDR_END 0xffff0000 /* VME address END & START */
+#define VME2_SADDR_START 0x0000ffff
+/*08*/ volatile u_long vme2_slavelmod1;
+/*0c*/ volatile u_long vme2_slavelmod2;
+#define VME2_SADDR_LADDR 0xffff0000 /* local base address */
+#define VME2_SADDR_SIZE(mem) (0x1000 - (mem) >> 16) /* encoding of size */
+/*10*/ volatile u_long vme2_slavectl;
+#define VME2_SLAVE_CHOOSE(bits, num) ((bits) << (16*((num)-1)))
+#define VME2_SLAVECTL_WP 0x00000100 /* write posting */
+#define VME2_SLAVECTL_SNP_NO 0x00000000 /* no snooping */
+#define VME2_SLAVECTL_SNP_SINK 0x00000200 /* sink data */
+#define VME2_SLAVECTL_SNP_INVAL 0x00000400 /* invalidate */
+#define VME2_SLAVECTL_ADDER 0x00000800 /* use adder */
+#define VME2_SLAVECTL_SUP 0x00000080 /* modifier bit */
+#define VME2_SLAVECTL_USR 0x00000040 /* modifier bit */
+#define VME2_SLAVECTL_A32 0x00000020 /* modifier bit */
+#define VME2_SLAVECTL_A24 0x00000010 /* modifier bit */
+#define VME2_SLAVECTL_D64 0x00000008 /* modifier bit */
+#define VME2_SLAVECTL_BLK 0x00000004 /* modifier bit */
+#define VME2_SLAVECTL_PGM 0x00000002 /* modifier bit */
+#define VME2_SLAVECTL_DAT 0x00000001 /* modifier bit */
+/*14*/ volatile u_long vme2_master1;
+/*18*/ volatile u_long vme2_master2;
+/*1c*/ volatile u_long vme2_master3;
+/*20*/ volatile u_long vme2_master4;
+/*24*/ volatile u_long vme2_master4mod;
+/*28*/ volatile u_long vme2_masterctl;
+#define VME2_MASTERCTL_4SHIFT 24
+#define VME2_MASTERCTL_3SHIFT 16
+#define VME2_MASTERCTL_2SHIFT 8
+#define VME2_MASTERCTL_1SHIFT 0
+#define VME2_MASTERCTL_D16 0x80
+#define VME2_MASTERCTL_WP 0x40
+#define VME2_MASTERCTL_AM 0x3f
+#define VME2_MASTERCTL_AM24SB 0x3f /* A24 Supervisory Block Transfer */
+#define VME2_MASTERCTL_AM24SP 0x3e /* A24 Supervisory Program Access */
+#define VME2_MASTERCTL_AM24SD 0x3d /* A24 Supervisory Data Access */
+#define VME2_MASTERCTL_AM24UB 0x3b /* A24 Non-priv. Block Transfer */
+#define VME2_MASTERCTL_AM24UP 0x3a /* A24 Non-priv. Program Access */
+#define VME2_MASTERCTL_AM24UD 0x39 /* A24 Non-priv. Data Access */
+#define VME2_MASTERCTL_AM16S 0x2d /* A16 Supervisory Access */
+#define VME2_MASTERCTL_AM16U 0x29 /* A16 Non-priv. Access */
+#define VME2_MASTERCTL_AM32SB 0x0f /* A32 Supervisory Block Transfer */
+#define VME2_MASTERCTL_AM32SP 0x0e /* A32 Supervisory Program Access */
+#define VME2_MASTERCTL_AM32SD 0x0d /* A32 Supervisory Data Access */
+#define VME2_MASTERCTL_AM32UB 0x0b /* A32 Non-priv. Block Transfer */
+#define VME2_MASTERCTL_AM32UP 0x0a /* A32 Non-priv. Program Access */
+#define VME2_MASTERCTL_AM32UD 0x09 /* A32 Non-priv Data Access */
+
+#define VME2_MASTERCTL_ALL 0xff
+/*2c*/ volatile u_long vme2_gcsrctl;
+#define VME2_GCSRCTL_OFF 0xf0000000
+#define VME2_GCSRCTL_MDEN4 0x00080000
+#define VME2_GCSRCTL_MDEN3 0x00040000
+#define VME2_GCSRCTL_MDEN2 0x00020000
+#define VME2_GCSRCTL_MDEN1 0x00010000
+#define VME2_GCSRCTL_I2EN 0x00008000 /* F decode (A24D16/A32D16) on */
+#define VME2_GCSRCTL_I2WP 0x00004000 /* F decode write post */
+#define VME2_GCSRCTL_I2SU 0x00002000 /* F decode is supervisor */
+#define VME2_GCSRCTL_I2PD 0x00001000 /* F decode is program */
+#define VME2_GCSRCTL_I1EN 0x00000800 /* short decode (A16Dx) on */
+#define VME2_GCSRCTL_I1D16 0x00000400 /* short decode is D16 */
+#define VME2_GCSRCTL_I1WP 0x00000200 /* short decode write post */
+#define VME2_GCSRCTL_I1SU 0x00000100 /* short decode is supervisor */
+#define VME2_GCSRCTL_ROMSIZE 0x000000c0 /* size of ROM */
+#define VME2_GCSRCTL_ROMBSPD 0x00000038 /* speed of ROM */
+#define VME2_GCSRCTL_ROMASPD 0x00000007 /* speed of ROM */
+/*30*/ volatile u_long vme2_dmactl;
+/*34*/ volatile u_long vme2_dmamode;
+/*38*/ volatile u_long vme2_dmaladdr;
+/*3c*/ volatile u_long vme2_dmavmeaddr;
+/*40*/ volatile u_long vme2_dmacount;
+/*44*/ volatile u_long vme2_dmatable;
+/*48*/ volatile u_long vme2_dmastat;
+/*4c*/ volatile u_long vme2_vmejunk;
+/*50*/ volatile u_long vme2_t1cmp;
+/*54*/ volatile u_long vme2_t1count;
+/*58*/ volatile u_long vme2_t2cmp;
+/*5c*/ volatile u_long vme2_t2count;
+/*60*/ volatile u_long vme2_tctl;
+#define VME2_TCTL_SCON 0x40000000 /* we are SCON */
+#define VME2_TCTL_SYSFAIL 0x20000000 /* light SYSFAIL led */
+#define VME2_TCTL_SRST 0x00800000 /* system reset */
+/*64*/ volatile u_long vme2_prescale;
+/*68*/ volatile u_long vme2_irqstat;
+/*6c*/ volatile u_long vme2_irqen;
+/*70*/ volatile u_long vme2_setsoftirq; /* VME2_IRQ_SWx only */
+/*74*/ volatile u_long vme2_irqclr; /* except VME2_IRQ_VMEx */
+#define VME2_IRQ_ACF 0x80000000
+#define VME2_IRQ_AB 0x40000000
+#define VME2_IRQ_SYSF 0x20000000
+#define VME2_IRQ_MWP 0x10000000
+#define VME2_IRQ_PE 0x08000000
+#define VME2_IRQ_V1IE 0x04000000
+#define VME2_IRQ_TIC2 0x02000000
+#define VME2_IRQ_TIC1 0x01000000
+#define VME2_IRQ_VIA 0x00800000
+#define VME2_IRQ_DMA 0x00400000
+#define VME2_IRQ_SIG3 0x00200000
+#define VME2_IRQ_SIG2 0x00100000
+#define VME2_IRQ_SIG1 0x00080000
+#define VME2_IRQ_SIG0 0x00040000
+#define VME2_IRQ_LM1 0x00020000
+#define VME2_IRQ_LM0 0x00010000
+#define VME2_IRQ_SW7 0x00008000
+#define VME2_IRQ_SW6 0x00004000
+#define VME2_IRQ_SW5 0x00002000
+#define VME2_IRQ_SW4 0x00001000
+#define VME2_IRQ_SW3 0x00000800
+#define VME2_IRQ_SW2 0x00000400
+#define VME2_IRQ_SW1 0x00000200
+#define VME2_IRQ_SW0 0x00000100
+#define VME2_IRQ_SPARE 0x00000080
+#define VME2_IRQ_VME7 0x00000040
+#define VME2_IRQ_VME6 0x00000020
+#define VME2_IRQ_VME5 0x00000010
+#define VME2_IRQ_VME4 0x00000008
+#define VME2_IRQ_VME3 0x00000004
+#define VME2_IRQ_VME2 0x00000002
+#define VME2_IRQ_VME1 0x00000001
+#define VME2_IRQ_VME(x) (1 << ((x) - 1))
+/*78*/ volatile u_long vme2_irql1;
+#define VME2_IRQL1_ACFSHIFT 28
+#define VME2_IRQL1_ABSHIFT 24
+#define VME2_IRQL1_SYSFSHIFT 20
+#define VME2_IRQL1_WPESHIFT 16
+#define VME2_IRQL1_PESHIFT 12
+#define VME2_IRQL1_V1IESHIFT 8
+#define VME2_IRQL1_TIC2SHIFT 4
+#define VME2_IRQL1_TIC1SHIFT 0
+/*7c*/ volatile u_long vme2_irql2;
+#define VME2_IRQL2_VIASHIFT 28
+#define VME2_IRQL2_DMASHIFT 24
+#define VME2_IRQL2_SIG3SHIFT 20
+#define VME2_IRQL2_SIG2SHIFT 16
+#define VME2_IRQL2_SIG1SHIFT 12
+#define VME2_IRQL2_SIG0SHIFT 8
+#define VME2_IRQL2_LM1SHIFT 4
+#define VME2_IRQL2_LM0SHIFT 0
+/*80*/ volatile u_long vme2_irql3;
+#define VME2_IRQL3_SW7SHIFT 28
+#define VME2_IRQL3_SW6SHIFT 24
+#define VME2_IRQL3_SW5SHIFT 20
+#define VME2_IRQL3_SW4SHIFT 16
+#define VME2_IRQL3_SW3SHIFT 12
+#define VME2_IRQL3_SW2SHIFT 8
+#define VME2_IRQL3_SW1SHIFT 4
+#define VME2_IRQL3_SW0SHIFT 0
+/*84*/ volatile u_long vme2_irql4;
+#define VME2_IRQL4_SPARESHIFT 28
+#define VME2_IRQL4_VME7SHIFT 24
+#define VME2_IRQL4_VME6SHIFT 20
+#define VME2_IRQL4_VME5SHIFT 16
+#define VME2_IRQL4_VME4SHIFT 12
+#define VME2_IRQL4_VME3SHIFT 8
+#define VME2_IRQL4_VME2SHIFT 4
+#define VME2_IRQL4_VME1SHIFT 0
+/*88*/ volatile u_long vme2_vbr;
+#define VME2_VBR_0SHIFT 28
+#define VME2_VBR_1SHIFT 24
+#define VME2_VBR_GPOXXXX 0x00ffffff
+/*8c*/ volatile u_long vme2_misc;
+#define VME2_MISC_MPIRQEN 0x00000080 /* do not set */
+#define VME2_MISC_REVEROM 0x00000040 /* 167: dis eprom. 166: en flash */
+#define VME2_MISC_DISSRAM 0x00000020 /* do not set */
+#define VME2_MISC_DISMST 0x00000010
+#define VME2_MISC_NOELBBSY 0x00000008 /* do not set */
+#define VME2_MISC_DISBSYT 0x00000004 /* do not set */
+#define VME2_MISC_ENINT 0x00000002 /* do not set */
+#define VME2_MISC_DISBGN 0x00000001 /* do not set */
+};
+
+#define VME2_A16D32BASE 0xffff0000UL
+#define VME2_A16D32LEN 0x00010000UL
+#define VME2_A32D16BASE 0xf1000000UL
+#define VME2_A32D16LEN 0x01000000UL
+#define VME2_A16D16BASE 0xffff0000UL
+#define VME2_A16D16LEN 0x00010000UL
+#define VME2_A24D16BASE 0xf0000000UL
+#define VME2_A24D16LEN 0x01000000UL
+#define VME2_A16BASE 0xffff0000UL
+#define VME2_A24BASE 0xff000000UL
+
+caddr_t vmepmap __P((struct vmesoftc *sc, caddr_t vmeaddr, int len,
+ int bustype));
+caddr_t vmemap __P((struct vmesoftc *sc, caddr_t vmeaddr, int len,
+ int bustype));
+int vmerw __P((struct vmesoftc *sc, struct uio *uio, int flags, int bus));
diff --git a/sys/arch/mvme68k/dev/vmel.c b/sys/arch/mvme68k/dev/vmel.c
new file mode 100644
index 00000000000..68fdb1cf7f2
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vmel.c
@@ -0,0 +1,173 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+/*
+ * The VMEL driver deals with D32 transfers on the VME bus. The number
+ * of address bits (A16, A24, A32) is irrelevant since the mapping
+ * functions will decide how many address bits are relevant.
+ */
+
+void vmelattach __P((struct device *, struct device *, void *));
+int vmelmatch __P((struct device *, void *, void *));
+
+struct vmelsoftc {
+ struct device sc_dev;
+ struct vmesoftc *sc_vme;
+};
+
+struct cfdriver vmelcd = {
+ NULL, "vmel", vmelmatch, vmelattach,
+ DV_DULL, sizeof(struct vmelsoftc), 0
+};
+
+int
+vmelmatch(parent, cf, args)
+ struct device *parent;
+ void *cf, *args;
+{
+ return (1);
+}
+
+int
+vmelscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ return (vmescan(parent, child, args, BUS_VMEL));
+}
+
+void
+vmelattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmelsoftc *sc = (struct vmelsoftc *)self;
+
+ printf("\n");
+
+ sc->sc_vme = (struct vmesoftc *)parent;
+
+ config_search(vmelscan, self, args);
+}
+
+/*ARGSUSED*/
+int
+vmelopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= vmelcd.cd_ndevs ||
+ vmelcd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmelclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmelioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+int
+vmelread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMEL));
+}
+
+int
+vmelwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMEL));
+}
+
+int
+vmelmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct vmelsoftc *sc = (struct vmelsoftc *) vmelcd.cd_devs[unit];
+ caddr_t pa;
+
+ pa = vmepmap(sc->sc_vme, (caddr_t)off, NBPG, BUS_VMEL);
+ printf("vmel %x pa %x\n", off, pa);
+ if (pa == NULL)
+ return (-1);
+ return (m68k_btop(pa));
+}
diff --git a/sys/arch/mvme68k/dev/vmes.c b/sys/arch/mvme68k/dev/vmes.c
new file mode 100644
index 00000000000..b4d6ac87725
--- /dev/null
+++ b/sys/arch/mvme68k/dev/vmes.c
@@ -0,0 +1,173 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Theo de Raadt
+ * 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 Theo de Raadt
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <mvme68k/dev/vme.h>
+
+/*
+ * The VMES driver deals with D16 transfers on the VME bus. The number
+ * of address bits (A16, A24, A32) is irrelevant since the mapping
+ * functions will decide how many address bits are relevant.
+ */
+
+void vmesattach __P((struct device *, struct device *, void *));
+int vmesmatch __P((struct device *, void *, void *));
+
+struct vmessoftc {
+ struct device sc_dev;
+ struct vmesoftc *sc_vme;
+};
+
+struct cfdriver vmescd = {
+ NULL, "vmes", vmesmatch, vmesattach,
+ DV_DULL, sizeof(struct vmessoftc), 0
+};
+
+int
+vmesmatch(parent, cf, args)
+ struct device *parent;
+ void *cf, *args;
+{
+ return (1);
+}
+
+int
+vmesscan(parent, child, args)
+ struct device *parent;
+ void *child, *args;
+{
+ return (vmescan(parent, child, args, BUS_VMES));
+}
+
+void
+vmesattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct vmessoftc *sc = (struct vmessoftc *)self;
+
+ printf("\n");
+
+ sc->sc_vme = (struct vmesoftc *)parent;
+
+ config_search(vmesscan, self, args);
+}
+
+/*ARGSUSED*/
+int
+vmesopen(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+ if (minor(dev) >= vmescd.cd_ndevs ||
+ vmescd.cd_devs[minor(dev)] == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmesclose(dev, flag, mode)
+ dev_t dev;
+ int flag, mode;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+vmesioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ int cmd, flag;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+int
+vmesread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMES));
+}
+
+int
+vmeswrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+
+ return (vmerw(sc->sc_vme, uio, flags, BUS_VMES));
+}
+
+int
+vmesmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ int unit = minor(dev);
+ struct vmessoftc *sc = (struct vmessoftc *) vmescd.cd_devs[unit];
+ caddr_t pa;
+
+ pa = vmepmap(sc->sc_vme, (caddr_t)off, NBPG, BUS_VMES);
+ printf("vmes %x pa %x\n", off, pa);
+ if (pa == NULL)
+ return (-1);
+ return (m68k_btop(pa));
+}