diff options
Diffstat (limited to 'sys/arch/vax/uba')
-rw-r--r-- | sys/arch/vax/uba/dhu.c | 13 | ||||
-rw-r--r-- | sys/arch/vax/uba/dz.c | 12 | ||||
-rw-r--r-- | sys/arch/vax/uba/qd.c | 3611 | ||||
-rw-r--r-- | sys/arch/vax/uba/qv.c | 1323 | ||||
-rw-r--r-- | sys/arch/vax/uba/tmscp.c | 2211 | ||||
-rw-r--r-- | sys/arch/vax/uba/tmscpreg.h | 120 | ||||
-rw-r--r-- | sys/arch/vax/uba/ts.c | 677 | ||||
-rw-r--r-- | sys/arch/vax/uba/uba.c | 1339 | ||||
-rw-r--r-- | sys/arch/vax/uba/ubareg.h | 241 | ||||
-rw-r--r-- | sys/arch/vax/uba/ubavar.h | 137 | ||||
-rw-r--r-- | sys/arch/vax/uba/uda.c | 2463 | ||||
-rw-r--r-- | sys/arch/vax/uba/udareg.h | 46 |
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 = ¤t_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; -}; |