summaryrefslogtreecommitdiff
path: root/sys/arch/vax/uba
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/vax/uba')
-rw-r--r--sys/arch/vax/uba/dhu.c13
-rw-r--r--sys/arch/vax/uba/dz.c12
-rw-r--r--sys/arch/vax/uba/qd.c3611
-rw-r--r--sys/arch/vax/uba/qv.c1323
-rw-r--r--sys/arch/vax/uba/tmscp.c2211
-rw-r--r--sys/arch/vax/uba/tmscpreg.h120
-rw-r--r--sys/arch/vax/uba/ts.c677
-rw-r--r--sys/arch/vax/uba/uba.c1339
-rw-r--r--sys/arch/vax/uba/ubareg.h241
-rw-r--r--sys/arch/vax/uba/ubavar.h137
-rw-r--r--sys/arch/vax/uba/uda.c2463
-rw-r--r--sys/arch/vax/uba/udareg.h46
12 files changed, 6134 insertions, 6059 deletions
diff --git a/sys/arch/vax/uba/dhu.c b/sys/arch/vax/uba/dhu.c
index 8dcf6236d7f..10ade80d77d 100644
--- a/sys/arch/vax/uba/dhu.c
+++ b/sys/arch/vax/uba/dhu.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dhu.c,v 1.5 1996/05/19 16:27:02 ragge Exp $ */
+/* $NetBSD: dhu.c,v 1.9 1997/01/11 11:34:41 ragge Exp $ */
/*
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
* Copyright (c) 1992, 1993
@@ -132,7 +132,7 @@ static unsigned dhumctl __P((struct dhu_softc *,int, int, int));
int dhuread __P((dev_t, struct uio *, int));
int dhuwrite __P((dev_t, struct uio *, int));
int dhuioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
- int dhustop __P((struct tty *, int));
+ void dhustop __P((struct tty *, int));
struct tty * dhutty __P((dev_t));
struct cfdriver dhu_cd = {
@@ -376,9 +376,9 @@ dhuopen(dev, flag, mode, p)
sc->sc_dhu[line].dhu_state = STATE_IDLE;
- sc->sc_dhu[line].dhu_txaddr = uballoc(
- sc->sc_dev.dv_parent->dv_unit,
- tp->t_outq.c_cs, tp->t_outq.c_cn, 0);
+ sc->sc_dhu[line].dhu_txaddr =
+ uballoc((struct uba_softc *)sc->sc_dev.dv_parent,
+ tp->t_outq.c_cs, tp->t_outq.c_cn, 0);
dhuaddr = sc->sc_addr;
@@ -561,7 +561,7 @@ dhutty(dev)
}
/*ARGSUSED*/
-int
+void
dhustop(tp, flag)
register struct tty *tp;
{
@@ -590,7 +590,6 @@ dhustop(tp, flag)
tp->t_state |= TS_FLUSH;
}
(void) splx(s);
- return 0;
}
static void
diff --git a/sys/arch/vax/uba/dz.c b/sys/arch/vax/uba/dz.c
index f1636b7f3ef..bc583be03c1 100644
--- a/sys/arch/vax/uba/dz.c
+++ b/sys/arch/vax/uba/dz.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dz.c,v 1.1 1996/04/08 17:22:20 ragge Exp $ */
+/* $NetBSD: dz.c,v 1.4 1996/10/13 03:35:15 christos Exp $ */
/*
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
* Copyright (c) 1992, 1993
@@ -121,7 +121,7 @@ struct tty * dztty __P((dev_t));
int dzread __P((dev_t, struct uio *, int));
int dzwrite __P((dev_t, struct uio *, int));
int dzioctl __P((dev_t, int, caddr_t, int, struct proc *));
- int dzstop __P((struct tty *, int));
+ void dzstop __P((struct tty *, int));
struct cfdriver dz_cd = {
NULL, "dz", DV_TTY
@@ -547,8 +547,8 @@ dztty (dev)
}
/*ARGSUSED*/
-int
-dzstop (tp, flag)
+void
+dzstop(tp, flag)
register struct tty *tp;
{
register struct dz_softc *sc;
@@ -560,14 +560,12 @@ dzstop (tp, flag)
s = spltty();
- if (tp->t_state & TS_BUSY)
- {
+ if (tp->t_state & TS_BUSY) {
sc->sc_dz[line].dz_end = sc->sc_dz[line].dz_mem;
if (!(tp->t_state & TS_TTSTOP))
tp->t_state |= TS_FLUSH;
}
(void) splx(s);
- return 0;
}
static void
diff --git a/sys/arch/vax/uba/qd.c b/sys/arch/vax/uba/qd.c
new file mode 100644
index 00000000000..71acc0792cc
--- /dev/null
+++ b/sys/arch/vax/uba/qd.c
@@ -0,0 +1,3611 @@
+/* $NetBSD: qd.c,v 1.4 1996/10/13 03:35:17 christos Exp $ */
+
+/*-
+ * Copyright (c) 1988 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.
+ *
+ * @(#)qd.c 7.1 (Berkeley) 6/28/91
+ */
+
+/************************************************************************
+* *
+* Copyright (c) 1985-1988 by *
+* Digital Equipment Corporation, Maynard, MA *
+* All rights reserved. *
+* *
+* This software is furnished under a license and may be used and *
+* copied only in accordance with the terms of such license and *
+* with the inclusion of the above copyright notice. This *
+* software or any other copies thereof may not be provided or *
+* otherwise made available to any other person. No title to and *
+* ownership of the software is hereby transferred. *
+* *
+* The information in this software is subject to change without *
+* notice and should not be construed as a commitment by Digital *
+* Equipment Corporation. *
+* *
+* Digital assumes no responsibility for the use or reliability *
+* of its software on equipment which is not supplied by Digital. *
+* *
+*************************************************************************/
+
+/*
+ * qd.c - QDSS display driver for VAXSTATION-II GPX workstation
+ */
+
+#include "qd.h"
+
+#if NQD > 0
+#include "../include/pte.h"
+#include "../include/mtpr.h"
+#include "sys/param.h"
+#include "../include/cpu.h"
+#include "sys/conf.h"
+#include "sys/user.h"
+#include "qdioctl.h"
+#include "sys/tty.h"
+#include "sys/map.h"
+#include "sys/buf.h"
+#include "sys/vm.h"
+#include "sys/clist.h"
+#include "sys/file.h"
+#include "sys/uio.h"
+#include "sys/kernel.h"
+#include "sys/exec.h"
+#include "sys/proc.h"
+#include "ubareg.h"
+#include "ubavar.h"
+#include "sys/syslog.h"
+#include "qduser.h" /* definitions shared with user level client */
+#include "qdreg.h" /* QDSS device register structures */
+
+/*
+ * QDSS driver status flags for tracking operational state
+ */
+struct qdflags {
+ u_int inuse; /* which minor dev's are in use now */
+ u_int config; /* I/O page register content */
+ u_int mapped; /* user mapping status word */
+ u_int kernel_loop; /* if kernel console is redirected */
+ u_int user_dma; /* DMA from user space in progress */
+ u_short pntr_id; /* type code of pointing device */
+ u_short duart_imask; /* shadowing for duart intrpt mask reg */
+ u_short adder_ie; /* shadowing for adder intrpt enbl reg */
+ u_short curs_acc; /* cursor acceleration factor */
+ u_short curs_thr; /* cursor acceleration threshold level */
+ u_short tab_res; /* tablet resolution factor */
+ u_short selmask; /* mask for active qd select entries */
+};
+
+/*
+ * bit definitions for 'inuse' entry
+ */
+#define CONS_DEV 0x01
+#define GRAPHIC_DEV 0x04
+
+/*
+ * bit definitions for 'mapped' member of flag structure
+ */
+#define MAPDEV 0x01 /* hardware is mapped */
+#define MAPDMA 0x02 /* DMA buffer mapped */
+#define MAPEQ 0x04 /* event queue buffer mapped */
+#define MAPSCR 0x08 /* scroll param area mapped */
+#define MAPCOLOR 0x10 /* color map writing buffer mapped */
+
+/*
+ * bit definitions for 'selmask' member of qdflag structure
+ */
+#define SEL_READ 0x01 /* read select is active */
+#define SEL_WRITE 0x02 /* write select is active */
+
+/*
+ * constants used in shared memory operations
+ */
+#define EVENT_BUFSIZE 1024 /* # of bytes per device's event buffer */
+#define MAXEVENTS ( (EVENT_BUFSIZE - sizeof(struct qdinput)) \
+ / sizeof(struct _vs_event) )
+#define DMA_BUFSIZ (1024 * 10)
+#define COLOR_BUFSIZ ((sizeof(struct color_buf) + 512) & ~0x01FF)
+
+/*
+ * reference to an array of "uba_device" structures built by the auto
+ * configuration program. The uba_device structure decribes the device
+ * sufficiently for the driver to talk to it. The auto configuration code
+ * fills in the uba_device structures (located in ioconf.c) from user
+ * maintained info.
+ */
+struct uba_device *qdinfo[NQD]; /* array of pntrs to each QDSS's */
+struct tty qd_tty[NQD*4]; /* teletype structures for each.. */
+extern char qvmem[][128*NBPG];
+extern struct pte QVmap[][128];
+#define CHUNK (64 * 1024)
+#define QMEMSIZE (1024 * 1024 * 4) /* 4 meg */
+
+/*
+ * static storage used by multiple functions in this code
+ */
+int Qbus_unmap[NQD]; /* Qbus mapper release code */
+struct qdflags qdflags[NQD]; /* QDSS device status flags */
+struct qdmap qdmap[NQD]; /* QDSS register map structure */
+caddr_t qdbase[NQD]; /* base address of each QDSS unit */
+struct buf qdbuf[NQD]; /* buf structs used by strategy */
+short qdopened[NQD]; /* graphics device is open exclusive use */
+
+/*
+ * the array "event_shared[]" is made up of a number of event queue buffers
+ * equal to the number of QDSS's configured into the running kernel (NQD).
+ * Each event queue buffer begins with an event queue header (struct qdinput)
+ * followed by a group of event queue entries (struct _vs_event). The array
+ * "*eq_header[]" is an array of pointers to the start of each event queue
+ * buffer in "event_shared[]".
+ */
+#define EQSIZE ((EVENT_BUFSIZE * NQD) + 512)
+
+char event_shared[EQSIZE]; /* reserve space for event bufs */
+struct qdinput *eq_header[NQD]; /* event queue header pntrs */
+
+/*
+ * This allocation method reserves enough memory pages for NQD shared DMA I/O
+ * buffers. Each buffer must consume an integral number of memory pages to
+ * guarantee that a following buffer will begin on a page boundary. Also,
+ * enough space is allocated so that the FIRST I/O buffer can start at the
+ * 1st page boundary after "&DMA_shared". Page boundaries are used so that
+ * memory protections can be turned on/off for individual buffers.
+ */
+#define IOBUFSIZE ((DMA_BUFSIZ * NQD) + 512)
+
+char DMA_shared[IOBUFSIZE]; /* reserve I/O buffer space */
+struct DMAreq_header *DMAheader[NQD]; /* DMA buffer header pntrs */
+
+/*
+ * The driver assists a client in scroll operations by loading dragon
+ * registers from an interrupt service routine. The loading is done using
+ * parameters found in memory shrade between the driver and it's client.
+ * The scroll parameter structures are ALL loacted in the same memory page
+ * for reasons of memory economy.
+ */
+char scroll_shared[2 * 512]; /* reserve space for scroll structs */
+struct scroll *scroll[NQD]; /* pointers to scroll structures */
+
+/*
+ * the driver is programmable to provide the user with color map write
+ * services at VSYNC interrupt time. At interrupt time the driver loads
+ * the color map with any user-requested load data found in shared memory
+ */
+#define COLOR_SHARED ((COLOR_BUFSIZ * NQD) + 512)
+
+char color_shared[COLOR_SHARED]; /* reserve space: color bufs */
+struct color_buf *color_buf[NQD]; /* pointers to color bufs */
+
+/*
+ * mouse input event structures
+ */
+struct mouse_report last_rep[NQD];
+struct mouse_report current_rep[NQD];
+
+struct proc *qdrsel[NQD]; /* process waiting for select */
+struct _vs_cursor cursor[NQD]; /* console cursor */
+int qdcount = 0; /* count of successfully probed qd's */
+int nNQD = NQD;
+int DMAbuf_size = DMA_BUFSIZ;
+int QDlast_DMAtype; /* type of the last DMA operation */
+
+#define QDSSMAJOR 41 /* QDSS major device number */
+/*
+ * macro to get system time. Used to time stamp event queue entries
+ */
+#define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000))
+
+int qdprobe();
+int qdattach();
+int qddint(); /* DMA gate array intrpt service */
+int qdaint(); /* Dragon ADDER intrpt service */
+int qdiint();
+
+u_short qdstd[] = { 0 };
+
+struct uba_driver qddriver = {
+ qdprobe, /* device probe entry */
+ 0, /* no slave device */
+ qdattach, /* device attach entry */
+ 0, /* no "fill csr/ba to start" */
+ qdstd, /* device addresses */
+ "qd", /* device name string */
+ qdinfo /* ptr to QDSS's uba_device struct */
+};
+
+#define QDPRIOR (PZERO-1) /* must be negative */
+#define FALSE 0
+#define TRUE ~FALSE
+#define BAD -1
+#define GOOD 0
+
+/*
+ * macro to create a system virtual page number from system virtual adrs
+ */
+#define VTOP(x) (((int)x & ~0xC0000000) >> PGSHIFT)
+
+/*
+ * QDSS register address offsets from start of QDSS address space
+ */
+#define QDSIZE (52 * 1024) /* size of entire QDSS foot print */
+#define TMPSIZE (16 * 1024) /* template RAM is 8k SHORT WORDS */
+#define TMPSTART 0x8000 /* offset of template RAM from base adrs */
+#define REGSIZE (5 * 512) /* regs touch 2.5k (5 pages) of addr space */
+#define REGSTART 0xC000 /* offset of reg pages from base adrs */
+#define ADDER (REGSTART+0x000)
+#define DGA (REGSTART+0x200)
+#define DUART (REGSTART+0x400)
+#define MEMCSR (REGSTART+0x800)
+#define CLRSIZE (3 * 512) /* color map size */
+#define CLRSTART (REGSTART+0xA00) /* color map start offset from base */
+/* 0x0C00 really */
+#define RED (CLRSTART+0x000)
+#define BLUE (CLRSTART+0x200)
+#define GREEN (CLRSTART+0x400)
+
+
+/*
+ * QDSS minor device numbers. The *real* minor device numbers are in
+ * the bottom two bits of the major/minor device spec. Bits 2 and up are
+ * used to specify the QDSS device number (ie: which one?)
+ */
+
+#define CONS 0
+#define GRAPHIC 2
+
+/*
+ * console cursor bitmap (white block cursor)
+ */
+short cons_cursor[32] = {
+ /* A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ /* B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
+ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
+};
+
+/*
+ * constants used in font operations
+ */
+#define CHARS 190 /* # of chars in the font */
+#define CHAR_HEIGHT 15 /* char height in pixels */
+#define CHAR_WIDTH 8 /* char width in pixels*/
+#define FONT_WIDTH (CHAR_WIDTH * CHARS) /* font width in pixels */
+#define ROWS CHAR_HEIGHT
+#define FONT_X 0 /* font's off screen adrs */
+#define FONT_Y (2048 - CHAR_HEIGHT)
+
+/* Offset to second row characters (XXX - should remove) */
+#define FONT_OFFSET ((MAX_SCREEN_X/CHAR_WIDTH)*CHAR_HEIGHT)
+
+extern char q_font[]; /* reference font object code */
+extern u_short q_key[]; /* reference key xlation tables */
+extern u_short q_shift_key[];
+extern char *q_special[];
+
+/*
+ * definitions for cursor acceleration reporting
+ */
+#define ACC_OFF 0x01 /* acceleration is inactive */
+
+/*
+ * virtual console support.
+ */
+extern (*v_putc)();
+#ifdef KADB
+extern (*v_getc)();
+extern (*v_poll)();
+#endif
+extern struct cdevsw *consops;
+int qdputc();
+int qdgetc();
+int qdpoll();
+int qdstart();
+int qdpolling = 0;
+
+/*
+ * LK-201 state storage for input console keyboard conversion to ASCII
+ */
+struct q_keyboard {
+ int shift; /* state variables */
+ int cntrl;
+ int lock;
+ int lastcode; /* last keycode typed */
+ unsigned kup[8]; /* bits for each keycode*/
+ unsigned dkeys[8]; /* down/up mode keys */
+ char last; /* last character */
+} q_keyboard;
+
+/*
+ * tty settings on first open
+ */
+#define IFLAG (BRKINT|ISTRIP|IXON|IXANY|ICRNL|IMAXBEL)
+#define OFLAG (OPOST|OXTABS|ONLCR)
+#define LFLAG (ISIG|ICANON|ECHO|IEXTEN)
+#define CFLAG (PARENB|CREAD|CS7|CLOCAL)
+
+/*
+ * Init QDSS as console (before probe routine)
+ */
+
+qdcons_init()
+{
+ register unit;
+ caddr_t phys_adr; /* physical QDSS base adrs */
+ u_int mapix; /* index into QVmap[] array */
+ struct percpu *pcpu; /* pointer to cpusw structure */
+ register struct qbus *qb;
+ u_short *qdaddr; /* address of QDSS IO page CSR */
+ u_short *devptr; /* vitual device space */
+ extern cnputc();
+
+#define QDSSCSR 0x1F00
+
+ if (v_putc != cnputc)
+ return 0;
+
+ unit = 0;
+
+ /*
+ * find the cpusw entry that matches this machine.
+ */
+ for (pcpu = percpu; pcpu && pcpu->pc_cputype != cpu; pcpu++)
+ ;
+ if (pcpu == NULL)
+ return 0;
+ if (pcpu->pc_io->io_type != IO_QBUS)
+ return 0;
+
+ /*
+ * Map device registers - the last 8K of qvmem.
+ */
+ qb = (struct qbus *)pcpu->pc_io->io_details;
+ ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize,
+ UBAIOPAGES * NBPG);
+ devptr = (u_short *)((char *)umem[0]+(qb->qb_memsize * NBPG));
+ qdaddr = (u_short *)((u_int)devptr + ubdevreg(QDSSCSR));
+ if (badaddr((caddr_t)qdaddr, sizeof(short)))
+ return 0;
+
+ /*
+ * Map q-bus memory used by qdss. (separate map)
+ */
+ mapix = QMEMSIZE - (CHUNK * (unit + 1));
+ phys_adr = qb->qb_maddr + mapix;
+ ioaccess(phys_adr, QVmap[0], (CHUNK*NQD));
+
+ /*
+ * tell QDSS which Q memory address base to decode
+ * (shifted right 16 bits - its in 64K units)
+ */
+ *qdaddr = (u_short)((int)mapix >> 16);
+ qdflags[unit].config = *(u_short *)qdaddr;
+
+ /*
+ * load qdmap struct with the virtual addresses of the QDSS elements
+ */
+ qdbase[unit] = (caddr_t) (qvmem[0]);
+ qdmap[unit].template = qdbase[unit] + TMPSTART;
+ qdmap[unit].adder = qdbase[unit] + ADDER;
+ qdmap[unit].dga = qdbase[unit] + DGA;
+ qdmap[unit].duart = qdbase[unit] + DUART;
+ qdmap[unit].memcsr = qdbase[unit] + MEMCSR;
+ qdmap[unit].red = qdbase[unit] + RED;
+ qdmap[unit].blue = qdbase[unit] + BLUE;
+ qdmap[unit].green = qdbase[unit] + GREEN;
+
+ qdflags[unit].duart_imask = 0; /* init shadow variables */
+
+ /*
+ * init the QDSS
+ */
+ /*
+ printf("qdbase[0] = %x, qdmap[0].memcsr = %x\n",
+ (char *)qdbase[0], qdmap[0].memcsr);
+ */
+
+ *(short *)qdmap[unit].memcsr |= SYNC_ON; /* once only: turn on sync */
+
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ clear_qd_screen(unit); /* clear the screen */
+ ldfont(unit); /* load the console font */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ v_putc = qdputc; /* kernel console output to qdss */
+#ifdef KADB
+ v_getc = qdgetc; /* kernel console input from qdss */
+ v_poll = qdpoll; /* kdb hook to disable char intr */
+#endif
+ consops = &cdevsw[QDSSMAJOR]; /* virtual console is qdss */
+ return 1;
+
+} /* qdcons_init */
+
+/*
+ * Configure QDSS into Q memory and make it intrpt.
+ *
+ * side effects: QDSS gets mapped into Qbus memory space at the first
+ * vacant 64kb boundary counting back from the top of
+ * Qbus memory space (qvmem+4mb)
+ *
+ * return: QDSS bus request level and vector address returned in
+ * registers by UNIX convention.
+ *
+ */
+qdprobe(reg)
+ caddr_t reg; /* character pointer to the QDSS I/O page register */
+{
+ register int br, cvec;
+ register int unit;
+ struct dga *dga; /* pointer to gate array structure */
+ int vector;
+#ifdef notdef
+ int *ptep; /* page table entry pointer */
+ caddr_t phys_adr; /* physical QDSS base adrs */
+ u_int mapix;
+#endif
+
+#ifdef lint
+ br = 0; cvec = br; br = cvec; nNQD = br; br = nNQD;
+ qddint(0); qdaint(0); qdiint(0); (void)qdgetc();
+#endif
+
+ /*
+ * calculate board unit number from I/O page register address
+ */
+ unit = (int) (((int)reg >> 1) & 0x0007);
+
+ /*
+ * QDSS regs must be mapped to Qbus memory space at a 64kb
+ * physical boundary. The Qbus memory space is mapped into
+ * the system memory space at config time. After config
+ * runs, "qvmem[0]" (ubavar.h) holds the system virtual adrs
+ * of the start of Qbus memory. The Qbus memory page table
+ * is found via an array of pte ptrs called "QVmap[]" (ubavar.h)
+ * which is also loaded at config time. These are the
+ * variables used below to find a vacant 64kb boundary in
+ * Qbus memory, and load it's corresponding physical adrs
+ * into the QDSS's I/O page CSR.
+ */
+
+ /*
+ * Only if QD is the graphics device.
+ */
+
+ /* if this QDSS is NOT the console, then do init here.. */
+
+ if (unit != 0) {
+ printf("qd: can't support two qdss's (yet)\n");
+#ifdef notdef /* can't test */
+ if (v_consputc != qdputc || unit != 0) {
+
+ /*
+ * read QDSS config info
+ */
+ qdflags[unit].config = *(u_short *)reg;
+
+ /*
+ * find an empty 64kb adrs boundary
+ */
+
+ qdbase[unit] = (caddr_t) (qvmem[0] + QMEMSIZE - CHUNK);
+
+ /*
+ * find the cpusw entry that matches this machine.
+ */
+ cpup = &cpusw[cpu];
+ while (!(BADADDR(qdbase[unit], sizeof(short))))
+ qdbase[unit] -= CHUNK;
+
+ /*
+ * tell QDSS which Q memory address base to decode
+ */
+ mapix = (int) (VTOP(qdbase[unit]) - VTOP(qvmem[0]));
+ ptep = (int *) QVmap[0] + mapix;
+ phys_adr = (caddr_t)(((int)*ptep&0x001FFFFF)<<PGSHIFT);
+ *(u_short *)reg = (u_short) ((int)phys_adr >> 16);
+
+ /*
+ * load QDSS adrs map with system addresses
+ * of device regs
+ */
+ qdmap[unit].template = qdbase[unit] + TMPSTART;
+ qdmap[unit].adder = qdbase[unit] + ADDER;
+ qdmap[unit].dga = qdbase[unit] + DGA;
+ qdmap[unit].duart = qdbase[unit] + DUART;
+ qdmap[unit].memcsr = qdbase[unit] + MEMCSR;
+ qdmap[unit].red = qdbase[unit] + RED;
+ qdmap[unit].blue = qdbase[unit] + BLUE;
+ qdmap[unit].green = qdbase[unit] + GREEN;
+
+ /* device init */
+
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ clear_qd_screen(unit);
+ ldfont(unit); /* load the console font */
+
+ /* once only: turn on sync */
+
+ *(short *)qdmap[unit].memcsr |= SYNC_ON;
+ }
+#endif /*notdef*/
+ }
+
+ /*
+ * The QDSS interrupts at HEX vectors xx0 (DMA) xx4
+ * (ADDER) and xx8 (DUART). Therefore, we take three
+ * vectors from the vector pool, and then continue
+ * to take them until we get a xx0 HEX vector. The
+ * pool provides vectors in contiguous decending
+ * order.
+ */
+
+ vector = (uba_hd[0].uh_lastiv -= 4*3); /* take three vectors */
+
+ while (vector & 0x0F) { /* if lo nibble != 0.. */
+ /* ..take another vector */
+ vector = (uba_hd[0].uh_lastiv -= 4);
+ }
+
+ /*
+ * setup DGA to do a DMA interrupt (transfer count = 0)
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr = (short) HALT; /* disable everything */
+ dga->ivr = (short) vector; /* load intrpt base vector */
+ dga->bytcnt_lo = (short) 0; /* DMA xfer count = 0 */
+ dga->bytcnt_hi = (short) 0;
+
+ /*
+ * turn on DMA interrupts
+ */
+ dga->csr &= ~SET_DONE_FIFO;
+ dga->csr |= DMA_IE | DL_ENB;
+
+ DELAY(20000); /* wait for the intrpt */
+ dga->csr = HALT; /* stop the wheels */
+
+ if (cvec != vector) /* if vector != base vector.. */
+ return(0); /* ..return = 'no device' */
+
+ /*
+ * score this as an existing qdss
+ */
+ qdcount++;
+
+ return(sizeof(short)); /* return size of QDSS I/O page reg */
+
+} /* qdprobe */
+
+qdattach(ui)
+ struct uba_device *ui;
+{
+ register unit; /* QDSS module # for this call */
+
+ unit = ui->ui_unit; /* get QDSS number */
+
+ /*
+ * init "qdflags[]" for this QDSS
+ */
+ qdflags[unit].inuse = 0; /* init inuse variable EARLY! */
+ qdflags[unit].mapped = 0;
+ qdflags[unit].kernel_loop = -1;
+ qdflags[unit].user_dma = 0;
+ qdflags[unit].curs_acc = ACC_OFF;
+ qdflags[unit].curs_thr = 128;
+ qdflags[unit].tab_res = 2; /* default tablet resolution factor */
+ qdflags[unit].duart_imask = 0; /* init shadow variables */
+ qdflags[unit].adder_ie = 0;
+
+ /*
+ * init structures used in kbd/mouse interrupt service. This code must
+ * come after the "init_shared()" routine has run since that routine
+ * inits the eq_header[unit] structure used here.
+ */
+
+ /*
+ * init the "latest mouse report" structure
+ */
+ last_rep[unit].state = 0;
+ last_rep[unit].dx = 0;
+ last_rep[unit].dy = 0;
+ last_rep[unit].bytcnt = 0;
+
+ /*
+ * init the event queue (except mouse position)
+ */
+ eq_header[unit]->header.events =
+ (struct _vs_event *)((int)eq_header[unit] + sizeof(struct qdinput));
+
+ eq_header[unit]->header.size = MAXEVENTS;
+ eq_header[unit]->header.head = 0;
+ eq_header[unit]->header.tail = 0;
+
+ /*
+ * open exclusive for graphics device.
+ */
+ qdopened[unit] = 0;
+
+} /* qdattach */
+
+/*ARGSUSED*/
+qdopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct uba_device *ui; /* ptr to uba structures */
+ register struct dga *dga; /* ptr to gate array struct */
+ register struct tty *tp;
+ struct duart *duart;
+ int unit;
+ int minor_dev;
+
+ minor_dev = minor(dev); /* get QDSS minor device number */
+ unit = minor_dev >> 2;
+
+ /*
+ * check for illegal conditions
+ */
+ ui = qdinfo[unit]; /* get ptr to QDSS device struct */
+ if (ui == 0 || ui->ui_alive == 0)
+ return(ENXIO); /* no such device or address */
+
+ duart = (struct duart *) qdmap[unit].duart;
+ dga = (struct dga *) qdmap[unit].dga;
+
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is the graphic device...
+ */
+ if (qdopened[unit] != 0)
+ return(EBUSY);
+ else
+ qdopened[unit] = 1;
+ qdflags[unit].inuse |= GRAPHIC_DEV; /* graphics dev is open */
+ /*
+ * enble kbd & mouse intrpts in DUART mask reg
+ */
+ qdflags[unit].duart_imask |= 0x22;
+ duart->imask = qdflags[unit].duart_imask;
+ } else {
+ /*
+ * this is the console
+ */
+ qdflags[unit].inuse |= CONS_DEV; /* mark console as open */
+ dga->csr |= CURS_ENB;
+ qdflags[unit].duart_imask |= 0x02;
+ duart->imask = qdflags[unit].duart_imask;
+ /*
+ * some setup for tty handling
+ */
+ tp = &qd_tty[minor_dev];
+ tp->t_addr = ui->ui_addr;
+ tp->t_oproc = qdstart;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ ttychars(tp);
+ tp->t_ispeed = B9600;
+ tp->t_ospeed = B9600;
+ tp->t_state = TS_ISOPEN | TS_CARR_ON;
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ }
+ /*
+ * enable intrpts, open line discipline
+ */
+ dga->csr |= GLOBAL_IE; /* turn on the interrupts */
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+ }
+ dga->csr |= GLOBAL_IE; /* turn on the interrupts */
+ return(0);
+
+} /* qdopen */
+
+/*ARGSUSED*/
+qdclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ register struct tty *tp;
+ register struct qdmap *qd;
+ register int *ptep;
+ struct dga *dga; /* gate array register map pointer */
+ struct duart *duart;
+ struct adder *adder;
+ int unit;
+ int minor_dev;
+ u_int mapix;
+ int i; /* SIGNED index */
+
+ minor_dev = minor(dev); /* get minor device number */
+ unit = minor_dev >> 2; /* get QDSS number */
+ qd = &qdmap[unit];
+
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is the graphic device...
+ */
+ if (qdopened[unit] != 1)
+ return(EBUSY);
+ else
+ qdopened[unit] = 0; /* allow it to be re-opened */
+ /*
+ * re-protect device memory
+ */
+ if (qdflags[unit].mapped & MAPDEV) {
+ /*
+ * TEMPLATE RAM
+ */
+ mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(TMPSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ /*
+ * ADDER
+ */
+ mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(REGSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ /*
+ * COLOR MAPS
+ */
+ mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(CLRSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ }
+
+ /*
+ * re-protect DMA buffer and free the map registers
+ */
+ if (qdflags[unit].mapped & MAPDMA) {
+ dga = (struct dga *) qdmap[unit].dga;
+ adder = (struct adder *) qdmap[unit].adder;
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* kill DMA */
+ adder->command = CANCEL;
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ dga->csr &= ~DMA_IE;
+ }
+ ptep = (int *)
+ ((VTOP(DMAheader[unit]*4)) + (mfpr(SBR)|0x80000000));
+ for (i = 0; i < btop(DMAbuf_size); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_V | PG_KW;
+ ubarelse(0, &Qbus_unmap[unit]);
+ }
+
+ /*
+ * re-protect 1K (2 pages) event queue
+ */
+ if (qdflags[unit].mapped & MAPEQ) {
+ ptep = (int *)
+ ((VTOP(eq_header[unit])*4) + (mfpr(SBR)|0x80000000));
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ }
+ /*
+ * re-protect scroll param area and disable scroll intrpts
+ */
+ if (qdflags[unit].mapped & MAPSCR) {
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect 512 scroll param area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ /*
+ * re-protect color map write buffer area and kill intrpts
+ */
+ if (qdflags[unit].mapped & MAPCOLOR) {
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ color_buf[unit]->status = 0;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ mtpr(TBIA, 0);
+ /* flag everything now unmapped */
+ qdflags[unit].mapped = 0;
+ qdflags[unit].inuse &= ~GRAPHIC_DEV;
+ qdflags[unit].curs_acc = ACC_OFF;
+ qdflags[unit].curs_thr = 128;
+ /*
+ * restore the console
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ adder = (struct adder *) qdmap[unit].adder;
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* halt the DMA! (just in case...) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ adder->command = CANCEL;
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ dga->csr &= ~DMA_IE;
+ }
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init ADDER/VIPER */
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ setup_input(unit); /* init the DUART */
+ ldfont(unit);
+ cursor[unit].x = 0;
+ cursor[unit].y = 0;
+ /*
+ * shut off the mouse rcv intrpt and turn on kbd intrpts
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ qdflags[unit].duart_imask &= ~(0x20);
+ qdflags[unit].duart_imask |= 0x02;
+ duart->imask = qdflags[unit].duart_imask;
+ /*
+ * shut off interrupts if all is closed
+ */
+ if (!(qdflags[unit].inuse & CONS_DEV)) {
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr &= ~(GLOBAL_IE | DMA_IE);
+ }
+ } else {
+ /*
+ * this is the console
+ */
+ tp = &qd_tty[minor_dev];
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ tp->t_state = 0;
+ qdflags[unit].inuse &= ~CONS_DEV;
+ /*
+ * if graphics device is closed, kill interrupts
+ */
+ if (!(qdflags[unit].inuse & GRAPHIC_DEV)) {
+ dga = (struct dga *) qdmap[unit].dga;
+ dga->csr &= ~(GLOBAL_IE | DMA_IE);
+ }
+ }
+
+ return(0);
+
+} /* qdclose */
+
+qdioctl(dev, cmd, datap, flags)
+ dev_t dev;
+ int cmd;
+ register caddr_t datap;
+ int flags;
+{
+ register int *ptep; /* page table entry pointer */
+ register int mapix; /* QVmap[] page table index */
+ register struct _vs_event *event;
+ register struct tty *tp;
+ register i;
+ struct qdmap *qd; /* pointer to device map struct */
+ struct dga *dga; /* Gate Array reg structure pntr */
+ struct duart *duart; /* DUART reg structure pointer */
+ struct adder *adder; /* ADDER reg structure pointer */
+ struct prgkbd *cmdbuf;
+ struct prg_cursor *curs;
+ struct _vs_cursor *pos;
+ int unit = minor(dev) >> 2; /* number of caller's QDSS */
+ u_int minor_dev = minor(dev);
+ int error;
+ int s;
+ short *temp; /* a pointer to template RAM */
+
+ /*
+ * service graphic device ioctl commands
+ */
+ switch (cmd) {
+
+ case QD_GETEVENT:
+ /*
+ * extract the oldest event from the event queue
+ */
+ if (ISEMPTY(eq_header[unit])) {
+ event = (struct _vs_event *) datap;
+ event->vse_device = VSE_NULL;
+ break;
+ }
+ event = (struct _vs_event *) GETBEGIN(eq_header[unit]);
+ s = spl5();
+ GETEND(eq_header[unit]);
+ splx(s);
+ bcopy((caddr_t)event, datap, sizeof(struct _vs_event));
+ break;
+
+ case QD_RESET:
+ /*
+ * init the dragon stuff, DUART, and driver variables
+ */
+ init_shared(unit); /* init shared memory */
+ setup_dragon(unit); /* init the ADDER/VIPER stuff */
+ clear_qd_screen(unit);
+ ldcursor(unit, cons_cursor); /* load default cursor map */
+ ldfont(unit); /* load the console font */
+ setup_input(unit); /* init the DUART */
+ break;
+
+ case QD_SET:
+ /*
+ * init the DUART and driver variables
+ */
+ init_shared(unit);
+ setup_input(unit);
+ break;
+
+ case QD_CLRSCRN:
+ /*
+ * clear the QDSS screen. (NOTE that this reinits the dragon)
+ */
+#ifdef notdef /* has caused problems and isn't necessary */
+ setup_dragon(unit);
+ clear_qd_screen(unit);
+#endif
+ break;
+
+ case QD_WTCURSOR:
+ /*
+ * load a cursor into template RAM
+ */
+ ldcursor(unit, (short *)datap);
+ break;
+
+ case QD_RDCURSOR:
+
+ temp = (short *) qdmap[unit].template;
+ /*
+ * cursor is 32 WORDS from the end of the 8k WORD...
+ * ...template space
+ */
+ temp += (8 * 1024) - 32;
+ for (i = 0; i < 32; ++i, datap += sizeof(short))
+ *(short *)datap = *temp++;
+ break;
+
+ case QD_POSCURSOR:
+ /*
+ * position the mouse cursor
+ */
+ dga = (struct dga *) qdmap[unit].dga;
+ pos = (struct _vs_cursor *) datap;
+ s = spl5();
+ dga->x_cursor = TRANX(pos->x);
+ dga->y_cursor = TRANY(pos->y);
+ eq_header[unit]->curs_pos.x = pos->x;
+ eq_header[unit]->curs_pos.y = pos->y;
+ splx(s);
+ break;
+
+ case QD_PRGCURSOR:
+ /*
+ * set the cursor acceleration factor
+ */
+ curs = (struct prg_cursor *) datap;
+ s = spl5();
+ qdflags[unit].curs_acc = curs->acc_factor;
+ qdflags[unit].curs_thr = curs->threshold;
+ splx(s);
+ break;
+
+ case QD_MAPDEVICE:
+ /*
+ * enable 'user write' to device pages
+ */
+ qdflags[unit].mapped |= MAPDEV;
+ qd = (struct qdmap *) &qdmap[unit];
+ /*
+ * enable user write to template RAM
+ */
+ mapix = VTOP((int)qd->template) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(TMPSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to registers
+ */
+ mapix = VTOP((int)qd->adder) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(REGSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to color maps
+ */
+ mapix = VTOP((int)qd->red) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ for (i = 0; i < btop(CLRSIZE); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ /*
+ * enable user write to DUART
+ */
+ mapix = VTOP((int)qd->duart) - VTOP(qvmem[0]);
+ ptep = (int *)(QVmap[0] + mapix);
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; /* duart page */
+
+ mtpr(TBIA, 0); /* invalidate translation buffer */
+
+ /*
+ * stuff qdmap structure in return buffer
+ */
+ bcopy((caddr_t)qd, datap, sizeof(struct qdmap));
+ break;
+
+ case QD_MAPIOBUF:
+ /*
+ * do setup for DMA by user process
+ *
+ * set 'user write enable' bits for DMA buffer
+ */
+ qdflags[unit].mapped |= MAPDMA;
+ ptep = (int *) ((VTOP(DMAheader[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ for (i = 0; i < btop(DMAbuf_size); i++, ptep++)
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* invalidate translation buffer */
+ /*
+ * set up QBUS map registers for DMA
+ */
+ DMAheader[unit]->QBAreg =
+ uballoc(0, (caddr_t)DMAheader[unit], DMAbuf_size, 0);
+ if (DMAheader[unit]->QBAreg == 0)
+ printf("qd%d: qdioctl: QBA setup error\n", unit);
+ Qbus_unmap[unit] = DMAheader[unit]->QBAreg;
+ DMAheader[unit]->QBAreg &= 0x3FFFF;
+ /*
+ * return I/O buf adr
+ */
+ *(int *)datap = (int) DMAheader[unit];
+ break;
+
+ case QD_MAPSCROLL:
+ /*
+ * map the shared scroll param area and enable scroll interpts
+ */
+ qdflags[unit].mapped |= MAPSCR;
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to scroll area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* invalidate translation buf */
+ scroll[unit]->status = 0;
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie |= FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ *(int *)datap = (int) scroll[unit]; /* return scroll area */
+ break;
+
+ case QD_UNMAPSCROLL:
+ /*
+ * unmap shared scroll param area and disable scroll intrpts
+ */
+ if (qdflags[unit].mapped & MAPSCR) {
+ qdflags[unit].mapped &= ~MAPSCR;
+ ptep = (int *) ((VTOP(scroll[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect 512 scroll param area
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ mtpr(TBIA, 0); /* smash CPU's translation buf */
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~FRAME_SYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ break;
+
+ case QD_MAPCOLOR:
+ /*
+ * map shared color map write buf and turn on vsync intrpt
+ */
+ qdflags[unit].mapped |= MAPCOLOR;
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to color map write buffer
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* clr CPU translation buf */
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie |= VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ /*
+ * return color area address
+ */
+ *(int *)datap = (int) color_buf[unit];
+ break;
+
+ case QD_UNMAPCOLOR:
+ /*
+ * unmap shared color map write buffer and kill VSYNC intrpts
+ */
+ if (qdflags[unit].mapped & MAPCOLOR) {
+ qdflags[unit].mapped &= ~MAPCOLOR;
+ ptep = (int *) ((VTOP(color_buf[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * re-protect color map write buffer
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_KW | PG_V;
+ mtpr(TBIA, 0);
+ adder = (struct adder *) qdmap[unit].adder;
+ qdflags[unit].adder_ie &= ~VSYNC;
+ adder->interrupt_enable = qdflags[unit].adder_ie;
+ }
+ break;
+
+ case QD_MAPEVENT:
+ /*
+ * give user write access to the event queue
+ */
+ qdflags[unit].mapped |= MAPEQ;
+ ptep = (int *) ((VTOP(eq_header[unit]) * 4)
+ + (mfpr(SBR) | 0x80000000));
+ /*
+ * allow user write to 1K event queue
+ */
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V; ptep++;
+ *ptep = (*ptep & ~PG_PROT) | PG_UW | PG_V;
+ mtpr(TBIA, 0); /* clr CPU translation buf */
+ /*
+ * return event queue address
+ */
+ *(int *)datap = (int)eq_header[unit];
+ break;
+
+ case QD_PRGKBD:
+ /*
+ * pass caller's programming commands to LK201
+ */
+ duart = (struct duart *)qdmap[unit].duart;
+ cmdbuf = (struct prgkbd *)datap; /* pnt to kbd cmd buf */
+ /*
+ * send command
+ */
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->cmd;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [1]\n", unit);
+ break;
+ }
+ /*
+ * send param1?
+ */
+ if (cmdbuf->cmd & LAST_PARAM)
+ break;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->param1;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [2]\n", unit);
+ break;
+ }
+ /*
+ * send param2?
+ */
+ if (cmdbuf->param1 & LAST_PARAM)
+ break;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmdbuf->param2;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [3]\n", unit);
+ break;
+ }
+ break;
+
+ case QD_PRGMOUSE:
+ /*
+ * pass caller's programming commands to the mouse
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = *datap;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [4]\n", unit);
+ }
+ break;
+
+ case QD_RDCONFIG:
+ /*
+ * get QDSS configuration word and return it
+ */
+ *(short *)datap = qdflags[unit].config;
+ break;
+
+ case QD_KERN_LOOP:
+ case QD_KERN_UNLOOP:
+ /*
+ * vestige from ultrix. BSD uses TIOCCONS to redirect
+ * kernel console output.
+ */
+ break;
+
+ case QD_PRGTABLET:
+ /*
+ * program the tablet
+ */
+ duart = (struct duart *) qdmap[unit].duart;
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = *datap;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd%d: qdioctl: timeout on XMT_RDY [5]\n", unit);
+ }
+ break;
+
+ case QD_PRGTABRES:
+ /*
+ * program the tablet report resolution factor
+ */
+ qdflags[unit].tab_res = *(short *)datap;
+ break;
+
+ default:
+ /*
+ * service tty ioctl's
+ */
+ if (!(minor_dev & 0x02)) {
+ tp = &qd_tty[minor_dev];
+ error =
+ (*linesw[tp->t_line].l_ioctl)(tp, cmd, datap, flags);
+ if (error >= 0) {
+ return(error);
+ }
+ error = ttioctl(tp, cmd, datap, flags);
+ if (error >= 0) {
+ return(error);
+ }
+ }
+ break;
+ }
+
+ return(0);
+
+} /* qdioctl */
+
+qdselect(dev, rw)
+ dev_t dev;
+ int rw;
+{
+ register s;
+ register unit;
+ register struct tty *tp;
+ u_int minor_dev = minor(dev);
+
+ s = spl5();
+ unit = minor_dev >> 2;
+
+ switch (rw) {
+ case FREAD:
+ if ((minor_dev & 0x03) == 2) {
+ /*
+ * this is a graphics device, so check for events
+ */
+ if(!(ISEMPTY(eq_header[unit]))) {
+ splx(s);
+ return(1);
+ }
+ qdrsel[unit] = u.u_procp;
+ qdflags[unit].selmask |= SEL_READ;
+ splx(s);
+ return(0);
+ } else {
+ /*
+ * this is a tty device
+ */
+ tp = &qd_tty[minor_dev];
+ if (ttnread(tp))
+ return(1);
+ tp->t_rsel = u.u_procp;
+ splx(s);
+ return(0);
+ }
+
+ case FWRITE:
+ if ((minor(dev) & 0x03) == 2) {
+ /*
+ * this is a graphics device, so check for dma buffers
+ */
+ if (DMA_ISEMPTY(DMAheader[unit]))
+ {
+ splx(s);
+ return(1);
+ }
+ qdrsel[unit] = u.u_procp;
+ qdflags[unit].selmask |= SEL_WRITE;
+ splx(s);
+ return(0);
+ } else {
+ /*
+ * this is a tty device
+ */
+ tp = &qd_tty[minor_dev];
+ if (tp->t_outq.c_cc <= tp->t_lowat)
+ return(1);
+ tp->t_wsel = u.u_procp;
+ splx(s);
+ return(0);
+ }
+ }
+ splx(s);
+ return(0);
+
+} /* qdselect() */
+
+extern qd_strategy();
+
+qdwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ register minor_dev;
+ register unit;
+
+ minor_dev = minor(dev);
+ unit = (minor_dev >> 2) & 0x07;
+
+ if (((minor_dev&0x03) != 0x02) && (qdflags[unit].inuse&CONS_DEV)) {
+ /*
+ * this is the console...
+ */
+ tp = &qd_tty[minor_dev];
+ return ((*linesw[tp->t_line].l_write)(tp, uio));
+ } else if (qdflags[unit].inuse & GRAPHIC_DEV) {
+ /*
+ * this is a DMA xfer from user space
+ */
+ return (physio(qd_strategy, &qdbuf[unit],
+ dev, B_WRITE, minphys, uio));
+ }
+ return (ENXIO);
+}
+
+qdread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ register minor_dev;
+ register unit;
+
+ minor_dev = minor(dev);
+ unit = (minor_dev >> 2) & 0x07;
+
+ if ((minor_dev & 0x03) != 0x02 && qdflags[unit].inuse & CONS_DEV) {
+ /*
+ * this is the console
+ */
+ tp = &qd_tty[minor_dev];
+ return ((*linesw[tp->t_line].l_read)(tp, uio));
+ } else if (qdflags[unit].inuse & GRAPHIC_DEV) {
+ /*
+ * this is a bitmap-to-processor xfer
+ */
+ return (physio(qd_strategy, &qdbuf[unit],
+ dev, B_READ, minphys, uio));
+ }
+ return (ENXIO);
+}
+
+/***************************************************************
+*
+* qd_strategy()... strategy routine to do DMA
+*
+***************************************************************/
+
+qd_strategy(bp)
+ register struct buf *bp;
+{
+ register struct dga *dga;
+ register struct adder *adder;
+ register unit;
+ int QBAreg;
+ int s;
+ int cookie;
+
+ unit = (minor(bp->b_dev) >> 2) & 0x07;
+
+ /*
+ * init pointers
+ */
+ if ((QBAreg = ubasetup(0, bp, 0)) == 0) {
+ printf("qd%d: qd_strategy: QBA setup error\n", unit);
+ goto STRAT_ERR;
+ }
+ dga = (struct dga *) qdmap[unit].dga;
+ s = spl5();
+ qdflags[unit].user_dma = -1;
+ dga->csr |= DMA_IE;
+ cookie = QBAreg & 0x3FFFF;
+ dga->adrs_lo = (short) cookie;
+ dga->adrs_hi = (short) (cookie >> 16);
+ dga->bytcnt_lo = (short) bp->b_bcount;
+ dga->bytcnt_hi = (short) (bp->b_bcount >> 16);
+
+ while (qdflags[unit].user_dma) {
+ sleep((caddr_t)&qdflags[unit].user_dma, QDPRIOR);
+ }
+ splx(s);
+ ubarelse(0, &QBAreg);
+ if (!(dga->csr & DMA_ERR)) {
+ iodone(bp);
+ return;
+ }
+
+STRAT_ERR:
+ adder = (struct adder *) qdmap[unit].adder;
+ adder->command = CANCEL; /* cancel adder activity */
+ dga->csr &= ~DMA_IE;
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ bp->b_flags |= B_ERROR; /* flag an error to physio() */
+
+ /*
+ * if DMA was running, flush spurious intrpt
+ */
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(DMAheader[unit]);
+ dga->csr |= DMA_IE;
+ }
+ iodone(bp);
+
+} /* qd_strategy */
+
+/*
+ * Start output to the console screen
+ */
+qdstart(tp)
+ register struct tty *tp;
+{
+ register which_unit, unit, c;
+ int s;
+
+ unit = minor(tp->t_dev);
+ which_unit = (unit >> 2) & 0x3;
+ unit &= 0x03;
+
+ s = spl5();
+
+ /*
+ * If it's currently active, or delaying, no need to do anything.
+ */
+ if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+ goto out;
+
+ /*
+ * Display chars until the queue is empty.
+ * Drop input from anything but the console
+ * device on the floor.
+ *
+ * XXX - this loop is done at spltty.
+ *
+ */
+ while (tp->t_outq.c_cc) {
+ c = getc(&tp->t_outq);
+ if (unit == 0)
+ blitc(which_unit, (u_char)c);
+ }
+ /*
+ * If there are sleepers, and output has drained below low
+ * water mark, wake up the sleepers.
+ */
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP){
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t) &tp->t_outq);
+ }
+ }
+
+ tp->t_state &= ~TS_BUSY;
+
+out:
+ splx(s);
+
+} /* qdstart */
+
+/*ARGSUSED*/
+void
+qdstop(tp, flag)
+ register struct tty *tp;
+ int flag;
+{
+ register int s;
+
+ s = spl5(); /* block intrpts during state modification */
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ else
+ tp->t_state &= ~TS_BUSY;
+ splx(s);
+}
+
+/*
+ * Output a character to the QDSS screen
+ */
+
+blitc(unit, chr)
+ register unit;
+ register u_char chr;
+{
+ register struct adder *adder;
+ register struct dga *dga;
+ register int i;
+ int nograph = !(qdflags[unit].inuse&GRAPHIC_DEV);
+ static short inescape[NQD];
+
+ adder = (struct adder *)qdmap[unit].adder;
+ dga = (struct dga *) qdmap[unit].dga;
+ /*
+ * BSD comment: this (&=0177) defeats the extended character
+ * set code for the glass tty, but if i had the time i would
+ * spend it ripping out the code completely. This driver
+ * is too big for its own good.
+ */
+ chr &= 0177;
+ /*
+ * Cursor addressing (so vi will work).
+ * Decode for "\E=%.%." cursor motion description.
+ * Corresponds to type "qdcons" in /etc/termcap:
+ *
+ * qd|qdss|qdcons|qdss glass tty (4.4 BSD):\
+ * :am:do=^J:le=^H:bs:cm=\E=%.%.:cl=1^Z:co#128:li#57::nd=^L:up=^K:
+ *
+ */
+ if (inescape[unit] && nograph) {
+ switch (inescape[unit]++) {
+ case 1:
+ if (chr != '=') {
+ /* abort escape sequence */
+ inescape[unit] = 0;
+ blitc(unit, chr);
+ }
+ return;
+ case 2:
+ /* position row */
+ cursor[unit].y = CHAR_HEIGHT * chr;
+ if (cursor[unit].y > 863 - CHAR_HEIGHT)
+ cursor[unit].y = 863 - CHAR_HEIGHT;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ return;
+ case 3:
+ /* position column */
+ cursor[unit].x = CHAR_WIDTH * chr;
+ if (cursor[unit].x > 1024 - CHAR_WIDTH)
+ cursor[unit].x = 1023 - CHAR_WIDTH;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ inescape[unit] = 0;
+ return;
+ default:
+ inescape[unit] = 0;
+ blitc(unit, chr);
+ }
+ }
+
+ switch (chr) {
+ case '\r': /* return char */
+ cursor[unit].x = 0;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ return;
+
+ case '\t': /* tab char */
+ for (i = 8 - ((cursor[unit].x >> 3) & 0x07); i > 0; --i) {
+ blitc(unit, ' ');
+ }
+ return;
+
+ case '\n': /* line feed char */
+ if ((cursor[unit].y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) {
+ if (nograph) {
+ cursor[unit].y -= CHAR_HEIGHT;
+ scroll_up(adder);
+ } else
+ cursor[unit].y = 0;
+ }
+ if (nograph)
+ dga->y_cursor = TRANY(cursor[unit].y);
+ return;
+
+ case '\b': /* backspace char */
+ if (cursor[unit].x > 0) {
+ cursor[unit].x -= CHAR_WIDTH;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ }
+ return;
+ case CTRL('k'): /* cursor up */
+ if (nograph && cursor[unit].y > 0) {
+ cursor[unit].y -= CHAR_HEIGHT;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case CTRL('^'): /* home cursor */
+ if (nograph) {
+ cursor[unit].x = 0;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ cursor[unit].y = 0;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case CTRL('l'): /* cursor right */
+ if (nograph && cursor[unit].x < 1023 - CHAR_WIDTH) {
+ cursor[unit].x += CHAR_WIDTH;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ }
+ return;
+
+ case CTRL('z'): /* clear screen */
+ if (nograph) {
+ setup_dragon(unit);
+ clear_qd_screen(unit);
+ /* home cursor - termcap seems to assume this */
+ cursor[unit].x = 0;
+ dga->x_cursor = TRANX(cursor[unit].x);
+ cursor[unit].y = 0;
+ dga->y_cursor = TRANY(cursor[unit].y);
+ }
+ return;
+
+ case '\033': /* start escape sequence */
+ if (nograph)
+ inescape[unit] = 1;
+ return;
+
+ default:
+ if ((chr < ' ') || (chr > '~'))
+ return;
+ }
+ /*
+ * setup VIPER operand control registers
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001); /* select plane #0 */
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FE); /* select other planes */
+ write_ID(adder, SRC1_OCR_B,
+ EXT_SOURCE | INT_NONE | NO_ID | BAR_SHIFT_DELAY);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */
+ write_ID(adder, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 1);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ adder->x_clip_min = 0;
+ adder->x_clip_max = 1024;
+ adder->y_clip_min = 0;
+ adder->y_clip_max = 864;
+ /*
+ * load DESTINATION origin and vectors
+ */
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+ adder->destination_x = cursor[unit].x;
+ adder->fast_dest_dx = CHAR_WIDTH;
+ adder->destination_y = cursor[unit].y;
+ adder->slow_dest_dy = CHAR_HEIGHT;
+ /*
+ * load SOURCE origin and vectors
+ */
+ if ((chr - ' ') > (CHARS - 1)) {
+ printf("Invalid character (x)%x in blitc\n",chr);
+ chr = ' ';
+ }
+ /*
+ * X position is modulo the number of characters per line
+ */
+ adder->source_1_x = FONT_X +
+ (((chr - ' ') % (MAX_SCREEN_X/CHAR_WIDTH)) * CHAR_WIDTH);
+ /*
+ * Point to either first or second row
+ */
+ adder->source_1_y = 2048 - 15 *
+ (((chr - ' ')/(MAX_SCREEN_X/CHAR_WIDTH)) + 1);
+ adder->source_1_dx = CHAR_WIDTH;
+ adder->source_1_dy = CHAR_HEIGHT;
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
+ /*
+ * update console cursor coordinates
+ */
+ cursor[unit].x += CHAR_WIDTH;
+ if (nograph)
+ dga->x_cursor = TRANX(cursor[unit].x);
+ if (cursor[unit].x > (1024 - CHAR_WIDTH)) {
+ blitc(unit, '\r');
+ blitc(unit, '\n');
+ }
+
+} /* blitc */
+
+qdreset() { }
+
+/*
+ * INTERRUPT SERVICE ROUTINES
+ */
+
+/*
+ * Service "DMA DONE" interrupt condition
+ */
+qddint(qd)
+ register qd;
+{
+ register struct DMAreq_header *header;
+ register struct DMAreq *request;
+ register struct dga *dga;
+ struct adder *adder;
+ int cookie; /* DMA adrs for QDSS */
+
+ (void)spl4(); /* allow interval timer in */
+
+ /*
+ * init pointers
+ */
+ header = DMAheader[qd]; /* register for optimization */
+ dga = (struct dga *) qdmap[qd].dga;
+ adder = (struct adder *) qdmap[qd].adder;
+
+ /*
+ * if this interrupt flagged as bogus for interrupt flushing purposes..
+ */
+ if (DMA_ISIGNORE(header)) {
+ DMA_CLRIGNORE(header);
+ return;
+ }
+
+ /*
+ * dump a DMA hardware error message if appropriate
+ */
+ if (dga->csr & DMA_ERR) {
+
+ if (dga->csr & PARITY_ERR)
+ printf("qd%d: qddint: DMA hardware parity fault.\n", qd);
+
+ if (dga->csr & BUS_ERR)
+ printf("qd%d: qddint: DMA hardware bus error.\n", qd);
+ }
+
+ /*
+ * if this was a DMA from user space...
+ */
+ if (qdflags[qd].user_dma) {
+ qdflags[qd].user_dma = 0;
+ wakeup((caddr_t)&qdflags[qd].user_dma);
+ return;
+ }
+
+ /*
+ * if we're doing DMA request queue services, field the error condition
+ */
+ if (dga->csr & DMA_ERR) {
+
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ dga->csr |= DMA_ERR; /* clear error condition */
+ adder->command = CANCEL; /* cancel adder activity */
+
+ DMA_SETERROR(header); /* flag error in header status word */
+ DMA_CLRACTIVE(header);
+ header->DMAreq[header->oldest].DMAdone |= HARD_ERROR;
+ header->newest = header->oldest;
+ header->used = 0;
+
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+
+ if (dga->bytcnt_lo != 0) {
+ dga->bytcnt_lo = 0;
+ dga->bytcnt_hi = 0;
+ DMA_SETIGNORE(header);
+ }
+ return;
+ }
+
+ /*
+ * if the DMA request queue is now becoming non-full,
+ * wakeup "select" client.
+ */
+ if (DMA_ISFULL(header)) {
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+ }
+
+ header->DMAreq[header->oldest].DMAdone |= REQUEST_DONE;
+ QDlast_DMAtype = header->DMAreq[header->oldest].DMAtype;
+
+ /* check for unexpected interrupt */
+ if (DMA_ISEMPTY(header))
+ return;
+
+ DMA_GETEND(header); /* update request queue indices */
+
+ /*
+ * if no more DMA pending, wake up "select" client and exit
+ */
+ if (DMA_ISEMPTY(header)) {
+
+ if (qdrsel[qd] && qdflags[qd].selmask & SEL_WRITE) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_WRITE;
+ }
+
+ DMA_CLRACTIVE(header); /* flag DMA done */
+ return;
+ }
+
+ /*
+ * initiate next DMA xfer
+ */
+ request = DMA_GETBEGIN(header);
+ if (request->DMAtype != QDlast_DMAtype) {
+ dga->csr &= ~0x0600; /* halt DMA (reset fifo) */
+ adder->command = CANCEL; /* cancel adder activity */
+ }
+
+
+ switch (request->DMAtype) {
+
+ case DISPLIST:
+ if (request->DMAtype != QDlast_DMAtype) {
+ dga->csr |= DL_ENB;
+ dga->csr &= ~(BTOP_ENB | BYTE_DMA);
+ }
+ break;
+
+ case PTOB:
+ if (request->DMAtype != QDlast_DMAtype) {
+ if (request->DMAdone & BYTE_PACK)
+ dga->csr |= (PTOB_ENB | BYTE_DMA);
+ else {
+ dga->csr |= PTOB_ENB;
+ dga->csr &= ~BYTE_DMA;
+ }
+ }
+ break;
+
+ case BTOP:
+ if (request->DMAtype != QDlast_DMAtype) {
+ if (request->DMAdone & BYTE_PACK) {
+ dga->csr &= ~DL_ENB;
+ dga->csr |= (BTOP_ENB | BYTE_DMA);
+ }
+ else {
+ dga->csr |= BTOP_ENB;
+ dga->csr &= ~(BYTE_DMA | DL_ENB);
+ }
+ }
+ break;
+ default:
+ printf("qd%d: qddint: illegal DMAtype parameter.\n", qd);
+ DMA_CLRACTIVE(header); /* flag DMA done */
+ return;
+ }
+
+ if (request->DMAdone & COUNT_ZERO) {
+ dga->csr &= ~SET_DONE_FIFO;
+ }
+ else if (request->DMAdone & FIFO_EMPTY) {
+ dga->csr |= SET_DONE_FIFO;
+ }
+
+ if (request->DMAdone & WORD_PACK)
+ dga->csr &= ~BYTE_DMA;
+ else if (request->DMAdone & BYTE_PACK)
+ dga->csr |= BYTE_DMA;
+
+ dga->csr |= DMA_IE;
+ QDlast_DMAtype = request->DMAtype;
+
+ cookie = ((int)request->bufp - (int)header) + (int)header->QBAreg;
+
+ dga->adrs_lo = (short) cookie;
+ dga->adrs_hi = (short) (cookie >> 16);
+
+ dga->bytcnt_lo = (short) request->length;
+ dga->bytcnt_hi = (short) (request->length >> 16);
+
+ return;
+}
+
+/*
+ * ADDER interrupt service routine
+ */
+qdaint(qd)
+ register qd;
+{
+ register struct adder *adder;
+ struct color_buf *cbuf;
+ int i;
+ register struct rgb *rgbp;
+ register short *red;
+ register short *green;
+ register short *blue;
+
+ (void)spl4(); /* allow interval timer in */
+
+ adder = (struct adder *) qdmap[qd].adder;
+
+ /*
+ * service the vertical blank interrupt (VSYNC bit) by loading
+ * any pending color map load request
+ */
+ if (adder->status & VSYNC) {
+ adder->status &= ~VSYNC; /* clear the interrupt */
+ cbuf = color_buf[qd];
+ if (cbuf->status & LOAD_COLOR_MAP) {
+
+ red = (short *) qdmap[qd].red;
+ green = (short *) qdmap[qd].green;
+ blue = (short *) qdmap[qd].blue;
+
+ for (i = cbuf->count, rgbp = cbuf->rgb;
+ --i >= 0; rgbp++) {
+ red[rgbp->offset] = (short) rgbp->red;
+ green[rgbp->offset] = (short) rgbp->green;
+ blue[rgbp->offset] = (short) rgbp->blue;
+ }
+
+ cbuf->status &= ~LOAD_COLOR_MAP;
+ }
+ }
+
+ /*
+ * service the scroll interrupt (FRAME_SYNC bit)
+ */
+ if (adder->status & FRAME_SYNC) {
+ adder->status &= ~FRAME_SYNC; /* clear the interrupt */
+
+ if (scroll[qd]->status & LOAD_REGS) {
+
+ for (i = 1000, adder->status = 0; i > 0 &&
+ !(adder->status&ID_SCROLL_READY); --i)
+ ;
+
+ if (i == 0) {
+ printf("qd%d: qdaint: timeout on ID_SCROLL_READY\n",
+ qd);
+ return;
+ }
+
+ adder->ID_scroll_data = scroll[qd]->viper_constant;
+ adder->ID_scroll_command = ID_LOAD | SCROLL_CONSTANT;
+
+ adder->y_scroll_constant =
+ scroll[qd]->y_scroll_constant;
+ adder->y_offset_pending = scroll[qd]->y_offset;
+
+ if (scroll[qd]->status & LOAD_INDEX) {
+
+ adder->x_index_pending =
+ scroll[qd]->x_index_pending;
+ adder->y_index_pending =
+ scroll[qd]->y_index_pending;
+ }
+
+ scroll[qd]->status = 0x00;
+ }
+ }
+}
+
+/*
+ * DUART input interrupt service routine
+ *
+ * XXX - this routine should be broken out - it is essentially
+ * straight line code.
+ */
+
+qdiint(qd)
+ register qd;
+{
+ register struct _vs_event *event;
+ register struct qdinput *eqh;
+ struct dga *dga;
+ struct duart *duart;
+ struct mouse_report *new_rep;
+ struct uba_device *ui;
+ struct tty *tp;
+ u_short chr;
+ u_short status;
+ u_short data;
+ u_short key;
+ char do_wakeup = 0; /* flag to do a select wakeup call */
+ char a, b, c; /* mouse button test variables */
+
+ (void)spl4(); /* allow interval timer in */
+
+ eqh = eq_header[qd]; /* optimized as a register */
+ new_rep = &current_rep[qd];
+ duart = (struct duart *) qdmap[qd].duart;
+
+ /*
+ * if the graphic device is turned on..
+ */
+ if (qdflags[qd].inuse & GRAPHIC_DEV) {
+ /*
+ * empty DUART
+ */
+ while (duart->statusA&RCV_RDY || duart->statusB&RCV_RDY) {
+ /*
+ * pick up LK-201 input (if any)
+ */
+ if (duart->statusA&RCV_RDY) {
+
+ /* if error condition, then reset it */
+
+ if (duart->statusA&0x70) {
+ duart->cmdA = 0x40;
+ continue;
+ }
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf(
+ "qd%d: qdiint: event queue overflow\n",
+ qd);
+ break;
+ }
+
+ /*
+ * Check for various keyboard errors */
+
+ key = duart->dataA & 0xFF;
+
+ if (key==LK_POWER_ERROR ||
+ key==LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR ||
+ key == LK_OUTPUT_ERROR) {
+ printf(
+ "qd%d: qdiint: keyboard error, code = %x\n",
+ qd,key);
+ return;
+ }
+
+ if (key < LK_LOWEST)
+ return;
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ event->vse_key = key;
+ event->vse_key &= 0x00FF;
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+ event->vse_time = TOY;
+ event->vse_type = VSE_BUTTON;
+ event->vse_direction = VSE_KBTRAW;
+ event->vse_device = VSE_DKB;
+ }
+
+ /*
+ * pick up the mouse input (if any) */
+
+ if ((status = duart->statusB) & RCV_RDY &&
+ qdflags[qd].pntr_id == MOUSE_ID) {
+
+ if (status & 0x70) {
+ duart->cmdB = 0x40;
+ continue;
+ }
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf(
+ "qd%d: qdiint: event queue overflow\n",
+ qd);
+ break;
+ }
+
+ data = duart->dataB; /* get report byte */
+ ++new_rep->bytcnt; /* bump report byte count */
+
+ /*
+ * if 1st byte of report.. */
+
+ if ( data & START_FRAME) {
+ new_rep->state = data;
+ if (new_rep->bytcnt > 1) {
+ /* start of new frame */
+ new_rep->bytcnt = 1;
+ /* ..continue looking */
+ continue;
+ }
+ }
+
+ /*
+ * if 2nd byte of report.. */
+
+ else if (new_rep->bytcnt == 2) {
+ new_rep->dx = data & 0x00FF;
+ }
+
+ /*
+ * if 3rd byte of report, load input event queue */
+
+ else if (new_rep->bytcnt == 3) {
+
+ new_rep->dy = data & 0x00FF;
+ new_rep->bytcnt = 0;
+
+ /*
+ * if mouse position has changed.. */
+
+ if (new_rep->dx != 0 || new_rep->dy != 0) {
+
+ /*
+ * calculate acceleration factor, if needed */
+
+ if (qdflags[qd].curs_acc > ACC_OFF) {
+
+ if (qdflags[qd].curs_thr <= new_rep->dx)
+ new_rep->dx +=
+ (new_rep->dx - qdflags[qd].curs_thr)
+ * qdflags[qd].curs_acc;
+
+ if (qdflags[qd].curs_thr <= new_rep->dy)
+ new_rep->dy +=
+ (new_rep->dy - qdflags[qd].curs_thr)
+ * qdflags[qd].curs_acc;
+ }
+
+ /*
+ * update cursor position coordinates */
+
+ if (new_rep->state & X_SIGN) {
+ eqh->curs_pos.x += new_rep->dx;
+ if (eqh->curs_pos.x > 1023)
+ eqh->curs_pos.x = 1023;
+ }
+ else {
+ eqh->curs_pos.x -= new_rep->dx;
+ if (eqh->curs_pos.x < -15)
+ eqh->curs_pos.x = -15;
+ }
+
+ if (new_rep->state & Y_SIGN) {
+ eqh->curs_pos.y -= new_rep->dy;
+ if (eqh->curs_pos.y < -15)
+ eqh->curs_pos.y = -15;
+ }
+ else {
+ eqh->curs_pos.y += new_rep->dy;
+ if (eqh->curs_pos.y > 863)
+ eqh->curs_pos.y = 863;
+ }
+
+ /*
+ * update cursor screen position */
+
+ dga = (struct dga *) qdmap[qd].dga;
+ dga->x_cursor = TRANX(eqh->curs_pos.x);
+ dga->y_cursor = TRANY(eqh->curs_pos.y);
+
+ /*
+ * if cursor is in the box, no event report */
+
+ if (eqh->curs_pos.x <= eqh->curs_box.right &&
+ eqh->curs_pos.x >= eqh->curs_box.left &&
+ eqh->curs_pos.y >= eqh->curs_box.top &&
+ eqh->curs_pos.y <= eqh->curs_box.bottom ) {
+ goto GET_MBUTTON;
+ }
+
+ /*
+ * report the mouse motion event */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_MOUSE; /* mouse */
+ event->vse_type = VSE_MMOTION; /* pos changed */
+ event->vse_key = 0;
+ event->vse_direction = 0;
+ event->vse_time = TOY; /* time stamp */
+ }
+
+GET_MBUTTON:
+ /*
+ * if button state has changed */
+
+ a = new_rep->state & 0x07; /*mask nonbutton bits */
+ b = last_rep[qd].state & 0x07;
+
+ if (a ^ b) {
+
+ for ( c = 1; c < 8; c <<= 1) {
+
+ if (!( c & (a ^ b))) /* this button change? */
+ continue;
+
+ /* event queue full? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n", qd);
+ break;
+ }
+
+ event = PUTBEGIN(eqh); /* get new event */
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request select wakeup */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_MOUSE; /* mouse */
+ event->vse_type = VSE_BUTTON; /* new button */
+ event->vse_time = TOY; /* time stamp */
+
+ /* flag changed button and if up or down */
+
+ if (c == RIGHT_BUTTON)
+ event->vse_key = VSE_RIGHT_BUTTON;
+ else if (c == MIDDLE_BUTTON)
+ event->vse_key = VSE_MIDDLE_BUTTON;
+ else if (c == LEFT_BUTTON)
+ event->vse_key = VSE_LEFT_BUTTON;
+
+ /* set bit = button depressed */
+
+ if (c & a)
+ event->vse_direction = VSE_KBTDOWN;
+ else
+ event->vse_direction = VSE_KBTUP;
+ }
+ }
+
+ /* refresh last report */
+
+ last_rep[qd] = current_rep[qd];
+
+ } /* get last byte of report */
+ } else if ((status = duart->statusB)&RCV_RDY &&
+ qdflags[qd].pntr_id == TABLET_ID) {
+ /*
+ * pickup tablet input, if any
+ */
+ if (status&0x70) {
+ duart->cmdB = 0x40;
+ continue;
+ }
+ /*
+ * event queue full now? (overflow condition)
+ */
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n", qd);
+ break;
+ }
+
+ data = duart->dataB; /* get report byte */
+ ++new_rep->bytcnt; /* bump report byte count */
+
+ /*
+ * if 1st byte of report.. */
+
+ if (data & START_FRAME) {
+ new_rep->state = data;
+ if (new_rep->bytcnt > 1) {
+ new_rep->bytcnt = 1; /* start of new frame */
+ continue; /* ..continue looking */
+ }
+ }
+
+ /*
+ * if 2nd byte of report.. */
+
+ else if (new_rep->bytcnt == 2) {
+ new_rep->dx = data & 0x3F;
+ }
+
+ /*
+ * if 3rd byte of report.. */
+
+ else if (new_rep->bytcnt == 3) {
+ new_rep->dx |= (data & 0x3F) << 6;
+ }
+
+ /*
+ * if 4th byte of report.. */
+
+ else if (new_rep->bytcnt == 4) {
+ new_rep->dy = data & 0x3F;
+ }
+
+ /*
+ * if 5th byte of report, load input event queue */
+
+ else if (new_rep->bytcnt == 5) {
+
+ new_rep->dy |= (data & 0x3F) << 6;
+ new_rep->bytcnt = 0;
+
+ /*
+ * update cursor position coordinates */
+
+ new_rep->dx /= qdflags[qd].tab_res;
+ new_rep->dy = (2200 - new_rep->dy)
+ / qdflags[qd].tab_res;
+
+ if (new_rep->dx > 1023) {
+ new_rep->dx = 1023;
+ }
+ if (new_rep->dy > 863) {
+ new_rep->dy = 863;
+ }
+
+ /*
+ * report an event if the puck/stylus has moved
+ */
+
+ if (eqh->curs_pos.x != new_rep->dx ||
+ eqh->curs_pos.y != new_rep->dy) {
+
+ eqh->curs_pos.x = new_rep->dx;
+ eqh->curs_pos.y = new_rep->dy;
+
+ /*
+ * update cursor screen position */
+
+ dga = (struct dga *) qdmap[qd].dga;
+ dga->x_cursor = TRANX(eqh->curs_pos.x);
+ dga->y_cursor = TRANY(eqh->curs_pos.y);
+
+ /*
+ * if cursor is in the box, no event report
+ */
+
+ if (eqh->curs_pos.x <= eqh->curs_box.right &&
+ eqh->curs_pos.x >= eqh->curs_box.left &&
+ eqh->curs_pos.y >= eqh->curs_box.top &&
+ eqh->curs_pos.y <= eqh->curs_box.bottom ) {
+ goto GET_TBUTTON;
+ }
+
+ /*
+ * report the tablet motion event */
+
+ event = PUTBEGIN(eqh);
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_TABLET; /* tablet */
+ /*
+ * right now, X handles tablet motion the same
+ * as mouse motion
+ */
+ event->vse_type = VSE_MMOTION; /* pos changed */
+ event->vse_key = 0;
+ event->vse_direction = 0;
+ event->vse_time = TOY; /* time stamp */
+ }
+GET_TBUTTON:
+ /*
+ * if button state has changed */
+
+ a = new_rep->state & 0x1E; /* mask nonbutton bits */
+ b = last_rep[qd].state & 0x1E;
+
+ if (a ^ b) {
+
+ /* event queue full now? (overflow condition) */
+
+ if (ISFULL(eqh) == TRUE) {
+ printf("qd%d: qdiint: event queue overflow\n",qd);
+ break;
+ }
+
+ event = PUTBEGIN(eqh); /* get new event */
+ PUTEND(eqh);
+
+ ++do_wakeup; /* request a select wakeup call */
+
+ event->vse_x = eqh->curs_pos.x;
+ event->vse_y = eqh->curs_pos.y;
+
+ event->vse_device = VSE_TABLET; /* tablet */
+ event->vse_type = VSE_BUTTON; /* button changed */
+ event->vse_time = TOY; /* time stamp */
+
+ /* define the changed button and if up or down */
+
+ for ( c = 1; c <= 0x10; c <<= 1) {
+ if (c & (a ^ b)) {
+ if (c == T_LEFT_BUTTON)
+ event->vse_key = VSE_T_LEFT_BUTTON;
+ else if (c == T_FRONT_BUTTON)
+ event->vse_key = VSE_T_FRONT_BUTTON;
+ else if (c == T_RIGHT_BUTTON)
+ event->vse_key = VSE_T_RIGHT_BUTTON;
+ else if (c == T_BACK_BUTTON)
+ event->vse_key = VSE_T_BACK_BUTTON;
+ break;
+ }
+ }
+
+ /* set bit = button depressed */
+
+ if (c & a)
+ event->vse_direction = VSE_KBTDOWN;
+ else
+ event->vse_direction = VSE_KBTUP;
+ }
+
+ /* refresh last report */
+
+ last_rep[qd] = current_rep[qd];
+
+ } /* get last byte of report */
+ } /* pick up tablet input */
+
+ } /* while input available.. */
+
+ /*
+ * do select wakeup
+ */
+ if (qdrsel[qd] && do_wakeup && qdflags[qd].selmask & SEL_READ) {
+ selwakeup(qdrsel[qd], 0);
+ qdrsel[qd] = 0;
+ qdflags[qd].selmask &= ~SEL_READ;
+ do_wakeup = 0;
+ }
+ } else {
+ /*
+ * if the graphic device is not turned on, this is console input
+ */
+ if (qdpolling)
+ return;
+ ui = qdinfo[qd];
+ if (ui == 0 || ui->ui_alive == 0)
+ return;
+
+ tp = &qd_tty[qd << 2];
+
+ /*
+ * Get a character from the keyboard.
+ */
+ while (duart->statusA&RCV_RDY) {
+ key = duart->dataA;
+ key &= 0xFF;
+ /*
+ * Check for various keyboard errors
+ */
+ if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
+ printf("qd%d: qdiint: Keyboard error, code = %x\n",qd,key);
+ return;
+ }
+
+ if (key < LK_LOWEST)
+ return;
+
+ /*
+ * See if its a state change key */
+
+ switch (key) {
+
+ case LOCK:
+ q_keyboard.lock ^= 0xffff; /* toggle */
+ if (q_keyboard.lock)
+ (void)led_control(qd, LK_LED_ENABLE,
+ LK_LED_LOCK);
+ else
+ (void)led_control(qd, LK_LED_DISABLE,
+ LK_LED_LOCK);
+ return;
+
+ case SHIFT:
+ q_keyboard.shift ^= 0xFFFF;
+ return;
+
+ case CNTRL:
+ q_keyboard.cntrl ^= 0xFFFF;
+ return;
+
+ case ALLUP:
+ q_keyboard.cntrl = 0;
+ q_keyboard.shift = 0;
+ return;
+
+ case REPEAT:
+ chr = q_keyboard.last;
+ break;
+
+ /*
+ * Test for cntrl characters. If set, see if the character
+ * is elligible to become a control character. */
+
+ default:
+
+ if (q_keyboard.cntrl) {
+ chr = q_key[key];
+ if (chr >= ' ' && chr <= '~')
+ chr &= 0x1F;
+ else if (chr >= 0xA1 && chr <= 0xFE)
+ chr &= 0x9F;
+ }
+ else if( q_keyboard.lock || q_keyboard.shift )
+ chr = q_shift_key[key];
+ else
+ chr = q_key[key];
+ break;
+ }
+
+ q_keyboard.last = chr;
+
+ /*
+ * Check for special function keys */
+
+ if (chr & 0x100) {
+ char *string;
+ string = q_special[chr & 0x7F];
+ while(*string)
+ (*linesw[tp->t_line].l_rint)(*string++, tp);
+ }
+ else {
+#ifdef KADB
+ if (!kdbrintr(chr&0177, tp))
+#endif
+ (*linesw[tp->t_line].l_rint)(chr&0177, tp);
+ }
+ }
+ }
+} /* qdiint */
+
+/*
+ *
+ * Clear the QDSS screen
+ *
+ * >>> NOTE <<<
+ *
+ * This code requires that certain adder initialization be valid. To
+ * assure that this requirement is satisfied, this routine should be
+ * called only after calling the "setup_dragon()" function.
+ *
+ * Clear the bitmap a piece at a time. Since the fast scroll clear
+ * only clears the current displayed portion of the bitmap put a
+ * temporary value in the y limit register so we can access whole
+ * bitmap
+ *
+ */
+clear_qd_screen(unit)
+ int unit;
+{
+ register struct adder *adder;
+ adder = (struct adder *) qdmap[unit].adder;
+
+ adder->x_limit = 1024;
+ adder->y_limit = 2048 - CHAR_HEIGHT;
+ adder->y_offset_pending = 0;
+#define WSV (void)wait_status(adder, VSYNC); (void)wait_status(adder, VSYNC)
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 864;
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 1728;
+ WSV;
+ adder->y_scroll_constant = SCROLL_ERASE;
+ WSV;
+ adder->y_offset_pending = 0; /* back to normal */
+ WSV;
+ adder->x_limit = MAX_SCREEN_X;
+ adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT;
+#undef WSV
+
+} /* clear_qd_screen */
+
+/*
+ * kernel console output to the glass tty
+ */
+qdputc(chr)
+ register char chr;
+{
+
+ /*
+ * if system is now physical, forget it (ie: crash DUMP)
+ */
+ if ((mfpr(MAPEN) & 1) == 0)
+ return;
+
+ blitc(0, (u_char)(chr & 0xff));
+ if ((chr & 0177) == '\n')
+ blitc(0, '\r');
+
+} /* qdputc */
+
+/*
+ * load the mouse cursor's template RAM bitmap
+ */
+ldcursor(unit, bitmap)
+ int unit;
+ register short *bitmap;
+{
+ register struct dga *dga;
+ register short *temp;
+ register int i;
+ int curs;
+
+ dga = (struct dga *) qdmap[unit].dga;
+ temp = (short *) qdmap[unit].template;
+
+ if (dga->csr & CURS_ENB) { /* if the cursor is enabled.. */
+ curs = -1; /* ..note that.. */
+ dga->csr &= ~CURS_ENB; /* ..and shut it off */
+ } else
+ curs = 0;
+
+ dga->csr &= ~CURS_ENB; /* shut off the cursor */
+
+ temp += (8 * 1024) - 32; /* cursor is 32 WORDS from the end */
+ /* ..of the 8k WORD template space */
+ for (i = 0; i < 32; ++i)
+ *temp++ = *bitmap++;
+
+ if (curs) { /* if cursor was enabled.. */
+ dga->csr |= CURS_ENB; /* ..turn it back on */
+ }
+
+} /* ldcursor */
+
+/*
+ * Put the console font in the QDSS off-screen memory
+ */
+ldfont(unit)
+ int unit;
+{
+ register struct adder *adder;
+
+ register i, j, k, max_chars_line;
+ register short packed;
+
+ adder = (struct adder *) qdmap[unit].adder;
+
+ /*
+ * setup VIPER operand control registers
+ */
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, SRC2_OCR_B,
+ EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, DST_OCR_B,
+ EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+
+ adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+
+ /*
+ * load destination data
+ */
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+
+ adder->destination_x = FONT_X;
+ adder->destination_y = FONT_Y;
+#if FONT_WIDTH > MAX_SCREEN_X
+ adder->fast_dest_dx = MAX_SCREEN_X;
+#else
+ adder->fast_dest_dx = FONT_WIDTH;
+#endif
+ adder->slow_dest_dy = CHAR_HEIGHT;
+
+ /*
+ * setup for processor to bitmap xfer */
+
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ adder->cmd = PBT | OCRB | 2 | DTE | 2;
+
+ /*
+ * Figure out how many characters can be stored on one "line" of
+ * offscreen memory.
+ */
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+ if ((CHARS/2 + CHARS%2) < max_chars_line)
+ max_chars_line = CHARS/2 + CHARS%2;
+
+ /*
+ * iteratively do the processor to bitmap xfer */
+
+ for (i = 0; i < ROWS; ++i) {
+
+ /* PTOB a scan line */
+
+ for (j = 0, k = i; j < max_chars_line; ++j) {
+ /* PTOB one scan of a char cell */
+
+ packed = q_font[k];
+ k += ROWS;
+ packed |= ((short)q_font[k] << 8);
+ k += ROWS;
+
+ (void)wait_status(adder, TX_READY);
+ adder->id_data = packed;
+ }
+ }
+
+ /*
+ * (XXX XXX XXX - should remove)
+ *
+ * Copy the second row of characters. Subtract the first
+ * row from the total number. Divide this quantity by 2
+ * because 2 chars are stored in a short in the PTOB loop
+ * below. Figure out how many characters can be stored on
+ * one "line" of offscreen memory
+ */
+
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+ if ((CHARS/2 + CHARS%2) < max_chars_line)
+ return;
+ max_chars_line = (CHARS/2 + CHARS%2) - max_chars_line; /* 95 - 64 */
+ /* Paranoia check to see if 3rd row may be needed */
+ if (max_chars_line > (MAX_SCREEN_X/(CHAR_WIDTH*2)))
+ max_chars_line = MAX_SCREEN_X/(CHAR_WIDTH*2);
+
+ adder->destination_x = FONT_X;
+ adder->destination_y = FONT_Y - CHAR_HEIGHT;
+ adder->fast_dest_dx = max_chars_line * CHAR_WIDTH * 2;
+ adder->slow_dest_dy = CHAR_HEIGHT;
+
+ /*
+ * setup for processor to bitmap xfer
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ adder->cmd = PBT | OCRB | 2 | DTE | 2;
+
+ /*
+ * iteratively do the processor to bitmap xfer
+ */
+ for (i = 0; i < ROWS; ++i) {
+ /*
+ * PTOB a scan line
+ */
+ for (j = 0, k = i; j < max_chars_line; ++j) {
+ /*
+ * PTOB one scan of a char cell
+ */
+ packed = q_font[k + FONT_OFFSET];
+ k += ROWS;
+ packed |= ((short)q_font[k + FONT_OFFSET] << 8);
+ k += ROWS;
+ (void)wait_status(adder, TX_READY);
+ adder->id_data = packed;
+ }
+ }
+
+} /* ldfont */
+
+qdpoll(onoff)
+{
+ qdpolling = onoff;
+}
+
+/*
+ * Get a character from the LK201 (polled)
+ */
+qdgetc()
+{
+ register short key;
+ register char chr;
+ register struct duart *duart;
+
+ duart = (struct duart *) qdmap[0].duart;
+
+ /*
+ * Get a character from the keyboard.
+ */
+LOOP:
+ while (!(duart->statusA&RCV_RDY))
+ ;
+
+ key = duart->dataA;
+ key &= 0xFF;
+
+ /*
+ * Check for various keyboard errors */
+
+ if (key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
+ printf("Keyboard error, code = %x\n", key);
+ return(0);
+ }
+
+ if (key < LK_LOWEST)
+ return(0);
+
+ /*
+ * See if its a state change key
+ */
+ switch (key) {
+
+ case LOCK:
+ q_keyboard.lock ^= 0xffff; /* toggle */
+ if (q_keyboard.lock)
+ (void)led_control(0, LK_LED_ENABLE, LK_LED_LOCK);
+ else
+ (void)led_control(0, LK_LED_DISABLE, LK_LED_LOCK);
+ goto LOOP;
+
+ case SHIFT:
+ q_keyboard.shift ^= 0xFFFF;
+ goto LOOP;
+
+ case CNTRL:
+ q_keyboard.cntrl ^= 0xFFFF;
+ goto LOOP;
+
+ case ALLUP:
+ q_keyboard.cntrl = 0;
+ q_keyboard.shift = 0;
+ goto LOOP;
+
+ case REPEAT:
+ chr = q_keyboard.last;
+ break;
+
+ /*
+ * Test for cntrl characters. If set, see if the character
+ * is elligible to become a control character.
+ */
+ default:
+
+ if (q_keyboard.cntrl) {
+ chr = q_key[key];
+ if (chr >= ' ' && chr <= '~')
+ chr &= 0x1F;
+ }
+ else if ( q_keyboard.lock || q_keyboard.shift )
+ chr = q_shift_key[key];
+ else
+ chr = q_key[key];
+ break;
+ }
+
+ if (chr < ' ' && chr > '~') /* if input is non-displayable */
+ return(0); /* ..then pitch it! */
+
+ q_keyboard.last = chr;
+
+ /*
+ * Check for special function keys */
+
+ if (chr & 0x80) /* pitch the function keys */
+ return(0);
+ else
+ return(chr);
+
+} /* qdgetc */
+
+/*
+ * led_control()... twiddle LK-201 LED's
+ */
+led_control(unit, cmd, led_mask)
+ int unit, cmd, led_mask;
+{
+ register i;
+ register struct duart *duart;
+
+ duart = (struct duart *)qdmap[unit].duart;
+
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = cmd;
+ break;
+ }
+ }
+ for (i = 1000; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = led_mask;
+ break;
+ }
+ }
+ if (i == 0)
+ return(BAD);
+ return(GOOD);
+
+} /* led_control */
+
+/*
+ * scroll_up()... move the screen up one character height
+ */
+scroll_up(adder)
+ register struct adder *adder;
+{
+ /*
+ * setup VIPER operand control registers
+ */
+ (void)wait_status(adder, ADDRESS_COMPLETE);
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF); /* select all planes */
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ write_ID(adder, SRC1_OCR_B,
+ EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+ write_ID(adder, DST_OCR_B,
+ EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+ /*
+ * load DESTINATION origin and vectors
+ */
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+ adder->destination_x = 0;
+ adder->fast_dest_dx = 1024;
+ adder->destination_y = 0;
+ adder->slow_dest_dy = 864 - CHAR_HEIGHT;
+ /*
+ * load SOURCE origin and vectors
+ */
+ adder->source_1_x = 0;
+ adder->source_1_dx = 1024;
+ adder->source_1_y = 0 + CHAR_HEIGHT;
+ adder->source_1_dy = 864 - CHAR_HEIGHT;
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
+ /*
+ * do a rectangle clear of last screen line
+ */
+ write_ID(adder, MASK_1, 0xffff);
+ write_ID(adder, SOURCE, 0xffff);
+ write_ID(adder,DST_OCR_B,
+ (EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY));
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 0);
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ adder->slow_dest_dx = 0; /* set up the width of */
+ adder->slow_dest_dy = CHAR_HEIGHT; /* rectangle */
+ adder->rasterop_mode = (NORMAL | DST_WRITE_ENABLE) ;
+ (void)wait_status(adder, RASTEROP_COMPLETE);
+ adder->destination_x = 0;
+ adder->destination_y = 864 - CHAR_HEIGHT;
+ adder->fast_dest_dx = 1024; /* set up the height */
+ adder->fast_dest_dy = 0; /* of rectangle */
+ write_ID(adder, LU_FUNCTION_R2, (FULL_SRC_RESOLUTION | LF_SOURCE));
+ adder->cmd = (RASTEROP | OCRB | LF_R2 | DTE ) ;
+
+} /* scroll_up */
+
+/*
+ * init shared memory pointers and structures
+ */
+init_shared(unit)
+ register unit;
+{
+ register struct dga *dga;
+
+ dga = (struct dga *) qdmap[unit].dga;
+
+ /*
+ * initialize the event queue pointers and header */
+
+ eq_header[unit] = (struct qdinput *)
+ ((((int)event_shared & ~(0x01FF)) + 512)
+ + (EVENT_BUFSIZE * unit));
+ eq_header[unit]->curs_pos.x = 0;
+ eq_header[unit]->curs_pos.y = 0;
+ dga->x_cursor = TRANX(eq_header[unit]->curs_pos.x);
+ dga->y_cursor = TRANY(eq_header[unit]->curs_pos.y);
+ eq_header[unit]->curs_box.left = 0;
+ eq_header[unit]->curs_box.right = 0;
+ eq_header[unit]->curs_box.top = 0;
+ eq_header[unit]->curs_box.bottom = 0;
+ /*
+ * assign a pointer to the DMA I/O buffer for this QDSS.
+ */
+ DMAheader[unit] = (struct DMAreq_header *)
+ (((int)(&DMA_shared[0] + 512) & ~0x1FF)
+ + (DMAbuf_size * unit));
+ DMAheader[unit]->DMAreq = (struct DMAreq *) ((int)DMAheader[unit]
+ + sizeof(struct DMAreq_header));
+ DMAheader[unit]->QBAreg = 0;
+ DMAheader[unit]->status = 0;
+ DMAheader[unit]->shared_size = DMAbuf_size;
+ DMAheader[unit]->used = 0;
+ DMAheader[unit]->size = 10; /* default = 10 requests */
+ DMAheader[unit]->oldest = 0;
+ DMAheader[unit]->newest = 0;
+ /*
+ * assign a pointer to the scroll structure for this QDSS.
+ */
+ scroll[unit] = (struct scroll *)
+ (((int)(&scroll_shared[0] + 512) & ~0x1FF)
+ + (sizeof(struct scroll) * unit));
+ scroll[unit]->status = 0;
+ scroll[unit]->viper_constant = 0;
+ scroll[unit]->y_scroll_constant = 0;
+ scroll[unit]->y_offset = 0;
+ scroll[unit]->x_index_pending = 0;
+ scroll[unit]->y_index_pending = 0;
+ /*
+ * assign a pointer to the color map write buffer for this QDSS
+ */
+ color_buf[unit] = (struct color_buf *)
+ (((int)(&color_shared[0] + 512) & ~0x1FF)
+ + (COLOR_BUFSIZ * unit));
+ color_buf[unit]->status = 0;
+ color_buf[unit]->count = 0;
+
+} /* init_shared */
+
+/*
+ * init the ADDER, VIPER, bitmaps, & color map
+ */
+setup_dragon(unit)
+ int unit;
+{
+
+ register struct adder *adder;
+ register struct dga *dga;
+ short *memcsr;
+ register i;
+ short top; /* clipping/scrolling boundaries */
+ short bottom;
+ short right;
+ short left;
+ short *red; /* color map pointers */
+ short *green;
+ short *blue;
+
+ /*
+ * init for setup
+ */
+ adder = (struct adder *) qdmap[unit].adder;
+ dga = (struct dga *) qdmap[unit].dga;
+ memcsr = (short *) qdmap[unit].memcsr;
+ dga->csr &= ~(DMA_IE | 0x700); /* halt DMA and kill the intrpts */
+ *memcsr = SYNC_ON; /* blank screen and turn off LED's */
+ adder->command = CANCEL;
+ /*
+ * set monitor timing
+ */
+ adder->x_scan_count_0 = 0x2800;
+ adder->x_scan_count_1 = 0x1020;
+ adder->x_scan_count_2 = 0x003A;
+ adder->x_scan_count_3 = 0x38F0;
+ adder->x_scan_count_4 = 0x6128;
+ adder->x_scan_count_5 = 0x093A;
+ adder->x_scan_count_6 = 0x313C;
+ adder->sync_phase_adj = 0x0100;
+ adder->x_scan_conf = 0x00C8;
+ /*
+ * got a bug in secound pass ADDER! lets take care of it
+ *
+ * normally, just use the code in the following bug fix code, but to
+ * make repeated demos look pretty, load the registers as if there was
+ * no bug and then test to see if we are getting sync
+ */
+ adder->y_scan_count_0 = 0x135F;
+ adder->y_scan_count_1 = 0x3363;
+ adder->y_scan_count_2 = 0x2366;
+ adder->y_scan_count_3 = 0x0388;
+ /*
+ * if no sync, do the bug fix code
+ */
+ if (wait_status(adder, VSYNC) == BAD) {
+ /* first load all Y scan registers with very short frame and
+ * wait for scroll service. This guarantees at least one SYNC
+ * to fix the pass 2 Adder initialization bug (synchronizes
+ * XCINCH with DMSEEDH)
+ */
+ adder->y_scan_count_0 = 0x01;
+ adder->y_scan_count_1 = 0x01;
+ adder->y_scan_count_2 = 0x01;
+ adder->y_scan_count_3 = 0x01;
+ /*
+ * delay at least 1 full frame time
+ */
+ (void)wait_status(adder, VSYNC);
+ (void)wait_status(adder, VSYNC);
+ /*
+ * now load the REAL sync values (in reverse order just to
+ * be safe.
+ */
+ adder->y_scan_count_3 = 0x0388;
+ adder->y_scan_count_2 = 0x2366;
+ adder->y_scan_count_1 = 0x3363;
+ adder->y_scan_count_0 = 0x135F;
+ }
+ *memcsr = SYNC_ON | UNBLANK; /* turn off leds and turn on video */
+ /*
+ * zero the index registers
+ */
+ adder->x_index_pending = 0;
+ adder->y_index_pending = 0;
+ adder->x_index_new = 0;
+ adder->y_index_new = 0;
+ adder->x_index_old = 0;
+ adder->y_index_old = 0;
+ adder->pause = 0;
+ /*
+ * set rasterop mode to normal pen down
+ */
+ adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+ /*
+ * set the rasterop registers to a default values
+ */
+ adder->source_1_dx = 1;
+ adder->source_1_dy = 1;
+ adder->source_1_x = 0;
+ adder->source_1_y = 0;
+ adder->destination_x = 0;
+ adder->destination_y = 0;
+ adder->fast_dest_dx = 1;
+ adder->fast_dest_dy = 0;
+ adder->slow_dest_dx = 0;
+ adder->slow_dest_dy = 1;
+ adder->error_1 = 0;
+ adder->error_2 = 0;
+ /*
+ * scale factor = UNITY
+ */
+ adder->fast_scale = UNITY;
+ adder->slow_scale = UNITY;
+ /*
+ * set the source 2 parameters
+ */
+ adder->source_2_x = 0;
+ adder->source_2_y = 0;
+ adder->source_2_size = 0x0022;
+ /*
+ * initialize plane addresses for eight vipers
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x0001);
+ write_ID(adder, PLANE_ADDRESS, 0x0000);
+ write_ID(adder, CS_UPDATE_MASK, 0x0002);
+ write_ID(adder, PLANE_ADDRESS, 0x0001);
+ write_ID(adder, CS_UPDATE_MASK, 0x0004);
+ write_ID(adder, PLANE_ADDRESS, 0x0002);
+ write_ID(adder, CS_UPDATE_MASK, 0x0008);
+ write_ID(adder, PLANE_ADDRESS, 0x0003);
+ write_ID(adder, CS_UPDATE_MASK, 0x0010);
+ write_ID(adder, PLANE_ADDRESS, 0x0004);
+ write_ID(adder, CS_UPDATE_MASK, 0x0020);
+ write_ID(adder, PLANE_ADDRESS, 0x0005);
+ write_ID(adder, CS_UPDATE_MASK, 0x0040);
+ write_ID(adder, PLANE_ADDRESS, 0x0006);
+ write_ID(adder, CS_UPDATE_MASK, 0x0080);
+ write_ID(adder, PLANE_ADDRESS, 0x0007);
+ /*
+ * initialize the external registers.
+ */
+ write_ID(adder, CS_UPDATE_MASK, 0x00FF);
+ write_ID(adder, CS_SCROLL_MASK, 0x00FF);
+ /*
+ * initialize resolution mode
+ */
+ write_ID(adder, MEMORY_BUS_WIDTH, 0x000C); /* bus width = 16 */
+ write_ID(adder, RESOLUTION_MODE, 0x0000); /* one bit/pixel */
+ /*
+ * initialize viper registers
+ */
+ write_ID(adder, SCROLL_CONSTANT, SCROLL_ENABLE|VIPER_LEFT|VIPER_UP);
+ write_ID(adder, SCROLL_FILL, 0x0000);
+ /*
+ * set clipping and scrolling limits to full screen
+ */
+ for (i = 1000, adder->status = 0;
+ i > 0 && !(adder->status&ADDRESS_COMPLETE); --i)
+ ;
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
+ top = 0;
+ bottom = 2048;
+ left = 0;
+ right = 1024;
+ adder->x_clip_min = left;
+ adder->x_clip_max = right;
+ adder->y_clip_min = top;
+ adder->y_clip_max = bottom;
+ adder->scroll_x_min = left;
+ adder->scroll_x_max = right;
+ adder->scroll_y_min = top;
+ adder->scroll_y_max = bottom;
+ (void)wait_status(adder, VSYNC); /* wait at LEAST 1 full frame */
+ (void)wait_status(adder, VSYNC);
+ adder->x_index_pending = left;
+ adder->y_index_pending = top;
+ adder->x_index_new = left;
+ adder->y_index_new = top;
+ adder->x_index_old = left;
+ adder->y_index_old = top;
+
+ for (i = 1000, adder->status = 0; i > 0 &&
+ !(adder->status&ADDRESS_COMPLETE) ; --i)
+ ;
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on ADDRESS_COMPLETE\n",unit);
+
+ write_ID(adder, LEFT_SCROLL_MASK, 0x0000);
+ write_ID(adder, RIGHT_SCROLL_MASK, 0x0000);
+ /*
+ * set source and the mask register to all ones (ie: white) o
+ */
+ write_ID(adder, SOURCE, 0xFFFF);
+ write_ID(adder, MASK_1, 0xFFFF);
+ write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+ write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+ /*
+ * initialize Operand Control Register banks for fill command
+ */
+ write_ID(adder, SRC1_OCR_A, EXT_NONE | INT_M1_M2 | NO_ID | WAIT);
+ write_ID(adder, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
+ write_ID(adder, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+ write_ID(adder, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
+ write_ID(adder, SRC2_OCR_B, EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT);
+ write_ID(adder, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+ /*
+ * init Logic Unit Function registers, (these are just common values,
+ * and may be changed as required).
+ */
+ write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+ write_ID(adder, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_SOURCE |
+ INV_M1_M2);
+ write_ID(adder, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_D_OR_S);
+ write_ID(adder, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_D_XOR_S);
+ /*
+ * load the color map for black & white
+ */
+ for (i = 0, adder->status = 0; i < 10000 && !(adder->status&VSYNC); ++i)
+ ;
+
+ if (i == 0)
+ printf("qd%d: setup_dragon: timeout on VSYNC\n", unit);
+
+ red = (short *) qdmap[unit].red;
+ green = (short *) qdmap[unit].green;
+ blue = (short *) qdmap[unit].blue;
+
+ *red++ = 0x00; /* black */
+ *green++ = 0x00;
+ *blue++ = 0x00;
+
+ *red-- = 0xFF; /* white */
+ *green-- = 0xFF;
+ *blue-- = 0xFF;
+
+ /*
+ * set color map for mouse cursor
+ */
+
+ red += 254;
+ green += 254;
+ blue += 254;
+
+ *red++ = 0x00; /* black */
+ *green++ = 0x00;
+ *blue++ = 0x00;
+
+ *red = 0xFF; /* white */
+ *green = 0xFF;
+ *blue = 0xFF;
+
+} /* setup_dragon */
+
+/*
+ * Init the DUART and set defaults in input
+ */
+setup_input(unit)
+ int unit;
+{
+ register struct duart *duart; /* DUART register structure pointer */
+ register i, bits;
+ char id_byte;
+
+ duart = (struct duart *) qdmap[unit].duart;
+ duart->imask = 0;
+
+ /*
+ * setup the DUART for kbd & pointing device
+ */
+ duart->cmdA = RESET_M; /* reset mode reg ptr for kbd */
+ duart->modeA = 0x13; /* 8 bits, no parity, rcv IE, */
+ /* no RTS control,char error mode */
+ duart->modeA = 0x07; /* 1 stop bit,CTS does not IE XMT */
+ /* no RTS control,no echo or loop */
+ duart->cmdB = RESET_M; /* reset mode reg pntr for host */
+ duart->modeB = 0x07; /* 8 bits, odd parity, rcv IE.. */
+ /* ..no RTS cntrl, char error mode */
+ duart->modeB = 0x07; /* 1 stop bit,CTS does not IE XMT */
+ /* no RTS control,no echo or loop */
+ duart->auxctl = 0x00; /* baud rate set 1 */
+ duart->clkselA = 0x99; /* 4800 baud for kbd */
+ duart->clkselB = 0x99; /* 4800 baud for mouse */
+
+ /* reset everything for keyboard */
+
+ for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
+ duart->cmdA = bits;
+
+ /* reset everything for host */
+
+ for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
+ duart->cmdB = bits;
+
+ duart->cmdA = EN_RCV | EN_XMT; /* enbl xmt & rcv for kbd */
+ duart->cmdB = EN_RCV | EN_XMT; /* enbl xmt & rcv for pointer device */
+
+ /*
+ * init keyboard defaults (DUART channel A)
+ */
+ for (i = 500; i > 0; --i) {
+ if (duart->statusA&XMT_RDY) {
+ duart->dataA = LK_DEFAULTS;
+ break;
+ }
+ }
+
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusA&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (duart->dataA) /* flush the ACK */
+ ;
+
+ /*
+ * identify the pointing device
+ */
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = SELF_TEST;
+ break;
+ }
+ }
+
+ /*
+ * wait for 1st byte of self test report */
+
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 1st byte of self test\n"
+ ,unit);
+ goto OUT;
+ }
+
+ if (duart->dataB)
+ ;
+
+ /*
+ * wait for ID byte of self test report
+ */
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 2nd byte of self test\n", unit);
+ goto OUT;
+ }
+
+ id_byte = duart->dataB;
+
+ /*
+ * wait for other bytes to come in
+ */
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB & RCV_RDY) {
+ if (duart->dataB)
+ ;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 3rd byte of self test\n", unit);
+ goto OUT;
+ }
+ for (i = 100000; i > 0; --i) {
+ if (duart->statusB&RCV_RDY) {
+ if (duart->dataB)
+ ;
+ break;
+ }
+ }
+ if (i == 0) {
+ printf("qd[%d]: setup_input: timeout on 4th byte of self test\n", unit);
+ goto OUT;
+ }
+ /*
+ * flag pointing device type and set defaults
+ */
+ for (i=100000; i>0; --i)
+ ; /*XXX*/
+
+ if ((id_byte & 0x0F) != TABLET_ID) {
+ qdflags[unit].pntr_id = MOUSE_ID;
+
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = INC_STREAM_MODE;
+ break;
+ }
+ }
+ }
+ else {
+ qdflags[unit].pntr_id = TABLET_ID;
+
+ for (i = 500; i > 0; --i) {
+ if (duart->statusB&XMT_RDY) {
+ duart->dataB = T_STREAM;
+ break;
+ }
+ }
+ }
+OUT:
+ duart->imask = qdflags[unit].duart_imask;
+
+} /* setup_input */
+
+/*
+ * delay for at least one display frame time
+ *
+ * return: BAD means that we timed out without ever seeing the
+ * vertical sync status bit
+ * GOOD otherwise
+ */
+wait_status(adder, mask)
+ register struct adder *adder;
+ register int mask;
+{
+ register i;
+
+ for (i = 10000, adder->status = 0 ; i > 0 &&
+ !(adder->status&mask) ; --i)
+ ;
+
+ if (i == 0) {
+ printf("wait_status: timeout polling for 0x%x in adder->status\n", mask);
+ return(BAD);
+ }
+
+ return(GOOD);
+
+} /* wait_status */
+
+/*
+ * write out onto the ID bus
+ */
+write_ID(adder, adrs, data)
+ register struct adder *adder;
+ register short adrs;
+ register short data;
+{
+ register i;
+
+ for (i = 100000, adder->status = 0 ;
+ i > 0 && !(adder->status&ADDRESS_COMPLETE) ; --i)
+ ;
+
+ if (i == 0)
+ goto ERR;
+
+ for (i = 100000, adder->status = 0 ;
+ i > 0 && !(adder->status&TX_READY) ; --i)
+ ;
+
+ if (i > 0) {
+ adder->id_data = data;
+ adder->command = ID_LOAD | adrs;
+ return ;
+ }
+
+ERR:
+ printf("write_ID: timeout trying to write to VIPER\n");
+ return ;
+
+} /* write_ID */
+#endif
diff --git a/sys/arch/vax/uba/qv.c b/sys/arch/vax/uba/qv.c
new file mode 100644
index 00000000000..650487dad4b
--- /dev/null
+++ b/sys/arch/vax/uba/qv.c
@@ -0,0 +1,1323 @@
+/* $NetBSD: qv.c,v 1.2 1996/09/02 06:44:28 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1988
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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.
+ *
+ * @(#)qv.c 7.2 (Berkeley) 1/21/94
+ */
+
+/*
+ * derived from: @(#)qv.c 1.8 (ULTRIX) 8/21/85
+ */
+
+/************************************************************************
+ * *
+ * Copyright (c) 1985 by *
+ * Digital Equipment Corporation, Maynard, MA *
+ * All rights reserved. *
+ * *
+ * This software is furnished under a license and may be used and *
+ * copied only in accordance with the terms of such license and *
+ * with the inclusion of the above copyright notice. This *
+ * software or any other copies thereof may not be provided or *
+ * otherwise made available to any other person. No title to and *
+ * ownership of the software is hereby transferred. *
+ * *
+ * This software is derived from software received from the *
+ * University of California, Berkeley, and from Bell *
+ * Laboratories. Use, duplication, or disclosure is subject to *
+ * restrictions under license agreements with University of *
+ * California and with AT&T. *
+ * *
+ * The information in this software is subject to change without *
+ * notice and should not be construed as a commitment by Digital *
+ * Equipment Corporation. *
+ * *
+ * Digital assumes no responsibility for the use or reliability *
+ * of its software on equipment which is not supplied by Digital. *
+ * *
+ ************************************************************************
+ *
+ * This driver provides glass tty functionality to the qvss. It is a strange
+ * device in that it supports three subchannels. The first being the asr,
+ * the second being a channel that intercepts the chars headed for the screen
+ * ( like a pseudo tty ) and the third being a source of mouse state changes.
+ * NOTE: the second is conditional on #ifdef CONS_HACK in this version
+ * of the driver, as it's a total crock.
+ *
+ * There may be one and only one qvss in the system. This restriction is based
+ * on the inability to map more than one at a time. This restriction will
+ * exist until the kernel has shared memory services. This driver therefore
+ * support a single unit. No attempt was made to have it service more.
+ *
+ * (this belongs in sccs - not here)
+ *
+ * 02 Aug 85 -- rjl
+ * Changed the names of the special setup routines so that the system
+ * can have a qvss or a qdss system console.
+ *
+ * 03 Jul 85 -- rjl
+ * Added a check for virtual mode in qvputc so that the driver
+ * doesn't crash while in a dump which is done in physical mode.
+ *
+ * 10 Apr 85 -- jg
+ * Well, our theory about keyboard handling was wrong; most of the
+ * keyboard is in autorepeat, down mode. These changes are to make
+ * the qvss work the same as the Vs100, which is not necessarily
+ * completely correct, as some chord usage may fail. But since we
+ * can't easily change the Vs100, we might as well propagate the
+ * problem to another device. There are also changes for screen and
+ * mouse accellaration.
+ *
+ * 27 Mar 85 -- rjl
+ * MicroVAX-II systems have interval timers that interrupt at ipl4.
+ * Everything else is higher and thus causes us to miss clock ticks. The
+ * problem isn't severe except in the case of a device like this one that
+ * generates lots of interrupts. We aren't willing to make this change to
+ * all device drivers but it seems acceptable in this case.
+ *
+ * 3 Dec 84 -- jg
+ * To continue the tradition of building a better mouse trap, this
+ * driver has been extended to form Vs100 style event queues. If the
+ * mouse device is open, the keyboard events are intercepted and put
+ * into the shared memory queue. Unfortunately, we are ending up with
+ * one of the longest Unix device drivers. Sigh....
+ *
+ * 20 Nov 84 -- rjl
+ * As a further complication this driver is required to function as the
+ * virtual system console. This code runs before and during auto-
+ * configuration and therefore is require to have a second path for setup.
+ * It is futher constrained to have a character output routine that
+ * is not dependant on the interrupt system.
+ *
+ */
+
+
+#include "qv.h"
+#if NQV > 0
+
+#include "../include/pte.h"
+
+#include "sys/param.h"
+#include "sys/conf.h"
+#include "sys/user.h"
+#include "qvioctl.h"
+#include "sys/tty.h"
+#include "sys/map.h"
+#include "sys/buf.h"
+#include "sys/vm.h"
+#include "sys/clist.h"
+#include "sys/file.h"
+#include "sys/uio.h"
+#include "sys/kernel.h"
+#include "sys/syslog.h"
+#include "../include/cpu.h"
+#include "../include/mtpr.h"
+#include "ubareg.h"
+#include "ubavar.h"
+
+#define CONS_HACK
+
+struct uba_device *qvinfo[NQV];
+
+struct tty qv_tty[NQV*4];
+
+#define nNQV NQV
+int nqv = NQV*4;
+
+/*
+ * Definition of the driver for the auto-configuration program.
+ */
+int qvprobe(), qvattach(), qvkint(), qvvint();
+u_short qvstd[] = { 0 };
+struct uba_driver qvdriver =
+ { qvprobe, 0, qvattach, 0, qvstd, "qv", qvinfo };
+
+extern char qvmem[][512*NBPG];
+extern struct pte QVmap[][512];
+
+/*
+ * Local variables for the driver. Initialized for 15' screen
+ * so that it can be used during the boot process.
+ */
+
+#define QVWAITPRI (PZERO+1)
+#define QVSSMAJOR 40
+
+#define QVKEYBOARD 0 /* minor 0, keyboard/glass tty */
+#define QVPCONS 1 /* minor 1, console interceptor XXX */
+#define QVMOUSECHAN 2 /* minor 2, mouse */
+#define QVSPARE 3 /* unused */
+#define QVCHAN(unit) ((unit) & 03)
+/*
+ * v_putc is the switch that is used to redirect the console cnputc to the
+ * virtual console vputc. consops is used to redirect the console
+ * device to the qvss console.
+ */
+extern (*v_putc)();
+extern struct cdevsw *consops;
+/*
+ * qv_def_scrn is used to select the appropriate tables. 0=15 inch 1=19 inch,
+ * 2 = uVAXII.
+ */
+int qv_def_scrn = 2;
+
+#define QVMAXEVQ 64 /* must be power of 2 */
+#define EVROUND(x) ((x) & (QVMAXEVQ - 1))
+
+/*
+ * Screen parameters 15 & 19 inch monitors. These determine the max size in
+ * pixel and character units for the display and cursor positions.
+ * Notice that the mouse defaults to original square algorithm, but X
+ * will change to its defaults once implemented.
+ */
+struct qv_info *qv_scn;
+struct qv_info qv_scn_defaults[] = {
+ {0, {0, 0}, 0, {0, 0}, 0, 0, 30, 80, 768, 480, 768-16, 480-16,
+ 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
+ {0, {0, 0}, 0, {0, 0}, 0, 0, 55, 120, 960, 864, 960-16, 864-16,
+ 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4},
+ {0, {0, 0}, 0, {0, 0}, 0, 0, 56, 120,1024, 864,1024-16, 864-16,
+ 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}
+};
+
+/*
+ * Screen controller initialization parameters. The definations and use
+ * of these parameters can be found in the Motorola 68045 crtc specs. In
+ * essence they set the display parameters for the chip. The first set is
+ * for the 15" screen and the second is for the 19" seperate sync. There
+ * is also a third set for a 19" composite sync monitor which we have not
+ * tested and which is not supported.
+ */
+static short qv_crt_parms[][16] = {
+ { 31, 25, 27, 0142, 31, 13, 30, 31, 4, 15, 040, 0, 0, 0, 0, 0 },
+/* VR100*/ { 39, 30, 32, 0262, 55, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0 },
+/* VR260*/ { 39, 32, 33, 0264, 56, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0},
+};
+
+/*
+ * Screen parameters
+ */
+struct qv_info *qv_scn;
+int maxqvmem = 254*1024 - sizeof(struct qv_info) - QVMAXEVQ*sizeof(vsEvent);
+
+/*
+ * Keyboard state
+ */
+struct qv_keyboard {
+ int shift; /* state variables */
+ int cntrl;
+ int lock;
+ char last; /* last character */
+} qv_keyboard;
+
+short divdefaults[15] = { LK_DOWN, /* 0 doesn't exist */
+ LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_DOWN,
+ LK_UPDOWN, LK_UPDOWN, LK_AUTODOWN, LK_AUTODOWN,
+ LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN,
+ LK_DOWN, LK_AUTODOWN };
+
+short kbdinitstring[] = { /* reset any random keyboard stuff */
+ LK_AR_ENABLE, /* we want autorepeat by default */
+ LK_CL_ENABLE, /* keyclick */
+ 0x84, /* keyclick volume */
+ LK_KBD_ENABLE, /* the keyboard itself */
+ LK_BELL_ENABLE, /* keyboard bell */
+ 0x84, /* bell volume */
+ LK_LED_DISABLE, /* keyboard leds */
+ LED_ALL };
+#define KBD_INIT_LENGTH sizeof(kbdinitstring)/sizeof(short)
+
+#define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000))
+
+int qv_ipl_lo = 1; /* IPL low flag */
+int mouseon = 0; /* mouse channel is enabled when 1*/
+struct proc *qvrsel; /* process waiting for select */
+
+int qvstart(), qvputc(), ttrstrt();
+
+/*
+ * Keyboard translation and font tables
+ */
+extern u_short q_key[], q_shift_key[], q_cursor[];
+extern char *q_special[], q_font[];
+
+/*
+ * See if the qvss will interrupt.
+ */
+
+/*ARGSUSED*/
+qvprobe(reg, ctlr)
+ caddr_t reg;
+ int ctlr;
+{
+ register int br, cvec; /* these are ``value-result'' */
+ register struct qvdevice *qvaddr = (struct qvdevice *)reg;
+ static int tvec, ovec;
+
+#ifdef lint
+ br = 0; cvec = br; br = cvec;
+ qvkint(0); qvvint(0);
+#endif
+ /*
+ * Allocate the next two vectors
+ */
+ tvec = 0360;
+ ovec = cvec;
+ /*
+ * Turn on the keyboard and vertical interrupt vectors.
+ */
+ qvaddr->qv_intcsr = 0; /* init the interrupt controler */
+ qvaddr->qv_intcsr = 0x40; /* reset irr */
+ qvaddr->qv_intcsr = 0x80; /* specify individual vectors */
+ qvaddr->qv_intcsr = 0xc0; /* preset autoclear data */
+ qvaddr->qv_intdata = 0xff; /* all setup as autoclear */
+
+ qvaddr->qv_intcsr = 0xe0; /* preset vector address 1 */
+ qvaddr->qv_intdata = tvec; /* give it the keyboard vector */
+ qvaddr->qv_intcsr = 0x28; /* enable tx/rx interrupt */
+
+ qvaddr->qv_intcsr = 0xe1; /* preset vector address 2 */
+ qvaddr->qv_intdata = tvec+4; /* give it the vertical sysnc */
+ qvaddr->qv_intcsr = 0x29; /* enable */
+
+ qvaddr->qv_intcsr = 0xa1; /* arm the interrupt ctrl */
+
+ qvaddr->qv_uartcmd = 0x15; /* set mode pntr/enable rx/tx */
+ qvaddr->qv_uartmode = 0x17; /* noparity, 8-bit */
+ qvaddr->qv_uartmode = 0x07; /* 1 stop bit */
+ qvaddr->qv_uartstatus = 0x99; /* 4800 baud xmit/recv */
+ qvaddr->qv_uartintstatus = 2; /* enable recv interrupts */
+
+ qvaddr->qv_csr |= QV_INT_ENABLE | QV_CUR_MODE;
+
+ DELAY(10000);
+
+ qvaddr->qv_csr &= ~QV_INT_ENABLE;
+
+ /*
+ * If the qvss did interrupt it was the second vector not
+ * the first so we have to return the first so that they
+ * will be setup properly
+ */
+ if( ovec == cvec ) {
+ return 0;
+ } else
+ cvec -= 4;
+ return (sizeof (struct qvdevice));
+}
+
+/*
+ * Routine called to attach a qv.
+ */
+qvattach(ui)
+ struct uba_device *ui;
+{
+
+ /*
+ * If not the console then we have to setup the screen
+ */
+ if (v_putc != qvputc || ui->ui_unit != 0)
+ (void)qv_setup((struct qvdevice *)ui->ui_addr, ui->ui_unit, 1);
+ else
+ qv_scn->qvaddr = (struct qvdevice *)ui->ui_addr;
+}
+
+
+/*ARGSUSED*/
+qvopen(dev, flag)
+ dev_t dev;
+{
+ register struct tty *tp;
+ register int unit, qv;
+ register struct qvdevice *qvaddr;
+ register struct uba_device *ui;
+ register struct qv_info *qp = qv_scn;
+
+ unit = minor(dev);
+ qv = unit >> 2;
+ if (unit >= nqv || (ui = qvinfo[qv])== 0 || ui->ui_alive == 0)
+ return (ENXIO);
+ if (QVCHAN(unit) == QVSPARE
+#ifndef CONS_HACK
+ || QVCHAN(unit) == QVPCONS
+#endif
+ )
+ return (ENODEV);
+ tp = &qv_tty[unit];
+ if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
+ return (EBUSY);
+ qvaddr = (struct qvdevice *)ui->ui_addr;
+ qv_scn->qvaddr = qvaddr;
+ tp->t_addr = (caddr_t)qvaddr;
+ tp->t_oproc = qvstart;
+
+ if ((tp->t_state&TS_ISOPEN) == 0) {
+ ttychars(tp);
+ tp->t_state = TS_ISOPEN|TS_CARR_ON;
+ tp->t_ispeed = B9600;
+ tp->t_ospeed = B9600;
+ if( QVCHAN(unit) == QVKEYBOARD ) {
+ /* make sure keyboard is always back to default */
+ qvkbdreset();
+ qvaddr->qv_csr |= QV_INT_ENABLE;
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ }
+ /* XXX ?why? else
+ tp->t_flags = RAW;
+ */
+ }
+ /*
+ * Process line discipline specific open if its not the
+ * mouse channel. For the mouse we init the ring ptr's.
+ */
+ if( QVCHAN(unit) != QVMOUSECHAN )
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+ else {
+ mouseon = 1;
+ /* set up event queue for later */
+ qp->ibuff = (vsEvent *)qp - QVMAXEVQ;
+ qp->iqsize = QVMAXEVQ;
+ qp->ihead = qp->itail = 0;
+ return 0;
+ }
+}
+
+/*
+ * Close a QVSS line.
+ */
+/*ARGSUSED*/
+qvclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ register struct tty *tp;
+ register unit;
+ register struct qvdevice *qvaddr;
+ int error;
+
+ unit = minor(dev);
+ tp = &qv_tty[unit];
+
+ /*
+ * If this is the keyboard unit (0) shutdown the
+ * interface.
+ */
+ qvaddr = (struct qvdevice *)tp->t_addr;
+ if (QVCHAN(unit) == QVKEYBOARD )
+ qvaddr->qv_csr &= ~QV_INT_ENABLE;
+
+ /*
+ * If unit is not the mouse channel call the line disc.
+ * otherwise clear the state flag, and put the keyboard into down/up.
+ */
+ if (QVCHAN(unit) != QVMOUSECHAN) {
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ error = ttyclose(tp);
+ } else {
+ mouseon = 0;
+ qv_init( qvaddr );
+ error = 0;
+ }
+ tp->t_state = 0;
+ return (error);
+}
+
+qvread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ int unit = minor( dev );
+
+ if (QVCHAN(unit) != QVMOUSECHAN) {
+ tp = &qv_tty[unit];
+ return ((*linesw[tp->t_line].l_read)(tp, uio));
+ }
+ return (ENXIO);
+}
+
+qvwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct tty *tp;
+ int unit = minor( dev );
+
+ /*
+ * If this is the mouse we simply fake the i/o, otherwise
+ * we let the line disp. handle it.
+ */
+ if (QVCHAN(unit) == QVMOUSECHAN) {
+ uio->uio_offset = uio->uio_resid;
+ uio->uio_resid = 0;
+ return 0;
+ }
+ tp = &qv_tty[unit];
+ return ((*linesw[tp->t_line].l_write)(tp, uio));
+}
+
+
+/*
+ * Mouse activity select routine
+ */
+qvselect(dev, rw)
+dev_t dev;
+{
+ register int s = spl5();
+ register struct qv_info *qp = qv_scn;
+
+ if( QVCHAN(minor(dev)) == QVMOUSECHAN )
+ switch(rw) {
+ case FREAD: /* if events okay */
+ if(qp->ihead != qp->itail) {
+ splx(s);
+ return(1);
+ }
+ qvrsel = u.u_procp;
+ splx(s);
+ return(0);
+ default: /* can never write */
+ splx(s);
+ return(0);
+ }
+ else {
+ splx(s);
+ return( ttselect(dev, rw) );
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * QVSS keyboard interrupt.
+ */
+qvkint(qv)
+ int qv;
+{
+ struct tty *tp;
+ register c;
+ struct uba_device *ui;
+ register int key;
+ register int i;
+
+ ui = qvinfo[qv];
+ if (ui == 0 || ui->ui_alive == 0)
+ return;
+ tp = &qv_tty[qv<<2];
+ /*
+ * Get a character from the keyboard.
+ */
+ key = ((struct qvdevice *)ui->ui_addr)->qv_uartdata & 0xff;
+ if( mouseon == 0) {
+ /*
+ * Check for various keyboard errors
+ */
+ if( key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
+ key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
+ log(LOG_ERR,
+ "qv%d: Keyboard error, code = %x\n",qv,key);
+ return;
+ }
+ if( key < LK_LOWEST ) return;
+ /*
+ * See if its a state change key
+ */
+ switch ( key ) {
+ case LOCK:
+ qv_keyboard.lock ^= 0xffff; /* toggle */
+ if( qv_keyboard.lock )
+ qv_key_out( LK_LED_ENABLE );
+ else
+ qv_key_out( LK_LED_DISABLE );
+ qv_key_out( LED_3 );
+ return;
+ case SHIFT:
+ qv_keyboard.shift ^= 0xffff;
+ return;
+ case CNTRL:
+ qv_keyboard.cntrl ^= 0xffff;
+ return;
+ case ALLUP:
+ qv_keyboard.cntrl = qv_keyboard.shift = 0;
+ return;
+ case REPEAT:
+ c = qv_keyboard.last;
+ break;
+ default:
+ /*
+ * Test for control characters. If set, see if the character
+ * is elligible to become a control character.
+ */
+ if( qv_keyboard.cntrl ) {
+ c = q_key[ key ];
+ if( c >= ' ' && c <= '~' )
+ c &= 0x1f;
+ } else if( qv_keyboard.lock || qv_keyboard.shift )
+ c = q_shift_key[ key ];
+ else
+ c = q_key[ key ];
+ break;
+ }
+
+ qv_keyboard.last = c;
+
+ /*
+ * Check for special function keys
+ */
+ if( c & 0x80 ) {
+ register char *string;
+ string = q_special[ c & 0x7f ];
+ while( *string )
+ (*linesw[tp->t_line].l_rint)(*string++, tp);
+ } else
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ } else {
+ /*
+ * Mouse channel is open put it into the event queue
+ * instead.
+ */
+ register struct qv_info *qp = qv_scn;
+ register vsEvent *vep;
+
+ if ((i = EVROUND(qp->itail+1)) == qp->ihead)
+ return;
+ vep = &qp->ibuff[qp->itail];
+ vep->vse_direction = VSE_KBTRAW;
+ vep->vse_type = VSE_BUTTON;
+ vep->vse_device = VSE_DKB;
+ vep->vse_x = qp->mouse.x;
+ vep->vse_y = qp->mouse.y;
+ vep->vse_time = TOY;
+ vep->vse_key = key;
+ qp->itail = i;
+ if(qvrsel) {
+ selwakeup(qvrsel,0);
+ qvrsel = 0;
+ }
+ }
+}
+
+/*
+ * Ioctl for QVSS.
+ */
+/*ARGSUSED*/
+qvioctl(dev, cmd, data, flag)
+ dev_t dev;
+ register caddr_t data;
+{
+ register struct tty *tp;
+ register int unit = minor(dev);
+ register struct qv_info *qp = qv_scn;
+ register struct qv_kpcmd *qk;
+ register unsigned char *cp;
+ int error;
+
+ /*
+ * Check for and process qvss specific ioctl's
+ */
+ switch( cmd ) {
+ case QIOCGINFO: /* return screen info */
+ bcopy((caddr_t)qp, data, sizeof (struct qv_info));
+ break;
+
+ case QIOCSMSTATE: /* set mouse state */
+ qp->mouse = *((vsCursor *)data);
+ qv_pos_cur( qp->mouse.x, qp->mouse.y );
+ break;
+
+ case QIOCINIT: /* init screen */
+ qv_init( qp->qvaddr );
+ break;
+
+ case QIOCKPCMD:
+ qk = (struct qv_kpcmd *)data;
+ if(qk->nbytes == 0) qk->cmd |= 0200;
+ if(mouseon == 0) qk->cmd |= 1; /* no mode changes */
+ qv_key_out(qk->cmd);
+ cp = &qk->par[0];
+ while(qk->nbytes-- > 0) { /* terminate parameters */
+ if(qk->nbytes <= 0) *cp |= 0200;
+ qv_key_out(*cp++);
+ }
+ break;
+ case QIOCADDR: /* get struct addr */
+ *(struct qv_info **) data = qp;
+ break;
+ default: /* not ours ?? */
+ tp = &qv_tty[unit];
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0) {
+ return (error);
+ }
+ break;
+ }
+ return (0);
+}
+/*
+ * Initialize the screen and the scanmap
+ */
+qv_init(qvaddr)
+struct qvdevice *qvaddr;
+{
+ register short *scanline;
+ register int i;
+ register short scan;
+ register char *ptr;
+ register struct qv_info *qp = qv_scn;
+
+ /*
+ * Clear the bit map
+ */
+ for( i=0 , ptr = qp->bitmap ; i<240 ; i += 2 , ptr += 2048)
+ bzero( ptr, 2048 );
+ /*
+ * Reinitialize the scanmap
+ */
+ scan = qvaddr->qv_csr & QV_MEM_BANK;
+ scanline = qp->scanmap;
+ for(i = 0 ; i < qp->max_y ; i++ )
+ *scanline++ = scan++;
+
+ /*
+ * Home the cursor
+ */
+ qp->row = qp->col = 0;
+
+ /*
+ * Reset the cursor to the default type.
+ */
+ for( i=0 ; i<16 ; i++ )
+ qp->cursorbits[i] = q_cursor[i];
+ qvaddr->qv_csr |= QV_CUR_MODE;
+ /*
+ * Reset keyboard to default state.
+ */
+ qvkbdreset();
+}
+
+qvreset()
+{
+}
+qvkbdreset()
+{
+ register int i;
+ qv_key_out(LK_DEFAULTS);
+ for( i=1 ; i < 15 ; i++ )
+ qv_key_out( divdefaults[i] | (i<<3));
+ for (i = 0; i < KBD_INIT_LENGTH; i++)
+ qv_key_out(kbdinitstring[i]);
+}
+
+#define abs(x) (((x) > 0) ? (x) : (-(x)))
+/*
+ * QVSS vertical sync interrupt
+ */
+qvvint(qv)
+ int qv;
+{
+ extern int selwait;
+ register struct qvdevice *qvaddr;
+ struct uba_device *ui;
+ register struct qv_info *qp = qv_scn;
+ int unit;
+ struct tty *tp0;
+ int i;
+ register int j;
+ /*
+ * Mouse state info
+ */
+ static ushort omouse = 0, nmouse = 0;
+ static char omx=0, omy=0, mx=0, my=0, om_switch=0, m_switch=0;
+ register int dx, dy;
+
+ /*
+ * Test and set the qv_ipl_lo flag. If the result is not zero then
+ * someone else must have already gotten here.
+ */
+ if( --qv_ipl_lo )
+ return;
+ (void)spl4();
+ ui = qvinfo[qv];
+ unit = qv<<2;
+ qvaddr = (struct qvdevice *)ui->ui_addr;
+ tp0 = &qv_tty[QVCHAN(unit) + QVMOUSECHAN];
+ /*
+ * See if the mouse has moved.
+ */
+ if( omouse != (nmouse = qvaddr->qv_mouse) ) {
+ omouse = nmouse;
+ mx = nmouse & 0xff;
+ my = nmouse >> 8;
+ dy = my - omy; omy = my;
+ dx = mx - omx; omx = mx;
+ if( dy < 50 && dy > -50 && dx < 50 && dx > -50 ) {
+ register vsEvent *vep;
+ if( qp->mscale < 0 ) { /* Ray Lanza's original */
+ if( dy < 0 )
+ dy = -( dy * dy );
+ else
+ dy *= dy;
+ if( dx < 0 )
+ dx = -( dx * dx );
+ else
+ dx *= dx;
+ }
+ else { /* Vs100 style, see WGA spec */
+ int thresh = qp->mthreshold;
+ int scale = qp->mscale;
+ if( abs(dx) > thresh ) {
+ if ( dx < 0 )
+ dx = (dx + thresh)*scale - thresh;
+ else
+ dx = (dx - thresh)*scale + thresh;
+ }
+ if( abs(dy) > thresh ) {
+ if ( dy < 0 )
+ dy = (dy + thresh)*scale - thresh;
+ else
+ dy = (dy - thresh)*scale + thresh;
+ }
+ }
+ qp->mouse.x += dx;
+ qp->mouse.y -= dy;
+ if( qp->mouse.x < 0 )
+ qp->mouse.x = 0;
+ if( qp->mouse.y < 0 )
+ qp->mouse.y = 0;
+ if( qp->mouse.x > qp->max_cur_x )
+ qp->mouse.x = qp->max_cur_x;
+ if( qp->mouse.y > qp->max_cur_y )
+ qp->mouse.y = qp->max_cur_y;
+ if( tp0->t_state & TS_ISOPEN )
+ qv_pos_cur( qp->mouse.x, qp->mouse.y );
+ if (qp->mouse.y < qp->mbox.bottom &&
+ qp->mouse.y >= qp->mbox.top &&
+ qp->mouse.x < qp->mbox.right &&
+ qp->mouse.x >= qp->mbox.left) goto switches;
+ qp->mbox.bottom = 0; /* trash box */
+ if (EVROUND(qp->itail+1) == qp->ihead)
+ goto switches;
+ i = EVROUND(qp->itail - 1);
+ if ((qp->itail != qp->ihead) && (i != qp->ihead)) {
+ vep = & qp->ibuff[i];
+ if(vep->vse_type == VSE_MMOTION) {
+ vep->vse_x = qp->mouse.x;
+ vep->vse_y = qp->mouse.y;
+ goto switches;
+ }
+ }
+ /* put event into queue and do select */
+ vep = & qp->ibuff[qp->itail];
+ vep->vse_type = VSE_MMOTION;
+ vep->vse_time = TOY;
+ vep->vse_x = qp->mouse.x;
+ vep->vse_y = qp->mouse.y;
+ qp->itail = EVROUND(qp->itail+1);
+ }
+ }
+ /*
+ * See if mouse switches have changed.
+ */
+switches:if( om_switch != ( m_switch = (qvaddr->qv_csr & QV_MOUSE_ANY) >> 8 ) ) {
+ qp->mswitches = ~m_switch & 0x7;
+ for (j = 0; j < 3; j++) { /* check each switch */
+ register vsEvent *vep;
+ if ( ((om_switch>>j) & 1) == ((m_switch>>j) & 1) )
+ continue;
+ /* check for room in the queue */
+ if ((i = EVROUND(qp->itail+1)) == qp->ihead) return;
+ /* put event into queue and do select */
+ vep = &qp->ibuff[qp->itail];
+ vep->vse_type = VSE_BUTTON;
+ vep->vse_key = 2 - j;
+ vep->vse_direction = VSE_KBTDOWN;
+ if ( (m_switch >> j) & 1)
+ vep->vse_direction = VSE_KBTUP;
+ vep->vse_device = VSE_MOUSE;
+ vep->vse_time = TOY;
+ vep->vse_x = qp->mouse.x;
+ vep->vse_y = qp->mouse.y;
+ }
+ qp->itail = i;
+ om_switch = m_switch;
+ qp->mswitches = m_switch;
+ }
+ /* if we have proc waiting, and event has happened, wake him up */
+ if(qvrsel && (qp->ihead != qp->itail)) {
+ selwakeup(qvrsel,0);
+ qvrsel = 0;
+ }
+ /*
+ * Okay we can take another hit now
+ */
+ qv_ipl_lo = 1;
+}
+
+/*
+ * Start transmission
+ */
+qvstart(tp)
+ register struct tty *tp;
+{
+ register int unit, c;
+ register struct tty *tp0;
+ int s;
+
+ unit = minor(tp->t_dev);
+#ifdef CONS_HACK
+ tp0 = &qv_tty[(unit&0xfc)+QVPCONS];
+#endif
+ unit = QVCHAN(unit);
+
+ s = spl5();
+ /*
+ * If it's currently active, or delaying, no need to do anything.
+ */
+ if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+ goto out;
+ /*
+ * Display chars until the queue is empty, if the second subchannel
+ * is open direct them there. Drop characters from subchannels other
+ * than 0 on the floor.
+ */
+
+ while( tp->t_outq.c_cc ) {
+ c = getc(&tp->t_outq);
+ if (unit == QVKEYBOARD)
+#ifdef CONS_HACK
+ if( tp0->t_state & TS_ISOPEN ){
+ (*linesw[tp0->t_line].l_rint)(c, tp0);
+ } else
+#endif
+ qvputchar( c & 0xff );
+ }
+ /*
+ * Position the cursor to the next character location.
+ */
+ qv_pos_cur( qv_scn->col*8, qv_scn->row*15 );
+
+ /*
+ * If there are sleepers, and output has drained below low
+ * water mark, wake up the sleepers.
+ */
+ if ( tp->t_outq.c_cc<= tp->t_lowat ) {
+ if (tp->t_state&TS_ASLEEP){
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ }
+ tp->t_state &= ~TS_BUSY;
+out:
+ splx(s);
+}
+
+/*
+ * Stop output on a line, e.g. for ^S/^Q or output flush.
+ */
+/*ARGSUSED*/
+void
+qvstop(tp, flag)
+ register struct tty *tp;
+ int flag;
+{
+ register int s;
+
+ /*
+ * Block input/output interrupts while messing with state.
+ */
+ s = spl5();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state&TS_TTSTOP)==0) {
+ tp->t_state |= TS_FLUSH;
+ } else
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+}
+
+qvputc(c)
+char c;
+{
+ qvputchar(c);
+ if (c == '\n')
+ qvputchar('\r');
+}
+
+/*
+ * Routine to display a character on the screen. The model used is a
+ * glass tty. It is assummed that the user will only use this emulation
+ * during system boot and that the screen will be eventually controlled
+ * by a window manager.
+ *
+ */
+qvputchar( c )
+register char c;
+{
+
+ register char *b_row, *f_row;
+ register int i;
+ register short *scanline;
+ register int ote = 128;
+ register struct qv_info *qp = qv_scn;
+
+ /*
+ * This routine may be called in physical mode by the dump code
+ * so we check and punt if that's the case.
+ */
+ if( (mfpr(MAPEN) & 1) == 0 )
+ return;
+
+ c &= 0x7f;
+
+ switch ( c ) {
+ case '\t': /* tab */
+ for( i = 8 - (qp->col & 0x7) ; i > 0 ; i-- )
+ qvputchar( ' ' );
+ break;
+
+ case '\r': /* return */
+ qp->col = 0;
+ break;
+
+ case '\010': /* backspace */
+ if( --qp->col < 0 )
+ qp->col = 0;
+ break;
+
+ case '\n': /* linefeed */
+ if( qp->row+1 >= qp->max_row )
+ qvscroll();
+ else
+ qp->row++;
+ /*
+ * Position the cursor to the next character location.
+ */
+ qv_pos_cur( qp->col*8, qp->row*15 );
+ break;
+
+ case '\007': /* bell */
+ /*
+ * We don't do anything to the keyboard until after
+ * autoconfigure.
+ */
+ if( qp->qvaddr )
+ qv_key_out( LK_RING_BELL );
+ return;
+
+ default:
+ if( c >= ' ' && c <= '~' ) {
+ scanline = qp->scanmap;
+ b_row = qp->bitmap+(scanline[qp->row*15]&0x3ff)*128+qp->col;
+ i = c - ' ';
+ if( i < 0 || i > 95 )
+ i = 0;
+ else
+ i *= 15;
+ f_row = (char *)((int)q_font + i);
+
+/* for( i=0 ; i<15 ; i++ , b_row += 128, f_row++ )
+ *b_row = *f_row;*/
+ /* inline expansion for speed */
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+ *b_row = *f_row++; b_row += ote;
+
+ if( ++qp->col >= qp->max_col ) {
+ qp->col = 0 ;
+ if( qp->row+1 >= qp->max_row )
+ qvscroll();
+ else
+ qp->row++;
+ }
+ }
+ break;
+ }
+}
+
+/*
+ * Position the cursor to a particular spot.
+ */
+qv_pos_cur( x, y)
+register int x,y;
+{
+ register struct qvdevice *qvaddr;
+ register struct qv_info *qp = qv_scn;
+ register index;
+
+ if( qvaddr = qp->qvaddr ) {
+ if( y < 0 || y > qp->max_cur_y )
+ y = qp->max_cur_y;
+ if( x < 0 || x > qp->max_cur_x )
+ x = qp->max_cur_x;
+ qp->cursor.x = x; /* keep track of real cursor*/
+ qp->cursor.y = y; /* position, indep. of mouse*/
+
+ qvaddr->qv_crtaddr = 10; /* select cursor start reg */
+ qvaddr->qv_crtdata = y & 0xf;
+ qvaddr->qv_crtaddr = 11; /* select cursor end reg */
+ qvaddr->qv_crtdata = y & 0xf;
+ qvaddr->qv_crtaddr = 14; /* select cursor y pos. */
+ qvaddr->qv_crtdata = y >> 4;
+ qvaddr->qv_xcur = x; /* pos x axis */
+ /*
+ * If the mouse is being used then we change the mode of
+ * cursor display based on the pixels under the cursor
+ */
+ if( mouseon ) {
+ index = y*128 + x/8;
+ if( qp->bitmap[ index ] && qp->bitmap[ index+128 ] )
+ qvaddr->qv_csr &= ~QV_CUR_MODE;
+ else
+ qvaddr->qv_csr |= QV_CUR_MODE;
+ }
+ }
+}
+/*
+ * Scroll the bitmap by moving the scanline map words. This could
+ * be done by moving the bitmap but it's much too slow for a full screen.
+ * The only drawback is that the scanline map must be reset when the user
+ * wants to do graphics.
+ */
+qvscroll()
+{
+ short tmpscanlines[15];
+ register char *b_row;
+ register short *scanline;
+ register struct qv_info *qp = qv_scn;
+
+ /*
+ * If the mouse is on we don't scroll so that the bit map
+ * remains sane.
+ */
+ if( mouseon ) {
+ qp->row = 0;
+ return;
+ }
+ /*
+ * Save the first 15 scanlines so that we can put them at
+ * the bottom when done.
+ */
+ bcopy((caddr_t)qp->scanmap, (caddr_t)tmpscanlines, sizeof tmpscanlines);
+
+ /*
+ * Clear the wrapping line so that it won't flash on the bottom
+ * of the screen.
+ */
+ scanline = qp->scanmap;
+ b_row = qp->bitmap+(*scanline&0x3ff)*128;
+ bzero( b_row, 1920 );
+
+ /*
+ * Now move the scanlines down
+ */
+ bcopy((caddr_t)(qp->scanmap+15), (caddr_t)qp->scanmap,
+ (qp->row * 15) * sizeof (short) );
+
+ /*
+ * Now put the other lines back
+ */
+ bcopy((caddr_t)tmpscanlines, (caddr_t)(qp->scanmap+(qp->row * 15)),
+ sizeof (tmpscanlines) );
+
+}
+
+/*
+ * Output to the keyboard. This routine status polls the transmitter on the
+ * keyboard to output a code. The timer is to avoid hanging on a bad device.
+ */
+qv_key_out(c)
+ u_short c;
+{
+ int timer = 30000;
+ register struct qv_info *qp = qv_scn;
+
+ if (qp->qvaddr) {
+ while ((qp->qvaddr->qv_uartstatus & 0x4) == 0 && timer--)
+ ;
+ qp->qvaddr->qv_uartdata = c;
+ }
+}
+/*
+ * Virtual console initialization. This routine sets up the qvss so that it can
+ * be used as the system console. It is invoked before autoconfig and has to do
+ * everything necessary to allow the device to serve as the system console.
+ * In this case it must map the q-bus and device areas and initialize the qvss
+ * screen.
+ */
+qvcons_init()
+{
+ struct percpu *pcpu; /* pointer to percpu structure */
+ register struct qbus *qb;
+ struct qvdevice *qvaddr; /* device pointer */
+ short *devptr; /* virtual device space */
+ extern cnputc(); /* standard serial console putc */
+#define QVSSCSR 017200
+
+ /*
+ * If secondary console already configured,
+ * don't override the previous one.
+ */
+ if (v_putc != cnputc)
+ return 0;
+ /*
+ * find the percpu entry that matches this machine.
+ */
+ for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ )
+ ;
+ if( pcpu == NULL )
+ return 0;
+ if (pcpu->pc_io->io_type != IO_QBUS)
+ return 0;
+
+ /*
+ * Found an entry for this cpu. Because this device is Microvax specific
+ * we assume that there is a single q-bus and don't have to worry about
+ * multiple adapters.
+ *
+ * Map the device registers.
+ */
+ qb = (struct qbus *)pcpu->pc_io->io_details;
+ ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize, UBAIOPAGES * NBPG);
+
+ /*
+ * See if the qvss is there.
+ */
+ devptr = (short *)((char *)umem[0] + (qb->qb_memsize * NBPG));
+ qvaddr = (struct qvdevice *)((u_int)devptr + ubdevreg(QVSSCSR));
+ if (badaddr((caddr_t)qvaddr, sizeof(short)))
+ return 0;
+ /*
+ * Okay the device is there lets set it up
+ */
+ if (!qv_setup(qvaddr, 0, 0))
+ return 0;
+ v_putc = qvputc;
+ consops = &cdevsw[QVSSMAJOR];
+ return 1;
+}
+/*
+ * Do the board specific setup
+ */
+qv_setup(qvaddr, unit, probed)
+struct qvdevice *qvaddr;
+int unit;
+int probed;
+{
+ caddr_t qvssmem; /* pointer to the display mem */
+ register i; /* simple index */
+ register struct qv_info *qp;
+ register int *pte;
+ struct percpu *pcpu; /* pointer to percpu structure */
+ register struct qbus *qb;
+
+ /*
+ * find the percpu entry that matches this machine.
+ */
+ for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ )
+ ;
+ if( pcpu == NULL )
+ return(0);
+
+ /*
+ * Found an entry for this cpu. Because this device is Microvax specific
+ * we assume that there is a single q-bus and don't have to worry about
+ * multiple adapters.
+ *
+ * Map the device memory.
+ */
+ qb = (struct qbus *)pcpu->pc_io->io_details;
+
+ i = (u_int)(qvaddr->qv_csr & QV_MEM_BANK) << 7;
+ ioaccess(qb->qb_maddr + i, QVmap[unit], 512 * NBPG);
+ qvssmem = qvmem[unit];
+ pte = (int *)(QVmap[unit]);
+ for (i=0; i < 512; i++, pte++)
+ *pte = (*pte & ~PG_PROT) | PG_UW | PG_V;
+
+ qv_scn = (struct qv_info *)((u_int)qvssmem + 251*1024);
+ qp = qv_scn;
+ if( (qvaddr->qv_csr & QV_19INCH) && qv_def_scrn == 0)
+ qv_def_scrn = 1;
+ *qv_scn = qv_scn_defaults[ qv_def_scrn ];
+ if (probed)
+ qp->qvaddr = qvaddr;
+ qp->bitmap = qvssmem;
+ qp->scanmap = (short *)((u_int)qvssmem + 254*1024);
+ qp->cursorbits = (short *)((u_int)qvssmem + 256*1024-32);
+ /* set up event queue for later */
+ qp->ibuff = (vsEvent *)qp - QVMAXEVQ;
+ qp->iqsize = QVMAXEVQ;
+ qp->ihead = qp->itail = 0;
+
+ /*
+ * Setup the crt controller chip.
+ */
+ for( i=0 ; i<16 ; i++ ) {
+ qvaddr->qv_crtaddr = i;
+ qvaddr->qv_crtdata = qv_crt_parms[ qv_def_scrn ][ i ];
+ }
+ /*
+ * Setup the display.
+ */
+ qv_init( qvaddr );
+
+ /*
+ * Turn on the video
+ */
+ qvaddr->qv_csr |= QV_VIDEO_ENA ;
+ return 1;
+}
+#endif
diff --git a/sys/arch/vax/uba/tmscp.c b/sys/arch/vax/uba/tmscp.c
deleted file mode 100644
index ef490d93e3d..00000000000
--- a/sys/arch/vax/uba/tmscp.c
+++ /dev/null
@@ -1,2211 +0,0 @@
-/* $NetBSD: tmscp.c,v 1.12 1996/04/08 18:37:30 ragge Exp $ */
-
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)tmscp.c 7.16 (Berkeley) 5/9/91
- */
-
-/*
- * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86";
- */
-
-/************************************************************************
- * *
- * Licensed from Digital Equipment Corporation *
- * Copyright (c) *
- * Digital Equipment Corporation *
- * Maynard, Massachusetts *
- * 1985, 1986 *
- * All rights reserved. *
- * *
- * The Information in this software is subject to change *
- * without notice and should not be construed as a commitment *
- * by Digital Equipment Corporation. Digital makes no *
- * representations about the suitability of this software for *
- * any purpose. It is supplied "As Is" without expressed or *
- * implied warranty. *
- * *
- * If the Regents of the University of California or its *
- * licensees modify the software in a manner creating *
- * diriviative copyright rights, appropriate copyright *
- * legends may be placed on the drivative work in addition *
- * to that set forth above. *
- * *
- ************************************************************************
- *
- * tmscp.c - TMSCP (TK50/TU81) tape device driver
- *
- * Modification History:
- *
- * 06-Jan-86 - afd
- * Changed the probe routine to use DELAY (not TODR). This now
- * works for MicroVAXen as well. This eliminates the busy-wait
- * for MicroVAXen so a dead TK50 controller will not hang autoconf.
- *
- * 06-Dec-85 - afd
- * Fixed a bug in density selection. The "set unit characteristics"
- * command to select density, was clearing the "unit flags" field
- * where the CACHE bit was for TU81-E. Now the unit's "format" and
- * "unitflgs" are saved in tms_info struct. And are used on STUNT
- * commands.
- *
- * 19-Oct-85 - afd
- * Added support to the open routine to allow drives to be opened
- * for low density (800 or 1600 bpi) use. When the slave routine
- * initiates a "get-unit-char" cmd, the format menu for the unit
- * is saved in the tms_info structure. The format menu is used in the
- * start routine to select the proper low density.
- *
- * 02-Oct-85 - afd
- * When a tmscp-type controller is initializing, it is possible for
- * the sa reg to become 0 between states. Thus the init code in
- * the interrupt routine had to be modified to reflect this.
- *
- * 21-Sep-85 - afd
- * The TK50 declares a serious exception when a tape mark is encountered.
- * This causes problems to dd (& other UN*X utilities). So a flag
- * is set in the rsp() routine when a tape mark is encountered. If
- * this flag is set, the start() routine appends the Clear Serious
- * Exception modifier to the next command.
- *
- * 03-Sep-85 -- jaw
- * messed up previous edit..
- *
- * 29-Aug-85 - jaw
- * fixed bugs in 8200 and 750 buffered datapath handling.
- *
- * 06-Aug-85 - afd
- * 1. When repositioning records or files, the count of items skipped
- * does NOT HAVE to be returned by controllers (& the TU81 doesn't).
- * So tmscprsp() had to be modified to stop reporting
- * residual count errors on reposition commands.
- *
- * 2. Fixed bug in the open routine which allowed multiple opens.
- *
- * 18-Jul-85 - afd
- * 1. Need to return status when mt status (or corresponding ioctl) is done.
- * Save resid, flags, endcode & status in tmscprsp() routine (except on
- * clear serious exception no-op). Return these fields when status
- * ioctl is done (in tmscpcommand()). How they are returned:
- * mt_resid = resid
- * mt_dsreg = flags|endcode
- * mt_erreg = status
- *
- * 2. Added latent support for enabling/disabling caching. This is
- * handled along with all other ioctl commands.
- *
- * 3. Need to issue a no-op on unrecognized ioctl in tmscpstart(), since
- * we have already commited to issuing a command at that point.
- *
- * 4. In tmscprsp() routine if encode is 0200 (invalid command issued);
- * We need to: Unlink the buffer from the I/O wait queue,
- * and signal iodone, so the higher level command can exit!
- * Just as if it were a valid command.
- *
- * 11-jul-85 -- jaw
- * fix bua/bda map registers.
- *
- * 19-Jun-85 -- jaw
- * VAX8200 name change.
- *
- * 06-Jun-85 - jaw
- * fixes for 8200.
- *
- * 9-Apr-85 - afd
- * Added timeout code to the probe routine, so if the controller
- * fails to init in 10 seconds we return failed status.
- *
- * 13-Mar-85 -jaw
- * Changes for support of the VAX8200 were merged in.
- *
- * 27-Feb-85 -tresvik
- * Changes for support of the VAX8600 were merged in.
- *
- */
-
-#define NTMS 2 /* XXX - This is _wery_ kludgy! /ragge */
-
-#include "tmscp.h"
-#if NTMSCP > 0
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/buf.h>
-#include <sys/conf.h>
-#include <sys/errno.h>
-#include <sys/file.h>
-#include <sys/map.h>
-#include <sys/ioctl.h>
-#include <sys/syslog.h>
-#include <sys/mtio.h>
-/* #include <sys/cmap.h> */
-#include <sys/uio.h>
-#include <sys/proc.h>
-#include <sys/tprintf.h>
-#include <sys/proc.h>
-
-#include <machine/pte.h>
-#include <machine/cpu.h>
-#include <machine/mtpr.h>
-#include <machine/sid.h>
-
-#include <vax/uba/ubareg.h>
-#include <vax/uba/ubavar.h>
-
-#define TENSEC (1000)
-#define TMS_PRI LOG_INFO
-
-#define NRSPL2 3 /* log2 number of response packets */
-#define NCMDL2 3 /* log2 number of command packets */
-#define NRSP (1<<NRSPL2)
-#define NCMD (1<<NCMDL2)
-
-#include <vax/uba/tmscpreg.h>
-#include <vax/vax/tmscpinf.h>
-#include <vax/vax/mscpvar.h>
-
-int tmscp_match __P((struct device *, void *, void *));
-void tmscp_attach __P((struct device *, struct device *, void *));
-void tmscpstrategy __P((struct buf *));
-
-struct cfdriver tmscp_cd = {
- NULL, "tmscp", DV_DULL
-};
-
-struct cfattach tmscp_ca = {
- sizeof(struct device), tmscp_match, tmscp_attach
-};
-
-/* Software state per controller */
-
-struct tmscp_softc {
- short sc_state; /* state of controller */
- short sc_mapped; /* Unibus map allocated for tmscp struct? */
- int sc_ubainfo; /* Unibus mapping info */
- struct tmscp *sc_tmscp; /* Unibus address of tmscp struct */
- int sc_ivec; /* interrupt vector address */
- short sc_credits; /* transfer credits */
- short sc_lastcmd; /* pointer into command ring */
- short sc_lastrsp; /* pointer into response ring */
- short sc_ipl; /* interrupt priority (Q-bus) */
-} tmscp_softc[NTMSCP];
-
-struct tmscp {
- struct tmscpca tmscp_ca; /* communications area */
- struct mscp tmscp_rsp[NRSP]; /* response packets */
- struct mscp tmscp_cmd[NCMD]; /* command packets */
-} tmscp[NTMSCP];
-
-int tmscpprobe __P((caddr_t, int, struct uba_ctlr *, struct uba_softc *));
-int tmscpslave __P((struct uba_device *, caddr_t));
-int tmscpinit __P((int));
-void tmscpattach __P((struct uba_device *));
-void tmscpintr __P((int));
-void tmscprsp __P((struct uba_ctlr *, struct tmscp *,
- struct tmscp_softc *, int));
-void tmscpstart __P((struct uba_ctlr *));
-void tmscpcommand __P((dev_t, int, int));
-struct mscp *tmscpgetcp __P((struct uba_ctlr *));
-void errinfo __P((int));
-int tmscpcmd __P((int, struct tmscp *, struct tmscpdevice *));
-
-int tmscpopen __P((dev_t, int, int, struct proc *p));
-int tmscpclose __P((dev_t, int, int, struct proc *p));
-void tmscpstrategy __P((struct buf *));
-int tmscpread __P((dev_t, struct uio *));
-int tmscpwrite __P((dev_t, struct uio *));
-int tmscpdump __P((dev_t, daddr_t, caddr_t, size_t));
-int tmscpioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-void tmscpreset __P((int));
-
-/*
- * Per drive-unit info
- */
-struct tms_info {
- daddr_t tms_dsize; /* Max user size from online pkt */
- unsigned tms_type; /* Drive type int field */
- int tms_resid; /* residual from last xfer */
- u_char tms_endcode; /* last command endcode */
- u_char tms_flags; /* last command end flags */
- unsigned tms_status; /* Command status from last command */
- char tms_openf; /* lock against multiple opens */
- char tms_lastiow; /* last op was a write */
- char tms_serex; /* set when serious exception occurs */
- char tms_clserex; /* set when serex being cleared by no-op */
- short tms_fmtmenu; /* the unit's format (density) menu */
- short tms_unitflgs; /* unit flag parameters */
- short tms_format; /* the unit's current format (density) */
- tpr_t tms_tpr; /* tprintf handle */
-} tms_info[NTMS];
-
-void tmserror __P((struct uba_ctlr *, struct mslg *));
-
-
-struct uba_ctlr *tmscpminfo[NTMSCP];
-struct uba_device *tmsdinfo[NTMS];
-/*
- * ifdef other tmscp devices here if they allow more than 1 unit/controller
- */
-struct uba_device *tmscpip[NTMSCP][1];
-struct buf ctmscpbuf[NTMSCP]; /* internal cmd buffer (for ioctls) */
-struct buf tmsutab[NTMS]; /* Drive queue */
-struct buf tmscpwtab[NTMSCP]; /* I/O wait queue, per controller */
-int tmscpmicro[NTMSCP]; /* to store microcode level */
-short utoctlr[NTMS]; /* Slave unit to controller mapping */
- /* filled in by the slave routine */
-
-/* Bits in minor device */
-#define TMSUNIT(dev) (minor(dev)&03)
-#define T_HIDENSITY 010
-
-/* Slave unit to controller mapping */
-#define TMSCPCTLR(dev) (utoctlr[TMSUNIT(dev)])
-
-/*
- * Internal (ioctl) command codes (these must also be declared in the
- * tmscpioctl routine). These correspond to ioctls in mtio.h
- */
-#define TMS_WRITM 0 /* write tape mark */
-#define TMS_FSF 1 /* forward space file */
-#define TMS_BSF 2 /* backward space file */
-#define TMS_FSR 3 /* forward space record */
-#define TMS_BSR 4 /* backward space record */
-#define TMS_REW 5 /* rewind tape */
-#define TMS_OFFL 6 /* rewind tape & mark unit offline */
-#define TMS_SENSE 7 /* noop - do a get unit status */
-#define TMS_CACHE 8 /* enable cache */
-#define TMS_NOCACHE 9 /* disable cache */
-/* These go last: after all real mt cmds, just bump the numbers up */
-#define TMS_CSE 10 /* clear serious exception */
-#define TMS_LOWDENSITY 11 /* set unit to low density */
-#define TMS_HIDENSITY 12 /* set unit to high density */
-
-/*
- * Controller states
- */
-#define S_IDLE 0 /* hasn't been initialized */
-#define S_STEP1 1 /* doing step 1 init */
-#define S_STEP2 2 /* doing step 2 init */
-#define S_STEP3 3 /* doing step 3 init */
-#define S_SCHAR 4 /* doing "set controller characteristics" */
-#define S_RUN 5 /* running */
-
-int tmscperror = 0; /* causes hex dump of packets */
-int tmscp_cp_wait = 0; /* Something to wait on for command */
- /* packets and or credits. */
-extern int hz; /* Should find the right include */
-
-#ifdef DEBUG
-#define printd if (tmscpdebug) printf
-int tmscpdebug = 1;
-#define printd10 if(tmscpdebug >= 10) printf
-#endif
-
-#define DRVNAME "tms"
-#define CTRLNAME "tmscp"
-
-u_short tmscpstd[] = { 0174504, 0 };
-struct uba_driver tmscpdriver =
-{ tmscpprobe, tmscpslave, tmscpattach, 0, tmscpstd, DRVNAME, tmsdinfo, CTRLNAME
-, tmscpminfo, 0};
-
-#define b_qsize b_resid /* queue size per drive, in tmsutab */
-#define b_ubinfo b_resid /* Unibus mapping info, per buffer */
-
-
-/*************************************************************************/
-
-#define DELAYTEN 1000
-extern struct cfdriver uba_cd;
-
-/*
- * Unfortunately qbgetpri can't be used because the TK50 doesn't flip the
- * TMSCP_STEP2 flag in the tmscpsa register until after the pending interrupt
- * has been acknowledged by the cpu. If you are at spl6(), the TMSCP_STEP2
- * flag never gets set and you return (0).
- */
-int
-tmscpprobe(reg, ctlr, um, uh)
- caddr_t reg; /* address of the IP register */
- int ctlr; /* index of controller in the tmscp_softc array */
- struct uba_ctlr *um;
- struct uba_softc *uh;
-{
- /* register int br, cvec; MUST be 1st (r11 & r10): IPL and intr vec */
- register struct tmscp_softc *sc = &tmscp_softc[ctlr];
- /* ptr to software controller structure */
- volatile struct tmscpdevice *tmscpaddr;
- int count; /* for probe delay time out */
- struct uba_softc *ubasc;
-
-# ifdef lint
- br = 0; cvec = br; br = cvec; reg = reg;
- tmscpreset(0); tmscpintr(0);
-# endif
-
- tmscpminfo[ctlr] = um;
- tmscpaddr = (struct tmscpdevice *) reg;
- /*
- * Set host-settable interrupt vector.
- * Assign 0 to the ip register to start the tmscp-device initialization.
- * The device is not really initialized at this point, this is just to
- * find out if the device exists.
- */
- ubasc = uba_cd.cd_devs[0]; /* XXX */
- sc->sc_ivec = (ubasc->uh_lastiv -= 4);
- tmscpaddr->tmscpip = 0;
-
- count=0;
- while(count < DELAYTEN)
- { /* wait for at most 10 secs */
- if((tmscpaddr->tmscpsa & TMSCP_STEP1) != 0)
- break;
- DELAY(10000);
- count=count+1;
- }
- if (count == DELAYTEN)
- return(0);
-
- tmscpaddr->tmscpsa = TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
-
- count=0;
- while(count < DELAYTEN)
- {
- if((tmscpaddr->tmscpsa & TMSCP_STEP2) != 0)
- break;
- DELAY(10000);
- count = count+1;
- }
- if (count == DELAYTEN)
- return(0);
-
-#ifdef QBA
- sc->sc_ipl = 0x15;
-#endif
- return(sizeof (struct tmscpdevice));
-}
-
-/*
- * Try to find a slave (a drive) on the controller.
- * If the controller is not in the run state, call init to initialize it.
- */
-int
-tmscpslave (ui, reg)
- struct uba_device *ui; /* ptr to the uba device structure */
- caddr_t reg; /* addr of the device controller */
-{
- register struct uba_ctlr *um = tmscpminfo[ui->ui_ctlr];
- volatile struct tmscp_softc *sc = &tmscp_softc[ui->ui_ctlr];
- volatile struct tms_info *tms = &tms_info[ui->ui_unit];
- volatile struct tmscpdevice *tmscpaddr; /* ptr to IP & SA */
- volatile struct mscp *mp;
- volatile int i; /* Something to write into to start */
- /* the tmscp polling */
-
-# ifdef lint
- reg = reg;
-# endif
- tmscpaddr = (struct tmscpdevice *)um->um_addr;
- /*
- * If its not in the run state, start the initialization process
- * (tmscpintr will complete it); if the initialization doesn't start;
- * then return.
- */
- if(sc->sc_state != S_RUN)
- {
-# ifdef DEBUG
- printd("tmscpslave: ctlr not running: calling init \n");
-# endif
- if(!tmscpinit(ui->ui_ctlr))
- return(0);
- }
- /*
- * Wait for the controller to come into the run state or go idle.
- * If it goes idle return.
- */
-# ifdef DEBUG
- i=1;
-# endif
- while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE)
-# ifdef DEBUG
- if (tmscpaddr->tmscpsa & TMSCP_ERR && i)
- {
- printd("tmscp-device: fatal error (%o)\n", tmscpaddr->tmscpsa&0xffff);
- i=0;
- }
-# endif
- ; /* wait */
- if(sc->sc_state == S_IDLE)
- { /* The tmscp device failed to initialize */
- printf("tmscp controller failed to init\n");
- return(0);
- }
- /* The controller is up so see if the drive is there */
- if(0 == (mp = tmscpgetcp(um)))
- {
- printf("tmscp can't get command packet\n");
- return(0);
- }
- /* Need to determine the drive type for generic driver */
- mp->mscp_opcode = M_OP_GTUNT; /* This should give us the device type */
- mp->mscp_unit = ui->ui_slave;
- mp->mscp_cmdref = (long) ui->ui_slave;
- tms->tms_status = 0; /* set to zero */
- tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
- *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;/* maybe we should poll*/
- i = tmscpaddr->tmscpip;
-#ifdef lint
- i = i;
-#endif
- while(!tms->tms_status)
- ; /* Wait for some status */
-# ifdef DEBUG
- printd("tmscpslave: status = %o\n",tms->tms_status & M_ST_MASK);
-# endif
- tmscpip[ui->ui_ctlr][ui->ui_slave] = 0;
- if(!tms->tms_type) /* packet from a GTUNT */
- return(0); /* Failed No such drive */
- else
- return(1); /* Got it and it is there */
-}
-
-
-/*
- * Set ui flags to zero to show device is not online & set tmscpip.
- * Unit to Controller mapping is set up here.
- * Open routine will issue the online command, later.
- */
-void
-tmscpattach (ui)
- register struct uba_device *ui; /* ptr to unibus dev struct */
-{
-
- ui->ui_flags = 0;
- tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
-# ifdef DEBUG
- /*
- * Check to see if the drive is available.
- * If not then just print debug.
- */
- if(tms_info[ui->ui_unit].tms_status != M_ST_AVLBL)
- printd("tmscpattach: unavailable \n");
-# endif
- utoctlr[ui->ui_unit] = ui->ui_ctlr;
-}
-
-
-/*
- * TMSCP interrupt routine.
- */
-void
-tmscpintr(d)
- int d;
-{
- volatile struct uba_ctlr *um = tmscpminfo[d];
- volatile struct tmscpdevice *tmscpaddr =
- (struct tmscpdevice *)um->um_addr;
- struct buf *bp;
- volatile int i;
- volatile struct tmscp_softc *sc = &tmscp_softc[d];
- struct tmscp *tm = &tmscp[d];
- struct tmscp *ttm;
- volatile struct mscp *mp;
-
-# ifdef DEBUG
- printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa);
-# endif
-
-#ifdef QBA
- if (cpunumber == VAX_78032)
- splx(sc->sc_ipl);
-#endif
- /*
- * How the interrupt is handled depends on the state of the controller.
- */
- switch (sc->sc_state) {
-
- case S_IDLE:
- printf("tmscp%d: random interrupt ignored\n", d);
- return;
-
- /* Controller was in step 1 last, see if its gone to step 2 */
- case S_STEP1:
-# define STEP1MASK 0174377
-# define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
- for (i = 0; i < 150; i++)
- {
- if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
- { /* still in step 1 (wait 1/100 sec) */
- DELAY(10000);
-# ifdef DEBUG
- printd("still in step 1, delaying\n");
-# endif DEBUG
- }
- else
- break;
- }
- if (i > 149)
- {
- sc->sc_state = S_IDLE;
- printf("failed to initialize, in step1: sa 0x%x", tmscpaddr->tmscpsa);
- wakeup((caddr_t)um);
- return;
- }
- tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)
- | ((cpunumber == VAX_780 || cpunumber == VAX_8600) ?
- TMSCP_PI : 0);
- sc->sc_state = S_STEP2;
- return;
-
- /* Controller was in step 2 last, see if its gone to step 3 */
- case S_STEP2:
-# define STEP2MASK 0174377
-# define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
- for (i = 0; i < 150; i++)
- {
- if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
- { /* still in step 2 (wait 1/100 sec) */
- DELAY(10000);
-# ifdef DEBUG
- printd("still in step 2, delaying\n");
-# endif DEBUG
- }
- else
- break;
- }
- if (i > 149)
- {
- sc->sc_state = S_IDLE;
- printf("failed to initialize, in step2: sa 0x%x", tmscpaddr->tmscpsa);
- wakeup((caddr_t)um);
- return;
- }
- tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)>>16;
- sc->sc_state = S_STEP3;
- return;
-
- /* Controller was in step 3 last, see if its gone to step 4 */
- case S_STEP3:
-# define STEP3MASK 0174000
-# define STEP3GOOD TMSCP_STEP4
- for (i = 0; i < 150; i++)
- {
- if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
- { /* still in step 3 (wait 1/100 sec) */
- DELAY(10000);
-# ifdef DEBUG
- printd("still in step 3, delaying\n");
-# endif DEBUG
- }
- else
- break;
- }
- if (i > 149)
- {
- sc->sc_state = S_IDLE;
- printf("failed to initialize, in step3: sa 0x%x", tmscpaddr->tmscpsa);
- wakeup((caddr_t)um);
- return;
- }
- /*
- * Get microcode version and model number of controller;
- * Signal initialization complete (_GO) (to the controller);
- * ask for Last Fail response if tmscperror is set;
- * Set state to "set controller characteristics".
- */
- tmscpmicro[d] = tmscpaddr->tmscpsa;
- tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0);
- sc->sc_state = S_SCHAR;
-# ifdef DEBUG
- printd("tmscpintr: completed state %d \n", sc->sc_state);
- printd("tmscp%d Version %d model %d\n",d,tmscpmicro[d]&0xF,
- (tmscpmicro[d]>>4) & 0xF);
-# endif
-
- /*
- * Initialize the data structures (response and command queues).
- */
- ttm = sc->sc_tmscp;
- for (i = 0; i < NRSP; i++)
- {
- tm->tmscp_ca.ca_rspdsc[i] = TMSCP_OWN | TMSCP_INT |
- (long)&ttm->tmscp_rsp[i].mscp_cmdref;
- tm->tmscp_rsp[i].mscp_dscptr = &tm->tmscp_ca.ca_rspdsc[i];
- tm->tmscp_rsp[i].mscp_header.tmscp_msglen = mscp_msglen;
- }
- for (i = 0; i < NCMD; i++)
- {
- tm->tmscp_ca.ca_cmddsc[i] = TMSCP_INT |
- (long)&ttm->tmscp_cmd[i].mscp_cmdref;
- tm->tmscp_cmd[i].mscp_dscptr = &tm->tmscp_ca.ca_cmddsc[i];
- tm->tmscp_cmd[i].mscp_header.tmscp_msglen = mscp_msglen;
- tm->tmscp_cmd[i].mscp_header.tmscp_vcid = 1;
- }
- bp = &tmscpwtab[d];
- bp->b_actf = NULL;
- sc->sc_lastcmd = 1;
- sc->sc_lastrsp = 0;
- mp = &tmscp[d].tmscp_cmd[0];
- mp->mscp_unit = mp->mscp_modifier = 0;
- mp->mscp_flags = 0;
- mp->mscp_version = 0;
- mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;
- /*
- * A host time out value of 0 means that the controller will not
- * time out. This is ok for the TK50.
- */
- mp->mscp_hsttmo = 0;
- mp->mscp_time = 0;
- mp->mscp_cntdep = 0;
- mp->mscp_opcode = M_OP_STCON;
- *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
- i = tmscpaddr->tmscpip; /* initiate polling */
- return;
-
- case S_SCHAR:
- case S_RUN:
- break;
-
- default:
- printf("tmscp%d: interrupt in unknown state %d ignored\n",d,sc->sc_state);
- return;
- } /* end switch */
-
- /*
- * The controller state is S_SCHAR or S_RUN
- */
-
- /*
- * If the error bit is set in the SA register then print an error
- * message and reinitialize the controller.
- */
- if (tmscpaddr->tmscpsa&TMSCP_ERR)
- {
- printf("tmscp%d: fatal error (%o)\n", d, tmscpaddr->tmscpsa&0xffff);
- tmscpaddr->tmscpip = 0;
- wakeup((caddr_t)um);
- }
- /*
- * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus)
- */
- if (tm->tmscp_ca.ca_bdp)
- {
- UBAPURGE(um->um_hd->uh_uba, tm->tmscp_ca.ca_bdp);
- tm->tmscp_ca.ca_bdp = 0;
- tmscpaddr->tmscpsa = 0; /* signal purge complete */
- }
-
- /*
- * Check for response ring transition.
- */
- if (tm->tmscp_ca.ca_rspint)
- {
- tm->tmscp_ca.ca_rspint = 0;
- for (i = sc->sc_lastrsp;; i++)
- {
- i %= NRSP;
- if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
- break;
- tmscprsp((struct uba_ctlr *)um, tm,
- (struct tmscp_softc *)sc, i);
- tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
- }
- sc->sc_lastrsp = i;
- }
-
- /*
- * Check for command ring transition.
- */
- if (tm->tmscp_ca.ca_cmdint)
- {
-# ifdef DEBUG
- printd("tmscpintr: command ring transition\n");
-# endif
- tm->tmscp_ca.ca_cmdint = 0;
- }
- if(tmscp_cp_wait)
- wakeup((caddr_t)&tmscp_cp_wait);
- (void) tmscpstart((struct uba_ctlr *)um);
-}
-
-
-/*
- * Open a tmscp device and set the unit online. If the controller is not
- * in the run state, call init to initialize the tmscp controller first.
- */
-
-/* ARGSUSED */
-int
-tmscpopen(dev, flag, type, p)
- dev_t dev;
- int flag, type;
- struct proc *p;
-{
- register int unit;
- register struct uba_device *ui;
- register struct tmscp_softc *sc;
- register struct tms_info *tms;
- register volatile struct mscp *mp;
- register struct uba_ctlr *um;
- volatile struct tmscpdevice *tmscpaddr;
- volatile int i;
- int s;
-
- unit = TMSUNIT(dev);
-# ifdef DEBUG
- printd("tmscpopen unit %d\n",unit);
- if(tmscpdebug)DELAY(10000);
-# endif
- if (unit >= NTMS || (ui = tmsdinfo[unit]) == 0 || ui->ui_alive == 0)
- return (ENXIO);
- tms = &tms_info[ui->ui_unit];
- if (tms->tms_openf)
- return (EBUSY);
- sc = &tmscp_softc[ui->ui_ctlr];
- tms->tms_openf = 1;
- tms->tms_tpr = tprintf_open(curproc);
- s = splbio();
- if (sc->sc_state != S_RUN)
- {
- if (sc->sc_state == S_IDLE)
- if(!tmscpinit(ui->ui_ctlr))
- {
- printf("tmscp controller failed to init\n");
- (void) splx(s);
- tms->tms_openf = 0;
- return(ENXIO);
- }
- /*
- * Wait for initialization to complete
- */
- timeout(wakeup,(caddr_t)ui->ui_mi,11*hz); /* to be sure*/
- sleep((caddr_t)ui->ui_mi, 0);
- if (sc->sc_state != S_RUN)
- {
- (void) splx(s);
- tms->tms_openf = 0;
- return (EIO);
- }
- }
- /*
- * Check to see if the device is really there.
- * this code was taken from Fred Canters 11 driver
- */
- um = ui->ui_mi;
- tmscpaddr = (struct tmscpdevice *) um->um_addr;
- (void) splx(s);
- if(ui->ui_flags == 0)
- {
- s = splbio();
- while(0 ==(mp = tmscpgetcp(um)))
- {
- tmscp_cp_wait++;
- sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
- tmscp_cp_wait--;
- }
- (void) splx(s);
- mp->mscp_opcode = M_OP_ONLIN;
- mp->mscp_unit = ui->ui_slave;
- mp->mscp_cmdref = (long) & tms->tms_type;
- /* need to sleep on something */
-# ifdef DEBUG
- printd("tmscpopen: bring unit %d online\n",ui->ui_unit);
-# endif
- *((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;
- i = tmscpaddr->tmscpip;
-#ifdef lint
- i = i;
-#endif
- /*
- * To make sure we wake up, timeout in 240 seconds.
- * Wakeup in tmscprsp routine.
- * 240 seconds (4 minutes) is necessary since a rewind
- * can take a few minutes.
- */
- timeout(wakeup,(caddr_t) mp->mscp_cmdref,240 * hz);
- sleep((caddr_t) mp->mscp_cmdref,PSWP+1);
- }
- if(ui->ui_flags == 0) {
- tms->tms_openf = 0;
- return(ENXIO); /* Didn't go online */
- }
- tms->tms_lastiow = 0;
- /*
- * If the high density device is not specified, set unit to low
- * density. This is done as an "internal" ioctl command so
- * that the command setup and response handling
- * is done thru "regular" command routines.
- */
- if ((minor(dev) & T_HIDENSITY) == 0)
- tmscpcommand(dev, TMS_LOWDENSITY, 1);
- else
- tmscpcommand(dev, TMS_HIDENSITY, 1);
- return (0);
-}
-
-
-/*
- * Close tape device.
- *
- * If tape was open for writing or last operation was
- * a write, then write two EOF's and backspace over the last one.
- * Unless this is a non-rewinding special file, rewind the tape.
- *
- * NOTE:
- * We want to be sure that any serious exception is cleared on the
- * close. A Clear Serious Exception (CSE) modifier is always done on
- * the rewind command. For the non-rewind case we check to see if the
- * "serex" field is set in the softc struct; if it is then issue a noop
- * command with the CSE modifier.
- * Make the tape available to others, by clearing openf flag.
- */
-int
-tmscpclose(dev, flag, type, p)
- register dev_t dev;
- register flag, type;
- struct proc *p;
-{
- register struct tms_info *tms;
- register struct uba_device *ui;
-
- ui = tmsdinfo[TMSUNIT(dev)];
-# ifdef DEBUG
- printd("tmscpclose: ctlr = %d\n",TMSCPCTLR(dev));
- printd("tmscpclose: unit = %d\n",TMSUNIT(dev));
- if(tmscpdebug)DELAY(10000);
-# endif
- tms = &tms_info[ui->ui_unit];
- if (flag == FWRITE || ((flag&FWRITE) && tms->tms_lastiow))
- {
- /* device, command, count */
- tmscpcommand (dev, TMS_WRITM, 1);
- tmscpcommand (dev, TMS_WRITM, 1);
- tmscpcommand (dev, TMS_BSR, 1);
- }
- if ((minor(dev)&T_NOREWIND) == 0)
- /*
- * Don't hang waiting for rewind complete.
- */
- tmscpcommand(dev, TMS_REW, 0);
- else
- if (tms->tms_serex)
- {
-# ifdef DEBUG
- printd("tmscpclose: clearing serex\n");
- if(tmscpdebug)DELAY(10000);
-# endif
- tmscpcommand(dev, TMS_CSE, 1);
- }
- tprintf_close(tms->tms_tpr);
- tms->tms_openf = 0;
- return (0);
-}
-
-
-/*
- * Execute a command on the tape drive a specified number of times.
- * This routine sets up a buffer and calls the strategy routine which
- * links the buffer onto the drive's buffer queue.
- * The start routine will take care of creating a tmscp command packet
- * with the command. The start routine is called by the strategy or the
- * interrupt routine.
- */
-void
-tmscpcommand (dev, com, count)
- register dev_t dev;
- int com, count;
-{
- register struct uba_device *ui;
- register struct buf *bp;
- register int s;
- int unit = TMSUNIT(dev);
-
- ui = tmsdinfo[unit];
- bp = &ctmscpbuf[ui->ui_ctlr];
-
- s = splbio();
- while (bp->b_flags&B_BUSY)
- {
- /*
- * This special check is because B_BUSY never
- * gets cleared in the non-waiting rewind case.
- */
- if (bp->b_bcount == 0 && (bp->b_flags&B_DONE))
- break;
- bp->b_flags |= B_WANTED;
- sleep((caddr_t)bp, PRIBIO);
- }
- bp->b_flags = B_BUSY|B_READ;
- splx(s);
- /*
- * Load the buffer. The b_count field gets used to hold the command
- * count. the b_resid field gets used to hold the command mneumonic.
- * These 2 fields are "known" to be "safe" to use for this purpose.
- * (Most other drivers also use these fields in this way.)
- */
- bp->b_dev = dev;
- bp->b_bcount = count;
- bp->b_resid = com;
- bp->b_blkno = 0;
- tmscpstrategy(bp);
- /*
- * In case of rewind from close, don't wait.
- * This is the only case where count can be 0.
- */
- if (count == 0)
- return;
- iowait(bp);
- if (bp->b_flags&B_WANTED)
- wakeup((caddr_t)bp);
- bp->b_flags &= B_ERROR;
-}
-
-/*
- * Find an unused command packet
- */
-struct mscp *
-tmscpgetcp(um)
- struct uba_ctlr *um;
-{
- register volatile struct mscp *mp;
- register volatile struct tmscpca *cp;
- register struct tmscp_softc *sc;
- register int i;
- int s;
-
- s = splbio();
- cp = &tmscp[um->um_ctlr].tmscp_ca;
- sc = &tmscp_softc[um->um_ctlr];
- /*
- * If no credits, can't issue any commands
- * until some outstanding commands complete.
- */
- i = sc->sc_lastcmd;
-# ifdef DEBUG
- printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits);
-# endif
- if(((cp->ca_cmddsc[i]&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
- (sc->sc_credits >= 2))
- {
- sc->sc_credits--; /* This commits to issuing a command */
- cp->ca_cmddsc[i] &= ~TMSCP_INT;
- mp = &tmscp[um->um_ctlr].tmscp_cmd[i];
- mp->mscp_unit = mp->mscp_modifier = 0;
- mp->mscp_opcode = mp->mscp_flags = 0;
- mp->mscp_bytecnt = mp->mscp_buffer = 0;
- sc->sc_lastcmd = (i + 1) % NCMD;
- (void) splx(s);
- return((struct mscp *)mp);
- }
- (void) splx(s);
- return(NULL);
-}
-
-
-/*
- * Initialize a TMSCP device. Set up UBA mapping registers,
- * initialize data structures, and start hardware
- * initialization sequence.
- */
-int
-tmscpinit (d)
- int d; /* index to the controller */
-{
- register struct tmscp_softc *sc;
- register struct tmscp *t;
- volatile struct tmscpdevice *tmscpaddr;
- struct uba_ctlr *um;
-
- sc = &tmscp_softc[d];
- um = tmscpminfo[d];
- um->um_tab.b_active++;
- t = &tmscp[d];
- tmscpaddr = (struct tmscpdevice *)um->um_addr;
- if (sc->sc_mapped == 0)
- {
- /*
- * Map the communications area and command
- * and response packets into Unibus address
- * space.
- */
- sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)t, sizeof (struct tmscp), 0);
- sc->sc_tmscp = (struct tmscp *)(UBAI_ADDR(sc->sc_ubainfo));
- sc->sc_mapped = 1;
- }
-
- /*
- * Start the hardware initialization sequence.
- */
- tmscpaddr->tmscpip = 0; /* start initialization */
-
- while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
- {
-# ifdef DEBUG
- printd("tmscpinit: tmscpsa = 0%o\n",tmscpaddr->tmscpsa);
- DELAY(100000);
-# endif
- if(tmscpaddr->tmscpsa & TMSCP_ERR)
- return(0); /* CHECK */
- }
- tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
- /*
- * Initialization continues in the interrupt routine.
- */
- sc->sc_state = S_STEP1;
- sc->sc_credits = 0;
- return(1);
-}
-
-
-/*
- * Start I/O operation
- * This code is convoluted. The majority of it was copied from the uda driver.
- */
-void
-tmscpstart(um)
- register struct uba_ctlr *um;
-{
- register struct buf *bp, *dp;
- register volatile struct mscp *mp;
- register struct tmscp_softc *sc;
- register struct tms_info *tms;
- register struct uba_device *ui;
- volatile struct tmscpdevice *tmscpaddr;
- volatile struct tmscp *tm = &tmscp[um->um_ctlr];
- volatile int i;
- int tempi;
- char ioctl; /* flag: set true if its an IOCTL command */
-
- sc = &tmscp_softc[um->um_ctlr];
-
- for(;;)
- {
- if ((dp = um->um_tab.b_actf) == NULL)
- {
- /*
- * Release unneeded UBA resources and return
- * (drive was inactive)
- */
- um->um_tab.b_active = 0;
- break;
- }
- if ((bp = dp->b_actf) == NULL)
- {
- /*
- * No more requests for this drive, remove
- * from controller queue and look at next drive.
- * We know we're at the head of the controller queue.
- */
- dp->b_active = 0;
- um->um_tab.b_actf = dp->b_hash.le_next;
- continue; /* Need to check for loop */
- }
- um->um_tab.b_active++;
- tmscpaddr = (struct tmscpdevice *)um->um_addr;
- ui = tmsdinfo[(TMSUNIT(bp->b_dev))];
- tms = &tms_info[ui->ui_unit];
- if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
- {
- tprintf(tms->tms_tpr,
- "tms%d: hard error bn%d\n",
- minor(bp->b_dev)&03, bp->b_blkno);
- log(TMS_PRI, "tmscp%d: sa 0%o, state %d\n",um->um_ctlr,
- tmscpaddr->tmscpsa&0xffff, sc->sc_state);
- (void)tmscpinit(um->um_ctlr);
- /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
- break;
- }
- /*
- * Default is that last command was NOT a write command;
- * if a write command is done it will be detected in tmscprsp.
- */
- tms->tms_lastiow = 0;
- if (ui->ui_flags == 0)
- { /* not online */
- if ((mp = tmscpgetcp(um)) == NULL)
- break;
- mp->mscp_opcode = M_OP_ONLIN;
- mp->mscp_unit = ui->ui_slave;
- dp->b_active = 2;
- um->um_tab.b_actf = dp->b_hash.le_next; /* remove from controller q */
- *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
- if (tmscpaddr->tmscpsa&TMSCP_ERR)
- printf("tmscp%d fatal error (0%o)\n",um->um_ctlr,
- tmscpaddr->tmscpsa&0xffff);
- i = tmscpaddr->tmscpip;
- continue;
- }
- switch (cpunumber) {
-
- case VAX_8600:
- case VAX_780:
- i = UBA_NEEDBDP|UBA_CANTWAIT;
- break;
- case VAX_750:
- i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT;
- break;
- case VAX_730:
- case VAX_78032:
- i = UBA_CANTWAIT;
- break;
- } /* end switch (cpunumber) */
- /*
- * If command is an ioctl command then set the ioctl flag for later use.
- * If not (i.e. it is a read or write) then attempt
- * to set up a buffer pointer.
- */
- ioctl = 0;
- if (bp == &ctmscpbuf[um->um_ctlr])
- ioctl = 1;
- else
- if ((i = ubasetup(um->um_ubanum, bp, i)) == 0)
- {
- if(dp->b_qsize != 0)
- break; /* When a command completes and */
- /* frees a bdp tmscpstart will be called */
- if ((mp = tmscpgetcp(um)) == NULL)
- break;
-# ifdef DEBUG
- printd("tmscpstart: GTUNT %d ubasetup = %d\n",ui->ui_unit, i);
- if(tmscpdebug)DELAY(10000);
-# endif
- mp->mscp_opcode = M_OP_GTUNT;
- mp->mscp_unit = ui->ui_slave;
- *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
- if (tmscpaddr->tmscpsa&TMSCP_ERR)
- printf("tmscp%d: fatal error (0%o)\n",um->um_ctlr,
- tmscpaddr->tmscpsa&0xffff);
- i = tmscpaddr->tmscpip; /* initiate polling */
- break;
- }
-# if defined(VAX750)
- if (cpunumber == VAX_750)
- tempi = i & 0xfffffff; /* mask off bdp */
- else
-# endif
- tempi = i;
- if ((mp = tmscpgetcp(um)) == NULL)
- {
- if (!ioctl) /* only need to release if NOT ioctl */
- ubarelse(um->um_ubanum,&tempi);
- break;
- }
- mp->mscp_cmdref = (long)bp; /* pointer to get back */
- mp->mscp_unit = ui->ui_slave;
- /*
- * If its an ioctl-type command then set up the appropriate
- * tmscp command; by doing a switch on the "b_resid" field where
- * the command mneumonic is stored.
- */
- if (ioctl)
- {
-# ifdef DEBUG
- printd("tmscpstart: doing ioctl cmd %d\n", bp->b_resid);
-# endif
- /*
- * The reccnt and tmkcnt fields are set to zero by the getcp
- * routine (as bytecnt and buffer fields). Thus reccnt and
- * tmkcnt are only modified here if they need to be set to
- * a non-zero value.
- */
- switch ((int)bp->b_resid) {
-
- case TMS_WRITM:
- mp->mscp_opcode = M_OP_WRITM;
- break;
- case TMS_FSF:
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_tmkcnt = bp->b_bcount;
- break;
- case TMS_BSF:
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_modifier = M_MD_REVRS;
- mp->mscp_tmkcnt = bp->b_bcount;
- break;
- case TMS_FSR:
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_modifier = M_MD_OBJCT;
- mp->mscp_reccnt = bp->b_bcount;
- break;
- case TMS_BSR:
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT;
- mp->mscp_reccnt = bp->b_bcount;
- break;
- /*
- * Clear serious exception is done for Rewind & Available cmds
- */
- case TMS_REW:
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX;
- if (bp->b_bcount == 0)
- mp->mscp_modifier |= M_MD_IMMED;
- tms->tms_serex = 0;
- break;
- case TMS_OFFL:
- mp->mscp_opcode = M_OP_AVAIL;
- mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX;
- tms->tms_serex = 0;
- break;
- case TMS_SENSE:
- mp->mscp_opcode = M_OP_GTUNT;
- break;
- case TMS_CACHE:
- mp->mscp_opcode = M_OP_STUNT;
- tms->tms_unitflgs |= M_UF_WBKNV;
- mp->mscp_unitflgs = tms->tms_unitflgs;
- mp->mscp_format = tms->tms_format;
- /* default device dependant parameters */
- mp->mscp_mediaid = 0;
- break;
- case TMS_NOCACHE:
- mp->mscp_opcode = M_OP_STUNT;
- tms->tms_unitflgs &= ~(M_UF_WBKNV);
- mp->mscp_unitflgs = tms->tms_unitflgs;
- mp->mscp_format = tms->tms_format;
- /* default device dependant parameters */
- mp->mscp_mediaid = 0;
- break;
- case TMS_CSE:
- /*
- * This is a no-op command. It performs a
- * clear serious exception only. (Done on a
- * non-rewinding close after a serious exception.)
- */
- mp->mscp_opcode = M_OP_REPOS;
- mp->mscp_modifier = M_MD_CLSEX;
- tms->tms_serex = 0;
- tms->tms_clserex = 1;
- break;
- case TMS_LOWDENSITY:
- /*
- * Set the unit to low density
- */
- mp->mscp_opcode = M_OP_STUNT;
- mp->mscp_unitflgs = tms->tms_unitflgs;
- mp->mscp_mediaid = 0; /* default device dependant parameters */
- if ((tms->tms_fmtmenu & M_TF_800) != 0)
- mp->mscp_format = M_TF_800;
- else
- mp->mscp_format = M_TF_PE & tms->tms_fmtmenu;
- tms->tms_format = mp->mscp_format;
- break;
- case TMS_HIDENSITY:
- /*
- * Set the unit to high density (format == 0)
- */
- mp->mscp_opcode = M_OP_STUNT;
- mp->mscp_unitflgs = tms->tms_unitflgs;
- mp->mscp_mediaid = 0; /* default device dependant parameters */
- mp->mscp_format = 0;
- tms->tms_format = 0;
- break;
- default:
- printf("Bad ioctl on tms unit %d\n", ui->ui_unit);
- /* Need a no-op. Reposition no amount */
- mp->mscp_opcode = M_OP_REPOS;
- break;
- } /* end switch (bp->b_resid) */
- }
- else /* Its a read/write command (not an ioctl) */
- {
- mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE;
- mp->mscp_bytecnt = bp->b_bcount;
- mp->mscp_buffer = UBAI_ADDR(i) | (UBAI_BDP(i) << 24);
-
- bp->b_ubinfo = tempi; /* save mapping info */
- }
- if (tms->tms_serex == 2) /* if tape mark read */
- {
- mp->mscp_modifier |= M_MD_CLSEX; /* clear serious exc */
- tms->tms_serex = 0;
- }
- *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
-# ifdef DEBUG
- printd("tmscpstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt);
- if(tmscpdebug)DELAY(100000);
-# endif
- i = tmscpaddr->tmscpip; /* initiate polling */
- dp->b_qsize++;
- /*
- * Move drive to the end of the controller queue
- */
- if (dp->b_hash.le_next != NULL)
- {
- um->um_tab.b_actf = dp->b_hash.le_next;
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- }
- /*
- * Move buffer to I/O wait queue
- */
- dp->b_actf = bp->b_actf;
- dp = &tmscpwtab[um->um_ctlr];
- MSCP_APPEND(bp, dp, b_actf);
- if (tmscpaddr->tmscpsa&TMSCP_ERR)
- {
- printf("tmscp%d: fatal error (0%o)\n", um->um_ctlr, tmscpaddr->tmscpsa&0xffff);
- (void)tmscpinit(um->um_ctlr);
- break;
- }
- } /* end for */
- /*
- * Check for response ring transitions lost in the
- * Race condition
- */
- for (i = sc->sc_lastrsp;; i++)
- {
- i %= NRSP;
- if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
- break;
- tmscprsp(um, (struct tmscp *)tm, sc, i);
- tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
- }
- sc->sc_lastrsp = i;
-}
-
-
-/*
- * Process a response packet
- */
-void
-tmscprsp(um, tm, sc, i)
- register struct uba_ctlr *um;
- struct tmscp *tm;
- register struct tmscp_softc *sc;
- int i;
-{
- register volatile struct mscp *mp;
- register struct tms_info *tms;
- struct uba_device *ui;
- struct buf *dp, *bp;
- int st;
- struct uba_softc *ubasc;
-
- mp = &tm->tmscp_rsp[i];
- mp->mscp_header.tmscp_msglen = mscp_msglen;
- sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */
- if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */
- return;
-# ifdef DEBUG
- printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK);
-# endif
- /*
- * If it's an error log message (datagram),
- * pass it on for more extensive processing.
- */
- if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10)
- { /* check */
- tmserror(um, (struct mslg *)mp);
- return;
- }
- st = mp->mscp_status&M_ST_MASK;
- /*
- * The controller interrupts as drive 0.
- * This means that you must check for controller interrupts
- * before you check to see if there is a drive 0.
- */
- if((M_OP_STCON|M_OP_END) == mp->mscp_opcode)
- {
- if (st == M_ST_SUCC)
- {
-# ifdef DEBUG
- printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf);
- printd("ctlr timeout = %d\n", mp->mscp_cnttmo);
-# endif
- sc->sc_state = S_RUN;
- }
- else
- sc->sc_state = S_IDLE;
- um->um_tab.b_active = 0;
- wakeup((caddr_t)um);
- return;
- }
- if (mp->mscp_unit >= NTMS)
- return;
- if ((ui = tmscpip[um->um_ctlr][mp->mscp_unit]) == 0)
- return;
- tms = &tms_info[ui->ui_unit];
- /*
- * Save endcode, endflags, and status for mtioctl get unit status.
- * NOTE: Don't do this on Clear serious exception (reposition no-op);
- * which is done on close since this would
- * overwrite the real status we want.
- */
- if (tms->tms_clserex != 1)
- {
- tms->tms_endcode = mp->mscp_opcode;
- tms->tms_flags = mp->mscp_flags;
- tms->tms_status = st;
- }
- else tms->tms_clserex = 0;
-
- switch (mp->mscp_opcode) {
- case M_OP_ONLIN|M_OP_END:
- tms->tms_type = mp->mscp_mediaid;
- dp = &tmsutab[ui->ui_unit];
- if (st == M_ST_SUCC)
- {
- /*
- * Link the drive onto the controller queue
- */
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- ui->ui_flags = 1; /* mark it online */
- tms->tms_dsize=(daddr_t)mp->mscp_maxwrt;
-# ifdef DEBUG
- printd("tmscprsp: unit %d online\n", mp->mscp_unit);
-# endif
- /*
- * This define decodes the Media type identifier
- */
-# define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')
-# ifdef DEBUG
- printd("tmscprsp: unit %d online %x %c%c %c%c%c%d\n"
- ,mp->mscp_unit, mp->mscp_mediaid ,F_to_C(mp,4)
- ,F_to_C(mp,3), F_to_C(mp,2)
- ,F_to_C(mp,1), F_to_C(mp,0), mp->mscp_mediaid & 0x7f);
-# endif
- dp->b_active = 1;
- } /* end if st == M_ST_SUCC */
- else
- {
- if ((bp = dp->b_actf))
- tprintf(tms->tms_tpr,
- "tms%d: hard error bn%d: OFFLINE\n",
- minor(bp->b_dev)&03, bp->b_blkno);
- else
- tprintf(tms->tms_tpr,
- "tms%d: hard error: OFFLINE\n",
- ui->ui_unit);
- while ((bp = dp->b_actf))
- {
- dp->b_actf = bp->b_actf;
- bp->b_flags |= B_ERROR;
- iodone(bp);
- }
- }
- if(mp->mscp_cmdref!=NULL)
- /* Seems to get lost sometimes in uda */
- wakeup((caddr_t)mp->mscp_cmdref);
- break;
- /*
- * The AVAILABLE ATTENTION message occurs when the
- * unit becomes available after loading,
- * marking the unit offline (ui_flags = 0) will force an
- * online command prior to using the unit.
- */
- case M_OP_AVATN:
- ui->ui_flags = 0;
- tms->tms_type = mp->mscp_mediaid;
- break;
- case M_OP_END:
- /*
- * An endcode without an opcode (0200) is an invalid command.
- * The mscp specification states that this would be a protocol
- * type error, such as illegal opcodes. The mscp spec. also
- * states that parameter error type of invalid commands should
- * return the normal end message for the command. This does not appear
- * to be the case. An invalid logical block number returned an endcode
- * of 0200 instead of the 0241 (read) that was expected.
- */
-
- printf("tmscp%d: invalid cmd, endcode = %o, status=%o\n",
- um->um_ctlr, mp->mscp_opcode, st);
- bp = (struct buf *)mp->mscp_cmdref;
- /*
- * Unlink buffer from I/O wait queue.
- * And signal iodone, so the higher level command can exit!
- *
- */
- dp = &tmscpwtab[um->um_ctlr];
- while (dp && dp->b_actf != bp)
- dp = dp->b_actf;
- if (dp == NULL)
- panic("tmscp: don't work1!");
- dp->b_actf = bp->b_actf;
- dp = &tmsutab[ui->ui_unit];
- dp->b_qsize--;
- iodone(bp);
- break;
- case M_OP_WRITE|M_OP_END:
- /* mark the last io op as a write */
- tms->tms_lastiow = 1;
- case M_OP_READ|M_OP_END:
- case M_OP_WRITM|M_OP_END:
- case M_OP_REPOS|M_OP_END:
- case M_OP_STUNT|M_OP_END:
- /*
- * The AVAILABLE message occurs when the mt ioctl "rewoffl" is
- * issued. For the ioctl, "rewoffl", a tmscp AVAILABLE command is
- * done with the UNLOAD modifier. This performs a rewind, followed
- * by marking the unit offline. So mark the unit offline
- * software wise as well (ui_flags = 0 and
- * tms->tms_openf = 0).
- */
- case M_OP_AVAIL|M_OP_END:
-# ifdef DEBUG
- printd("tmscprsp: position = %d\n", mp->mscp_lbn);
-# endif
- bp = (struct buf *)mp->mscp_cmdref;
- /*
- * Only need to release buffer if the command was read or write.
- * No ubasetup was done in "tmscpstart" if it was an ioctl cmd.
- */
- if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
- mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
- ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo);
- /*
- * Unlink buffer from I/O wait queue.
- */
- dp = &tmscpwtab[um->um_ctlr];
- while (dp && dp->b_actf != bp)
- dp = dp->b_actf;
- if (dp == NULL)
- panic("tmscp: don't work2!");
- dp->b_actf = bp->b_actf;
-# if defined(VAX750)
- ubasc = uba_cd.cd_devs[um->um_ubanum];
- if (cpunumber == VAX_750) {
- if ((tmscpwtab[um->um_ctlr].b_actf == NULL) &&
- (um->um_ubinfo != 0)) {
- ubarelse(um->um_ubanum, &um->um_ubinfo);
- }
- else {
- if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
- mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
- UBAPURGE(ubasc->uh_uba,(um->um_ubinfo >>28) & 0x0f);
- }
- }
-# endif
- dp = &tmsutab[ui->ui_unit];
- dp->b_qsize--;
- if (st == M_ST_OFFLN || st == M_ST_AVLBL)
- {
- ui->ui_flags = 0; /* mark unit offline */
- tms->tms_openf = 0;
- tms->tms_type = mp->mscp_mediaid;
- /*
- * Link the buffer onto the front of the drive queue
- */
- bp->b_actf = dp->b_actf;
- dp->b_actf = bp;
- /*
- * Link the drive onto the controller queue
- */
- if (dp->b_active == 0)
- {
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- dp->b_active = 1;
- }
-# if defined(VAX750)
- if (cpunumber == VAX_750 && um->um_ubinfo == 0)
- um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
-# endif
- return;
- }
- if (st != M_ST_SUCC)
- {
- if (mp->mscp_flags & M_EF_SEREX)
- tms->tms_serex = 1;
- if (st != M_ST_TAPEM)
- {
- tprintf(tms->tms_tpr,
- "tms%d: hard error bn%d\n",
- minor(bp->b_dev)&03, bp->b_blkno);
- errinfo(st); /* produces more info */
-# ifdef DEBUG
- printd("tmscprsp: error; status sub-code = 0%o, flags = 0%o\n",
- (mp->mscp_status & 177740)>>5, mp->mscp_flags);
-# endif
- bp->b_flags |= B_ERROR;
- }
- else
- /* Hit a tape mark - Set serex flag to
- * a special value so we can clear the
- * serious exception on the next command.
- */
- tms->tms_serex = 2;
- }
- /*
- * The tmscp spec states that controllers do not have to
- * report the number of records or files skipped. So on
- * reposition commands we go strictly by cmd status.
- */
- if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END))
- bp->b_resid = bp->b_bcount - mp->mscp_bytecnt;
- else
- bp->b_resid = 0;
- tms->tms_resid = bp->b_resid;
- iodone(bp);
- break;
-
- case M_OP_GTUNT|M_OP_END:
-# ifdef DEBUG
- printd("tmscprsp: GTUNT end packet status = 0%o\n",st);
- printd("tmscprsp: unit %d mediaid %x %c%c %c%c%c%d %x %x t=%d\n"
- ,mp->mscp_unit, mp->mscp_mediaid
- ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2)
- ,F_to_C(mp,1),F_to_C(mp,0)
- ,mp->mscp_mediaid & 0x7f
- ,mp->mscp_unitid.val[0]
- ,mp->mscp_unitid.val[1]
- ,mp->mscp_format);
-# endif
- tms->tms_type = mp->mscp_mediaid;
- tms->tms_fmtmenu = mp->mscp_fmtmenu;
- tms->tms_unitflgs = mp->mscp_unitflgs;
- break;
-
- default:
- printf("tmscp unknown packet\n");
- tmserror(um, (struct mslg *)mp);
- } /* end switch mp->mscp_opcode */
-}
-
-
-/*
- * Give a meaningful error when the mscp_status field returns an error code.
- */
-
-void
-errinfo(st)
- int st; /* the status code */
-{
- switch(st) {
- case M_ST_ICMD:
- printf("invalid command\n");
- break;
- case M_ST_ABRTD:
- printf("command aborted\n");
- break;
- case M_ST_OFFLN:
- printf("unit offline\n");
- break;
- case M_ST_WRTPR:
- printf("unit write protected\n");
- break;
- case M_ST_COMP:
- printf("compare error\n");
- break;
- case M_ST_DATA:
- printf("data error\n");
- break;
- case M_ST_HSTBF:
- printf("host buffer access error\n");
- break;
- case M_ST_CNTLR:
- printf("controller error\n");
- break;
- case M_ST_DRIVE:
- printf("drive error\n");
- break;
- case M_ST_FMTER:
- printf("formatter error\n");
- break;
- case M_ST_BOT:
- printf("BOT encountered\n");
- break;
- case M_ST_TAPEM:
- printf("tape mark encountered\n");
- break;
- case M_ST_RDTRN:
- printf("record data truncated\n");
- break;
- case M_ST_PLOST:
- printf("position lost\n");
- break;
- case M_ST_SEX:
- printf("serious exception\n");
- break;
- case M_ST_LED:
- printf("LEOT detected\n");
- break;
- }
-}
-
-
-/*
- * Manage buffers and perform block mode read and write operations.
- */
-void
-tmscpstrategy (bp)
- register struct buf *bp;
-{
- register struct uba_device *ui;
- register struct uba_ctlr *um;
- register struct buf *dp;
- register int unit = TMSUNIT(bp->b_dev);
- int s;
-
- if (unit >= NTMS)
- {
-# ifdef DEBUG
- printd ("tmscpstrategy: bad unit # %d\n",unit);
-# endif
- bp->b_flags |= B_ERROR;
- iodone(bp);
- return;
- }
- ui = tmsdinfo[unit];
- um = ui->ui_mi;
- if (ui == 0 || ui->ui_alive == 0)
- {
- bp->b_flags |= B_ERROR;
- iodone(bp);
- return;
- }
- s = splbio();
- /*
- * Link the buffer onto the drive queue
- */
- dp = &tmsutab[ui->ui_unit];
- MSCP_APPEND(bp, dp, b_actf);
- /*
- * Link the drive onto the controller queue
- */
- if (dp->b_active == 0)
- {
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- dp->b_active = 1;
- }
- /*
- * If the controller is not active, start it.
- */
- if (um->um_tab.b_active == 0)
- {
-# if defined(VAX750)
- if (cpunumber == VAX_750
- && tmscpwtab[um->um_ctlr].b_actf == NULL)
- {
- if (um->um_ubinfo != 0)
- log(TMS_PRI, "tmscpstrategy: ubinfo 0x%x\n",
- um->um_ubinfo);
- else
- um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
- }
-# endif
-# ifdef DEBUG
- printd10("tmscpstrategy: Controller not active, starting it\n");
-# endif
- (void) tmscpstart(um);
- }
- splx(s);
- return;
-}
-
-int
-tmscpread(dev, uio)
- dev_t dev;
- struct uio *uio;
-{
-
- return (physio(tmscpstrategy, NULL, dev, B_READ, minphys, uio));
-}
-
-int
-tmscpwrite(dev, uio)
- dev_t dev;
- struct uio *uio;
-{
-
- return (physio(tmscpstrategy, NULL, dev, B_WRITE, minphys, uio));
-}
-
-#define DBSIZE 32
-
-#define ca_Rspdsc ca_rspdsc[0]
-#define ca_Cmddsc ca_rspdsc[1]
-#define tmscp_Rsp tmscp_rsp[0]
-#define tmscp_Cmd tmscp_cmd[0]
-
-struct tmscp tmscpd[NTMSCP];
-
-int
-tmscpdump(dev, blkno, va, size)
- dev_t dev;
- daddr_t blkno;
- caddr_t va;
- size_t size;
-{
-#ifdef notyet
- volatile struct tmscpdevice *tmscpaddr;
- volatile struct tmscp *tmscp_ubaddr;
- char *start;
- int num, blk, unit;
- register struct uba_regs *uba;
- register struct uba_device *ui;
- register volatile struct tmscp *tmscpp;
- register struct pte *io;
- register int i;
-
- unit = minor(dev) & 03;
- if (unit >= NTMS)
- return (ENXIO);
-# define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
- ui = phys(struct uba_device *, tmsdinfo[unit]);
- if (ui->ui_alive == 0)
- return (ENXIO);
- uba = phys(struct uba_softc *, ui->ui_hd)->uh_physuba;
- ubainit(uba);
- tmscpaddr = (struct tmscpdevice *)ui->ui_physaddr;
- DELAY(2000000);
- tmscpp = phys(struct tmscp *, &tmscpd[ui->ui_ctlr]);
-
- num = btoc(sizeof(struct tmscp)) + 1;
- io = (struct pte *)&uba->uba_map[NUBMREG-num];
- for(i = 0; i<num; i++)
- *(int *)io++ = UBAMR_MRV|(btop(tmscpp)+i);
- tmscp_ubaddr = (struct tmscp *)(((int)tmscpp & PGOFSET)|((NUBMREG-num)<<9));
-
- tmscpaddr->tmscpip = 0;
- while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
- if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- tmscpaddr->tmscpsa = TMSCP_ERR;
- while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
- if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- tmscpaddr->tmscpsa = (short)((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase);
- while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
- if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
- while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
- if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- tmscpaddr->tmscpsa = TMSCP_GO;
- tmscpp->tmscp_ca.ca_Rspdsc = (long)&tmscp_ubaddr->tmscp_Rsp.mscp_cmdref;
- tmscpp->tmscp_ca.ca_Cmddsc = (long)&tmscp_ubaddr->tmscp_Cmd.mscp_cmdref;
- tmscpp->tmscp_Cmd.mscp_header.tmscp_vcid = 1; /* for tape */
- tmscpp->tmscp_Cmd.mscp_cntflgs = 0;
- tmscpp->tmscp_Cmd.mscp_version = 0;
- if (tmscpcmd(M_OP_STCON, tmscpp, tmscpaddr) == 0) {
- return(EFAULT);
- }
- tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
- if (tmscpcmd(M_OP_ONLIN, tmscpp, tmscpaddr) == 0) {
- return(EFAULT);
- }
-
- num = maxfree;
- start = 0;
- while (num > 0)
- {
- blk = num > DBSIZE ? DBSIZE : num;
- io = (struct pte *)uba->uba_map;
- for (i = 0; i < blk; i++)
- *(int *)io++ = (btop(start)+i) | UBAMR_MRV;
- *(int *)io = 0;
- tmscpp->tmscp_Cmd.mscp_lbn = btop(start);
- tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
- tmscpp->tmscp_Cmd.mscp_bytecnt = blk*NBPG;
-# ifdef MVAX
- if( cpu == MVAX_I )
- tmscpp->tmscp_Cmd.mscp_buffer = (long) start;
- else
-# endif MVAX
- tmscpp->tmscp_Cmd.mscp_buffer = 0;
- if (tmscpcmd(M_OP_WRITE, tmscpp, tmscpaddr) == 0)
- return(EIO);
- start += blk*NBPG;
- num -= blk;
- }
-#endif
- return (0);
-}
-
-
-/*
- * Perform a standalone tmscp command. This routine is only used by tmscpdump.
- */
-
-int
-tmscpcmd(op, tmscpp, tmscpaddr)
- int op;
- struct tmscp *tmscpp;
- struct tmscpdevice *tmscpaddr;
-{
- volatile int i;
-
-
- tmscpp->tmscp_Cmd.mscp_opcode = op;
- tmscpp->tmscp_Rsp.mscp_header.tmscp_msglen = mscp_msglen;
- tmscpp->tmscp_Cmd.mscp_header.tmscp_msglen = mscp_msglen;
- tmscpp->tmscp_ca.ca_Rspdsc |= TMSCP_OWN|TMSCP_INT;
- tmscpp->tmscp_ca.ca_Cmddsc |= TMSCP_OWN|TMSCP_INT;
- if (tmscpaddr->tmscpsa&TMSCP_ERR)
- printf("tmscp fatal error (0%o)\n", tmscpaddr->tmscpsa&0xffff);
- i = tmscpaddr->tmscpip;
-#ifdef lint
- i = i;
-#endif
- for (;;)
- {
- if (tmscpp->tmscp_ca.ca_cmdint)
- tmscpp->tmscp_ca.ca_cmdint = 0;
- if (tmscpp->tmscp_ca.ca_rspint)
- break;
- }
- tmscpp->tmscp_ca.ca_rspint = 0;
- if (tmscpp->tmscp_Rsp.mscp_opcode != (op|M_OP_END) ||
- (tmscpp->tmscp_Rsp.mscp_status&M_ST_MASK) != M_ST_SUCC)
- {
- printf("error: com %d opc 0x%x stat 0x%x\ndump ", op,
- tmscpp->tmscp_Rsp.mscp_opcode, tmscpp->tmscp_Rsp.mscp_status);
- return(0);
- }
- return(1);
-}
-
-/*
- * Catch ioctl commands, and call the "command" routine to do them.
- */
-
-/* ARGSUSED */
-int
-tmscpioctl(dev, cmd, data, flag, p)
- dev_t dev;
- u_long cmd;
- caddr_t data;
- int flag;
- struct proc *p;
-{
- register struct buf *bp = &ctmscpbuf[TMSCPCTLR(dev)];
- register callcount; /* number of times to call cmd routine */
- register struct uba_device *ui;
- register struct tms_info *tms;
- int fcount; /* number of files (or records) to space */
- int error = 0;
- register struct mtop *mtop; /* mag tape cmd op to perform */
- register struct mtget *mtget; /* mag tape struct to get info in */
-
- /* we depend of the values and order of the TMS ioctl codes here */
- static tmsops[] =
- {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
- TMS_CACHE,TMS_NOCACHE};
-
- switch (cmd) {
- case MTIOCTOP: /* tape operation */
- mtop = (struct mtop *)data;
- switch (mtop->mt_op) {
-
- case MTWEOF:
- callcount = mtop->mt_count;
- fcount = 1;
- break;
- case MTFSF: case MTBSF:
- case MTFSR: case MTBSR:
- callcount = 1;
- fcount = mtop->mt_count;
- break;
- case MTREW: case MTOFFL: case MTNOP:
- case MTCACHE: case MTNOCACHE:
- callcount = 1;
- fcount = 1; /* wait for this rewind */
- break;
- default:
- return (ENXIO);
- } /* end switch mtop->mt_op */
-
- if (callcount <= 0 || fcount <= 0)
- return (EINVAL);
- while (--callcount >= 0)
- {
- tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
- if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
- bp->b_resid)
- return (EIO);
- if (bp->b_flags & B_ERROR) /* like hitting BOT */
- break;
- }
- if (bp->b_flags&B_ERROR)
- if ((error = bp->b_error)==0)
- return (EIO);
- return (error);
-
- case MTIOCGET:
- /*
- * Return status info associated with the particular UNIT.
- */
- ui = tmsdinfo[TMSUNIT(dev)];
- tms = &tms_info[ui->ui_unit];
- mtget = (struct mtget *)data;
- mtget->mt_type = MT_ISTMSCP;
- mtget->mt_dsreg = tms->tms_flags << 8;
- mtget->mt_dsreg |= tms->tms_endcode;
- mtget->mt_erreg = tms->tms_status;
- mtget->mt_resid = tms->tms_resid;
- break;
-
- default:
- return (ENXIO);
- }
- return (0);
-}
-
-
-/*
- * Reset (for raw mode use only).
- */
-void
-tmscpreset (uban)
- int uban;
-{
- register struct uba_ctlr *um;
- register struct uba_device *ui;
- register struct buf *bp, *dp;
- register int unit;
- struct buf *nbp;
- int d;
-
- for (d = 0; d < NTMSCP; d++)
- {
- if ((um = tmscpminfo[d]) == 0 || um->um_ubanum != uban ||
- um->um_alive == 0)
- continue;
- printf(" tmscp%d", d);
- um->um_tab.b_active = 0;
- um->um_tab.b_actf = 0;
- tmscp_softc[d].sc_state = S_IDLE;
- tmscp_softc[d].sc_mapped = 0;
- for (unit = 0; unit < NTMS; unit++)
- {
- if ((ui = tmsdinfo[unit]) == 0)
- continue;
- if (ui->ui_alive == 0 || ui->ui_mi != um)
- continue;
- tmsutab[unit].b_active = 0;
- tmsutab[unit].b_qsize = 0;
- }
- for (bp = tmscpwtab[d].b_actf; bp; bp = nbp)
- {
- nbp = bp->b_actf;
- bp->b_ubinfo = 0;
- /*
- * Link the buffer onto the drive queue
- */
- dp = &tmsutab[TMSUNIT(bp->b_dev)];
- MSCP_APPEND(bp, dp, b_actf);
- /*
- * Link the drive onto the controller queue
- */
- if (dp->b_active == 0)
- {
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- dp->b_active = 1;
- }
- }
- (void)tmscpinit(d);
- }
-}
-
-
-/*
- * Process an error log message
- *
- * Only minimal decoding is done, only "useful"
- * information is printed. Eventually should
- * send message to an error logger.
- */
-void
-tmserror(um, mp)
- register struct uba_ctlr *um;
- register struct mslg *mp;
-{
- register i;
-
-# ifdef DEBUG
- printd("tmserror:\n");
-# endif
- if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT)))
- log(TMS_PRI, "tmscp%d: %s error, ", um->um_ctlr,
- mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard");
-
- switch (mp->mslg_format) {
-
- case M_FM_CNTERR:
- log(TMS_PRI, "controller error, event 0%o\n", mp->mslg_event);
- break;
- case M_FM_BUSADDR:
- log(TMS_PRI, "host memory access error, event 0%o, addr 0%o\n",
- mp->mslg_event,
- (unsigned int)(mp->mslg_unitid & 0xffffffff));
- break;
- case M_FM_TAPETRN:
- log(TMS_PRI, "tape transfer error, unit %d, grp 0x%x, event 0%o\n",
- mp->mslg_unit, mp->mslg_group, mp->mslg_event);
- break;
- case M_FM_STIERR:
- log(TMS_PRI, "STI error, unit %d, event 0%o\n",
- mp->mslg_unit, mp->mslg_event);
-#ifdef notdef
- /* too painful to do with log() */
- for(i = 0; i < 62;i++)
- mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff);
- mprintf("\n");
-#endif
- break;
- case M_FM_STIDEL:
- log(TMS_PRI, "STI Drive Error Log, unit %d, event 0%o\n",
- mp->mslg_unit, mp->mslg_event);
- break;
- case M_FM_STIFEL:
- log(TMS_PRI, "STI Formatter Error Log, unit %d, event 0%o\n",
- mp->mslg_unit, mp->mslg_event);
- break;
- default:
- log(TMS_PRI, "unknown error, unit %d, format 0%o, event 0%o\n",
- mp->mslg_unit, mp->mslg_format, mp->mslg_event);
- }
-
- if (tmscperror)
- {
- register long *p = (long *)mp;
-
- for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p))
- printf("%x ", (unsigned int)*p++);
- printf("\n");
- }
-}
-
-int
-tmscp_match(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- return 0;
-}
-
-void
-tmscp_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
-}
-
-#endif
diff --git a/sys/arch/vax/uba/tmscpreg.h b/sys/arch/vax/uba/tmscpreg.h
deleted file mode 100644
index de806fcdb53..00000000000
--- a/sys/arch/vax/uba/tmscpreg.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $NetBSD: tmscpreg.h,v 1.1 1995/02/23 17:53:19 ragge Exp $ */
-
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)tmscpreg.h 7.2 (Berkeley) 5/9/91
- */
-
-/* @(#)tmscpreg.h 1.1 11/2/84 84/09/25 */
-
-/****************************************************************
- * *
- * Licensed from Digital Equipment Corporation *
- * Copyright (c) *
- * Digital Equipment Corporation *
- * Maynard, Massachusetts *
- * 1985, 1986 *
- * All rights reserved. *
- * *
- * The Information in this software is subject to change *
- * without notice and should not be construed as a commitment *
- * by Digital Equipment Corporation. Digital makes no *
- * representations about the suitability of this software for *
- * any purpose. It is supplied "As Is" without expressed or *
- * implied warranty. *
- * *
- * If the Regents of the University of California or its *
- * licensees modify the software in a manner creating *
- * diriviative copyright rights, appropriate copyright *
- * legends may be placed on the drivative work in addition *
- * to that set forth above. *
- * *
- ****************************************************************/
-/*
- * TMSCP registers and structures
- */
-
-#ifndef _UBA_TMSCPREG_
-#define _UBA_TMSCPREG_
-struct tmscpdevice {
- short tmscpip; /* initialization and polling */
- short tmscpsa; /* status and address */
-};
-
-#define TMSCP_ERR 0100000 /* error bit */
-#define TMSCP_STEP4 0040000 /* step 4 has started */
-#define TMSCP_STEP3 0020000 /* step 3 has started */
-#define TMSCP_STEP2 0010000 /* step 2 has started */
-#define TMSCP_STEP1 0004000 /* step 1 has started */
-#define TMSCP_NV 0002000 /* no host settable interrupt vector */
-#define TMSCP_QB 0001000 /* controller supports Q22 bus */
-#define TMSCP_DI 0000400 /* controller implements diagnostics */
-#define TMSCP_OD 0000200 /* port allows odd host addr's in the buffer descriptor */
-#define TMSCP_IE 0000200 /* interrupt enable */
-#define TMSCP_MP 0000100 /* port supports address mapping */
-#define TMSCP_LF 0000002 /* host requests last fail response packet */
-#define TMSCP_PI 0000001 /* host requests adapter purge interrupts */
-#define TMSCP_GO 0000001 /* start operation, after init */
-
-
-/*
- * TMSCP Communications Area
- */
-
-struct tmscpca {
- short ca_xxx1; /* unused */
- char ca_xxx2; /* unused */
- char ca_bdp; /* BDP to purge */
- short ca_cmdint; /* command queue transition interrupt flag */
- short ca_rspint; /* response queue transition interrupt flag */
- long ca_rspdsc[NRSP];/* response descriptors */
- long ca_cmddsc[NCMD];/* command descriptors */
-};
-
-#define ca_ringbase ca_rspdsc[0]
-
-#define TMSCP_OWN 0x80000000 /* port owns this descriptor (else host
- owns it) */
-#define TMSCP_INT 0x40000000 /* allow interrupt on ring transition */
-
-#define TMSCP_MAP 0x80000000 /* modifier for mapped buffer descriptors */
-
-/*
- * TMSCP packet info (same as MSCP)
- */
-struct mscp_header {
- short tmscp_msglen; /* length of MSCP packet */
- char tmscp_credits; /* low 4 bits: credits, high 4 bits: msgtype */
- char tmscp_vcid; /* virtual circuit id (connection id) */
-};
-#endif
diff --git a/sys/arch/vax/uba/ts.c b/sys/arch/vax/uba/ts.c
index c2bb299e6a2..cdb14f69d4a 100644
--- a/sys/arch/vax/uba/ts.c
+++ b/sys/arch/vax/uba/ts.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ts.c,v 1.6 1996/04/08 18:37:32 ragge Exp $ */
+/* $NetBSD: ts.c,v 1.11 1997/01/11 11:34:43 ragge Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@@ -14,8 +14,8 @@
* 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.
+ * 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.
@@ -32,35 +32,35 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)tmscp.c 7.16 (Berkeley) 5/9/91
+ * @(#)tmscp.c 7.16 (Berkeley) 5/9/91
*/
/*
- * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86";
+ * sccsid = "@(#)tmscp.c 1.24 (ULTRIX) 1/21/86";
*/
/************************************************************************
- * *
- * Licensed from Digital Equipment Corporation *
- * Copyright (c) *
- * Digital Equipment Corporation *
- * Maynard, Massachusetts *
- * 1985, 1986 *
- * All rights reserved. *
- * *
- * The Information in this software is subject to change *
- * without notice and should not be construed as a commitment *
- * by Digital Equipment Corporation. Digital makes no *
- * representations about the suitability of this software for *
- * any purpose. It is supplied "As Is" without expressed or *
- * implied warranty. *
- * *
- * If the Regents of the University of California or its *
- * licensees modify the software in a manner creating *
- * diriviative copyright rights, appropriate copyright *
- * legends may be placed on the drivative work in addition *
- * to that set forth above. *
- * *
+ * *
+ * Licensed from Digital Equipment Corporation *
+ * Copyright (c) *
+ * Digital Equipment Corporation *
+ * Maynard, Massachusetts *
+ * 1985, 1986 *
+ * All rights reserved. *
+ * *
+ * The Information in this software is subject to change *
+ * without notice and should not be construed as a commitment *
+ * by Digital Equipment Corporation. Digital makes no *
+ * representations about the suitability of this software for *
+ * any purpose. It is supplied "As Is" without expressed or *
+ * implied warranty. *
+ * *
+ * If the Regents of the University of California or its *
+ * licensees modify the software in a manner creating *
+ * diriviative copyright rights, appropriate copyright *
+ * legends may be placed on the drivative work in addition *
+ * to that set forth above. *
+ * *
************************************************************************/
/*
@@ -69,20 +69,9 @@
* should be TS11 compatible (untested)
*/
-#define NCMD 1
-#define NMSG 1
-
-#if 0
-# define DEBUG
-# define TRACE
-#else
-# undef DEBUG
-# undef TRACE
-#endif
-
#define TS11_COMPAT /* don't use extended features provided by TS05 */
-#ifdef NEED_18BIT
+#ifdef NEED_18BIT
#define TS_UBAFLAGS UBA_NEED16
#else
#define TS_UBAFLAGS 0
@@ -92,10 +81,10 @@
#define ENABLE_END
#define ENABLE_EAI /* enable Attention-Interrupts */
-#undef ENABLE_EAI
+#undef ENABLE_EAI
#define ENABLE_ERI /* Enable Release Buffer Interrupts */
-#undef ENABLE_ERI
+#undef ENABLE_ERI
#ifdef DEBUG
int tsdebug = 1;
@@ -129,11 +118,6 @@ int tstrace = 1;
*/
-#include "ts.h"
-
-#if NTS > 0
-
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -147,7 +131,6 @@ int tstrace = 1;
#include <sys/mtio.h>
#include <sys/uio.h>
#include <sys/proc.h>
-#include <sys/tprintf.h>
#include <machine/pte.h>
#include <machine/sid.h>
@@ -159,24 +142,14 @@ int tstrace = 1;
#include <vax/uba/tsreg.h>
-int ts_match __P((struct device *, void *, void *));
-void ts_attach __P((struct device *, struct device *, void *));
-void tsstrategy __P((struct buf *));
-
-struct cfdriver ts_cd = {
- NULL, "ts", DV_DULL
-};
-
-struct cfattach ts_ca = {
- sizeof(struct device), ts_match, ts_attach
-};
+#include "ts.h"
/*
* ts command packets and communication area (per controller)
*/
-struct ts {
+struct ts {
struct tsdevice *reg; /* address of i/o-registers */
- struct tscmd cmd; /* command packet(s) */
+ struct tscmd cmd; /* command packet(s) */
struct tsmsg msg; /* message packet(s) */
} ts[NTS];
@@ -186,37 +159,38 @@ struct ts {
* (thus we have no struct ts_info)
*/
struct ts_softc {
- struct ts *sc_ts; /* Unibus address of uda struct */
- short sc_mapped; /* Unibus map allocated ? */
- int sc_ubainfo; /* Unibus mapping info */
- short sc_state; /* see below: ST_xxx */
- short sc_flags; /* see below: FL_xxx */
+ struct device sc_dev; /* Autoconf ... */
+ struct uba_unit sc_unit; /* Struct common for UBA to talk */
+ struct ts *sc_ts; /* Unibus address of uda struct */
+ short sc_mapped; /* Unibus map allocated ? */
+ int sc_ubainfo; /* Unibus mapping info */
+ short sc_state; /* see below: ST_xxx */
+ short sc_flags; /* see below: FL_xxx */
short sc_lcmd; /* last command word */
short sc_rtc; /* retry count for lcmd */
short sc_lssr; /* last status register */
short sc_lmsgh; /* last message header */
short sc_lxst0; /* last status word */
short sc_cmdf; /* command flags (ack,cvc,ie) */
- short sc_openf; /* lock against multiple opens */
+ short sc_openf; /* lock against multiple opens */
short sc_liowf; /* last operation was write */
- int sc_micro; /* microcode revision */
- int sc_ivec; /* interrupt vector address */
- short sc_ipl; /* interrupt priority, Q-bus */
- tpr_t sc_tpr; /* tprintf handle */
-} ts_softc[NTS];
-
-int tsprobe __P((caddr_t, int, struct uba_ctlr *, struct uba_softc *));
-int tsslave __P((struct uba_device *, caddr_t));
-void tsattach __P((struct uba_device *));
+ int sc_micro; /* microcode revision */
+ int sc_ivec; /* interrupt vector address */
+ short sc_ipl; /* interrupt priority, Q-bus */
+};
+
void tsintr __P((int));
-int tsinit __P((int));
+int tsinit __P((struct ts_softc *));
void tscommand __P((dev_t, int, int));
int tsstatus __P((int));
int tsexec __P((int, int));
-int tsstart __P((struct uba_ctlr *, struct buf *));
+int tsstart __P((struct ts_softc *, struct buf *));
int tswchar __P((int));
void tsreset __P((int));
void tsxstatus __P((struct tsmsg *));
+int tsmatch __P((struct device *, void *, void *));
+void tsattach __P((struct device *, struct device *, void *));
+void tsstrategy __P((struct buf *));
int tsopen __P((dev_t, int, int, struct proc *));
int tsclose __P((dev_t, int, int, struct proc *));
@@ -225,37 +199,30 @@ int tsread __P((dev_t, struct uio *));
int tswrite __P((dev_t, struct uio *));
int tsdump __P((dev_t, daddr_t, caddr_t, size_t));
+struct cfdriver ts_cd = {
+ NULL, "ts", DV_DULL
+};
+
+struct cfattach ts_ca = {
+ sizeof(struct ts_softc), tsmatch, tsattach
+};
+
#define ST_INVALID 0 /* uninitialized, before probe */
#define ST_PROBE 1 /* during tsprobe(), not used */
#define ST_SLAVE 2 /* in tsslave(), init almost complete */
#define ST_ATTACH 3 /* during tsattach(), not used */
-#define ST_INITIALIZED 4 /* init completed, set by tsintr() */
+#define ST_INITIALIZED 4 /* init completed, set by tsintr() */
#define ST_RUNNING 5
#define ST_IDLE 6
#define ST_BUSY 7
/* Bits in minor device */
#define TS_UNIT(dev) (minor(dev)&03)
-#define TS_CTLR(dev) (TS_UNIT(dev))
#define TS_HIDENSITY 010
-#define TS_PRI LOG_INFO
-
-/*
- * Definition of the driver for autoconf.
- */
-#define CTLRNAME "zs" /* ts/zs ??? */
-#define UNITNAME "ts"
-
-struct uba_ctlr *zsinfo[NTS]; /* controller-info */
-struct uba_device *tsinfo[NTS]; /* unit(tape)-info */
+#define TS_PRI LOG_INFO
-u_short tsstd[] = { 0172520, 0172524, /* standart csr for ts */
- 0172530, 0172534, 0 }; /* standart csr for ts */
-
-struct uba_driver tsdriver = { tsprobe, tsslave, tsattach, 0, tsstd,
- UNITNAME, tsinfo, CTLRNAME, zsinfo, 0 };
/*
* Since we don't have credits and thus only one operation per time,
@@ -274,30 +241,25 @@ struct buf *ts_wtab[NTS]; /* dummy I/O wait queue */
* initialize data structures, what else ???
*/
int
-tsinit (unit)
- int unit;
+tsinit (sc)
+ struct ts_softc *sc;
{
- register struct ts_softc *sc;
volatile struct tsdevice *tsregs;
- struct uba_ctlr *um;
+ int unit = sc->sc_dev.dv_unit;
+ struct uba_unit *uu;
- trace (("tsinit: unit = %d\n", unit));
-
- sc = &ts_softc[unit];
- um = zsinfo[unit];
- um->um_tab.b_active++; /* ??? */
- tsregs = (struct tsdevice *)um->um_addr;
+ uu = &sc->sc_unit;
+ tsregs = (struct tsdevice *)ts[unit].reg;
if (sc->sc_mapped == 0) {
/*
* Map the communications area and command and message
* buffer into Unibus address space.
*/
- sc->sc_ubainfo = uballoc (um->um_ubanum, (caddr_t)&ts[unit],
- sizeof (struct ts), TS_UBAFLAGS);
+ sc->sc_ubainfo = uballoc((struct uba_softc *)
+ sc->sc_dev.dv_parent,
+ (caddr_t)&ts[unit], sizeof (struct ts), TS_UBAFLAGS);
sc->sc_ts = (struct ts *)(UBAI_ADDR(sc->sc_ubainfo));
sc->sc_mapped = 1;
- debug (("sc_mapped: %d [%x, %x]\n", sc->sc_mapped,
- sc->sc_ubainfo, sc->sc_ts));
}
/*
@@ -320,7 +282,7 @@ tsexec (ctlr, cmd)
int ctlr;
int cmd;
{
- register struct ts_softc *sc = &ts_softc[ctlr];
+ register struct ts_softc *sc = ts_cd.cd_devs[ctlr];
register struct tscmd *tscmdp = &ts[ctlr].cmd;
register long tscmdma = (long)&sc->sc_ts->cmd; /* mapped address */
volatile struct tsdevice *tsreg = ts[ctlr].reg;
@@ -349,13 +311,12 @@ tsexec (ctlr, cmd)
case TS_CMD_STAT: cmdName = "Get Status (END)"; break;
default: cmdName = "unexptected Command"; break;
}
- debug (("tsexec: cmd = 0x%x (%s)\n", tscmdp->cmdr, cmdName));
#endif
sr = tsreg->tssr;
if ((sr & TS_SSR) == 0) { /* subsystem NOT ready */
printf ("%s%d: subsystem not ready [%x]\n",
- CTLRNAME, ctlr, sr);
+ sc->sc_dev.dv_xname, sr);
return (-1);
}
dbx = ((char*)tsreg) + 3; /* dbx is located at the fourth byte */
@@ -375,7 +336,7 @@ tsexec (ctlr, cmd)
* wait for SSR or RMR to show up
*/
sr = tsreg->tssr;
- if ((sr & TS_SSR) != 0) { /* something went wrong .. */
+ if ((sr & TS_SSR) != 0) { /* something went wrong .. */
if (sr & TS_RMR) {
printf ("ts: error writing TSDB (RMR)\n");
return (-1);
@@ -404,15 +365,14 @@ tscommand (dev, cmd, count)
int count;
{
register struct buf *bp;
- register int s;
+ register int s;
trace (("tscommand (%d, %x, %d)\n", TS_UNIT(dev), cmd, count));
s = splbio();
bp = &ts_cbuf[TS_UNIT(dev)];
-#if 1
+
while (bp->b_flags & B_BUSY) {
- debug (("looping 'cause B_BUSY\n"));
/*
* This special check is because B_BUSY never
* gets cleared in the non-waiting rewind case. ???
@@ -420,12 +380,11 @@ tscommand (dev, cmd, count)
if (bp->b_bcount == 0 && (bp->b_flags & B_DONE))
break;
bp->b_flags |= B_WANTED;
- debug (("sleeping ...\n"));;
sleep ((caddr_t)bp, PRIBIO);
/* check MOT-flag !!! */
}
bp->b_flags = B_BUSY | B_READ;
-#endif
+
splx(s);
/*
@@ -438,7 +397,6 @@ tscommand (dev, cmd, count)
bp->b_bcount = count;
bp->b_resid = cmd;
bp->b_blkno = 0;
- debug (("tscommand: calling tsstrategy ...\n"));
tsstrategy (bp);
/*
* In case of rewind from close, don't wait.
@@ -459,42 +417,34 @@ tscommand (dev, cmd, count)
* Start an I/O operation on TS05 controller
*/
int
-tsstart (um, bp)
- register struct uba_ctlr *um;
+tsstart (sc, bp)
+ register struct ts_softc *sc;
register struct buf *bp;
{
- register struct ts_softc *sc = &ts_softc[um->um_ctlr];
- volatile struct tsdevice *tsreg = ts[um->um_ctlr].reg;
- register struct tscmd *tscmdp = &ts[um->um_ctlr].cmd;
+ int ctlr = sc->sc_dev.dv_unit;
+ volatile struct tsdevice *tsreg = ts[ctlr].reg;
+ register struct tscmd *tscmdp = &ts[ctlr].cmd;
register struct buf *dp;
volatile int i, itmp;
- int unit;
int ioctl;
int cmd;
- unit = um->um_ctlr;
- trace (("tsstart (unit = %d)\n", unit));
- sc = &ts_softc[unit];
-
- if ((dp = ts_wtab[unit]) != NULL) {
+ if ((dp = ts_wtab[ctlr]) != NULL) {
/*
* There's already a command pending ...
* Either we are called by tsintr or we have missed
* something important (race condition).
*/
- debug (("tsstart: I/O queue not empty.\n"));
/* bertram: ubarelse ??? */
- ts_wtab[um->um_ctlr] = NULL;
+ ts_wtab[ctlr] = NULL;
dp->b_flags |= B_ERROR;
iodone (dp);
if (tsreg->tssr & TS_SC) { /* Special Condition; Error */
- tprintf (sc->sc_tpr, "%s%d: error at bn%d\n",
- UNITNAME, unit, dp->b_blkno);
- log (TS_PRI, "%s%d: tssr 0x%x, state %d\n",
- CTLRNAME, unit, tsreg->tssr, sc->sc_state);
- tsinit (unit);
+ log (TS_PRI, "%s: tssr 0x%x, state %d\n",
+ sc->sc_dev.dv_xname, tsreg->tssr, sc->sc_state);
+ tsinit (sc);
return (-1);
}
/* XXX */
@@ -505,47 +455,43 @@ tsstart (um, bp)
* If it's an ioctl then just set the flags for later use;
* For other commands attempt to setup a buffer pointer.
*/
- if (bp == &ts_cbuf[um->um_ctlr]) {
+ if (bp == &ts_cbuf[ctlr]) {
ioctl = 1;
- debug (("tsstart(ioctl): unit %d\n", um->um_ctlr));
} else {
ioctl = 0;
- debug (("tsstart(rw): unit %d\n", um->um_ctlr));
/*
* now we try to map the buffer into uba map space (???)
*/
i = TS_UBAFLAGS;
- switch (cpunumber) {
+ switch (vax_cputype) {
case VAX_8600:
case VAX_780:
i |= UBA_CANTWAIT;
break;
case VAX_750:
- i |= um->um_ubinfo | UBA_CANTWAIT;
+ i |= sc->sc_unit.uu_ubinfo | UBA_CANTWAIT;
break;
case VAX_730:
case VAX_78032:
i |= UBA_CANTWAIT;
break;
default:
- printf ("unsupported cpu %d in tsstart.\n", cpunumber);
- } /* end switch (cpunumber) */
+ printf ("unsupported cpu %d in tsstart.\n", vax_cputype);
+ } /* end switch (vax_cputype) */
- debug (("ubasetup (%x, %x, %x)\n", um->um_ubanum, bp, i));
- if ((i = ubasetup (um->um_ubanum, bp, i)) == 0) {
+ if ((i = ubasetup(sc->sc_dev.dv_parent->dv_unit, bp, i)) == 0) {
/*
* For some reasons which I don't (yet? :) understand,
* tmscp.c initiates in this situation a GET-UNIT
* command. (Because no data-buffers are neccess. ??)
*/
- debug (("tsstart: %d, ubasetup = 0\n", um->um_ctlr));
cmd = TS_CMD_STAT;
goto do_cmd;
return (-1); /* ??? */
}
#if defined(VAX750)
- if (cpunumber == VAX_750)
+ if (vax_cputype == VAX_750)
itmp = i & 0xfffffff; /* mask off bdp */
else
#endif
@@ -553,7 +499,6 @@ tsstart (um, bp)
/* XXX */
}
- debug (("ubasetup done. [%x, %x, %d]\n", i, itmp, ioctl));
/*
* If it's an ioctl command, then assemble the command.
@@ -561,7 +506,6 @@ tsstart (um, bp)
* in <sys/mtio.h>
*/
if (ioctl) {
- debug (("tsstart: doing ioctl %d\n", bp->b_resid));
switch ((int)bp->b_resid) {
case MTWEOF:
cmd = TS_CMD_WTM;
@@ -597,24 +541,20 @@ tsstart (um, bp)
cmd = TS_CMD_STAT;
break;
default:
- printf ("%s%d: bad ioctl %d\n",
- CTLRNAME, unit, (int)bp->b_resid);
+ printf ("%s: bad ioctl %d\n", sc->sc_dev.dv_xname,
+ (int)bp->b_resid);
/* Need a no-op. get status */
cmd = TS_CMD_STAT;
} /* end switch (bp->b_resid) */
} else { /* Its a read/write command (not an ioctl) */
- debug (("tsstart: non-ioctl [%x, %xi, %x]\n",
- tscmdp, UBAI_ADDR(i), bp));
tscmdp->cw1 = UBAI_ADDR(i) & 0xffff;
tscmdp->cw2 = (UBAI_ADDR(i) >> 16) & 0x3f;
tscmdp->cw3 = bp->b_bcount;
if (bp->b_flags & B_READ) {
- debug (("read-command(%d)\n", tscmdp->cw3));
cmd = TS_CMD_RNF;
}
else {
- debug (("write-command(%d)\n", tscmdp->cw3));
cmd = TS_CMD_WD;
}
bp->b_ubinfo = itmp; /* save mapping info */
@@ -623,22 +563,20 @@ tsstart (um, bp)
/*
* Move buffer to I/O wait pseudo-queue
*/
- if (ts_wtab[um->um_ctlr]) {
+ if (ts_wtab[ctlr]) {
/*
* we are already waiting for something ...
* this should not happen, so we have a problem now.
* bertram: set error-flag and call iodone() ???
*/
- debug (("tsstart: already waiting for something ...\n"));
}
- ts_wtab[um->um_ctlr] = bp;
+ ts_wtab[ctlr] = bp;
/*
* Now that the command-buffer is setup, give it to the controller
*/
do_cmd:
- debug (("tsstart: calling tsexec(%d, %d)\n", unit, cmd));
- return (tsexec (unit, cmd));
+ return (tsexec(ctlr, cmd));
}
/*
@@ -650,6 +588,7 @@ int
tswchar (ctlr)
int ctlr;
{
+ struct ts_softc *sc = ts_cd.cd_devs[ctlr];
volatile struct tsdevice *tsregs = ts[ctlr].reg;
volatile struct tscmd *tscmdp = &ts[ctlr].cmd;
volatile struct tsmsg *tsmsgp = &ts[ctlr].msg;
@@ -658,17 +597,17 @@ tswchar (ctlr)
/*
* assemble and send "WRITE CHARACTERISTICS" command
*/
- ma = (long)tsmsgp;
- if (ma & 0x7FC00001) { /* address must be even and 22-bit */
- printf ("invalid address 0x%0x for msg-buffer.\n", ma);
- return (-1);
- }
-
- tsmsgp->hdr = ma & 0xFFFF; /* low order addr. bits */
- tsmsgp->dfl = (ma >> 16) & 0x003F; /* high order addr. bits */
- tsmsgp->rbpcr = 16; /* size of message-buffer */
- tsmsgp->xst0 = 0; /* chacacteristics mode word */
- tsmsgp->xst1 = 0; /* control word (ext.feat.) */
+ ma = (long)tsmsgp;
+ if (ma & 0x7FC00001) { /* address must be even and 22-bit */
+ printf ("invalid address 0x%0x for msg-buffer.\n", ma);
+ return (-1);
+ }
+
+ tsmsgp->hdr = ma & 0xFFFF; /* low order addr. bits */
+ tsmsgp->dfl = (ma >> 16) & 0x003F; /* high order addr. bits */
+ tsmsgp->rbpcr = 16; /* size of message-buffer */
+ tsmsgp->xst0 = 0; /* chacacteristics mode word */
+ tsmsgp->xst1 = 0; /* control word (ext.feat.) */
#ifdef TS11_COMPAT
tsmsgp->rbpcr = 14; /* size of message-buffer */
@@ -695,29 +634,29 @@ tswchar (ctlr)
#endif
#endif
- tscmdp->cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_WCHAR; /* obsolete */
- tscmdp->cw1 = ma & 0xFFFF;
- tscmdp->cw2 = (ma >> 16) & 0x003F;
- tscmdp->cw3 = 10; /* size of charact.-data */
+ tscmdp->cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_WCHAR; /* obsolete */
+ tscmdp->cw1 = ma & 0xFFFF;
+ tscmdp->cw2 = (ma >> 16) & 0x003F;
+ tscmdp->cw3 = 10; /* size of charact.-data */
- if (tsexec (ctlr, TS_CMD_WCHAR) < 0) {
- printf ("%s%d: write characteristics command failed [%x]\n",
- CTLRNAME, ctlr, tsregs->tssr);
- return (-1);
+ if (tsexec (ctlr, TS_CMD_WCHAR) < 0) {
+ printf ("%s: write characteristics command failed [%x]\n",
+ sc->sc_dev.dv_xname, tsregs->tssr);
+ return (-1);
}
- timeout = 1000; /* timeout in 10 seconds */
- do {
+ timeout = 1000; /* timeout in 10 seconds */
+ do {
DELAY(10000);
- sr = tsregs->tssr;
- debug10 (("\ttssr: 0x%x\n", sr));
- if (timeout-- > 0) {
- printf ("timeout during initialize.");
- tsstatus (sr);
- return (-1);
- }
- } while ((sr & TS_SSR) == 0);
- tsstatus (sr);
+ sr = tsregs->tssr;
+ debug10 (("\ttssr: 0x%x\n", sr));
+ if (timeout-- > 0) {
+ printf ("timeout during initialize.");
+ tsstatus (sr);
+ return (-1);
+ }
+ } while ((sr & TS_SSR) == 0);
+ tsstatus (sr);
return (0);
}
@@ -729,101 +668,95 @@ void
tsreset(ctlr)
int ctlr;
{
+ struct ts_softc *sc = ts_cd.cd_devs[ctlr];
volatile struct tsdevice *tsreg = ts[ctlr].reg;
volatile unsigned int sr, timeout;
- trace (("tsreset (%d)\n", ctlr));
-
/*
* reset ctlr by writing into TSSR, then write characteristics
*/
- timeout = 1000; /* timeout in 10 seconds */
- tsreg->tssr = 0; /* start initialization */
- do {
+ timeout = 1000; /* timeout in 10 seconds */
+ tsreg->tssr = 0; /* start initialization */
+ do {
DELAY(10000);
- sr = tsreg->tssr;
- debug10 (("\ttssr: 0x%x\n", sr));
- if (timeout-- > 0) {
- if (sr != 0)
- printf ("%s%d: timeout waiting for TS_SSR\n",
- CTLRNAME, ctlr);
- tsstatus (sr);
+ sr = tsreg->tssr;
+ debug10 (("\ttssr: 0x%x\n", sr));
+ if (timeout-- > 0) {
+ if (sr != 0)
+ printf ("%s: timeout waiting for TS_SSR\n",
+ sc->sc_dev.dv_xname);
+ tsstatus (sr);
return;
- }
- } while ((sr & TS_SSR) == 0); /* wait until subsystem ready */
- tsstatus (sr);
+ }
+ } while ((sr & TS_SSR) == 0); /* wait until subsystem ready */
+ tsstatus (sr);
return;
}
-extern struct cfdriver uba_cd;
/*
* probe for device. If found, try to raise an interrupt.
+ * XXX - most of this should be done in the attach routine.
*/
-int
-tsprobe (reg, ctlr, um, uh)
- caddr_t reg; /* address of TSDB register */
- int ctlr; /* index of the controller */
- struct uba_ctlr *um; /* controller-info */
- struct uba_softc *uh;
+int
+tsmatch(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
{
- register struct ts_softc *sc;
- register struct tsdevice *tsregs = (struct tsdevice*) reg;
+ struct ts_softc *sc = match;
+ struct uba_softc *uh = (void *)parent;
+ struct uba_attach_args *ua = aux;
+ struct tsdevice *tsregs = (struct tsdevice*)ua->ua_addr;
volatile unsigned int sr, timeout, count;
- struct uba_softc *ubasc;
-
- trace (("tsprobe (%x, %d, %x)\n", reg, ctlr, um));
+ int ctlr = sc->sc_dev.dv_unit;
ts_wtab[ctlr] = NULL;
- sc = &ts_softc[ctlr];
sc->sc_ts = &ts[ctlr];
sc->sc_state = ST_PROBE;
sc->sc_flags = 0;
- zsinfo[ctlr] = um;
- ts[ctlr].reg = (struct tsdevice*) reg;
+ ts[ctlr].reg = (struct tsdevice*)ua->ua_addr;
/*
- * Set host-settable interrupt vector.
- * Assign 0 to the TSSR register to start the ts-device initialization.
- * The device is not really initialized at this point, this is just to
- * find out if the device exists.
- */
- ubasc = uba_cd.cd_devs[0]; /* XXX */
- sc->sc_ivec = (ubasc->uh_lastiv -= 4);
+ * Set host-settable interrupt vector.
+ * Assign 0 to the TSSR register to start the ts-device initialization.
+ * The device is not really initialized at this point, this is just to
+ * find out if the device exists.
+ */
+ sc->sc_ivec = (uh->uh_lastiv -= 4);
count = 0;
again:
timeout = 1000; /* timeout in 10 seconds */
- tsregs->tssr = 0; /* start initialization */
+ tsregs->tssr = 0; /* start initialization */
do {
DELAY(10000);
sr = tsregs->tssr;
debug10 (("\ttssr-1: 0x%x\n", sr));
if (timeout-- > 0) {
if (sr != 0) /* the device exists !!! */
- printf ("%s%d: timeout waiting for TS_SSR\n",
- CTLRNAME, ctlr);
+ printf ("%s: timeout waiting for TS_SSR\n",
+ sc->sc_dev.dv_xname);
tsstatus (sr);
goto bad;
}
} while ((sr & TS_SSR) == 0); /* wait until subsystem ready */
tsstatus (sr);
- tswchar (ctlr); /* write charact. to enable interrupts */
+ tswchar (ctlr); /* write charact. to enable interrupts */
/* completion of this will raise the intr. */
#ifdef notyet
- sc->sc_ipl = br = qbgetpri();
+ sc->sc_ipl = br = qbgetpri();
#else
- sc->sc_ipl = 0x15;
+ sc->sc_ipl = 0x15;
#endif
- return (sizeof (struct tsdevice));
+ return (sizeof (struct tsdevice));
bad: if (++count < 3)
goto again;
#ifdef notyet
- splx(s);
+ splx(s);
#endif
return (0);
}
@@ -834,14 +767,14 @@ bad: if (++count < 3)
* Since there's only one drive per controller there's nothing to do.
* (we could check the status of the drive (online/offline/...)
*/
-int
-tsslave (ui, reg)
- struct uba_device *ui; /* ptr to the uba device structure */
- caddr_t reg; /* addr of the device controller */
+void
+tsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
{
- register int ctlr = ui->ui_ctlr;
- register struct ts_softc *sc = &ts_softc[ctlr];
- register struct tsmsg *tsmsgp = &ts[ctlr].msg;
+ struct ts_softc *sc = (void *)self;
+ int ctlr = sc->sc_dev.dv_unit;
+ struct tsmsg *tsmsgp = &ts[ctlr].msg;
trace (("tsslave (%x, %x)\n", ui, reg));
@@ -852,46 +785,30 @@ tsslave (ui, reg)
*/
sc->sc_state = ST_SLAVE; /* tsintr() checks this ... */
if (tswchar (ctlr) < 0) {
- printf ("%s%d: cannot initialize", CTLRNAME, ctlr);
- return (0); /* ??? XXX ??? */
+ printf ("%s: cannot initialize", sc->sc_dev.dv_xname);
}
sc->sc_micro = (tsmsgp->xst2 & TS_SF_MCRL) >> 2;
- printf ("%s%d: rev %d, extended features %s, transport %s\n",
- CTLRNAME, ctlr, sc->sc_micro,
+ printf ("%s: rev %d, extended features %s, transport %s\n",
+ sc->sc_dev.dv_xname, sc->sc_micro,
(tsmsgp->xst2 & TS_SF_EFES ? "enabled" : "disabled"),
(ts[ctlr].reg->tssr & TS_OFL ? "offline" : "online"));
- tsinit (ctlr); /* must be called once, why not here ? */
-
- return (1);
+ tsinit (sc); /* must be called once, why not here ? */
}
/*
- * Open routine will issue the online command, later.
- * Just reset the flags and do nothing ...
- */
-void
-tsattach (ui)
- struct uba_device *ui;
-{
- trace (("\ntsattach (%x)", ui));
- ui->ui_flags = 0; /* mark unit offline */
-}
-
-
-/*
* TSV05/TS05 interrupt routine
*/
void
tsintr(ctlr)
int ctlr;
{
- register struct ts_softc *sc = &ts_softc[ctlr];
+ register struct ts_softc *sc = ts_cd.cd_devs[ctlr];
register struct tsmsg *tsmsgp = &ts[ctlr].msg;
register struct tscmd *tscmdp = &ts[ctlr].cmd;
volatile struct tsdevice *tsreg = ts[ctlr].reg;
- struct uba_ctlr *um = zsinfo[ctlr];
+ struct uba_unit *um = &sc->sc_unit;
register struct buf *bp;
unsigned short sr = tsreg->tssr; /* save TSSR */
@@ -902,12 +819,16 @@ tsintr(ctlr)
short cmask = tscmdp->cmdr & TS_CF_CMASK;
#ifdef DEBUG
- printf ("TSSR: %b, MSG: %x ", sr, TS_TSSR_BITS, mh);
+ {
+ char bits[64];
+ printf ("TSSR: %s, MSG: %x ", bitmask_snprintf(sr,
+ TS_TSSR_BITS, bits, sizeof(bits)), mh);
+ }
switch (tsmsgp->hdr & 0x001F) {
case 16: printf ("(End)"); break;
case 17: printf ("(Fail)"); break;
case 18: printf ("(Error)"); break;
- case 19: printf ("(Attention)"); break;
+ case 19: printf ("(Attention)"); break;
}
#endif
@@ -917,8 +838,8 @@ tsintr(ctlr)
sc->sc_cmdf |= TS_CF_CVC;
#ifdef QBA /* copied from uda.c */
- if(cpunumber == VAX_78032)
- splx(sc->sc_ipl); /* Qbus interrupt protocol is odd */
+ if(vax_cputype == VAX_78032)
+ splx(sc->sc_ipl); /* Qbus interrupt protocol is odd */
#endif
/*
@@ -935,14 +856,12 @@ tsintr(ctlr)
switch (sc->sc_state) {
case ST_INVALID:
- /*
- * Ignore unsolicited interrupts.
- */
- debug (("%s%d: intr in state ST_INVALID [%x,%x]\n",
- CTLRNAME, ctlr, sr, mh));
- log (LOG_WARNING, "%s%d: stray intr [%x,%x]\n",
- CTLRNAME, ctlr, sr, mh);
- return;
+ /*
+ * Ignore unsolicited interrupts.
+ */
+ log (LOG_WARNING, "%s: stray intr [%x,%x]\n",
+ sc->sc_dev.dv_xname, sr, mh);
+ return;
case ST_SLAVE:
/*
@@ -950,11 +869,9 @@ tsintr(ctlr)
* issued by tsslave() and indicates the end of the
* initialization phase. Just ignore it ...
*/
- debug (("%s%d: intr in state ST_SLAVE [%x,%x]\n",
- CTLRNAME, ctlr, sr, mh));
if ((sr & TS_SC) != 0 || (sr & TS_TC) != TS_TC_NORM) {
- printf ("%s%d: problem during init [%x,%x]\n",
- CTLRNAME, ctlr, sr, mh);
+ printf("%s: problem during init [%x,%x]\n",
+ sc->sc_dev.dv_xname, sr, mh);
/* return here ??? */
/* break and check the error outside switch ??? */
break;
@@ -968,23 +885,18 @@ tsintr(ctlr)
* Here we expect interrupts indicating the end of
* commands or indicating problems.
*/
- debug (("%s%d: intr ST_RUN (%s) [%x,%x]\n",
- CTLRNAME, ctlr, ((tsmsgp->xst0 & TS_SF_ONL) ?
- "online" : "offline"), sr, mh));
/*
* Anything else is handled outside this switch ...
*/
break;
case ST_IDLE:
- debug (("%s%d: intr ST_IDLE [%x,%x]\n",
- CTLRNAME, ctlr, sr, mh));
break;
default:
- printf ("%s%d: unexpected interrupt during state %d [%x,%x]\n",
- CTLRNAME, ctlr, sc->sc_state, sr, mh);
+ printf ("%s: unexpected interrupt during state %d [%x,%x]\n",
+ sc->sc_dev.dv_xname, sc->sc_state, sr, mh);
return;
}
@@ -998,7 +910,6 @@ tsintr(ctlr)
* Normal termination -- The operation is completed
* witout incident.
*/
- debug (("%s%d: Normal Termination\n", CTLRNAME, ctlr));
sc->sc_state = ST_IDLE; /* XXX ??? */
sc->sc_state = ST_RUNNING;
sc->sc_liowf = (ccode == TS_CC_WRITE);
@@ -1006,12 +917,16 @@ tsintr(ctlr)
if ((bp = ts_wtab[ctlr]) != NULL) {
ts_wtab[ctlr] = NULL; /* pseudo-unlink */
- if (bp != &ts_cbuf[ctlr]) { /* no ioctl */
- debug (("ubarelse\n"));
- ubarelse (um->um_ubanum, (int *)&bp->b_ubinfo);
+ if (bp != &ts_cbuf[ctlr]) { /* no ioctl */
+ ubarelse((struct uba_softc *)
+ sc->sc_dev.dv_parent,
+ (int *)&bp->b_ubinfo);
#if defined(VAX750)
- if (cpunumber == VAX_750 && um->um_ubinfo != 0)
- ubarelse(um->um_ubanum, &um->um_ubinfo);
+ if (vax_cputype == VAX_750 &&
+ sc->sc_unit.uu_ubinfo != 0)
+ ubarelse((struct uba_softc *)
+ sc->sc_dev.dv_parent,
+ &sc->sc_unit.uu_ubinfo);
/* XXX */
#endif
}
@@ -1030,10 +945,9 @@ tsintr(ctlr)
* (Without EAI enabled, no Attention interrupts occur.
* drive status changes are signaled by the VCK flag.)
*/
- debug (("%s%d: Attention\n", CTLRNAME, ctlr));
return;
- case TS_TC_TSA:
+ case TS_TC_TSA:
/*
* Tape Status Alert -- A status condition is encountered
* that may have significance to the program. Bits of
@@ -1050,7 +964,7 @@ tsintr(ctlr)
}
break;
- case TS_TC_FR:
+ case TS_TC_FR:
/*
* Function Reject -- The specified function was not
* initiated. Bits of interest include OFL, VCK, BOT,
@@ -1075,7 +989,7 @@ tsintr(ctlr)
}
break;
- case TS_TC_TPD:
+ case TS_TC_TPD:
/*
* Recoverable Error -- Tape position is a record beyond
* what its position was when the function was initiated.
@@ -1096,7 +1010,7 @@ tsintr(ctlr)
return;
case TS_CMD_WD: /* Write Data (Next) */
debug (("retry write data ...\n"));
- sc->sc_rtc = 1;
+ sc->sc_rtc = 1;
tsexec (ctlr, TS_CMD_WDR);
return;
case TS_CMD_WTM:
@@ -1109,7 +1023,7 @@ tsintr(ctlr)
}
break;
- case TS_TC_TNM:
+ case TS_TC_TNM:
/*
* Recoverable Error -- Tape position has not changed.
* Suggested recovery procedure is to log the error and
@@ -1126,7 +1040,7 @@ tsintr(ctlr)
}
break;
- case TS_TC_TPL:
+ case TS_TC_TPL:
/*
* Unrecoverable Error -- Tape position has been lost.
* No valid recovery procedures exist unless the tape
@@ -1135,7 +1049,7 @@ tsintr(ctlr)
printf ("Tape position lost\n");
break;
- case TS_TC_FCE:
+ case TS_TC_FCE:
/*
* Fatal subsytem Error -- The subsytem is incapable
* of properly performing commands, or at least its
@@ -1146,8 +1060,8 @@ tsintr(ctlr)
printf ("Fatal Controller Error\n");
default:
- printf ("%s%d: error 0x%x, resetting controller\n",
- CTLRNAME, ctlr, sr & TS_TC);
+ printf ("%s: error 0x%x, resetting controller\n",
+ sc->sc_dev.dv_xname, sr & TS_TC);
tsreset (ctlr);
}
@@ -1157,14 +1071,13 @@ tsintr(ctlr)
if ((bp = ts_wtab[ctlr]) != NULL) {
ts_wtab[ctlr] = NULL; /* pseudo unlink */
- if (bp != &ts_cbuf[ctlr]) { /* no ioctl */
- debug (("ubarelse-2\n"));
- ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo);
- }
- if ((sr & TS_TC) != TS_TC_NORM) {
+ if (bp != &ts_cbuf[ctlr]) /* no ioctl */
+ ubarelse((struct uba_softc *)sc->sc_dev.dv_parent,
+ (int *)&bp->b_ubinfo);
+
+ if ((sr & TS_TC) != TS_TC_NORM)
bp->b_flags |= B_ERROR;
- debug (("tsintr: bp->b_flags |= B_ERROR\n"));
- }
+
debug (("resid:%d, count:%d, rbpcr:%d\n",
bp->b_resid, bp->b_bcount, tsmsgp->rbpcr));
bp->b_resid = tsmsgp->rbpcr; /* XXX */
@@ -1196,27 +1109,27 @@ tsopen (dev, flag, type, p)
trace (("tsopen (%x, %x)\n", dev, flag));
- if (unit >= NTS || (ui = tsinfo[unit]) == 0 || ui->ui_alive == 0) {
- debug (("ui->ui_alive == 0\n"));
- return (ENXIO);
- }
- sc = &ts_softc[ui->ui_ctlr]; /* unit ??? */
- if (sc->sc_openf) {
- debug (("sc->sc_openf\n"));
- return (EBUSY);
- }
+ if (unit >= ts_cd.cd_ndevs)
+ return ENXIO;
+
+ sc = ts_cd.cd_devs[unit];
+ if (sc == 0)
+ return ENXIO;
+
+ if (sc->sc_openf)
+ return EBUSY;
+
sc->sc_openf = 1;
- sc->sc_tpr = tprintf_open (curproc);
+
s = splbio ();
if (sc->sc_state < ST_RUNNING) { /* XXX */
- printf ("ts%d not running.\n", ui->ui_ctlr);
+ printf ("%s not running.\n", sc->sc_dev.dv_xname);
(void) splx (s);
sc->sc_openf = 0;
return (ENXIO);
}
- um = ui->ui_mi;
(void) splx (s);
-#if 1
+
/*
* check if transport is really online.
* (without attention-interrupts enabled, we really don't know
@@ -1224,14 +1137,14 @@ tsopen (dev, flag, type, p)
* (ie. MTNOP) once and check the actual status.)
*/
tscommand (dev, MTNOP, 1);
- if (ts[TS_CTLR(dev)].reg->tssr & TS_OFL) {
- printf ("ts%d: transport is offline.\n", ui->ui_ctlr);
+ if (ts[unit].reg->tssr & TS_OFL) {
+ printf ("%s: transport is offline.\n", sc->sc_dev.dv_xname);
sc->sc_openf = 0;
- return (EIO); /* transport is offline */
+ return EIO; /* transport is offline */
}
-#endif
+
sc->sc_liowf = 0;
- return (0);
+ return 0;
}
@@ -1246,16 +1159,13 @@ tsopen (dev, flag, type, p)
*/
int
tsclose (dev, flag, type, p)
- dev_t dev;
- int flag, type;
+ dev_t dev;
+ int flag, type;
struct proc *p;
{
- register struct ts_softc *sc = &ts_softc[TS_UNIT(dev)];
-
- trace (("tsclose (%x, %d)\n", dev, flag));
+ register struct ts_softc *sc = ts_cd.cd_devs[TS_UNIT(dev)];
if (flag == FWRITE || ((flag & FWRITE) && sc->sc_liowf)) {
- debug (("tsclose: writing eot\n"));
/*
* We are writing two tape marks (EOT), but place the tape
* before the second one, so that another write operation
@@ -1263,18 +1173,15 @@ tsclose (dev, flag, type, p)
*/
tscommand (dev, MTWEOF, 1); /* Write Tape Mark */
tscommand (dev, MTWEOF, 1); /* Write Tape Mark */
- tscommand (dev, MTBSF, 1); /* Skip Tape Marks Reverse */
+ tscommand (dev, MTBSF, 1); /* Skip Tape Marks Reverse */
}
- if ((minor(dev)&T_NOREWIND) == 0) {
- debug (("tsclose: rewinding\n"));
+ if ((dev & T_NOREWIND) == 0)
tscommand (dev, MTREW, 0);
- }
- tprintf_close (sc->sc_tpr);
sc->sc_openf = 0;
sc->sc_liowf = 0;
- return (0);
+ return 0;
}
@@ -1283,51 +1190,20 @@ tsclose (dev, flag, type, p)
*/
void
tsstrategy (bp)
- register struct buf *bp;
+ register struct buf *bp;
{
- register struct uba_device *ui;
- register struct uba_ctlr *um;
register int unit = TS_UNIT(bp->b_dev);
+ struct ts_softc *sc = (void *)ts_cd.cd_devs[unit];
int s;
- trace (("tsstrategy (...)\n"));
- if (unit >= NTS) {
- debug (("tsstrategy: bad unit # %d\n",unit));
- bp->b_flags |= B_ERROR;
- iodone(bp);
- return;
- }
- ui = tsinfo[unit];
- if (ui == 0 || ui->ui_alive == 0) {
- debug (("tsstrategy: ui_alive == 0\n"));
- bp->b_flags |= B_ERROR;
- iodone(bp);
- return;
- }
-
s = splbio ();
/*
* we have only one command at one time, no credits.
* thus we don't need buffer management and controller queue
* just try to execute the command ...
*/
-#if 0
- if (ts_wtab[unit] != NULL) {
- debug (("tsstrategy: already waiting for something\n"));
- ts_wtab[unit]->b_flags |= B_ERROR;
- iodone (ts_wtab[unit]);
- }
- ts_wtab[unit] = bp;
-#endif
- um = ui->ui_mi;
- if (um->um_tab.b_active == 0) {
- /*
- * If the controller is not active, start it.
- */
- }
-
- tsstart (um, bp);
+ tsstart (sc, bp);
splx(s);
return;
}
@@ -1338,10 +1214,10 @@ tsstrategy (bp)
*/
int
tsioctl (dev, cmd, data, flag, p)
- dev_t dev;
+ dev_t dev;
u_long cmd;
- caddr_t data;
- int flag;
+ caddr_t data;
+ int flag;
struct proc *p;
{
register struct buf *bp = &ts_cbuf[TS_UNIT(dev)];
@@ -1413,11 +1289,11 @@ tsioctl (dev, cmd, data, flag, p)
return (error);
case MTIOCGET: /* get tape status */
- sc = &ts_softc[TS_CTLR(dev)];
+ sc = ts_cd.cd_devs[TS_UNIT(dev)];
mtget = (struct mtget *)data;
mtget->mt_type = MT_ISTS;
- mtget->mt_dsreg = (unsigned)(ts[TS_CTLR(dev)].reg->tssr);
- mtget->mt_erreg = (unsigned)(ts[TS_CTLR(dev)].msg.hdr);
+ mtget->mt_dsreg = (unsigned)(ts[TS_UNIT(dev)].reg->tssr);
+ mtget->mt_erreg = (unsigned)(ts[TS_UNIT(dev)].msg.hdr);
mtget->mt_resid = 0; /* ??? */
mtget->mt_density = 0; /* ??? */
break;
@@ -1482,7 +1358,10 @@ tsstatus (sr)
int sr;
{
#ifdef DEBUG
- debug (("status: TSSR=%b\n", sr, TS_TSSR_BITS));
+ char bits[64];
+
+ debug (("status: TSSR=%s\n", bitmask_snprintf(sr, TS_TSSR_BITS,
+ bits, sizeof(bits))));
if (tsdebug < 5)
return (0);
@@ -1496,7 +1375,7 @@ tsstatus (sr)
if (sr & TS_A11) printf ("Address Bits 17-16\n");
if (sr & TS_SSR) printf ("Subsystem Ready\n");
if (sr & TS_OFL) printf ("Off Line\n");
- if (sr & TS_FTC) printf ("Fatal Termination Class Code\n");
+ if (sr & TS_FTC) printf ("Fatal Termination Class Code\n");
switch (sr & TS_TC) {
case TS_TC_NORM: printf ("Normal Termination\n"); break;
case TS_TC_ATTN: printf ("Attention Condition\n"); break;
@@ -1516,10 +1395,18 @@ tsxstatus (mp)
struct tsmsg *mp;
{
#ifdef DEBUG
- debug (("tsxstatus: xst0=%b, xst1=%b, xst2=%b, xst3=%b, xst4=%b\n",
- mp->xst0, TS_XST0_BITS, mp->xst1, TS_XST1_BITS,
- mp->xst2, TS_XST2_BITS, mp->xst3, TS_XST3_BITS,
- mp->xst4, "\20"));
+ char bits[64];
+
+ debug (("tsxstatus: xst0=%s, ", bitmask_snprintf(mp->xst0,
+ TS_XST0_BITS, bits, sizeof(bits))));
+ debug (("xst1=%s, ", bitmask_snprintf(mp->xst1, TS_XST1_BITS,
+ bits, sizeof(bits))));
+ debug (("xst2=%s, ", bitmask_snprintf(mp->xst2, TS_XST2_BITS,
+ bits, sizeof(bits))));
+ debug (("xst3=%s, ", bitmask_snprintf(mp->xst3, TS_XST3_BITS,
+ bits, sizeof(bits))));
+ debug (("xst4=%s\n", bitmask_snprintf(mp->xst4, "\20",
+ bits, sizeof(bits))));
if (tsdebug < 10)
return (0);
@@ -1566,23 +1453,3 @@ tsxstatus (mp)
if (mp->xst4 & TS_SF_RCX) printf ("Retry Count Exceeded\n");
#endif
}
-
-int
-ts_match(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- return 0;
-}
-
-void
-ts_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
-}
-
-
-
-#endif /* #if NTS > 0 */
-
diff --git a/sys/arch/vax/uba/uba.c b/sys/arch/vax/uba/uba.c
index 2018c4a60bd..fd1a2eadb84 100644
--- a/sys/arch/vax/uba/uba.c
+++ b/sys/arch/vax/uba/uba.c
@@ -1,8 +1,8 @@
-/* $NetBSD: uba.c,v 1.22 1996/04/08 18:37:34 ragge Exp $ */
-
+/* $NetBSD: uba.c,v 1.29 1996/10/13 03:35:24 christos Exp $ */
/*
+ * Copyright (c) 1996 Jonathan Stone.
+ * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
* Copyright (c) 1982, 1986 The Regents of the University of California.
- * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)uba.c 7.10 (Berkeley) 12/16/90
- * @(#)autoconf.c 7.20 (Berkeley) 5/9/91
+ * @(#)autoconf.c 7.20 (Berkeley) 5/9/91
*/
#include <sys/param.h>
@@ -66,35 +66,435 @@
#include <vax/uba/ubareg.h>
#include <vax/uba/ubavar.h>
-extern int cold;
-
-volatile int rbr,rcvec;
+volatile int rbr, rcvec, svec;
-int uba_match __P((struct device *, void *, void *));
-void uba_attach __P((struct device *, struct device *, void *));
-void ubascan __P((struct device *, void *));
-int ubaprint __P((void *, const char *));
-void uba_dw780int __P((int));
-void ubaerror __P((int, struct uba_softc *, int *, int *,
- struct uba_regs *));
-void ubainit __P((struct uba_softc *));
-void ubastray __P((int));
-void unifind __P((struct uba_softc *, caddr_t));
-void ubapurge __P((struct uba_ctlr *));
-void ubainitmaps __P((struct uba_softc *));
-int qbgetpri __P((void));
-int ubamem __P((int, int, int, int));
-void uba_dw780int __P((int));
+static void ubascan __P((struct device *, void *));
+static int ubaprint __P((void *, const char *));
+static void ubastray __P((int));
+static void ubainitmaps __P((struct uba_softc *));
+static void uba_attach __P((struct uba_softc *, unsigned long));
+static int ubasetup __P((struct uba_softc *, struct buf *, int));
struct cfdriver uba_cd = {
NULL, "uba", DV_DULL, 1
};
-struct cfattach uba_ca = {
- sizeof(struct uba_softc), uba_match, uba_attach
+#define spluba spl7
+
+#if defined(DW780) || defined(DW750)
+
+int dw_match __P((struct device *, void *, void *));
+
+int
+dw_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
+ struct cfdata *cf = vcf;
+
+ if ((cf->cf_loc[0] != sa->nexnum) && (cf->cf_loc[0] > -1 ))
+ return 0;
+
+ /*
+ * The uba type is actually only telling where the uba
+ * space is in nexus space.
+ */
+ if ((sa->type & ~3) != NEX_UBA0)
+ return 0;
+
+ return 1;
+}
+#endif
+
+#ifdef DW780
+/*
+ * The DW780 are directly connected to the SBI on 11/780 and 8600.
+ */
+void dw780_attach __P((struct device *, struct device *, void *));
+void dw780_beforescan __P((struct uba_softc *));
+void dw780_afterscan __P((struct uba_softc *));
+int dw780_errchk __P((struct uba_softc *));
+void dw780_init __P((struct uba_softc *));
+void dw780_purge __P((struct uba_softc *, int));
+void uba_dw780int __P((int));
+static void ubaerror __P((struct uba_softc *, int *, int *));
+
+struct cfattach uba_sbi_ca = {
+ sizeof(struct uba_softc), dw_match, dw780_attach
+};
+
+char ubasr_bits[] = UBASR_BITS;
+
+void
+dw780_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct uba_softc *sc = (void *)self;
+ struct sbi_attach_args *sa = aux;
+ int ubaddr = sa->type & 3;
+
+ printf(": DW780\n");
+
+ /*
+ * Fill in bus specific data.
+ */
+ sc->uh_uba = (void *)sa->nexaddr;
+ sc->uh_nbdp = NBDP780;
+ sc->uh_nr = sa->nexnum * (parent->dv_unit + 1);
+ sc->uh_beforescan = dw780_beforescan;
+ sc->uh_afterscan = dw780_afterscan;
+ sc->uh_errchk = dw780_errchk;
+ sc->uh_ubapurge = dw780_purge;
+ sc->uh_ubainit = dw780_init;
+ sc->uh_type = DW780;
+ sc->uh_memsize = UBAPAGES;
+ sc->uh_iarea = (void *)scb + NBPG + ubaddr * NBPG;
+ sc->uh_mr = sc->uh_uba->uba_map;
+
+ bcopy(&idsptch, &sc->uh_dw780, sizeof(struct ivec_dsp));
+ sc->uh_dw780.pushlarg = sc->uh_dev.dv_unit;
+ sc->uh_dw780.hoppaddr = uba_dw780int;
+ scb->scb_nexvec[0][sa->nexnum] = scb->scb_nexvec[1][sa->nexnum]
+ = scb->scb_nexvec[2][sa->nexnum]
+ = scb->scb_nexvec[3][sa->nexnum] = &sc->uh_dw780;
+
+ uba_attach(sc, (parent->dv_unit ? UMEMB8600(ubaddr) :
+ UMEMA8600(ubaddr)) + (UBAPAGES * NBPG));
+}
+
+void
+dw780_beforescan(sc)
+ struct uba_softc *sc;
+{
+ volatile int *hej = &sc->uh_uba->uba_sr;
+
+ if (sc->uh_type == DW780) {
+ *hej = *hej;
+ sc->uh_uba->uba_cr = UBACR_IFS|UBACR_BRIE;
+ }
+}
+
+void
+dw780_afterscan(sc)
+ struct uba_softc *sc;
+{
+ if (sc->uh_type == DW780)
+ sc->uh_uba->uba_cr = UBACR_IFS | UBACR_BRIE |
+ UBACR_USEFIE | UBACR_SUEFIE |
+ (sc->uh_uba->uba_cr & 0x7c000000);
+}
+
+/*
+ * On DW780 badaddr() in uba space sets a bit in uba_sr instead of
+ * doing a machine check.
+ */
+int
+dw780_errchk(sc)
+ struct uba_softc *sc;
+{
+ volatile int *hej = &sc->uh_uba->uba_sr;
+
+ if (sc->uh_type == DW780 && *hej) {
+ *hej = *hej;
+ return 1;
+ }
+ return 0;
+}
+
+void
+uba_dw780int(uba)
+ int uba;
+{
+ int br, vec, arg;
+ struct uba_softc *sc = uba_cd.cd_devs[uba];
+ struct uba_regs *ur = sc->uh_uba;
+ void (*func) __P((int));
+
+ br = mfpr(PR_IPL);
+ svec = ur->uba_brrvr[br - 0x14];
+ if (svec <= 0) {
+ ubaerror(sc, &br, (int *)&svec);
+ if (svec == 0)
+ return;
+ }
+ vec = svec >> 2;
+ if (cold)
+ rcvec = vec;
+ func = sc->uh_idsp[vec].hoppaddr;
+ arg = sc->uh_idsp[vec].pushlarg;
+ (*func)(arg);
+}
+
+void
+dw780_init(sc)
+ struct uba_softc *sc;
+{
+ sc->uh_uba->uba_cr = UBACR_ADINIT;
+ sc->uh_uba->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE;
+ while ((sc->uh_uba->uba_cnfgr & UBACNFGR_UBIC) == 0)
+ ;
+}
+
+void
+dw780_purge(sc, bdp)
+ struct uba_softc *sc;
+ int bdp;
+{
+ sc->uh_uba->uba_dpr[bdp] |= UBADPR_BNE;
+}
+
+int ubawedgecnt = 10;
+int ubacrazy = 500;
+int zvcnt_max = 5000; /* in 8 sec */
+int ubaerrcnt;
+/*
+ * This routine is called by the locore code to process a UBA
+ * error on an 11/780 or 8600. The arguments are passed
+ * on the stack, and value-result (through some trickery).
+ * In particular, the uvec argument is used for further
+ * uba processing so the result aspect of it is very important.
+ * It must not be declared register.
+ */
+/*ARGSUSED*/
+void
+ubaerror(uh, ipl, uvec)
+ register struct uba_softc *uh;
+ int *ipl, *uvec;
+{
+ struct uba_regs *uba = uh->uh_uba;
+ register sr, s;
+
+ if (*uvec == 0) {
+ /*
+ * Declare dt as unsigned so that negative values
+ * are handled as >8 below, in case time was set back.
+ */
+ u_long dt = time.tv_sec - uh->uh_zvtime;
+
+ uh->uh_zvtotal++;
+ if (dt > 8) {
+ uh->uh_zvtime = time.tv_sec;
+ uh->uh_zvcnt = 0;
+ }
+ if (++uh->uh_zvcnt > zvcnt_max) {
+ printf("%s: too many zero vectors (%d in <%d sec)\n",
+ uh->uh_dev.dv_xname, uh->uh_zvcnt, (int)dt + 1);
+ printf("\tIPL 0x%x\n\tcnfgr: %b Adapter Code: 0x%x\n",
+ *ipl, uba->uba_cnfgr&(~0xff), UBACNFGR_BITS,
+ uba->uba_cnfgr&0xff);
+ printf("\tsr: %b\n\tdcr: %x (MIC %sOK)\n",
+ uba->uba_sr, ubasr_bits, uba->uba_dcr,
+ (uba->uba_dcr&0x8000000)?"":"NOT ");
+ ubareset(uh->uh_dev.dv_unit);
+ }
+ return;
+ }
+ if (uba->uba_cnfgr & NEX_CFGFLT) {
+ printf("%s: sbi fault sr=%b cnfgr=%b\n",
+ uh->uh_dev.dv_xname, uba->uba_sr, ubasr_bits,
+ uba->uba_cnfgr, NEXFLT_BITS);
+ ubareset(uh->uh_dev.dv_unit);
+ *uvec = 0;
+ return;
+ }
+ sr = uba->uba_sr;
+ s = spluba();
+ printf("%s: uba error sr=%b fmer=%x fubar=%o\n", uh->uh_dev.dv_xname,
+ uba->uba_sr, ubasr_bits, uba->uba_fmer, 4*uba->uba_fubar);
+ splx(s);
+ uba->uba_sr = sr;
+ *uvec &= UBABRRVR_DIV;
+ if (++ubaerrcnt % ubawedgecnt == 0) {
+ if (ubaerrcnt > ubacrazy)
+ panic("uba crazy");
+ printf("ERROR LIMIT ");
+ ubareset(uh->uh_dev.dv_unit);
+ *uvec = 0;
+ return;
+ }
+ return;
+}
+#endif
+
+#ifdef DW750
+/*
+ * The DW780 and DW750 are quite similar to their function from
+ * a programmers point of view. Differencies are number of BDP's
+ * and bus status/command registers, the latter are (partly) IPR's
+ * on 750.
+ */
+void dw750_attach __P((struct device *, struct device *, void *));
+void dw750_init __P((struct uba_softc *));
+void dw750_purge __P((struct uba_softc *, int));
+
+struct cfattach uba_cmi_ca = {
+ sizeof(struct uba_softc), dw_match, dw750_attach
+};
+
+void
+dw750_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct uba_softc *sc = (void *)self;
+ struct sbi_attach_args *sa = aux;
+ int ubaddr = sa->nexinfo & 1;
+
+ printf(": DW750\n");
+
+ /*
+ * Fill in bus specific data.
+ */
+ sc->uh_uba = (void *)sa->nexaddr;
+ sc->uh_nbdp = NBDP750;
+ sc->uh_nr = sa->nexnum;
+ sc->uh_ubapurge = dw750_purge;
+ sc->uh_ubainit = dw750_init;
+ sc->uh_type = DW750;
+ sc->uh_memsize = UBAPAGES;
+ sc->uh_iarea = (void *)scb + NBPG + ubaddr * NBPG;
+ sc->uh_mr = sc->uh_uba->uba_map;
+
+ uba_attach(sc, UMEM750(ubaddr) + (UBAPAGES * NBPG));
+}
+
+void
+dw750_init(sc)
+ struct uba_softc *sc;
+{
+ mtpr(0, PR_IUR);
+ DELAY(500000);
+}
+
+void
+dw750_purge(sc, bdp)
+ struct uba_softc *sc;
+ int bdp;
+{
+ sc->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE | UBADPR_NXM | UBADPR_UCE;
+}
+#endif
+
+#ifdef QBA
+/*
+ * The Q22 bus is the main IO bus on MicroVAX II/MicroVAX III systems.
+ * It has an address space of 4MB (22 address bits), therefore the name,
+ * and is hardware compatible with all 16 and 18 bits Q-bus devices.
+ * This driver can only handle map registers up to 1MB due to map info
+ * storage, but that should be enough for normal purposes.
+ */
+int qba_match __P((struct device *, void *, void *));
+void qba_attach __P((struct device *, struct device *, void *));
+void qba_beforescan __P((struct uba_softc*));
+void qba_init __P((struct uba_softc*));
+
+struct cfattach uba_backplane_ca = {
+ sizeof(struct uba_softc), qba_match, qba_attach
};
+int
+qba_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct bp_conf *bp = aux;
+
+ if (strcmp(bp->type, "uba"))
+ return 0;
+
+ return 1;
+}
+
+void
+qba_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct uba_softc *sc = (void *)self;
+ vm_offset_t mini, maxi;
+
+ printf(": Q22\n");
+
+
+ /*
+ * Fill in bus specific data.
+ */
+/* sc->uh_uba not used; no regs */
+/* sc->uh_nbdp is 0; Qbus has no BDP's */
+/* sc->uh_nr is 0; there can be only one! */
+/* sc->uh_afterscan; not used */
+/* sc->uh_errchk; not used */
+ sc->uh_beforescan = qba_beforescan;
+ sc->uh_ubainit = qba_init;
+ sc->uh_type = QBA;
+ sc->uh_memsize = QBAPAGES;
+ sc->uh_iarea = (void *)scb + NBPG;
+ /*
+ * Map in the UBA page map into kernel space. On other UBAs,
+ * the map registers are in the bus IO space.
+ */
+ (void)kmem_suballoc(kernel_map, &mini, &maxi,
+ QBAPAGES * sizeof(struct pte), FALSE);
+ pmap_map(mini, QBAMAP, QBAMAP + QBAPAGES * sizeof(struct pte),
+ VM_PROT_READ | VM_PROT_WRITE);
+ sc->uh_mr = (void *)mini;
+
+ uba_attach(sc, QIOPAGE);
+}
+
+/*
+ * Called when the QBA is set up; to enable DMA access from
+ * QBA devices to main memory.
+ */
+void
+qba_beforescan(sc)
+ struct uba_softc *sc;
+{
+ *((u_short *)(sc->uh_iopage + QIPCR)) = Q_LMEAE;
+}
+
+void
+qba_init(sc)
+ struct uba_softc *sc;
+{
+ mtpr(0, PR_IUR);
+ DELAY(500000);
+ qba_beforescan(sc);
+}
+#endif
+#ifdef DWBUA
+int bua_match __P((struct device *, void *, void *));
+void bua_attach __P((struct device *, struct device *, void *));
+
+struct cfattach uba_bi_ca = {
+ sizeof(struct uba_softc), bua_match, bua_attach
+};
+
+bua_beforescan(sc)
+ struct uba_softc *sc;
+{
+ if (sc->uh_type == DWBUA)
+ BUA(ubar)->bua_offset = (int)sc->uh_vec - (int)&scb[0];
+}
+
+void
+bua_init(sc)
+ struct uba_softc *sc;
+{
+ BUA(uba)->bua_csr |= BUACSR_UPI;
+ /* give devices time to recover from power fail */
+ DELAY(500000);
+ break;
+}
+#endif
+#ifdef DW730
+struct cfattach uba_dw730_ca = {
+ sizeof(struct uba_softc), dw730_match, dw730_attach
+};
+#endif
/*
* Stray interrupt vector handler, used when nowhere else to go to.
*/
@@ -104,13 +504,12 @@ ubastray(arg)
{
struct callsframe *cf = FRAMEOFFSET(arg);
struct uba_softc *sc = uba_cd.cd_devs[arg];
- struct uba_regs *ur = sc->uh_uba;
int vektor;
rbr = mfpr(PR_IPL);
#ifdef DW780
if (sc->uh_type == DW780)
- vektor = ur->uba_brrvr[rbr - 0x14] >> 2;
+ vektor = svec >> 2;
else
#endif
vektor = (cf->ca_pc - (unsigned)&sc->uh_idsp[0]) >> 4;
@@ -121,131 +520,10 @@ ubastray(arg)
#endif
rcvec = vektor;
} else
- printf("uba%d: unexpected interrupt, vector %o, br %d\n",
- arg, vektor << 2, rbr - 20);
-}
-
-/*
- * Find devices on a UNIBUS.
- * Uses per-driver routine to set <br,cvec> into <r11,r10>,
- * and then fills in the tables, with help from a per-driver
- * slave initialization routine.
- */
-void
-unifind(uhp0, pumem)
- struct uba_softc *uhp0;
- caddr_t pumem;
-{
- register struct uba_device *ui;
- register struct uba_ctlr *um;
- register struct uba_softc *uhp = uhp0;
- volatile struct uba_regs *ubar = uhp->uh_uba;
- u_short *reg, *ap, addr;
- struct uba_driver *udp;
- int i;
- volatile extern int rbr, rcvec;
-
-#define ubaddr(uhp, off) (u_short *)((int)(uhp)->uh_iopage + ubdevreg(off))
- /*
- * Check each unibus mass storage controller.
- * For each one which is potentially on this uba,
- * see if it is really there, and if it is record it and
- * then go looking for slaves.
- */
- for (um = ubminit; (udp = um->um_driver); um++) {
- if ((um->um_ubanum != uhp->uh_dev.dv_unit &&
- um->um_ubanum != '?') || um->um_alive)
- continue;
- addr = (u_short)(u_long)um->um_addr;
- /*
- * use the particular address specified first,
- * or if it is given as "0", of there is no device
- * at that address, try all the standard addresses
- * in the driver til we find it
- */
- for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
- reg = ubaddr(uhp, addr);
- if (badaddr((caddr_t)reg, 2))
- continue;
-
-#if DW780
- if (uhp->uh_type == DW780 && ubar->uba_sr) {
- ubar->uba_sr = ubar->uba_sr;
- continue;
- }
-#endif
- rcvec = 0x200;
- i = (*udp->ud_probe)((caddr_t)reg, um->um_ctlr, um, uhp);
-#if DW780
- if (uhp->uh_type == DW780 && ubar->uba_sr) {
- ubar->uba_sr = ubar->uba_sr;
- continue;
- }
-#endif
- if (i == 0)
- continue;
- printf("%s%d at uba%d csr %o ",
- udp->ud_mname, um->um_ctlr, uhp->uh_dev.dv_unit, addr);
- if (rcvec == 0) {
- printf("zero vector\n");
- continue;
- }
- if (rcvec == 0x200) {
- printf("didn't interrupt\n");
- continue;
- }
- printf("vec %o, ipl %x\n", rcvec << 2, rbr);
- um->um_alive = 1;
- um->um_ubanum = uhp->uh_dev.dv_unit;
- um->um_hd = uhp;
- um->um_addr = (caddr_t)reg;
- udp->ud_minfo[um->um_ctlr] = um;
- uhp->uh_idsp[rcvec].hoppaddr = um->um_intr;
- uhp->uh_idsp[rcvec].pushlarg = um->um_ctlr;
- for (ui = ubdinit; ui->ui_driver; ui++) {
- int t;
-
- if (ui->ui_driver != udp || ui->ui_alive ||
- (ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?') ||
- (ui->ui_ubanum != uhp->uh_dev.dv_unit &&
- ui->ui_ubanum != '?'))
- continue;
- t = ui->ui_ctlr;
- ui->ui_ctlr = um->um_ctlr;
- if ((*udp->ud_slave)(ui, (caddr_t)reg) == 0)
- ui->ui_ctlr = t;
- else {
- ui->ui_alive = 1;
- ui->ui_ubanum = uhp->uh_dev.dv_unit;
- ui->ui_hd = uhp;
- ui->ui_addr = (caddr_t)reg;
- ui->ui_physaddr = pumem + ubdevreg(addr);
- if (ui->ui_dk && dkn < DK_NDRIVE)
- ui->ui_dk = dkn++;
- else
- ui->ui_dk = -1;
- ui->ui_mi = um;
- /* ui_type comes from driver */
- udp->ud_dinfo[ui->ui_unit] = ui;
- printf("%s%d at %s%d slave %d",
- udp->ud_dname, ui->ui_unit,
- udp->ud_mname, um->um_ctlr, ui->ui_slave);
- (*udp->ud_attach)(ui);
- printf("\n");
- }
- }
- break;
- }
- }
+ printf("uba%d: unexpected interrupt, vector 0x%x, br 0x%x\n",
+ arg, svec, rbr);
}
-
-#ifdef DW780
-char ubasr_bits[] = UBASR_BITS;
-#endif
-
-#define spluba splbio /* IPL 17 */
-
/*
* Do transfer on device argument. The controller
* and uba involved are implied by the device.
@@ -253,7 +531,7 @@ char ubasr_bits[] = UBASR_BITS;
* We return 1 if the transfer was started, 0 if it was not.
*
* The onq argument must be zero iff the device is not on the
- * queue for this UBA. If onq is set, the device must be at the
+ * queue for this UBA. If onq is set, the device must be at the
* head of the queue. In any case, if the transfer is started,
* the device will be off the queue, and if not, it will be on.
*
@@ -263,82 +541,64 @@ char ubasr_bits[] = UBASR_BITS;
* does not now have a BDP.
*/
int
-ubaqueue(ui, onq)
- register struct uba_device *ui;
- int onq;
+ubaqueue(uu, bp)
+ register struct uba_unit *uu;
+ struct buf *bp;
{
- register struct uba_ctlr *um = ui->ui_mi;
register struct uba_softc *uh;
- register struct uba_driver *ud;
- register int s, unit;
+ register int s;
- uh = uba_cd.cd_devs[um->um_ubanum];
- ud = um->um_driver;
+ uh = (void *)((struct device *)(uu->uu_softc))->dv_parent;
s = spluba();
/*
* Honor exclusive BDP use requests.
*/
- if ((ud->ud_xclu && uh->uh_users > 0) || uh->uh_xclu)
+ if ((uu->uu_xclu && uh->uh_users > 0) || uh->uh_xclu)
goto rwait;
- if (ud->ud_keepbdp) {
+ if (uu->uu_keepbdp) {
/*
* First get just a BDP (though in fact it comes with
* one map register too).
*/
- if (um->um_bdp == 0) {
- um->um_bdp = uballoc(um->um_ubanum,
- (caddr_t)0, 0, UBA_NEEDBDP|UBA_CANTWAIT);
- if (um->um_bdp == 0)
+ if (uu->uu_bdp == 0) {
+ uu->uu_bdp = uballoc(uh, (caddr_t)0, 0,
+ UBA_NEEDBDP|UBA_CANTWAIT);
+ if (uu->uu_bdp == 0)
goto rwait;
}
/* now share it with this transfer */
- um->um_ubinfo = ubasetup(um->um_ubanum,
- um->um_tab.b_actf->b_actf,
- um->um_bdp|UBA_HAVEBDP|UBA_CANTWAIT);
+ uu->uu_ubinfo = ubasetup(uh, bp,
+ uu->uu_bdp|UBA_HAVEBDP|UBA_CANTWAIT);
} else
- um->um_ubinfo = ubasetup(um->um_ubanum,
- um->um_tab.b_actf->b_actf, UBA_NEEDBDP|UBA_CANTWAIT);
- if (um->um_ubinfo == 0)
+ uu->uu_ubinfo = ubasetup(uh, bp, UBA_NEEDBDP|UBA_CANTWAIT);
+ if (uu->uu_ubinfo == 0)
goto rwait;
uh->uh_users++;
- if (ud->ud_xclu)
+ if (uu->uu_xclu)
uh->uh_xclu = 1;
+
splx(s);
- if (ui->ui_dk >= 0) {
- unit = ui->ui_dk;
- dk_busy |= 1<<unit;
- dk_xfer[unit]++;
- dk_wds[unit] += um->um_tab.b_actf->b_actf->b_bcount>>6;
- }
- if (onq)
- uh->uh_actf = ui->ui_forw;
- (*ud->ud_dgo)(um);
return (1);
+
rwait:
- if (!onq) {
- ui->ui_forw = NULL;
- if (uh->uh_actf == NULL)
- uh->uh_actf = ui;
- else
- uh->uh_actl->ui_forw = ui;
- uh->uh_actl = ui;
- }
+ SIMPLEQ_INSERT_TAIL(&uh->uh_resq, uu, uu_resq);
splx(s);
return (0);
}
void
-ubadone(um)
- struct uba_ctlr *um;
+ubadone(uu)
+ struct uba_unit *uu;
{
- struct uba_softc *uh = uba_cd.cd_devs[um->um_ubanum];
+ struct uba_softc *uh = (void *)((struct device *)
+ (uu->uu_softc))->dv_parent;
- if (um->um_driver->ud_xclu)
+ if (uu->uu_xclu)
uh->uh_xclu = 0;
uh->uh_users--;
- if (um->um_driver->ud_keepbdp)
- um->um_ubinfo &= ~BDPMASK; /* keep BDP for misers */
- ubarelse(um->um_ubanum, &um->um_ubinfo);
+ if (uu->uu_keepbdp)
+ uu->uu_ubinfo &= ~BDPMASK; /* keep BDP for misers */
+ ubarelse(uh, &uu->uu_ubinfo);
}
/*
@@ -349,27 +609,19 @@ ubadone(um)
* bdp number and number of map registers.
*/
int
-ubasetup(uban, bp, flags)
+ubasetup(uh, bp, flags)
+ struct uba_softc *uh;
struct buf *bp;
- int uban, flags;
+ int flags;
{
- struct uba_softc *uh = uba_cd.cd_devs[uban];
- struct pte *pte, *io;
int npf;
- int pfnum, temp;
+ int temp;
int reg, bdp;
- unsigned v;
- struct proc *rp;
int a, o, ubinfo;
-#ifdef DW730
- if (uh->uh_type == DW730)
- flags &= ~UBA_NEEDBDP;
-#endif
-#ifdef QBA
- if (uh->uh_type == QBA)
+ if (uh->uh_nbdp == 0)
flags &= ~UBA_NEEDBDP;
-#endif
+
o = (int)bp->b_un.b_addr & PGOFSET;
npf = btoc(bp->b_bcount + o) + 1;
if (npf > UBA_MAXNMR)
@@ -412,47 +664,9 @@ ubasetup(uban, bp, flags)
temp = (bdp << 21) | UBAMR_MRV;
if (bdp && (o & 01))
temp |= UBAMR_BO;
- if ((bp->b_flags & B_PHYS) == 0)
- pte = (struct pte *)kvtopte(bp->b_un.b_addr);
- else {
- struct pte *hej;
- int i;
- rp = bp->b_proc;
- v = btop((u_int)bp->b_un.b_addr&0x3fffffff);
+ disk_reallymapin(bp, uh->uh_mr, reg, temp | PG_V);
- /*
- * It may be better to use pmap_extract() here
- * somewhere, but so far we do it "the hard way" :)
- */
- if (((u_int)bp->b_un.b_addr < 0x40000000) ||
- ((u_int)bp->b_un.b_addr > 0x7fffffff))
- hej = rp->p_vmspace->vm_pmap.pm_pcb->P0BR;
- else
- hej = rp->p_vmspace->vm_pmap.pm_pcb->P1BR;
-
- pte = &hej[v];
- for (i = 0; i < (npf - 1); i++) {
- if ((pte + i)->pg_pfn == 0) {
- int rv;
-
- rv = vm_fault(&rp->p_vmspace->vm_map,
- (u_int)bp->b_un.b_addr + i * NBPG,
- VM_PROT_READ, FALSE);
- if (rv)
- panic("DMA to nonexistent page");
- }
- }
- }
- io = &uh->uh_mr[reg];
- while (--npf > 0) {
- pfnum = pte->pg_pfn;
- if (pfnum == 0)
- panic("uba zero uentry");
- pte++;
- *(int *)io++ = pfnum | temp;
- }
- *(int *)io = 0;
return (ubinfo);
}
@@ -460,9 +674,10 @@ ubasetup(uban, bp, flags)
* Non buffer setup interface... set up a buffer and call ubasetup.
*/
int
-uballoc(uban, addr, bcnt, flags)
+uballoc(uh, addr, bcnt, flags)
+ struct uba_softc *uh;
caddr_t addr;
- int uban, bcnt, flags;
+ int bcnt, flags;
{
struct buf ubabuf;
@@ -470,7 +685,7 @@ uballoc(uban, addr, bcnt, flags)
ubabuf.b_flags = B_BUSY;
ubabuf.b_bcount = bcnt;
/* that's all the fields ubasetup() needs */
- return (ubasetup(uban, &ubabuf, flags));
+ return (ubasetup(uh, &ubabuf, flags));
}
/*
@@ -479,10 +694,11 @@ uballoc(uban, addr, bcnt, flags)
* against uba resets on 11/780's.
*/
void
-ubarelse(uban, amr)
- int uban, *amr;
+ubarelse(uh, amr)
+ struct uba_softc *uh;
+ int *amr;
{
- register struct uba_softc *uh = uba_cd.cd_devs[uban];
+ struct uba_unit *uu;
register int bdp, reg, npf, s;
int mr;
@@ -503,26 +719,9 @@ ubarelse(uban, amr)
*amr = 0;
bdp = UBAI_BDP(mr);
if (bdp) {
- switch (uh->uh_type) {
-#ifdef DWBUA
- case DWBUA:
- BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE;
- break;
-#endif
-#ifdef DW780
- case DW780:
- uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE;
- break;
-#endif
-#ifdef DW750
- case DW750:
- uh->uh_uba->uba_dpr[bdp] |=
- UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE;
- break;
-#endif
- default:
- break;
- }
+ if (uh->uh_ubapurge)
+ (*uh->uh_ubapurge)(uh, bdp);
+
uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */
if (uh->uh_bdpwant) {
uh->uh_bdpwant = 0;
@@ -549,35 +748,10 @@ ubarelse(uban, amr)
uh->uh_mrwant = 0;
wakeup((caddr_t)&uh->uh_mrwant);
}
- while (uh->uh_actf && ubaqueue(uh->uh_actf, 1))
- ;
-}
-
-void
-ubapurge(um)
- register struct uba_ctlr *um;
-{
- register struct uba_softc *uh = um->um_hd;
- register int bdp = UBAI_BDP(um->um_ubinfo);
-
- switch (uh->uh_type) {
-#ifdef DWBUA
- case DWBUA:
- BUA(uh->uh_uba)->bua_dpr[bdp] |= BUADPR_PURGE;
- break;
-#endif
-#ifdef DW780
- case DW780:
- uh->uh_uba->uba_dpr[bdp] |= UBADPR_BNE;
- break;
-#endif
-#ifdef DW750
- case DW750:
- uh->uh_uba->uba_dpr[bdp] |= UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE;
- break;
-#endif
- default:
- break;
+ while ((uu = uh->uh_resq.sqh_first)) {
+ SIMPLEQ_REMOVE_HEAD(&uh->uh_resq, uu, uu_resq);
+ if ((*uu->uu_ready)(uu) == 0)
+ break;
}
}
@@ -589,29 +763,11 @@ ubainitmaps(uhp)
if (uhp->uh_memsize > UBA_MAXMR)
uhp->uh_memsize = UBA_MAXMR;
rminit(uhp->uh_map, (long)uhp->uh_memsize, (long)1, "uba", UAMSIZ);
- switch (uhp->uh_type) {
-#ifdef DWBUA
- case DWBUA:
- uhp->uh_bdpfree = (1<<NBDPBUA) - 1;
- break;
-#endif
-#ifdef DW780
- case DW780:
- uhp->uh_bdpfree = (1<<NBDP780) - 1;
- break;
-#endif
-#ifdef DW750
- case DW750:
- uhp->uh_bdpfree = (1<<NBDP750) - 1;
- break;
-#endif
- default:
- break;
- }
+ uhp->uh_bdpfree = (1 << uhp->uh_nbdp) - 1;
}
/*
- * Generate a reset on uba number uban. Then
+ * Generate a reset on uba number uban. Then
* call each device that asked to be called during attach,
* giving it a chance to clean up so as to be able to continue.
*/
@@ -626,82 +782,25 @@ ubareset(uban)
uh->uh_users = 0;
uh->uh_zvcnt = 0;
uh->uh_xclu = 0;
- uh->uh_actf = uh->uh_actl = 0;
+ SIMPLEQ_INIT(&uh->uh_resq);
uh->uh_bdpwant = 0;
uh->uh_mrwant = 0;
ubainitmaps(uh);
wakeup((caddr_t)&uh->uh_bdpwant);
wakeup((caddr_t)&uh->uh_mrwant);
printf("%s: reset", uh->uh_dev.dv_xname);
- ubainit(uh);
-#ifdef notyet
- ubameminit(uban);
-#endif
+ (*uh->uh_ubainit)(uh);
+
for (i = 0; i < uh->uh_resno; i++)
(*uh->uh_reset[i])(uh->uh_resarg[i]);
printf("\n");
splx(s);
}
-/*
- * Init a uba.
- */
-void
-ubainit(uhp)
- struct uba_softc *uhp;
-{
- volatile struct uba_regs *ur = uhp->uh_uba;
-
- switch (uhp->uh_type) {
-#ifdef DWBUA
- case DWBUA:
- BUA(uba)->bua_csr |= BUACSR_UPI;
- /* give devices time to recover from power fail */
- DELAY(500000);
- break;
-#endif
-#if DW780
- case DW780:
- ur->uba_cr = UBACR_ADINIT;
- ur->uba_cr = UBACR_IFS|UBACR_BRIE|UBACR_USEFIE|UBACR_SUEFIE;
- while ((ur->uba_cnfgr & UBACNFGR_UBIC) == 0)
- ;
- break;
-#endif
-#ifdef DW750
- case DW750:
-#endif
-#ifdef DW730
- case DW730:
-#endif
-#ifdef QBA
- case QBA:
-#endif
-#if DW750 || DW730 || QBA
- mtpr(0, PR_IUR);
- /* give devices time to recover from power fail */
-
-/* THIS IS PROBABLY UNNECESSARY */
- DELAY(500000);
-/* END PROBABLY UNNECESSARY */
-
-#ifdef QBA
- /*
- * Re-enable local memory access
- * from the Q-bus.
- */
- if (uhp->uh_type == QBA)
- *((u_short *)(uhp->uh_iopage + QIPCR)) = Q_LMEAE;
-#endif QBA
- break;
-#endif DW750 || DW730 || QBA
- }
-}
-
-#ifdef QBA
+#ifdef notyet
/*
* Determine the interrupt priority of a Q-bus
- * peripheral. The device probe routine must spl6(),
+ * peripheral. The device probe routine must spl6(),
* attempt to make the device request an interrupt,
* delaying as necessary, then call this routine
* before resetting the device.
@@ -709,329 +808,45 @@ ubainit(uhp)
int
qbgetpri()
{
-#ifdef notyet
int pri;
- extern int cvec;
- panic("qbgetpri");
for (pri = 0x17; pri > 0x14; ) {
- if (cvec && cvec != 0x200) /* interrupted at pri */
+ if (rcvec && rcvec != 0x200) /* interrupted at pri */
break;
pri--;
splx(pri - 1);
}
- (void) spl0();
+ spl0();
return (pri);
-#else
- return 0x17;
-#endif
-}
-#endif
-
-#ifdef DW780
-int ubawedgecnt = 10;
-int ubacrazy = 500;
-int zvcnt_max = 5000; /* in 8 sec */
-/*
- * This routine is called by the locore code to process a UBA
- * error on an 11/780 or 8600. The arguments are passed
- * on the stack, and value-result (through some trickery).
- * In particular, the uvec argument is used for further
- * uba processing so the result aspect of it is very important.
- * It must not be declared register.
- */
-/*ARGSUSED*/
-void
-ubaerror(uban, uh, ipl, uvec, uba)
- register int uban;
- register struct uba_softc *uh;
- int *ipl, *uvec;
- register struct uba_regs *uba;
-{
- register sr, s;
-
- if (*uvec == 0) {
- /*
- * Declare dt as unsigned so that negative values
- * are handled as >8 below, in case time was set back.
- */
- u_long dt = time.tv_sec - uh->uh_zvtime;
-
- uh->uh_zvtotal++;
- if (dt > 8) {
- uh->uh_zvtime = time.tv_sec;
- uh->uh_zvcnt = 0;
- }
- if (++uh->uh_zvcnt > zvcnt_max) {
- printf("uba%d: too many zero vectors (%d in <%d sec)\n",
- uban, uh->uh_zvcnt, (int)dt + 1);
- printf("\tIPL 0x%x\n\tcnfgr: %b Adapter Code: 0x%x\n",
- *ipl, uba->uba_cnfgr&(~0xff), UBACNFGR_BITS,
- uba->uba_cnfgr&0xff);
- printf("\tsr: %b\n\tdcr: %x (MIC %sOK)\n",
- uba->uba_sr, ubasr_bits, uba->uba_dcr,
- (uba->uba_dcr&0x8000000)?"":"NOT ");
- ubareset(uban);
- }
- return;
- }
- if (uba->uba_cnfgr & NEX_CFGFLT) {
- printf("uba%d: sbi fault sr=%b cnfgr=%b\n",
- uban, uba->uba_sr, ubasr_bits,
- uba->uba_cnfgr, NEXFLT_BITS);
- ubareset(uban);
- *uvec = 0;
- return;
- }
- sr = uba->uba_sr;
- s = spluba();
- printf("uba%d: uba error sr=%b fmer=%x fubar=%o\n",
- uban, uba->uba_sr, ubasr_bits, uba->uba_fmer, 4*uba->uba_fubar);
- splx(s);
- uba->uba_sr = sr;
- *uvec &= UBABRRVR_DIV;
- if (++uh->uh_errcnt % ubawedgecnt == 0) {
- if (uh->uh_errcnt > ubacrazy)
- panic("uba crazy");
- printf("ERROR LIMIT ");
- ubareset(uban);
- *uvec = 0;
- return;
- }
- return;
}
#endif
/*
- * Look for devices with unibus memory, allow them to configure, then disable
- * map registers as necessary. Called during autoconfiguration and ubareset.
- * The device ubamem routine returns 0 on success, 1 on success if it is fully
- * configured (has no csr or interrupt, so doesn't need to be probed),
- * and -1 on failure.
- */
-#ifdef notyet
-ubameminit(uban)
-{
- register struct uba_device *ui;
- register struct uba_softc *uh = uba_cd.cd_devs[uban];
- caddr_t umembase, addr;
-#define ubaoff(off) ((int)(off) & 0x1fff)
-
- umembase = uh->uh_iopage;
- uh->uh_lastmem = 0;
- for (ui = ubdinit; ui->ui_driver; ui++) {
- if (ui->ui_ubanum != uban && ui->ui_ubanum != '?')
- continue;
- if (ui->ui_driver->ud_ubamem) {
- /*
- * During autoconfiguration, need to fudge ui_addr.
- */
- addr = ui->ui_addr;
- ui->ui_addr = umembase + ubaoff(addr);
- switch ((*ui->ui_driver->ud_ubamem)(ui, uban)) {
- case 1:
- ui->ui_alive = 1;
- /* FALLTHROUGH */
- case 0:
- ui->ui_ubanum = uban;
- break;
- }
- ui->ui_addr = addr;
- }
- }
-#ifdef DW780
-jdhfgsjdkfhgsdjkfghak
- /*
- * On a DW780, throw away any map registers disabled by rounding
- * the map disable in the configuration register
- * up to the next 8K boundary, or below the last unibus memory.
- */
- if (uh->uh_type == DW780) {
- register i;
-
- i = btop(((uh->uh_lastmem + 8191) / 8192) * 8192);
- while (i)
- (void) rmget(uh->uh_map, 1, i--);
- }
-#endif
-}
-#endif
-
-/*
- * Allocate UNIBUS memory. Allocates and initializes
- * sufficient mapping registers for access. On a 780,
- * the configuration register is setup to disable UBA
- * response on DMA transfers to addresses controlled
- * by the disabled mapping registers.
- * On a DW780, should only be called from ubameminit, or in ascending order
- * from 0 with 8K-sized and -aligned addresses; freeing memory that isn't
- * the last unibus memory would free unusable map registers.
- * Doalloc is 1 to allocate, 0 to deallocate.
- */
-int
-ubamem(uban, addr, npg, doalloc)
- int uban, addr, npg, doalloc;
-{
- register struct uba_softc *uh = uba_cd.cd_devs[uban];
- register int a;
- int s;
-
- a = (addr >> 9) + 1;
- s = spluba();
- if (doalloc)
- panic("uba: rmget");
-/* a = rmget(uh->uh_map, npg, a); */
- else
- rmfree(uh->uh_map, (long)npg, (long)a);
- splx(s);
- if (a) {
- register int i, *m;
-
- m = (int *)&uh->uh_mr[a - 1];
- for (i = 0; i < npg; i++)
- *m++ = 0; /* All off, especially 'valid' */
- i = addr + npg * 512;
- if (doalloc && i > uh->uh_lastmem)
- uh->uh_lastmem = i;
- else if (doalloc == 0 && i == uh->uh_lastmem)
- uh->uh_lastmem = addr;
-#ifdef DW780
- /*
- * On a 780, set up the map register disable
- * field in the configuration register. Beware
- * of callers that request memory ``out of order''
- * or in sections other than 8K multiples.
- * Ubameminit handles such requests properly, however.
- */
- if (uh->uh_type == DW780) {
- i = uh->uh_uba->uba_cr &~ 0x7c000000;
- i |= ((uh->uh_lastmem + 8191) / 8192) << 26;
- uh->uh_uba->uba_cr = i;
- }
-#endif
- }
- return (a);
-}
-
-#include "ik.h"
-#include "vs.h"
-#if NIK > 0 || NVS > 0
-/*
- * Map a virtual address into users address space. Actually all we
- * do is turn on the user mode write protection bits for the particular
- * page of memory involved.
- */
-maptouser(vaddress)
- caddr_t vaddress;
-{
-
- kvtopte(vaddress)->pg_prot = (PG_UW >> 27);
-}
-
-unmaptouser(vaddress)
- caddr_t vaddress;
-{
-
- kvtopte(vaddress)->pg_prot = (PG_KW >> 27);
-}
-#endif
-
-#ifdef DW780
-void
-uba_dw780int(uba)
- int uba;
-{
- int br, svec, vec, arg;
- struct uba_softc *sc = uba_cd.cd_devs[uba];
- struct uba_regs *ur = sc->uh_uba;
- void (*func) __P((int));
-
- br = mfpr(PR_IPL);
- svec = ur->uba_brrvr[br - 0x14];
- if (svec < 0) {
- ubaerror(uba, sc, &br, &svec, ur);
- if (svec == 0)
- return;
- }
- vec = svec >> 2;
- if (cold)
- rcvec = vec;
- func = sc->uh_idsp[vec].hoppaddr;
- arg = sc->uh_idsp[vec].pushlarg;
- (*func)(arg);
-}
-#endif
-
-/*
- * The match routine checks which UBA adapter number it is, to
- * be sure to use correct interrupt vectors.
- */
-int
-uba_match(parent, vcf, aux)
- struct device *parent;
- void *vcf, *aux;
-{
- struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
- struct cfdata *cf = vcf;
-
- if ((cf->cf_loc[0] != sa->nexnum) && (cf->cf_loc[0] > -1 ))
- return 0;
-
- switch (sa->type) {
- case NEX_UBA0:
- sa->nexinfo = 0;
- break;
- case NEX_UBA1:
- sa->nexinfo = 1;
- break;
- case NEX_UBA2:
- sa->nexinfo = 2;
- break;
- case NEX_UBA3:
- sa->nexinfo = 3;
- break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-/*
- * The attach routines:
+ * The common attach routines:
* Allocates interrupt vectors.
- * Puts correct (cpu-specific) addresses in uba_softc.
+ * Puts correct values in uba_softc.
* Calls the scan routine to search for uba devices.
*/
void
-uba_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
+uba_attach(sc, iopagephys)
+ struct uba_softc *sc;
+ unsigned long iopagephys;
{
- struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
- struct uba_regs *ubar = (struct uba_regs *)sa->nexaddr;
- struct uba_softc *sc = (struct uba_softc *)self;
- vm_offset_t min, max, ubaphys, ubaiophys;
+ vm_offset_t mini, maxi;
extern struct ivec_dsp idsptch;
- printf("\n");
/*
- * Allocate place for unibus memory in virtual space.
- * This is done with kmem_suballoc() but after that
- * never used in the vm system. Is it OK to do so?
+ * Set last free interrupt vector for devices with
+ * programmable interrupt vectors. Use is to decrement
+ * this number and use result as interrupt vector.
*/
- (void)kmem_suballoc(kernel_map, &min, &max,
- (UBAPAGES + UBAIOPAGES) * NBPG, FALSE);
- sc->uh_mem = (caddr_t)min;
- sc->uh_uba = (void*)ubar;
- sc->uh_memsize = UBAPAGES;
- sc->uh_iopage = (void *)min + (sc->uh_memsize * NBPG);
- sc->uh_iarea = (void *)scb + NBPG + sa->nexinfo * NBPG;
- sc->uh_resno = 0;
+ sc->uh_lastiv = 0x200;
+ SIMPLEQ_INIT(&sc->uh_resq);
+
/*
* Create interrupt dispatchers for this uba.
*/
-#define NO_IVEC 128
+#define NO_IVEC 128
{
vm_offset_t iarea;
int i;
@@ -1048,81 +863,15 @@ uba_attach(parent, self, aux)
sc->uh_iarea[i] = (unsigned int)&sc->uh_idsp[i];
}
}
-
- switch (cpunumber) {
-#if VAX780 || VAX8600
- case VAX_780:
- case VAX_8600:
- sc->uh_mr = (void *)ubar->uba_map;
- sc->uh_type = DW780;
- sc->uh_physuba = (struct uba_regs *)kvtophys(sa->nexaddr);
- if (parent->dv_unit == 0) {
- ubaphys = UMEMA8600(sa->nexinfo);
- ubaiophys = UMEMA8600(sa->nexinfo) + (UBAPAGES * NBPG);
- } else {
- ubaphys = UMEMB8600(sa->nexinfo);
- ubaiophys = UMEMB8600(sa->nexinfo) + (UBAPAGES * NBPG);
- }
- bcopy(&idsptch, &sc->uh_dw780, sizeof(struct ivec_dsp));
- sc->uh_dw780.pushlarg = sc->uh_dev.dv_unit;
- sc->uh_dw780.hoppaddr = uba_dw780int;
- scb->scb_nexvec[0][sa->nexnum] = scb->scb_nexvec[1][sa->nexnum]
- = scb->scb_nexvec[2][sa->nexnum]
- = scb->scb_nexvec[3][sa->nexnum] = &sc->uh_dw780;
- break;
-#endif
-#if VAX750
- case VAX_750:
- sc->uh_mr = (void *)ubar->uba_map;
- sc->uh_type = DW750;
- sc->uh_physuba = (struct uba_regs *)kvtophys(sa->nexaddr);
- ubaphys = UMEM750(sa->nexinfo);
- ubaiophys = UMEM750(sa->nexinfo) + (UBAPAGES * NBPG);
- break;
-#endif
-#if VAX630 || VAX410
- case VAX_78032:
- switch (cpu_type) {
-#if VAX630
- case VAX_630:
- sc->uh_mr = (void *)sa->nexaddr;
- sc->uh_type = QBA;
- sc->uh_physuba = (void*)QBAMAP630;
- ubaphys = QMEM630;
- ubaiophys = QIOPAGE630;
- break;
-#endif
- default:
- ubaphys = QMEM630;
- ubaiophys = QIOPAGE630;
- };
- break;
-#endif
-#if VAX650
- case VAX_650:
- sc->uh_mr = (void *)sa->nexaddr;
- sc->uh_type = QBA;
- sc->uh_physuba = (void*)QBAMAP630; /* XXX */
- ubaphys = QMEM630; /* XXX */
- ubaiophys = QIOPAGE630; /* XXX */
- break;
-#endif
- default:
- printf("Bad luck, this cputype does not support UBA's\n");
- return;
- };
/*
- * Map uba space in kernel virtual; especially i/o space.
+ * Allocate place for unibus memory in virtual space.
+ * This is done with kmem_suballoc() but after that
+ * never used in the vm system. Is it OK to do so?
*/
- pmap_map(min, ubaphys, ubaphys + (UBAPAGES * NBPG),
+ (void)kmem_suballoc(kernel_map, &mini, &maxi, UBAIOPAGES * NBPG, FALSE);
+ pmap_map(mini, iopagephys, iopagephys + UBAIOPAGES * NBPG,
VM_PROT_READ|VM_PROT_WRITE);
- pmap_map(min + (UBAPAGES * NBPG), ubaiophys, ubaiophys +
- (UBAIOPAGES * NBPG), VM_PROT_READ|VM_PROT_WRITE);
-#if VAX630 || VAX650
- /* Enable access to local memory. */
- if (cpu_type == VAX_630 || cpunumber == VAX_650)
- *((u_short *)(sc->uh_iopage + QIPCR)) = Q_LMEAE;
-#endif
+ sc->uh_iopage = (void *)mini;
/*
* Initialize the UNIBUS, by freeing the map
* registers and the buffered data path registers
@@ -1133,50 +882,20 @@ uba_attach(parent, self, aux)
ubainitmaps(sc);
/*
- * Set last free interrupt vector for devices with
- * programmable interrupt vectors. Use is to decrement
- * this number and use result as interrupt vector.
- */
- sc->uh_lastiv = 0x200;
-
-#ifdef DWBUA
- if (sc->uh_type == DWBUA)
- BUA(ubar)->bua_offset = (int)sc->uh_vec - (int)&scb[0];
-#endif
-
-#ifdef DW780
- if (sc->uh_type == DW780) {
- ubar->uba_sr = ubar->uba_sr;
- ubar->uba_cr = UBACR_IFS|UBACR_BRIE;
- }
-#endif
-#ifdef notyet
- /*
- * First configure devices that have unibus memory,
- * allowing them to allocate the correct map registers.
- */
- ubameminit(uhp->uh_dev.dv_unit);
-#endif
- /*
* Map the first page of UNIBUS i/o space to the first page of memory
- * for devices which will need to dma output to produce an interrupt.
- * ??? - Why? This is rpb page... /ragge
+ * for devices which will need to dma to produce an interrupt.
*/
*(int *)(&sc->uh_mr[0]) = UBAMR_MRV;
+ if (sc->uh_beforescan)
+ (*sc->uh_beforescan)(sc);
/*
* Now start searching for devices.
*/
- unifind(sc, (caddr_t)ubaiophys);/* Some devices are not yet converted */
- config_scan(ubascan,self);
-
-#ifdef DW780
- if (sc->uh_type == DW780)
- ubar->uba_cr = UBACR_IFS | UBACR_BRIE |
- UBACR_USEFIE | UBACR_SUEFIE |
- (ubar->uba_cr & 0x7c000000);
-#endif
+ config_scan(ubascan,(struct device *)sc);
+ if (sc->uh_afterscan)
+ (*sc->uh_afterscan)(sc);
}
void
@@ -1187,31 +906,21 @@ ubascan(parent, match)
struct device *dev = match;
struct cfdata *cf = dev->dv_cfdata;
struct uba_softc *sc = (struct uba_softc *)parent;
- volatile struct uba_regs *ubar = sc->uh_uba;
struct uba_attach_args ua;
int i;
- ua.ua_addr = (caddr_t)ubaddr(sc, cf->cf_loc[0]);
+ ua.ua_addr = (caddr_t)((int)sc->uh_iopage + ubdevreg(cf->cf_loc[0]));
ua.ua_reset = NULL;
- if (badaddr(ua.ua_addr, 2))
+ if (badaddr(ua.ua_addr, 2) || (sc->uh_errchk ? (*sc->uh_errchk)(sc):0))
goto forgetit;
-#ifdef DW780
- if (sc->uh_type == DW780 && ubar->uba_sr) {
- ubar->uba_sr = ubar->uba_sr;
- goto forgetit;
- }
-#endif
rcvec = 0x200;
i = (*cf->cf_attach->ca_match) (parent, dev, &ua);
-#ifdef DW780
- if (sc->uh_type == DW780 && ubar->uba_sr) {
- ubar->uba_sr = ubar->uba_sr;
- goto forgetit;
- }
-#endif
+ if (sc->uh_errchk)
+ if ((*sc->uh_errchk)(sc))
+ goto forgetit;
if (i == 0)
goto forgetit;
@@ -1220,13 +929,21 @@ ubascan(parent, match)
sc->uh_idsp[rcvec].hoppaddr = ua.ua_ivec;
sc->uh_idsp[rcvec].pushlarg = dev->dv_unit;
- if (ua.ua_reset) { /* device wants ubaeset */
+ if (ua.ua_reset) { /* device wants ubraeset */
if (sc->uh_resno == 0) {
sc->uh_reset = malloc(1024, M_DEVBUF, M_NOWAIT);
- sc->uh_resarg = malloc(256, M_DEVBUF, M_NOWAIT);
+ sc->uh_resarg = (int *)sc->uh_reset + 128;
+ }
+#ifdef DIAGNOSTIC
+ if (sc->uh_resno > 127) {
+ printf("%s: Expand reset table, skipping reset %s\n",
+ sc->uh_dev.dv_xname, dev->dv_xname);
+ } else
+#endif
+ {
+ sc->uh_resarg[sc->uh_resno] = dev->dv_unit;
+ sc->uh_reset[sc->uh_resno++] = ua.ua_reset;
}
- sc->uh_resarg[sc->uh_resno] = dev->dv_unit;
- sc->uh_reset[sc->uh_resno++] = ua.ua_reset;
}
ua.ua_br = rbr;
ua.ua_cvec = rcvec;
diff --git a/sys/arch/vax/uba/ubareg.h b/sys/arch/vax/uba/ubareg.h
index d63093e5613..823ae525d7f 100644
--- a/sys/arch/vax/uba/ubareg.h
+++ b/sys/arch/vax/uba/ubareg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ubareg.h,v 1.7 1996/04/08 18:37:35 ragge Exp $ */
+/* $NetBSD: ubareg.h,v 1.9 1996/08/20 13:38:02 ragge Exp $ */
/*-
* Copyright (c) 1982, 1986 The Regents of the University of California.
@@ -52,26 +52,26 @@
*/
#if VAX780 || VAX8600
-#define DW780 1 /* has adaptor regs, sr: 780/785/8600 */
+#define DW780 1 /* has adaptor regs, sr: 780/785/8600 */
#else
#undef DW780
#endif
#if VAX750
-#define DW750 2 /* has adaptor regs, no sr: 750, 730 */
+#define DW750 2 /* has adaptor regs, no sr: 750, 730 */
#endif
#if VAX730
-#define DW730 3 /* has adaptor regs, no sr: 750, 730 */
+#define DW730 3 /* has adaptor regs, no sr: 750, 730 */
#endif
#if VAX630 || VAX650
-#define QBA 4 /* 22-bit Q-bus, no adaptor regs: uVAX II */
+#define QBA 4 /* 22-bit Q-bus, no adaptor regs: uVAX II */
#endif
-#if VAX8200 || VAX8500 || VAX8800
-#define DWBUA 5 /* BI UNIBUS adaptor: 8200/8500/8800 */
+#if 0 /* XXX VAX8200 || VAX8500 || VAX8800 */
+#define DWBUA 5 /* BI UNIBUS adaptor: 8200/8500/8800 */
#endif
/*
@@ -80,20 +80,16 @@
* QBAPAGES should be 8192, but we don't need nearly that much
* address space, and the return from the allocation routine
* can accommodate at most 2047 (ubavar.h: UBA_MAXMR);
- * QBAPAGES must be at least UBAPAGES. Choose pragmatically.
+ * QBAPAGES must be at least UBAPAGES. Choose pragmatically.
*
* Is there ever any need to have QBAPAGES != UBAPAGES???
* Wont work now anyway, QBAPAGES _must_ be .eq. UBAPAGES.
*/
-#define UBAPAGES 496
-#define NUBMREG 496
-/* #if defined(GATEWAY) && !defined(QNIVERT) */
-/* #define QBAPAGES 1024 */
-/* #else */
-#define QBAPAGES UBAPAGES
-/* #endif */
-#define UBAIOADDR 0760000 /* start of I/O page */
-#define UBAIOPAGES 16
+#define UBAPAGES 496
+#define NUBMREG 496
+#define QBAPAGES 1024
+#define UBAIOADDR 0760000 /* start of I/O page */
+#define UBAIOPAGES 16
#ifndef _LOCORE
/*
@@ -112,39 +108,39 @@ struct dwbua_regs {
int pad3[10];
int bua_bdps[20]; /* buffered data path space *//*???*/
int pad4[8];
- pt_entry_t bua_map[UBAPAGES]; /* unibus map registers */
+ struct pte bua_map[UBAPAGES]; /* unibus map registers */
int pad5[UBAIOPAGES]; /* no maps for device address space */
};
#ifdef DWBUA
/* bua_csr */
-#define BUACSR_ERR 0x80000000 /* composite error */
-#define BUACSR_BIF 0x10000000 /* BI failure */
-#define BUACSR_SSYNTO 0x08000000 /* slave sync timeout */
-#define BUACSR_UIE 0x04000000 /* unibus interlock error */
-#define BUACSR_IVMR 0x02000000 /* invalid map register */
-#define BUACSR_BADBDP 0x01000000 /* bad BDP select */
-#define BUACSR_BUAEIE 0x00100000 /* bua error interrupt enable (?) */
-#define BUACSR_UPI 0x00020000 /* unibus power init */
-#define BUACSR_UREGDUMP 0x00010000 /* microdiag register dump */
-#define BUACSR_IERRNO 0x000000ff /* mask for internal errror number */
+#define BUACSR_ERR 0x80000000 /* composite error */
+#define BUACSR_BIF 0x10000000 /* BI failure */
+#define BUACSR_SSYNTO 0x08000000 /* slave sync timeout */
+#define BUACSR_UIE 0x04000000 /* unibus interlock error */
+#define BUACSR_IVMR 0x02000000 /* invalid map register */
+#define BUACSR_BADBDP 0x01000000 /* bad BDP select */
+#define BUACSR_BUAEIE 0x00100000 /* bua error interrupt enable (?) */
+#define BUACSR_UPI 0x00020000 /* unibus power init */
+#define BUACSR_UREGDUMP 0x00010000 /* microdiag register dump */
+#define BUACSR_IERRNO 0x000000ff /* mask for internal errror number */
/* bua_offset */
-#define BUAOFFSET_MASK 0x00003e00 /* hence max offset = 15872 */
+#define BUAOFFSET_MASK 0x00003e00 /* hence max offset = 15872 */
/* bua_dpr */
-#define BUADPR_DPSEL 0x00e00000 /* data path select (?) */
-#define BUADPR_PURGE 0x00000001 /* purge bdp */
+#define BUADPR_DPSEL 0x00e00000 /* data path select (?) */
+#define BUADPR_PURGE 0x00000001 /* purge bdp */
/* bua_map -- in particular, those bits that are not in DW780s & DW750s */
-#define BUAMR_IOADR 0x40000000 /* I/O address space */
-#define BUAMR_LAE 0x04000000 /* longword access enable */
+#define BUAMR_IOADR 0x40000000 /* I/O address space */
+#define BUAMR_LAE 0x04000000 /* longword access enable */
/* I see no reason to use either one, though ... act 6 Aug 1987 */
-#define UBA_PURGEBUA(uba, bdp) \
+#define UBA_PURGEBUA(uba, bdp) \
(((struct dwbua_regs *)(uba))->bua_dpr[bdp] |= BUADPR_PURGE)
#else
-#define UBA_PURGEBUA(uba, bdp)
+#define UBA_PURGEBUA(uba, bdp)
#endif
/*
@@ -162,164 +158,131 @@ struct uba_regs {
int uba_brrvr[4]; /* receive vector registers */
int uba_dpr[16]; /* buffered data path register */
int pad2[480];
- pt_entry_t uba_map[UBAPAGES]; /* unibus map register */
+ struct pte uba_map[UBAPAGES]; /* unibus map register */
int pad3[UBAIOPAGES]; /* no maps for device address space */
};
#endif
#ifdef DW780
/* uba_cnfgr */
-#define UBACNFGR_UBINIT 0x00040000 /* unibus init asserted */
-#define UBACNFGR_UBPDN 0x00020000 /* unibus power down */
-#define UBACNFGR_UBIC 0x00010000 /* unibus init complete */
+#define UBACNFGR_UBINIT 0x00040000 /* unibus init asserted */
+#define UBACNFGR_UBPDN 0x00020000 /* unibus power down */
+#define UBACNFGR_UBIC 0x00010000 /* unibus init complete */
#define UBACNFGR_BITS \
"\40\40PARFLT\37WSQFLT\36URDFLT\35ISQFLT\34MXTFLT\33XMTFLT\30ADPDN\27ADPUP\23UBINIT\22UBPDN\21UBIC"
/* uba_cr */
-#define UBACR_MRD16 0x40000000 /* map reg disable bit 4 */
-#define UBACR_MRD8 0x20000000 /* map reg disable bit 3 */
-#define UBACR_MRD4 0x10000000 /* map reg disable bit 2 */
-#define UBACR_MRD2 0x08000000 /* map reg disable bit 1 */
-#define UBACR_MRD1 0x04000000 /* map reg disable bit 0 */
-#define UBACR_IFS 0x00000040 /* interrupt field switch */
-#define UBACR_BRIE 0x00000020 /* BR interrupt enable */
-#define UBACR_USEFIE 0x00000010 /* UNIBUS to SBI error field IE */
-#define UBACR_SUEFIE 0x00000008 /* SBI to UNIBUS error field IE */
-#define UBACR_CNFIE 0x00000004 /* configuration IE */
-#define UBACR_UPF 0x00000002 /* UNIBUS power fail */
-#define UBACR_ADINIT 0x00000001 /* adapter init */
+#define UBACR_MRD16 0x40000000 /* map reg disable bit 4 */
+#define UBACR_MRD8 0x20000000 /* map reg disable bit 3 */
+#define UBACR_MRD4 0x10000000 /* map reg disable bit 2 */
+#define UBACR_MRD2 0x08000000 /* map reg disable bit 1 */
+#define UBACR_MRD1 0x04000000 /* map reg disable bit 0 */
+#define UBACR_IFS 0x00000040 /* interrupt field switch */
+#define UBACR_BRIE 0x00000020 /* BR interrupt enable */
+#define UBACR_USEFIE 0x00000010 /* UNIBUS to SBI error field IE */
+#define UBACR_SUEFIE 0x00000008 /* SBI to UNIBUS error field IE */
+#define UBACR_CNFIE 0x00000004 /* configuration IE */
+#define UBACR_UPF 0x00000002 /* UNIBUS power fail */
+#define UBACR_ADINIT 0x00000001 /* adapter init */
/* uba_sr */
-#define UBASR_BR7FULL 0x08000000 /* BR7 receive vector reg full */
-#define UBASR_BR6FULL 0x04000000 /* BR6 receive vector reg full */
-#define UBASR_BR5FULL 0x02000000 /* BR5 receive vector reg full */
-#define UBASR_BR4FULL 0x01000000 /* BR4 receive vector reg full */
-#define UBASR_RDTO 0x00000400 /* UNIBUS to SBI read data timeout */
-#define UBASR_RDS 0x00000200 /* read data substitute */
-#define UBASR_CRD 0x00000100 /* corrected read data */
-#define UBASR_CXTER 0x00000080 /* command transmit error */
-#define UBASR_CXTMO 0x00000040 /* command transmit timeout */
-#define UBASR_DPPE 0x00000020 /* data path parity error */
-#define UBASR_IVMR 0x00000010 /* invalid map register */
-#define UBASR_MRPF 0x00000008 /* map register parity failure */
-#define UBASR_LEB 0x00000004 /* lost error */
-#define UBASR_UBSTO 0x00000002 /* UNIBUS select timeout */
-#define UBASR_UBSSYNTO 0x00000001 /* UNIBUS slave sync timeout */
-
-#define UBASR_BITS \
+#define UBASR_BR7FULL 0x08000000 /* BR7 receive vector reg full */
+#define UBASR_BR6FULL 0x04000000 /* BR6 receive vector reg full */
+#define UBASR_BR5FULL 0x02000000 /* BR5 receive vector reg full */
+#define UBASR_BR4FULL 0x01000000 /* BR4 receive vector reg full */
+#define UBASR_RDTO 0x00000400 /* UNIBUS to SBI read data timeout */
+#define UBASR_RDS 0x00000200 /* read data substitute */
+#define UBASR_CRD 0x00000100 /* corrected read data */
+#define UBASR_CXTER 0x00000080 /* command transmit error */
+#define UBASR_CXTMO 0x00000040 /* command transmit timeout */
+#define UBASR_DPPE 0x00000020 /* data path parity error */
+#define UBASR_IVMR 0x00000010 /* invalid map register */
+#define UBASR_MRPF 0x00000008 /* map register parity failure */
+#define UBASR_LEB 0x00000004 /* lost error */
+#define UBASR_UBSTO 0x00000002 /* UNIBUS select timeout */
+#define UBASR_UBSSYNTO 0x00000001 /* UNIBUS slave sync timeout */
+
+#define UBASR_BITS \
"\20\13RDTO\12RDS\11CRD\10CXTER\7CXTMO\6DPPE\5IVMR\4MRPF\3LEB\2UBSTO\1UBSSYNTO"
/* uba_brrvr[] */
-#define UBABRRVR_AIRI 0x80000000 /* adapter interrupt request */
-#define UBABRRVR_DIV 0x0000ffff /* device interrupt vector field */
+#define UBABRRVR_AIRI 0x80000000 /* adapter interrupt request */
+#define UBABRRVR_DIV 0x0000ffff /* device interrupt vector field */
#endif
/* uba_dpr */
#ifdef DW780
-#define UBADPR_BNE 0x80000000 /* buffer not empty - purge */
-#define UBADPR_BTE 0x40000000 /* buffer transfer error */
-#define UBADPR_DPF 0x20000000 /* DP function (RO) */
-#define UBADPR_BS 0x007f0000 /* buffer state field */
-#define UBADPR_BUBA 0x0000ffff /* buffered UNIBUS address */
-#define UBA_PURGE780(uba, bdp) \
- ((uba)->uba_dpr[(int)bdp] |= UBADPR_BNE)
-#else
-#define UBA_PURGE780(uba, bdp)
+#define UBADPR_BNE 0x80000000 /* buffer not empty - purge */
+#define UBADPR_BTE 0x40000000 /* buffer transfer error */
+#define UBADPR_DPF 0x20000000 /* DP function (RO) */
+#define UBADPR_BS 0x007f0000 /* buffer state field */
+#define UBADPR_BUBA 0x0000ffff /* buffered UNIBUS address */
#endif
#ifdef DW750
-#define UBADPR_ERROR 0x80000000 /* error occurred */
-#define UBADPR_NXM 0x40000000 /* nxm from memory */
-#define UBADPR_UCE 0x20000000 /* uncorrectable error */
-#define UBADPR_PURGE 0x00000001 /* purge bdp */
-/* the DELAY is for a hardware problem */
-#define UBA_PURGE750(uba, bdp) { \
- ((uba)->uba_dpr[(int)bdp] |= (UBADPR_PURGE|UBADPR_NXM|UBADPR_UCE)); \
- {volatile int N=8;while(N--);} \
-}
-#else
-#define UBA_PURGE750(uba, bdp)
+#define UBADPR_ERROR 0x80000000 /* error occurred */
+#define UBADPR_NXM 0x40000000 /* nxm from memory */
+#define UBADPR_UCE 0x20000000 /* uncorrectable error */
+#define UBADPR_PURGE 0x00000001 /* purge bdp */
#endif
-/*
- * Macros for fast buffered data path purging in time-critical routines.
- *
- * Too bad C pre-processor doesn't have the power of LISP in macro
- * expansion...
- */
-
-/* THIS IS WRONG, should use pointer to uba_hd */
-#if DWBUA || DW780 || DW750
-#define UBAPURGE(uba, bdp) { \
- switch (MACHID(cpu_type)) { \
- case VAX_8200: UBA_PURGEBUA(uba, bdp); break; \
- case VAX_8600: case VAX_780: UBA_PURGE780((uba), (bdp)); break; \
- case VAX_750: UBA_PURGE750((uba), (bdp)); break; \
- } \
-}
-#else
-#define UBAPURGE(uba, bdp)
-#endif
-
-
-
/* uba_mr[] */
-#define UBAMR_MRV 0x80000000 /* map register valid */
-#define UBAMR_BO 0x02000000 /* byte offset bit */
-#define UBAMR_DPDB 0x01e00000 /* data path designator field */
-#define UBAMR_SBIPFN 0x001fffff /* SBI page address field */
+#define UBAMR_MRV 0x80000000 /* map register valid */
+#define UBAMR_BO 0x02000000 /* byte offset bit */
+#define UBAMR_DPDB 0x01e00000 /* data path designator field */
+#define UBAMR_SBIPFN 0x001fffff /* SBI page address field */
-#define UBAMR_DPSHIFT 21 /* shift to data path designator */
+#define UBAMR_DPSHIFT 21 /* shift to data path designator */
/*
* Number of unibus buffered data paths and possible uba's per cpu type.
*/
-#define NBDP8600 15
-#define NBDP780 15
-#define NBDPBUA 5
-#define NBDP750 3
-#define NBDP730 0
-#define MAXNBDP 15
+#define NBDP8600 15
+#define NBDP780 15
+#define NBDPBUA 5
+#define NBDP750 3
+#define NBDP730 0
+#define MAXNBDP 15
/*
* Symbolic BUS addresses for UBAs.
*/
#if VAX630 || VAX650
-#define QBAMAP630 ((struct pte *)0x20088000)
-#define QMEM630 0x30000000
-#define QIOPAGE630 0x20000000
+#define QBAMAP 0x20088000
+#define QMEM 0x30000000
+#define QIOPAGE 0x20000000
/*
* Q-bus control registers
*/
-#define QIPCR 0x1f40 /* from start of iopage */
+#define QIPCR 0x1f40 /* from start of iopage */
/* bits in QIPCR */
-#define Q_DBIRQ 0x0001 /* doorbell interrupt request */
-#define Q_LMEAE 0x0020 /* local mem external access enable */
-#define Q_DBIIE 0x0040 /* doorbell interrupt enable */
-#define Q_AUXHLT 0x0100 /* auxiliary processor halt */
-#define Q_DMAQPE 0x8000 /* Q22 bus address space parity error */
+#define Q_DBIRQ 0x0001 /* doorbell interrupt request */
+#define Q_LMEAE 0x0020 /* local mem external access enable */
+#define Q_DBIIE 0x0040 /* doorbell interrupt enable */
+#define Q_AUXHLT 0x0100 /* auxiliary processor halt */
+#define Q_DMAQPE 0x8000 /* Q22 bus address space parity error */
#endif
#if VAX730
-#define UMEM730 0xfc0000
+#define UMEM730 0xfc0000
#endif
#if VAX750
-#define UMEM750(i) (0xfc0000-(i)*0x40000)
+#define UMEM750(i) (0xfc0000-(i)*0x40000)
#endif
#if VAX780
-#define UMEM780(i) (0x20100000+(i)*0x40000)
+#define UMEM780(i) (0x20100000+(i)*0x40000)
#endif
#if VAX8200 /* BEWARE, argument is node, not ubanum */
-#define UMEM8200(i) (0x20400000+(i)*0x40000)
+#define UMEM8200(i) (0x20400000+(i)*0x40000)
#endif
#if VAX8600 || VAX780
-#define UMEMA8600(i) (0x20100000+(i)*0x40000)
-#define UMEMB8600(i) (0x22100000+(i)*0x40000)
+#define UMEMA8600(i) (0x20100000+(i)*0x40000)
+#define UMEMB8600(i) (0x22100000+(i)*0x40000)
#endif
/*
@@ -327,4 +290,4 @@ struct uba_regs {
* something like 0172520, by forcing it into the last 8K
* of UNIBUS memory space.
*/
-#define ubdevreg(addr) ((addr) & 017777)
+#define ubdevreg(addr) ((addr) & 017777)
diff --git a/sys/arch/vax/uba/ubavar.h b/sys/arch/vax/uba/ubavar.h
index c179cb4887c..50b84a00afb 100644
--- a/sys/arch/vax/uba/ubavar.h
+++ b/sys/arch/vax/uba/ubavar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ubavar.h,v 1.15 1996/04/08 18:37:36 ragge Exp $ */
+/* $NetBSD: ubavar.h,v 1.18 1996/08/20 13:38:04 ragge Exp $ */
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
@@ -71,129 +71,60 @@
*/
struct uba_softc {
struct device uh_dev; /* Device struct, autoconfig */
+ SIMPLEQ_HEAD(, uba_unit) uh_resq; /* resource wait chain */
int uh_type; /* type of adaptor */
struct uba_regs *uh_uba; /* virt addr of uba adaptor regs */
- struct uba_regs *uh_physuba; /* phys addr of uba adaptor regs */
struct pte *uh_mr; /* start of page map */
int uh_memsize; /* size of uba memory, pages */
- caddr_t uh_mem; /* start of uba memory address space */
caddr_t uh_iopage; /* start of uba io page */
void (**uh_reset) __P((int));/* UBA reset function array */
int *uh_resarg; /* array of ubareset args */
int uh_resno; /* Number of devices to reset */
struct ivec_dsp *uh_idsp; /* Interrupt dispatch area */
u_int *uh_iarea; /* Interrupt vector array */
- struct uba_device *uh_actf; /* head of queue to transfer */
- struct uba_device *uh_actl; /* tail of queue to transfer */
short uh_mrwant; /* someone is waiting for map reg */
short uh_bdpwant; /* someone awaits bdp's */
int uh_bdpfree; /* free bdp's */
- int uh_hangcnt; /* number of ticks hung */
int uh_zvcnt; /* number of recent 0 vectors */
long uh_zvtime; /* time over which zvcnt accumulated */
int uh_zvtotal; /* total number of 0 vectors */
- int uh_errcnt; /* number of errors */
int uh_lastiv; /* last free interrupt vector */
short uh_users; /* transient bdp use count */
short uh_xclu; /* an rk07 is using this uba! */
int uh_lastmem; /* limit of any unibus memory */
-#define UAMSIZ 100
struct map *uh_map; /* register free map */
+ int (*uh_errchk) __P((struct uba_softc *));
+ void (*uh_beforescan) __P((struct uba_softc *));
+ void (*uh_afterscan) __P((struct uba_softc *));
+ void (*uh_ubainit) __P((struct uba_softc *));
+ void (*uh_ubapurge) __P((struct uba_softc *, int));
+#ifdef DW780
struct ivec_dsp uh_dw780; /* Interrupt handles for DW780 */
+#endif
+ short uh_nr; /* Unibus sequential number */
+ short uh_nbdp; /* # of BDP's */
};
+#define UAMSIZ 100
+
/* given a pointer to uba_regs, find DWBUA registers */
/* this should be replaced with a union in uba_softc */
#define BUA(uba) ((struct dwbua_regs *)(uba))
/*
* Per-controller structure.
- * (E.g. one for each disk and tape controller, and other things
- * which use and release buffered data paths.)
- *
- * If a controller has devices attached, then there are
- * cross-referenced uba_drive structures.
- * This structure is the one which is queued in unibus resource wait,
- * and saves the information about unibus resources which are used.
- * The queue of devices waiting to transfer is also attached here.
+ * The unit struct is common to both the adapter and the controller
+ * to which it belongs. It is only used on controllers that handles
+ * BDP's, and calls the adapter queueing subroutines.
*/
-struct uba_ctlr {
- struct uba_driver *um_driver;
- short um_ctlr; /* controller index in driver */
- short um_ubanum; /* the uba it is on */
- short um_alive; /* controller exists */
- void (*um_intr) __P((int)); /* interrupt handler(s) XXX */
- caddr_t um_addr; /* address of device in i/o space */
- struct uba_softc *um_hd;
-/* the driver saves the prototype command here for use in its go routine */
- int um_cmd; /* communication to dgo() */
- int um_ubinfo; /* save unibus registers, etc */
- int um_bdp; /* for controllers that hang on to bdp's */
- struct buf um_tab; /* queue of devices for this controller */
-};
-
-/*
- * Per ``device'' structure.
- * (A controller has devices or uses and releases buffered data paths).
- * (Everything else is a ``device''.)
- *
- * If a controller has many drives attached, then there will
- * be several uba_device structures associated with a single uba_ctlr
- * structure.
- *
- * This structure contains all the information necessary to run
- * a unibus device such as a dz or a dh. It also contains information
- * for slaves of unibus controllers as to which device on the slave
- * this is. A flags field here can also be given in the system specification
- * and is used to tell which dz lines are hard wired or other device
- * specific parameters.
- */
-struct uba_device {
- struct uba_driver *ui_driver;
- short ui_unit; /* unit number on the system */
- short ui_ctlr; /* mass ctlr number; -1 if none */
- short ui_ubanum; /* the uba it is on */
- short ui_slave; /* slave on controller */
- void (*ui_intr) __P((int)); /* interrupt handler(s) XXX */
- caddr_t ui_addr; /* address of device in i/o space */
- short ui_dk; /* if init 1 set to number for iostat */
- int ui_flags; /* parameter from system specification */
- short ui_alive; /* device exists */
- short ui_type; /* driver specific type information */
- caddr_t ui_physaddr; /* phys addr, for standalone (dump) code */
-/* this is the forward link in a list of devices on a controller */
- struct uba_device *ui_forw;
-/* if the device is connected to a controller, this is the controller */
- struct uba_ctlr *ui_mi;
- struct uba_softc *ui_hd;
-};
-
-/*
- * Per-driver structure.
- *
- * Each unibus driver defines entries for a set of routines
- * as well as an array of types which are acceptable to it.
- * These are used at boot time by the configuration program.
- */
-struct uba_driver {
- /* see if a driver is really there XXX*/
- int (*ud_probe) __P((caddr_t, int, struct uba_ctlr *,
- struct uba_softc *));
- /* see if a slave is there XXX */
- int (*ud_slave) __P((struct uba_device *, caddr_t));
- /* setup driver for a slave XXX */
- void (*ud_attach) __P((struct uba_device *));
- /* fill csr/ba to start transfer XXX */
- void (*ud_dgo) __P((struct uba_ctlr *));
- u_short *ud_addr; /* device csr addresses */
- char *ud_dname; /* name of a device */
- struct uba_device **ud_dinfo; /* backpointers to ubdinit structs */
- char *ud_mname; /* name of a controller */
- struct uba_ctlr **ud_minfo; /* backpointers to ubminit structs */
- short ud_xclu; /* want exclusive use of bdp's */
- short ud_keepbdp; /* hang on to bdp's once allocated */
- int (*ud_ubamem) __P((struct uba_device *, int));
- /* see if dedicated memory is present */
+struct uba_unit {
+ SIMPLEQ_ENTRY(uba_unit) uu_resq;/* Queue while waiting for resources */
+ void *uu_softc; /* Pointer to units softc */
+ int uu_ubinfo; /* save unibus registers, etc */
+ int uu_bdp; /* for controllers that hang on to bdp's */
+ int (*uu_ready) __P((struct uba_unit *));
+ short uu_xclu; /* want exclusive use of bdp's */
+ short uu_keepbdp; /* hang on to bdp's once allocated */
};
/*
@@ -246,25 +177,17 @@ struct ubinfo {
#ifndef _LOCORE
#ifdef _KERNEL
-#define ubago(ui) ubaqueue(ui, 0)
-
-/*
- * Ubminit and ubdinit initialize the mass storage controller and
- * device tables specifying possible devices.
- */
-extern struct uba_ctlr ubminit[];
-extern struct uba_device ubdinit[];
+#define ubago(ui) ubaqueue(ui)
+#define b_forw b_hash.le_next /* Nice to have when handling uba queues */
extern struct cfdriver uba_cd;
-void ubainit __P((struct uba_softc *));
void ubasetvec __P((struct device *, int, void (*) __P((int))));
-int uballoc __P((int, caddr_t, int, int));
-void ubarelse __P((int, int *));
-int ubaqueue __P((struct uba_device *, int));
-void ubadone __P((struct uba_ctlr *));
+int uballoc __P((struct uba_softc *, caddr_t, int, int));
+void ubarelse __P((struct uba_softc *, int *));
+int ubaqueue __P((struct uba_unit *, struct buf *));
+void ubadone __P((struct uba_unit *));
void ubareset __P((int));
-int ubasetup __P((int, struct buf *, int));
#endif /* _KERNEL */
#endif !_LOCORE
diff --git a/sys/arch/vax/uba/uda.c b/sys/arch/vax/uba/uda.c
index c911d3a9b3f..86fa0c20fd2 100644
--- a/sys/arch/vax/uba/uda.c
+++ b/sys/arch/vax/uba/uda.c
@@ -1,5 +1,6 @@
-/* $NetBSD: uda.c,v 1.16 1996/05/19 16:43:42 ragge Exp $ */
+/* $NetBSD: uda.c,v 1.23 1996/10/13 03:35:26 christos Exp $ */
/*
+ * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
@@ -38,367 +39,133 @@
*/
/*
- * UDA50/MSCP device driver
+ * UDA50 disk device driver
*/
-#define POLLSTATS
-
-/*
- * TODO
- * write bad block forwarding code
- */
-
-#include "uda.h"
-#include "ra.h"
-
-/*
- * CONFIGURATION OPTIONS. The next three defines are tunable -- tune away!
- *
- * COMPAT_42 enables 4.2/4.3 compatibility (label mapping)
- *
- * NRSPL2 and NCMDL2 control the number of response and command
- * packets respectively. They may be any value from 0 to 7, though
- * setting them higher than 5 is unlikely to be of any value.
- * If you get warnings about your command ring being too small,
- * try increasing the values by one.
- *
- * MAXUNIT controls the maximum unit number (number of drives per
- * controller) we are prepared to handle.
- *
- * DEFAULT_BURST must be at least 1.
- */
-#define COMPAT_42
-#define todr() 0 /* XXX */
-#define NRSPL2 5 /* log2 number of response packets */
-#define NCMDL2 5 /* log2 number of command packets */
-#define MAXUNIT 8 /* maximum allowed unit number */
-#define DEFAULT_BURST 4 /* default DMA burst size */
-
-#define ALLSTEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)
-
-#define STEP1MASK (ALLSTEPS | UDA_IE | UDA_NCNRMASK)
-#define STEP1GOOD (UDA_STEP2 | UDA_IE | (NCMDL2 << 3) | NRSPL2)
-
-#define STEP2MASK (ALLSTEPS | UDA_IE | UDA_IVECMASK)
-#define STEP2GOOD (UDA_STEP3 | UDA_IE | (sc->sc_ivec >> 2))
-
-#define STEP3MASK ALLSTEPS
-#define STEP3GOOD UDA_STEP4
-
#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/systm.h>
-#include <sys/buf.h>
-#include <sys/conf.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/proc.h>
-#include <sys/user.h>
-#include <sys/map.h>
-#include <sys/device.h>
-#include <sys/dkstat.h>
-#include <sys/disklabel.h>
-#include <sys/syslog.h>
-#include <sys/stat.h>
-#include <machine/pte.h>
#include <machine/sid.h>
+#include <machine/pte.h>
#include <machine/cpu.h>
-#include <vax/uba/ubareg.h>
#include <vax/uba/ubavar.h>
-
-#define NRSP (1 << NRSPL2)
-#define NCMD (1 << NCMDL2)
-
+#include <vax/uba/ubareg.h>
#include <vax/uba/udareg.h>
-#include <vax/vax/mscp.h>
-#include <vax/vax/mscpvar.h>
-#include <machine/mtpr.h>
-extern int cold;
+#include <vax/mscp/mscp.h>
+#include <vax/mscp/mscpvar.h>
+#include <vax/mscp/mscpreg.h>
/*
- * This macro is for delay during init. Some MSCP clone card (Dilog)
- * can't handle fast read from its registers, and therefore need
- * a delay between them.
+ * Variants of SIMPLEQ macros for use with buf structs.
*/
-#define DELAYTEN 1000
-#define Wait_step( mask, result, status ) { \
- status = 1; \
- if ((udaddr->udasa & mask) != result) { \
- volatile int count = 0; \
- while ((udaddr->udasa & mask) != result) { \
- DELAY(10000); \
- count += 1; \
- if (count > DELAYTEN) \
- break; \
- } \
- if (count > DELAYTEN) \
- status = 0; \
- } \
- }
+#define BUFQ_INSERT_TAIL(head, elm) { \
+ (elm)->b_actf = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->b_actf; \
+}
-/*
- * UDA communications area and MSCP packet pools, per controller.
- */
-struct uda {
- struct udaca uda_ca; /* communications area */
- struct mscp uda_rsp[NRSP]; /* response packets */
- struct mscp uda_cmd[NCMD]; /* command packets */
-};
+#define BUFQ_REMOVE_HEAD(head, elm) { \
+ if (((head)->sqh_first = (elm)->b_actf) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+}
/*
* Software status, per controller.
*/
struct uda_softc {
- struct uda *sc_uuda; /* Unibus address of uda struct */
- struct uda sc_uda; /* Struct for uda communication */
- short sc_state; /* UDA50 state; see below */
- short sc_flags; /* flags; see below */
- int sc_micro; /* microcode revision */
- int sc_ivec; /* interrupt vector address */
+ struct device sc_dev; /* Autoconfig info */
+ struct uba_unit sc_unit; /* Struct common for UBA to communicate */
+ SIMPLEQ_HEAD(, buf) sc_bufq; /* bufs awaiting for resources */
+ struct mscp_pack *sc_uuda; /* Unibus address of uda struct */
+ struct mscp_pack sc_uda; /* Struct for uda communication */
+ struct udadevice *sc_udadev; /* pointer to ip/sa regs */
+ struct mscp *sc_mscp; /* Keep pointer to active mscp */
short sc_ipl; /* interrupt priority, Q-bus */
- struct mscp_info sc_mi;/* MSCP info (per mscpvar.h) */
-#ifndef POLLSTATS
+ struct mscp_softc *sc_softc; /* MSCP info (per mscpvar.h) */
int sc_wticks; /* watchdog timer ticks */
-#else
- short sc_wticks;
- short sc_ncmd;
-#endif
-} uda_softc[NUDA];
+};
-#ifdef POLLSTATS
-struct udastats {
- int ncmd;
- int cmd[NCMD + 1];
-} udastats = { NCMD + 1 };
-#endif
+static int udamatch __P((struct device *, void *, void *));
+static void udaattach __P((struct device *, struct device *, void *));
+static void udareset __P((int));
+static void mtcreset __P((int));
+static void reset __P((struct uda_softc *));
+static void udaintr __P((int));
+static void mtcintr __P((int));
+static void intr __P((struct uda_softc *));
+int udaready __P((struct uba_unit *));
+void udactlrdone __P((struct device *, int));
+int udaprint __P((void *, const char *));
+void udasaerror __P((struct device *, int));
+int udago __P((struct device *, struct buf *));
+
+struct cfdriver mtc_cd = {
+ NULL, "mtc", DV_DULL
+};
-int udamatch __P((struct device *, void *, void *));
-void uda_attach __P((struct device *, struct device *, void *));
+struct cfattach mtc_ca = {
+ sizeof(struct uda_softc), udamatch, udaattach
+};
struct cfdriver uda_cd = {
NULL, "uda", DV_DULL
};
struct cfattach uda_ca = {
- sizeof(struct device), udamatch, uda_attach
+ sizeof(struct uda_softc), udamatch, udaattach
};
/*
- * Controller states
- */
-#define ST_IDLE 0 /* uninitialised */
-#define ST_STEP1 1 /* in `STEP 1' */
-#define ST_STEP2 2 /* in `STEP 2' */
-#define ST_STEP3 3 /* in `STEP 3' */
-#define ST_SETCHAR 4 /* in `Set Controller Characteristics' */
-#define ST_RUN 5 /* up and running */
-
-/*
- * Flags
- */
-#define SC_MAPPED 0x01 /* mapped in Unibus I/O space */
-#define SC_INSTART 0x02 /* inside udastart() */
-#define SC_GRIPED 0x04 /* griped about cmd ring too small */
-#define SC_INSLAVE 0x08 /* inside udaslave() */
-#define SC_DOWAKE 0x10 /* wakeup when ctlr init done */
-#define SC_STARTPOLL 0x20 /* need to initiate polling */
-
-/*
- * Device to unit number and partition and back
- */
-#define UNITSHIFT 3
-#define UNITMASK 7
-#define udaunit(dev) (minor(dev) >> UNITSHIFT)
-#define udapart(dev) (minor(dev) & UNITMASK)
-#define udaminor(u, p) (((u) << UNITSHIFT) | (p))
-
-/*
- * Drive status, per drive
- */
-struct ra_info {
- daddr_t ra_dsize; /* size in sectors */
-/* u_long ra_type; /* drive type */
- u_long ra_mediaid; /* media id */
- int ra_state; /* open/closed state */
- struct ra_geom { /* geometry information */
- u_short rg_nsectors; /* sectors/track */
- u_short rg_ngroups; /* track groups */
- u_short rg_ngpc; /* groups/cylinder */
- u_short rg_ntracks; /* ngroups*ngpc */
- u_short rg_ncyl; /* ra_dsize/ntracks/nsectors */
-#ifdef notyet
- u_short rg_rctsize; /* size of rct */
- u_short rg_rbns; /* replacement blocks per track */
- u_short rg_nrct; /* number of rct copies */
-#endif
- } ra_geom;
- int ra_wlabel; /* label sector is currently writable */
- u_long ra_openpart; /* partitions open */
- u_long ra_bopenpart; /* block partitions open */
- u_long ra_copenpart; /* character partitions open */
-} ra_info[NRA];
-
-/*
- * Software state, per drive
- */
-#define CLOSED 0
-#define WANTOPEN 1
-#define RDLABEL 2
-#define OPEN 3
-#define OPENRAW 4
-
-/*
- * Definition of the driver for autoconf.
- */
-int udaprobe __P((caddr_t, int, struct uba_ctlr *, struct uba_softc *));
-int udaslave __P((struct uba_device *, caddr_t));
-void udaattach __P((struct uba_device *));
-void udadgo __P((struct uba_ctlr *));
-void udaintr __P((int));
-
-struct uba_ctlr *udaminfo[NUDA];
-struct uba_device *udadinfo[NRA];
-struct disklabel udalabel[NRA];
-
-u_short udastd[] = { 0 };
-struct uba_driver udadriver =
- { udaprobe, udaslave, udaattach, udadgo, udastd, "ra", udadinfo, "uda",
- udaminfo };
-
-/*
* More driver definitions, for generic MSCP code.
*/
-void udadgram __P((struct mscp_info *, struct mscp *));
-void udactlrdone __P((struct mscp_info *, struct mscp *));
-int udaunconf __P((struct mscp_info *, struct mscp *));
-void udaiodone __P((struct mscp_info *, struct buf *, int));
-int udaonline __P((struct uba_device *, struct mscp *));
-int udagotstatus __P((struct uba_device *, struct mscp *));
-void udareplace __P((struct uba_device *, struct mscp *));
-int udaioerror __P((struct uba_device *, struct mscp *, struct buf *));
-void udabb __P((struct uba_device *, struct mscp *, struct buf *));
-
-struct buf udautab[NRA]; /* per drive transfer queue */
-
-struct mscp_driver udamscpdriver =
- { MAXUNIT, NRA, UNITSHIFT, udautab, udalabel, udadinfo,
- udadgram, udactlrdone, udaunconf, udaiodone,
- udaonline, udagotstatus, udareplace, udaioerror, udabb,
- "uda", "ra" };
+struct mscp_ctlr uda_mscp_ctlr = {
+ udactlrdone,
+ udago,
+ udasaerror,
+};
/*
* Miscellaneous private variables.
*/
-char udasr_bits[] = UDASR_BITS;
-
-struct uba_device *udaip[NUDA][MAXUNIT];
- /* inverting pointers: ctlr & unit => Unibus
- device pointer */
-
-int udaburst[NUDA] = { 0 }; /* burst size, per UDA50, zero => default;
- in data space so patchable via adb */
+static int ivec_no;
-struct mscp udaslavereply; /* get unit status response packet, set
- for udaslave by udaunconf, via udaintr */
-
-static struct uba_ctlr *probeum;/* this is a hack---autoconf should pass ctlr
- info to slave routine; instead, we remember
- the last ctlr argument to probe */
-
-int udawstart;
-void udawatch(); /* watchdog timer */
-
-/*
- * Externals
- */
-int hz;
+int
+udaprint(aux, name)
+ void *aux;
+ const char *name;
+{
+ if (name)
+ printf("%s: mscpbus", name);
+ return UNCONF;
+}
/*
* Poke at a supposed UDA50 to see if it is there.
- * This routine duplicates some of the code in udainit() only
- * because autoconf has not set up the right information yet.
- * We have to do everything `by hand'.
*/
int
udamatch(parent, match, aux)
- struct device *parent;
- void *match, *aux;
-{
- return 0;
-}
-
-void
-uda_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
-}
-
-udaprobe(reg, ctlr, um, uhp)
- caddr_t reg;
- int ctlr;
- struct uba_ctlr *um;
- struct uba_softc *uhp;
-{
- struct uda_softc *sc;
- volatile struct udadevice *udaddr;
- struct mscp_info *mi;
- struct uba_softc *ubasc;
- extern int cpu_type;
- int timeout, tries, count;
-#ifdef notyet
+ struct device *parent;
+ void *match, *aux;
+{
+ struct uba_attach_args *ua = aux;
+ struct device *dev = match;
+ struct mscp_softc mi; /* Nice hack */
+ struct uba_softc *ubasc;
+ int tries;
+#if QBA && notyet
+ extern volatile int rbr;
int s;
#endif
-#ifdef VAX750
- /*
- * The UDA50 wants to share BDPs on 750s, but not on 780s or
- * 8600s. (730s have no BDPs anyway.) Toward this end, we
- * here set the `keep bdp' flag in the per-driver information
- * if this is a 750. (We just need to do it once, but it is
- * easiest to do it now, for each UDA50.)
- */
- if (MACHID(cpu_type) == VAX_750)
- udadriver.ud_keepbdp = 1;
-#endif
- probeum = um; /* remember for udaslave() */
- /*
- * Set up the controller-specific generic MSCP driver info.
- * Note that this should really be done in the (nonexistent)
- * controller attach routine.
- */
- sc = &uda_softc[ctlr];
- mi = &sc->sc_mi;
- mi->mi_md = &udamscpdriver;
- mi->mi_ctlr = um->um_ctlr;
- mi->mi_tab = (void*)&um->um_tab;
- mi->mi_ip = udaip[ctlr];
- mi->mi_cmd.mri_size = NCMD;
- mi->mi_cmd.mri_desc = sc->sc_uda.uda_ca.ca_cmddsc;
- mi->mi_cmd.mri_ring = sc->sc_uda.uda_cmd;
- mi->mi_rsp.mri_size = NRSP;
- mi->mi_rsp.mri_desc = sc->sc_uda.uda_ca.ca_rspdsc;
- mi->mi_rsp.mri_ring = sc->sc_uda.uda_rsp;
- mi->mi_wtab.b_actf = &mi->mi_wtab;
+ /* Get an interrupt vector. */
+ ubasc = (void *)parent;
+ ivec_no = ubasc->uh_lastiv - 4;
- /*
- * More controller specific variables. Again, this should
- * be in the controller attach routine.
- */
- if (udaburst[ctlr] == 0)
- udaburst[ctlr] = DEFAULT_BURST;
-
- /*
- * Get an interrupt vector. Note that even if the controller
- * does not respond, we keep the vector. This is not a serious
- * problem; but it would be easily fixed if we had a controller
- * attach routine. Sigh.
- */
- ubasc = uhp;
- sc->sc_ivec = ubasc->uh_lastiv -= 4;
- udaddr = (struct udadevice *) reg;
+ mi.mi_sa = &((struct udadevice *)ua->ua_addr)->udasa;
+ mi.mi_ip = &((struct udadevice *)ua->ua_addr)->udaip;
/*
* Initialise the controller (partially). The UDA50 programmer's
@@ -408,961 +175,165 @@ udaprobe(reg, ctlr, um, uhp)
* initialise within ten seconds. Or so I hear; I have not seen
* this manual myself.
*/
-#ifdef notyet
+#if 0
s = spl6();
#endif
tries = 0;
again:
- udaddr->udaip = 0; /* start initialisation */
-
- count = 0;
- while ( count < DELAYTEN ) {
- if ( (udaddr->udasa & UDA_STEP1) != 0 )
- break;
- DELAY(10000);
- count += 1;
- }
- /* nothing there */
- if ( count == DELAYTEN )
- return(0);
+ *mi.mi_ip = 0;
+ if (mscp_waitstep(&mi, MP_STEP1, MP_STEP1) == 0)
+ return 0; /* Nothing here... */
- udaddr->udasa = UDA_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | UDA_IE |
- (sc->sc_ivec >> 2);
+ *mi.mi_sa = MP_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | MP_IE |
+ (ivec_no >> 2);
- count = 0;
- while (count < DELAYTEN) {
- if ((udaddr->udasa & UDA_STEP2 ) != 0)
- break;
- DELAY(10000);
- count += 1;
- }
-
- if (count == DELAYTEN) {
- printf("udaprobe: uda%d: init step2 no change.\n",
- um->um_ctlr);
+ if (mscp_waitstep(&mi, MP_STEP2, MP_STEP2) == 0) {
+ printf("udaprobe: init step2 no change. sa=%x\n", *mi.mi_sa);
goto bad;
}
/* should have interrupted by now */
-#ifdef notyet
- sc->sc_ipl = br = qbgetpri();
-#else
- sc->sc_ipl = 0x15;
+#if 0
+ rbr = qbgetpri();
#endif
- return (sizeof (struct udadevice));
+ if (strcmp(dev->dv_cfdata->cf_driver->cd_name, mtc_cd.cd_name)) {
+ ua->ua_ivec = udaintr;
+ ua->ua_reset = udareset;
+ } else {
+ ua->ua_ivec = mtcintr;
+ ua->ua_reset = mtcreset;
+ }
+
+ return 1;
bad:
if (++tries < 2)
goto again;
-#ifdef notyet
+#if 0
splx(s);
#endif
- return (0);
-}
-
-/*
- * Find a slave. We allow wildcard slave numbers (something autoconf
- * is not really prepared to deal with); and we need to know the
- * controller number to talk to the UDA. For the latter, we keep
- * track of the last controller probed, since a controller probe
- * immediately precedes all slave probes for that controller. For the
- * former, we simply put the unit number into ui->ui_slave after we
- * have found one.
- *
- * Note that by the time udaslave is called, the interrupt vector
- * for the UDA50 has been set up (so that udaunconf() will be called).
- */
-udaslave(ui, reg)
- register struct uba_device *ui;
- caddr_t reg;
-{
- register struct uba_ctlr *um = probeum;
- volatile struct mscp *mp;
- volatile struct uda_softc *sc;
- int next = 0, timeout, tries;
- volatile int i;
-
-#ifdef lint
- i = 0; i = i;
-#endif
- /*
- * Make sure the controller is fully initialised, by waiting
- * for it if necessary.
- */
- sc = &uda_softc[um->um_ctlr];
- if (sc->sc_state == ST_RUN)
- goto findunit;
- tries = 0;
-again:
- if (udainit(ui->ui_ctlr))
- return (0);
- timeout = 1000;
- while (timeout-- > 0) {
- DELAY(10000);
- if (sc->sc_state == ST_RUN)
- goto findunit;
- }
-
- if (++tries < 2)
- goto again;
- printf("uda%d: controller hung\n", um->um_ctlr);
- return (0);
-
- /*
- * The controller is all set; go find the unit. Grab an
- * MSCP packet and send out a Get Unit Status command, with
- * the `next unit' modifier if we are looking for a generic
- * unit. We set the `in slave' flag so that udaunconf()
- * knows to copy the response to `udaslavereply'.
- */
-findunit:
- udaslavereply.mscp_opcode = 0;
- sc->sc_flags |= SC_INSLAVE;
- if ((mp = mscp_getcp((void *)&sc->sc_mi, MSCP_DONTWAIT)) == NULL)
- panic("udaslave"); /* `cannot happen' */
- mp->mscp_opcode = M_OP_GETUNITST;
- if (ui->ui_slave == '?') {
- mp->mscp_unit = next;
- mp->mscp_modifier = M_GUM_NEXTUNIT;
- } else {
- mp->mscp_unit = ui->ui_slave;
- mp->mscp_modifier = 0;
- }
- *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
- i = ((struct udadevice *) reg)->udaip; /* initiate polling */
- mp = &udaslavereply;
- timeout = 1000;
- while (timeout-- > 0) {
- DELAY(10000);
- if (mp->mscp_opcode)
- goto gotit;
- }
- printf("uda%d: no response to Get Unit Status request\n",
- um->um_ctlr);
- sc->sc_flags &= ~SC_INSLAVE;
- return (0);
-
-gotit:
- sc->sc_flags &= ~SC_INSLAVE;
-
- /*
- * Got a slave response. If the unit is there, use it.
- */
- switch (mp->mscp_status & M_ST_MASK) {
-
- case M_ST_SUCCESS: /* worked */
- case M_ST_AVAILABLE: /* found another drive */
- break; /* use it */
-
- case M_ST_OFFLINE:
- /*
- * Figure out why it is off line. It may be because
- * it is nonexistent, or because it is spun down, or
- * for some other reason.
- */
- switch (mp->mscp_status & ~M_ST_MASK) {
-
- case M_OFFLINE_UNKNOWN:
- /*
- * No such drive, and there are none with
- * higher unit numbers either, if we are
- * using M_GUM_NEXTUNIT.
- */
- return (0);
-
- case M_OFFLINE_UNMOUNTED:
- /*
- * The drive is not spun up. Use it anyway.
- *
- * N.B.: this seems to be a common occurrance
- * after a power failure. The first attempt
- * to bring it on line seems to spin it up
- * (and thus takes several minutes). Perhaps
- * we should note here that the on-line may
- * take longer than usual.
- */
- break;
-
- default:
- /*
- * In service, or something else equally unusable.
- */
- printf("uda%d: unit %d off line: ", um->um_ctlr,
- mp->mscp_unit);
- mscp_printevent((void *)mp);
- goto try_another;
- }
- break;
-
- default:
- printf("uda%d: unable to get unit status: ", um->um_ctlr);
- mscp_printevent((void *)mp);
- return (0);
- }
-
- /*
- * Does this ever happen? What (if anything) does it mean?
- */
- if (mp->mscp_unit < next) {
- printf("uda%d: unit %d, next %d\n",
- um->um_ctlr, mp->mscp_unit, next);
- return (0);
- }
-
- if (mp->mscp_unit >= MAXUNIT) {
- printf("uda%d: cannot handle unit number %d (max is %d)\n",
- um->um_ctlr, mp->mscp_unit, MAXUNIT - 1);
- return (0);
- }
-
- /*
- * See if we already handle this drive.
- * (Only likely if ui->ui_slave=='?'.)
- */
- if (udaip[um->um_ctlr][mp->mscp_unit] != NULL) {
-try_another:
- if (ui->ui_slave != '?')
- return (0);
- next = mp->mscp_unit + 1;
- goto findunit;
- }
-
- /*
- * Voila!
- */
- uda_rasave(ui->ui_unit, mp, 0);
- ui->ui_flags = 0; /* not on line, nor anything else */
- ui->ui_slave = mp->mscp_unit;
- return (1);
+ return 0;
}
-/*
- * Attach a found slave. Make sure the watchdog timer is running.
- * If this disk is being profiled, fill in the `wpms' value (used by
- * what?). Set up the inverting pointer, and attempt to bring the
- * drive on line and read its label.
- */
void
-udaattach(ui)
- register struct uba_device *ui;
+udaattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
{
- register int unit = ui->ui_unit;
-
- if (udawstart == 0) {
- timeout(udawatch, (caddr_t) 0, hz);
- udawstart++;
- }
+ struct uda_softc *sc = (void *)self;
+ struct uba_attach_args *ua = aux;
+ struct uba_softc *uh = (void *)parent;
+ struct mscp_attach_args ma;
+ int ctlr, ubinfo;
- /*
- * Floppies cannot be brought on line unless there is
- * a disk in the drive. Since an ONLINE while cold
- * takes ten seconds to fail, and (when notyet becomes now)
- * no sensible person will swap to one, we just
- * defer the ONLINE until someone tries to use the drive.
- *
- * THIS ASSUMES THAT DRIVE TYPES ?X? ARE FLOPPIES
- */
- if (MSCP_MID_ECH(1, ra_info[unit].ra_mediaid) == 'X' - '@') {
- printf(": floppy");
- return;
- }
- if (ui->ui_dk >= 0)
- dk_wpms[ui->ui_dk] = (60 * 31 * 256); /* approx */
- udaip[ui->ui_ctlr][ui->ui_slave] = ui;
+ printf("\n");
- if (uda_rainit(ui, 0))
- printf(": offline");
- else if (ra_info[unit].ra_state == OPEN) {
- printf(": %s, size = %d sectors",
- udalabel[unit].d_typename, ra_info[unit].ra_dsize);
-#ifdef notyet
- addswap(makedev(UDADEVNUM, udaminor(unit, 0)), &udalabel[unit]);
+ uh->uh_lastiv -= 4; /* remove dynamic interrupt vector */
+#ifdef QBA
+ sc->sc_ipl = ua->ua_br;
#endif
- }
-}
-/*
- * Initialise a UDA50. Return true iff something goes wrong.
- */
-udainit(ctlr)
- int ctlr;
-{
- register struct uda_softc *sc;
- volatile struct udadevice *udaddr;
- struct uba_ctlr *um;
- int timo, ubinfo, count, i, wait_status;
- unsigned short hej;
-/* printf("udainit\n"); */
- sc = &uda_softc[ctlr];
- um = udaminfo[ctlr];
- if ((sc->sc_flags & SC_MAPPED) == 0) {
- /*
- * Map the communication area and command and
- * response packets into Unibus space.
- */
- ubinfo = uballoc(um->um_ubanum, (caddr_t) &sc->sc_uda,
- sizeof (struct uda), UBA_CANTWAIT);
- if (ubinfo == 0) {
- printf("uda%d: uballoc map failed\n", ctlr);
- return (-1);
- }
- sc->sc_uuda = (struct uda *) UBAI_ADDR(ubinfo);
- sc->sc_flags |= SC_MAPPED;
- }
- bzero(&sc->sc_uda, sizeof (struct uda));
+ ctlr = sc->sc_dev.dv_unit;
+ sc->sc_udadev = (struct udadevice *)ua->ua_addr;
+ SIMPLEQ_INIT(&sc->sc_bufq);
/*
- * While we are thinking about it, reset the next command
- * and response indicies.
+ * Fill in the uba_unit struct, so we can communicate with the uba.
*/
- sc->sc_mi.mi_cmd.mri_next = 0;
- sc->sc_mi.mi_rsp.mri_next = 0;
+ sc->sc_unit.uu_softc = sc; /* Backpointer to softc */
+ sc->sc_unit.uu_ready = udaready;/* go routine called from adapter */
+ sc->sc_unit.uu_keepbdp = vax_cputype == VAX_750 ? 1 : 0;
/*
- * Start up the hardware initialisation sequence.
+ * Map the communication area and command and
+ * response packets into Unibus space.
*/
-#define STEP0MASK (UDA_ERR | UDA_STEP4 | UDA_STEP3 | UDA_STEP2 | \
- UDA_STEP1 | UDA_NV)
-
- sc->sc_state = ST_IDLE; /* in case init fails */
- udaddr = (struct udadevice *)um->um_addr;
- udaddr->udaip = 0;
- count = 0;
- while (count < DELAYTEN) {
- if ((udaddr->udasa & UDA_STEP1) != 0)
- break;
- DELAY(10000);
- count += 1;
- }
- if (count == DELAYTEN) {
- printf("uda%d: timeout during init\n", ctlr);
- return (-1);
- }
+ ubinfo = uballoc((struct uba_softc *)sc->sc_dev.dv_parent,
+ (caddr_t) &sc->sc_uda, sizeof (struct mscp_pack), UBA_CANTWAIT);
- if ((udaddr->udasa & STEP0MASK) != UDA_STEP1) {
- printf("uda%d: init failed, sa=%b\n", ctlr,
- udaddr->udasa, udasr_bits);
- udasaerror(um, 0);
- return (-1);
- }
-
- /*
- * Success! Record new state, and start step 1 initialisation.
- * The rest is done in the interrupt handler.
- */
- sc->sc_state = ST_STEP1;
- udaddr->udasa = UDA_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | UDA_IE |
- (sc->sc_ivec >> 2);
-
- return (0);
-}
-
-/*
- * Open a drive.
- */
-/*ARGSUSED*/
-udaopen(dev, flag, fmt)
- dev_t dev;
- int flag, fmt;
-{
- register int unit;
- register struct uba_device *ui;
- register struct uda_softc *sc;
- register struct disklabel *lp;
- register struct partition *pp;
- register struct ra_info *ra;
- int s, i, part, mask, error = 0;
- daddr_t start, end;
-/* printf("udaopen\n"); */
- /*
- * Make sure this is a reasonable open request.
- */
- unit = udaunit(dev);
- if (unit >= NRA || (ui = udadinfo[unit]) == 0 || ui->ui_alive == 0)
- return (ENXIO);
-
- /*
- * Make sure the controller is running, by (re)initialising it if
- * necessary.
- */
- sc = &uda_softc[ui->ui_ctlr];
- s = splbio();
- if (sc->sc_state != ST_RUN) {
- if (sc->sc_state == ST_IDLE && udainit(ui->ui_ctlr)) {
- splx(s);
- return (EIO);
- }
- /*
- * In case it does not come up, make sure we will be
- * restarted in 10 seconds. This corresponds to the
- * 10 second timeouts in udaprobe() and udaslave().
- */
- sc->sc_flags |= SC_DOWAKE;
- timeout(wakeup, (caddr_t) sc, 10 * hz);
- sleep((caddr_t) sc, PRIBIO);
- if (sc->sc_state != ST_RUN) {
- splx(s);
- printf("uda%d: controller hung\n", ui->ui_ctlr);
- return (EIO);
- }
- untimeout(wakeup, (caddr_t) sc);
+#ifdef DIAGNOSTIC
+ if (ubinfo == 0) {
+ printf("%s: uballoc map failed\n", sc->sc_dev.dv_xname);
+ return;
}
+#endif
+ sc->sc_uuda = (struct mscp_pack *) UBAI_ADDR(ubinfo);
- /*
- * Wait for the state to settle
- */
- ra = &ra_info[unit];
- while (ra->ra_state != OPEN && ra->ra_state != OPENRAW &&
- ra->ra_state != CLOSED)
- if (error = tsleep((caddr_t)ra, (PZERO + 1) | PCATCH,
- devopn, 0)) {
- splx(s);
- return (error);
- }
-
- /*
- * If not on line, or we are not sure of the label, reinitialise
- * the drive.
- */
- if ((ui->ui_flags & UNIT_ONLINE) == 0 ||
- (ra->ra_state != OPEN && ra->ra_state != OPENRAW))
- error = uda_rainit(ui, flag);
- splx(s);
- if (error)
- return (error);
+ bzero(&sc->sc_uda, sizeof (struct mscp_pack));
- part = udapart(dev);
- lp = &udalabel[unit];
- if (part >= lp->d_npartitions)
- return (ENXIO);
/*
- * Warn if a partition is opened that overlaps another
- * already open, unless either is the `raw' partition
- * (whole disk).
+ * The only thing that differ UDA's and Tape ctlr's is
+ * their vcid. Beacuse there are no way to determine which
+ * ctlr type it is, we check what is generated and later
+ * set the correct vcid.
*/
-#define RAWPART 2 /* 'c' partition */ /* XXX */
- mask = 1 << part;
- if ((ra->ra_openpart & mask) == 0 && part != RAWPART) {
- pp = &lp->d_partitions[part];
- start = pp->p_offset;
- end = pp->p_offset + pp->p_size;
- for (pp = lp->d_partitions, i = 0;
- i < lp->d_npartitions; pp++, i++) {
- if (pp->p_offset + pp->p_size <= start ||
- pp->p_offset >= end || i == RAWPART)
- continue;
- if (ra->ra_openpart & (1 << i))
- log(LOG_WARNING,
- "ra%d%c: overlaps open partition (%c)\n",
- unit, part + 'a', i + 'a');
- }
- }
- switch (fmt) {
- case S_IFCHR:
- ra->ra_copenpart |= mask;
- break;
- case S_IFBLK:
- ra->ra_bopenpart |= mask;
- break;
- }
- ra->ra_openpart |= mask;
- return (0);
-}
-
-/* ARGSUSED */
-udaclose(dev, flags, fmt)
- dev_t dev;
- int flags, fmt;
-{
- register int unit = udaunit(dev);
- register struct ra_info *ra = &ra_info[unit];
- int s, mask = (1 << udapart(dev));
-/* printf("udaclose\n"); */
- switch (fmt) {
- case S_IFCHR:
- ra->ra_copenpart &= ~mask;
- break;
- case S_IFBLK:
- ra->ra_bopenpart &= ~mask;
- break;
- }
- ra->ra_openpart = ra->ra_copenpart | ra->ra_bopenpart;
+ ma.ma_type = (strcmp(self->dv_cfdata->cf_driver->cd_name,
+ mtc_cd.cd_name) ? MSCPBUS_DISK : MSCPBUS_TAPE);
- /*
- * Should wait for I/O to complete on this partition even if
- * others are open, but wait for work on blkflush().
- */
- if (ra->ra_openpart == 0) {
- s = splbio();
- while (udautab[unit].b_actf)
- sleep((caddr_t)&udautab[unit], PZERO - 1);
- splx(s);
- ra->ra_state = CLOSED;
- ra->ra_wlabel = 0;
- }
- return (0);
+ ma.ma_mc = &uda_mscp_ctlr;
+ ma.ma_type |= MSCPBUS_UDA;
+ ma.ma_uuda = sc->sc_uuda;
+ ma.ma_uda = &sc->sc_uda;
+ ma.ma_softc = &sc->sc_softc;
+ ma.ma_ip = &sc->sc_udadev->udaip;
+ ma.ma_sa = ma.ma_sw = &sc->sc_udadev->udasa;
+ ma.ma_ivec = ivec_no;
+ ma.ma_ctlrnr = (ua->ua_iaddr == 0772150 ? 0 : 1); /* XXX */
+ ma.ma_adapnr = uh->uh_nr;
+ config_found(&sc->sc_dev, &ma, udaprint);
}
/*
- * Initialise a drive. If it is not already, bring it on line,
- * and set a timeout on it in case it fails to respond.
- * When on line, read in the pack label.
+ * Start a transfer if there are free resources available, otherwise
+ * let it go in udaready, forget it for now.
*/
-uda_rainit(ui, flags)
- volatile struct uba_device *ui;
- int flags;
+int
+udago(usc, bp)
+ struct device *usc;
+ struct buf *bp;
{
- register struct uda_softc *sc = &uda_softc[ui->ui_ctlr];
- register struct disklabel *lp;
- register struct mscp *mp;
- register int unit = ui->ui_unit;
- register struct ra_info *ra;
- char *msg, *readdisklabel();
- int s, i;
- volatile int hej;
- void udastrategy();
- extern int cold;
-
- ra = &ra_info[unit];
- if ((ui->ui_flags & UNIT_ONLINE) == 0) {
- mp = mscp_getcp(&sc->sc_mi, MSCP_WAIT);
- mp->mscp_opcode = M_OP_ONLINE;
- mp->mscp_unit = ui->ui_slave;
- mp->mscp_cmdref = (long)&ui->ui_flags;
- *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
- ra->ra_state = WANTOPEN;
- if (!cold)
- s = splbio();
- hej = ((struct udadevice *)ui->ui_addr)->udaip;
-
- if (cold) {
- i = 1000;
- while ((ui->ui_flags & UNIT_ONLINE) == 0) {
- DELAY(10000);
- if (i-- < 0)
- break;
- }
- } else {
- timeout(wakeup, (caddr_t)&ui->ui_flags, 10 * hz);
- sleep((caddr_t)&ui->ui_flags, PSWP + 1);
- splx(s);
- untimeout(wakeup, (caddr_t)&ui->ui_flags);
- }
- if (ra->ra_state != OPENRAW) {
- ra->ra_state = CLOSED;
- wakeup((caddr_t)ra);
- return (EIO);
- }
- }
-
- lp = &udalabel[unit];
- lp->d_secsize = DEV_BSIZE;
- lp->d_secperunit = ra->ra_dsize;
+ struct uda_softc *sc = (void *)usc;
+ struct uba_unit *uu = &sc->sc_unit;
- if (flags & O_NDELAY)
- return (0);
- ra->ra_state = RDLABEL;
/*
- * Set up default sizes until we have the label, or longer
- * if there is none. Set secpercyl, as readdisklabel wants
- * to compute b_cylin (although we do not need it), and set
- * nsectors in case diskerr is called.
+ * If we already are queued for resources, don't call ubaqueue
+ * again. (Then we would trash the wait queue). Just queue the
+ * buf and let the rest be done in udaready.
*/
- lp->d_secpercyl = 1;
- lp->d_npartitions = 1;
- lp->d_secsize = 512;
- lp->d_secperunit = ra->ra_dsize;
- lp->d_nsectors = ra->ra_geom.rg_nsectors;
- lp->d_partitions[0].p_size = lp->d_secperunit;
- lp->d_partitions[0].p_offset = 0;
-
- /*
- * Read pack label.
- */
- if ((msg = readdisklabel(udaminor(unit, 0), udastrategy, lp,NULL))
- != NULL) {
- if (cold)
- printf(": %s", msg);
- else
- log(LOG_ERR, "ra%d: %s", unit, msg);
-#ifdef COMPAT_42
- if (udamaptype(unit, lp))
- ra->ra_state = OPEN;
+ if (sc->sc_bufq.sqh_first)
+ BUFQ_INSERT_TAIL(&sc->sc_bufq, bp)
+ else {
+ if (ubaqueue(uu, bp))
+ mscp_dgo(sc->sc_softc, (UBAI_ADDR(uu->uu_ubinfo) |
+ (UBAI_BDP(uu->uu_ubinfo) << 24)),uu->uu_ubinfo,bp);
else
- ra->ra_state = OPENRAW;
-#else
- ra->ra_state = OPENRAW;
- uda_makefakelabel(ra, lp);
-#endif
- } else
- ra->ra_state = OPEN;
- wakeup((caddr_t)ra);
- return (0);
-}
-
-/*
- * Copy the geometry information for the given ra from a
- * GET UNIT STATUS response. If check, see if it changed.
- */
-uda_rasave(unit, mp, check)
- int unit;
- register struct mscp *mp;
- int check;
-{
- register struct ra_info *ra = &ra_info[unit];
-/* printf("uda_rasave\n"); */
- if (check && ra->ra_mediaid != mp->mscp_guse.guse_mediaid) {
- printf("ra%d: changed types! was %d now %d\n", unit,
- ra->ra_mediaid, mp->mscp_guse.guse_mediaid);
- ra->ra_state = CLOSED; /* ??? */
- }
- /* ra->ra_type = mp->mscp_guse.guse_drivetype; */
- ra->ra_mediaid = mp->mscp_guse.guse_mediaid;
- ra->ra_geom.rg_nsectors = mp->mscp_guse.guse_nspt;
- ra->ra_geom.rg_ngroups = mp->mscp_guse.guse_group;
- ra->ra_geom.rg_ngpc = mp->mscp_guse.guse_ngpc;
- ra->ra_geom.rg_ntracks = ra->ra_geom.rg_ngroups * ra->ra_geom.rg_ngpc;
- /* ra_geom.rg_ncyl cannot be computed until we have ra_dsize */
-#ifdef notyet
- ra->ra_geom.rg_rctsize = mp->mscp_guse.guse_rctsize;
- ra->ra_geom.rg_rbns = mp->mscp_guse.guse_nrpt;
- ra->ra_geom.rg_nrct = mp->mscp_guse.guse_nrct;
-#endif
-}
-
-/*
- * Queue a transfer request, and if possible, hand it to the controller.
- *
- * This routine is broken into two so that the internal version
- * udastrat1() can be called by the (nonexistent, as yet) bad block
- * revectoring routine.
- */
-void
-udastrategy(bp)
- register struct buf *bp;
-{
- register int unit;
- register struct uba_device *ui;
- register struct ra_info *ra;
- struct partition *pp;
- int p;
- daddr_t sz, maxsz;
-/* printf("udastrategy\n"); */
- /*
- * Make sure this is a reasonable drive to use.
- */
- if ((unit = udaunit(bp->b_dev)) >= NRA ||
- (ui = udadinfo[unit]) == NULL || ui->ui_alive == 0 ||
- (ra = &ra_info[unit])->ra_state == CLOSED) {
- bp->b_error = ENXIO;
- goto bad;
- }
-
- /*
- * If drive is open `raw' or reading label, let it at it.
- */
- if (ra->ra_state < OPEN) {
- udastrat1(bp);
- return;
+ BUFQ_INSERT_TAIL(&sc->sc_bufq, bp)
}
- p = udapart(bp->b_dev);
- if ((ra->ra_openpart & (1 << p)) == 0) {
- bp->b_error = ENODEV;
- goto bad;
- }
-
- /*
- * Determine the size of the transfer, and make sure it is
- * within the boundaries of the partition.
- */
- pp = &udalabel[unit].d_partitions[p];
- maxsz = pp->p_size;
- if (pp->p_offset + pp->p_size > ra->ra_dsize)
- maxsz = ra->ra_dsize - pp->p_offset;
- sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
- if (bp->b_blkno + pp->p_offset <= LABELSECTOR &&
-#if LABELSECTOR != 0
- bp->b_blkno + pp->p_offset + sz > LABELSECTOR &&
-#endif
- (bp->b_flags & B_READ) == 0 && ra->ra_wlabel == 0) {
- bp->b_error = EROFS;
- goto bad;
- }
- if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
- /* if exactly at end of disk, return an EOF */
- if (bp->b_blkno == maxsz) {
- bp->b_resid = bp->b_bcount;
- biodone(bp);
- return;
- }
- /* or truncate if part of it fits */
- sz = maxsz - bp->b_blkno;
- if (sz <= 0) {
- bp->b_error = EINVAL; /* or hang it up */
- goto bad;
- }
- bp->b_bcount = sz << DEV_BSHIFT;
- }
- udastrat1(bp);
- return;
-bad:
- bp->b_flags |= B_ERROR;
- biodone(bp);
+
+ return 0;
}
/*
- * Work routine for udastrategy.
+ * Called if we have been blocked for resources, and resources
+ * have been freed again. Return 1 if we could start all
+ * transfers again, 0 if we still are waiting.
*/
-udastrat1(bp)
- register struct buf *bp;
-{
- register int unit = udaunit(bp->b_dev);
- register struct uba_ctlr *um;
- register struct buf *dp;
- struct uba_device *ui;
- int s = splbio();
-/* printf("udastrat1\n"); */
- /*
- * Append the buffer to the drive queue, and if it is not
- * already there, the drive to the controller queue. (However,
- * if the drive queue is marked to be requeued, we must be
- * awaiting an on line or get unit status command; in this
- * case, leave it off the controller queue.)
- */
- um = (ui = udadinfo[unit])->ui_mi;
- dp = &udautab[unit];
- MSCP_APPEND(bp, dp, b_actf);
- if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) {
- MSCP_APPEND(dp, &um->um_tab, b_hash.le_next);
- dp->b_active++;
- }
-/* Was: MSCP_APPEND(bp, dp, av_forw);
- if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) {
- MSCP_APPEND(dp, &um->um_tab, b_forw);
- dp->b_active++;
- }
-*/
- /*
- * Start activity on the controller. Note that unlike other
- * Unibus drivers, we must always do this, not just when the
- * controller is not active.
- */
- udastart(um);
- splx(s);
-}
-
-int
-udaread(dev, uio)
- dev_t dev;
- struct uio *uio;
-{
-
- return (physio(udastrategy, NULL, dev, B_READ, minphys, uio));
-}
-
int
-udawrite(dev, uio)
- dev_t dev;
- struct uio *uio;
+udaready(uu)
+ struct uba_unit *uu;
{
+ struct uda_softc *sc = uu->uu_softc;
+ struct buf *bp;
- return (physio(udastrategy, NULL, dev, B_WRITE, minphys, uio));
-}
-
-/*
- * Start up whatever transfers we can find.
- * Note that udastart() must be called at splbio().
- */
-udastart(um)
- register struct uba_ctlr *um;
-{
- volatile struct uda_softc *sc = &uda_softc[um->um_ctlr];
- register struct buf *bp, *dp;
- register struct mscp *mp;
- struct uba_device *ui;
- volatile struct udadevice *udaddr;
- struct partition *pp;
- int sz;
- volatile int i;
-/* printf("udastart\n"); */
-#ifdef lint
- i = 0; i = i;
-#endif
- /*
- * If it is not running, try (again and again...) to initialise
- * it. If it is currently initialising just ignore it for now.
- */
- if (sc->sc_state != ST_RUN) {
- if (sc->sc_state == ST_IDLE && udainit(um->um_ctlr))
- printf("uda%d: still hung\n", um->um_ctlr);
- return;
- }
-
- /*
- * If um_cmd is nonzero, this controller is on the Unibus
- * resource wait queue. It will not help to try more requests;
- * instead, when the Unibus unblocks and calls udadgo(), we
- * will call udastart() again.
- */
- if (um->um_cmd)
- return;
-
- sc->sc_flags |= SC_INSTART;
- udaddr = (struct udadevice *) um->um_addr;
-
-loop:
- /*
- * Service the drive at the head of the queue. It may not
- * need anything, in which case it might be shutting down
- * in udaclose().
- */
- if ((dp = um->um_tab.b_actf) == NULL)
- goto out;
- if ((bp = dp->b_actf) == NULL) {
- dp->b_active = 0;
- um->um_tab.b_actf = dp->b_hash.le_next;
-/* Was: um->um_tab.b_actf = dp->b_forw; */
- if (ra_info[dp - udautab].ra_openpart == 0)
- wakeup((caddr_t)dp); /* finish close protocol */
- goto loop;
- }
-
- if (udaddr->udasa & UDA_ERR) { /* ctlr fatal error */
- udasaerror(um, 1);
- goto out;
- }
-
- /*
- * Get an MSCP packet, then figure out what to do. If
- * we cannot get a command packet, the command ring may
- * be too small: We should have at least as many command
- * packets as credits, for best performance.
- */
- if ((mp = mscp_getcp((void*)&sc->sc_mi, MSCP_DONTWAIT)) == NULL) {
- if (sc->sc_mi.mi_credits > MSCP_MINCREDITS &&
- (sc->sc_flags & SC_GRIPED) == 0) {
- log(LOG_NOTICE, "uda%d: command ring too small\n",
- um->um_ctlr);
- sc->sc_flags |= SC_GRIPED;/* complain only once */
- }
- goto out;
- }
-
- /*
- * Bring the drive on line if it is not already. Get its status
- * if we do not already have it. Otherwise just start the transfer.
- */
- ui = udadinfo[udaunit(bp->b_dev)];
- if ((ui->ui_flags & UNIT_ONLINE) == 0) {
- mp->mscp_opcode = M_OP_ONLINE;
- goto common;
- }
- if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) {
- mp->mscp_opcode = M_OP_GETUNITST;
-common:
-if (ui->ui_flags & UNIT_REQUEUE) panic("udastart");
- /*
- * Take the drive off the controller queue. When the
- * command finishes, make sure the drive is requeued.
- */
- um->um_tab.b_actf = dp->b_hash.le_next;
-/* Was: um->um_tab.b_actf = dp->b_forw; */
- dp->b_active = 0;
- ui->ui_flags |= UNIT_REQUEUE;
- mp->mscp_unit = ui->ui_slave;
- *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
- sc->sc_flags |= SC_STARTPOLL;
-#ifdef POLLSTATS
- sc->sc_ncmd++;
-#endif
- goto loop;
- }
-
- pp = &udalabel[ui->ui_unit].d_partitions[udapart(bp->b_dev)];
- mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE;
- mp->mscp_unit = ui->ui_slave;
- mp->mscp_seq.seq_lbn = bp->b_blkno + pp->p_offset;
- sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
- mp->mscp_seq.seq_bytecount = bp->b_blkno + sz > pp->p_size ?
- (pp->p_size - bp->b_blkno) >> DEV_BSHIFT : bp->b_bcount;
- /* mscp_cmdref is filled in by mscp_go() */
-
- /*
- * Drop the packet pointer into the `command' field so udadgo()
- * can tell what to start. If ubago returns 1, we can do another
- * transfer. If not, um_cmd will still point at mp, so we will
- * know that we are waiting for resources.
- */
- um->um_cmd = (int)mp;
- if (ubago(ui))
- goto loop;
-
- /*
- * All done, or blocked in ubago(). If we managed to
- * issue some commands, start up the beast.
- */
-out:
- if (sc->sc_flags & SC_STARTPOLL) {
-#ifdef POLLSTATS
- udastats.cmd[sc->sc_ncmd]++;
- sc->sc_ncmd = 0;
-#endif
- i = ((struct udadevice *)um->um_addr)->udaip;
+ while ((bp = sc->sc_bufq.sqh_first)) {
+ if (ubaqueue(uu, bp)) {
+ BUFQ_REMOVE_HEAD(&sc->sc_bufq, bp);
+ mscp_dgo(sc->sc_softc, (UBAI_ADDR(uu->uu_ubinfo) |
+ (UBAI_BDP(uu->uu_ubinfo) << 24)),uu->uu_ubinfo,bp);
+ } else
+ return 0;
}
- sc->sc_flags &= ~(SC_INSTART | SC_STARTPOLL);
-}
-
-/*
- * Start a transfer.
- *
- * If we are not called from within udastart(), we must have been
- * blocked, so call udastart to do more requests (if any). If
- * this calls us again immediately we will not recurse, because
- * that time we will be in udastart(). Clever....
- */
-void
-udadgo(um)
- register struct uba_ctlr *um;
-{
- struct uda_softc *sc = &uda_softc[um->um_ctlr];
- struct mscp *mp = (struct mscp *)um->um_cmd;
-/* printf("udago\n"); */
- um->um_tab.b_active++; /* another transfer going */
-
- /*
- * Fill in the MSCP packet and move the buffer to the
- * I/O wait queue. Mark the controller as no longer on
- * the resource queue, and remember to initiate polling.
- */
- mp->mscp_seq.seq_buffer = UBAI_ADDR(um->um_ubinfo) |
- (UBAI_BDP(um->um_ubinfo) << 24);
- mscp_go(&sc->sc_mi, mp, um->um_ubinfo);
- um->um_cmd = 0;
- um->um_ubinfo = 0; /* tyke it awye */
- sc->sc_flags |= SC_STARTPOLL;
-#ifdef POLLSTATS
- sc->sc_ncmd++;
-#endif
- if ((sc->sc_flags & SC_INSTART) == 0)
- udastart(um);
-}
-
-void
-udaiodone(mi, bp, info)
- register struct mscp_info *mi;
- struct buf *bp;
- int info;
-{
- register struct uba_ctlr *um = udaminfo[mi->mi_ctlr];
-/* printf("udaiodone\n"); */
- um->um_ubinfo = info;
- ubadone(um);
- biodone(bp);
- if (um->um_bdp && mi->mi_wtab.b_actf == &mi->mi_wtab)
- ubarelse(um->um_ubanum, &um->um_bdp);
-/* Was: if (um->um_bdp && mi->mi_wtab.av_forw == &mi->mi_wtab)
- ubarelse(um->um_ubanum, &um->um_bdp); */
- um->um_tab.b_active--; /* another transfer done */
+ return 1;
}
static struct saerr {
@@ -1414,24 +385,26 @@ static struct saerr {
* If the error bit was set in the controller status register, gripe,
* then (optionally) reset the controller and requeue pending transfers.
*/
-udasaerror(um, doreset)
- register struct uba_ctlr *um;
+void
+udasaerror(usc, doreset)
+ struct device *usc;
int doreset;
{
- register int code = ((struct udadevice *)um->um_addr)->udasa;
+ struct uda_softc *sc = (void *)usc;
+ register int code = sc->sc_udadev->udasa;
register struct saerr *e;
-/*printf("udasaerror\n"); */
- if ((code & UDA_ERR) == 0)
+
+ if ((code & MP_ERR) == 0)
return;
for (e = saerr; e->code; e++)
if (e->code == code)
break;
- printf("uda%d: controller error, sa=0%o (%s%s)\n",
- um->um_ctlr, code, e->desc + 1,
+ printf("%s: controller error, sa=0%o (%s%s)\n",
+ sc->sc_dev.dv_xname, code, e->desc + 1,
*e->desc == 'E' ? " error" : "");
if (doreset) {
- mscp_requeue(&uda_softc[um->um_ctlr].sc_mi);
- (void) udainit(um->um_ctlr);
+ mscp_requeue(sc->sc_softc);
+/* (void) udainit(sc); XXX */
}
}
@@ -1440,1034 +413,110 @@ udasaerror(um, doreset)
* continue initialisation, or acknowledge command and response
* interrupts, and process responses.
*/
-void
+static void
udaintr(ctlr)
int ctlr;
{
- struct uba_ctlr *um = udaminfo[ctlr];
- struct uda_softc *sc = &uda_softc[ctlr];
- volatile struct udadevice *udaddr = (struct udadevice *)um->um_addr;
- struct uda *ud;
- struct mscp *mp;
- volatile int i, wait_status;
- extern int cpu_type;
+ intr(uda_cd.cd_devs[ctlr]);
+}
+
+static void
+mtcintr(ctlr)
+ int ctlr;
+{
+ intr(mtc_cd.cd_devs[ctlr]);
+}
+
+static void
+intr(sc)
+ struct uda_softc *sc;
+{
+ volatile struct udadevice *udaddr = sc->sc_udadev;
+ struct uba_softc *uh;
+ struct mscp_pack *ud;
#ifdef QBA
- if(cpunumber == VAX_78032)
+ if(vax_cputype == VAX_TYP_UV2)
splx(sc->sc_ipl); /* Qbus interrupt protocol is odd */
#endif
sc->sc_wticks = 0; /* reset interrupt watchdog */
- /*
- * Combinations during steps 1, 2, and 3: STEPnMASK
- * corresponds to which bits should be tested;
- * STEPnGOOD corresponds to the pattern that should
- * appear after the interrupt from STEPn initialisation.
- * All steps test the bits in ALLSTEPS.
- */
-
- switch (sc->sc_state) {
-
- case ST_IDLE:
- /*
- * Ignore unsolicited interrupts.
- */
- log(LOG_WARNING, "uda%d: stray intr\n", ctlr);
- return;
-
- case ST_STEP1:
- /*
- * Begin step two initialisation.
- */
- i = 0;
- Wait_step(STEP1MASK, STEP1GOOD, wait_status);
- if (!wait_status) {
-initfailed:
- printf("uda%d: init step %d failed, sa=%b\n",
- ctlr, i, udaddr->udasa, udasr_bits);
- udasaerror(um, 0);
- sc->sc_state = ST_IDLE;
- if (sc->sc_flags & SC_DOWAKE) {
- sc->sc_flags &= ~SC_DOWAKE;
- wakeup((caddr_t)sc);
- }
- return;
- }
- udaddr->udasa = (int)&sc->sc_uuda->uda_ca.ca_rspdsc[0] |
- (MACHID(cpu_type) == VAX_780 || MACHID(cpu_type)
- == VAX_8600 ? UDA_PI : 0);
- sc->sc_state = ST_STEP2;
- return;
-
- case ST_STEP2:
- /*
- * Begin step 3 initialisation.
- */
- i = 2;
- Wait_step(STEP2MASK, STEP2GOOD, wait_status);
- if (!wait_status)
- goto initfailed;
-
- udaddr->udasa = ((int)&sc->sc_uuda->uda_ca.ca_rspdsc[0]) >> 16;
- sc->sc_state = ST_STEP3;
- return;
-
- case ST_STEP3:
- /*
- * Set controller characteristics (finish initialisation).
- */
- i = 3;
- Wait_step(STEP3MASK, STEP3GOOD, wait_status);
- if (!wait_status)
- goto initfailed;
-
- i = udaddr->udasa & 0xff;
- if (i != sc->sc_micro) {
- sc->sc_micro = i;
- printf("uda%d: version %d model %d\n",
- ctlr, i & 0xf, i >> 4);
- }
-
- /*
- * Present the burst size, then remove it. Why this
- * should be done this way, I have no idea.
- *
- * Note that this assumes udaburst[ctlr] > 0.
- */
- udaddr->udasa = UDA_GO | (udaburst[ctlr] - 1) << 2;
- udaddr->udasa = UDA_GO;
- printf("uda%d: DMA burst size set to %d\n",
- ctlr, udaburst[ctlr]);
-
- udainitds(ctlr); /* initialise data structures */
-
- /*
- * Before we can get a command packet, we need some
- * credits. Fake some up to keep mscp_getcp() happy,
- * get a packet, and cancel all credits (the right
- * number should come back in the response to the
- * SCC packet).
- */
- sc->sc_mi.mi_credits = MSCP_MINCREDITS + 1;
- mp = mscp_getcp(&sc->sc_mi, MSCP_DONTWAIT);
- if (mp == NULL) /* `cannot happen' */
- panic("udaintr");
- sc->sc_mi.mi_credits = 0;
- mp->mscp_opcode = M_OP_SETCTLRC;
- mp->mscp_unit = 0;
- mp->mscp_sccc.sccc_ctlrflags = M_CF_ATTN | M_CF_MISC |
- M_CF_THIS;
- *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
- i = udaddr->udaip;
- sc->sc_state = ST_SETCHAR;
- return;
-
- case ST_SETCHAR:
- case ST_RUN:
- /*
- * Handle Set Ctlr Characteristics responses and operational
- * responses (via mscp_dorsp).
- */
- break;
-
- default:
- printf("uda%d: driver bug, state %d\n", ctlr, sc->sc_state);
- panic("udastate");
- }
-
- if (udaddr->udasa & UDA_ERR) { /* ctlr fatal error */
- udasaerror(um, 1);
+ if (udaddr->udasa & MP_ERR) { /* ctlr fatal error */
+ udasaerror(&sc->sc_dev, 1);
return;
}
-
ud = &sc->sc_uda;
-
/*
* Handle buffer purge requests.
*/
- if (ud->uda_ca.ca_bdp) {
- UBAPURGE(um->um_hd->uh_uba, ud->uda_ca.ca_bdp);
- ud->uda_ca.ca_bdp = 0;
+ uh = (void *)sc->sc_dev.dv_parent;
+ if (ud->mp_ca.ca_bdp) {
+ if (uh->uh_ubapurge)
+ (*uh->uh_ubapurge)(uh, ud->mp_ca.ca_bdp);
+ ud->mp_ca.ca_bdp = 0;
udaddr->udasa = 0; /* signal purge complete */
}
- /*
- * Check for response and command ring transitions.
- */
- if (ud->uda_ca.ca_rspint) {
- ud->uda_ca.ca_rspint = 0;
- mscp_dorsp(&sc->sc_mi);
- }
- if (ud->uda_ca.ca_cmdint) {
- ud->uda_ca.ca_cmdint = 0;
- MSCP_DOCMD(&sc->sc_mi);
- }
- udastart(um);
-}
-
-/*
- * Initialise the various data structures that control the UDA50.
- */
-udainitds(ctlr)
- int ctlr;
-{
- register struct uda *uud = uda_softc[ctlr].sc_uuda;
- register struct uda *ud = &uda_softc[ctlr].sc_uda;
- register struct mscp *mp;
- register int i;
-/* printf("udainitds\n"); */
- for (i = 0, mp = ud->uda_rsp; i < NRSP; i++, mp++) {
- ud->uda_ca.ca_rspdsc[i] = MSCP_OWN | MSCP_INT |
- (long)&uud->uda_rsp[i].mscp_cmdref;
- mp->mscp_addr = &ud->uda_ca.ca_rspdsc[i];
- mp->mscp_msglen = MSCP_MSGLEN;
- }
- for (i = 0, mp = ud->uda_cmd; i < NCMD; i++, mp++) {
- ud->uda_ca.ca_cmddsc[i] = MSCP_INT |
- (long)&uud->uda_cmd[i].mscp_cmdref;
- mp->mscp_addr = &ud->uda_ca.ca_cmddsc[i];
- mp->mscp_msglen = MSCP_MSGLEN;
- }
-}
-
-/*
- * Handle an error datagram.
- */
-void
-udadgram(mi, mp)
- struct mscp_info *mi;
- struct mscp *mp;
-{
-/* printf("udadgram\n"); */
- mscp_decodeerror(mi->mi_md->md_mname, mi->mi_ctlr, mp);
- /*
- * SDI status information bytes 10 and 11 are the microprocessor
- * error code and front panel code respectively. These vary per
- * drive type and are printed purely for field service information.
- */
- if (mp->mscp_format == M_FM_SDI)
- printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
- mp->mscp_erd.erd_sdistat[10],
- mp->mscp_erd.erd_sdistat[11]);
-}
-
-/*
- * The Set Controller Characteristics command finished.
- * Record the new state of the controller.
- */
-void
-udactlrdone(mi, mp)
- register struct mscp_info *mi;
- struct mscp *mp;
-{
- register struct uda_softc *sc = &uda_softc[mi->mi_ctlr];
-/* printf("udactlrdone\n"); */
- if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)
- sc->sc_state = ST_RUN;
- else {
- printf("uda%d: SETCTLRC failed: ",
- mi->mi_ctlr, mp->mscp_status);
- mscp_printevent(mp);
- sc->sc_state = ST_IDLE;
- }
- if (sc->sc_flags & SC_DOWAKE) {
- sc->sc_flags &= ~SC_DOWAKE;
- wakeup((caddr_t)sc);
- }
-}
-
-/*
- * Received a response from an as-yet unconfigured drive. Configure it
- * in, if possible.
- */
-udaunconf(mi, mp)
- struct mscp_info *mi;
- register struct mscp *mp;
-{
-/* printf("udaunconf\n"); */
- /*
- * If it is a slave response, copy it to udaslavereply for
- * udaslave() to look at.
- */
- if (mp->mscp_opcode == (M_OP_GETUNITST | M_OP_END) &&
- (uda_softc[mi->mi_ctlr].sc_flags & SC_INSLAVE) != 0) {
- bcopy(mp, &udaslavereply, sizeof(struct mscp));
-/* udaslavereply = *mp; */
- return (MSCP_DONE);
- }
-
- /*
- * Otherwise, it had better be an available attention response.
- */
- if (mp->mscp_opcode != M_OP_AVAILATTN)
- return (MSCP_FAILED);
-
- /* do what autoconf does */
- return (MSCP_FAILED); /* not yet, arwhite, not yet */
-}
-
-/*
- * A drive came on line. Check its type and size. Return DONE if
- * we think the drive is truly on line. In any case, awaken anyone
- * sleeping on the drive on-line-ness.
- */
-udaonline(ui, mp)
- register struct uba_device *ui;
- struct mscp *mp;
-{
- register struct ra_info *ra = &ra_info[ui->ui_unit];
-/* printf("udaonline\n"); */
- wakeup((caddr_t)&ui->ui_flags);
- if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
- if (!cold)
- printf("uda%d: ra%d", ui->ui_ctlr, ui->ui_unit);
- printf(": attempt to bring on line failed: ");
- mscp_printevent(mp);
- ra->ra_state = CLOSED;
- return (MSCP_FAILED);
- }
-
- ra->ra_state = OPENRAW;
- ra->ra_dsize = (daddr_t)mp->mscp_onle.onle_unitsize;
- if (!cold)
- printf("ra%d: uda%d, unit %d, size = %d sectors\n", ui->ui_unit,
- ui->ui_ctlr, mp->mscp_unit, ra->ra_dsize);
- /* can now compute ncyl */
- ra->ra_geom.rg_ncyl = ra->ra_dsize / ra->ra_geom.rg_ntracks /
- ra->ra_geom.rg_nsectors;
- return (MSCP_DONE);
-}
-
-/*
- * We got some (configured) unit's status. Return DONE if it succeeded.
- */
-udagotstatus(ui, mp)
- register struct uba_device *ui;
- register struct mscp *mp;
-{
-/* printf("udagotstatus\n"); */
- if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
- printf("uda%d: attempt to get status for ra%d failed: ",
- ui->ui_ctlr, ui->ui_unit);
- mscp_printevent(mp);
- return (MSCP_FAILED);
- }
- /* record for (future) bad block forwarding and whatever else */
- uda_rasave(ui->ui_unit, mp, 1);
- return (MSCP_DONE);
-}
-
-/*
- * A transfer failed. We get a chance to fix or restart it.
- * Need to write the bad block forwaring code first....
- */
-/*ARGSUSED*/
-udaioerror(ui, mp, bp)
- register struct uba_device *ui;
- register struct mscp *mp;
- struct buf *bp;
-{
-/* printf("udaioerror\n"); */
- if (mp->mscp_flags & M_EF_BBLKR) {
- /*
- * A bad block report. Eventually we will
- * restart this transfer, but for now, just
- * log it and give up.
- */
- log(LOG_ERR, "ra%d: bad block report: %d%s\n",
- ui->ui_unit, mp->mscp_seq.seq_lbn,
- mp->mscp_flags & M_EF_BBLKU ? " + others" : "");
- } else {
- /*
- * What the heck IS a `serious exception' anyway?
- * IT SURE WOULD BE NICE IF DEC SOLD DOCUMENTATION
- * FOR THEIR OWN CONTROLLERS.
- */
- if (mp->mscp_flags & M_EF_SEREX)
- log(LOG_ERR, "ra%d: serious exception reported\n",
- ui->ui_unit);
- }
- return (MSCP_FAILED);
-}
-
-/*
- * A replace operation finished.
- */
-/*ARGSUSED*/
-void
-udareplace(ui, mp)
- struct uba_device *ui;
- struct mscp *mp;
-{
-
- panic("udareplace");
-}
-
-/*
- * A bad block related operation finished.
- */
-/*ARGSUSED*/
-void
-udabb(ui, mp, bp)
- struct uba_device *ui;
- struct mscp *mp;
- struct buf *bp;
-{
-
- panic("udabb");
-}
-
-
-/*
- * I/O controls.
- */
-udaioctl(dev, cmd, data, flag)
- dev_t dev;
- int cmd;
- caddr_t data;
- int flag;
-{
- register int unit = udaunit(dev);
- register struct disklabel *lp;
- register struct ra_info *ra = &ra_info[unit];
- int error = 0;
-/* printf("udaioctl\n"); */
- lp = &udalabel[unit];
-
- switch (cmd) {
-
- case DIOCGDINFO:
- *(struct disklabel *)data = *lp;
- break;
-
- case DIOCGPART:
- ((struct partinfo *)data)->disklab = lp;
- ((struct partinfo *)data)->part =
- &lp->d_partitions[udapart(dev)];
- break;
-
- case DIOCSDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- error = setdisklabel(lp, (struct disklabel *)data,
- (ra->ra_state == OPENRAW) ? 0 : ra->ra_openpart,0);
- break;
-
- case DIOCWLABEL:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else
- ra->ra_wlabel = *(int *)data;
- break;
-
- case DIOCWDINFO:
- if ((flag & FWRITE) == 0)
- error = EBADF;
- else if ((error = setdisklabel(lp, (struct disklabel *)data,
- (ra->ra_state == OPENRAW) ? 0 : ra->ra_openpart,0)) == 0) {
- int wlab;
-
- ra->ra_state = OPEN;
- /* simulate opening partition 0 so write succeeds */
- ra->ra_openpart |= (1 << 0); /* XXX */
- wlab = ra->ra_wlabel;
- ra->ra_wlabel = 1;
- error = writedisklabel(dev, udastrategy, lp,0);
- ra->ra_openpart = ra->ra_copenpart | ra->ra_bopenpart;
- ra->ra_wlabel = wlab;
- }
- break;
-
-#ifdef notyet
- case UDAIOCREPLACE:
- /*
- * Initiate bad block replacement for the given LBN.
- * (Should we allow modifiers?)
- */
- error = EOPNOTSUPP;
- break;
-
- case UDAIOCGMICRO:
- /*
- * Return the microcode revision for the UDA50 running
- * this drive.
- */
- *(int *)data = uda_softc[uddinfo[unit]->ui_ctlr].sc_micro;
- break;
-#endif
-
- default:
- error = ENOTTY;
- break;
- }
- return (error);
+ mscp_intr(sc->sc_softc);
}
/*
* A Unibus reset has occurred on UBA uban. Reinitialise the controller(s)
* on that Unibus, and requeue outstanding I/O.
*/
-udareset(uban)
- int uban;
+void
+udareset(ctlr)
+ int ctlr;
{
- register struct uba_ctlr *um;
- register struct uda_softc *sc;
- register int ctlr;
-/* printf("udareset\n"); */
- for (ctlr = 0, sc = uda_softc; ctlr < NUDA; ctlr++, sc++) {
- if ((um = udaminfo[ctlr]) == NULL || um->um_ubanum != uban ||
- um->um_alive == 0)
- continue;
- printf(" uda%d", ctlr);
-
- /*
- * Our BDP (if any) is gone; our command (if any) is
- * flushed; the device is no longer mapped; and the
- * UDA50 is not yet initialised.
- */
- if (um->um_bdp) {
- printf("<%d>", UBAI_BDP(um->um_bdp));
- um->um_bdp = 0;
- }
- um->um_ubinfo = 0;
- um->um_cmd = 0;
- sc->sc_flags &= ~SC_MAPPED;
- sc->sc_state = ST_IDLE;
-
- /* reset queues and requeue pending transfers */
- mscp_requeue(&sc->sc_mi);
-
- /*
- * If it fails to initialise we will notice later and
- * try again (and again...). Do not call udastart()
- * here; it will be done after the controller finishes
- * initialisation.
- */
- if (udainit(ctlr))
- printf(" (hung)");
- }
+ reset(uda_cd.cd_devs[ctlr]);
}
-/*
- * Watchdog timer: If the controller is active, and no interrupts
- * have occurred for 30 seconds, assume it has gone away.
- */
void
-udawatch()
+mtcreset(ctlr)
+ int ctlr;
{
- register int i;
- register struct uba_ctlr *um;
- register struct uda_softc *sc;
- timeout(udawatch, (caddr_t) 0, hz); /* every second */
- for (i = 0, sc = uda_softc; i < NUDA; i++, sc++) {
- if ((um = udaminfo[i]) == 0 || !um->um_alive)
- continue;
- if (sc->sc_state == ST_IDLE)
- continue;
- if (sc->sc_state == ST_RUN && !um->um_tab.b_active)
- sc->sc_wticks = 0;
- else if (++sc->sc_wticks >= 30) {
- sc->sc_wticks = 0;
- printf("uda%d: lost interrupt\n", i);
- ubareset(um->um_ubanum);
- }
- }
+ reset(mtc_cd.cd_devs[ctlr]);
}
-/*
- * Do a panic dump. We set up the controller for one command packet
- * and one response packet, for which we use `struct uda1'.
- */
-struct uda1 {
- struct uda1ca uda1_ca; /* communications area */
- struct mscp uda1_rsp; /* response packet */
- struct mscp uda1_cmd; /* command packet */
-} uda1;
-
-#define DBSIZE 32 /* dump 16K at a time */
-
-udadump(dev)
- dev_t dev;
+static void
+reset(sc)
+ struct uda_softc *sc;
{
- struct udadevice *udaddr;
- struct uda1 *ud_ubaddr;
- char *start;
- int num, blk, unit, maxsz, blkoff, reg;
- struct partition *pp;
- struct uba_regs *uba;
- struct uba_device *ui;
- struct uda1 *ud;
- struct pte *io;
- int i;
-
- /*
- * Make sure the device is a reasonable place on which to dump.
- */
- unit = udaunit(dev);
- if (unit >= NRA)
- return (ENXIO);
-#define phys(cast, addr) ((cast) ((int)addr & 0x7fffffff))
- ui = phys(struct uba_device *, udadinfo[unit]);
- if (ui == NULL || ui->ui_alive == 0)
- return (ENXIO);
-
- /*
- * Find and initialise the UBA; get the physical address of the
- * device registers, and of communications area and command and
- * response packet.
- */
- uba = phys(struct uba_softc *, ui->ui_hd)->uh_physuba;
- ubainit(ui->ui_hd);
- udaddr = (struct udadevice *)ui->ui_physaddr;
- ud = phys(struct uda1 *, &uda1);
- /*
- * Map the ca+packets into Unibus I/O space so the UDA50 can get
- * at them. Use the registers at the end of the Unibus map (since
- * we will use the registers at the beginning to map the memory
- * we are dumping).
- */
- num = btoc(sizeof(struct uda1)) + 1;
- reg = NUBMREG - num;
- io = (void *)&uba->uba_map[reg];
- for (i = 0; i < num; i++)
- *(int *)io++ = UBAMR_MRV | (btop(ud) + i);
- ud_ubaddr = (struct uda1 *)(((int)ud & PGOFSET) | (reg << 9));
+ printf(" %s", sc->sc_dev.dv_xname);
/*
- * Initialise the controller, with one command and one response
- * packet.
+ * Our BDP (if any) is gone; our command (if any) is
+ * flushed; the device is no longer mapped; and the
+ * UDA50 is not yet initialised.
*/
- udaddr->udaip = 0;
- if (udadumpwait(udaddr, UDA_STEP1))
- return (EFAULT);
- udaddr->udasa = UDA_ERR;
- if (udadumpwait(udaddr, UDA_STEP2))
- return (EFAULT);
- udaddr->udasa = (int)&ud_ubaddr->uda1_ca.ca_rspdsc;
- if (udadumpwait(udaddr, UDA_STEP3))
- return (EFAULT);
- udaddr->udasa = ((int)&ud_ubaddr->uda1_ca.ca_rspdsc) >> 16;
- if (udadumpwait(udaddr, UDA_STEP4))
- return (EFAULT);
- uda_softc[ui->ui_ctlr].sc_micro = udaddr->udasa & 0xff;
- udaddr->udasa = UDA_GO;
-
- /*
- * Set up the command and response descriptor, then set the
- * controller characteristics and bring the drive on line.
- * Note that all uninitialised locations in uda1_cmd are zero.
- */
- ud->uda1_ca.ca_rspdsc = (long)&ud_ubaddr->uda1_rsp.mscp_cmdref;
- ud->uda1_ca.ca_cmddsc = (long)&ud_ubaddr->uda1_cmd.mscp_cmdref;
- /* ud->uda1_cmd.mscp_sccc.sccc_ctlrflags = 0; */
- /* ud->uda1_cmd.mscp_sccc.sccc_version = 0; */
- if (udadumpcmd(M_OP_SETCTLRC, ud, ui))
- return (EFAULT);
- ud->uda1_cmd.mscp_unit = ui->ui_slave;
- if (udadumpcmd(M_OP_ONLINE, ud, ui))
- return (EFAULT);
-
- pp = phys(struct partition *,
- &udalabel[unit].d_partitions[udapart(dev)]);
- maxsz = pp->p_size;
- blkoff = pp->p_offset;
+ if (sc->sc_unit.uu_bdp) {
+ printf("<%d>", UBAI_BDP(sc->sc_unit.uu_bdp));
+ sc->sc_unit.uu_bdp = 0;
+ }
+ sc->sc_unit.uu_ubinfo = 0;
+/* sc->sc_unit.uu_cmd = 0; XXX */
- /*
- * Dump all of physical memory, or as much as will fit in the
- * space provided.
- */
- start = 0;
- printf("Dumpar {r inte implementerade {n :) \n");
- asm("halt");
-/* num = maxfree; */
- if (dumplo + num >= maxsz)
- num = maxsz - dumplo;
- blkoff += dumplo;
+ /* reset queues and requeue pending transfers */
+ mscp_requeue(sc->sc_softc);
/*
- * Write out memory, DBSIZE pages at a time.
- * N.B.: this code depends on the fact that the sector
- * size == the page size.
+ * If it fails to initialise we will notice later and
+ * try again (and again...). Do not call udastart()
+ * here; it will be done after the controller finishes
+ * initialisation.
*/
- while (num > 0) {
- blk = num > DBSIZE ? DBSIZE : num;
- io = (void *)uba->uba_map;
- /*
- * Map in the pages to write, leaving an invalid entry
- * at the end to guard against wild Unibus transfers.
- * Then do the write.
- */
- for (i = 0; i < blk; i++)
- *(int *)io++ = UBAMR_MRV | (btop(start) + i);
- *(int *)io = 0;
- ud->uda1_cmd.mscp_unit = ui->ui_slave;
- ud->uda1_cmd.mscp_seq.seq_lbn = btop(start) + blkoff;
- ud->uda1_cmd.mscp_seq.seq_bytecount = blk << PGSHIFT;
- if (udadumpcmd(M_OP_WRITE, ud, ui))
- return (EIO);
- start += blk << PGSHIFT;
- num -= blk;
- }
- return (0); /* made it! */
+/* XXX if (udainit(sc)) */
+ printf(" (hung)");
}
-/*
- * Wait for some of the bits in `bits' to come on. If the error bit
- * comes on, or ten seconds pass without response, return true (error).
- */
-udadumpwait(udaddr, bits)
- volatile struct udadevice *udaddr;
- register int bits;
-{
- register int timo = todr() + 1000;
-
- while ((udaddr->udasa & bits) == 0) {
- if (udaddr->udasa & UDA_ERR) {
- printf("udasa=%b\ndump ", udaddr->udasa, udasr_bits);
- return (1);
- }
- if (todr() >= timo) {
- printf("timeout\ndump ");
- return (1);
- }
- }
- return (0);
-}
-
-/*
- * Feed a command to the UDA50, wait for its response, and return
- * true iff something went wrong.
- */
-udadumpcmd(op, ud, ui)
- int op;
- register struct uda1 *ud;
- struct uba_device *ui;
-{
- volatile struct udadevice *udaddr;
- volatile int n;
-#define mp (&ud->uda1_rsp)
-
- udaddr = (struct udadevice *)ui->ui_physaddr;
- ud->uda1_cmd.mscp_opcode = op;
- ud->uda1_cmd.mscp_msglen = MSCP_MSGLEN;
- ud->uda1_rsp.mscp_msglen = MSCP_MSGLEN;
- ud->uda1_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT;
- ud->uda1_ca.ca_cmddsc |= MSCP_OWN | MSCP_INT;
- if (udaddr->udasa & UDA_ERR) {
- printf("udasa=%b\ndump ", udaddr->udasa, udasr_bits);
- return (1);
- }
- n = udaddr->udaip;
- n = todr() + 1000;
- for (;;) {
- if (todr() > n) {
- printf("timeout\ndump ");
- return (1);
- }
- if (ud->uda1_ca.ca_cmdint)
- ud->uda1_ca.ca_cmdint = 0;
- if (ud->uda1_ca.ca_rspint == 0)
- continue;
- ud->uda1_ca.ca_rspint = 0;
- if (mp->mscp_opcode == (op | M_OP_END))
- break;
- printf("\n");
- switch (MSCP_MSGTYPE(mp->mscp_msgtc)) {
-
- case MSCPT_SEQ:
- printf("sequential");
- break;
-
- case MSCPT_DATAGRAM:
- mscp_decodeerror("uda", ui->ui_ctlr, mp);
- printf("datagram");
- break;
-
- case MSCPT_CREDITS:
- printf("credits");
- break;
-
- case MSCPT_MAINTENANCE:
- printf("maintenance");
- break;
-
- default:
- printf("unknown (type 0x%x)",
- MSCP_MSGTYPE(mp->mscp_msgtc));
- break;
- }
- printf(" ignored\ndump ");
- ud->uda1_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT;
- }
- if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
- printf("error: op 0x%x => 0x%x status 0x%x\ndump ", op,
- mp->mscp_opcode, mp->mscp_status);
- return (1);
- }
- return (0);
-#undef mp
-}
-
-/*
- * Return the size of a partition, if known, or -1 if not.
- */
-udasize(dev)
- dev_t dev;
-{
- register int unit = udaunit(dev);
- register struct uba_device *ui;
-
- if (unit >= NRA || (ui = udadinfo[unit]) == NULL ||
- ui->ui_alive == 0 || (ui->ui_flags & UNIT_ONLINE) == 0 ||
- ra_info[unit].ra_state != OPEN)
- return (-1);
- return ((int)udalabel[unit].d_partitions[udapart(dev)].p_size);
-}
-
-#ifdef COMPAT_42
-/*
- * Tables mapping unlabelled drives.
- */
-struct size {
- daddr_t nblocks;
- daddr_t blkoff;
-} ra60_sizes[8] = {
- 15884, 0, /* A=sectors 0 thru 15883 */
- 33440, 15884, /* B=sectors 15884 thru 49323 */
- 400176, 0, /* C=sectors 0 thru 400175 */
- 82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */
- 268772, 131404, /* 4.2 H => E=sectors 131404 thru 400175 */
- 350852, 49324, /* F=sectors 49324 thru 400175 */
- 157570, 242606, /* UCB G => G=sectors 242606 thru 400175 */
- 193282, 49324, /* UCB H => H=sectors 49324 thru 242605 */
-}, ra70_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 33440, 15972, /* B=blk 15972 thru 49323 */
- -1, 0, /* C=blk 0 thru end */
- 15884, 341220, /* D=blk 341220 thru 357103 */
- 55936, 357192, /* E=blk 357192 thru 413127 */
- -1, 413457, /* F=blk 413457 thru end */
- -1, 341220, /* G=blk 341220 thru end */
- 291346, 49731, /* H=blk 49731 thru 341076 */
-}, ra80_sizes[8] = {
- 15884, 0, /* A=sectors 0 thru 15883 */
- 33440, 15884, /* B=sectors 15884 thru 49323 */
- 242606, 0, /* C=sectors 0 thru 242605 */
- 0, 0, /* D=unused */
- 193282, 49324, /* UCB H => E=sectors 49324 thru 242605 */
- 82080, 49324, /* 4.2 G => F=sectors 49324 thru 131403 */
- 192696, 49910, /* G=sectors 49910 thru 242605 */
- 111202, 131404, /* 4.2 H => H=sectors 131404 thru 242605 */
-}, ra81_sizes[8] ={
-/*
- * These are the new standard partition sizes for ra81's.
- * An RA_COMPAT system is compiled with D, E, and F corresponding
- * to the 4.2 partitions for G, H, and F respectively.
- */
-#ifndef UCBRA
- 15884, 0, /* A=sectors 0 thru 15883 */
- 66880, 16422, /* B=sectors 16422 thru 83301 */
- 891072, 0, /* C=sectors 0 thru 891071 */
-#ifdef RA_COMPAT
- 82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */
- 759668, 131404, /* 4.2 H => E=sectors 131404 thru 891071 */
- 478582, 412490, /* 4.2 F => F=sectors 412490 thru 891071 */
-#else
- 15884, 375564, /* D=sectors 375564 thru 391447 */
- 307200, 391986, /* E=sectors 391986 thru 699185 */
- 191352, 699720, /* F=sectors 699720 thru 891071 */
-#endif RA_COMPAT
- 515508, 375564, /* G=sectors 375564 thru 891071 */
- 291346, 83538, /* H=sectors 83538 thru 374883 */
-
-/*
- * These partitions correspond to the sizes used by sites at Berkeley,
- * and by those sites that have received copies of the Berkeley driver
- * with deltas 6.2 or greater (11/15/83).
- */
-#else UCBRA
-
- 15884, 0, /* A=sectors 0 thru 15883 */
- 33440, 15884, /* B=sectors 15884 thru 49323 */
- 891072, 0, /* C=sectors 0 thru 891071 */
- 15884, 242606, /* D=sectors 242606 thru 258489 */
- 307200, 258490, /* E=sectors 258490 thru 565689 */
- 325382, 565690, /* F=sectors 565690 thru 891071 */
- 648466, 242606, /* G=sectors 242606 thru 891071 */
- 193282, 49324, /* H=sectors 49324 thru 242605 */
-
-#endif UCBRA
-}, ra82_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 66880, 16245, /* B=blk 16245 thru 83124 */
- -1, 0, /* C=blk 0 thru end */
- 15884, 375345, /* D=blk 375345 thru 391228 */
- 307200, 391590, /* E=blk 391590 thru 698789 */
- -1, 699390, /* F=blk 699390 thru end */
- -1, 375345, /* G=blk 375345 thru end */
- 291346, 83790, /* H=blk 83790 thru 375135 */
-}, ra90_sizes[8] = {
- 15884, 0, /* A=sectors 0 thru 15883 */
- 66880, 16146, /* B=sectors 16146 thru 83025 */
- 2376153,0, /* C=sectors 0 thru 2376152 */
- 15884, 374946, /* D=sectors 374946 thru 390829 */
- 307200, 391092, /* E=sectors 391092 thru 698291 */
- 1677390,698763, /* F=sectors 698763 thru 2376152 */
- 2001207,374946, /* G=sectors 374946 thru 2376152 */
- 291346, 83421, /* H=sectors 83421 thru 374766 */
-}, ra92_sizes[8] = {
- 15884, 0, /* A=sectors 0 thru 15883 */
- 66880, 16146, /* B=sectors 16146 thru 83025 */
- 2941263,0, /* C=sectors 0 thru 2941262 */
- 15884, 374946, /* D=sectors 374946 thru 390829 */
- 307200, 391092, /* E=sectors 391092 thru 698291 */
- 2242500,698763, /* F=sectors 698763 thru 2941262 */
- 2566317,374946, /* G=sectors 374946 thru 2941262 */
- 291346, 83421, /* H=sectors 83421 thru 374766 */
-}, rc25_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 10032, 15884, /* B=blk 15884 thru 49323 */
- -1, 0, /* C=blk 0 thru end */
- 0, 0, /* D=blk 340670 thru 356553 */
- 0, 0, /* E=blk 356554 thru 412489 */
- 0, 0, /* F=blk 412490 thru end */
- -1, 25916, /* G=blk 49324 thru 131403 */
- 0, 0, /* H=blk 131404 thru end */
-}, rd52_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 9766, 15884, /* B=blk 15884 thru 25649 */
- -1, 0, /* C=blk 0 thru end */
- 0, 0, /* D=unused */
- 0, 0, /* E=unused */
- 0, 0, /* F=unused */
- -1, 25650, /* G=blk 25650 thru end */
- 0, 0, /* H=unused */
-}, rd53_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 33440, 15884, /* B=blk 15884 thru 49323 */
- -1, 0, /* C=blk 0 thru end */
- 0, 0, /* D=unused */
- 33440, 0, /* E=blk 0 thru 33439 */
- -1, 33440, /* F=blk 33440 thru end */
- -1, 49324, /* G=blk 49324 thru end */
- -1, 15884, /* H=blk 15884 thru end */
-}, rd54_sizes[8] = {
- 15884, 0, /* A=blk 0 thru 15883 */
- 33440, 15884, /* B=blk 15884 thru 49323 */
- -1, 0, /* C=blk 0 thru end */
- 130938, 49324, /* D=blk 49324 thru 180261 */
- 130938, 180262, /* E=blk 180262 thru 311199 (end) */
- 0, 0, /* F=unused */
- 261876, 49324, /* G=blk 49324 thru 311199 (end) */
- 0, 0, /* H=unused */
-}, rx50_sizes[8] = {
- 800, 0, /* A=blk 0 thru 799 */
- 0, 0,
- -1, 0, /* C=blk 0 thru end */
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
-};
-
-/*
- * Media ID decoding table.
- */
-struct udatypes {
- u_long ut_id; /* media drive ID */
- char *ut_name; /* drive type name */
- struct size *ut_sizes; /* partition tables */
- int ut_nsectors, ut_ntracks, ut_ncylinders;
-} udatypes[] = {
- { MSCP_MKDRIVE2('R', 'A', 60), "ra60", ra60_sizes, 42, 4, 2382 },
- { MSCP_MKDRIVE2('R', 'A', 70), "ra70", ra70_sizes, 33, 11, 1507 },
- { MSCP_MKDRIVE2('R', 'A', 80), "ra80", ra80_sizes, 31, 14, 559 },
- { MSCP_MKDRIVE2('R', 'A', 81), "ra81", ra81_sizes, 51, 14, 1248 },
- { MSCP_MKDRIVE2('R', 'A', 82), "ra82", ra82_sizes, 57, 15, 1423 },
- { MSCP_MKDRIVE2('R', 'A', 90), "ra90", ra90_sizes, 69, 13, 2649 },
- { MSCP_MKDRIVE2('R', 'A', 92), "ra92", ra92_sizes, 69, 13, 3279 },
- { MSCP_MKDRIVE2('R', 'C', 25), "rc25-removable",
- rc25_sizes, 42, 4, 302 },
- { MSCP_MKDRIVE3('R', 'C', 'F', 25), "rc25-fixed",
- rc25_sizes, 42, 4, 302 },
- { MSCP_MKDRIVE2('R', 'D', 52), "rd52", rd52_sizes, 18, 7, 480 },
- { MSCP_MKDRIVE2('R', 'D', 53), "rd53", rd53_sizes, 17, 8, 1019 },
- { MSCP_MKDRIVE2('R', 'D', 32), "rd54-from-rd32",
- rd54_sizes, 17, 15, 1220 },
- { MSCP_MKDRIVE2('R', 'D', 54), "rd54", rd54_sizes, 17, 15, 1220 },
- { MSCP_MKDRIVE2('R', 'X', 50), "rx50", rx50_sizes, 10, 1, 80 },
- 0
-};
-
-#define NTYPES (sizeof(udatypes) / sizeof(*udatypes))
-
-udamaptype(unit, lp)
- int unit;
- register struct disklabel *lp;
+void
+udactlrdone(usc, info)
+ struct device *usc;
+ int info;
{
- register struct udatypes *ut;
- register struct size *sz;
- register struct partition *pp;
- register char *p;
- register int i;
- register struct ra_info *ra = &ra_info[unit];
-
- i = MSCP_MEDIA_DRIVE(ra->ra_mediaid);
- for (ut = udatypes; ut->ut_id; ut++)
- if (ut->ut_id == i &&
- ut->ut_nsectors == ra->ra_geom.rg_nsectors &&
- ut->ut_ntracks == ra->ra_geom.rg_ntracks &&
- ut->ut_ncylinders == ra->ra_geom.rg_ncyl)
- goto found;
-
- /* not one we know; fake up a label for the whole drive */
- uda_makefakelabel(ra, lp);
- i = ra->ra_mediaid; /* print the port type too */
- addlog(": no partition table for %c%c %c%c%c%d, size %d;\n\
-using (s,t,c)=(%d,%d,%d)",
- MSCP_MID_CHAR(4, i), MSCP_MID_CHAR(3, i),
- MSCP_MID_CHAR(2, i), MSCP_MID_CHAR(1, i),
- MSCP_MID_CHAR(0, i), MSCP_MID_NUM(i), lp->d_secperunit,
- lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders);
- if (!cold)
- addlog("\n");
- return (0);
-found:
- p = ut->ut_name;
- for (i = 0; i < sizeof(lp->d_typename) - 1 && *p; i++)
- lp->d_typename[i] = *p++;
- lp->d_typename[i] = 0;
- sz = ut->ut_sizes;
- lp->d_nsectors = ut->ut_nsectors;
- lp->d_ntracks = ut->ut_ntracks;
- lp->d_ncylinders = ut->ut_ncylinders;
- lp->d_npartitions = 8;
- lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
- for (pp = lp->d_partitions; pp < &lp->d_partitions[8]; pp++, sz++) {
- pp->p_offset = sz->blkoff;
- if ((pp->p_size = sz->nblocks) == (u_long)-1)
- pp->p_size = ra->ra_dsize - sz->blkoff;
- }
- return (1);
-}
-#endif /* COMPAT_42 */
+ struct uda_softc *sc = (void *)usc;
-/*
- * Construct a label for a drive from geometry information
- * if we have no better information.
- */
-uda_makefakelabel(ra, lp)
- register struct ra_info *ra;
- register struct disklabel *lp;
-{
- lp->d_nsectors = ra->ra_geom.rg_nsectors;
- lp->d_ntracks = ra->ra_geom.rg_ntracks;
- lp->d_ncylinders = ra->ra_geom.rg_ncyl;
- lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
- bcopy("ra??", lp->d_typename, sizeof("ra??"));
- lp->d_npartitions = 1;
- lp->d_partitions[0].p_offset = 0;
- lp->d_partitions[0].p_size = lp->d_secperunit;
+ /* XXX check if we shall release the BDP */
+ sc->sc_unit.uu_ubinfo = info;
+ ubadone(&sc->sc_unit);
}
diff --git a/sys/arch/vax/uba/udareg.h b/sys/arch/vax/uba/udareg.h
index f6107a49605..ebada167582 100644
--- a/sys/arch/vax/uba/udareg.h
+++ b/sys/arch/vax/uba/udareg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: udareg.h,v 1.2 1994/10/26 08:02:51 cgd Exp $ */
+/* $NetBSD: udareg.h,v 1.3 1996/07/01 21:24:50 ragge Exp $ */
/*
* Copyright (c) 1988 Regents of the University of California.
@@ -54,22 +54,6 @@ struct udadevice {
};
/*
- * Bits in UDA status register during initialisation
- */
-#define UDA_ERR 0x8000 /* error */
-#define UDA_STEP4 0x4000 /* step 4 has started */
-#define UDA_STEP3 0x2000 /* step 3 has started */
-#define UDA_STEP2 0x1000 /* step 2 has started */
-#define UDA_STEP1 0x0800 /* step 1 has started */
-#define UDA_NV 0x0400 /* no host settable interrupt vector */
-#define UDA_QB 0x0200 /* controller supports Q22 bus */
-#define UDA_DI 0x0100 /* controller implements diagnostics */
-#define UDA_IE 0x0080 /* interrupt enable */
-#define UDA_NCNRMASK 0x003f /* in STEP1, bits 0-2=NCMDL2, 3-5=NRSPL2 */
-#define UDA_IVECMASK 0x007f /* in STEP2, bits 0-6 are interruptvec / 4 */
-#define UDA_PI 0x0001 /* host requests adapter purge interrupts */
-
-/*
* Bits in UDA status register after initialisation
*/
#define UDA_GO 0x0001 /* run */
@@ -77,31 +61,3 @@ struct udadevice {
#define UDASR_BITS \
"\20\20ERR\17STEP4\16STEP3\15STEP2\14STEP1\13NV\12QB\11DI\10IE\1GO"
-/*
- * UDA Communications Area. Note that this structure definition
- * requires NRSP and NCMD to be defined already.
- */
-struct udaca {
- short ca_xxx1; /* unused */
- char ca_xxx2; /* unused */
- char ca_bdp; /* BDP to purge */
- short ca_cmdint; /* command ring transition flag */
- short ca_rspint; /* response ring transition flag */
- long ca_rspdsc[NRSP];/* response descriptors */
- long ca_cmddsc[NCMD];/* command descriptors */
-};
-
-/*
- * Simplified routines (e.g., uddump) reprogram the UDA50 for one command
- * and one response at a time; uda1ca is like udaca except that it provides
- * exactly one command and response descriptor.
- */
-struct uda1ca {
- short ca_xxx1;
- char ca_xxx2;
- char ca_bdp;
- short ca_cmdint;
- short ca_rspint;
- long ca_rspdsc;
- long ca_cmddsc;
-};