BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:33:43 +0000 (16:33 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:33:43 +0000 (16:33 -0800)
Work on file usr/src/sys/vaxuba/ad.c
Work on file usr/src/sys/vaxuba/adreg.h
Work on file usr/src/sys/vaxuba/dmf.c
Work on file usr/src/sys/vaxuba/dhreg.h
Work on file usr/src/sys/vaxuba/ct.c
Work on file usr/src/sys/vaxuba/dmfreg.h
Work on file usr/src/sys/vaxuba/dmreg.h
Work on file usr/src/sys/vaxuba/dh.c
Work on file usr/src/sys/vaxuba/dzreg.h
Work on file usr/src/sys/vaxuba/idc.c
Work on file usr/src/sys/vaxuba/ik.c
Work on file usr/src/sys/vaxuba/dz.c
Work on file usr/src/sys/vaxuba/dn.c
Work on file usr/src/sys/vaxuba/idcreg.h
Work on file usr/src/sys/vaxuba/lpa.c
Work on file usr/src/sys/vaxuba/kgclock.c
Work on file usr/src/sys/vaxuba/lp.c
Work on file usr/src/sys/vaxuba/pdma.h
Work on file usr/src/sys/vaxuba/rlreg.h
Work on file usr/src/sys/vaxuba/rkreg.h
Work on file usr/src/sys/vaxuba/rl.c
Work on file usr/src/sys/vaxuba/rx.c
Work on file usr/src/sys/vaxuba/tmreg.h
Work on file usr/src/sys/vaxuba/rxreg.h
Work on file usr/src/sys/vaxuba/ts.c
Work on file usr/src/sys/vaxuba/tsreg.h
Work on file usr/src/sys/vaxuba/udareg.h
Work on file usr/src/sys/vaxuba/ut.c
Work on file usr/src/sys/vaxuba/upreg.h
Work on file usr/src/sys/vaxuba/uda.c
Work on file usr/src/sys/vaxuba/up.c
Work on file usr/src/sys/vaxuba/uu.c
Work on file usr/src/sys/vaxuba/utreg.h
Work on file usr/src/sys/vaxuba/va.c
Work on file usr/src/sys/vaxuba/uureg.h
Work on file usr/src/sys/vaxuba/vpreg.h

Synthesized-from: CSRG/cd1/4.2

36 files changed:
usr/src/sys/vaxuba/ad.c [new file with mode: 0644]
usr/src/sys/vaxuba/adreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/ct.c [new file with mode: 0644]
usr/src/sys/vaxuba/dh.c [new file with mode: 0644]
usr/src/sys/vaxuba/dhreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/dmf.c [new file with mode: 0644]
usr/src/sys/vaxuba/dmfreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/dmreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/dn.c [new file with mode: 0644]
usr/src/sys/vaxuba/dz.c [new file with mode: 0644]
usr/src/sys/vaxuba/dzreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/idc.c [new file with mode: 0644]
usr/src/sys/vaxuba/idcreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/ik.c [new file with mode: 0644]
usr/src/sys/vaxuba/kgclock.c [new file with mode: 0644]
usr/src/sys/vaxuba/lp.c [new file with mode: 0644]
usr/src/sys/vaxuba/lpa.c [new file with mode: 0644]
usr/src/sys/vaxuba/pdma.h [new file with mode: 0644]
usr/src/sys/vaxuba/rkreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/rl.c [new file with mode: 0644]
usr/src/sys/vaxuba/rlreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/rx.c [new file with mode: 0644]
usr/src/sys/vaxuba/rxreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/tmreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/ts.c [new file with mode: 0644]
usr/src/sys/vaxuba/tsreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/uda.c [new file with mode: 0644]
usr/src/sys/vaxuba/udareg.h [new file with mode: 0644]
usr/src/sys/vaxuba/up.c [new file with mode: 0644]
usr/src/sys/vaxuba/upreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/ut.c [new file with mode: 0644]
usr/src/sys/vaxuba/utreg.h [new file with mode: 0644]
usr/src/sys/vaxuba/uu.c [new file with mode: 0644]
usr/src/sys/vaxuba/uureg.h [new file with mode: 0644]
usr/src/sys/vaxuba/va.c [new file with mode: 0644]
usr/src/sys/vaxuba/vpreg.h [new file with mode: 0644]

diff --git a/usr/src/sys/vaxuba/ad.c b/usr/src/sys/vaxuba/ad.c
new file mode 100644 (file)
index 0000000..27e2c7f
--- /dev/null
@@ -0,0 +1,165 @@
+/*     ad.c    6.1     83/07/29        */
+
+#include "ad.h"
+#if NAD > 0
+/*
+ * Data translation AD converter interface -- Bill Reeves
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/adreg.h"
+
+#define ADBUSY 01
+#define ADWAITPRI (PZERO+1)
+
+int adprobe(), adattach();
+struct uba_device *addinfo[NAD];
+u_short adstd[] = { 0770400, 0000000, 0 };
+struct uba_driver addriver =
+       { adprobe, 0, adattach, 0, adstd, "ad", addinfo, 0, 0 };
+
+struct ad {
+       char    ad_open;
+       short int ad_uid;
+       short int ad_state;
+       short int ad_softcsr;
+       short int ad_softdata;
+       short int ad_chan;
+       int     ad_icnt;
+       int     ad_loop;
+} ad[NAD];
+
+#define ADUNIT(dev) (minor(dev))
+
+adprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* value-result */
+       register struct addevice *adaddr = (struct addevice *) reg;
+
+       adaddr->ad_csr = AD_IENABLE | AD_START;
+       DELAY(40000);
+       adaddr->ad_csr = 0;
+       return (sizeof (struct addevice));
+}
+
+/*ARGSUSED*/
+adattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+adopen(dev)
+       dev_t dev;
+{
+       register struct ad *adp;
+       register struct uba_device *ui;
+
+       if (ADUNIT(dev) >= NAD || (adp = &ad[ADUNIT(dev)])->ad_open ||
+           (ui = addinfo[ADUNIT(dev)]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       adp->ad_open = 1;
+       adp->ad_icnt = 0;
+       adp->ad_state = 0;
+       adp->ad_uid = u.u_uid;
+       return (0);
+}
+
+adclose(dev)
+       dev_t dev;
+{
+
+       ad[ADUNIT(dev)].ad_open = 0;
+       ad[ADUNIT(dev)].ad_state = 0;
+}
+
+/*ARGSUSED*/
+adioctl(dev, cmd, addr, flag)
+       dev_t dev;
+       register caddr_t addr;
+{
+       register struct addevice *adaddr =
+           (struct addevice *) addinfo[ADUNIT(dev)]->ui_addr;
+       register struct uba_device *ui = addinfo[ADUNIT(dev)];
+       register struct ad *adp;
+       register int i;
+       short int chan;
+
+       switch (cmd) {
+
+       case ADIOSCHAN:
+               adp = &ad[ADUNIT(dev)];
+               adp->ad_chan = (*(int *)data)<<8;
+               break;
+
+       case ADIOGETW:
+               adp = &ad[ADUNIT(dev)];
+               spl6();
+               adaddr->ad_csr = adp->ad_chan;
+               i = 1000;
+               while (i-- > 0 && (adaddr->ad_csr&037400) != adp->ad_chan) {
+                       adp->ad_loop++;
+                       adaddr->ad_csr = adp->ad_chan;
+               }
+               adp->ad_state |= ADBUSY;
+               adaddr->ad_csr |= AD_IENABLE|AD_START;
+               while (adp->ad_state&ADBUSY)
+                       sleep((caddr_t)adp, ADWAITPRI);
+               spl0();
+               *(int *)data = adp->ad_softdata;
+               break;
+
+       default:
+               return (ENOTTY);        /* Not a legal ioctl cmd. */
+       }
+       return (0);
+}
+
+/*ARGSUSED*/
+adintr(dev)
+       dev_t dev;
+{
+       register struct addevice *adaddr =
+                       (struct addevice *) addinfo[ADUNIT(dev)]->ui_addr;
+       register struct ad *adp = &ad[ADUNIT(dev)];
+
+       adp->ad_icnt++;
+       adp->ad_softcsr = adaddr->ad_csr;
+       adp->ad_softdata = adaddr->ad_data;
+       if(adp->ad_state&ADBUSY) {
+               adp->ad_state &= ~ADBUSY;
+               wakeup((caddr_t)adp);
+       }
+}
+
+adreset(uban)
+       int uban;
+{
+       register int i;
+       register struct uba_device *ui;
+       register struct ad *adp = ad;
+       register struct addevice *adaddr;
+
+       for(i = 0; i < NAD; i++, adp++) {
+               if((ui = addinfo[i]) == 0 || ui->ui_alive == 0 ||
+                               ui->ui_ubanum != uban || adp->ad_open == 0)
+                       continue;
+               printf(" ad%d", i);
+               if(adp->ad_state&ADBUSY == 0)
+                       continue;
+               adaddr = (struct addevice *) ui->ui_addr;
+               adaddr->ad_csr = 0;
+               adaddr->ad_csr = adp->ad_chan|AD_IENABLE|AD_START;
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxuba/adreg.h b/usr/src/sys/vaxuba/adreg.h
new file mode 100644 (file)
index 0000000..960641c
--- /dev/null
@@ -0,0 +1,23 @@
+/*     adreg.h 6.1     83/07/29        */
+
+struct addevice {
+       short int ad_csr;                       /* Control status register */
+       short int ad_data;                      /* Data buffer */
+};
+
+#define AD_CHAN                ADIOSCHAN
+#define AD_READ                ADIOGETW
+#define        ADIOSCHAN       _IOW(a, 0, int)         /* set channel */
+#define        ADIOGETW        _IOR(a, 1, int)         /* read one word */
+
+/*
+ * Unibus CSR register bits
+ */
+
+#define AD_START               01
+#define AD_SCHMITT             020
+#define AD_CLOCK               040
+#define AD_IENABLE             0100
+#define AD_DONE                0200
+#define AD_INCENABLE           040000
+#define AD_ERROR               0100000
diff --git a/usr/src/sys/vaxuba/ct.c b/usr/src/sys/vaxuba/ct.c
new file mode 100644 (file)
index 0000000..a352b10
--- /dev/null
@@ -0,0 +1,131 @@
+/*     ct.c    6.1     83/07/29        */
+
+#include "ct.h"
+#if NCT > 0
+/*
+ * GP DR11C driver used for C/A/T
+ *
+ * BUGS:
+ *     This driver hasn't been tested in 4.1bsd
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/tty.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define        PCAT    (PZERO+9)
+#define        CATHIWAT        100
+#define        CATLOWAT        30
+
+struct ct_softc {
+       int     sc_openf;
+       struct  clist sc_oq;
+} ct_softc[NCT];
+
+struct ctdevice {
+       short   ctcsr;
+       short   ctbuf;
+};
+
+int    ctprobe(), ctattach(), ctintr();
+struct uba_device *ctdinfo[NCT];
+u_short        ctstd[] = { 0 };
+struct uba_driver ctdriver = 
+    { ctprobe, 0, ctattach, 0, ctstd, "ct", ctdinfo };
+
+#define        CTUNIT(dev)     (minor(dev))
+
+ctprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* value-result */
+       register struct ctdevice *ctaddr = (struct ctdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       ctintr(0);
+#endif
+       ctaddr->ctcsr = IENABLE;
+       DELAY(10000);
+       ctaddr->ctcsr = 0;
+       return (sizeof (struct ctdevice));
+}
+
+/*ARGSUSED*/
+ctattach(ui)
+       register struct uba_device *ui;
+{
+
+}
+
+ctopen(dev)
+       dev_t dev;
+{
+       register struct ct_softc *sc;
+       register struct uba_device *ui;
+       register struct ctdevice *ctaddr;
+
+       if (CTUNIT(dev) >= NCT || (ui = ctdinfo[CTUNIT(dev)]) == 0 ||
+           ui->ui_alive == 0 || (sc = &ct_softc[CTUNIT(dev)])->sc_openf)
+               return (ENXIO);
+       sc->sc_openf = 1;
+       ctaddr->ctcsr |= IENABLE;
+       return (0);
+}
+
+ctclose(dev)
+       dev_t dev;
+{
+
+       ct_softc[CTUNIT(dev)].sc_openf = 0;
+       ctintr(dev);
+}
+
+ctwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
+       register int c;
+
+       while ((c=cupass(uio)) >= 0) {
+               (void) spl5();
+               while (sc->sc_oq.c_cc > CATHIWAT)
+                       sleep((caddr_t)&sc->sc_oq, PCAT);
+               while (putc(c, &sc->sc_oq) < 0)
+                       sleep((caddr_t)&lbolt, PCAT);
+               ctintr(dev);
+               (void) spl0();
+       }
+}
+
+ctintr(dev)
+       dev_t dev;
+{
+       register int c;
+       register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
+       register struct ctdevice *ctaddr =
+           (struct ctdevice *)ctdinfo[CTUNIT(dev)]->ui_addr;
+
+       if (ctaddr->ctcsr&DONE) {
+               if ((c = getc(&sc->sc_oq)) >= 0) {
+                       ctaddr->ctbuf = c;
+                       if (sc->sc_oq.c_cc==0 || sc->sc_oq.c_cc==CATLOWAT)
+                               wakeup(&sc->sc_oq);
+               } else {
+                       if (sc->sc_openf==0)
+                               ctaddr->ctcsr = 0;
+               }
+       }
+
+}
+#endif
diff --git a/usr/src/sys/vaxuba/dh.c b/usr/src/sys/vaxuba/dh.c
new file mode 100644 (file)
index 0000000..58d2ff6
--- /dev/null
@@ -0,0 +1,735 @@
+/*     dh.c    6.1     83/07/29        */
+
+#include "dh.h"
+#if NDH > 0
+/*
+ * DH-11/DM-11 driver
+ */
+#include "../machine/pte.h"
+
+#include "bk.h"
+#include "../h/param.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/ioctl.h"
+#include "../h/tty.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/vm.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/dhreg.h"
+#include "../vaxuba/dmreg.h"
+
+#include "../h/bk.h"
+#include "../h/clist.h"
+#include "../h/file.h"
+#include "../h/uio.h"
+
+/*
+ * Definition of the driver for the auto-configuration program.
+ * There is one definition for the dh and one for the dm.
+ */
+int    dhprobe(), dhattach(), dhrint(), dhxint();
+struct uba_device *dhinfo[NDH];
+u_short        dhstd[] = { 0 };
+struct uba_driver dhdriver =
+       { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
+
+int    dmprobe(), dmattach(), dmintr();
+struct uba_device *dminfo[NDH];
+u_short        dmstd[] = { 0 };
+struct uba_driver dmdriver =
+       { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
+
+#ifndef        PORTSELECTOR
+#define        ISPEED  B300
+#define        IFLAGS  (EVENP|ODDP|ECHO)
+#else
+#define        ISPEED  B4800
+#define        IFLAGS  (EVENP|ODDP)
+#endif
+
+/*
+ * Local variables for the driver
+ */
+short  dhsar[NDH];                     /* software copy of last bar */
+short  dhsoftCAR[NDH];
+
+struct tty dh11[NDH*16];
+int    ndh11   = NDH*16;
+int    dhact;                          /* mask of active dh's */
+int    dhstart(), ttrstrt();
+
+/*
+ * The clist space is mapped by the driver onto each UNIBUS.
+ * The UBACVT macro converts a clist space address for unibus uban
+ * into an i/o space address for the DMA routine.
+ */
+int    dh_ubinfo[MAXNUBA];             /* info about allocated unibus map */
+int    cbase[MAXNUBA];                 /* base address in unibus map */
+#define        UBACVT(x, uban)         (cbase[uban] + ((x)-(char *)cfree))
+
+/*
+ * Routine for configuration to force a dh to interrupt.
+ * Set to transmit at 9600 baud, and cause a transmitter interrupt.
+ */
+/*ARGSUSED*/
+dhprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* these are ``value-result'' */
+       register struct dhdevice *dhaddr = (struct dhdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       if (ndh11 == 0) ndh11 = 1;
+       dhrint(0); dhxint(0);
+#endif
+#ifndef notdef
+       dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
+       DELAY(1000);
+       dhaddr->un.dhcsr &= ~DH_RI;
+       dhaddr->un.dhcsr = 0;
+#else
+       dhaddr->un.dhcsr = DH_TIE;
+       DELAY(5);
+       dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
+       dhaddr->dhbcr = -1;
+       dhaddr->dhcar = 0;
+       dhaddr->dhbar = 1;
+       DELAY(100000);          /* wait 1/10'th of a sec for interrupt */
+       dhaddr->un.dhcsr = 0;
+       if (cvec && cvec != 0x200)
+               cvec -= 4;              /* transmit -> receive */
+#endif
+       return (sizeof (struct dhdevice));
+}
+
+/*
+ * Routine called to attach a dh.
+ */
+dhattach(ui)
+       struct uba_device *ui;
+{
+
+       dhsoftCAR[ui->ui_unit] = ui->ui_flags;
+}
+
+/*
+ * Configuration routine to cause a dm to interrupt.
+ */
+dmprobe(reg)
+       caddr_t reg;
+{
+       register int br, vec;                   /* value-result */
+       register struct dmdevice *dmaddr = (struct dmdevice *)reg;
+
+#ifdef lint
+       br = 0; vec = br; br = vec;
+       dmintr(0);
+#endif
+       dmaddr->dmcsr = DM_DONE|DM_IE;
+       DELAY(20);
+       dmaddr->dmcsr = 0;
+       return (1);
+}
+
+/*ARGSUSED*/
+dmattach(ui)
+       struct uba_device *ui;
+{
+
+       /* no local state to set up */
+}
+
+/*
+ * Open a DH11 line, mapping the clist onto the uba if this
+ * is the first dh on this uba.  Turn on this dh if this is
+ * the first use of it.  Also do a dmopen to wait for carrier.
+ */
+/*ARGSUSED*/
+dhopen(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit, dh;
+       register struct dhdevice *addr;
+       register struct uba_device *ui;
+       int s;
+
+       unit = minor(dev);
+       dh = unit >> 4;
+       if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       tp = &dh11[unit];
+       if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
+               return (EBUSY);
+       addr = (struct dhdevice *)ui->ui_addr;
+       tp->t_addr = (caddr_t)addr;
+       tp->t_oproc = dhstart;
+       tp->t_state |= TS_WOPEN;
+       /*
+        * While setting up state for this uba and this dh,
+        * block uba resets which can clear the state.
+        */
+       s = spl5();
+       if (dh_ubinfo[ui->ui_ubanum] == 0) {
+               /* 512+ is a kludge to try to get around a hardware problem */
+               dh_ubinfo[ui->ui_ubanum] =
+                   uballoc(ui->ui_ubanum, (caddr_t)cfree,
+                       512+nclist*sizeof(struct cblock), 0);
+               cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
+       }
+       if ((dhact&(1<<dh)) == 0) {
+               addr->un.dhcsr |= DH_IE;
+               dhact |= (1<<dh);
+               addr->dhsilo = 16;
+       }
+       splx(s);
+       /*
+        * If this is first open, initialze tty state to default.
+        */
+       if ((tp->t_state&TS_ISOPEN) == 0) {
+               ttychars(tp);
+#ifndef PORTSELECTOR
+               if (tp->t_ispeed == 0) {
+#endif
+                       tp->t_ispeed = ISPEED;
+                       tp->t_ospeed = ISPEED;
+                       tp->t_flags = IFLAGS;
+#ifndef PORTSELECTOR
+               }
+#endif
+               dhparam(unit);
+       }
+       /*
+        * Wait for carrier, then process line discipline specific open.
+        */
+       dmopen(dev);
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+/*
+ * Close a DH11 line, turning off the DM11.
+ */
+/*ARGSUSED*/
+dhclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register struct tty *tp;
+       register unit;
+
+       unit = minor(dev);
+       tp = &dh11[unit];
+       (*linesw[tp->t_line].l_close)(tp);
+       ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
+       if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
+               dmctl(unit, DML_OFF, DMSET);
+       ttyclose(tp);
+}
+
+dhread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp = &dh11[minor(dev)];
+
+       return ((*linesw[tp->t_line].l_read)(tp, uio));
+}
+
+dhwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp = &dh11[minor(dev)];
+
+       return ((*linesw[tp->t_line].l_write)(tp, uio));
+}
+
+/*
+ * DH11 receiver interrupt.
+ */
+dhrint(dh)
+       int dh;
+{
+       register struct tty *tp;
+       register c;
+       register struct dhdevice *addr;
+       register struct tty *tp0;
+       register struct uba_device *ui;
+       int overrun = 0;
+
+       ui = dhinfo[dh];
+       if (ui == 0 || ui->ui_alive == 0)
+               return;
+       addr = (struct dhdevice *)ui->ui_addr;
+       tp0 = &dh11[dh<<4];
+       /*
+        * Loop fetching characters from the silo for this
+        * dh until there are no more in the silo.
+        */
+       while ((c = addr->dhrcr) < 0) {
+               tp = tp0 + ((c>>8)&0xf);
+#ifndef PORTSELECTOR
+               if ((tp->t_state&TS_ISOPEN)==0) {
+#else
+               if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
+#endif
+                       wakeup((caddr_t)tp);
+                       continue;
+               }
+               if (c & DH_PE)
+                       if ((tp->t_flags&(EVENP|ODDP))==EVENP
+                        || (tp->t_flags&(EVENP|ODDP))==ODDP )
+                               continue;
+               if ((c & DH_DO) && overrun == 0) {
+                       printf("dh%d: silo overflow\n", dh);
+                       overrun = 1;
+               }
+               if (c & DH_FE)
+                       /*
+                        * At framing error (break) generate
+                        * a null (in raw mode, for getty), or a
+                        * interrupt (in cooked/cbreak mode).
+                        */
+                       if (tp->t_flags&RAW)
+                               c = 0;
+                       else
+                               c = tp->t_intrc;
+#if NBK > 0
+               if (tp->t_line == NETLDISC) {
+                       c &= 0177;
+                       BKINPUT(c, tp);
+               } else
+#endif
+                       (*linesw[tp->t_line].l_rint)(c, tp);
+       }
+}
+
+/*
+ * Ioctl for DH11.
+ */
+/*ARGSUSED*/
+dhioctl(dev, cmd, data, flag)
+       caddr_t data;
+{
+       register struct tty *tp;
+       register int unit = minor(dev);
+       int error;
+
+       tp = &dh11[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) {
+               if (cmd == TIOCSETP || cmd == TIOCSETN)
+                       dhparam(unit);
+               return (error);
+       }
+       switch (cmd) {
+
+       case TIOCSBRK:
+               ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
+               break;
+
+       case TIOCCBRK:
+               ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
+               break;
+
+       case TIOCSDTR:
+               dmctl(unit, DML_DTR|DML_RTS, DMBIS);
+               break;
+
+       case TIOCCDTR:
+               dmctl(unit, DML_DTR|DML_RTS, DMBIC);
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+/*
+ * Set parameters from open or stty into the DH hardware
+ * registers.
+ */
+dhparam(unit)
+       register int unit;
+{
+       register struct tty *tp;
+       register struct dhdevice *addr;
+       register int lpar;
+       int s;
+
+       tp = &dh11[unit];
+       addr = (struct dhdevice *)tp->t_addr;
+       /*
+        * Block interrupts so parameters will be set
+        * before the line interrupts.
+        */
+       s = spl5();
+       addr->un.dhcsrl = (unit&0xf) | DH_IE;
+       if ((tp->t_ispeed)==0) {
+               tp->t_state |= TS_HUPCLS;
+               dmctl(unit, DML_OFF, DMSET);
+               return;
+       }
+       lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
+       if ((tp->t_ispeed) == B134)
+               lpar |= BITS6|PENABLE|HDUPLX;
+       else if (tp->t_flags & (RAW|LITOUT))
+               lpar |= BITS8;
+       else
+               lpar |= BITS7|PENABLE;
+       if ((tp->t_flags&EVENP) == 0)
+               lpar |= OPAR;
+       if ((tp->t_ospeed) == B110)
+               lpar |= TWOSB;
+       addr->dhlpr = lpar;
+       splx(s);
+}
+
+/*
+ * DH11 transmitter interrupt.
+ * Restart each line which used to be active but has
+ * terminated transmission since the last interrupt.
+ */
+dhxint(dh)
+       int dh;
+{
+       register struct tty *tp;
+       register struct dhdevice *addr;
+       short ttybit, bar, *sbar;
+       register struct uba_device *ui;
+       register int unit;
+       u_short cntr;
+
+       ui = dhinfo[dh];
+       addr = (struct dhdevice *)ui->ui_addr;
+       if (addr->un.dhcsr & DH_NXM) {
+               addr->un.dhcsr |= DH_CNI;
+               printf("dh%d: NXM\n", dh);
+       }
+       sbar = &dhsar[dh];
+       bar = *sbar & ~addr->dhbar;
+       unit = dh * 16; ttybit = 1;
+       addr->un.dhcsr &= (short)~DH_TI;
+       for (; bar; unit++, ttybit <<= 1) {
+               if (bar & ttybit) {
+                       *sbar &= ~ttybit;
+                       bar &= ~ttybit;
+                       tp = &dh11[unit];
+                       tp->t_state &= ~TS_BUSY;
+                       if (tp->t_state&TS_FLUSH)
+                               tp->t_state &= ~TS_FLUSH;
+                       else {
+                               addr->un.dhcsrl = (unit&017)|DH_IE;
+                               /*
+                                * Do arithmetic in a short to make up
+                                * for lost 16&17 bits.
+                                */
+                               cntr = addr->dhcar -
+                                   UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
+                               ndflush(&tp->t_outq, (int)cntr);
+                       }
+                       if (tp->t_line)
+                               (*linesw[tp->t_line].l_start)(tp);
+                       else
+                               dhstart(tp);
+               }
+       }
+}
+
+/*
+ * Start (restart) transmission on the given DH11 line.
+ */
+dhstart(tp)
+       register struct tty *tp;
+{
+       register struct dhdevice *addr;
+       register int car, dh, unit, nch;
+       int s;
+
+       unit = minor(tp->t_dev);
+       dh = unit >> 4;
+       unit &= 0xf;
+       addr = (struct dhdevice *)tp->t_addr;
+
+       /*
+        * Must hold interrupts in following code to prevent
+        * state of the tp from changing.
+        */
+       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;
+       /*
+        * If there are sleepers, and output has drained below low
+        * water mark, wake up the sleepers.
+        */
+       if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
+               if (tp->t_state&TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup((caddr_t)&tp->t_outq);
+               }
+               if (tp->t_wsel) {
+                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+                       tp->t_wsel = 0;
+                       tp->t_state &= ~TS_WCOLL;
+               }
+       }
+       /*
+        * Now restart transmission unless the output queue is
+        * empty.
+        */
+       if (tp->t_outq.c_cc == 0)
+               goto out;
+       if (tp->t_flags & (RAW|LITOUT))
+               nch = ndqb(&tp->t_outq, 0);
+       else {
+               nch = ndqb(&tp->t_outq, 0200);
+               /*
+                * If first thing on queue is a delay process it.
+                */
+               if (nch == 0) {
+                       nch = getc(&tp->t_outq);
+                       timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
+                       tp->t_state |= TS_TIMEOUT;
+                       goto out;
+               }
+       }
+       /*
+        * If characters to transmit, restart transmission.
+        */
+       if (nch) {
+               car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
+               addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
+               /*
+                * The following nonsense with short word
+                * is to make sure the dhbar |= word below
+                * is done with an interlocking bisw2 instruction.
+                */
+               { short word = 1 << unit;
+               dhsar[dh] |= word;
+               addr->dhcar = car;
+               addr->dhbcr = -nch;
+               addr->dhbar |= word;
+               }
+               tp->t_state |= TS_BUSY;
+       }
+out:
+       splx(s);
+}
+
+/*
+ * Stop output on a line, e.g. for ^S/^Q or output flush.
+ */
+/*ARGSUSED*/
+dhstop(tp, flag)
+       register struct tty *tp;
+{
+       register struct dhdevice *addr;
+       register int unit, s;
+
+       addr = (struct dhdevice *)tp->t_addr;
+       /*
+        * Block input/output interrupts while messing with state.
+        */
+       s = spl5();
+       if (tp->t_state & TS_BUSY) {
+               /*
+                * Device is transmitting; stop output
+                * by selecting the line and setting the byte
+                * count to -1.  We will clean up later
+                * by examining the address where the dh stopped.
+                */
+               unit = minor(tp->t_dev);
+               addr->un.dhcsrl = (unit&017) | DH_IE;
+               if ((tp->t_state&TS_TTSTOP)==0)
+                       tp->t_state |= TS_FLUSH;
+               addr->dhbcr = -1;
+       }
+       splx(s);
+}
+
+/*
+ * Reset state of driver if UBA reset was necessary.
+ * Reset the csrl and lpr registers on open lines, and
+ * restart transmitters.
+ */
+dhreset(uban)
+       int uban;
+{
+       register int dh, unit;
+       register struct tty *tp;
+       register struct uba_device *ui;
+       int i;
+
+       if (dh_ubinfo[uban] == 0)
+               return;
+       dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
+           512+nclist*sizeof (struct cblock), 0);
+       cbase[uban] = dh_ubinfo[uban]&0x3ffff;
+       dh = 0;
+       for (dh = 0; dh < NDH; dh++) {
+               ui = dhinfo[dh];
+               if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
+                       continue;
+               printf(" dh%d", dh);
+               ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
+               ((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
+               unit = dh * 16;
+               for (i = 0; i < 16; i++) {
+                       tp = &dh11[unit];
+                       if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
+                               dhparam(unit);
+                               dmctl(unit, DML_ON, DMSET);
+                               tp->t_state &= ~TS_BUSY;
+                               dhstart(tp);
+                       }
+                       unit++;
+               }
+       }
+       dhtimer();
+}
+
+/*
+ * At software clock interrupt time or after a UNIBUS reset
+ * empty all the dh silos.
+ */
+dhtimer()
+{
+       register int dh;
+       register int s = spl5();
+
+       for (dh = 0; dh < NDH; dh++)
+               dhrint(dh);
+       splx(s);
+}
+
+/*
+ * Turn on the line associated with dh dev.
+ */
+dmopen(dev)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register struct dmdevice *addr;
+       register struct uba_device *ui;
+       register int unit;
+       register int dm;
+       int s;
+
+       unit = minor(dev);
+       dm = unit >> 4;
+       tp = &dh11[unit];
+       unit &= 0xf;
+       if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
+           (dhsoftCAR[dm]&(1<<unit))) {
+               tp->t_state |= TS_CARR_ON;
+               return;
+       }
+       addr = (struct dmdevice *)ui->ui_addr;
+       s = spl5();
+       addr->dmcsr &= ~DM_SE;
+       while (addr->dmcsr & DM_BUSY)
+               ;
+       addr->dmcsr = unit;
+       addr->dmlstat = DML_ON;
+       if (addr->dmlstat&DML_CAR)
+               tp->t_state |= TS_CARR_ON;
+       addr->dmcsr = DM_IE|DM_SE;
+       while ((tp->t_state&TS_CARR_ON)==0)
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       splx(s);
+}
+
+/*
+ * Dump control bits into the DM registers.
+ */
+dmctl(dev, bits, how)
+       dev_t dev;
+       int bits, how;
+{
+       register struct uba_device *ui;
+       register struct dmdevice *addr;
+       register int unit, s;
+       int dm;
+
+       unit = minor(dev);
+       dm = unit >> 4;
+       if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
+               return;
+       addr = (struct dmdevice *)ui->ui_addr;
+       s = spl5();
+       addr->dmcsr &= ~DM_SE;
+       while (addr->dmcsr & DM_BUSY)
+               ;
+       addr->dmcsr = unit & 0xf;
+       switch(how) {
+       case DMSET:
+               addr->dmlstat = bits;
+               break;
+       case DMBIS:
+               addr->dmlstat |= bits;
+               break;
+       case DMBIC:
+               addr->dmlstat &= ~bits;
+               break;
+       }
+       addr->dmcsr = DM_IE|DM_SE;
+       splx(s);
+}
+
+/*
+ * DM11 interrupt; deal with carrier transitions.
+ */
+dmintr(dm)
+       register int dm;
+{
+       register struct uba_device *ui;
+       register struct tty *tp;
+       register struct dmdevice *addr;
+
+       ui = dminfo[dm];
+       if (ui == 0)
+               return;
+       addr = (struct dmdevice *)ui->ui_addr;
+       if (addr->dmcsr&DM_DONE) {
+               if (addr->dmcsr&DM_CF) {
+                       tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
+                       wakeup((caddr_t)&tp->t_rawq);
+                       if ((tp->t_state&TS_WOPEN) == 0 &&
+                           (tp->t_flags & MDMBUF)) {
+                               if (addr->dmlstat & DML_CAR) {
+                                       tp->t_state &= ~TS_TTSTOP;
+                                       ttstart(tp);
+                               } else if ((tp->t_state&TS_TTSTOP) == 0) {
+                                       tp->t_state |= TS_TTSTOP;
+                                       dhstop(tp, 0);
+                               }
+                       } else if ((addr->dmlstat&DML_CAR)==0) {
+                               if ((tp->t_state&TS_WOPEN)==0 &&
+                                   (tp->t_flags & NOHANG) == 0) {
+                                       gsignal(tp->t_pgrp, SIGHUP);
+                                       gsignal(tp->t_pgrp, SIGCONT);
+                                       addr->dmlstat = 0;
+                                       ttyflush(tp, FREAD|FWRITE);
+                               }
+                               tp->t_state &= ~TS_CARR_ON;
+                       } else
+                               tp->t_state |= TS_CARR_ON;
+               }
+               addr->dmcsr = DM_IE|DM_SE;
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxuba/dhreg.h b/usr/src/sys/vaxuba/dhreg.h
new file mode 100644 (file)
index 0000000..d2f6ec5
--- /dev/null
@@ -0,0 +1,47 @@
+/*     dhreg.h 6.1     83/07/29        */
+
+/* 
+ * DH-11 device register definitions.
+ */
+struct dhdevice {
+       union {
+               short   dhcsr;          /* control-status register */
+               char    dhcsrl;         /* low byte for line select */
+       } un;
+       short   dhrcr;                  /* receive character register */
+       short   dhlpr;                  /* line parameter register */
+       u_short dhcar;                  /* current address register */
+       short   dhbcr;                  /* byte count register */
+       u_short dhbar;                  /* buffer active register */
+       short   dhbreak;                /* break control register */
+       short   dhsilo;                 /* silo status register */
+};
+
+/* Bits in dhcsr */
+#define        DH_TI   0100000         /* transmit interrupt */
+#define        DH_SI   0040000         /* storage interrupt */
+#define        DH_TIE  0020000         /* transmit interrupt enable */
+#define        DH_SIE  0010000         /* storage interrupt enable */
+#define        DH_MC   0004000         /* master clear */
+#define        DH_NXM  0002000         /* non-existant memory */
+#define        DH_MM   0001000         /* maintenance mode */
+#define        DH_CNI  0000400         /* clear non-existant memory interrupt */
+#define        DH_RI   0000200         /* receiver interrupt */
+#define        DH_RIE  0000100         /* receiver interrupt enable */
+
+/* Bits in dhlpr */
+#define        BITS6   01
+#define        BITS7   02
+#define        BITS8   03
+#define        TWOSB   04
+#define        PENABLE 020
+/* DEC manuals incorrectly say this bit causes generation of even parity. */
+#define        OPAR    040
+#define        HDUPLX  040000
+
+#define        DH_IE   (DH_TIE|DH_SIE|DH_RIE)
+
+/* Bits in dhrcr */
+#define        DH_PE           0010000         /* parity error */
+#define        DH_FE           0020000         /* framing error */
+#define        DH_DO           0040000         /* data overrun */
diff --git a/usr/src/sys/vaxuba/dmf.c b/usr/src/sys/vaxuba/dmf.c
new file mode 100644 (file)
index 0000000..3246a57
--- /dev/null
@@ -0,0 +1,709 @@
+/*     dmf.c   6.1     83/07/29        */
+
+#include "dmf.h"
+#if NDMF > 0
+/*
+ * DMF32 driver
+ *
+ * TODO:
+ *     test with modem
+ *     load as much as possible into silo
+ *     get correct numbers for receive silo parameter timeout
+ *     use auto XON/XOFF
+ *     test reset code
+ *     test with more than one unit
+ *     optimize for efficient DMA and dynamically
+ *       decide between silo and DMA mode
+ */
+#include "../machine/pte.h"
+
+#include "bk.h"
+#include "../h/param.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/ioctl.h"
+#include "../h/tty.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/vm.h"
+#include "../h/bk.h"
+#include "../h/clist.h"
+#include "../h/file.h"
+#include "../h/uio.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/dmfreg.h"
+
+/*
+ * Definition of the driver for the auto-configuration program.
+ */
+int    dmfprobe(), dmfattach(), dmfrint(), dmfxint();
+struct uba_device *dmfinfo[NDMF];
+u_short        dmfstd[] = { 0 };
+struct uba_driver dmfdriver =
+       { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
+
+/*
+ * Local variables for the driver
+ */
+char   dmf_speeds[] =
+       { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
+
+struct tty dmf_tty[NDMF*8];
+char   dmfsoftCAR[NDMF];
+#ifndef lint
+int    ndmf = NDMF*8;                  /* used by iostat */
+#endif
+int    dmfact;                         /* mask of active dmf's */
+int    dmfstart(), ttrstrt();
+
+#ifdef DMFDMA
+/*
+ * The clist space is mapped by the driver onto each UNIBUS.
+ * The UBACVT macro converts a clist space address for unibus uban
+ * into an i/o space address for the DMA routine.
+ */
+int    dmf_ubinfo[MAXNUBA];            /* info about allocated unibus map */
+static int cbase[MAXNUBA];             /* base address in unibus map */
+#define        UBACVT(x, uban)         (cbase[uban] + ((x)-(char *)cfree))
+#endif
+
+/*
+ * Routine for configuration to set dmf interrupt.
+ */
+/*ARGSUSED*/
+dmfprobe(reg, ctlr)
+       caddr_t reg;
+       int ctlr;
+{
+       register int br, cvec;          /* these are ``value-result'' */
+       register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       dmfxint(0); dmfrint(0);
+       dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint();
+#endif
+       br = 0x15;
+       cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
+       dmfaddr->dmfccsr0 = cvec >> 2;
+       /* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */
+       return (sizeof (struct dmfdevice));
+}
+
+/*
+ * Routine called to attach a dmf.
+ */
+dmfattach(ui)
+       struct uba_device *ui;
+{
+
+       dmfsoftCAR[ui->ui_unit] = ui->ui_flags;
+}
+
+
+/*
+ * Open a DMF32 line, mapping the clist onto the uba if this
+ * is the first dmf on this uba.  Turn on this dmf if this is
+ * the first use of it.
+ */
+/*ARGSUSED*/
+dmfopen(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit, dmf;
+       register struct dmfdevice *addr;
+       register struct uba_device *ui;
+       int s;
+
+       unit = minor(dev);
+       dmf = unit >> 3;
+       if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       tp = &dmf_tty[unit];
+       if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
+               return (EBUSY);
+       addr = (struct dmfdevice *)ui->ui_addr;
+       tp->t_addr = (caddr_t)addr;
+       tp->t_oproc = dmfstart;
+       tp->t_state |= TS_WOPEN;
+       /*
+        * While setting up state for this uba and this dmf,
+        * block uba resets which can clear the state.
+        */
+       s = spl5();
+#ifdef DMFDMA
+       if (dmf_ubinfo[ui->ui_ubanum] == 0) {
+               dmf_ubinfo[ui->ui_ubanum] =
+                   uballoc(ui->ui_ubanum, (caddr_t)cfree,
+                       nclist*sizeof(struct cblock), 0);
+               cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff;
+       }
+#endif
+       if ((dmfact&(1<<dmf)) == 0) {
+               addr->dmfcsr |= DMF_IE;
+               dmfact |= (1<<dmf);
+               addr->dmfrsp = 1;       /* DON'T KNOW WHAT TO SET IT TO YET */
+       }
+       splx(s);
+       /*
+        * If this is first open, initialze tty state to default.
+        */
+       if ((tp->t_state&TS_ISOPEN) == 0) {
+               ttychars(tp);
+               if (tp->t_ispeed == 0) {
+                       tp->t_ispeed = B300;
+                       tp->t_ospeed = B300;
+                       tp->t_flags = ODDP|EVENP|ECHO;
+               }
+               dmfparam(unit);
+       }
+       /*
+        * Wait for carrier, then process line discipline specific open.
+        */
+       if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) ||
+           (dmfsoftCAR[dmf] & (1<<(unit&07))))
+               tp->t_state |= TS_CARR_ON;
+       s = spl5();
+       while ((tp->t_state & TS_CARR_ON) == 0) {
+               tp->t_state |= TS_WOPEN;
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       }
+       splx(s);
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+/*
+ * Close a DMF32 line.
+ */
+/*ARGSUSED*/
+dmfclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register struct tty *tp;
+       register unit;
+
+       unit = minor(dev);
+       tp = &dmf_tty[unit];
+       (*linesw[tp->t_line].l_close)(tp);
+       (void) dmfmctl(unit, DMF_BRK, DMBIC);
+       if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
+               (void) dmfmctl(unit, DMF_OFF, DMSET);
+       ttyclose(tp);
+}
+
+dmfread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp;
+
+       tp = &dmf_tty[minor(dev)];
+       return ((*linesw[tp->t_line].l_read)(tp, uio));
+}
+
+dmfwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp;
+
+       tp = &dmf_tty[minor(dev)];
+       return ((*linesw[tp->t_line].l_write)(tp, uio));
+}
+
+/*
+ * DMF32 receiver interrupt.
+ */
+dmfrint(dmf)
+       int dmf;
+{
+       register struct tty *tp;
+       register c;
+       register struct dmfdevice *addr;
+       register struct tty *tp0;
+       register struct uba_device *ui;
+       int overrun = 0, s;
+
+       ui = dmfinfo[dmf];
+       if (ui == 0 || ui->ui_alive == 0)
+               return;
+       addr = (struct dmfdevice *)ui->ui_addr;
+       tp0 = &dmf_tty[dmf<<3];
+       /*
+        * Loop fetching characters from the silo for this
+        * dmf until there are no more in the silo.
+        */
+       while ((c = addr->dmfrbuf) < 0) {
+               tp = tp0 + ((c>>8)&07);
+               if (c & DMF_DSC) {
+                       s = spl5();
+                       addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07);
+                       if (addr->dmfrms & DMF_CAR) {
+                               if ((tp->t_state & TS_CARR_ON) == 0) {
+                                       wakeup((caddr_t)&tp->t_rawq);
+                                       tp->t_state |= TS_CARR_ON;
+                               }
+                       } else {
+                               if (tp->t_state & TS_CARR_ON) {
+                                       gsignal(tp->t_pgrp, SIGHUP);
+                                       gsignal(tp->t_pgrp, SIGCONT);
+                                       addr->dmfcsr = DMF_IE | DMFIR_LCR |
+                                               ((c>>8)&07);
+                                       addr->dmftms = 0;
+                                       ttyflush(tp, FREAD|FWRITE);
+                               }
+                               tp->t_state &= ~TS_CARR_ON;
+                       }
+                       splx(s);
+                       continue;
+               }
+               if ((tp->t_state&TS_ISOPEN)==0) {
+                       wakeup((caddr_t)tp);
+                       continue;
+               }
+               if (c & DMF_PE)
+                       if ((tp->t_flags&(EVENP|ODDP))==EVENP
+                        || (tp->t_flags&(EVENP|ODDP))==ODDP )
+                               continue;
+               if ((c & DMF_DO) && overrun == 0) {
+                       printf("dmf%d: silo overflow\n", dmf);
+                       overrun = 1;
+               }
+               if (c & DMF_FE)
+                       /*
+                        * At framing error (break) generate
+                        * a null (in raw mode, for getty), or a
+                        * interrupt (in cooked/cbreak mode).
+                        */
+                       if (tp->t_flags&RAW)
+                               c = 0;
+                       else
+                               c = tp->t_intrc;
+#if NBK > 0
+               if (tp->t_line == NETLDISC) {
+                       c &= 0177;
+                       BKINPUT(c, tp);
+               } else
+#endif
+                       (*linesw[tp->t_line].l_rint)(c, tp);
+       }
+}
+
+/*
+ * Ioctl for DMF32.
+ */
+/*ARGSUSED*/
+dmfioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct tty *tp;
+       register int unit = minor(dev);
+       int error;
+       tp = &dmf_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) {
+               if (cmd == TIOCSETP || cmd == TIOCSETN)
+                       dmfparam(unit);
+               return (error);
+       }
+       switch (cmd) {
+
+       case TIOCSBRK:
+               (void) dmfmctl(dev, DMF_BRK, DMBIS);
+               break;
+
+       case TIOCCBRK:
+               (void) dmfmctl(dev, DMF_BRK, DMBIC);
+               break;
+
+       case TIOCSDTR:
+               (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS);
+               break;
+
+       case TIOCCDTR:
+               (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC);
+               break;
+
+       case TIOCMSET:
+               (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET);
+               break;
+
+       case TIOCMBIS:
+               (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS);
+               break;
+
+       case TIOCMBIC:
+               (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC);
+               break;
+
+       case TIOCMGET:
+               *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET));
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+dmtodmf(bits)
+       register int bits;
+{
+       register int b;
+
+       b = bits & 012;
+       if (bits & DML_ST) b |= DMF_RATE;
+       if (bits & DML_RTS) b |= DMF_RTS;
+       if (bits & DML_USR) b |= DMF_USRW;
+       return(b);
+}
+
+dmftodm(bits)
+       register int bits;
+{
+       register int b;
+
+       b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE;
+       if (bits & DMF_USRR) b |= DML_USR;
+       if (bits & DMF_RTS) b |= DML_RTS;
+       return(b);
+}
+
+/*
+ * Set parameters from open or stty into the DMF hardware
+ * registers.
+ */
+dmfparam(unit)
+       register int unit;
+{
+       register struct tty *tp;
+       register struct dmfdevice *addr;
+       register int lpar, lcr;
+       int s;
+
+       tp = &dmf_tty[unit];
+       addr = (struct dmfdevice *)tp->t_addr;
+       /*
+        * Block interrupts so parameters will be set
+        * before the line interrupts.
+        */
+       s = spl5();
+       addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE;
+       if ((tp->t_ispeed)==0) {
+               tp->t_state |= TS_HUPCLS;
+               (void) dmfmctl(unit, DMF_OFF, DMSET);
+               return;
+       }
+       lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8);
+       lcr = DMFLCR_ENA;
+       if ((tp->t_ispeed) == B134)
+               lpar |= BITS6|PENABLE;
+       else if (tp->t_flags & (RAW|LITOUT))
+               lpar |= BITS8;
+       else {
+               lpar |= BITS7|PENABLE;
+               /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
+       }
+       if (tp->t_flags&EVENP)
+               lpar |= EPAR;
+       if ((tp->t_ospeed) == B110)
+               lpar |= TWOSB;
+       lpar |= (unit&07);
+       addr->dmflpr = lpar;
+       SETLCR(addr, lcr);
+       splx(s);
+}
+
+/*
+ * DMF32 transmitter interrupt.
+ * Restart the idle line.
+ */
+dmfxint(dmf)
+       int dmf;
+{
+       register struct tty *tp;
+       register struct dmfdevice *addr;
+       register struct uba_device *ui;
+       register int unit, t;
+#ifdef DMFDMA
+       short cntr;
+       int s;
+#endif
+
+       ui = dmfinfo[dmf];
+       addr = (struct dmfdevice *)ui->ui_addr;
+       while ((t = addr->dmfcsr) & DMF_TI) {
+               unit = dmf*8 + ((t>>8)&07);
+               tp = &dmf_tty[unit];
+               tp->t_state &= ~TS_BUSY;
+               if (t & DMF_NXM) {
+                       printf("dmf%d: NXM line %d\n", dmf, unit&7);
+                       /* SHOULD RESTART OR SOMETHING... */
+               }
+               if (tp->t_state&TS_FLUSH)
+                       tp->t_state &= ~TS_FLUSH;
+#ifdef DMFDMA
+               else {
+                       s = spl5();
+                       addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07);
+                       if (addr->dmftsc == 0) {
+                               /*
+                                * Do arithmetic in a short to make up
+                                * for lost 16&17 bits.
+                                */
+                               addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07);
+                               cntr = addr->dmftba -
+                                   UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
+                               ndflush(&tp->t_outq, (int)cntr);
+                       }
+                       splx(s);
+               }
+#endif
+               if (tp->t_line)
+                       (*linesw[tp->t_line].l_start)(tp);
+               else
+                       dmfstart(tp);
+       }
+}
+
+/*
+ * Start (restart) transmission on the given DMF32 line.
+ */
+dmfstart(tp)
+       register struct tty *tp;
+{
+       register struct dmfdevice *addr;
+       register int unit, nch;
+       int s;
+
+       unit = minor(tp->t_dev);
+       unit &= 07;
+       addr = (struct dmfdevice *)tp->t_addr;
+
+       /*
+        * Must hold interrupts in following code to prevent
+        * state of the tp from changing.
+        */
+       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;
+       /*
+        * If there are still characters in the silo,
+        * just reenable the transmitter.
+        */
+       addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
+       if (addr->dmftsc) {
+               addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
+               SETLCR(addr, addr->dmflcr|DMF_TE);
+               tp->t_state |= TS_BUSY;
+               goto out;
+       }
+       /*
+        * If there are sleepers, and output has drained below low
+        * water mark, wake up the sleepers.
+        */
+       if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
+               tp->t_state &= ~TS_ASLEEP;
+               wakeup((caddr_t)&tp->t_outq);
+       }
+       /*
+        * Now restart transmission unless the output queue is
+        * empty.
+        */
+       if (tp->t_outq.c_cc == 0)
+               goto out;
+       if (tp->t_flags & (RAW|LITOUT))
+               nch = ndqb(&tp->t_outq, 0);
+       else {
+               nch = ndqb(&tp->t_outq, 0200);
+               /*
+                * If first thing on queue is a delay process it.
+                */
+               if (nch == 0) {
+                       nch = getc(&tp->t_outq);
+                       timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
+                       tp->t_state |= TS_TIMEOUT;
+                       goto out;
+               }
+       }
+       /*
+        * If characters to transmit, restart transmission.
+        */
+       if (nch) {
+#ifdef DMFDMA
+               addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
+               SETLCR(addr, addr->dmflcr|DMF_TE);
+               car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
+               addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
+               addr->dmftba = car;
+               addr->dmftcc = ((car>>2)&0xc000) | nch;
+#else
+               register char *cp = tp->t_outq.c_cf;
+               register int i;
+
+               nch = MIN(nch, DMF_SILOCNT);
+               addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
+               SETLCR(addr, addr->dmflcr|DMF_TE);
+               addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
+               for (i = 0; i < nch; i++)
+                       addr->dmftbuf = *cp++;
+               ndflush(&tp->t_outq, nch);
+#endif
+               tp->t_state |= TS_BUSY;
+       }
+out:
+       splx(s);
+}
+
+/*
+ * Stop output on a line, e.g. for ^S/^Q or output flush.
+ */
+/*ARGSUSED*/
+dmfstop(tp, flag)
+       register struct tty *tp;
+{
+       register struct dmfdevice *addr;
+       register int unit, s;
+
+       addr = (struct dmfdevice *)tp->t_addr;
+       /*
+        * Block input/output interrupts while messing with state.
+        */
+       s = spl5();
+       if (tp->t_state & TS_BUSY) {
+               /*
+                * Device is transmitting; stop output
+                * by selecting the line and disabling
+                * the transmitter.  If this is a flush
+                * request then flush the output silo,
+                * otherwise we will pick up where we
+                * left off by enabling the transmitter.
+                */
+               unit = minor(tp->t_dev);
+               addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE;
+               SETLCR(addr, addr->dmflcr &~ DMF_TE);
+               if ((tp->t_state&TS_TTSTOP)==0) {
+                       tp->t_state |= TS_FLUSH;
+                       SETLCR(addr, addr->dmflcr|DMF_FLUSH);
+               } else
+                       tp->t_state &= ~TS_BUSY;
+       }
+       splx(s);
+}
+
+/*
+ * DMF32 modem control
+ */
+dmfmctl(dev, bits, how)
+       dev_t dev;
+       int bits, how;
+{
+       register struct dmfdevice *dmfaddr;
+       register int unit, mbits, lcr;
+       int s;
+
+       unit = minor(dev);
+       dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr);
+       unit &= 07;
+       s = spl5();
+       dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
+       mbits = dmfaddr->dmfrms << 8;
+       dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
+       mbits |= dmfaddr->dmftms;
+       lcr = dmfaddr->dmflcr;
+       switch (how) {
+       case DMSET:
+               mbits = (mbits &0xff00) | bits;
+               break;
+
+       case DMBIS:
+               mbits |= bits;
+               break;
+
+       case DMBIC:
+               mbits &= ~bits;
+               break;
+
+       case DMGET:
+               (void) splx(s);
+               return(mbits);
+       }
+       if (mbits & DMF_BRK)
+               lcr |= DMF_RBRK;
+       else
+               lcr &= ~DMF_RBRK;
+       lcr = ((mbits & 037) << 8) | (lcr & 0xff);
+       dmfaddr->dmfun.dmfirw = lcr;
+       (void) splx(s);
+       return(mbits);
+}
+
+/*
+ * Reset state of driver if UBA reset was necessary.
+ * Reset the csr, lpr, and lcr registers on open lines, and
+ * restart transmitters.
+ */
+dmfreset(uban)
+       int uban;
+{
+       register int dmf, unit;
+       register struct tty *tp;
+       register struct uba_device *ui;
+       register struct dmfdevice *addr;
+       int i;
+
+#ifdef DMFDMA
+       if (dmf_ubinfo[uban] == 0)
+               return;
+       dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
+           nclist*sizeof (struct cblock), 0);
+       cbase[uban] = dmf_ubinfo[uban]&0x3ffff;
+#endif
+       for (dmf = 0; dmf < NDMF; dmf++) {
+               ui = dmfinfo[dmf];
+               if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
+                       continue;
+               printf(" dmf%d", dmf);
+               addr = (struct dmfdevice *)ui->ui_addr;
+               addr->dmfcsr = DMF_IE;
+               addr->dmfrsp = 1;
+               unit = dmf * 8;
+               for (i = 0; i < 8; i++) {
+                       tp = &dmf_tty[unit];
+                       if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
+                               dmfparam(unit);
+                               (void) dmfmctl(unit, DMF_ON, DMSET);
+                               tp->t_state &= ~TS_BUSY;
+                               dmfstart(tp);
+                       }
+                       unit++;
+               }
+       }
+}
+
+/* stubs for interrupt routines for devices not yet supported */
+
+dmfsrint() { printf("dmfsrint\n"); }
+
+dmfsxint() { printf("dmfsxint\n"); }
+
+dmfdaint() { printf("dmfdaint\n"); }
+
+dmfdbint() { printf("dmfdbint\n"); }
+
+dmflint() { printf("dmflint\n"); }
+#endif
diff --git a/usr/src/sys/vaxuba/dmfreg.h b/usr/src/sys/vaxuba/dmfreg.h
new file mode 100644 (file)
index 0000000..8ad6572
--- /dev/null
@@ -0,0 +1,115 @@
+/*     dmfreg.h        6.1     83/07/29        */
+
+/*
+ * DMF-32 definitions.
+ */
+
+/*
+ * "dmf" (unqualified) refers to the async portion of the dmf32,
+ * "dmfc" to the combo portion,
+ * "dmfs" to the sync portion,
+ * "dmfl" to the lp portion, and
+ * "dmfd" to the dr portion.
+ */
+struct dmfdevice {
+       short   dmfccsr0;               /* combo csr 0 */
+       short   dmfccsr1;               /* combo csr 1 */
+       short   dmfs[4];
+       short   dmfcsr;                 /* control-status register */
+       short   dmflpr;                 /* line parameter register */
+       short   dmfrbuf;                /* receiver buffer (ro) */
+       union {
+               u_short dmfirw;         /* indirect register word */
+               u_char  dmfirc[2];      /*    "         "    bytes */
+       } dmfun;
+       short   dmfl[2];
+       short   dmfd[4];
+};
+
+#define        dmfrsp  dmfrbuf         /* receive silo parameter register (wo) */
+#define        dmftbuf dmfun.dmfirc[0] /* transmit buffer */
+#define        dmftsc  dmfun.dmfirc[0] /* transmit silo count */
+#define        dmfrms  dmfun.dmfirc[1] /* receive modem status */
+#define        dmflcr  dmfun.dmfirc[0] /* line control register */
+#define        dmftms  dmfun.dmfirc[1] /* transmit modem status */
+#define        dmftba  dmfun.dmfirw    /* transmit buffer address */
+#define        dmftcc  dmfun.dmfirw    /* transmit character count */
+
+/* bits in dmfcsr */
+#define        DMF_TI  0100000         /* transmit interrupt */
+#define        DMF_TIE 0040000         /* transmit interrupt enable */
+#define        DMF_NXM 0020000         /* non-existant memory */
+#define        DMF_LIN 0003400         /* transmit line number */
+#define        DMF_RI  0000200         /* receiver interrupt */
+#define        DMF_RIE 0000100         /* receiver interrupt enable */
+#define        DMF_CLR 0000040         /* master reset */
+#define        DMF_IAD 0000037         /* indirect address register */
+
+#define        DMFIR_TBUF      000     /* select tbuf indirect register */
+#define        DMFIR_LCR       010     /* select lcr indirect register */
+#define        DMFIR_TBA       020     /* select tba indirect register */
+#define        DMFIR_TCC       030     /* select tcc indirect register */
+
+/* bits in dmflpr */
+#define        BITS6   (01<<3)
+#define        BITS7   (02<<3)
+#define        BITS8   (03<<3)
+#define        TWOSB   0200
+#define        PENABLE 040
+#define        EPAR    0100
+
+#define        DMF_IE  (DMF_TIE|DMF_RIE)
+
+#define        DMF_SILOCNT     32              /* size of DMF output silo (per line) */
+
+/* bits in dmfrbuf */
+#define        DMF_DSC         0004000         /* data set change */
+#define        DMF_PE          0010000         /* parity error */
+#define        DMF_FE          0020000         /* framing error */
+#define        DMF_DO          0040000         /* data overrun */
+
+/* bits in dmfrms */
+#define        DMF_USRR        0004            /* user modem signal (pin 25) */
+#define        DMF_SR          0010            /* secondary receive */
+#define        DMF_CTS         0020            /* clear to send */
+#define        DMF_CAR         0040            /* carrier detect */
+#define        DMF_RNG         0100            /* ring */
+#define        DMF_DSR         0200            /* data set ready */
+
+/* bits in dmftms */
+#define        DMF_USRW        0001            /* user modem signal (pin 18) */
+#define        DMF_DTR         0002            /* data terminal ready */
+#define        DMF_RATE        0004            /* data signal rate select */
+#define        DMF_ST          0010            /* secondary transmit */
+#define        DMF_RTS         0020            /* request to send */
+#define        DMF_BRK         0040            /* pseudo break bit */
+#define        DMF_PREEMPT     0200            /* preempt output */
+
+/* flags for modem control */
+#define        DMF_ON  (DMF_DTR|DMF_RTS)
+#define        DMF_OFF 0
+
+/* bits in dmflcr */
+#define        DMF_MIE         0040            /* modem interrupt enable */
+#define        DMF_FLUSH       0020            /* flush transmit silo */
+#define        DMF_RBRK        0010            /* real break bit */
+#define        DMF_RE          0004            /* receive enable */
+#define        DMF_AUTOX       0002            /* auto XON/XOFF */
+#define        DMF_TE          0001            /* transmit enable */
+
+#define        DMFLCR_ENA      (DMF_MIE|DMF_RE|DMF_TE)
+
+/* bits in dm lsr, copied from dh.c */
+#define        DML_USR         0001000         /* usr modem sig, not a real DM bit */
+#define        DML_DSR         0000400         /* data set ready, not a real DM bit */
+#define        DML_RNG         0000200         /* ring */
+#define        DML_CAR         0000100         /* carrier detect */
+#define        DML_CTS         0000040         /* clear to send */
+#define        DML_SR          0000020         /* secondary receive */
+#define        DML_ST          0000010         /* secondary transmit */
+#define        DML_RTS         0000004         /* request to send */
+#define        DML_DTR         0000002         /* data terminal ready */
+#define        DML_LE          0000001         /* line enable */
+
+#define SETLCR(pt, exp) \
+       pt->dmfun.dmfirw = (((pt)->dmftms)<<8) | ((exp)&0xff)
diff --git a/usr/src/sys/vaxuba/dmreg.h b/usr/src/sys/vaxuba/dmreg.h
new file mode 100644 (file)
index 0000000..97c2357
--- /dev/null
@@ -0,0 +1,37 @@
+/*     dmreg.h 6.1     83/07/29        */
+
+/*
+ * DM-11 device register definitions.
+ */
+struct dmdevice {
+       short   dmcsr;          /* control status register */
+       short   dmlstat;        /* line status register */
+       short   dmpad1[2];
+};
+
+/* bits in dm csr */
+#define        DM_RF           0100000         /* ring flag */
+#define        DM_CF           0040000         /* carrier flag */
+#define        DM_CTS          0020000         /* clear to send */
+#define        DM_SRF          0010000         /* secondary receive flag */
+#define        DM_CS           0004000         /* clear scan */
+#define        DM_CM           0002000         /* clear multiplexor */
+#define        DM_MM           0001000         /* maintenance mode */
+#define        DM_STP          0000400         /* step */
+#define        DM_DONE         0000200         /* scanner is done */
+#define        DM_IE           0000100         /* interrupt enable */
+#define        DM_SE           0000040         /* scan enable */
+#define        DM_BUSY         0000020         /* scan busy */
+
+/* bits in dm lsr */
+#define        DML_RNG         0000200         /* ring */
+#define        DML_CAR         0000100         /* carrier detect */
+#define        DML_CTS         0000040         /* clear to send */
+#define        DML_SR          0000020         /* secondary receive */
+#define        DML_ST          0000010         /* secondary transmit */
+#define        DML_RTS         0000004         /* request to send */
+#define        DML_DTR         0000002         /* data terminal ready */
+#define        DML_LE          0000001         /* line enable */
+
+#define        DML_ON          (DML_DTR|DML_RTS|DML_LE)
+#define        DML_OFF         (DML_LE)
diff --git a/usr/src/sys/vaxuba/dn.c b/usr/src/sys/vaxuba/dn.c
new file mode 100644 (file)
index 0000000..a2886b7
--- /dev/null
@@ -0,0 +1,197 @@
+/*     dn.c    6.1     83/07/29        */
+
+#include "dn.h"
+#if NDN > 0
+/*
+ * DN-11 ACU interface
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/map.h"
+#include "../h/conf.h"
+#include "../h/uio.h"
+
+#include "../vaxuba/ubavar.h"
+
+struct dndevice {
+       u_short dn_reg[4];
+};
+
+struct uba_device *dninfo[NDN];
+int dnprobe(), dnattach(), dnintr();
+u_short dnstd[] = { 0175200 };
+struct uba_driver dndriver =
+       { dnprobe, 0, dnattach, 0, dnstd, "dn", dninfo };
+
+#define        CRQ     0x001           /* call request */
+#define        DPR     0x002           /* digit present */
+#define        MENABLE 0x004           /* master enable */
+#define MAINT  0x008           /* maintenance mode */
+#define        PND     0x010           /* present next digit */
+#define        DSS     0x020           /* data set status */
+#define        IENABLE 0x040           /* interrupt enable */
+#define        DONE    0x080           /* operation complete */
+#define        DLO     0x1000          /* data line occupied */
+#define        ACR     0x4000          /* abandon call and retry */
+#define        PWI     0x8000          /* power indicate */
+
+#define        DNPRI   (PZERO+5)
+#define DNUNIT(dev)    (minor(dev)>>2)
+#define DNREG(dev)     ((dev)&03)
+
+#define OBUFSIZ        40              /* largest phone # dialer can handle */
+
+/*
+ * There's no good way to determine the correct number of dialers attached
+ * to a single device (especially when dialers such as Vadic-821 MACS
+ * exist which can address four chassis, each with its own dialer).
+ */
+dnprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;  /* value-result, must be r11, r10 */
+       register struct dndevice *dnaddr = (struct dndevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = 0; br = cvec; cvec = br;
+       dnintr(0);
+#endif
+       /*
+        * If there's at least one dialer out there it better be
+        * at chassis 0.
+        */
+       dnaddr->dn_reg[0] = MENABLE|IENABLE|DONE;
+       DELAY(5);
+       dnaddr->dn_reg[0] = 0;
+       return (sizeof (struct dndevice));
+}
+
+/*ARGSUSED*/
+dnattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+/*ARGSUSED*/
+dnopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register struct dndevice *dp;
+       register u_short unit, *dnreg;
+       register struct uba_device *ui;
+       register short dialer;
+
+       if ((unit = DNUNIT(dev)) >= NDN || (ui = dninfo[unit]) == 0 ||
+           ui->ui_alive == 0)
+               return (ENXIO);
+       dialer = DNREG(dev);
+       dp = (struct dndevice *)ui->ui_addr;
+       if (dp->dn_reg[dialer] & PWI)
+               return (ENXIO);
+       dnreg = &(dp->dn_reg[dialer]);
+       if (*dnreg&(DLO|CRQ))
+               return (EBUSY);
+       dp->dn_reg[0] |= MENABLE;
+       *dnreg = IENABLE|MENABLE|CRQ;
+       return (0);
+}
+
+/*ARGSUSED*/
+dnclose(dev, flag)
+       dev_t dev;
+{
+       register struct dndevice *dp;
+
+       dp = (struct dndevice *)dninfo[DNUNIT(dev)]->ui_addr;
+       dp->dn_reg[DNREG(dev)] = MENABLE;
+}
+
+dnwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register u_short *dnreg;
+       register int cc;
+       register struct dndevice *dp;
+       char obuf[OBUFSIZ];
+       register char *cp;
+       extern lbolt;
+       int error;
+
+       dp = (struct dndevice *)dninfo[DNUNIT(dev)]->ui_addr;
+       dnreg = &(dp->dn_reg[DNREG(dev)]);
+       cc = MIN(uio->uio_resid, OBUFSIZ);
+       cp = obuf;
+       error = uiomove(cp, cc, UIO_WRITE, uio);
+       if (error)
+               return (error);
+       while ((*dnreg & (PWI|ACR|DSS)) == 0 && cc >= 0) {
+               (void) spl4();
+               if ((*dnreg & PND) == 0 || cc == 0)
+                       sleep((caddr_t)dnreg, DNPRI);
+               else switch(*cp) {
+               
+               case '-':
+                       sleep((caddr_t)&lbolt, DNPRI);
+                       sleep((caddr_t)&lbolt, DNPRI);
+                       break;
+
+               case 'f':
+                       *dnreg &= ~CRQ;
+                       sleep((caddr_t)&lbolt, DNPRI);
+                       *dnreg |= CRQ;
+                       break;
+
+               case '*': case ':':
+                       *cp = 012;
+                       goto dial;
+
+               case '#': case ';':
+                       *cp = 013;
+                       goto dial;
+
+               case 'e': case '<':
+                       *cp = 014;
+                       goto dial;
+
+               case 'w': case '=':
+                       *cp = 015;
+                       goto dial;
+
+               default:
+                       if (*cp < '0' || *cp > '9')
+                               break;
+               dial:
+                       *dnreg = (*cp << 8) | (IENABLE|MENABLE|DPR|CRQ);
+                       sleep((caddr_t)dnreg, DNPRI);
+               }
+               cp++, cc--;
+               spl0();
+       }
+       if (*dnreg & (PWI|ACR))
+               return (EIO);
+       return (0);
+}
+
+dnintr(dev)
+       dev_t dev;
+{
+       register u_short *basereg, *dnreg;
+
+       basereg = (u_short *)dninfo[dev]->ui_addr;
+       *basereg &= ~MENABLE;
+       for (dnreg = basereg; dnreg < basereg + 4; dnreg++)
+               if (*dnreg & DONE) {
+                       *dnreg &= ~(DONE|DPR);
+                       wakeup((caddr_t)dnreg);
+               }
+       *basereg |= MENABLE;
+}
+#endif
diff --git a/usr/src/sys/vaxuba/dz.c b/usr/src/sys/vaxuba/dz.c
new file mode 100644 (file)
index 0000000..4a84c54
--- /dev/null
@@ -0,0 +1,635 @@
+/*     dz.c    6.1     83/07/29        */
+
+#include "dz.h"
+#if NDZ > 0
+/*
+ *  DZ-11/DZ-32 Driver
+ *
+ * This driver mimics dh.c; see it for explanation of common code.
+ */
+#include "bk.h"
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/ioctl.h"
+#include "../h/tty.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/vm.h"
+#include "../h/conf.h"
+#include "../h/bk.h"
+#include "../h/file.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vaxuba/pdma.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/dzreg.h"
+
+/*
+ * Driver information for auto-configuration stuff.
+ */
+int    dzprobe(), dzattach(), dzrint();
+struct uba_device *dzinfo[NDZ];
+u_short        dzstd[] = { 0 };
+struct uba_driver dzdriver =
+       { dzprobe, 0, dzattach, 0, dzstd, "dz", dzinfo };
+
+#define        NDZLINE         (NDZ*8)
+
+int    dzstart(), dzxint(), dzdma();
+int    ttrstrt();
+struct tty dz_tty[NDZLINE];
+int    dz_cnt = { NDZLINE };
+int    dzact;
+
+#define dzwait(x)      while (((x)->dzlcs & DZ_ACK) == 0)
+
+/*
+ * Software copy of dzbrk since it isn't readable
+ */
+char   dz_brk[NDZ];
+char   dzsoftCAR[NDZ];
+char   dz_lnen[NDZ];   /* saved line enable bits for DZ32 */
+
+/*
+ * The dz11 doesn't interrupt on carrier transitions, so
+ * we have to use a timer to watch it.
+ */
+char   dz_timer;               /* timer started? */
+
+/*
+ * Pdma structures for fast output code
+ */
+struct pdma dzpdma[NDZLINE];
+
+char   dz_speeds[] =
+       { 0,020,021,022,023,024,0,025,026,027,030,032,034,036,037,0 };
+#ifndef PORTSELECTOR
+#define        ISPEED  B300
+#define        IFLAGS  (EVENP|ODDP|ECHO)
+#else
+#define        ISPEED  B4800
+#define        IFLAGS  (EVENP|ODDP)
+#endif
+
+dzprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+       register struct dzdevice *dzaddr = (struct dzdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       dzrint(0); dzxint((struct tty *)0);
+#endif
+       dzaddr->dzcsr = DZ_TIE|DZ_MSE|DZ_32;
+       if (dzaddr->dzcsr & DZ_32)
+               dzaddr->dzlnen = 1;
+       else
+               dzaddr->dztcr = 1;              /* enable any line */
+       DELAY(100000);
+       dzaddr->dzcsr = DZ_CLR|DZ_32;           /* reset everything */
+       if (cvec && cvec != 0x200)
+               cvec -= 4;
+       return (sizeof (struct dzdevice));
+}
+
+dzattach(ui)
+       register struct uba_device *ui;
+{
+       register struct pdma *pdp = &dzpdma[ui->ui_unit*8];
+       register struct tty *tp = &dz_tty[ui->ui_unit*8];
+       register int cntr;
+       extern dzscan();
+
+       for (cntr = 0; cntr < 8; cntr++) {
+               pdp->p_addr = (struct dzdevice *)ui->ui_addr;
+               pdp->p_arg = (int)tp;
+               pdp->p_fcn = dzxint;
+               pdp++, tp++;
+       }
+       dzsoftCAR[ui->ui_unit] = ui->ui_flags;
+       if (dz_timer == 0) {
+               dz_timer++;
+               timeout(dzscan, (caddr_t)0, hz);
+       }
+}
+
+/*ARGSUSED*/
+dzopen(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit;
+       unit = minor(dev);
+       if (unit >= dz_cnt || dzpdma[unit].p_addr == 0)
+               return (ENXIO);
+       tp = &dz_tty[unit];
+       tp->t_addr = (caddr_t)&dzpdma[unit];
+       tp->t_oproc = dzstart;
+       tp->t_state |= TS_WOPEN;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+               ttychars(tp);
+               tp->t_ospeed = tp->t_ispeed = ISPEED;
+               tp->t_flags = IFLAGS;
+               /* tp->t_state |= TS_HUPCLS; */
+               dzparam(unit);
+       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+               return (EBUSY);
+       (void) dzmctl(dev, DZ_ON, DMSET);
+       (void) spl5();
+       while ((tp->t_state & TS_CARR_ON) == 0) {
+               tp->t_state |= TS_WOPEN;
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       }
+       (void) spl0();
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+/*ARGSUSED*/
+dzclose(dev, flag)
+       dev_t dev;
+{
+       register struct tty *tp;
+       register int unit;
+       register struct dzdevice *dzaddr;
+       int dz;
+       unit = minor(dev);
+       dz = unit >> 3;
+       tp = &dz_tty[unit];
+       (*linesw[tp->t_line].l_close)(tp);
+       dzaddr = dzpdma[unit].p_addr;
+       if (dzaddr->dzcsr&DZ_32)
+               (void) dzmctl(dev, DZ_BRK, DMBIC);
+       else
+               dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
+       if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN) == 0)
+               (void) dzmctl(dev, DZ_OFF, DMSET);
+       ttyclose(tp);
+}
+dzread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp;
+       tp = &dz_tty[minor(dev)];
+       return ((*linesw[tp->t_line].l_read)(tp, uio));
+}
+dzwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register struct tty *tp;
+       tp = &dz_tty[minor(dev)];
+       return ((*linesw[tp->t_line].l_write)(tp, uio));
+}
+/*ARGSUSED*/
+dzrint(dz)
+       int dz;
+{
+       register struct tty *tp;
+       register int c;
+       register struct dzdevice *dzaddr;
+       register struct tty *tp0;
+       register int unit;
+       int overrun = 0;
+       if ((dzact & (1<<dz)) == 0)
+               return;
+       unit = dz * 8;
+       dzaddr = dzpdma[unit].p_addr;
+       tp0 = &dz_tty[unit];
+       dzaddr->dzcsr &= ~(DZ_RIE|DZ_MIE);      /* the manual says this song */
+       dzaddr->dzcsr |= DZ_RIE|DZ_MIE;         /*   and dance is necessary */
+       while (dzaddr->dzcsr & DZ_MSC) {        /* DZ32 modem change interrupt */
+               c = dzaddr->dzmtsr;
+               tp = tp0 + (c&7);
+               if (tp >= &dz_tty[dz_cnt])
+                       break;
+               dzaddr->dzlcs = c&7;    /* get status of modem lines */
+               dzwait(dzaddr);         /* wait for them */
+               if (c & DZ_CD)          /* carrier status change? */
+               if (dzaddr->dzlcs & DZ_CD) {    /* carrier up? */
+                       if ((tp->t_state&TS_CARR_ON) == 0) {
+                               wakeup((caddr_t)&tp->t_rawq);
+                               tp->t_state |= TS_CARR_ON;
+                       }
+               } else {        /* no carrier */
+                       if (tp->t_state&TS_CARR_ON) {
+                               gsignal(tp->t_pgrp, SIGHUP);
+                               gsignal(tp->t_pgrp, SIGCONT);
+                               dzaddr->dzlcs = DZ_ACK|(c&7);
+                               ttyflush(tp, FREAD|FWRITE);
+                       }
+                       tp->t_state &= ~TS_CARR_ON;
+               }
+       }
+       while ((c = dzaddr->dzrbuf) < 0) {      /* char present */
+               tp = tp0 + ((c>>8)&07);
+               if (tp >= &dz_tty[dz_cnt])
+                       continue;
+               if ((tp->t_state & TS_ISOPEN) == 0) {
+                       wakeup((caddr_t)&tp->t_rawq);
+#ifdef PORTSELECTOR
+                       if ((tp->t_state&TS_WOPEN) == 0)
+#endif
+                       continue;
+               }
+               if (c&DZ_FE)
+                       if (tp->t_flags & RAW)
+                               c = 0;
+                       else
+                               c = tp->t_intrc;
+               if (c&DZ_DO && overrun == 0) {
+                       /* printf("dz%d,%d: silo overflow\n", dz, (c>>8)&7); */
+                       overrun = 1;
+               }
+               if (c&DZ_PE)    
+                       if (((tp->t_flags & (EVENP|ODDP)) == EVENP)
+                         || ((tp->t_flags & (EVENP|ODDP)) == ODDP))
+                               continue;
+#if NBK > 0
+               if (tp->t_line == NETLDISC) {
+                       c &= 0177;
+                       BKINPUT(c, tp);
+               } else
+#endif
+                       (*linesw[tp->t_line].l_rint)(c, tp);
+       }
+}
+/*ARGSUSED*/
+dzioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct tty *tp;
+       register int unit = minor(dev);
+       register int dz = unit >> 3;
+       register struct dzdevice *dzaddr;
+       int error;
+       tp = &dz_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) {
+               if (cmd == TIOCSETP || cmd == TIOCSETN)
+                       dzparam(unit);
+               return (error);
+       }
+       switch (cmd) {
+
+       case TIOCSBRK:
+               dzaddr = ((struct pdma *)(tp->t_addr))->p_addr;
+               if (dzaddr->dzcsr&DZ_32)
+                       (void) dzmctl(dev, DZ_BRK, DMBIS);
+               else
+                       dzaddr->dzbrk = (dz_brk[dz] |= 1 << (unit&07));
+               break;
+
+       case TIOCCBRK:
+               dzaddr = ((struct pdma *)(tp->t_addr))->p_addr;
+               if (dzaddr->dzcsr&DZ_32)
+                       (void) dzmctl(dev, DZ_BRK, DMBIC);
+               else
+                       dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
+               break;
+
+       case TIOCSDTR:
+               (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIS);
+               break;
+
+       case TIOCCDTR:
+               (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIC);
+               break;
+
+       case TIOCMSET:
+               (void) dzmctl(dev, dmtodz(*(int *)data), DMSET);
+               break;
+
+       case TIOCMBIS:
+               (void) dzmctl(dev, dmtodz(*(int *)data), DMBIS);
+               break;
+
+       case TIOCMBIC:
+               (void) dzmctl(dev, dmtodz(*(int *)data), DMBIC);
+               break;
+
+       case TIOCMGET:
+               *(int *)data = dztodm(dzmctl(dev, 0, DMGET));
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+dmtodz(bits)
+       register int bits;
+{
+       register int b;
+
+       b = (bits >>1) & 0370;
+       if (bits & DML_ST) b |= DZ_ST;
+       if (bits & DML_RTS) b |= DZ_RTS;
+       if (bits & DML_DTR) b |= DZ_DTR;
+       if (bits & DML_LE) b |= DZ_LE;
+       return(b);
+}
+
+dztodm(bits)
+       register int bits;
+{
+       register int b;
+
+       b = (bits << 1) & 0360;
+       if (bits & DZ_DSR) b |= DML_DSR;
+       if (bits & DZ_DTR) b |= DML_DTR;
+       if (bits & DZ_ST) b |= DML_ST;
+       if (bits & DZ_RTS) b |= DML_RTS;
+       return(b);
+}
+dzparam(unit)
+       register int unit;
+{
+       register struct tty *tp;
+       register struct dzdevice *dzaddr;
+       register int lpr;
+       tp = &dz_tty[unit];
+       dzaddr = dzpdma[unit].p_addr;
+       dzaddr->dzcsr = DZ_IEN;
+       dzact |= (1<<(unit>>3));
+       if (tp->t_ispeed == 0) {
+               (void) dzmctl(unit, DZ_OFF, DMSET);     /* hang up line */
+               return;
+       }
+       lpr = (dz_speeds[tp->t_ispeed]<<8) | (unit & 07);
+       if (tp->t_flags & (RAW|LITOUT))
+               lpr |= BITS8;
+       else
+               lpr |= (BITS7|PENABLE);
+       if ((tp->t_flags & EVENP) == 0)
+               lpr |= OPAR;
+       if (tp->t_ispeed == B110)
+               lpr |= TWOSB;
+       dzaddr->dzlpr = lpr;
+}
+dzxint(tp)
+       register struct tty *tp;
+{
+       register struct pdma *dp;
+       register s, dz, unit;
+       s = spl5();             /* block pdma interrupts */
+       dp = (struct pdma *)tp->t_addr;
+       tp->t_state &= ~TS_BUSY;
+       if (tp->t_state & TS_FLUSH)
+               tp->t_state &= ~TS_FLUSH;
+       else {
+               ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
+               dp->p_end = dp->p_mem = tp->t_outq.c_cf;
+       }
+       if (tp->t_line)
+               (*linesw[tp->t_line].l_start)(tp);
+       else
+               dzstart(tp);
+       dz = minor(tp->t_dev) >> 3;
+       unit = minor(tp->t_dev) & 7;
+       if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0)
+               if (dp->p_addr->dzcsr & DZ_32)
+                       dp->p_addr->dzlnen = (dz_lnen[dz] &= ~(1<<unit));
+               else
+                       dp->p_addr->dztcr &= ~(1<<unit);
+       splx(s);
+}
+
+dzstart(tp)
+       register struct tty *tp;
+{
+       register struct pdma *dp;
+       register struct dzdevice *dzaddr;
+       register int cc;
+       int s, dz, unit;
+       dp = (struct pdma *)tp->t_addr;
+       dzaddr = dp->p_addr;
+       s = spl5();
+       if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+               goto out;
+       if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
+               if (tp->t_state&TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup((caddr_t)&tp->t_outq);
+               }
+               if (tp->t_wsel) {
+                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+                       tp->t_wsel = 0;
+                       tp->t_state &= ~TS_WCOLL;
+               }
+       }
+       if (tp->t_outq.c_cc == 0)
+               goto out;
+       if (tp->t_flags & (RAW|LITOUT))
+               cc = ndqb(&tp->t_outq, 0);
+       else {
+               cc = ndqb(&tp->t_outq, 0200);
+               if (cc == 0) {
+                       cc = getc(&tp->t_outq);
+                       timeout(ttrstrt, (caddr_t)tp, (cc&0x7f) + 6);
+                       tp->t_state |= TS_TIMEOUT;
+                       goto out;
+               }
+       }
+       tp->t_state |= TS_BUSY;
+       dp->p_end = dp->p_mem = tp->t_outq.c_cf;
+       dp->p_end += cc;
+       dz = minor(tp->t_dev) >> 3;
+       unit = minor(tp->t_dev) & 7;
+       if (dzaddr->dzcsr & DZ_32)
+               dzaddr->dzlnen = (dz_lnen[dz] |= (1<<unit));
+       else
+               dzaddr->dztcr |= (1<<unit);
+out:
+       splx(s);
+}
+/*
+ * Stop output on a line.
+ */
+/*ARGSUSED*/
+dzstop(tp, flag)
+       register struct tty *tp;
+{
+       register struct pdma *dp;
+       register int s;
+
+       dp = (struct pdma *)tp->t_addr;
+       s = spl5();
+       if (tp->t_state & TS_BUSY) {
+               dp->p_end = dp->p_mem;
+               if ((tp->t_state&TS_TTSTOP)==0)
+                       tp->t_state |= TS_FLUSH;
+       }
+       splx(s);
+}
+dzmctl(dev, bits, how)
+       dev_t dev;
+       int bits, how;
+{
+       register struct dzdevice *dzaddr;
+       register int unit, mbits;
+       int b, s;
+
+       unit = minor(dev);
+       b = 1<<(unit&7);
+       dzaddr = dzpdma[unit].p_addr;
+       s = spl5();
+       if (dzaddr->dzcsr & DZ_32) {
+               dzwait(dzaddr)
+               DELAY(100);             /* IS 100 TOO MUCH? */
+               dzaddr->dzlcs = unit&7;
+               DELAY(100);
+               dzwait(dzaddr)
+               DELAY(100);
+               mbits = dzaddr->dzlcs;
+               mbits &= 0177770;
+       } else {
+               mbits = (dzaddr->dzdtr & b) ? DZ_DTR : 0;
+               mbits |= (dzaddr->dzmsr & b) ? DZ_CD : 0;
+               mbits |= (dzaddr->dztbuf & b) ? DZ_RI : 0;
+       }
+       switch (how) {
+       case DMSET:
+               mbits = bits;
+               break;
+
+       case DMBIS:
+               mbits |= bits;
+               break;
+
+       case DMBIC:
+               mbits &= ~bits;
+               break;
+
+       case DMGET:
+               (void) splx(s);
+               return(mbits);
+       }
+       if (dzaddr->dzcsr & DZ_32) {
+               mbits |= DZ_ACK|(unit&7);
+               dzaddr->dzlcs = mbits;
+       } else {
+               if (mbits & DZ_DTR)
+                       dzaddr->dzdtr |= b;
+               else
+                       dzaddr->dzdtr &= ~b;
+       }
+       (void) splx(s);
+       return(mbits);
+}
+dzscan()
+{
+       register i;
+       register struct dzdevice *dzaddr;
+       register bit;
+       register struct tty *tp;
+       register car;
+       for (i = 0; i < dz_cnt ; i++) {
+               dzaddr = dzpdma[i].p_addr;
+               if (dzaddr == 0)
+                       continue;
+               tp = &dz_tty[i];
+               bit = 1<<(i&07);
+               car = 0;
+               if (dzsoftCAR[i>>3]&bit)
+                       car = 1;
+               else if (dzaddr->dzcsr & DZ_32) {
+                       dzaddr->dzlcs = i&07;
+                       dzwait(dzaddr);
+                       car = dzaddr->dzlcs & DZ_CD;
+               } else
+                       car = dzaddr->dzmsr&bit;
+               if (car) {
+                       /* carrier present */
+                       if ((tp->t_state & TS_CARR_ON) == 0) {
+                               wakeup((caddr_t)&tp->t_rawq);
+                               tp->t_state |= TS_CARR_ON;
+                       }
+               } else {
+                       if ((tp->t_state&TS_CARR_ON) &&
+                           (tp->t_flags&NOHANG) == 0) {
+                               /* carrier lost */
+                               if (tp->t_state&TS_ISOPEN) {
+                                       gsignal(tp->t_pgrp, SIGHUP);
+                                       gsignal(tp->t_pgrp, SIGCONT);
+                                       dzaddr->dzdtr &= ~bit;
+                                       ttyflush(tp, FREAD|FWRITE);
+                               }
+                               tp->t_state &= ~TS_CARR_ON;
+                       }
+               }
+       }
+       timeout(dzscan, (caddr_t)0, 2*hz);
+}
+
+dztimer()
+{
+       register int dz;
+       register int s = spl5();
+
+       for (dz = 0; dz < NDZ; dz++)
+               dzrint(dz);
+       splx(s);
+}
+
+/*
+ * Reset state of driver if UBA reset was necessary.
+ * Reset parameters and restart transmission on open lines.
+ */
+dzreset(uban)
+       int uban;
+{
+       register int unit;
+       register struct tty *tp;
+       register struct uba_device *ui;
+
+       for (unit = 0; unit < NDZLINE; unit++) {
+               ui = dzinfo[unit >> 3];
+               if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
+                       continue;
+               if (unit%8 == 0)
+                       printf(" dz%d", unit>>3);
+               tp = &dz_tty[unit];
+               if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
+                       dzparam(unit);
+                       (void) dzmctl(unit, DZ_ON, DMSET);
+                       tp->t_state &= ~TS_BUSY;
+                       dzstart(tp);
+               }
+       }
+       dztimer();
+}
+#endif
diff --git a/usr/src/sys/vaxuba/dzreg.h b/usr/src/sys/vaxuba/dzreg.h
new file mode 100644 (file)
index 0000000..b19307e
--- /dev/null
@@ -0,0 +1,83 @@
+/*     dzreg.h 6.1     83/07/29        */
+
+/*
+ * DZ-11/DZ-32 Registers and bits.
+ */
+struct dzdevice {
+       short dzcsr;
+       short dzrbuf;
+       union {
+               struct {
+                       char    dztcr0;
+                       char    dzdtr0;
+                       char    dztbuf0;
+                       char    dzbrk0;
+               } dz11;
+               struct {
+                       short   dzlcs0;
+                       char    dztbuf0;
+                       char    dzlnen0;
+               } dz32;
+       } dzun;
+};
+
+#define dzlpr  dzrbuf
+#define dzmsr  dzun.dz11.dzbrk0
+#define dztcr  dzun.dz11.dztcr0
+#define dzdtr  dzun.dz11.dzdtr0
+#define dztbuf dzun.dz11.dztbuf0
+#define dzlcs  dzun.dz32.dzlcs0
+#define        dzbrk   dzmsr
+#define dzlnen dzun.dz32.dzlnen0
+#define dzmtsr dzun.dz32.dztbuf0
+
+/* bits in dzlpr */
+#define        BITS7   0020
+#define        BITS8   0030
+#define        TWOSB   0040
+#define        PENABLE 0100
+#define        OPAR    0200
+
+/* bits in dzrbuf */
+#define        DZ_PE   010000
+#define        DZ_FE   020000
+#define        DZ_DO   040000
+
+/* bits in dzcsr */
+#define        DZ_32   000001          /* DZ32 mode */
+#define        DZ_MIE  000002          /* Modem Interrupt Enable */
+#define        DZ_CLR  000020          /* Reset dz */
+#define        DZ_MSE  000040          /* Master Scan Enable */
+#define        DZ_RIE  000100          /* Receiver Interrupt Enable */
+#define DZ_MSC 004000          /* Modem Status Change */
+#define        DZ_SAE  010000          /* Silo Alarm Enable */
+#define        DZ_TIE  040000          /* Transmit Interrupt Enable */
+#define        DZ_IEN  (DZ_32|DZ_MIE|DZ_MSE|DZ_RIE|DZ_TIE|DZ_SAE)
+
+/* flags for modem-control */
+#define        DZ_ON   DZ_DTR
+#define        DZ_OFF  0
+
+/* bits in dzlcs */
+#define DZ_ACK 0100000         /* ACK bit in dzlcs */
+#define DZ_RTS 0010000         /* Request To Send */
+#define        DZ_ST   0004000         /* Secondary Transmit */
+#define        DZ_BRK  0002000         /* Break */
+#define DZ_DTR 0001000         /* Data Terminal Ready */
+#define        DZ_LE   0000400         /* Line Enable */
+#define        DZ_DSR  0000200         /* Data Set Ready */
+#define        DZ_RI   0000100         /* Ring Indicate */
+#define DZ_CD  0000040         /* Carrier Detect */
+#define        DZ_CTS  0000020         /* Clear To Send */
+#define        DZ_SR   0000010         /* Secondary Receive */
+/* bits in dm lsr, copied from dmreg.h */
+#define        DML_DSR         0000400         /* data set ready, not a real DM bit */
+#define        DML_RNG         0000200         /* ring */
+#define        DML_CAR         0000100         /* carrier detect */
+#define        DML_CTS         0000040         /* clear to send */
+#define        DML_SR          0000020         /* secondary receive */
+#define        DML_ST          0000010         /* secondary transmit */
+#define        DML_RTS         0000004         /* request to send */
+#define        DML_DTR         0000002         /* data terminal ready */
+#define        DML_LE          0000001         /* line enable */
diff --git a/usr/src/sys/vaxuba/idc.c b/usr/src/sys/vaxuba/idc.c
new file mode 100644 (file)
index 0000000..088490f
--- /dev/null
@@ -0,0 +1,872 @@
+/*     idc.c   6.1     83/07/29        */
+
+#include "rb.h"
+#if NIDC > 0
+int    idcdebug = 0;
+#define        printd if(idcdebug)printf
+int    idctrb[1000];
+int    *trp = idctrb;
+#define        trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;}
+/*
+ * IDC (RB730) disk driver
+ *
+ * There can only ever be one IDC on a machine,
+ * and only on a VAX-11/730.  We take advantage
+ * of that to simplify the driver.
+ *
+ * TODO:
+ *     dk_busy
+ *     ecc
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/dk.h"
+#include "../h/cmap.h"
+#include "../h/dkbad.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/idcreg.h"
+
+struct idc_softc {
+       int     sc_bcnt;        /* number of bytes to transfer */
+       int     sc_resid;       /* total number of bytes to transfer */
+       int     sc_ubaddr;      /* Unibus address of data */
+       short   sc_unit;        /* unit doing transfer */
+       short   sc_softas;      /* software attention summary bits */
+       union idc_dar {
+               long    dar_l;
+               u_short dar_w[2];
+               u_char  dar_b[4];
+       } sc_un;                /* prototype disk address register */
+} idc_softc;
+
+#define        dar_dar         dar_l           /* the whole disk address */
+#define        dar_cyl         dar_w[1]        /* cylinder address */
+#define        dar_trk         dar_b[1]        /* track */
+#define        dar_sect        dar_b[0]        /* sector */
+#define        sc_dar          sc_un.dar_dar
+#define        sc_cyl          sc_un.dar_cyl
+#define        sc_trk          sc_un.dar_trk
+#define        sc_sect         sc_un.dar_sect
+
+/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
+struct size {
+       daddr_t nblocks;
+       int     cyloff;
+} rb02_sizes[8] ={
+       15884,  0,              /* A=cyl 0 thru 399 */
+       4480,   400,            /* B=cyl 400 thru 510 */
+       20480,  0,              /* C=cyl 0 thru 511 */
+       0,      0,
+       0,      0,
+       0,      0,
+       0,      0,
+       0,      0,
+}, rb80_sizes[8] ={
+       15884,  0,              /* A=cyl 0 thru 36 */
+       33440,  37,             /* B=cyl 37 thru 114 */
+       242606, 0,              /* C=cyl 0 thru 558 */
+       0,      0,
+       0,      0,
+       0,      0,
+       82080,  115,            /* G=cyl 115 thru 304 */
+       110143, 305,            /* H=cyl 305 thru 558 */
+};
+/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
+
+int    idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr();
+struct uba_ctlr *idcminfo[NIDC];
+struct uba_device *idcdinfo[NRB];
+
+u_short        idcstd[] = { 0174400, 0};
+struct uba_driver idcdriver =
+ { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 };
+struct buf idcutab[NRB];
+union  idc_dar idccyl[NRB];
+
+struct idcst {
+       short   nbps;
+       short   nsect;
+       short   ntrak;
+       short   nspc;
+       short   ncyl;
+       struct  size *sizes;
+} idcst[] = {
+       256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes,
+       512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes,
+};
+
+struct buf ridcbuf[NRB];
+
+#define        b_cylin b_resid
+
+#ifdef INTRLVE
+daddr_t        dkblock();
+#endif
+
+int    idcwstart, idcwticks, idcwatch();
+
+/*ARGSUSED*/
+idcprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+       register struct idcdevice *idcaddr;
+
+#ifdef lint    
+       br = 0; cvec = br; br = cvec;
+#endif
+       idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
+       idcaddr->idccsr = IDC_ATTN|IDC_IE;
+       while ((idcaddr->idccsr & IDC_CRDY) == 0)
+               ;
+       idcaddr->idccsr = IDC_ATTN|IDC_CRDY;
+       return (sizeof (struct idcdevice));
+}
+
+/*ARGSUSED*/
+idcslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       register struct idcdevice *idcaddr;
+       register int i;
+
+       idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
+       ui->ui_type = 0;
+       idcaddr->idcmpr = IDCGS_GETSTAT;
+       idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8);
+       (void) idcwait(idcaddr, 0);
+       i = idcaddr->idcmpr;
+       idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16));
+       /* read header to synchronize microcode */
+       (void) idcwait(idcaddr, 0);
+       idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR;
+       (void) idcwait(idcaddr, 0);
+       if (idcaddr->idccsr & IDC_ERR)
+               return (0);
+       i = idcaddr->idcmpr;            /* read header word 1 */
+       i = idcaddr->idcmpr;            /* read header word 2 */
+#ifdef lint
+       i = i;
+#endif
+       if (idcaddr->idccsr&IDC_R80)
+               ui->ui_type = 1;
+       return (1);
+}
+
+idcattach(ui)
+       register struct uba_device *ui;
+{
+
+       /*
+        * Fix all addresses to correspond
+        * to the "real" IDC address.
+        */
+       ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200;
+       ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200;
+       if (idcwstart == 0) {
+               timeout(idcwatch, (caddr_t)0, hz);
+               idcwstart++;
+       }
+       if (ui->ui_dk >= 0)
+               if (ui->ui_type)
+                       dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256);
+               else
+                       dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128);
+       idccyl[ui->ui_unit].dar_dar = -1;
+       ui->ui_flags = 0;
+}
+
+idcopen(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       return (0);
+}
+idcstrategy(bp)
+       register struct buf *bp;
+{
+       register struct uba_device *ui;
+       register struct idcst *st;
+       register int unit;
+       register struct buf *dp;
+       int xunit = minor(bp->b_dev) & 07;
+       long bn, sz;
+
+       sz = (bp->b_bcount+511) >> 9;
+       unit = dkunit(bp);
+       if (unit >= NRB)
+               goto bad;
+       ui = idcdinfo[unit];
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       st = &idcst[ui->ui_type];
+       if (bp->b_blkno < 0 ||
+           (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
+               goto bad;
+       if (ui->ui_type == 0)
+               bn *= 2;
+       bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
+       (void) spl5();
+       trace("strt",bp);
+       dp = &idcutab[ui->ui_unit];
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               trace("!act",dp);
+               (void) idcustart(ui);
+               bp = &ui->ui_mi->um_tab;
+               if (bp->b_actf && bp->b_active == 0)
+                       (void) idcstart(ui->ui_mi);
+       }
+       (void) spl0();
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+idcustart(ui)
+       register struct uba_device *ui;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um;
+       register struct idcdevice *idcaddr;
+       register struct idcst *st;
+       union idc_dar cyltrk;
+       daddr_t bn;
+       int unit;
+
+       if (ui == 0)
+               return (0);
+       dk_busy &= ~(1<<ui->ui_dk);
+       dp = &idcutab[ui->ui_unit];
+       um = ui->ui_mi;
+       unit = ui->ui_slave;
+       trace("ust", dp);
+       idcaddr = (struct idcdevice *)um->um_addr;
+       if (um->um_tab.b_active) {
+               idc_softc.sc_softas |= 1<<unit;
+               trace("umac",idc_softc.sc_softas);
+               return (0);
+       }
+       if ((bp = dp->b_actf) == NULL) {
+               trace("!bp",0);
+               return (0);
+       }
+       if (dp->b_active) {
+               trace("dpac",dp->b_active);
+               goto done;
+       }
+       dp->b_active = 1;
+       /* CHECK DRIVE READY? */
+       bn = dkblock(bp);
+       trace("seek", bn);
+       if (ui->ui_type == 0)
+               bn *= 2;
+       st = &idcst[ui->ui_type];
+       cyltrk.dar_cyl = bp->b_cylin;
+       cyltrk.dar_trk = (bn / st->nsect) % st->ntrak;
+       cyltrk.dar_sect = 0;
+       printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar);
+       /*
+        * If on cylinder, no need to seek.
+        */
+       if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar)
+               goto done;
+       /*
+        * RB80 can change heads (tracks) just by loading
+        * the disk address register, perform optimization
+        * here instead of doing a full seek.
+        */
+       if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) {
+               idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8);
+               idcaddr->idcdar = cyltrk.dar_dar;
+               idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
+               goto done;
+       }
+       /*
+        * Need to do a full seek.  Select the unit, clear
+        * its attention bit, set the command, load the
+        * disk address register, and then go.
+        */
+       idcaddr->idccsr =
+           IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
+       idcaddr->idcdar = cyltrk.dar_dar;
+       idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
+       printd("  seek");
+       idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8);
+       if (ui->ui_dk >= 0) {
+               dk_busy |= 1<<ui->ui_dk;
+               dk_seek[ui->ui_dk]++;
+       }
+       /*
+        * RB80's initiate seeks very quickly.  Wait for it
+        * to come ready rather than taking the interrupt.
+        */
+       if (ui->ui_type) {
+               if (idcwait(idcaddr, 10) == 0)
+                       return (1);
+               idcaddr->idccsr &= ~IDC_ATTN;
+               /* has the seek completed? */
+               if (idcaddr->idccsr & IDC_DRDY) {
+                       printd(", drdy");
+                       idcaddr->idccsr =
+                           IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
+                       goto done;
+               }
+       }
+       printd(", idccsr = 0x%x\n", idcaddr->idccsr);
+       return (1);
+done:
+       if (dp->b_active != 2) {
+               trace("!=2",dp->b_active);
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else {
+                       trace("!NUL",um->um_tab.b_actl);
+                       um->um_tab.b_actl->b_forw = dp;
+               }
+               um->um_tab.b_actl = dp;
+               dp->b_active = 2;
+       }
+       return (0);
+}
+
+idcstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct uba_device *ui;
+       register struct idcdevice *idcaddr;
+       register struct idc_softc *sc;
+       struct idcst *st;
+       daddr_t bn;
+       int sn, tn, cmd;
+
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL) {
+               trace("nodp",um);
+               return (0);
+       }
+       if ((bp = dp->b_actf) == NULL) {
+               trace("nobp", dp);
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       um->um_tab.b_active = 1;
+       ui = idcdinfo[dkunit(bp)];
+       bn = dkblock(bp);
+       trace("star",bp);
+       if (ui->ui_type == 0)
+               bn *= 2;
+       sc = &idc_softc;
+       st = &idcst[ui->ui_type];
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       sc->sc_sect = sn;
+       sc->sc_trk = tn;
+       sc->sc_cyl = bp->b_cylin;
+       idcaddr = (struct idcdevice *)ui->ui_addr;
+       printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar);
+       if (bp->b_flags & B_READ)
+               cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8);
+       else
+               cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8);
+       idcaddr->idccsr = IDC_CRDY|cmd;
+       if ((idcaddr->idccsr&IDC_DRDY) == 0) {
+               printf("rb%d: not ready\n", dkunit(bp));
+               um->um_tab.b_active = 0;
+               um->um_tab.b_errcnt = 0;
+               dp->b_actf = bp->av_forw;
+               dp->b_active = 0;
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               goto loop;
+       }
+       idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
+       idccyl[ui->ui_unit].dar_sect = 0;
+       sn = (st->nsect - sn) * st->nbps;
+       if (sn > bp->b_bcount)
+               sn = bp->b_bcount;
+       sc->sc_bcnt = sn;
+       sc->sc_resid = bp->b_bcount;
+       sc->sc_unit = ui->ui_slave;
+       printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd);
+       um->um_cmd = cmd;
+       (void) ubago(ui);
+       return (1);
+}
+
+idcdgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
+       register struct idc_softc *sc = &idc_softc;
+
+       /*
+        * VERY IMPORTANT: must load registers in this order.
+        */
+       idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff;
+       idcaddr->idcbcr = -sc->sc_bcnt;
+       idcaddr->idcdar = sc->sc_dar;
+       printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd);
+       idcaddr->idccsr = um->um_cmd;
+       trace("go", um);
+       um->um_tab.b_active = 2;
+       /*** CLEAR SPURIOUS ATTN ON R80? ***/
+}
+
+idcintr(idc)
+       int idc;
+{
+       register struct uba_ctlr *um = idcminfo[idc];
+       register struct uba_device *ui;
+       register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
+       register struct idc_softc *sc = &idc_softc;
+       register struct buf *bp, *dp;
+       struct idcst *st;
+       int unit, as, er, cmd, ds = 0;
+
+       printd("idcintr, idccsr 0x%x", idcaddr->idccsr);
+top:
+       idcwticks = 0;
+       trace("intr", um->um_tab.b_active);
+       if (um->um_tab.b_active == 2) {
+               /*
+                * Process a data transfer complete interrupt.
+                */
+               um->um_tab.b_active = 1;
+               dp = um->um_tab.b_actf;
+               bp = dp->b_actf;
+               ui = idcdinfo[dkunit(bp)];
+               unit = ui->ui_slave;
+               st = &idcst[ui->ui_type];
+               idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
+               if ((er = idcaddr->idccsr) & IDC_ERR) {
+                       if (er & IDC_DE) {
+                               idcaddr->idcmpr = IDCGS_GETSTAT;
+                               idcaddr->idccsr = IDC_GETSTAT|(unit<<8);
+                               (void) idcwait(idcaddr, 0);
+                               ds = idcaddr->idcmpr;
+                               idcaddr->idccsr =
+                                   IDC_IE|IDC_CRDY|(1<<(unit+16));
+                       }
+                       printd(", er 0x%x, ds 0x%x", er, ds);
+                       if (ds & IDCDS_WL) {
+                               printf("rb%d: write locked\n", dkunit(bp));
+                               bp->b_flags |= B_ERROR;
+                       } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) {
+hard:
+                               harderr(bp, "rb");
+                               printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 
+                                   ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS);
+                               bp->b_flags |= B_ERROR;
+                       } else if (er & IDC_DCK) {
+                               switch (er & IDC_ECS) {
+                               case IDC_ECS_NONE:
+                                       break;
+                               case IDC_ECS_SOFT:
+                                       idcecc(ui);
+                                       break;
+                               case IDC_ECS_HARD:
+                               default:
+                                       goto hard;
+                               }
+                       } else
+                               /* recoverable error, set up for retry */
+                               goto seek;
+               }
+               if ((sc->sc_resid -= sc->sc_bcnt) != 0) {
+                       sc->sc_ubaddr += sc->sc_bcnt;
+                       /*
+                        * Current transfer is complete, have
+                        * we overflowed to the next track?
+                        */
+                       if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) {
+                               sc->sc_sect = 0;
+                               if (++sc->sc_trk == st->ntrak) {
+                                       sc->sc_trk = 0;
+                                       sc->sc_cyl++;
+                               } else if (ui->ui_type) {
+                                       /*
+                                        * RB80 can change heads just by
+                                        * loading the disk address register.
+                                        */
+                                       idcaddr->idccsr = IDC_SEEK|IDC_CRDY|
+                                           IDC_IE|(unit<<8);
+                                       printd(", change to track 0x%x", sc->sc_dar);
+                                       idcaddr->idcdar = sc->sc_dar;
+                                       idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
+                                       idccyl[ui->ui_unit].dar_sect = 0;
+                                       goto cont;
+                               }
+                               /*
+                                * Changing tracks on RB02 or cylinders
+                                * on RB80, start a seek.
+                                */
+seek:
+                               cmd = IDC_IE|IDC_SEEK|(unit<<8);
+                               idcaddr->idccsr = cmd|IDC_CRDY;
+                               idcaddr->idcdar = sc->sc_dar;
+                               printd(", seek to 0x%x\n", sc->sc_dar);
+                               idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
+                               idccyl[ui->ui_unit].dar_sect = 0;
+                               sc->sc_bcnt = 0;
+                               idcaddr->idccsr = cmd;
+                               if (ui->ui_type) {
+                                       if (idcwait(idcaddr, 10) == 0)
+                                               return;
+                                       idcaddr->idccsr &= ~IDC_ATTN;
+                                       if (idcaddr->idccsr & IDC_DRDY)
+                                               goto top;
+                               }
+                       } else {
+                               /*
+                                * Continue transfer on current track.
+                                */
+cont:
+                               sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps;
+                               if (sc->sc_bcnt > sc->sc_resid)
+                                       sc->sc_bcnt = sc->sc_resid;
+                               if (bp->b_flags & B_READ)
+                                       cmd = IDC_IE|IDC_READ|(unit<<8);
+                               else
+                                       cmd = IDC_IE|IDC_WRITE|(unit<<8);
+                               idcaddr->idccsr = cmd|IDC_CRDY;
+                               idcaddr->idcbar = sc->sc_ubaddr;
+                               idcaddr->idcbcr = -sc->sc_bcnt;
+                               idcaddr->idcdar = sc->sc_dar;
+                               printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt);
+                               idcaddr->idccsr = cmd;
+                               um->um_tab.b_active = 2;
+                       }
+                       return;
+               }
+               /*
+                * Entire transfer is done, clean up.
+                */
+               ubadone(um);
+               dk_busy &= ~(1 << ui->ui_dk);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_errcnt = 0;
+               um->um_tab.b_actf = dp->b_forw;
+               dp->b_active = 0;
+               dp->b_errcnt = 0;
+               dp->b_actf = bp->av_forw;
+               trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf);
+               bp->b_resid = sc->sc_resid;
+               printd(", iodone, resid 0x%x\n", bp->b_resid);
+               iodone(bp);
+               if (dp->b_actf)
+                       if (idcustart(ui))
+                               return;
+       } else if (um->um_tab.b_active == 1) {
+               /*
+                * Got an interrupt while setting up for a command
+                * or doing a mid-transfer seek.  Save any attentions
+                * for later and process a mid-transfer seek complete.
+                */
+               as = idcaddr->idccsr;
+               idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
+               as = (as >> 16) & 0xf;
+               unit = sc->sc_unit;
+               sc->sc_softas |= as & ~(1<<unit);
+               if (as & (1<<unit)) {
+                       printd(", seek1 complete");
+                       um->um_tab.b_active = 2;
+                       goto top;
+               }
+               printd(", as1 %o\n", as);
+               return;
+       }
+       /*
+        * Process any seek initiated or complete interrupts.
+        */
+       as = idcaddr->idccsr;
+       idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
+       as = ((as >> 16) & 0xf) | sc->sc_softas;
+       sc->sc_softas = 0;
+       trace("as", as);
+       printd(", as %o", as);
+       for (unit = 0; unit < NRB; unit++)
+               if (as & (1<<unit)) {
+                       as &= ~(1<<unit);
+                       idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
+                       ui = idcdinfo[unit];
+                       if (ui) {
+                               printd(", attn unit %d", unit);
+                               if (idcaddr->idccsr & IDC_DRDY)
+                                       if (idcustart(ui)) {
+                                               sc->sc_softas = as;
+                                               return;
+                                       }
+                       } else {
+                               printd(", unsol. intr. unit %d", unit);
+                       }
+               }
+       printd("\n");
+       if (um->um_tab.b_actf && um->um_tab.b_active == 0) {
+               trace("stum",um->um_tab.b_actf);
+               (void) idcstart(um);
+       }
+}
+
+idcwait(addr, n)
+       register struct idcdevice *addr;
+       register int n;
+{
+       register int i;
+
+       while (--n && (addr->idccsr & IDC_CRDY) == 0)
+               for (i = 10; i; i--)
+                       ;
+       return (n);
+}
+
+idcread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRB)
+               return (ENXIO);
+       return (physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys, uio));
+}
+
+idcwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRB)
+               return (ENXIO);
+       return (physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+idcecc(ui)
+       register struct uba_device *ui;
+{
+       register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr;
+       register struct buf *bp = idcutab[ui->ui_unit].b_actf;
+       register struct uba_ctlr *um = ui->ui_mi;
+       register struct idcst *st;
+       register int i;
+       struct uba_regs *ubp = ui->ui_hd->uh_uba;
+       int bit, byte, mask;
+       caddr_t addr;
+       int reg, npf, o;
+       int cn, tn, sn;
+
+       printf("idcecc: HELP!\n");
+       npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;;
+       reg = btop(idc_softc.sc_ubaddr) + npf;
+       o = (int)bp->b_un.b_addr & PGOFSET;
+       st = &idcst[ui->ui_type];
+       cn = idc_softc.sc_cyl;
+       tn = idc_softc.sc_trk;
+       sn = idc_softc.sc_sect;
+       um->um_tab.b_active = 1;        /* Either complete or continuing... */
+       printf("rb%d%c: soft ecc sn%d\n", dkunit(bp),
+           'a'+(minor(bp->b_dev)&07),
+           (cn*st->ntrak + tn) * st->nsect + sn + npf);
+       mask = idc->idceccpat;
+       i = idc->idceccpos - 1;         /* -1 makes 0 origin */
+       bit = i&07;
+       i = (i&~07)>>3;
+       byte = i + o;
+       while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) {
+               addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
+                   (byte & PGOFSET);
+               putmemc(addr, getmemc(addr)^(mask<<bit));
+               byte++;
+               i++;
+               bit -= 8;
+       }
+       idc_softc.sc_bcnt += idc->idcbcr;
+       um->um_tab.b_errcnt = 0;        /* error has been corrected */
+       return;
+}
+
+idcreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
+       register unit;
+
+       if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban ||
+           um->um_alive == 0)
+               return;
+       printf(" idc0");
+       um->um_tab.b_active = 0;
+       um->um_tab.b_actf = um->um_tab.b_actl = 0;
+       if (um->um_ubinfo) {
+               printf("<%d>", (um->um_ubinfo>>28)&0xf);
+               um->um_ubinfo = 0;
+       }
+       for (unit = 0; unit < NRB; unit++) {
+               if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
+                       continue;
+               idcutab[unit].b_active = 0;
+               (void) idcustart(ui);
+       }
+       (void) idcstart(um);
+}
+
+idcwatch()
+{
+       register struct uba_ctlr *um;
+       register unit;
+
+       timeout(idcwatch, (caddr_t)0, hz);
+       um = idcminfo[0];
+       if (um == 0 || um->um_alive == 0)
+               return;
+       if (um->um_tab.b_active == 0) {
+               for (unit = 0; unit < NRB; unit++)
+                       if (idcutab[unit].b_active)
+                               goto active;
+               idcwticks = 0;
+               return;
+       }
+active:
+       idcwticks++;
+       if (idcwticks >= 20) {
+               idcwticks = 0;
+               printf("idc0: lost interrupt\n");
+               idcintr(0);
+       }
+}
+
+/*ARGSUSED*/
+idcdump(dev)
+       dev_t dev;
+{
+       struct idcdevice *idcaddr;
+       char *start;
+       int num, blk, unit;
+       struct size *sizes;
+       register struct uba_regs *uba;
+       register struct uba_device *ui;
+       struct idcst *st;
+       union idc_dar dar;
+       int nspg;
+
+       unit = minor(dev) >> 3;
+       if (unit >= NRB)
+               return (ENXIO);
+#define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
+       ui = phys(struct uba_device *, idcdinfo[unit]);
+       if (ui->ui_alive == 0)
+               return (ENXIO);
+       uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
+       ubainit(uba);
+       idcaddr = (struct idcdevice *)ui->ui_physaddr;
+       if (idcwait(idcaddr, 100) == 0)
+               return (EFAULT);
+       /*
+        * Since we can only transfer one track at a time, and
+        * the rl02 has 256 byte sectors, all the calculations
+        * are done in terms of physical sectors (i.e. num and blk
+        * are in sectors not NBPG blocks.
+        */
+       st = phys(struct idcst *, &idcst[ui->ui_type]);
+       sizes = phys(struct size *, st->sizes);
+       if (dumplo < 0 || dumplo + maxfree >= sizes[minor(dev)&07].nblocks)
+               return (EINVAL);
+       nspg = NBPG / st->nbps;
+       num = maxfree * nspg;
+       start = 0;
+
+       while (num > 0) {
+               register struct pte *io;
+               register int i;
+               daddr_t bn;
+
+               bn = (dumplo + btop(start)) * nspg;
+               dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff;
+               bn %= st->nspc;
+               dar.dar_trk = bn / st->nsect;
+               dar.dar_sect = bn % st->nsect;
+               blk = st->nsect - dar.dar_sect;
+               if (num < blk)
+                       blk = num;
+
+               io = uba->uba_map;
+               for (i = 0; i < (blk + nspg - 1) / nspg; i++)
+                       *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
+               *(int *)io = 0;
+
+               idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8;
+               if ((idcaddr->idccsr&IDC_DRDY) == 0)
+                       return (EFAULT);
+               idcaddr->idcdar = dar.dar_dar;
+               idcaddr->idccsr = IDC_SEEK | unit << 8;
+               while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY))
+                       != (IDC_CRDY|IDC_DRDY))
+                       ;
+               if (idcaddr->idccsr & IDC_ERR) {
+                       printf("rb%d: seek, csr=%b\n",
+                               unit, idcaddr->idccsr, IDCCSR_BITS);
+                       return (EIO);
+               }
+
+               idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8;
+               if ((idcaddr->idccsr&IDC_DRDY) == 0)
+                       return (EFAULT);
+               idcaddr->idcbar = 0;                    /* start addr 0 */
+               idcaddr->idcbcr = - (blk * st->nbps);
+               idcaddr->idcdar = dar.dar_dar;
+               idcaddr->idccsr = IDC_WRITE | unit << 8;
+               while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY))
+                       != (IDC_CRDY|IDC_DRDY))
+                       ;
+               if (idcaddr->idccsr & IDC_ERR) {
+                       printf("rb%d: write, csr=%b\n",
+                               unit, idcaddr->idccsr, IDCCSR_BITS);
+                       return (EIO);
+               }
+
+               start += blk * st->nbps;
+               num -= blk;
+       }
+       return (0);
+}
+idcsize(dev)
+       dev_t dev;
+{
+       int unit = minor(dev) >> 3;
+       struct uba_device *ui;
+       struct idcst *st;
+
+       if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       st = &idcst[ui->ui_type];
+       return (st->sizes[minor(dev) & 07].nblocks);
+}
+#endif
diff --git a/usr/src/sys/vaxuba/idcreg.h b/usr/src/sys/vaxuba/idcreg.h
new file mode 100644 (file)
index 0000000..b3dc86e
--- /dev/null
@@ -0,0 +1,99 @@
+/*     idcreg.h        6.1     83/07/29        */
+
+#define        NRB02SECT       40      /* RB02 sectors/track */
+#define        NRB02TRK        2       /* RB02 tracks/cylinder */
+#define        NRB02CYL        512     /* RB02 cylinders/disk */
+#define        NRB80SECT       31      /* RB80 sectors/track */
+#define        NRB80TRK        14      /* RB80 tracks/cylinder */
+#define        NRB80CYL        559     /* RB80 cylinders/disk */
+
+struct idcdevice
+{
+       int     idccsr;         /* control status register */
+       int     idcbar;         /* bus address register */
+       int     idcbcr;         /* byte count register */
+       int     idcdar;         /* disk address register */
+       int     idcmpr;         /* multi-purpose register */
+       int     idceccpos;      /* ecc position register */
+       int     idceccpat;      /* ecc pattern register */
+       int     idcreset;       /* master reset register */
+};
+
+/* idccsr */
+#define        IDC_TOI         0x10000000      /* time out inhibit */
+#define        IDC_ASSI        0x08000000      /* automatic skip sector inhibit */
+#define        IDC_R80         0x04000000      /* selected disk is R80 */
+#define        IDC_MTN         0x02000000      /* maintenance */
+#define        IDC_IR          0x01000000      /* interrupt request */
+#define        IDC_SSE         0x00800000      /* R80 skip sector error */
+#define        IDC_SSEI        0x00400000      /* R80 skip sector error inhibit */
+#define        IDC_ECS         0x00300000      /* R80 ecc status */
+#define        IDC_ECS_NONE    0x00000000      /*   no data error */
+#define        IDC_ECS_HARD    0x00200000      /*   hard ecc error */
+#define        IDC_ECS_SOFT    0x00300000      /*   soft ecc error */
+#define        IDC_ATTN        0x000f0000      /* attention bits */
+#define        IDC_ERR         0x00008000      /* composite error */
+#define        IDC_DE          0x00004000      /* drive error */
+#define        IDC_NXM         0x00002000      /* non-existant memory */
+#define        IDC_DLT         0x00001000      /* data late */
+#define        IDC_HNF         IDC_DLT         /* header not found */
+#define        IDC_DCK         0x00000800      /* data check */
+#define        IDC_OPI         0x00000400      /* operation incomplete */
+#define        IDC_DS          0x00000300      /* drive select bits */
+#define        IDC_CRDY        0x00000080      /* controller ready */
+#define        IDC_IE          0x00000040      /* interrupt enable */
+#define        IDC_FUNC        0x0000000e      /* function code */
+#define        IDC_DRDY        0x00000001      /* drive ready */
+
+#define        IDC_HARD        (IDC_NXM|IDC_DE)
+
+#define        IDCCSR_BITS \
+"\20\35TOI\34ASSI\33R80\32MTN\31IR\30SSE\27SSEI\26ECS1\25ECS0\24ATN3\
+\23ATN2\22ATN1\21ATN0\20ERR\17DE\16NXM\15DLT\14DCK\13OPI\12DS1\11DS0\
+\10CRDY\7IE\4F2\3F1\2F0\1DRDY"
+
+/* function codes */
+#define        IDC_NOP         000             /* no operation */
+#define        IDC_WCHK        002             /* write check data */
+#define        IDC_GETSTAT     004             /* get status */
+#define        IDC_SEEK        006             /* seek */
+#define        IDC_RHDR        010             /* read header */
+#define        IDC_WRITE       012             /* write data */
+#define        IDC_READ        014             /* read data */
+#define        IDC_RNOHCHK     016             /* read data w/o header check */
+
+/* idcmpr for RL02 get status command */
+#define        IDCGS_RST       010             /* reset */
+#define        IDCGS_GS        002             /* get status, must be 1 */
+#define        IDCGS_M         001             /* mark, must be 1 */
+#define        IDCGS_GETSTAT   (IDCGS_RST|IDCGS_GS|IDCGS_M)
+
+/* RL02 status word */
+#define        IDCDS_WDE       0100000         /* write data error */
+#define        IDCDS_HCE       0040000         /* head current error */
+#define        IDCDS_WL        0020000         /* write lock */
+#define        IDCDS_SKTO      0010000         /* seek timeout */
+#define        IDCDS_SPD       0004000         /* spindle error */
+#define        IDCDS_WGE       0002000         /* write gate error */
+#define        IDCDS_VC        0001000         /* volume check */
+#define        IDCDS_DSE       0000400         /* drive select error */
+#define        IDCDS_HS        0000100         /* head select */
+#define        IDCDS_CO        0000040         /* cover open */
+#define        IDCDS_HO        0000020         /* heads out */
+#define        IDCDS_BH        0000010         /* brush home */
+#define        IDCDS_STATE     0000007         /* drive state */
+
+#define        IDCRB02DS_BITS \
+"\10\20WDE\17HCE\16WL\15SKTO\14SPD\13WBE\12VC\11DSE\
+\7HS\6CO\5HO\4BH\3STC\2STB\1STA"
+
+/* R80 status word */
+#define        IDCDS_WTP       0020000         /* write protect */
+#define        IDCDS_DRDY      0010000         /* driver ready */
+#define        IDCDS_ONCY      0004000         /* on cylinder */
+#define        IDCDS_SKE       0002000         /* seek error */
+#define        IDCDS_PLGV      0001000         /* plug valid */
+#define        IDCDS_FLT       0000400         /* fault */
+
+#define        IDCRB80DS_BITS \
+"\10\16WTP\15DRDY\14ONCY\13SKE\12PLGV\11FLT\5SEC4\4SEC3\3SEC2\2SEC1\1SEC0"
diff --git a/usr/src/sys/vaxuba/ik.c b/usr/src/sys/vaxuba/ik.c
new file mode 100644 (file)
index 0000000..a865e8d
--- /dev/null
@@ -0,0 +1,246 @@
+/*     ik.c    6.1     83/07/29        */
+
+#include "ik.h"
+#if NIK > 0
+/*
+ * Ikonas Frame Buffer Interface -- Bill Reeves.
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/uio.h"
+#include "../h/ioctl.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ikreg.h"
+
+#define IKBUSY 01
+#define IKDMAPRI (PZERO-1)
+#define IKWAITPRI (PZERO+1)
+
+int    ikprobe(), ikattach(), ikintr();
+struct uba_device *ikdinfo[NIK];
+u_short        ikstd[] = { 0772460, 0000000, 0 };
+struct uba_driver ikdriver =
+       { ikprobe, 0, ikattach, 0, ikstd, "ik", ikdinfo, 0, 0 };
+
+struct ik_softc {
+       char    ik_open;
+       short   ik_uid;
+       short   ik_state;
+       int     ik_ubinfo;
+       int     ik_count;
+       struct  buf *ik_bp;
+       int     ik_bufp;
+       int     ik_icnt;
+} ik_softc[NIK];
+
+int    ikstrategy();
+u_int  ikminphys();
+struct buf rikbuf[NIK];
+
+#define IKUNIT(dev) (minor(dev))
+
+ikprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* value-result */
+       register struct ikdevice *ikaddr = (struct ikdevice *) reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       ikintr(0);
+#endif
+       ikaddr->ik_istat = 0;
+       ikaddr->ik_xaddr = 0;
+       ikaddr->ik_yaddr = 0;
+       ikaddr->ik_ustat = IK_IENABLE | IK_GO;
+       DELAY(10000);
+       ikaddr->ik_ustat = 0;
+       return (sizeof (struct ikdevice));
+}
+
+/*ARGSUSED*/
+ikattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+ikopen(dev)
+       dev_t dev;
+{
+       register struct ik_softc *ikp;
+       register struct uba_device *ui;
+
+       if (IKUNIT(dev) >= NIK || (ikp = &ik_softc[minor(dev)])->ik_open ||
+           (ui = ikdinfo[IKUNIT(dev)]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       ikp->ik_open = 1;
+       ikp->ik_icnt = 0;
+       ikp->ik_state = 0;
+       ikp->ik_uid = u.u_uid;
+       maptouser(ui->ui_addr);
+       return (0);
+}
+
+ikclose(dev)
+       dev_t dev;
+{
+
+       ik_softc[minor(dev)].ik_open = 0;
+       ik_softc[minor(dev)].ik_state = 0;
+       unmaptouser(ikdinfo[IKUNIT(dev)]->ui_addr);
+}
+
+ikread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = IKUNIT(dev);
+
+       if (unit >= NIK)
+               return (ENXIO);
+       return (physio(ikstrategy, &rikbuf[unit], dev, B_READ, ikminphys, uio));
+}
+
+ikwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = IKUNIT(dev);
+
+       if (unit >= NIK)
+               return (ENXIO);
+       return (physio(ikstrategy, &rikbuf[unit], dev, B_WRITE, ikminphys, uio));
+}
+
+u_int
+ikminphys(bp)
+       register struct buf *bp;
+{
+
+       if (bp->b_bcount > 65536)       /* may be able to do twice as much */
+               bp->b_bcount = 65536;
+}
+
+ikstrategy(bp)
+       register struct buf *bp;
+{
+       register struct ik_softc *ikp = &ik_softc[IKUNIT(bp->b_dev)];
+       register struct uba_device *ui;
+
+       if (IKUNIT(bp->b_dev) >= NIK || (ui = ikdinfo[IKUNIT(bp->b_dev)]) == 0
+                               || ui->ui_alive == 0)
+               goto bad;
+       (void) spl5();
+       while (ikp->ik_state & IKBUSY)
+               sleep((caddr_t)ikp, IKDMAPRI+1);
+       ikp->ik_state |= IKBUSY;
+       ikp->ik_bp = bp;
+       ikp->ik_ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
+       ikp->ik_bufp = ikp->ik_ubinfo & 0x3ffff;
+       ikp->ik_count = -(bp->b_bcount>>1);     /* its a word count */
+       ikstart(ui);
+       while (ikp->ik_state&IKBUSY)
+               sleep((caddr_t)ikp, IKDMAPRI);
+       ikp->ik_count = 0;
+       ikp->ik_bufp = 0;
+       (void) spl0();
+       ubarelse(ui->ui_ubanum, &ikp->ik_ubinfo);
+       ikp->ik_bp = 0;
+       iodone(bp);
+       wakeup((caddr_t)ikp);
+       return;
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+ikstart(ui)
+       register struct uba_device *ui;
+{
+       register int istat;
+       register struct ikdevice *ikaddr = (struct ikdevice *) ui->ui_addr;
+       register struct ik_softc *ikp = &ik_softc[IKUNIT(ui->ui_unit)];
+
+       istat = ikaddr->ik_istat|DMAENABLE;
+       ikaddr->ik_istat = istat;
+       ikaddr->ik_wc =  ikp->ik_count;
+       ikaddr->ik_ubaddr = ikp->ik_bufp;
+       ikaddr->ik_ustat = IK_GO|IK_IENABLE|((ikp->ik_bufp>>12)&060);
+}
+
+/*ARGSUSED*/
+ikioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       register caddr_t data;
+       int flag;
+{
+       register struct uba_device *ui = ikdinfo[IKUNIT(dev)];
+       register struct ik_softc *ikp;
+
+       switch (cmd) {
+
+       case IKIOGETADDR:
+               *(caddr_t *)data = ui->ui_addr;
+               break;
+
+       case IKIOWAITINT:
+               ikp = &ik_softc[IKUNIT(dev)];
+               ikp->ik_state |= IKBUSY;
+               while (ikp->ik_state&IKBUSY)
+                       sleep((caddr_t)ikp, IKWAITPRI);
+               break;
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+/*ARGSUSED*/
+ikintr(dev)
+       dev_t dev;
+{
+       register struct ikdevice *ikaddr =
+                       (struct ikdevice *) ikdinfo[IKUNIT(dev)]->ui_addr;
+       register struct ik_softc *ikp = &ik_softc[IKUNIT(dev)];
+
+       ikp->ik_icnt++;
+       if (ikp->ik_state&IKBUSY) {
+               ikaddr->ik_ustat = 0;
+               ikp->ik_state &= ~IKBUSY;
+               wakeup((caddr_t)ikp);
+       }
+}
+
+ikreset(uban)
+       int uban;
+{
+       register int i;
+       register struct uba_device *ui;
+       register struct ik_softc *ikp = ik_softc;
+
+       for (i = 0; i < NIK; i++, ikp++) {
+               if ((ui = ikdinfo[i]) == 0 || ui->ui_alive == 0 ||
+                   ui->ui_ubanum != uban || ikp->ik_open == 0)
+                       continue;
+               printf(" ik%d", i);
+               if ((ikp->ik_state&IKBUSY) == 0)
+                       continue;
+               ikp->ik_ubinfo =
+                   ubasetup(ui->ui_ubanum, ikp->ik_bp, UBA_NEEDBDP);
+               ikp->ik_count = -(ikp->ik_bp->b_bcount/2);
+               ikstart(ui);
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxuba/kgclock.c b/usr/src/sys/vaxuba/kgclock.c
new file mode 100644 (file)
index 0000000..dd4ca6a
--- /dev/null
@@ -0,0 +1,86 @@
+/*     kgclock.c       6.1     83/07/29        */
+
+#include "kg.h"
+#if NKG > 0
+/*
+ * KL-11 as profiling clock
+ */
+#include "../machine/pte.h"
+#include "../machine/psl.h"
+
+#include "../h/param.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+
+#include "../vaxuba/ubavar.h"
+
+int    kgprobe(), kgattach();
+struct uba_device *kginfo[1];
+u_short        kgstd[] = { 0177560, 0 };
+struct uba_driver kgdriver =
+    { kgprobe, 0, kgattach, 0, kgstd, "kg", kginfo };
+
+struct klregs {
+       u_short fill[2];
+       u_short tcsr;
+       u_short tbuf;
+};
+#define        KLSTRT  0300            /* intr enbl + done */
+struct klregs *klbase;
+
+kgprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;  /* value-result */
+       register struct klregs *klp = (struct klregs *)reg;
+
+       klp->tcsr = KLSTRT;
+       DELAY(100000);
+       klp->tcsr = 0;
+}
+
+kgattach(ui)
+       struct uba_device *ui;
+{
+
+       klbase = (struct klregs *)ui->ui_addr;
+}
+
+/*
+ * start the sampling clock
+ */
+startkgclock()
+{
+
+       if (klbase)
+               klbase->tcsr = KLSTRT;  /* enable interrupts */
+}
+
+/* ARGSUSED */
+kgclock(dev, r0, r1, r2, r3, r4 ,r5, pc, ps)
+       caddr_t pc;
+       int ps;
+{
+       register int k;
+       static long otime;
+       static long calibrate;
+
+       klbase->tbuf = 0377;    /* reprime clock (scope sync too) */
+       if (phz == 0) {
+               if (otime == 0) {
+                       otime = time.tv_sec + 1;
+                       calibrate = 0;
+               }
+               if (time.tv_sec >= otime)
+                       calibrate++;
+               if (time.tv_sec >= otime + 4) {
+                       phz = calibrate / 4;
+                       otime = 0;
+               }
+               return;
+       }
+       gatherstats(pc, ps);    /* this routine lives in kern_clock.c */
+}
+#endif
diff --git a/usr/src/sys/vaxuba/lp.c b/usr/src/sys/vaxuba/lp.c
new file mode 100644 (file)
index 0000000..42d4537
--- /dev/null
@@ -0,0 +1,342 @@
+/*     lp.c    6.1     83/07/29        */
+
+#include "lp.h"
+#if NLP > 0
+/*
+ * LP-11 Line printer driver
+ *
+ * This driver has been modified to work on printers where
+ * leaving IENABLE set would cause continuous interrupts.
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/uio.h"
+#include "../h/tty.h"
+#include "../h/kernel.h"
+
+#include "../vaxuba/ubavar.h"
+
+#define        LPPRI   (PZERO+8)
+#define        IENABLE 0100
+#define        DONE    0200
+#define        ERROR   0100000
+#define        LPLWAT  650
+#define        LPHWAT  800
+
+#define MAXCOL 132
+#define CAP    1
+
+#define LPUNIT(dev) (minor(dev) >> 3)
+
+struct lpdevice {
+       short   lpsr;
+       short   lpbuf;
+};
+
+struct lp_softc {
+       struct  clist sc_outq;
+       int     sc_state;
+       int     sc_physcol;
+       int     sc_logcol;
+       int     sc_physline;
+       char    sc_flags;
+       short   sc_maxcol;
+       int     sc_lpchar;
+       struct  buf *sc_inbuf;
+} lp_softc[NLP];
+
+struct uba_device *lpinfo[NLP];
+
+int lpprobe(), lpattach(), lptout();
+u_short lpstd[] = { 0177514 };
+struct uba_driver lpdriver =
+       { lpprobe, 0, lpattach, 0, lpstd, "lp", lpinfo };
+
+/* bits for state */
+#define        OPEN            1       /* device is open */
+#define        TOUT            2       /* timeout is active */
+#define        MOD             4       /* device state has been modified */
+#define        ASLP            8       /* awaiting draining of printer */
+
+int    lptout();
+
+lpattach(ui)
+       struct uba_device *ui;
+{
+       register struct lp_softc *sc;
+
+       sc = &lp_softc[ui->ui_unit];
+       sc->sc_lpchar = -1;
+       if (ui->ui_flags)
+               sc->sc_maxcol = ui->ui_flags;
+       else
+               sc->sc_maxcol = MAXCOL;
+}
+
+lpprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;                  /* value-result */
+       register struct lpdevice *lpaddr = (struct lpdevice *)reg;
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       lpintr(0);
+#endif
+
+       lpaddr->lpsr = IENABLE;
+       DELAY(5);
+       lpaddr->lpsr = 0;
+       return (sizeof (struct lpdevice));
+}
+
+/*ARGSUSED*/
+lpopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int unit;
+       register struct lpdevice *lpaddr;
+       register struct lp_softc *sc;
+       register struct uba_device *ui;
+
+       if ((unit = LPUNIT(dev)) >= NLP ||
+           (sc = &lp_softc[unit])->sc_state&OPEN ||
+           (ui = lpinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       lpaddr = (struct lpdevice *)ui->ui_addr;
+       if (lpaddr->lpsr&ERROR)
+               return (EIO);
+       sc->sc_state |= OPEN;
+       sc->sc_inbuf = geteblk(512);
+       sc->sc_flags = minor(dev) & 07;
+       (void) spl4();
+       if ((sc->sc_state&TOUT) == 0) {
+               sc->sc_state |= TOUT;
+               timeout(lptout, (caddr_t)dev, 10*hz);
+       }
+       (void) spl0();
+       lpcanon(dev, '\f');
+       return (0);
+}
+
+/*ARGSUSED*/
+lpclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
+
+       lpcanon(dev, '\f');
+       brelse(sc->sc_inbuf);
+       sc->sc_state &= ~OPEN;
+}
+
+lpwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register unsigned n;
+       register char *cp;
+       register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
+       int error;
+
+       while (n = min(512, (unsigned)uio->uio_resid)) {
+               cp = sc->sc_inbuf->b_un.b_addr;
+               error = uiomove(cp, (int)n, UIO_WRITE, uio);
+               if (error)
+                       return (error);
+               do
+                       lpcanon(dev, *cp++);
+               while (--n);
+       }
+       return (0);
+}
+
+lpcanon(dev, c)
+       dev_t dev;
+       register int c;
+{
+       register int logcol, physcol;
+       register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
+
+       if (sc->sc_flags&CAP) {
+               register c2;
+
+               if (c>='a' && c<='z')
+                       c += 'A'-'a'; else
+               switch (c) {
+
+               case '{':
+                       c2 = '(';
+                       goto esc;
+
+               case '}':
+                       c2 = ')';
+                       goto esc;
+
+               case '`':
+                       c2 = '\'';
+                       goto esc;
+
+               case '|':
+                       c2 = '!';
+                       goto esc;
+
+               case '~':
+                       c2 = '^';
+
+               esc:
+                       lpcanon(dev, c2);
+                       sc->sc_logcol--;
+                       c = '-';
+               }
+       }
+       logcol = sc->sc_logcol;
+       physcol = sc->sc_physcol;
+       if (c == ' ')
+               logcol++;
+       else switch(c) {
+
+       case '\t':
+               logcol = (logcol+8) & ~7;
+               break;
+
+       case '\f':
+               if (sc->sc_physline == 0 && physcol == 0)
+                       break;
+               /* fall into ... */
+
+       case '\n':
+               lpoutput(dev, c);
+               if (c == '\f')
+                       sc->sc_physline = 0;
+               else
+                       sc->sc_physline++;
+               physcol = 0;
+               /* fall into ... */
+
+       case '\r':
+               logcol = 0;
+               (void) spl4();
+               lpintr(LPUNIT(dev));
+               (void) spl0();
+               break;
+
+       case '\b':
+               if (logcol > 0)
+                       logcol--;
+               break;
+
+       default:
+               if (logcol < physcol) {
+                       lpoutput(dev, '\r');
+                       physcol = 0;
+               }
+               if (logcol < sc->sc_maxcol) {
+                       while (logcol > physcol) {
+                               lpoutput(dev, ' ');
+                               physcol++;
+                       }
+                       lpoutput(dev, c);
+                       physcol++;
+               }
+               logcol++;
+       }
+       if (logcol > 1000)      /* ignore long lines  */
+               logcol = 1000;
+       sc->sc_logcol = logcol;
+       sc->sc_physcol = physcol;
+}
+
+lpoutput(dev, c)
+       dev_t dev;
+       int c;
+{
+       register struct lp_softc *sc = &lp_softc[LPUNIT(dev)];
+
+       if (sc->sc_outq.c_cc >= LPHWAT) {
+               (void) spl4();
+               lpintr(LPUNIT(dev));                            /* unchoke */
+               while (sc->sc_outq.c_cc >= LPHWAT) {
+                       sc->sc_state |= ASLP;           /* must be ERROR */
+                       sleep((caddr_t)sc, LPPRI);
+               }
+               (void) spl0();
+       }
+       while (putc(c, &sc->sc_outq))
+               sleep((caddr_t)&lbolt, LPPRI);
+}
+
+lpintr(lp11)
+       int lp11;
+{
+       register int n;
+       register struct lp_softc *sc = &lp_softc[lp11];
+       register struct uba_device *ui = lpinfo[lp11];
+       register struct lpdevice *lpaddr = (struct lpdevice *)ui->ui_addr;
+
+       lpaddr->lpsr &= ~IENABLE;
+       n = sc->sc_outq.c_cc;
+       if (sc->sc_lpchar < 0)
+               sc->sc_lpchar = getc(&sc->sc_outq);
+       while ((lpaddr->lpsr&DONE) && sc->sc_lpchar >= 0) {
+               lpaddr->lpbuf = sc->sc_lpchar;
+               sc->sc_lpchar = getc(&sc->sc_outq);
+       }
+       sc->sc_state |= MOD;
+       if (sc->sc_outq.c_cc > 0 && (lpaddr->lpsr&ERROR)==0)
+               lpaddr->lpsr |= IENABLE;        /* ok and more to do later */
+       if (n>LPLWAT && sc->sc_outq.c_cc<=LPLWAT && sc->sc_state&ASLP) {
+               sc->sc_state &= ~ASLP;
+               wakeup((caddr_t)sc);            /* top half should go on */
+       }
+}
+
+lptout(dev)
+       dev_t dev;
+{
+       register struct lp_softc *sc;
+       register struct uba_device *ui;
+       register struct lpdevice *lpaddr;
+
+       sc = &lp_softc[LPUNIT(dev)];
+       ui = lpinfo[LPUNIT(dev)];
+       lpaddr = (struct lpdevice *) ui->ui_addr;
+       if ((sc->sc_state&MOD) != 0) {
+               sc->sc_state &= ~MOD;           /* something happened */
+               timeout(lptout, (caddr_t)dev, 2*hz);    /* so don't sweat */
+               return;
+       }
+       if ((sc->sc_state&OPEN) == 0) {
+               sc->sc_state &= ~TOUT;          /* no longer open */
+               lpaddr->lpsr = 0;
+               return;
+       }
+       if (sc->sc_outq.c_cc && (lpaddr->lpsr&DONE) && (lpaddr->lpsr&ERROR)==0)
+               lpintr(LPUNIT(dev));                    /* ready to go */
+       timeout(lptout, (caddr_t)dev, 10*hz);
+}
+
+lpreset(uban)
+       int uban;
+{
+       register struct uba_device *ui;
+       register struct lpdevice *lpaddr;
+       register int unit;
+
+       for (unit = 0; unit < NLP; unit++) {
+               if ((ui = lpinfo[unit]) == 0 || ui->ui_ubanum != uban ||
+                   ui->ui_alive == 0)
+                       continue;
+               printf(" lp%d", unit);
+               lpaddr = (struct lpdevice *)ui->ui_addr;
+               lpaddr->lpsr |= IENABLE;
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxuba/lpa.c b/usr/src/sys/vaxuba/lpa.c
new file mode 100644 (file)
index 0000000..f16a317
--- /dev/null
@@ -0,0 +1,599 @@
+/*     lpa.c   6.1     83/07/29        */
+
+#include "lpa.h"
+#if NLPA > 0
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/proc.h"
+#include "../h/ioctl.h"
+#include "../h/uio.h"
+
+#include "../vaxuba/ubavar.h"
+
+/*
+ * LPA driver for -- Asa Romberger
+ *
+ *     open
+ *     write microcode
+ *     write dedicated mode dispatch table
+ *     ioctl TIOCSETP to set parameters
+ *             struct iocb {
+ *                     short *baddr;   buffer address
+ *                     short rate;     - 1,000,000 / frequency in Hz
+ *                     short wc;       15-13 = number of buffers - 1
+ *                                     12-0 = buffer size in words
+ *             } iocb;
+ *     read - 1 character indicating buffer index
+ *             fill or empty buffer
+ * minor device number = DDCCCCCC where:
+ *     DD      = 00 for analog input
+ *             = 01 for analog output
+ *     CCCCCC  = channel number
+ */
+ *     define NOMCODE to eliminate the microcode download check
+ */
+/* #define TRACELPA */
+/* #define NOMCODE */
+
+#ifdef TRACELPA
+#      define TRACER(x)        printf(x)
+#      define TRACERN(x, d)    printf(x, d)
+#else
+#      define TRACER(x)
+#      define TRACERN(x, d)
+#endif
+
+       /* PRIORITY AT WHICH PROGRAM SHOULD RUN */
+       /* THIS SHOULD EVENTUALLY  TELL UNIX THIS IS A REAL-TIME DEVICE */
+
+#define NICE   0
+
+#define inc(v)         (sc->v = ((sc->v + 1) % sc->sc_nbuf))
+
+#define LPAPRI         (PZERO + 0)
+#define LPAUNIT(dev)   0
+#define LPADEVICE(dev) (((dev) >> 6) & 03)
+#define LPACHANNEL(dev)        ((dev) & 077)
+
+int    lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
+u_short        lpastd[] = {0170460, 0};
+struct uba_device *lpadinfo[NLPA];
+struct uba_driver lpadriver =
+  {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
+
+struct lpa_softc {
+       int     sc_flag;        /* flags, as defined below */
+       int     sc_device;      /* device: 0 = analog in, 1 = analog out */
+       int     sc_channel;     /* device channel number */
+       struct buf sc_ubuffer;  /* user buffer header */
+       int     sc_ubabuf;      /* uba allocation pointer for buffer */
+       int     sc_ubufn;       /* present buffer that user is accessing */
+       int     sc_lbufn;       /* present buffer that lpa is accessing */
+       int     sc_lbufnx;      /* next buffer for lpa (value in ustat) */
+       int     sc_nbuf;        /* number of buffers */
+       int     sc_count;       /* buffer size in words */
+       short   sc_ustat;       /* user status word */
+       struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */
+       int     sc_ubaustat;    /* uba allocation pointer for ustat */
+       struct buf *sc_buffer;  /* scratch buffer header */
+       int     sc_start;       /* 0 if lpa operation has been started */
+} lpa_softc[NLPA];
+
+/* flags for sc_flag */
+#define OPEN   01              /* device is open */
+#define MCODE  02              /* microcode has been loaded */
+#define DMDT   04              /* dedicated mode dispatch table loaded */
+#define STTY   010             /* stty call and device initialized */
+#define SLEEP  020             /* sleeping */
+
+/* bits for ustat */
+#define DONE   0100000         /* done */
+#define STOP   0040000         /* stop data transfer */
+#define NBI    0003400         /* next buffer index */
+#define LBI    0000003         /* last buffer index */
+
+struct lpadevice {
+       short   lcim;           /* control in and maintenance */
+       short   lcos;           /* control and status out */
+       short   lrda;           /* request description array address word */
+       short   lms;            /* maintenance status */
+};
+
+/* control in and maintenance register bits */
+#define        READYI  0000200         /* ready in */
+#define IIE    0000100         /* in interrupt enable */
+#define RDAEXT 0000014         /* rda address extension */
+#define RDAEXTOFFSET   2       /* offset of RDAEXT from right side */
+#define GO     0000001         /* go */
+#define RUN    0100000         /* run */
+#define RESET  0040000         /* reset */
+#define CWRITE 0020000         /* cram write */
+#define EA     0004000         /* enable arbitration */
+#define ROMO   0002000         /* rom O */
+#define ROMI   0001000         /* rom I */
+#define SMICRO 0000400         /* step microprocessor */
+
+/* control and status out register bits */
+#define READYO 0200            /* ready out */
+#define OIE    0100            /* out interrupt enable */
+#define UINDEX 0007            /* user index */
+#define ERROR  0100000         /* error */
+#define ESTAT  0060000         /* error status */
+#define ESCODE 0017400         /* error sub code */
+#define ECODE  0077400         /* error status + error sub code */
+#define OVERRUN        0243            /* overrun error */
+
+/* LPA COMMAND DESCRIPTION AREA */
+
+/* INIT COMMAND */
+#define INIT   0               /* mode */
+#define MCVERS 4               /* microcode version */
+#define ACLOCKA        0170404         /* LPA bus addresses */
+#define ACLOCKB        0170432
+#define AAD1   0170400
+#define AAD2   1               /* 0170440 - DOES NOT EXIST */
+#define ADA    0170420
+#define ADIO1  1               /* 0167770 - DOES NOT EXIST */
+#define ADIO2  1               /* 0167760 - DOES NOT EXIST */
+#define ADIO3  1               /* 0167750 - DOES NOT EXIST */
+#define ADIO4  1               /* 0167740 - DOES NOT EXIST */
+#define ADIO5  1               /* 0167730 - DOES NOT EXIST */
+
+/* CLOCK START COMMAND */
+#define CLOCK  1               /* mode */
+#define CLOCKA 0<<4            /* clock A */
+       /* clock status word */
+#define ENACTR 1               /* enable counter */
+#define R1M    1<<1            /* 1 MHz rate */
+#define R100K  2<<1            /* 100 KHz rate */
+#define R10K   3<<1            /* 10 KHz rate */
+#define R1K    4<<1            /* 1 KHz rate */
+#define R100   5<<1            /* 100 Hz rate */
+#define REXT   6<<1            /* external rate (from st1 input) */
+#define R60    7<<1            /* line frequency rate */
+#define MFIE   0100            /* mode flag interrupt enable */
+#define MSI    0<<8            /* single interval mode */
+#define MRI    1<<8            /* repeat interval mode */
+#define MEET   2<<8            /* external event time mode */
+#define MEETZ  3<<8            /* external event time mode from zero base */
+#define ST1EC  020000          /* st1 enable counter */
+#define ST1IE  040000          /* st1 interrupt enable */
+
+/* DATA TRANSFER START COMMAND */
+#define DTS    2               /* mode */
+#define SCHAN  1<<8            /* single channel */
+
+lpaprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;  /* value result */
+       register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+#endif
+       /* this should force an interrupt, stall, clear the lpa */
+       br = 0x15;
+       cvec = 0330;
+TRACER("PROBE\n");
+       return (sizeof (struct lpadevice));
+}
+
+lpaattach(ui)
+       register struct upa_device *ui;
+{
+
+}
+
+lpaopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int unit = LPAUNIT(dev);
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+
+TRACER("OPEN\n");
+       if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
+           ui->ui_alive == 0)
+               return (ENXIO);
+       (void) spl7();
+       lpaaddr->lcim = RESET;
+       lpaaddr->lcim = 0;
+       (void) spl0();
+       lpaaddr->lcos = 0;      /* clear the registers as a precaution */
+       lpaaddr->lrda = 0;
+       lpaaddr->lms = 0;
+       sc->sc_flag = OPEN;
+       sc->sc_device = LPADEVICE(dev);
+       sc->sc_channel = LPACHANNEL(dev);
+       sc->sc_buffer = geteblk();
+       sc->sc_buffer->b_error = 0;
+       sc->sc_buffer->b_proc = u.u_procp;
+       sc->sc_ubufn = -1;
+       /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
+       u.u_procp->p_nice = NICE;
+       return (0);
+}
+
+lpaclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int unit = LPAUNIT(dev);
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+
+       if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
+               if (sc->sc_start)
+                       lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
+               sc->sc_flag |= STOP;
+               (void) spl5();
+               while (sc->sc_flag & STOP) {
+TRACER("SLEEP\n");
+                       sc->sc_flag |= SLEEP;
+                       sleep((caddr_t)sc, LPAPRI);
+               }
+       }
+       (void) spl7();
+       lpaaddr->lcim = RESET;
+       lpaaddr->lcim = 0;
+       (void) spl0();
+       if (sc->sc_ubabuf) {
+               ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
+               sc->sc_ubabuf = 0;
+               (void) spl6();
+               vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
+                       (sc->sc_device)? B_READ : B_WRITE);
+               u.u_procp->p_flag &= ~SPHYSIO;
+               (void) spl0();
+       }
+       if (sc->sc_ubaustat) {
+               ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
+               sc->sc_ubaustat = 0;
+       }
+       if (sc->sc_buffer) {
+               brelse(sc->sc_buffer);
+               sc->sc_buffer = 0;
+       }
+       sc->sc_flag = 0;
+TRACER("CLOSE\n");
+}
+
+lpawrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = LPAUNIT(dev);
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+       register int f;
+
+TRACER("WRITE\n");
+       f = sc->sc_flag;
+       if ((f & OPEN) == 0)
+               return (ENXIO);
+       if ((f & MCODE) == 0)           /* first write is the microcode */
+               return (lpamcode(lpaaddr, sc, uio));
+       if ((f & DMDT) == 0)            /* second write is the dispatch table */
+               return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio));
+       return (ENXIO);
+}
+
+lpamcode(lpaaddr, sc, uio)
+       register struct lpadevice *lpaaddr;
+       register struct lpa_softc *sc;
+       struct uio *uio;
+{
+       short v, r;
+       register int mcaddr;
+       int error;
+
+       mcaddr = 0;
+       while (uio->uio_resid) {
+               error = uiomove(&v, 2, UIO_WRITE, uio);
+               if (error)
+                       break;
+               lpaaddr->lcim = 0;              /* load microcode word */
+               lpaaddr->lrda = mcaddr;
+               lpaaddr->lms = v;
+               lpaaddr->lcim = ROMO;
+               lpaaddr->lcim |= CWRITE;
+               lpaaddr->lcim = 0;              /* verify microcode word */
+               lpaaddr->lrda = mcaddr;
+               lpaaddr->lcim = ROMO;
+               if ((r = lpaaddr->lms) != v) {
+                       /* download failure */
+                       printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
+                       return (ENXIO);
+               }
+               mcaddr++;
+       }
+       lpaaddr->lcim = RUN | EA;       /* turn it on */
+       sc->sc_flag |= MCODE;
+       lpaaddr->lcim |= IIE;
+       lpaaddr->lcos |= OIE;
+       return (error);
+TRACER("MCODE\n");
+}
+
+lpadmdt(lpaaddr, sc, ubanum, uio)
+       register struct lpadevice *lpaaddr;
+       register struct lpa_softc *sc;
+       register short ubanum;
+       struct uio *uio;
+{
+       register short *p;
+       register int n;
+       int error;
+
+       p = (short *) sc->sc_buffer->b_un.b_addr;               /* INIT */
+       *p++ = (MCVERS << 8) | INIT;    /* mode */
+       *p++ = ACLOCKA;         /* LPA bus device addresses */
+       *p++ = ACLOCKB;
+       *p++ = AAD1;
+       *p++ = AAD2;
+       *p++ = ADA;
+       *p++ = ADIO1;
+       *p++ = ADIO2;
+       *p++ = ADIO3;
+       *p++ = ADIO4;
+       *p++ = ADIO5;
+       n = min(uio->uio_resid, 256);   /* dedicated mode dispatch table */
+       error = uiomove((char *)p, n, UIO_WRITE, uio);
+       if (error)
+               return (error);
+       n >>= 1;
+       p += n;
+       while (n++ < 128)
+               *p++ = 0;
+       lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
+       sc->sc_flag |= DMDT;
+       return (0);
+TRACER("DMDT\n");
+}
+
+lpaioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register int unit = LPAUNIT(dev);
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+       register short *p;
+       register int i;
+       register int v;
+       struct iocb {
+               short *baddr;
+               short rate;
+               short wc;
+       } *iocb;
+
+TRACER("IOCTL IN\n");
+       if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0)
+               return (ENXIO);
+       iocb = (struct iocb *)data;
+       p = (short *) sc->sc_buffer->b_un.b_addr;       /* CLOCK START */
+       *p++ = CLOCK | CLOCKA;                  /* mode */
+       *p++ = ENACTR | R1M | MFIE | MRI;       /* clock status */
+       *p = iocb->rate;                        /* clock preset */
+       lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
+TRACER("CLOCK STARTED\n");
+       p = (short *) sc->sc_buffer->b_un.b_addr;       /* DATA TRANSFER START*/
+       *p++ = (sc->sc_device << 7) | DTS | SCHAN;      /* mode */
+       sc->sc_count = iocb->wc & 017777;       /* word count per buffer */
+       *p++ = sc->sc_count;
+                                                       /* user status word */
+       sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
+       sc->sc_ustatbuf.b_flags = 0;
+       sc->sc_ustatbuf.b_bcount = 2;
+       sc->sc_ustatbuf.b_proc = u.u_procp;
+       sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
+       v = sc->sc_ubaustat;
+       *p++ = v;
+       *p = (v >> 16) & 03;            /* into low portion of word */
+       sc->sc_nbuf = (iocb->wc >> 13) & 07;    /* number of buffers */
+       *p++ |= sc->sc_nbuf++ << 8;             /* into high portion of word */
+                                       /* buffer addresses */
+       if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
+           sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
+           (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
+TRACER("USER BUFFER FAULT\n");
+               return (EFAULT);
+       }
+       sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
+       sc->sc_ubuffer.b_proc = u.u_procp;
+       u.u_procp->p_flag |= SPHYSIO;
+       vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
+       sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
+       v = sc->sc_ubabuf;
+       for (i = 0; i < sc->sc_nbuf; i++) {
+               *p++ = v;
+               *p++ = (v >> 16) & 03;
+               v += sc->sc_count * 2;
+       }
+       for ( ; i <= 7; i++) {
+               *p++ = 0;
+               *p++ = 0;
+       }
+       *p++ = 0; *p++ = 0;             /* random channel list address */
+       *p++ = 0;                       /* delay */
+       *p++ = sc->sc_channel;          /* start channel, channel inc */
+       *p++ = 1;                       /* number of samples in a sequence */
+       *p++ = 0;                       /* dwell */
+       *p++ = 0;                       /* start word no., event mark word */
+       *p++ = 0;                       /* start word mask */
+       *p = 0;                         /* event mark mask */
+       sc->sc_ustat = 0;
+       sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
+       sc->sc_lbufn = 0;
+       sc->sc_lbufnx = 0;
+       sc->sc_flag |= STTY;
+TRACER("IOCTL OUT\n");
+       return (0);
+}
+
+lparead(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = LPAUNIT(dev);
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+
+TRACER("READ\n");
+       if ((sc->sc_flag & STTY) == 0)
+               return (ENXIO);
+       if (sc->sc_flag & ERROR)
+               return (ENXIO);
+       if (sc->sc_start)
+               if (--sc->sc_start == 0) {
+                       lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
+TRACER("START\n");
+               }
+       inc(sc_ubufn);
+       if (sc->sc_start == 0) {
+               (void) spl5();
+               while (sc->sc_ubufn == sc->sc_lbufn) {
+                       if (sc->sc_flag & ERROR)
+                               return (ENXIO);
+TRACER("SLEEP\n");
+                       sc->sc_flag |= SLEEP;
+                       sleep(sc, LPAPRI);
+               }
+               (void) spl0();
+       }
+TRACERN("READ %d\n", sc->sc_ubufn);
+       return (uiomove(&sc->sc_ubufn, 1, UIO_READ, uio));
+}
+
+lpacmd(bp, lpaaddr, sc, ubanum)
+       register struct buf *bp;
+       register struct lpadevice *lpaaddr;
+       register struct lpa_softc *sc;
+       register short ubanum;
+{
+       int ubareg;
+
+TRACER("CMD\n");
+       ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
+       lpawait(lpaaddr, sc);
+       lpaaddr->lrda = ubareg;
+       lpaaddr->lcim &= ~RDAEXT;
+       lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
+       lpawait(lpaaddr, sc);
+       ubarelse(ubanum, &ubareg);
+}
+
+lpawait(lpaaddr, sc)
+       register struct lpadevice *lpaaddr;
+       register struct lpa_softc *sc;
+{
+
+       (void) spl5();
+       while ((lpaaddr->lcim & READYI) == 0) {
+TRACER("SLEEP\n");
+               sc->sc_flag |= SLEEP;
+               sleep((caddr_t)sc, LPAPRI);
+       }
+       (void) spl0();
+}
+
+lpaiintr(unit)
+       int unit;
+{
+       register struct lpa_softc *sc = &lpa_softc[unit];
+
+TRACER("{I");
+       if (sc->sc_flag & SLEEP) {
+TRACER("<WAKEUP>");
+               wakeup((caddr_t)sc);
+               sc->sc_flag &= ~SLEEP;
+       }
+TRACER("}");
+}
+
+lpaointr(unit)
+       int unit;
+{
+       register int c, m;
+       register struct lpa_softc *sc = &lpa_softc[unit];
+       register struct uba_device *ui = lpadinfo[unit];
+       register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
+       int spx;
+
+TRACER("{O");
+       if (sc->sc_flag & SLEEP) {
+TRACER("<WAKEUP>");
+               wakeup(sc);
+               sc->sc_flag &= ~SLEEP;
+       }
+       c = lpaaddr->lcos;
+       m = lpaaddr->lms;
+       lpaaddr->lcos &= ~READYO;
+       if (c & ERROR) {
+TRACER("<ERROR>");
+               c = (c >> 8) & 0377;
+               if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
+                       printf("LPA ERROR %o %o\n", c, m&0177777);
+                       sc->sc_flag |= ERROR;
+               }
+               sc->sc_flag &= ~STOP;
+TRACER("}\n");
+               return;
+       }
+TRACERN("<LPA %d>", sc->sc_lbufnx);
+       sc->sc_lbufn = sc->sc_lbufnx;
+       if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
+TRACER("<STOP?>");
+               if (sc->sc_flag & STOP)
+                       return;
+               printf("LPA OVERRUN\n");
+               sc->sc_flag |= ERROR;
+       }
+       inc(sc_lbufnx);
+TRACERN("<USTAT %o>", sc->sc_ustat);
+       spx = spl7();
+       sc->sc_ustat &= ~NBI;
+       sc->sc_ustat |= sc->sc_lbufnx << 8;
+       sc->sc_ustat &= ~DONE;
+       (void) splx(spx);
+TRACERN("<LPAN %d>}", sc->sc_lbufnx);
+}
+
+lpareset(uban)
+       int uban;
+{
+       register struct uba_device *ui;
+       register struct lpadevice *lpaaddr;
+       register struct lpa_softc *sc;
+       register int unit;
+
+TRACER("LPA RESET\n");
+       for (unit = 0; unit < NLPA; unit++) {
+               if ((ui = lpadinfo[unit]) == 0 ||
+                   ui->ui_ubanum != uban || ui->ui_alive == 0)
+                       continue;
+               printf(" lpa%d", unit);
+               lpaaddr = (struct lpadevice *)ui->ui_addr;
+               sc = &lpa_softc[unit];
+               sc->sc_flag |= ERROR;
+               (void) spl7();
+               lpaaddr->lcim = RESET;
+               lpaaddr->lcim = 0;
+               (void) spl0();
+               if (sc->sc_flag & SLEEP) {
+                       wakeup((caddr_t)sc);
+                       sc->sc_flag &= ~SLEEP;
+               }
+       }
+}
+#endif NLPA
diff --git a/usr/src/sys/vaxuba/pdma.h b/usr/src/sys/vaxuba/pdma.h
new file mode 100644 (file)
index 0000000..20e14ef
--- /dev/null
@@ -0,0 +1,9 @@
+/*     pdma.h  6.1     83/07/29        */
+
+struct pdma {
+       struct  dzdevice *p_addr;
+       char    *p_mem;
+       char    *p_end;
+       int     p_arg;
+       int     (*p_fcn)();
+};
diff --git a/usr/src/sys/vaxuba/rkreg.h b/usr/src/sys/vaxuba/rkreg.h
new file mode 100644 (file)
index 0000000..0e202a8
--- /dev/null
@@ -0,0 +1,130 @@
+/*     rkreg.h 6.1     83/07/29        */
+
+#define NRK7CYL        815
+#define        NRK6CYL         411
+#define NRKSECT                22
+#define NRKTRK         3
+
+struct rkdevice
+{
+       short   rkcs1;          /* control status reg 1 */
+       short   rkwc;           /* word count */
+       u_short rkba;           /* bus address */
+       short   rkda;           /* disk address */
+       short   rkcs2;          /* control status reg 2 */
+       short   rkds;           /* drive status */
+       short   rker;           /* driver error register */
+       short   rkatt;          /* attention status/offset register */
+       short   rkcyl;          /* current cylinder register */
+       short   rkxxx;
+       short   rkdb;           /* data buffer register */
+       short   rkmr1;          /* maint reg 1 */
+       short   rkec1;          /* burst error bit position */
+       short   rkec2;          /* burst error bit pattern */
+       short   rkmr2;          /* maint reg 2 */
+       short   rkmr3;          /* maint reg 3 */
+};
+
+/* rkcs1 */
+#define RK_CCLR                0100000         /* controller clear (also error) */
+#define        RK_CERR         RK_CCLR
+#define        RK_DI           0040000         /* drive interrupt */
+#define        RK_DTCPAR       0020000         /* drive to controller parity */
+#define        RK_CFMT         0010000         /* 18 bit word format */
+#define        RK_CTO          0004000         /* controller timeout */
+#define        RK_CDT          0002000         /* drive type (rk07/rk06) */
+/* bits 8 and 9 are the extended bus address */
+#define        RK_CRDY         0000200         /* controller ready */
+#define        RK_IE           0000100         /* interrupt enable */
+/* bits 1 to 4 are the function code */
+#define        RK_GO           0000001
+
+/* commands */
+#define RK_SELECT      000             /* select drive */
+#define RK_PACK                002             /* pack acknowledge */
+#define RK_DCLR                004             /* drive clear */
+#define        RK_UNLOAD       006             /* unload */
+#define        RK_START        010             /* start spindle */
+#define        RK_RECAL        012             /* recalibrate */
+#define        RK_OFFSET       014             /* offset */
+#define        RK_SEEK         016             /* seek */
+#define        RK_READ         020             /* read data */
+#define        RK_WRITE        022             /* write data */
+#define        RK_RHDR         026             /* read header */
+#define        RK_WHDR         030             /* write header */
+
+/* rkcs2 */
+#define        RKCS2_DLT       0100000         /* data late */
+#define        RKCS2_WCE       0040000         /* write check */
+#define        RKCS2_UPE       0020000         /* unibus parity */
+#define        RKCS2_NED       0010000         /* non-existant drive */
+#define        RKCS2_NEM       0004000         /* non-existant memory */
+#define        RKCS2_PGE       0002000         /* programming error */
+#define        RKCS2_MDS       0001000         /* multiple drive select */
+#define        RKCS2_UFE       0000400         /* unit field error */
+#define        RKCS2_OR        0000200         /* output ready */
+#define        RKCS2_IR        0000100         /* input ready */
+#define        RKCS2_SCLR      0000040         /* subsystem clear */
+#define        RKCS2_BAI       0000020         /* bus address increment inhibit */
+#define        RKCS2_RLS       0000010         /* release */
+/* bits 0-2 are drive select */
+
+#define        RKCS2_BITS \
+"\10\20DLT\17WCE\16UPE\15NED\14NEM\13PGE\12MDS\11UFE\
+\10OR\7IR\6SCLR\5BAI\4RLS"
+
+#define        RKCS2_HARD              (RKCS2_NED|RKCS2_PGE)
+
+/* rkds */
+#define        RKDS_SVAL       0100000         /* status valid */
+#define        RKDS_CDA        0040000         /* current drive attention */
+#define        RKDS_PIP        0020000         /* positioning in progress */
+/* bit 12 is spare */
+#define        RKDS_WRL        0004000         /* write lock */
+/* bits 9 and 10 are spare */
+#define        RKDS_DDT        0000400         /* disk drive type */
+#define        RKDS_DRDY       0000200         /* drive ready */
+#define        RKDS_VV         0000100         /* volume valid */
+#define        RKDS_DROT       0000040         /* drive off track */
+#define        RKDS_SPLS       0000020         /* speed loss */
+#define        RKDS_ACLO       0000010         /* ac low */
+#define        RKDS_OFF        0000004         /* offset mode */
+#define        RKDS_DRA        0000001         /* drive available */
+
+#define        RKDS_DREADY     (RKDS_DRA|RKDS_VV|RKDS_DRDY)
+#define        RKDS_BITS \
+"\10\20SVAL\17CDA\16PIP\14WRL\11DDT\
+\10DRDY\7VV\6DROT\5SPLS\4ACLO\3OFF\1DRA"
+#define        RKDS_HARD       (RKDS_ACLO|RKDS_SPLS)
+
+/* rker */
+#define        RKER_DCK        0100000         /* data check */
+#define        RKER_UNS        0040000         /* drive unsafe */
+#define        RKER_OPI        0020000         /* operation incomplete */
+#define        RKER_DTE        0010000         /* drive timing error */
+#define        RKER_WLE        0004000         /* write lock error */
+#define        RKER_IDAE       0002000         /* invalid disk address error */
+#define        RKER_COE        0001000         /* cylinder overflow error */
+#define        RKER_HRVC       0000400         /* header vertical redundancy check */
+#define        RKER_BSE        0000200         /* bad sector error */
+#define        RKER_ECH        0000100         /* hard ecc error */
+#define        RKER_DTYE       0000040         /* drive type error */
+#define        RKER_FMTE       0000020         /* format error */
+#define        RKER_DRPAR      0000010         /* control-to-drive parity error */
+#define        RKER_NXF        0000004         /* non-executable function */
+#define        RKER_SKI        0000002         /* seek incomplete */
+#define        RKER_ILF                0000001         /* illegal function */
+
+#define        RKER_BITS \
+"\10\20DCK\17UNS\16OPI\15DTE\14WLE\13IDAE\12COE\11HRVC\
+\10BSE\7ECH\6DTYE\5FMTE\4DRPAR\3NXF\2SKI\1ILF"
+#define        RKER_HARD       \
+       (RKER_WLE|RKER_IDAE|RKER_COE|RKER_DTYE|RKER_FMTE|RKER_ILF)
+
+/* offset bits in rkas */
+#define        RKAS_P400       0020            /*  +400 RK06,  +200 RK07 */
+#define        RKAS_M400       0220            /*  -400 RK06,  -200 RK07 */
+#define        RKAS_P800       0040            /*  +800 RK06,  +400 RK07 */
+#define        RKAS_M800       0240            /*  -800 RK06,  -400 RK07 */
+#define        RKAS_P1200      0060            /*  +800 RK06,  +400 RK07 */
+#define        RKAS_M1200      0260            /* -1200 RK06, -1200 RK07 */
diff --git a/usr/src/sys/vaxuba/rl.c b/usr/src/sys/vaxuba/rl.c
new file mode 100644 (file)
index 0000000..33382d0
--- /dev/null
@@ -0,0 +1,675 @@
+/*     rl.c    6.1     83/07/29        */
+
+#include "rl.h"
+#if NRL > 0
+/*
+ * UNIBUS RL02 disk driver
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dk.h"
+#include "../h/dkbad.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vax/nexus.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/rlreg.h"
+
+/* Pending Controller items and statistics */
+struct rl_softc {
+       int     rl_softas;      /* Attention sumary, (seeks pending) */
+       int     rl_ndrive;      /* Number of drives on controller */
+       int     rl_wticks;      /* Monitor time for function */
+} rl_softc[NHL];
+
+/* 
+ * State of controller from last transfer.
+ * Since only one transfer can be done at a time per
+ * controller, only allocate one for each controller.
+ */
+struct rl_stat {
+       short   rl_cyl[4];      /* Current cylinder for each drive */
+       short   rl_dn;          /* drive number currently transferring */
+       short   rl_cylnhd;      /* current cylinder and head of transfer */
+       u_short rl_bleft;       /* bytes left to transfer */
+       u_short rl_bpart;       /* bytes transferred */
+} rl_stat[NHL];
+
+/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
+/* Last cylinder not used. Saved for Bad Sector File */
+struct size {
+       daddr_t nblocks;
+       int     cyloff;
+} rl02_sizes[8] = {
+       15884,          0,              /* A=cyl   0 thru 397 */
+        4520,          398,            /* B=cyl 398 thru 510 */
+          -1,          0,              /* C=cyl   0 thru 511 */
+        4520,          398,            /* D=cyl 398 thru 510 */
+           0,          0,              /* F= Not Defined     */
+       20440,          0,              /* G=cyl   0 thru 510 */
+           0,          0,              /* H= Not Defined     */
+};
+/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
+
+int    rlprobe(), rlslave(), rlattach(), rldgo(), rlintr();
+struct uba_ctlr        *rlminfo[NHL];
+struct uba_device      *rldinfo[NRL];
+struct uba_device      *rlip[NHL][4];
+
+/* RL02 driver structure */
+u_short        rlstd[] = { 0174400 };
+struct uba_driver hldriver =
+    { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo };
+
+/* User table per controller */
+struct buf     rlutab[NRL];
+
+/* RL02 drive structure */
+struct RL02 {
+       short   nbpt;           /* Number of 512 byte blocks/track */
+       short   ntrak;
+       short   nbpc;           /* Number of 512 byte blocks/cylinder */
+       short   ncyl;
+       short   btrak;          /* Number of bytes/track */
+       struct  size *sizes;
+} rl02 = {
+       20,     2,      40,     512,    20*512, rl02_sizes /* rl02/DEC*/
+};
+
+struct buf     rrlbuf[NRL];
+
+#define        b_cylin b_resid         /* Last seek as CYL<<1 | HD */
+
+#ifdef INTRLVE
+daddr_t dkblock();
+#endif
+
+int    rlwstart, rlwatch();            /* Have started guardian */
+
+/* Check that controller exists */
+/*ARGSUSED*/
+rlprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+
+#ifdef lint    
+       br = 0; cvec = br; br = cvec;
+       rlintr(0);
+#endif
+       ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP;
+       DELAY(10);
+       ((struct rldevice *)reg)->rlcs &= ~RL_IE;
+       return (sizeof (struct rldevice));
+}
+
+rlslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       register struct rldevice *rladdr = (struct rldevice *)reg;
+       short ctr = 0;
+
+       /*
+        * DEC reports that:
+        * For some unknown reason the RL02 (seems to be only drive 1)
+        * does not return a valid drive status the first time that a
+        * GET STATUS request is issued for the drive, in fact it can
+        * take up to three or more GET STATUS requests to obtain the
+        * correct status.
+        * In order to overcome this, the driver has been modified to
+        * issue a GET STATUS request and validate the drive status
+        * returned.  If a valid status is not returned after eight
+        * attempts, then an error message is printed.
+        */
+       do {
+               rladdr->rlda.getstat = RL_RESET;
+               rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
+               rlwait(rladdr);
+       } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8);
+       if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
+               return (0);
+       if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) {
+               printf("rl%d: rl01's not supported\n", ui->ui_slave);
+               return(0);
+       }
+       return (1);
+}
+
+rlattach(ui)
+       register struct uba_device *ui;
+{
+       register struct rldevice *rladdr;
+
+       if (rlwstart == 0) {
+               timeout(rlwatch, (caddr_t)0, hz);
+               rlwstart++;
+       }
+       /* Initialize iostat values */
+       if (ui->ui_dk >= 0)
+               dk_mspw[ui->ui_dk] = .000003906;   /* 16bit transfer time? */
+       rlip[ui->ui_ctlr][ui->ui_slave] = ui;
+       rl_softc[ui->ui_ctlr].rl_ndrive++;
+       rladdr = (struct rldevice *)ui->ui_addr;
+       /* reset controller */
+       rladdr->rlda.getstat = RL_RESET;        /* SHOULD BE REPEATED? */
+       rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */
+       rlwait(rladdr);
+       /* determine disk posistion */
+       rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
+       rlwait(rladdr);
+       /* save disk drive posistion */
+       rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] =
+            (rladdr->rlmp.readhdr & 0177700) >> 6;
+       rl_stat[ui->ui_ctlr].rl_dn = -1;
+}
+rlopen(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       return (0);
+}
+
+rlstrategy(bp)
+       register struct buf *bp;
+{
+       register struct uba_device *ui;
+       register int drive;
+       register struct buf *dp;
+       int partition = minor(bp->b_dev) & 07, s;
+       long bn, sz;
+
+       sz = (bp->b_bcount+511) >> 9;
+       drive = dkunit(bp);
+       if (drive >= NRL)
+               goto bad;
+       ui = rldinfo[drive];
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       if (bp->b_blkno < 0 ||
+           (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks)
+               goto bad;
+       /* bn is in 512 byte block size */
+       bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff;
+       s = spl5();
+       dp = &rlutab[ui->ui_unit];
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               rlustart(ui);
+               bp = &ui->ui_mi->um_tab;
+               if (bp->b_actf && bp->b_active == 0)
+                       rlstart(ui->ui_mi);
+       }
+       splx(s);
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+/*
+ * Unit start routine.
+ * Seek the drive to be where the data is
+ * and then generate another interrupt
+ * to actually start the transfer.
+ */
+rlustart(ui)
+       register struct uba_device *ui;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um;
+       register struct rldevice *rladdr;
+       daddr_t bn;
+       short hd, diff;
+
+       if (ui == 0)
+               return;
+       um = ui->ui_mi;
+       dk_busy &= ~(1 << ui->ui_dk);
+       dp = &rlutab[ui->ui_unit];
+       if ((bp = dp->b_actf) == NULL)
+               return;
+       /*
+        * If the controller is active, just remember
+        * that this device has to be positioned...
+        */
+       if (um->um_tab.b_active) {
+               rl_softc[um->um_ctlr].rl_softas |=  1<<ui->ui_slave;
+               return;
+       }
+       /*
+        * If we have already positioned this drive,
+        * then just put it on the ready queue.
+        */
+       if (dp->b_active)
+               goto done;
+       dp->b_active = 1;       /* positioning drive */
+       rladdr = (struct rldevice *)um->um_addr;
+
+       /*
+        * Figure out where this transfer is going to
+        * and see if we are seeked correctly.
+        */
+       bn = dkblock(bp);               /* Block # desired */
+       /*
+        * Map 512 byte logical disk blocks
+        * to 256 byte sectors (rl02's are stupid).
+        */
+       hd = (bn / rl02.nbpt) & 1;      /* Get head required */
+       diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin;
+       if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd)
+               goto done;              /* on cylinder and head */
+       /*
+        * Not at correct position.
+        */
+       rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd;
+       if (diff < 0)
+               rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4;
+       else
+               rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4;
+       rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
+
+       /*
+        * Mark unit busy for iostat.
+        */
+       if (ui->ui_dk >= 0) {
+               dk_busy |= 1<<ui->ui_dk;
+               dk_seek[ui->ui_dk]++;
+       }
+       rlwait(rladdr);
+done:
+       /*
+        * Device is ready to go.
+        * Put it on the ready queue for the controller
+        * (unless its already there.)
+        */
+       if (dp->b_active != 2) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_active = 2;       /* Request on ready queue */
+       }
+}
+
+/*
+ * Start up a transfer on a drive.
+ */
+rlstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct uba_device *ui;
+       register struct rldevice *rladdr;
+       register struct rl_stat *st = &rl_stat[um->um_ctlr];
+       daddr_t bn;
+       short sn, cyl, cmd;
+
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL) {
+               st->rl_dn = -1;
+               st->rl_cylnhd = 0;
+               st->rl_bleft = 0;
+               st->rl_bpart = 0;
+               return;
+       }
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       /*
+        * Mark controller busy, and
+        * determine destination.
+        */
+       um->um_tab.b_active++;
+       ui = rldinfo[dkunit(bp)];               /* Controller */
+       bn = dkblock(bp);                       /* 512 byte Block number */
+       cyl = bp->b_cylin << 1;                 /* Cylinder */
+       cyl |= (bn / rl02.nbpt) & 1;            /* Get head required */
+       sn = (bn % rl02.nbpt) << 1;             /* Sector number */
+       rladdr = (struct rldevice *)ui->ui_addr;
+       rlwait(rladdr);
+       rladdr->rlda.rw = cyl<<6 | sn;
+       /* save away current transfers drive status */
+       st->rl_dn = ui->ui_slave;
+       st->rl_cylnhd = cyl;
+       st->rl_bleft = bp->b_bcount;
+       st->rl_bpart = rl02.btrak - (sn * NRLBPSC);
+       /*
+        * RL02 must seek between cylinders and between tracks,
+        * determine maximum data transfer at this time.
+        */
+       if (st->rl_bleft < st->rl_bpart)
+               st->rl_bpart = st->rl_bleft;
+       rladdr->rlmp.rw = -(st->rl_bpart >> 1);
+       if (bp->b_flags & B_READ)
+               cmd = RL_IE | RL_READ | (ui->ui_slave << 8);
+       else
+               cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8);
+       um->um_cmd = cmd;
+       (void) ubago(ui);
+}
+
+rldgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
+
+       rladdr->rlba = um->um_ubinfo;
+       rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE);
+}
+
+/*
+ * Handle a disk interrupt.
+ */
+rlintr(rl21)
+       register rl21;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um = rlminfo[rl21];
+       register struct uba_device *ui;
+       register struct rldevice *rladdr = (struct rldevice *)um->um_addr;
+       register unit;
+       struct rl_softc *rl = &rl_softc[um->um_ctlr];
+       struct rl_stat *st = &rl_stat[um->um_ctlr];
+       int as = rl->rl_softas, status;
+
+       rl->rl_wticks = 0;
+       rl->rl_softas = 0;
+       dp = um->um_tab.b_actf;
+       bp = dp->b_actf;
+       ui = rldinfo[dkunit(bp)];
+       dk_busy &= ~(1 << ui->ui_dk);
+
+       /*
+        * Check for and process errors on
+        * either the drive or the controller.
+        */
+       if (rladdr->rlcs & RL_ERR) {
+               u_short err;
+               rlwait(rladdr);
+               err = rladdr->rlcs;
+               /* get staus and reset controller */
+               rladdr->rlda.getstat = RL_GSTAT;
+               rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT;
+               rlwait(rladdr);
+               status = rladdr->rlmp.getstat;
+               /* reset drive */
+               rladdr->rlda.getstat = RL_RESET;
+               rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/
+               rlwait(rladdr);
+               if ((status & RLMP_WL) == RLMP_WL) {
+                       /*
+                        * Give up on write protected devices
+                        * immediately.
+                        */
+                       printf("rl%d: write protected\n", dkunit(bp));
+                       bp->b_flags |= B_ERROR;
+               } else if (++um->um_tab.b_errcnt > 10) {
+                       /*
+                        * After 10 retries give up.
+                        */
+                       harderr(bp, "rl");
+                       printf("cs=%b mp=%b\n", err, RLCS_BITS,
+                           status, RLER_BITS);
+                       bp->b_flags |= B_ERROR;
+               } else
+                       um->um_tab.b_active = 0;         /* force retry */
+               /* determine disk position */
+               rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR;
+               rlwait(rladdr);
+               /* save disk drive position */
+               st->rl_cyl[ui->ui_slave] =
+                   (rladdr->rlmp.readhdr & 0177700) >> 6;
+       }
+       /*
+        * If still ``active'', then don't need any more retries.
+        */
+       if (um->um_tab.b_active) {
+               /* RL02 check if more data from previous request */
+               if ((bp->b_flags & B_ERROR) == 0 &&
+                    (int)(st->rl_bleft -= st->rl_bpart) > 0) {
+                       /*
+                        * The following code was modeled from the rk07
+                        * driver when an ECC error occured.  It has to
+                        * fix the bits then restart the transfer which is
+                        * what we have to do (restart transfer).
+                        */
+                       int reg, npf, o, cmd, ubaddr, diff, head;
+
+                       /* seek to next head/track */
+                       /* increment head and/or cylinder */
+                       st->rl_cylnhd++;
+                       diff = (st->rl_cyl[ui->ui_slave] >> 1) -
+                               (st->rl_cylnhd >> 1);
+                       st->rl_cyl[ui->ui_slave] = st->rl_cylnhd;
+                       head = st->rl_cylnhd & 1;
+                       rlwait(rladdr);
+                       if (diff < 0)
+                               rladdr->rlda.seek =
+                                   -diff << 7 | RLDA_HGH | head << 4;
+                       else
+                               rladdr->rlda.seek =
+                                   diff << 7 | RLDA_LOW | head << 4;
+                       rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK;
+                       npf = btop( bp->b_bcount - st->rl_bleft );
+                       reg = btop(um->um_ubinfo&0x3ffff) + npf;
+                       o = (int)bp->b_un.b_addr & PGOFSET;
+                       ubapurge(um);
+                       um->um_tab.b_active++;
+                       rlwait(rladdr);
+                       rladdr->rlda.rw = st->rl_cylnhd << 6;
+                       if (st->rl_bleft < (st->rl_bpart = rl02.btrak))
+                               st->rl_bpart = st->rl_bleft;
+                       rladdr->rlmp.rw = -(st->rl_bpart >> 1);
+                       cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) |
+                           RL_IE | (ui->ui_slave << 8);
+                       ubaddr = (int)ptob(reg) + o;
+                       cmd |= ((ubaddr >> 12) & RL_BAE);
+                       rladdr->rlba = ubaddr;
+                       rladdr->rlcs = cmd;
+                       return;
+               }
+               um->um_tab.b_active = 0;
+               um->um_tab.b_errcnt = 0;
+               dp->b_active = 0;
+               dp->b_errcnt = 0;
+               /* "b_resid" words remaining after error */
+               bp->b_resid = st->rl_bleft;
+               um->um_tab.b_actf = dp->b_forw;
+               dp->b_actf = bp->av_forw;
+               st->rl_dn = -1;
+               st->rl_bpart = st->rl_bleft = 0;
+               iodone(bp);
+               /*
+                * If this unit has more work to do,
+                * then start it up right away.
+                */
+               if (dp->b_actf)
+                       rlustart(ui);
+               as &= ~(1<<ui->ui_slave);
+       } else
+               as |= (1<<ui->ui_slave);
+       ubadone(um);
+       /* reset state info */
+       st->rl_dn = -1;
+       st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0;
+       /*
+        * Process other units which need attention.
+        * For each unit which needs attention, call
+        * the unit start routine to place the slave
+        * on the controller device queue.
+        */
+       while (unit = ffs(as)) {
+               unit--;         /* was 1 origin */
+               as &= ~(1<<unit);
+               rlustart(rlip[rl21][unit]);
+       }
+       /*
+        * If the controller is not transferring, but
+        * there are devices ready to transfer, start
+        * the controller.
+        */
+       if (um->um_tab.b_actf && um->um_tab.b_active == 0)
+               rlstart(um);
+}
+
+rlwait(rladdr)
+       register struct rldevice *rladdr;
+{
+
+       while ((rladdr->rlcs & RL_CRDY) == 0)
+               ;
+}
+
+rlread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRL)
+               return (ENXIO);
+       return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio));
+}
+
+rlwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRL)
+               return (ENXIO);
+       return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Reset driver after UBA init.
+ * Cancel software state of all pending transfers
+ * and restart all units and the controller.
+ */
+rlreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
+       register struct rldevice *rladdr;
+       register struct rl_stat *st;
+       register int rl21, unit;
+
+       for (rl21 = 0; rl21 < NHL; rl21++) {
+               if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               printf(" hl%d", rl21);
+               rladdr = (struct rldevice *)um->um_addr;
+               st = &rl_stat[rl21];
+               um->um_tab.b_active = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               /* reset controller */
+               st->rl_dn = -1;
+               st->rl_cylnhd = 0;
+               st->rl_bleft = 0;
+               st->rl_bpart = 0;
+               rlwait(rladdr);
+               for (unit = 0; unit < NRL; unit++) {
+                       rladdr->rlcs = (unit << 8) | RL_GETSTAT;
+                       rlwait(rladdr);
+                       /* Determine disk posistion */
+                       rladdr->rlcs = (unit << 8) | RL_RHDR;
+                       rlwait(rladdr);
+                       /* save disk drive posistion */
+                       st->rl_cyl[unit] =
+                               (rladdr->rlmp.readhdr & 0177700) >> 6;
+                       if ((ui = rldinfo[unit]) == 0)
+                               continue;
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
+                               continue;
+                       rlutab[unit].b_active = 0;
+                       rlustart(ui);
+               }
+               rlstart(um);
+       }
+}
+
+/*
+ * Wake up every second and if an interrupt is pending
+ * but nothing has happened increment a counter.
+ * If nothing happens for 20 seconds, reset the UNIBUS
+ * and begin anew.
+ */
+rlwatch()
+{
+       register struct uba_ctlr *um;
+       register rl21, unit;
+       register struct rl_softc *rl;
+
+       timeout(rlwatch, (caddr_t)0, hz);
+       for (rl21 = 0; rl21 < NHL; rl21++) {
+               um = rlminfo[rl21];
+               if (um == 0 || um->um_alive == 0)
+                       continue;
+               rl = &rl_softc[rl21];
+               if (um->um_tab.b_active == 0) {
+                       for (unit = 0; unit < NRL; unit++)
+                               if (rlutab[unit].b_active &&
+                                   rldinfo[unit]->ui_mi == um)
+                                       goto active;
+                       rl->rl_wticks = 0;
+                       continue;
+               }
+active:
+               rl->rl_wticks++;
+               if (rl->rl_wticks >= 20) {
+                       rl->rl_wticks = 0;
+                       printf("hl%d: lost interrupt\n", rl21);
+                       ubareset(um->um_ubanum);
+               }
+       }
+}
+
+/*ARGSUSED*/
+rldump(dev)
+       dev_t dev;
+{
+
+       /* don't think there is room on swap for it anyway. */
+}
+
+rlsize(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       return (rl02.sizes[minor(dev) & 07].nblocks);
+}
+#endif
diff --git a/usr/src/sys/vaxuba/rlreg.h b/usr/src/sys/vaxuba/rlreg.h
new file mode 100644 (file)
index 0000000..a7e64d2
--- /dev/null
@@ -0,0 +1,107 @@
+/*     rlreg.h 6.1     83/07/29        */
+
+struct rldevice {
+       short   rlcs;           /* control status */
+       u_short rlba;           /* bus address */
+       union {                 /* disk address */
+               u_short seek;           /* disk seek address */
+               u_short rw;             /* disk read/write address */
+               u_short getstat;        /* get disk status command */
+       } rlda;
+       union {                 /* multi-purpose register */
+               u_short getstat;        /* get status */
+               u_short readhdr;        /* read header */
+               u_short rw;             /* read/write word count */
+       } rlmp;
+};
+
+#define        NRLCYLN         512     /* number of cylinders per disk */
+#define NRLTRKS                2       /* number of tracks per cylinder */
+#define NRLSECT                40      /* number of sectors per track */
+#define NRLBPSC                256     /* bytes per sector */
+
+/* rlcs */
+/* commands */
+#define RL_NOOP                0000000         /* no-operation */
+#define RL_WCHECK      0000002         /* write check */
+#define RL_GETSTAT     0000004         /* get status */
+#define        RL_SEEK         0000006         /* seek */
+#define        RL_RHDR         0000010         /* read header */
+#define        RL_WRITE        0000012         /* write data */
+#define        RL_READ         0000014         /* read data */
+#define        RL_RDNCK        0000016         /* read data without hdr check */
+
+#define RL_DRDY                0000001         /* When set indicates drive ready */
+#define RL_BAE         0000060         /* UNIBUS address bits 16 & 17 */
+#define        RL_IE           0000100         /* interrupt enable */
+#define        RL_CRDY         0000200         /* controller ready */
+#define RL_DS0         0000400         /* drive select 0 */
+#define RL_DS1         0001000         /* drive select 1 */
+#define        RL_OPI          0002000         /* operation incomplete */
+#define        RL_DCRC         0004000         /* CRC error occurred */
+#define        RL_DLT          0010000         /* data late or header not found */
+#define        RL_NXM          0020000         /* non-existant memory */
+#define        RL_DE           0040000         /* selected drive flagged an error */
+#define        RL_ERR          0100000         /* composite error */
+
+#define        RL_DCRDY        (RL_DRDY | RL_CRDY)
+
+#define        RLCS_BITS \
+"\10\20ERR\17DE\16NXM\15DLT\14DCRC\13OPI\1DRDY"
+
+/* da_seek */
+#define        RLDA_LOW        0000001         /* lower cylinder seek */
+#define        RLDA_HGH        0000005         /* higher cylinder seek */
+#define        RLDA_HSU        0000000         /* upper head select */
+#define        RLDA_HSL        0000020         /* lower head select */
+#define        RLDA_CA         0177600         /* cylinder address */
+
+/* da_rw */
+#define        RLDA_SA         0000077         /* sector address */
+#define RLDA_HST       0000000         /* upper head select */
+#define        RLDA_HSB        0000100         /* lower head select */
+
+/* da_getstat */
+
+#define        RL_GSTAT        0000003         /* Get status */
+#define        RL_RESET        0000013         /* get status with reset */
+
+/* mp_getstat */
+#define        RLMP_STA        0000001         /* drive state: load cartridge */
+#define        RLMP_STB        0000002         /* drive state: brush cycle */
+#define        RLMP_STC        0000004         /* drive state: seek */
+#define        RLMP_BH         0000010         /* set when brushes are home */
+#define        RLMP_HO         0000020         /* set when brushes over the disk */
+#define        RLMP_CO         0000040         /* set when cover open */
+#define        RLMP_HS         0000100         /* indicates selected head:
+                                               0 upper head
+                                               1 lower head */
+#define        RLMP_DT         0000200         /* indicates drive type:
+                                               0 RL01
+                                               1 RL02 */
+#define        RLMP_DSE        0000400         /* set on multiple drive selection */
+#define        RLMP_VC         0001000         /* set on pack mounted and spining */
+#define        RLMP_WGE        0002000         /* write gate error */
+#define        RLMP_SPE        0004000         /* spin speed error */
+#define        RLMP_SKTO       0010000         /*\\b* seek time out error */
+#define RLMP_WL                0020000         /* set on protected drive */
+#define RLMP_CHE       0040000         /* current head error */
+#define RLMP_WDE       0100000         /* write data error */
+
+/* mp_rhc */
+#define        RLMP_SA         0000077         /* sector address */
+#define        RLMP_CA         0177600         /* cylinder address */
+
+/* check these bits after a get status and reset */
+#define RLMP_STATUS (RLMP_WDE|RLMP_CHE|RLMP_SKTO|RLMP_SPE|RLMP_WGE \
+       |RLMP_VC|RLMP_DSE|RLMP_CO|RLMP_HO|RLMP_BH|RLMP_STC|RLMP_STB|RLMP_STA)
+
+/* these are the bits that should be on in the above check */
+#define RLMP_STATOK (RLMP_HO|RLMP_BH|RLMP_STC|RLMP_STA)
+
+/* mp_rw */
+#define        RLMP_WC         0017777         /* word count 2's complement */
+
+#define        RLER_BITS \
+"\10\20WDE\17CHE\16WL\15SKTO\14SPE\13WGE\12VC\11DSE\
+\10DT\7HS\6CO\5HO\4BH\3STC\2STB\1STA"
diff --git a/usr/src/sys/vaxuba/rx.c b/usr/src/sys/vaxuba/rx.c
new file mode 100644 (file)
index 0000000..c41e5e9
--- /dev/null
@@ -0,0 +1,868 @@
+/*     rx.c    6.1     83/07/29        */
+
+#include "rx.h"
+#if NFX > 0
+/*
+ * RX02 floppy disk device driver
+ *
+ */
+
+/*
+ * TODO:
+ *     - clean up the code for multisector transfers using
+ *       a 'transfer in progress' flag
+ *     - Test Deleted Data read/write 
+ *     - Test error handling/reporting and 'volume valid' stuff
+ *
+ *     Note: If the drive subsystem is
+ *     powered off at boot time, the controller won't interrupt!
+ */
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/errno.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/uio.h"
+#include "../h/file.h"
+
+#include "../vax/cpu.h"
+#include "../vax/nexus.h"
+
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/rxreg.h"
+
+#define b_cylin        b_resid
+
+/* per-controller data */
+struct rx_ctlr {
+       int     rxc_state;      /* controller state */
+#define        RXS_READ        1       /* read started */
+#define        RXS_EMPTY       2       /* empty started */
+#define        RXS_FILL        3       /* fill started */
+#define        RXS_WRITE       4       /* write started */
+#define        RXS_FORMAT      5       /* format started */
+#define        RXS_RDSTAT      6       /* status read started */
+#define        RXS_RDERR       7       /* error read started */
+#define        RXS_IDLE        8       /* device is idle */
+       u_short rxc_rxcs;       /* extended error status */
+       u_short rxc_rxdb;
+       u_short rxc_rxxt[4];
+       int     rxc_tocnt;      /* for watchdog routine */
+#define        RX_MAXTIMEOUT   30      /* # seconds to wait before giving up */
+} rx_ctlr[NFX];
+
+/* per-drive buffers */
+struct buf     rrxbuf[NRX];    /* buffers for raw I/O */
+struct buf     erxbuf[NRX];    /* buffers for reading error status */
+struct buf     rxutab[NRX];    /* per drive buffers */
+
+/* per-drive data */
+struct rx_softc {
+       int     sc_flags;       /* drive status flags */
+#define        RXF_DIRECT      0x01    /* if set: use direct sector mapping */
+#define        RXF_TRKONE      0x02    /* if set: start mapping on track 1 */
+#define        RXF_DBLDEN      0x04    /* use double density */
+#define        RXF_DEVTYPE     0x07    /* mapping flags */
+#define        RXF_LOCK        0x10    /* exclusive use */
+#define        RXF_DDMK        0x20    /* deleted-data mark detected */
+#define        RXF_USEWDDS     0x40    /* write deleted-data sector */
+#define        RXF_FORMAT      0x80    /* format in progress */
+#define        RXF_BAD         0x100   /* drive bad, cannot be used */
+       int     sc_csbits;      /* constant bits for CS register */
+       int     sc_open;        /* count number of opens */
+       int     sc_offset;      /* raw mode kludge to avoid restricting */
+                               /* single sector transfers to start on */
+                               /* DEV_BSIZE boundaries */
+       /*
+        * The rest of this structure is used to 
+        * store temporaries while simulating multi 
+        * sector transfers
+        */
+       caddr_t sc_uaddr;       /* unibus base address */
+       long    sc_bcnt;        /* total transfer count */
+       long    sc_resid;       /* no. of bytes left to transfer */
+} rx_softc[NRX];
+
+struct rxerr {
+       short   rxcs;
+       short   rxdb;
+       short   rxxt[4];        /* error code dump from controller */
+} rxerr[NRX];
+/* End of per-drive data */
+
+struct uba_device *rxdinfo[NRX];
+struct uba_ctlr *rxminfo[NFX];
+
+struct buf *savebp;
+
+int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr(), rxwatch(), rxphys();
+u_short rxstd[] = { 0177170, 0177150, 0 };
+struct uba_driver fxdriver =
+  { rxprobe, rxslave, rxattach, rxdgo, rxstd, "rx", rxdinfo, "fx", rxminfo };
+
+int    rxwstart;
+#define        RXUNIT(dev)     (minor(dev)>>3)
+#define        MASKREG(reg)    (reg&0xffff)
+
+/* constants related to floppy data capacity */
+#define        RXSECS  2002                            /* # sectors on a floppy */
+#define        DDSTATE (sc->sc_csbits&RX_DDEN)
+#define        NBPS    (DDSTATE ? 256 : 128)           /* # bytes per sector */
+#define        RXSIZE  (DDSTATE ? 512512 : 256256)     /* # bytes per disk */
+#define        SECMASK (DDSTATE ? 0xff : 0x7f)         /* shifted-out bits of offset */
+
+#define        B_CTRL          0x80000000              /* control (format) request */
+#define B_RDSTAT       0x40000000              /* read drive status (open) */
+
+/*ARGSUSED*/
+rxprobe (reg)
+       caddr_t reg;
+{
+       register int br, cvec;                  /* value-result */
+       struct rxdevice *rxaddr = (struct rxdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       rxintr(0);
+#endif lint
+       rxaddr->rxcs = RX_INTR;
+       DELAY(10);
+       rxaddr->rxcs = 0;
+       return (sizeof (*rxaddr));
+}
+
+rxslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+
+       ui->ui_dk = 1;
+       return (ui->ui_slave == 0 || ui->ui_slave == 1);
+}
+
+/*ARGSUSED*/
+rxattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+/*ARGSUSED1*/
+rxopen(dev, flag)
+       dev_t dev;
+{ 
+       register int unit = RXUNIT(dev);
+       register struct rx_softc *sc;
+       register struct uba_device *ui;
+       struct rx_ctlr *rxc;
+
+       if (unit >= NRX || (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       sc = &rx_softc[unit];
+       if (sc->sc_open == 0 && sc->sc_csbits == 0) {
+               struct buf *bp = &erxbuf[unit];
+               /*
+                * lock the device while an open 
+                * is in progress
+                */
+               sc->sc_flags = (minor(dev) & RXF_DEVTYPE) | RXF_LOCK;
+               sc->sc_csbits = RX_INTR;
+               sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1;
+
+               bp->b_dev = dev;
+               bp->b_flags = B_RDSTAT | B_BUSY;
+               bp->b_error = 0;
+               bp->b_blkno = 0;
+               sc->sc_offset = 0;
+               sc->sc_resid  = 0;
+               /*
+                * read device status to determine if
+                * a floppy is present in the drive and
+                * what density it is
+                */
+               rxstrategy(bp);
+               iowait(bp);
+               if (bp->b_flags & B_ERROR) {
+                       sc->sc_csbits = 0;
+                       return (bp->b_error);
+               }
+               if (rxwstart++ == 0) {
+                       rxc = &rx_ctlr[ui->ui_mi->um_ctlr];
+                       rxc->rxc_tocnt = 0;
+                       timeout(rxwatch, (caddr_t)0, hz);  /* start watchdog */
+               }
+#ifdef RXDEBUG
+               printf("rxopen: csbits=0x%x\n", sc->sc_csbits);
+#endif
+               sc->sc_flags &= ~RXF_LOCK;
+       } else  {
+               if (sc->sc_flags & RXF_LOCK)
+                       return(EBUSY);
+       }
+       sc->sc_open++;
+       return (0);
+}
+
+/*ARGSUSED1*/
+rxclose(dev, flag)
+       dev_t dev;
+{
+       register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
+
+       --sc->sc_open;
+#ifdef RXDEBUG
+       printf("rxclose: dev=0x%x, sc_open=%d\n", dev, sc->sc_open);
+#endif
+}
+
+rxstrategy(bp)
+       register struct buf *bp;
+{
+       struct uba_device *ui;
+       register struct buf *dp;
+       struct rx_softc *sc;
+       int s, unit = RXUNIT(bp->b_dev);
+
+       if (unit >= NRX)
+               goto bad;
+       ui = rxdinfo[unit];
+       if (ui == 0 || ui->ui_alive == 0) 
+               goto bad;
+       sc = &rx_softc[unit];
+       if (bp->b_blkno < 0 || dbtob(bp->b_blkno) > RXSIZE)
+               goto bad;
+       if (sc->sc_flags & RXF_BAD) {
+               bp->b_error = EIO;
+               goto dbad;
+       }
+       s = spl5();
+#ifdef RXDEBUG
+       printf("rxstrat: bp=0x%x, fl=0x%x, un=%d, bl=%d, cnt=%d\n", 
+               bp, bp->b_flags, unit, bp->b_blkno, bp->b_bcount);
+#endif
+       bp->b_cylin = bp->b_blkno;      /* don't care to calculate trackno */
+       dp = &rxutab[unit];
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               rxustart(ui);
+               bp = &ui->ui_mi->um_tab;
+               if (bp->b_actf && bp->b_active == 0)
+                       rxstart(ui->ui_mi);
+       }
+       splx(s);
+       return;
+
+bad:
+       bp->b_error = ENXIO;
+dbad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+/*
+ * Unit start routine.
+ * Put this unit on the ready queue for the controller
+ */
+rxustart(ui)
+       register struct uba_device *ui;
+{
+       struct buf *dp = &rxutab[ui->ui_unit];
+       struct uba_ctlr *um = ui->ui_mi;
+       
+       dp->b_forw = NULL;
+       if (um->um_tab.b_actf == NULL)
+               um->um_tab.b_actf = dp;
+       else
+               um->um_tab.b_actl->b_forw = dp;
+       um->um_tab.b_actl = dp;
+       dp->b_active++;
+}
+/*
+ * Sector mapping routine.
+ * Two independent sets of choices are available:
+ *
+ * (a) The first logical sector may either be on track 1 or track 0.
+ * (b) The sectors on a track may either be taken in 2-for-1 interleaved
+ *      fashion or directly.
+ * This gives a total of four possible mapping schemes.
+ *
+ * Physical tracks on the RX02 are numbered 0-76.  Physical sectors on
+ * each track are numbered 1-26.
+ *
+ * When interleaving is used, sectors on the first logical track are
+ * taken in the order 1, 3, 5, ..., 25, 2, 4, 6, ..., 26.  A skew of
+ * six sectors per track is also used (to allow time for the heads to
+ * move); hence, the sectors on the second logical track are taken in
+ * the order 7, 9, 11, ..., 25, 1, 3, 5, 8, 10, 12, ..., 26, 2, 4, 6;
+ * the third logical track starts with sector 13; and so on.
+ *
+ * When the mapping starts with track 1, track 0 is the last logical
+ * track, and this track is always handled directly (without inter-
+ * leaving), even when the rest of the disk is interleaved.  (This is
+ * still compatible with DEC RT-11, which does not use track 0 at all.)
+ */
+rxmap(bp, psector, ptrack)
+       struct buf *bp;
+       int *psector, *ptrack;
+{
+       register int lt, ls, ptoff;
+       struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
+
+       ls = (dbtob(bp->b_blkno) + (sc->sc_offset - sc->sc_resid)) / NBPS;
+       lt = ls / 26;
+       ls %= 26;
+       /*
+        * The "physical track offset" (ptoff) takes the
+        * starting physical track (0 or 1) and the desired
+        * interleaving into account.  If lt+ptoff >= 77,
+        * then interleaving is not performed.
+        */
+       ptoff = 0;
+       if (sc->sc_flags & RXF_DIRECT)
+               ptoff = 77;
+       if (sc->sc_flags & RXF_TRKONE)
+               ptoff++;
+       if (lt + ptoff < 77)
+               ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
+       *ptrack = (lt + ptoff) % 77;
+       *psector = ls + 1;
+}
+
+/*
+ * Controller start routine.
+ * Start a new transfer or continue a multisector
+ * transfer. If this is a new transfer (dp->b_active == 1)
+ * save the start address of the data buffer and the total
+ * byte count in the soft control structure. These are
+ * restored into the buffer structure when the transfer has
+ * been completed, before calling 'iodone'.
+ */
+rxstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct rxdevice *rxaddr;
+       register struct rx_ctlr *rxc;
+       register struct rx_softc *sc;
+       struct buf *dp, *bp;
+       int unit, sector, track;
+
+       if (um->um_tab.b_active)
+               return;
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       um->um_tab.b_active++;
+       unit = RXUNIT(bp->b_dev);
+       sc = &rx_softc[unit];
+       if (sc->sc_flags & RXF_BAD) {
+               rxpurge(um);
+               return;
+       }
+       if (dp->b_active == 1) {
+               sc->sc_resid = bp->b_bcount;
+               sc->sc_uaddr = bp->b_un.b_addr;
+               sc->sc_bcnt = bp->b_bcount;
+               sc->sc_offset += sc->sc_bcnt;
+               dp->b_active++;
+       }
+       rxaddr = (struct rxdevice *)um->um_addr;
+       rxc = &rx_ctlr[um->um_ctlr];
+       bp->b_bcount = sc->sc_resid;
+       if (bp->b_bcount > NBPS)
+               bp->b_bcount = NBPS;
+       rxc->rxc_tocnt = 0;
+#ifdef RXDEBUG
+       printf("rxstart: ");
+#endif
+       if (rxaddr->rxcs == 0x800) {
+               /*
+                * 'Volume valid'? (check if the 
+                * drive unit has been powered down)
+                */
+               rxaddr->rxcs = RX_INIT;
+               while((rxaddr->rxcs&RX_DONE) == 0)
+                       ;
+       }
+       if (bp->b_flags & B_CTRL) {                             /* format */
+               rxc->rxc_state = RXS_FORMAT;
+               rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = 'I';
+               return;
+       }
+       if (bp->b_flags & B_RDSTAT) {                   /* read drive status */
+               rxc->rxc_state = RXS_RDSTAT;
+               rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
+               return;
+       }
+
+       if (bp->b_flags & B_READ) {
+               rxmap(bp, &sector, &track);                     /* read */
+#ifdef RXDEBUG
+               printf("read tr=%d, sc=%d", track, sector);
+#endif
+               rxc->rxc_state = RXS_READ;
+               rxaddr->rxcs = RX_READ | sc->sc_csbits;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = (u_short)sector;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = (u_short)track;
+       } else {
+#ifdef RXDEBUG
+               printf("write");
+#endif
+               rxc->rxc_state = RXS_FILL;                      /* write */
+               um->um_cmd = RX_FILL;
+               (void) ubago(rxdinfo[unit]);
+       }
+#ifdef RXDEBUG
+       printf("\n");
+#endif
+}
+
+rxdgo(um)
+       struct uba_ctlr *um;
+{
+       register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr;
+       int ubinfo = um->um_ubinfo;
+       struct buf *bp = um->um_tab.b_actf->b_actf;
+       struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
+       struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
+
+       rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
+       if (rxc->rxc_state != RXS_RDERR) {
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = (u_short) bp->b_bcount >> 1;
+       }
+       while ((rxaddr->rxcs&RX_TREQ) == 0)
+               ;
+       rxaddr->rxdb = (u_short) ubinfo;
+}
+
+rxintr(ctlr)
+       int ctlr;
+{
+       int unit, sector, track;
+       struct uba_ctlr *um = rxminfo[ctlr];
+       register struct rxdevice *rxaddr;
+       register struct buf *bp, *dp;
+       register struct rx_softc *sc;
+       struct uba_device *ui;
+       struct rxerr *er;
+       struct rx_ctlr *rxc;
+
+       if (!um->um_tab.b_active)
+               return;
+       dp = um->um_tab.b_actf;
+       if (!dp->b_active)
+               return;
+       bp = dp->b_actf;
+       unit = RXUNIT(bp->b_dev);
+       sc = &rx_softc[unit];
+       ui = rxdinfo[unit];
+       rxaddr = (struct rxdevice *)um->um_addr;
+       rxc = &rx_ctlr[um->um_ctlr];
+       rxc->rxc_tocnt = 0;
+       er = &rxerr[unit];
+#ifdef RXDEBUG
+       printf("rxint: dev=%x, st=%d, cs=0x%x, db=0x%x\n", 
+               bp->b_dev, rxc->rxc_state, rxaddr->rxcs, rxaddr->rxdb);
+#endif
+       if ((rxaddr->rxcs & RX_ERR) &&
+           (rxc->rxc_state != RXS_RDSTAT) && (rxc->rxc_state != RXS_RDERR))
+               goto error;
+       switch (rxc->rxc_state) {
+
+       /*
+        * Incomplete commands.  Perform next step
+        * and return.  Note that b_active is set on
+        * entrance and, therefore, also on exit.
+        */
+       case RXS_READ:
+               if (rxaddr->rxdb & RXES_DDMARK)
+                       sc->sc_flags |= RXF_DDMK;
+               else
+                       sc->sc_flags &= ~RXF_DDMK;
+               rxc->rxc_state = RXS_EMPTY;
+               um->um_cmd = RX_EMPTY;
+               (void) ubago(ui);
+               return;
+
+       case RXS_FILL:
+               rxc->rxc_state = RXS_WRITE;
+               if (sc->sc_flags & RXF_USEWDDS) {
+                       rxaddr->rxcs = RX_WDDS | sc->sc_csbits;
+                       sc->sc_flags &= ~RXF_USEWDDS;
+               } else
+                       rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
+               rxmap(bp, &sector, &track);
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = sector;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
+                       ;
+               rxaddr->rxdb = track;
+               return;
+
+       /*
+        * Possibly completed command.
+        */
+       case RXS_RDSTAT:
+               if (bp->b_flags & B_RDSTAT) {
+                       if ((rxaddr->rxdb&RXES_READY) == 0) {
+                               bp->b_flags |= B_ERROR;
+                               bp->b_error = ENODEV;
+                       } else {
+                               sc->sc_csbits |= rxaddr->rxdb&RXES_DBLDEN ?
+                                       RX_DDEN : RX_SDEN;
+                       }
+                       goto rdone;
+               }
+               if (rxaddr->rxdb&RXES_READY)
+                       goto rderr;
+               bp->b_error = ENODEV;
+               bp->b_flags |= B_ERROR;
+               goto done;
+
+       /*
+        * Command completed.
+        */
+       case RXS_EMPTY:
+       case RXS_WRITE: 
+               goto done;
+
+       case RXS_FORMAT:
+               goto rdone;
+
+       case RXS_RDERR:
+               bp = savebp;
+               rxmap(bp, &sector, &track);
+               printf("rx%d: hard error, trk %d psec %d ",
+                       unit, track, sector);
+               printf("cs=%b, db=%b, err=", MASKREG(er->rxcs), 
+                       RXCS_BITS, MASKREG(er->rxdb), RXES_BITS);
+               printf("%x, %x, %x, %x\n", MASKREG(er->rxxt[0]),
+                       MASKREG(er->rxxt[1]), MASKREG(er->rxxt[2]), 
+                       MASKREG(er->rxxt[3]));
+               goto done;
+
+       default:
+               printf("rx%d: state %d (reset)\n", unit, rxc->rxc_state);
+               rxreset(um->um_ubanum);
+               return;
+       }
+error:
+       /*
+        * In case of an error:
+        *  (a) Give up now if a format (ioctl) was in progress, if a
+        *        density error was detected, or if the drive went offline
+        *  (b) Retry up to nine times if a CRC (data) error was detected,
+        *        then give up if the error persists.
+        *  (c) In all other cases, reinitialize the drive and try the
+        *        operation once more before giving up.
+        */
+       if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR))
+               goto giveup;
+       if (rxaddr->rxdb & RXES_CRCERR) {
+               if (++um->um_tab.b_errcnt >= 10)
+                       goto giveup;
+               goto retry;
+       }
+       um->um_tab.b_errcnt += 9;
+       if (um->um_tab.b_errcnt >= 10)
+               goto giveup;
+       rxaddr->rxcs = RX_INIT;
+       /* no way to get an interrupt for "init done", so just wait */
+       while ((rxaddr->rxcs&RX_DONE) == 0)
+               ;
+       /* if someone opened the drive: give up */
+       if ((rxaddr->rxdb&RXES_READY) == 0)
+               goto giveup;
+retry:
+       /*
+        * In case we already have UNIBUS resources, give
+        * them back since we reallocate things in rxstart.
+        */
+       if (um->um_ubinfo)
+               ubadone(um);
+       um->um_tab.b_active = 0;
+       rxstart(um);
+       return;
+
+giveup:
+       /*
+        * Hard I/O error --
+        * ALL errors are considered fatal and will abort the
+        * transfer and purge the i/o request queue
+        */
+       sc->sc_flags |= RXF_BAD;
+       sc->sc_resid = 0;       /* make sure the transfer is terminated */
+       rxc->rxc_state = RXS_RDSTAT;
+       rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
+       return;
+
+rderr:
+       /*
+        * A hard error (other than not ready) has occurred.
+        * Read the extended error status information.
+        * Before doing this, save the current CS and DB register values,
+        * because the read error status operation may modify them.
+        * Insert buffer with request at the head of the queue.
+        */
+       bp->b_error = EIO;
+       bp->b_flags |= B_ERROR;
+       if (um->um_ubinfo)
+               ubadone(um);
+       savebp = bp;
+       er->rxcs = rxaddr->rxcs;
+       er->rxdb = rxaddr->rxdb;
+       bp = &erxbuf[unit];
+       bp->b_un.b_addr = (caddr_t)er->rxxt;
+       bp->b_bcount = sizeof (er->rxxt);
+       bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
+       if (dp->b_actf == NULL)
+               dp->b_actl = bp;
+       bp->b_forw = dp->b_actf;
+       dp->b_actf = bp;
+       rxc->rxc_state = RXS_RDERR;
+       um->um_cmd = RX_RDERR;
+       (void) ubago(ui);
+       return;
+
+done:
+       ubadone(um);
+rdone:
+       um->um_tab.b_active = 0;
+       um->um_tab.b_errcnt = 0;
+       if ((sc->sc_resid -= NBPS) > 0) {
+               bp->b_un.b_addr += NBPS;
+               rxstart(um);
+               return;
+       }
+       bp->b_un.b_addr = sc->sc_uaddr;
+       bp->b_resid = 0;
+       bp->b_bcount = sc->sc_bcnt;
+       dp->b_actf = bp->av_forw;
+       iodone(bp);
+       sc->sc_offset = 0;
+       rxc->rxc_state = RXS_IDLE;
+       um->um_tab.b_actf = dp->b_forw;
+       dp->b_active = 0;
+       dp->b_errcnt = 0;
+#ifdef RXDEBUG
+       printf(".. bp=%x, new=%x\n", bp, dp->b_actf);
+#endif
+       /*
+        * If this unit has more work to do,
+        * start it up right away
+        */
+       if (dp->b_actf)
+               rxustart(ui);
+
+       rxstart(um);
+}
+
+/*ARGSUSED*/
+
+rxwatch()
+{
+       register struct uba_device *ui;
+       register struct uba_ctlr *um;
+       register struct rx_softc *sc;
+       struct rx_ctlr *rxc;
+       int i, dopen = 0;
+
+       for (i=0; i<NRX; i++) {
+               ui = rxdinfo[i];
+               if (ui == 0 || ui->ui_alive == 0)
+                       continue;
+               sc = &rx_softc[i];
+               if ((sc->sc_open == 0) && (rxutab[i].b_active == 0)) {
+                       sc->sc_csbits = 0;
+                       continue;
+               }
+               dopen++;
+               um = ui->ui_mi;
+               rxc = &rx_ctlr[um->um_ctlr];
+               if (++rxc->rxc_tocnt >= RX_MAXTIMEOUT) {
+                       rxc->rxc_tocnt = 0;
+                       if (um->um_tab.b_active) {      
+                               printf("rx%d: timeout\n", i);/* for debugging */
+                               rxintr(um->um_ctlr);
+                       }
+               }
+       }
+       if (dopen)
+               timeout(rxwatch, (caddr_t)0, hz);
+       else
+               rxwstart = 0;
+}
+
+rxreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct rxdevice *rxaddr;
+       register int ctlr;
+
+       for (ctlr = 0; ctlr < NFX; ctlr++) {
+               if ((um = rxminfo[ctlr]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               if (um->um_ubinfo)
+                       um->um_ubinfo = 0;
+               rx_ctlr[ctlr].rxc_state = RXS_IDLE;
+               rxaddr = (struct rxdevice *)um->um_addr;
+               rxaddr->rxcs = RX_INIT;
+               while ((rxaddr->rxcs&RX_DONE) == 0)
+                       ;
+               rxstart(um);
+       }
+}
+
+rxread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int unit = RXUNIT(dev);
+       struct rx_softc *sc = &rx_softc[unit];
+
+       if (uio->uio_offset + uio->uio_resid > RXSIZE)
+               return (ENXIO);
+       if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
+               return (ENXIO);
+       sc->sc_offset = uio->uio_offset % DEV_BSIZE;
+       return (physio(rxstrategy, &rrxbuf[unit], dev, B_READ, minphys, uio));
+}
+
+rxwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int unit = RXUNIT(dev);
+       struct rx_softc *sc = &rx_softc[unit];
+
+       if (uio->uio_offset + uio->uio_resid > RXSIZE)
+               return (ENXIO);
+       if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
+               return (ENXIO);
+       sc->sc_offset = uio->uio_offset % DEV_BSIZE;
+       return(physio(rxstrategy, &rrxbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Control routine:
+ * processes four kinds of requests:
+ *
+ *     (1) Set density (i.e., format the diskette) according to 
+ *               that specified data parameter
+ *     (2) Arrange for the next sector to be written with a deleted-
+ *               data mark.
+ *     (3) Report whether the last sector read had a deleted-data mark
+ *     (4) Report the density of the diskette in the indicated drive
+ *         (since the density it automatically determined by the driver,
+ *          this is the only way to let an application program know the
+ *          density)
+ *
+ * Requests relating to deleted-data marks can be handled right here.
+ * A "set density" (format) request, however, must additionally be 
+ * processed through "rxstart", just like a read or write request.
+ */
+
+/*ARGSUSED3*/
+rxioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{   
+       int unit = RXUNIT(dev);
+       struct rx_softc *sc = &rx_softc[unit];
+
+       switch (cmd) {
+
+       case RXIOC_FORMAT:
+               if ((flag&FWRITE) == 0)
+                       return (EBADF);
+               if (sc->sc_open > 1)
+                       return (EBUSY);
+               if (*(int *)data)
+                       sc->sc_csbits |= RX_DDEN;
+               else
+                       sc->sc_csbits &= ~RX_DDEN;
+               return (rxformat(dev));
+
+       case RXIOC_WDDS:
+               sc->sc_flags |= RXF_USEWDDS;
+               return (0);
+
+       case RXIOC_RDDSMK:
+               *(int *)data = sc->sc_flags & RXF_DDMK;
+               return (0);
+
+       case RXIOC_GDENS:
+               *(int *)data = sc->sc_csbits & RX_DDEN;
+               return (0);
+       }
+       return (ENXIO);
+}
+
+/*
+ * Initiate a format command.
+ */
+rxformat(dev)
+       dev_t dev;
+{
+       int unit = RXUNIT(dev);
+       struct buf *bp;
+       struct rx_softc *sc = &rx_softc[unit];
+       int s, error = 0;
+
+       bp = &rrxbuf[unit];
+       bp->b_flags = B_BUSY | B_CTRL;
+       sc->sc_flags = RXF_FORMAT | RXF_LOCK;
+       bp->b_dev = dev;
+       bp->b_error = 0;
+       bp->b_blkno = 0;
+       rxstrategy(bp);
+       iowait(bp);
+       if (bp->b_flags & B_ERROR)
+               error = bp->b_error;
+       bp->b_flags &= ~B_BUSY;
+       sc->sc_flags &= ~RXF_LOCK;
+       return (error);
+}
+
+/*
+ * A permanent hard error condition has occured,
+ * purge the buffer queue
+ */
+rxpurge(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+
+       dp = um->um_tab.b_actf;
+       while (dp->b_actf) {
+               dp->b_errcnt++;
+               bp = dp->b_actf;
+               bp->b_error = EIO;
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               dp->b_actf = bp->av_forw;
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxuba/rxreg.h b/usr/src/sys/vaxuba/rxreg.h
new file mode 100644 (file)
index 0000000..fc42b06
--- /dev/null
@@ -0,0 +1,94 @@
+/*     rxreg.h 6.1     83/07/29        */
+
+#include <sys/ioctl.h>
+/*
+ * RX02 registers
+ */
+struct rxdevice {
+       short   rxcs;           /* control/status register */
+       short   rxdb;           /* data buffer register */
+};
+
+/*
+ * RX211 Command and Status Register (RX2CS)
+ */
+#define        RX_DRV0         0x0000  /* select drive 0 */
+#define        RX_DRV1         0x0010  /* select drive 1 */
+#define        RX_DONE         0x0020  /* function complete */
+#define        RX_INTR         0x0040  /* interrupt enable */
+#define        RX_TREQ         0x0080  /* transfer request (data only) */
+#define        RX_SDEN         0x0000  /* single density */
+#define        RX_DDEN         0x0100  /* double density */
+#define        RX_EXT          0x3000  /* extended address bits */
+#define        RX_INIT         0x4000  /* initialize RX211 interface */
+#define        RX_ERR          0x8000  /* general error bit */
+
+/*
+ * RX211 control function bits (0-3 of RX2CS)
+ */
+#define        RX_FILL         0x0001  /* fill the buffer */
+#define        RX_EMPTY        0x0003  /* empty the buffer */
+#define        RX_WRITE        0x0005  /* write the buffer to disk */
+#define        RX_READ         0x0007  /* read a disk sector to the buffer */
+#define        RX_FORMAT       0x0009  /* set the media density (format) */
+#define        RX_RDSTAT       0x000b  /* read the disk status */
+#define        RX_WDDS         0x000d  /* write a deleted-data sector */
+#define        RX_RDERR        0x000f  /* read the error registers */
+
+#define        RXCS_BITS \
+"\20\20RX_ERR\17RX_INIT\11RX_DDEN\10RX_TREQ\7RX_IE\6RX_DONE\5RX_DRV1"
+
+/*
+ * RX211 Error and Status Register (RX2ES) --
+ * information is located in RX2DB after completion of function.
+ * The READY bit's value is available only after a "read status".
+ */
+#define        RXES_CRCERR     0x0001  /* CRC error (data read error) */
+#define        RXES_IDONE      0x0004  /* reinitialization complete */
+#define RXES_DENERR    0x0010  /* density error */
+#define        RXES_DBLDEN     0x0020  /* set if double density */
+#define        RXES_DDMARK     0x0040  /* deleted-data mark */
+#define        RXES_READY      0x0080  /* drive is ready */
+
+#define        RXES_BITS \
+"\20\14RXES_NXM\13RXES_WCOF\11RXES_DRV1\10RXES_RDY\7RXES_DDMK\6RXES_DDEN\5\
+RXES_DNER\4RXES_ACLO\3RXES_ID\1RXES_CRC"
+
+/* 
+ * Ioctl commands, move to dkio.h later
+ */
+#define RXIOC_FORMAT   _IOW(d, 1, int) /* format the disk */
+#define RXIOC_WDDS     _IOW(d, 2, int) /* write `deleted data' mark */
+                                       /* on next sector */
+#define RXIOC_RDDSMK   _IOR(d, 3, int) /* did last read sector contain */
+                                       /* `deleted data'?*/
+#define        RXIOC_GDENS     _IOR(d, 4, int) /* return density of current disk */
+
+#ifdef RXDEFERR
+/*
+ * Table of values for definitive error code (rxxt[0] & 0xff)
+ */
+struct rxdeferr {
+       short   errval;
+       char    *errmsg;
+} rxdeferr[] = {
+       { 0010, "Can't find home on drive 0" },
+       { 0020, "Can't find home on drive 1" },
+       { 0040, "Bad track number requested" },
+       { 0050, "Home found too soon" },
+       { 0070, "Can't find desired sector" },
+       { 0110, "No SEP clock seen" },
+       { 0120, "No preamble found" },
+       { 0130, "Preamble, but no ID mark" },
+       { 0140, "Header CRC error"},
+       { 0150, "Track addr wrong in header" },
+       { 0160, "Too many tries for ID AM" },
+       { 0170, "No data AM found" },
+       { 0200, "Data CRC error" },
+       { 0220, "Maintenance test failure" },
+       { 0230, "Word count overflow" },
+       { 0240, "Density error" },
+       { 0250, "Set-density protocol bad" },
+       { 0,    "Undefined error code" }
+};
+#endif
diff --git a/usr/src/sys/vaxuba/tmreg.h b/usr/src/sys/vaxuba/tmreg.h
new file mode 100644 (file)
index 0000000..9a3f695
--- /dev/null
@@ -0,0 +1,63 @@
+/*     tmreg.h 6.1     83/07/29        */
+
+/*
+ * TM11 controller registers
+ */
+struct tmdevice {
+       u_short tmer;           /* error register, per drive */
+       u_short tmcs;           /* control-status register */
+       short   tmbc;           /* byte/frame count */
+       u_short tmba;           /* address */
+       short   tmdb;           /* data buffer */
+       short   tmrd;           /* read lines */
+       short   tmmr;           /* maintenance register */
+};
+
+#define        b_repcnt  b_bcount
+#define        b_command b_resid
+
+/* bits in tmcs */
+#define        TM_GO           0000001
+#define        TM_OFFL         0000000         /* offline */
+#define        TM_RCOM         0000002         /* read */
+#define        TM_WCOM         0000004         /* write */
+#define        TM_WEOF         0000006         /* write-eof */
+#define        TM_SFORW        0000010         /* space forward */
+#define        TM_SREV         0000012         /* space backwards */
+#define        TM_WIRG         0000014         /* write with xtra interrecord gap */
+#define        TM_REW          0000016         /* rewind */
+#define        TM_SENSE        TM_IE           /* sense (internal to driver) */
+
+#define        tmreverseop(cmd)                ((cmd)==TM_SREV || (cmd)==TM_REW)
+
+/* TM_SNS is a pseudo-op used to get tape status */
+#define        TM_IE           0000100         /* interrupt enable */
+#define        TM_CUR          0000200         /* control unit is ready */
+#define        TM_DCLR         0010000         /* drive clear */
+#define        TM_D800         0060000         /* select 800 bpi density */
+#define        TM_ERR          0100000         /* drive error summary */
+
+/* bits in tmer */
+#define        TMER_ILC        0100000         /* illegal command */
+#define        TMER_EOF        0040000         /* end of file */
+#define        TMER_CRE        0020000         /* cyclic redundancy error */
+#define        TMER_PAE        0010000         /* parity error */
+#define        TMER_BGL        0004000         /* bus grant late */
+#define        TMER_EOT        0002000         /* at end of tape */
+#define        TMER_RLE        0001000         /* record length error */
+#define        TMER_BTE        0000400         /* bad tape error */
+#define        TMER_NXM        0000200         /* non-existant memory */
+#define        TMER_SELR       0000100         /* tape unit properly selected */
+#define        TMER_BOT        0000040         /* at beginning of tape */
+#define        TMER_CH7        0000020         /* 7 channel tape */
+#define        TMER_SDWN       0000010         /* gap settling down */
+#define        TMER_WRL        0000004         /* tape unit write protected */
+#define        TMER_RWS        0000002         /* tape unit rewinding */
+#define        TMER_TUR        0000001         /* tape unit ready */
+
+#define        TMER_BITS       \
+"\10\20ILC\17EOF\16CRE\15PAE\14BGL\13EOT\12RLE\11BTE\10NXM\
+\7SELR\6BOT\5CH7\4SDWN\3WRL\2RWS\1TUR"
+
+#define        TMER_HARD       (TMER_ILC|TMER_EOT)
+#define        TMER_SOFT       (TMER_CRE|TMER_PAE|TMER_BGL|TMER_RLE|TMER_BTE|TMER_NXM)
diff --git a/usr/src/sys/vaxuba/ts.c b/usr/src/sys/vaxuba/ts.c
new file mode 100644 (file)
index 0000000..5832336
--- /dev/null
@@ -0,0 +1,917 @@
+/*     ts.c    6.1     83/07/29        */
+
+#include "ts.h"
+#if NTS > 0
+/*
+ * TS11 tape driver
+ *
+ * TODO:
+ *     write dump code
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/dir.h"
+#include "../h/conf.h"
+#include "../h/user.h"
+#include "../h/file.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/ioctl.h"
+#include "../h/mtio.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/tsreg.h"
+
+/*
+ * There is a ctsbuf per tape controller.
+ * It is used as the token to pass to the internal routines
+ * to execute tape ioctls.
+ * In particular, when the tape is rewinding on close we release
+ * the user process but any further attempts to use the tape drive
+ * before the rewind completes will hang waiting for ctsbuf.
+ */
+struct buf     ctsbuf[NTS];
+
+/*
+ * Raw tape operations use rtsbuf.  The driver
+ * notices when rtsbuf is being used and allows the user
+ * program to continue after errors and read records
+ * not of the standard length (BSIZE).
+ */
+struct buf     rtsbuf[NTS];
+
+/*
+ * Driver unibus interface routines and variables.
+ */
+int    tsprobe(), tsslave(), tsattach(), tsdgo(), tsintr();
+struct uba_ctlr *tsminfo[NTS];
+struct uba_device *tsdinfo[NTS];
+struct buf     tsutab[NTS];
+u_short        tsstd[] = { 0772520, 0 };
+/*** PROBABLY DON'T NEED ALL THESE SINCE CONTROLLER == DRIVE ***/
+struct uba_driver zsdriver =
+ { tsprobe, tsslave, tsattach, tsdgo, tsstd, "ts", tsdinfo, "zs", tsminfo, 0 };
+
+/* bits in minor device */
+#define        TSUNIT(dev)     (minor(dev)&03)
+#define        T_NOREWIND      04
+
+#define        INF     (daddr_t)1000000L
+
+/*
+ * Software state per tape transport.
+ * Also contains hardware state in message packets.
+ *
+ * 1. A tape drive is a unique-open device; we refuse opens when it is already.
+ * 2. We keep track of the current position on a block tape and seek
+ *    before operations by forward/back spacing if necessary.
+ * 3. We remember if the last operation was a write on a tape, so if a tape
+ *    is open read write and the last thing done is a write we can
+ *    write a standard end of tape mark (two eofs).
+ * 4. We remember the status registers after the last command, using
+ *    then internally and returning them to the SENSE ioctl.
+ */
+struct ts_softc {
+       char    sc_openf;       /* lock against multiple opens */
+       char    sc_lastiow;     /* last op was a write */
+       short   sc_resid;       /* copy of last bc */
+       daddr_t sc_blkno;       /* block number, for block device tape */
+       daddr_t sc_nxrec;       /* position of end of tape, if known */
+       struct  ts_cmd sc_cmd;  /* the command packet */
+       struct  ts_sts sc_sts;  /* status packet, for returned status */
+       struct  ts_char sc_char; /* characteristics packet */
+       struct  ts_softc *sc_ubaddr; /* Unibus address of ts_softc structure */
+       u_short sc_uba;         /* Unibus addr of cmd pkt for tsdb */
+       short   sc_mapped;      /* is ts_sfotc mapped in Unibus space? */
+} ts_softc[NTS];
+
+/*
+ * States for um->um_tab.b_active, the per controller state flag.
+ * This is used to sequence control in the driver.
+ */
+#define        SSEEK   1               /* seeking */
+#define        SIO     2               /* doing seq i/o */
+#define        SCOM    3               /* sending control command */
+#define        SREW    4               /* sending a drive rewind */
+
+/*
+ * Determine if there is a controller for
+ * a ts at address reg.  Our goal is to make the
+ * device interrupt.
+ */
+/*ARGSUSED*/
+tsprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* must be r11,r10; value-result */
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       tsintr(0);
+#endif
+       ((struct tsdevice *)reg)->tssr = 0;
+       DELAY(100);
+       if ((((struct tsdevice *)reg)->tssr & TS_NBA) == 0)
+               return(0);
+       /* IT'S TOO HARD TO MAKE THIS THING INTERRUPT JUST TO FIND ITS VECTOR */
+       cvec = ((unsigned)reg) & 07 ? 0260 : 0224;
+       br = 0x15;
+       return (sizeof (struct tsdevice));
+}
+
+/*
+ * TS11 only supports one drive per controller;
+ * check for ui_slave == 0.
+ *
+ * DO WE REALLY NEED THIS ROUTINE???
+ */
+/*ARGSUSED*/
+tsslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+
+       if (ui->ui_slave)       /* non-zero slave not allowed */
+               return(0);
+       return (1);
+}
+
+/*
+ * Record attachment of the unit to the controller.
+ *
+ * SHOULD THIS ROUTINE DO ANYTHING???
+ */
+/*ARGSUSED*/
+tsattach(ui)
+       struct uba_device *ui;
+{
+
+}
+
+/*
+ * Open the device.  Tapes are unique open
+ * devices, so we refuse if it is already open.
+ * We also check that a tape is available, and
+ * don't block waiting here; if you want to wait
+ * for a tape you should timeout in user code.
+ */
+tsopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int tsunit;
+       register struct uba_device *ui;
+       register struct ts_softc *sc;
+
+       tsunit = TSUNIT(dev);
+       if (tsunit>=NTS || (sc = &ts_softc[tsunit])->sc_openf ||
+           (ui = tsdinfo[tsunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       if (tsinit(tsunit))
+               return (ENXIO);
+       tscommand(dev, TS_SENSE, 1);
+       if ((sc->sc_sts.s_xs0&TS_ONL) == 0) {
+               uprintf("ts%d: not online\n", tsunit);
+               return (EIO);
+       }
+       if ((flag&(FREAD|FWRITE)) == FWRITE && (sc->sc_sts.s_xs0&TS_WLK)) {
+               uprintf("ts%d: no write ring\n", tsunit);
+               return (EIO);
+       }
+       sc->sc_openf = 1;
+       sc->sc_blkno = (daddr_t)0;
+       sc->sc_nxrec = INF;
+       sc->sc_lastiow = 0;
+       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.
+ * Make the tape available to others.
+ */
+tsclose(dev, flag)
+       register dev_t dev;
+       register flag;
+{
+       register struct ts_softc *sc = &ts_softc[TSUNIT(dev)];
+
+       if (flag == FWRITE || (flag&FWRITE) && sc->sc_lastiow) {
+               tscommand(dev, TS_WEOF, 1);
+               tscommand(dev, TS_WEOF, 1);
+               tscommand(dev, TS_SREV, 1);
+       }
+       if ((minor(dev)&T_NOREWIND) == 0)
+               /*
+                * 0 count means don't hang waiting for rewind complete
+                * rather ctsbuf stays busy until the operation completes
+                * preventing further opens from completing by
+                * preventing a TS_SENSE from completing.
+                */
+               tscommand(dev, TS_REW, 0);
+       sc->sc_openf = 0;
+}
+
+/*
+ * Initialize the TS11.  Set up Unibus mapping for command
+ * packets and set device characteristics.
+ */
+tsinit(unit)
+       register int unit;
+{
+       register struct ts_softc *sc = &ts_softc[unit];
+       register struct uba_ctlr *um = tsminfo[unit];
+       register struct tsdevice *addr = (struct tsdevice *)um->um_addr;
+       register int i;
+
+       /*
+        * Map the command and message packets into Unibus
+        * address space.  We do all the command and message
+        * packets at once to minimize the amount of Unibus
+        * mapping necessary.
+        */
+       if (sc->sc_mapped == 0) {
+               ctsbuf[unit].b_un.b_addr = (caddr_t)sc;
+               ctsbuf[unit].b_bcount = sizeof(*sc);
+               i = ubasetup(um->um_ubanum, &ctsbuf[unit], 0);
+               i &= 0777777;
+               sc->sc_ubaddr = (struct ts_softc *)i;
+               sc->sc_mapped++;
+       }
+       /*
+        * Now initialize the TS11 controller.
+        * Set the characteristics.
+        */
+       if (addr->tssr & (TS_NBA|TS_OFL)) {
+               addr->tssr = 0;         /* subsystem initialize */
+               tswait(addr);
+               i = (int)&sc->sc_ubaddr->sc_cmd;        /* Unibus addr of cmd */
+               sc->sc_uba = (u_short)(i + ((i>>16)&3));
+               sc->sc_char.char_addr = (int)&sc->sc_ubaddr->sc_sts;
+               sc->sc_char.char_size = sizeof(struct ts_sts);
+               sc->sc_char.char_mode = TS_ESS;
+               sc->sc_cmd.c_cmd = TS_ACK | TS_SETCHR;
+               i = (int)&sc->sc_ubaddr->sc_char;
+               sc->sc_cmd.c_loba = i;
+               sc->sc_cmd.c_hiba = (i>>16)&3;
+               sc->sc_cmd.c_size = sizeof(struct ts_char);
+               addr->tsdb = sc->sc_uba;
+               tswait(addr);
+               if (addr->tssr & TS_NBA)
+                       return(1);
+       }
+       return(0);
+}
+
+/*
+ * Execute a command on the tape drive
+ * a specified number of times.
+ */
+tscommand(dev, com, count)
+       dev_t dev;
+       int com, count;
+{
+       register struct buf *bp;
+       register int s;
+
+       bp = &ctsbuf[TSUNIT(dev)];
+       s = spl5();
+       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_repcnt == 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);
+       bp->b_dev = dev;
+       bp->b_repcnt = count;
+       bp->b_command = com;
+       bp->b_blkno = 0;
+       tsstrategy(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;
+}
+
+/*
+ * Queue a tape operation.
+ */
+tsstrategy(bp)
+       register struct buf *bp;
+{
+       int tsunit = TSUNIT(bp->b_dev);
+       register struct uba_ctlr *um;
+       register struct buf *dp;
+       register int s;
+
+       /*
+        * Put transfer at end of controller queue
+        */
+       bp->av_forw = NULL;
+       um = tsdinfo[tsunit]->ui_mi;
+       s = spl5();
+       dp = &tsutab[tsunit];
+       if (dp->b_actf == NULL)
+               dp->b_actf = bp;
+       else
+               dp->b_actl->av_forw = bp;
+       dp->b_actl = bp;
+       um->um_tab.b_actf = um->um_tab.b_actl = dp;
+       /*
+        * If the controller is not busy, get
+        * it going.
+        */
+       if (um->um_tab.b_active == 0)
+               tsstart(um);
+       splx(s);
+}
+
+/*
+ * Start activity on a ts controller.
+ */
+tsstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp;
+       register struct tsdevice *addr = (struct tsdevice *)um->um_addr;
+       register struct ts_softc *sc;
+       register struct ts_cmd *tc;
+       register struct uba_device *ui;
+       int tsunit, cmd;
+       daddr_t blkno;
+
+       /*
+        * Start the controller if there is something for it to do.
+        */
+loop:
+       if ((bp = um->um_tab.b_actf->b_actf) == NULL)
+               return;
+       tsunit = TSUNIT(bp->b_dev);
+       ui = tsdinfo[tsunit];
+       sc = &ts_softc[tsunit];
+       tc = &sc->sc_cmd;
+       /*
+        * Default is that last command was NOT a write command;
+        * if we do a write command we will notice this in tsintr().
+        */
+       sc->sc_lastiow = 0;
+       if (sc->sc_openf < 0 || (addr->tssr&TS_OFL)) {
+               /*
+                * Have had a hard error on a non-raw tape
+                * or the tape unit is now unavailable
+                * (e.g. taken off line).
+                */
+               bp->b_flags |= B_ERROR;
+               goto next;
+       }
+       if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) {
+               /*
+                * Execute control operation with the specified count.
+                */
+               um->um_tab.b_active =
+                   bp->b_command == TS_REW ? SREW : SCOM;
+               tc->c_repcnt = bp->b_repcnt;
+               goto dobpcmd;
+       }
+       /*
+        * The following checks handle boundary cases for operation
+        * on non-raw tapes.  On raw tapes the initialization of
+        * sc->sc_nxrec by tsphys causes them to be skipped normally
+        * (except in the case of retries).
+        */
+       if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
+               /*
+                * Can't read past known end-of-file.
+                */
+               bp->b_flags |= B_ERROR;
+               bp->b_error = ENXIO;
+               goto next;
+       }
+       if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
+           bp->b_flags&B_READ) {
+               /*
+                * Reading at end of file returns 0 bytes.
+                */
+               bp->b_resid = bp->b_bcount;
+               clrbuf(bp);
+               goto next;
+       }
+       if ((bp->b_flags&B_READ) == 0)
+               /*
+                * Writing sets EOF
+                */
+               sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
+       /*
+        * If the data transfer command is in the correct place,
+        * set up all the registers except the csr, and give
+        * control over to the UNIBUS adapter routines, to
+        * wait for resources to start the i/o.
+        */
+       if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
+               tc->c_size = bp->b_bcount;
+               if ((bp->b_flags&B_READ) == 0)
+                       cmd = TS_WCOM;
+               else
+                       cmd = TS_RCOM;
+               if (um->um_tab.b_errcnt)
+                       cmd |= TS_RETRY;
+               um->um_tab.b_active = SIO;
+               tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd;
+               (void) ubago(ui);
+               return;
+       }
+       /*
+        * Tape positioned incorrectly;
+        * set to seek forwards or backwards to the correct spot.
+        * This happens for raw tapes only on error retries.
+        */
+       um->um_tab.b_active = SSEEK;
+       if (blkno < bdbtofsb(bp->b_blkno)) {
+               bp->b_command = TS_SFORW;
+               tc->c_repcnt = bdbtofsb(bp->b_blkno) - blkno;
+       } else {
+               bp->b_command = TS_SREV;
+               tc->c_repcnt = blkno - bdbtofsb(bp->b_blkno);
+       }
+dobpcmd:
+       /*
+        * Do the command in bp.
+        */
+       tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command;
+       addr->tsdb = sc->sc_uba;
+       return;
+
+next:
+       /*
+        * Done with this operation due to error or
+        * the fact that it doesn't do anything.
+        * Release UBA resources (if any), dequeue
+        * the transfer and continue processing this slave.
+        */
+       if (um->um_ubinfo)
+               ubadone(um);
+       um->um_tab.b_errcnt = 0;
+       um->um_tab.b_actf->b_actf = bp->av_forw;
+       iodone(bp);
+       goto loop;
+}
+
+/*
+ * The UNIBUS resources we needed have been
+ * allocated to us; start the device.
+ */
+tsdgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct tsdevice *addr = (struct tsdevice *)um->um_addr;
+       register struct ts_softc *sc = &ts_softc[um->um_ctlr];
+       register int i;
+
+       i = um->um_ubinfo & 0777777;
+       sc->sc_cmd.c_loba = i;
+       sc->sc_cmd.c_hiba = (i>>16)&3;
+       addr->tsdb = sc->sc_uba;
+}
+
+/*
+ * Ts interrupt routine.
+ */
+/*ARGSUSED*/
+tsintr(ts11)
+       int ts11;
+{
+       register struct buf *bp;
+       register struct uba_ctlr *um = tsminfo[ts11];
+       register struct tsdevice *addr;
+       register struct ts_softc *sc;
+       int tsunit;
+       register state;
+
+       if ((bp = um->um_tab.b_actf->b_actf) == NULL)
+               return;
+       tsunit = TSUNIT(bp->b_dev);
+       addr = (struct tsdevice *)tsdinfo[tsunit]->ui_addr;
+       /*
+        * If last command was a rewind, and tape is still
+        * rewinding, wait for the rewind complete interrupt.
+        *
+        * SHOULD NEVER GET AN INTERRUPT IN THIS STATE.
+        */
+       if (um->um_tab.b_active == SREW) {
+               um->um_tab.b_active = SCOM;
+               if ((addr->tssr&TS_SSR) == 0)
+                       return;
+       }
+       /*
+        * An operation completed... record status
+        */
+       sc = &ts_softc[tsunit];
+       if ((bp->b_flags & B_READ) == 0)
+               sc->sc_lastiow = 1;
+       state = um->um_tab.b_active;
+       um->um_tab.b_active = 0;
+       /*
+        * Check for errors.
+        */
+       if (addr->tssr&TS_SC) {
+               switch (addr->tssr & TS_TC) {
+               case TS_UNREC:          /* unrecoverable */
+               case TS_FATAL:          /* fatal error */
+               case TS_ATTN:           /* attention (shouldn't happen) */
+               case TS_RECNM:          /* recoverable, no motion */
+                       break;
+
+               case TS_SUCC:           /* success termination */
+                       printf("ts%d: success\n", TSUNIT(minor(bp->b_dev)));
+                       goto ignoreerr;
+
+               case TS_ALERT:          /* tape status alert */
+                       /*
+                        * If we hit the end of the tape file,
+                        * update our position.
+                        */
+                       if (sc->sc_sts.s_xs0 & (TS_TMK|TS_EOT)) {
+                               tsseteof(bp);           /* set blkno and nxrec */
+                               state = SCOM;           /* force completion */
+                               /*
+                                * Stuff bc so it will be unstuffed correctly
+                                * later to get resid.
+                                */
+                               sc->sc_sts.s_rbpcr = bp->b_bcount;
+                               goto opdone;
+                       }
+                       /*
+                        * If we were reading raw tape and the record was too long
+                        * or too short, then we don't consider this an error.
+                        */
+                       if (bp == &rtsbuf[TSUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
+                           sc->sc_sts.s_xs0&(TS_RLS|TS_RLL))
+                               goto ignoreerr;
+               case TS_RECOV:          /* recoverable, tape moved */
+                       /*
+                        * If this was an i/o operation retry up to 8 times.
+                        */
+                       if (state==SIO) {
+                               if (++um->um_tab.b_errcnt < 7) {
+                                       ubadone(um);
+                                       goto opcont;
+                               } else
+                                       sc->sc_blkno++;
+                       } else {
+                               /*
+                                * Non-i/o errors on non-raw tape
+                                * cause it to close.
+                                */
+                               if (sc->sc_openf>0 && bp != &rtsbuf[TSUNIT(bp->b_dev)])
+                                       sc->sc_openf = -1;
+                       }
+                       break;
+
+               case TS_REJECT:         /* function reject */
+                       if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE)
+                               printf("ts%d: write locked\n", TSUNIT(bp->b_dev));
+                       if ((sc->sc_sts.s_xs0 & TS_ONL) == 0)
+                               printf("ts%d: offline\n", TSUNIT(bp->b_dev));
+                       break;
+               }
+               /*
+                * Couldn't recover error
+                */
+               printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev),
+                   bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS);
+               if (sc->sc_sts.s_xs1)
+                       printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS);
+               if (sc->sc_sts.s_xs2)
+                       printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS);
+               if (sc->sc_sts.s_xs3)
+                       printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS);
+               printf("\n");
+               bp->b_flags |= B_ERROR;
+               goto opdone;
+       }
+       /*
+        * Advance tape control FSM.
+        */
+ignoreerr:
+       switch (state) {
+
+       case SIO:
+               /*
+                * Read/write increments tape block number
+                */
+               sc->sc_blkno++;
+               goto opdone;
+
+       case SCOM:
+               /*
+                * For forward/backward space record update current position.
+                */
+               if (bp == &ctsbuf[TSUNIT(bp->b_dev)])
+               switch (bp->b_command) {
+
+               case TS_SFORW:
+                       sc->sc_blkno += bp->b_repcnt;
+                       break;
+
+               case TS_SREV:
+                       sc->sc_blkno -= bp->b_repcnt;
+                       break;
+               }
+               goto opdone;
+
+       case SSEEK:
+               sc->sc_blkno = bdbtofsb(bp->b_blkno);
+               goto opcont;
+
+       default:
+               panic("tsintr");
+       }
+opdone:
+       /*
+        * Reset error count and remove
+        * from device queue.
+        */
+       um->um_tab.b_errcnt = 0;
+       um->um_tab.b_actf->b_actf = bp->av_forw;
+       bp->b_resid = sc->sc_sts.s_rbpcr;
+       ubadone(um);
+       iodone(bp);
+       if (um->um_tab.b_actf->b_actf == 0)
+               return;
+opcont:
+       tsstart(um);
+}
+
+tsseteof(bp)
+       register struct buf *bp;
+{
+       register int tsunit = TSUNIT(bp->b_dev);
+       register struct ts_softc *sc = &ts_softc[tsunit];
+
+       if (bp == &ctsbuf[TSUNIT(bp->b_dev)]) {
+               if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
+                       /* reversing */
+                       sc->sc_nxrec = bdbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr;
+                       sc->sc_blkno = sc->sc_nxrec;
+               } else {
+                       /* spacing forward */
+                       sc->sc_blkno = bdbtofsb(bp->b_blkno) + sc->sc_sts.s_rbpcr;
+                       sc->sc_nxrec = sc->sc_blkno - 1;
+               }
+               return;
+       } 
+       /* eof on read */
+       sc->sc_nxrec = bdbtofsb(bp->b_blkno);
+}
+
+tsread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = tsphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_READ, minphys, uio));
+}
+
+tswrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = tsphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(tsstrategy, &rtsbuf[TSUNIT(dev)], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Check that a raw device exists.
+ * If it does, set up sc_blkno and sc_nxrec
+ * so that the tape will appear positioned correctly.
+ */
+tsphys(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int tsunit = TSUNIT(dev);
+       register daddr_t a;
+       register struct ts_softc *sc;
+       register struct uba_device *ui;
+
+       if (tsunit >= NTS || (ui=tsdinfo[tsunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       sc = &ts_softc[tsunit];
+       a = bdbtofsb(uio->uio_offset >> 9);
+       sc->sc_blkno = a;
+       sc->sc_nxrec = a + 1;
+       return (0);
+}
+
+tsreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
+       register struct buf *dp;
+       register ts11;
+
+       for (ts11 = 0; ts11 < NTS; ts11++) {
+               if ((um = tsminfo[ts11]) == 0 || um->um_alive == 0 ||
+                  um->um_ubanum != uban)
+                       continue;
+               printf(" ts%d", ts11);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               if (ts_softc[ts11].sc_openf > 0)
+                       ts_softc[ts11].sc_openf = -1;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               if ((ui = tsdinfo[ts11]) && ui->ui_mi == um && ui->ui_alive) {
+                       dp = &tsutab[ts11];
+                       dp->b_active = 0;
+                       dp->b_forw = 0;
+                       if (um->um_tab.b_actf == NULL)
+                               um->um_tab.b_actf = dp;
+                       else
+                               um->um_tab.b_actl->b_forw = dp;
+                       um->um_tab.b_actl = dp;
+               }
+               (void) tsinit(ts11);
+               tsstart(um);
+       }
+}
+
+/*ARGSUSED*/
+tsioctl(dev, cmd, data, flag)
+       caddr_t data;
+       dev_t dev;
+{
+       int tsunit = TSUNIT(dev);
+       register struct ts_softc *sc = &ts_softc[tsunit];
+       register struct buf *bp = &ctsbuf[TSUNIT(dev)];
+       register callcount;
+       int fcount;
+       struct mtop *mtop;
+       struct mtget *mtget;
+       /* we depend of the values and order of the MT codes here */
+       static tsops[] =
+        {TS_WEOF,TS_SFORWF,TS_SREVF,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE};
+
+       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:
+                       callcount = 1;
+                       fcount = 1;
+                       break;
+
+               default:
+                       return (ENXIO);
+               }
+               if (callcount <= 0 || fcount <= 0)
+                       return (EINVAL);
+               while (--callcount >= 0) {
+                       tscommand(dev, tsops[mtop->mt_op], fcount);
+                       if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
+                           bp->b_resid)
+                               return (EIO);
+                       if ((bp->b_flags&B_ERROR) || sc->sc_sts.s_xs0&TS_BOT)
+                               break;
+               }
+               return (geterror(bp));
+
+       case MTIOCGET:
+               mtget = (struct mtget *)data;
+               mtget->mt_dsreg = 0;
+               mtget->mt_erreg = sc->sc_sts.s_xs0;
+               mtget->mt_resid = sc->sc_resid;
+               mtget->mt_type = MT_ISTS;
+               break;
+
+       default:
+               return (ENXIO);
+       }
+       return (0);
+}
+
+#define        DBSIZE  20
+
+tsdump()
+{
+       register struct uba_device *ui;
+       register struct uba_regs *up;
+       register struct tsdevice *addr;
+       int blk, num;
+       int start;
+
+       start = 0;
+       num = maxfree;
+#define        phys(a,b)       ((b)((int)(a)&0x7fffffff))
+       if (tsdinfo[0] == 0)
+               return (ENXIO);
+       ui = phys(tsdinfo[0], struct uba_device *);
+       up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
+       ubainit(up);
+       DELAY(1000000);
+       addr = (struct tsdevice *)ui->ui_physaddr;
+       addr->tssr = 0;
+       tswait(addr);
+       while (num > 0) {
+               blk = num > DBSIZE ? DBSIZE : num;
+               tsdwrite(start, blk, addr, up);
+               start += blk;
+               num -= blk;
+       }
+       tseof(addr);
+       tseof(addr);
+       tswait(addr);
+       if (addr->tssr&TS_SC)
+               return (EIO);
+       addr->tssr = 0;
+       tswait(addr);
+       return (0);
+}
+
+tsdwrite(dbuf, num, addr, up)
+       register int dbuf, num;
+       register struct tsdevice *addr;
+       struct uba_regs *up;
+{
+       register struct pte *io;
+       register int npf;
+
+       tswait(addr);
+       io = up->uba_map;
+       npf = num+1;
+       while (--npf != 0)
+                *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
+       *(int *)io = 0;
+#ifdef notyet
+       addr->tsbc = -(num*NBPG);
+       addr->tsba = 0;
+       addr->tscs = TS_WCOM | TM_GO;
+#endif
+}
+
+tswait(addr)
+       register struct tsdevice *addr;
+{
+       register s;
+
+       do
+               s = addr->tssr;
+       while ((s & TS_SSR) == 0);
+}
+
+tseof(addr)
+       struct tsdevice *addr;
+{
+
+       tswait(addr);
+#ifdef notyet
+       addr->tscs = TS_WEOF | TM_GO;
+#endif
+}
+#endif
diff --git a/usr/src/sys/vaxuba/tsreg.h b/usr/src/sys/vaxuba/tsreg.h
new file mode 100644 (file)
index 0000000..dfd2972
--- /dev/null
@@ -0,0 +1,160 @@
+/*     tsreg.h 6.1     83/07/29        */
+
+/*
+ * TS11 controller registers
+ */
+struct tsdevice {
+       u_short tsdb;           /* data buffer */
+       u_short tssr;           /* status register */
+};
+
+/* Bits in (unibus) status register */
+#define        TS_SC   0100000         /* special condition (error) */
+#define        TS_UPE  0040000         /* Unibus parity error */
+#define        TS_SPE  0020000         /* serial bus parity error */
+#define        TS_RMR  0010000         /* register modification refused */
+#define        TS_NXM  0004000         /* nonexistant memory */
+#define        TS_NBA  0002000         /* need buffer address */
+#define        TS_XMEM 0001400         /* Unibus xmem bits */
+#define        TS_SSR  0000200         /* subsytem ready */
+#define        TS_OFL  0000100         /* off-line */
+#define        TS_FTC  0000060         /* fatal termination class */
+#define        TS_TC   0000016         /* termination class */
+
+#define        TS_SUCC 000             /* successful termination */
+#define        TS_ATTN 002             /* attention */
+#define        TS_ALERT 004            /* tape status alert */
+#define        TS_REJECT 06            /* function reject */
+#define        TS_RECOV 010            /* recoverable error */
+#define        TS_RECNM 012            /* recoverable error, no tape motion */
+#define        TS_UNREC 014            /* unrecoverable error */
+#define        TS_FATAL 016            /* fatal error */
+
+#define        TSSR_BITS       \
+"\10\20SC\17UPE\16SPE\15RMR\14NXM\13NBA\12A17\11A16\10SSR\
+\7OFL\6FC1\5FC0\4TC2\3TC1\2TC0\1-"
+
+#define        b_repcnt        b_bcount
+#define        b_command       b_resid
+
+/* status message */
+struct ts_sts {
+       u_short s_sts;          /* packet header */
+       u_short s_len;          /* packet length */
+       u_short s_rbpcr;        /* residual frame count */
+       u_short s_xs0;          /* extended status 0 - 3 */
+       u_short s_xs1;
+       u_short s_xs2;
+       u_short s_xs3;
+};
+
+/* Error codes in xstat 0 */
+#define        TS_TMK  0100000         /* tape mark detected */
+#define        TS_RLS  0040000         /* record length short */
+#define        TS_LET  0020000         /* logical end of tape */
+#define        TS_RLL  0010000         /* record length long */
+#define        TS_WLE  0004000         /* write lock error */
+#define        TS_NEF  0002000         /* non-executable function */
+#define        TS_ILC  0001000         /* illegal command */
+#define        TS_ILA  0000400         /* illegal address */
+#define        TS_MOT  0000200         /* capstan is moving */
+#define        TS_ONL  0000100         /* on-line */
+#define        TS_IES  0000040         /* interrupt enable status */
+#define        TS_VCK  0000020         /* volume check */
+#define        TS_PED  0000010         /* phase-encoded drive */
+#define        TS_WLK  0000004         /* write locked */
+#define        TS_BOT  0000002         /* beginning of tape */
+#define        TS_EOT  0000001         /* end of tape */
+
+#define        TSXS0_BITS      \
+"\10\20TMK\17RLS\16LET\15RLL\14WLE\13NEF\12ILC\11ILA\10MOT\
+\7ONL\6IES\5VCK\4PED\3WLK\2BOT\1EOT"
+
+/* Error codes in xstat 1 */
+#define        TS_DLT  0100000         /* data late */
+#define        TS_COR  0020000         /* correctable data */
+#define        TS_CRS  0010000         /* crease detected */
+#define        TS_TIG  0004000         /* trash in the gap */
+#define        TS_DBF  0002000         /* deskew buffer full */
+#define        TS_SCK  0001000         /* speed check */
+#define        TS_IPR  0000200         /* invalid preamble */
+#define        TS_SYN  0000100         /* synchronization failure */
+#define        TS_IPO  0000040         /* invalid postamble */
+#define        TS_IED  0000020         /* invalid end of data */
+#define        TS_POS  0000010         /* postamble short */
+#define        TS_POL  0000004         /* postamble long */
+#define        TS_UNC  0000002         /* uncorrectable data */
+#define        TS_MTE  0000001         /* multitrack error */
+
+#define        TSXS1_BITS      \
+"\10\20DLT\17-\16COR\15CRS\14TIG\13DBF\12SCK\11-\10IPR\
+\7SYN\6IPO\5IED\4POS\3POL\2UNC\1MTE"
+
+/* Error codes in xstat 2 */
+#define        TS_OPM  0100000         /* operation in progress */
+#define        TS_SIP  0040000         /* silo parity error */
+#define        TS_BPE  0020000         /* serial bus parity error */
+#define        TS_CAF  0010000         /* capstan acceleration failure */
+#define        TS_WCF  0002000         /* write card fail */
+#define        TS_DTP  0000400         /* dead track parity */
+#define        TS_DT   0000377         /* dead tracks */
+
+#define        TSXS2_BITS      \
+"\10\20OPM\17SIP\16BPE\15CAF\14-\13WCF\12-\11DTP"
+
+/* Error codes in xstat 3 */
+#define        TS_MEC  0177400         /* microdiagnostic error code */
+#define        TS_LMX  0000200         /* limit exceeded */
+#define        TS_OPI  0000100         /* operation incomplete */
+#define        TS_REV  0000040         /* reverse */
+#define        TS_CRF  0000020         /* capstan response fail */
+#define        TS_DCK  0000010         /* density check */
+#define        TS_NOI  0000004         /* noise record */
+#define        TS_LXS  0000002         /* limit exceeded statically */
+#define        TS_RIB  0000001         /* reverse into BOT */
+
+#define        TSXS3_BITS      \
+"\10\10LMX\7OPI\6REV\5CRF\4DCK\3NOI\2LXS\1RIB"
+
+
+/* command message */
+struct ts_cmd {
+       u_short c_cmd;          /* command */
+       u_short c_loba;         /* low order buffer address */
+       u_short c_hiba;         /* high order buffer address */
+#define        c_repcnt c_loba
+       u_short c_size;         /* byte count */
+};
+
+/* commands and command bits */
+#define        TS_ACK          0100000         /* ack - release command packet */
+#define        TS_CVC          0040000         /* clear volume check */
+#define        TS_IE           0000200
+#define        TS_RCOM         0000001
+#define        TS_REREAD       0001001         /* read data retry */
+#define        TS_SETCHR       0000004         /* set characteristics */
+#define        TS_WCOM         0000005
+#define        TS_REWRITE      0001005         /* write data retry */
+#define        TS_RETRY        0001000         /* retry bit for read and write */
+#define        TS_SFORW        0000010         /* forward space record */
+#define        TS_SREV         0000410         /* reverse space record */
+#define        TS_SFORWF       0001010         /* forward space file */
+#define        TS_SREVF        0001410         /* reverse space file */
+#define        TS_REW          0002010         /* rewind */
+#define        TS_OFFL         0000412         /* unload */
+#define        TS_WEOF         0000011         /* write tape mark */
+#define        TS_SENSE        0000017         /* get status */
+
+/* characteristics data */
+struct ts_char {
+       long    char_addr;              /* address of status packet */
+       u_short char_size;              /* its size */
+       u_short char_mode;              /* characteristics */
+};
+
+
+/* characteristics */
+#define        TS_ESS  0200            /* enable skip tape marks stop */
+#define        TS_ENB  0100            /* ??? */
+#define        TS_EAI  0040            /* enable attention interrupts */
+#define        TS_ERI  0020            /* enable message buffer release interrupts */
diff --git a/usr/src/sys/vaxuba/uda.c b/usr/src/sys/vaxuba/uda.c
new file mode 100644 (file)
index 0000000..dc69103
--- /dev/null
@@ -0,0 +1,889 @@
+/*     uda.c   6.1     83/07/29        */
+
+#include "ra.h"
+#if NUDA > 0
+/*
+ * UDA50/RAxx disk device driver
+ *
+ * Restrictions:
+ *     Unit numbers must be less than 8.
+ *
+ * TO DO:
+ *     write dump code
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/dk.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#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 "../vaxuba/udareg.h"
+#include "../vax/mscp.h"
+
+struct uda_softc {
+       short   sc_state;       /* state of controller */
+       short   sc_mapped;      /* Unibus map allocated for uda struct? */
+       int     sc_ubainfo;     /* Unibus mapping info */
+       struct uda *sc_uda;     /* Unibus address of uda 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 */
+} uda_softc[NUDA];
+
+/*
+ * 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 */
+
+struct uda {
+       struct udaca    uda_ca;         /* communications area */
+       struct mscp     uda_rsp[NRSP];  /* response packets */
+       struct mscp     uda_cmd[NCMD];  /* command packets */
+} uda[NUDA];
+
+/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
+struct size {
+       daddr_t nblocks;
+       daddr_t blkoff;
+} ra_sizes[8] ={
+       15884,  0,              /* A=blk 0 thru 15883 */
+       33440,  15884,          /* B=blk 15884 thru 49323 */
+       -1,     0,              /* C=blk 0 thru end */
+       15884,  340670,         /* D=blk 340670 thru 356553 */
+       55936,  356554,         /* E=blk 356554 thru 412489 */
+       -1,     412490,         /* F=blk 412490 thru end */
+       82080,  49324,          /* G=blk 49324 thru 131403 */
+       -1,     131404,         /* H=blk 131404 thru end */
+};
+/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
+
+int    udaerror = 0;                   /* causes hex dump of packets */
+int    udadebug = 0;
+#define        printd  if (udadebug) printf
+
+daddr_t        radsize[NRA];                   /* disk size, from ONLINE end packet */
+
+int    udprobe(), udslave(), udattach(), udintr();
+struct mscp *udgetcp();
+struct uba_ctlr *udminfo[NUDA];
+struct uba_device *uddinfo[NRA];
+struct uba_device *udip[NUDA][8];      /* 8 == max number of drives */
+
+u_short        udstd[] = { 0772150, 0772550, 0777550, 0 };
+struct uba_driver udadriver =
+ { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 };
+struct buf rudbuf[NRA];
+struct buf udutab[NRA];
+struct buf udwtab[NUDA];               /* I/O wait queue, per controller */
+
+#define        b_qsize         b_resid         /* queue size per drive, in udutab */
+#define        b_ubinfo        b_resid         /* Unibus mapping info, per buffer */
+
+udprobe(reg, ctlr)
+       caddr_t reg;
+       int ctlr;
+{
+       register int br, cvec;
+       register struct uda_softc *sc = &uda_softc[ctlr];
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec; reg = reg;
+       udreset(0); udintr(0);
+#endif
+       /* SHOULD CHECK THAT IT REALLY IS A UDA */
+       br = 0x15;
+       cvec = sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4);
+       return(sizeof (struct udadevice));
+}
+
+udslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       /*
+        * TOO HARD TO FIND OUT IF DISK IS THERE UNTIL
+        * INITIALIZED.  WE'LL FIND OUT WHEN WE FIRST
+        * TRY TO ACCESS IT.
+        */
+#ifdef lint
+       ui = ui; reg = reg;
+#endif
+       return(1);
+}
+
+udattach(ui)
+       register struct uba_device *ui;
+{
+
+       if (ui->ui_dk >= 0)
+               dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256);     /* approx */
+       ui->ui_flags = 0;
+       udip[ui->ui_ctlr][ui->ui_slave] = ui;
+       radsize[ui->ui_unit] = (daddr_t)0xffffff;       /* max possible size */
+}
+
+/*
+ * Open a UDA.  Initialize the device and
+ * set the unit online.
+ */
+udopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int unit;
+       register struct uba_device *ui;
+       register struct uda_softc *sc;
+       int s;
+
+#ifdef lint
+       flag = flag;
+#endif
+       unit = minor(dev) >> 3;
+       if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       sc = &uda_softc[ui->ui_ctlr];
+       s = spl5();
+       if (sc->sc_state != S_RUN) {
+               if (sc->sc_state == S_IDLE)
+                       udinit(ui->ui_ctlr);
+               /* wait for initialization to complete */
+               sleep((caddr_t)ui->ui_mi, 0);
+               if (sc->sc_state != S_RUN)
+                       return (EIO);
+       }
+       splx(s);
+       /* SHOULD PROBABLY FORCE AN ONLINE ATTEMPT
+          TO SEE IF DISK IS REALLY THERE */
+       return (0);
+}
+
+/*
+ * Initialize a UDA.  Set up UBA mapping registers,
+ * initialize data structures, and start hardware
+ * initialization sequence.
+ */
+udinit(d)
+       int d;
+{
+       register struct uda_softc *sc;
+       register struct uda *ud;
+       struct udadevice *udaddr;
+       struct uba_ctlr *um;
+
+       sc = &uda_softc[d];
+       um = udminfo[d];
+       um->um_tab.b_active++;
+       ud = &uda[d];
+       udaddr = (struct udadevice *)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)ud,
+                   sizeof (struct uda), 0);
+               sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff);
+               sc->sc_mapped = 1;
+       }
+
+       /*
+        * Start the hardware initialization sequence.
+        */
+       udaddr->udaip = 0;              /* start initialization */
+       while ((udaddr->udasa & UDA_STEP1) == 0)
+               ;
+       udaddr->udasa = UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4);
+       /*
+        * Initialization continues in interrupt routine.
+        */
+       sc->sc_state = S_STEP1;
+       sc->sc_credits = 0;
+}
+
+udstrategy(bp)
+       register struct buf *bp;
+{
+       register struct uba_device *ui;
+       register struct uba_ctlr *um;
+       register struct buf *dp;
+       register int unit;
+       int xunit = minor(bp->b_dev) & 07;
+       daddr_t sz, maxsz;
+       int s;
+
+       sz = (bp->b_bcount+511) >> 9;
+       unit = dkunit(bp);
+       if (unit >= NRA)
+               goto bad;
+       ui = uddinfo[unit];
+       um = ui->ui_mi;
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       if ((maxsz = ra_sizes[xunit].nblocks) < 0)
+               maxsz = radsize[unit] - ra_sizes[xunit].blkoff;
+       if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz ||
+           ra_sizes[xunit].blkoff >= radsize[unit])
+               goto bad;
+       s = spl5();
+       /*
+        * Link the buffer onto the drive queue
+        */
+       dp = &udutab[ui->ui_unit];
+       if (dp->b_actf == 0)
+               dp->b_actf = bp;
+       else
+               dp->b_actl->av_forw = bp;
+       dp->b_actl = bp;
+       bp->av_forw = 0;
+       /*
+        * Link the drive onto the controller queue
+        */
+       if (dp->b_active == 0) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_active = 1;
+       }
+       if (um->um_tab.b_active == 0) {
+#if defined(VAX750)
+               if (cpu == VAX_750
+                   && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) {
+                       if (um->um_ubinfo != 0)
+                               printf("udastrat: ubinfo 0x%x\n",um->um_ubinfo);
+                       else
+                               um->um_ubinfo =
+                                  uballoc(um->um_ubanum, (caddr_t)0, 0,
+                                       UBA_NEEDBDP);
+               }
+#endif
+               (void) udstart(um);
+       }
+       splx(s);
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+udstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct mscp *mp;
+       register struct uda_softc *sc;
+       register struct uba_device *ui;
+       struct udadevice *udaddr;
+       int i;
+
+       sc = &uda_softc[um->um_ctlr];
+       
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL) {
+               /*
+                * Release uneeded UBA resources and return
+                */
+               um->um_tab.b_active = 0;
+               return (0);
+       }
+       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_forw;
+               goto loop;
+       }
+       um->um_tab.b_active++;
+       udaddr = (struct udadevice *)um->um_addr;
+       if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) {
+               harderr(bp, "ra");
+               printf("udasa %o, state %d\n", udaddr->udasa&0xffff, sc->sc_state);
+               udinit(um->um_ctlr);
+               /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */
+               return (0);
+       }
+       ui = uddinfo[dkunit(bp)];
+       /*
+        * If no credits, can't issue any commands
+        * until some outstanding commands complete.
+        */
+       if (sc->sc_credits < 2)
+               return (0);
+       if ((mp = udgetcp(um)) == NULL)
+               return (0);
+       sc->sc_credits--;       /* committed to issuing a command */
+       if (ui->ui_flags == 0) {        /* not online */
+               mp->mscp_opcode = M_OP_ONLIN;
+               mp->mscp_unit = ui->ui_slave;
+               dp->b_active = 2;
+               um->um_tab.b_actf = dp->b_forw; /* remove from controller q */
+               printd("uda: bring unit %d online\n", ui->ui_slave);
+               *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT;
+               i = udaddr->udaip;
+               goto loop;
+       }
+       switch (cpu) {
+       case VAX_780:
+               i = UBA_NEEDBDP|UBA_CANTWAIT;
+               break;
+
+       case VAX_750:
+               i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT;
+               break;
+
+       case VAX_730:
+               i = UBA_CANTWAIT;
+               break;
+       }
+       if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) {
+               mp->mscp_opcode = M_OP_GTUNT;
+               mp->mscp_unit = ui->ui_slave;
+               *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT;
+               i = udaddr->udaip;      /* initiate polling */
+               return(1);              /* wait for interrupt */
+       }
+       mp->mscp_cmdref = (long)bp;     /* pointer to get back */
+       mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE;
+       mp->mscp_unit = ui->ui_slave;
+       mp->mscp_lbn = bp->b_blkno + ra_sizes[minor(bp->b_dev)&7].blkoff;
+       mp->mscp_bytecnt = bp->b_bcount;
+       mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24);
+#if defined(VAX750)
+       if (cpu == VAX_750)
+               i &= 0xfffffff;         /* mask off bdp */
+#endif
+       bp->b_ubinfo = i;               /* save mapping info */
+       *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT;
+       i = udaddr->udaip;              /* initiate polling */
+       if (ui->ui_dk >= 0) {
+               dk_busy |= 1<<ui->ui_dk;
+               dp->b_qsize++;
+               dk_xfer[ui->ui_dk]++;
+               dk_wds[ui->ui_dk] += bp->b_bcount>>6;
+       }
+
+       /*
+        * Move drive to the end of the controller queue
+        */
+       if (dp->b_forw != NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_forw = NULL;
+       }
+       /*
+        * Move buffer to I/O wait queue
+        */
+       dp->b_actf = bp->av_forw;
+       dp = &udwtab[um->um_ctlr];
+       bp->av_forw = dp;
+       bp->av_back = dp->av_back;
+       dp->av_back->av_forw = bp;
+       dp->av_back = bp;
+       goto loop;
+}
+
+/*
+ * UDA interrupt routine.
+ */
+udintr(d)
+       int d;
+{
+       register struct uba_ctlr *um = udminfo[d];
+       register struct udadevice *udaddr = (struct udadevice *)um->um_addr;
+       struct buf *bp;
+       register int i;
+       register struct uda_softc *sc = &uda_softc[d];
+       register struct uda *ud = &uda[d];
+       struct uda *uud;
+       struct mscp *mp;
+
+       printd("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa);
+       switch (sc->sc_state) {
+       case S_IDLE:
+               printf("uda%d: random interrupt ignored\n", d);
+               return;
+
+       case S_STEP1:
+#define        STEP1MASK       0174377
+#define        STEP1GOOD       (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2)
+               if ((udaddr->udasa&STEP1MASK) != STEP1GOOD) {
+                       sc->sc_state = S_IDLE;
+                       wakeup((caddr_t)um);
+                       return;
+               }
+               udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)|
+                   (cpu == VAX_780 ? UDA_PI : 0);
+               sc->sc_state = S_STEP2;
+               return;
+
+       case S_STEP2:
+#define        STEP2MASK       0174377
+#define        STEP2GOOD       (UDA_STEP3|UDA_IE|(sc->sc_ivec/4))
+               if ((udaddr->udasa&STEP2MASK) != STEP2GOOD) {
+                       sc->sc_state = S_IDLE;
+                       wakeup((caddr_t)um);
+                       return;
+               }
+               udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16;
+               sc->sc_state = S_STEP3;
+               return;
+
+       case S_STEP3:
+#define        STEP3MASK       0174000
+#define        STEP3GOOD       UDA_STEP4
+               if ((udaddr->udasa&STEP3MASK) != STEP3GOOD) {
+                       sc->sc_state = S_IDLE;
+                       wakeup((caddr_t)um);
+                       return;
+               }
+               udaddr->udasa = UDA_GO;
+               sc->sc_state = S_SCHAR;
+
+               /*
+                * Initialize the data structures.
+                */
+               uud = sc->sc_uda;
+               for (i = 0; i < NRSP; i++) {
+                       ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT|
+                               (long)&uud->uda_rsp[i].mscp_cmdref;
+                       ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i];
+                       ud->uda_rsp[i].mscp_header.uda_msglen = sizeof (struct mscp);
+               }
+               for (i = 0; i < NCMD; i++) {
+                       ud->uda_ca.ca_cmddsc[i] = UDA_INT|
+                               (long)&uud->uda_cmd[i].mscp_cmdref;
+                       ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i];
+                       ud->uda_cmd[i].mscp_header.uda_msglen = sizeof (struct mscp);
+               }
+               bp = &udwtab[d];
+               bp->av_forw = bp->av_back = bp;
+               sc->sc_lastcmd = 0;
+               sc->sc_lastrsp = 0;
+               if ((mp = udgetcp(um)) == NULL) {
+                       sc->sc_state = S_IDLE;
+                       wakeup((caddr_t)um);
+                       return;
+               }
+               mp->mscp_opcode = M_OP_STCON;
+               mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;
+               *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT;
+               i = udaddr->udaip;      /* initiate polling */
+               return;
+
+       case S_SCHAR:
+       case S_RUN:
+               break;
+
+       default:
+               printf("uda%d: interrupt in unknown state %d ignored\n",
+                       d, sc->sc_state);
+               return;
+       }
+
+       if (udaddr->udasa&UDA_ERR) {
+               printf("uda%d: fatal error (%o)\n", d, udaddr->udasa&0xffff);
+               udaddr->udaip = 0;
+               wakeup((caddr_t)um);
+       }
+
+       /*
+        * Check for a buffer purge request.
+        */
+       if (ud->uda_ca.ca_bdp) {
+               /*
+                * THIS IS A KLUDGE.
+                * Maybe we should change the entire
+                * UBA interface structure.
+                */
+               int s = spl7();
+
+               i = um->um_ubinfo;
+               printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp);
+               um->um_ubinfo = ud->uda_ca.ca_bdp<<28;
+               ubapurge(um);
+               um->um_ubinfo = i;
+               (void) splx(s);
+               ud->uda_ca.ca_bdp = 0;
+               udaddr->udasa = 0;      /* signal purge complete */
+       }
+
+       /*
+        * Check for response ring transition.
+        */
+       if (ud->uda_ca.ca_rspint) {
+               ud->uda_ca.ca_rspint = 0;
+               for (i = sc->sc_lastrsp;; i++) {
+                       i %= NRSP;
+                       if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN)
+                               break;
+                       udrsp(um, ud, sc, i);
+                       ud->uda_ca.ca_rspdsc[i] |= UDA_OWN;
+               }
+               sc->sc_lastrsp = i;
+       }
+
+       /*
+        * Check for command ring transition.
+        */
+       if (ud->uda_ca.ca_cmdint) {
+               printd("uda: command ring transition\n");
+               ud->uda_ca.ca_cmdint = 0;
+       }
+       (void) udstart(um);
+}
+
+/*
+ * Process a response packet
+ */
+udrsp(um, ud, sc, i)
+       register struct uba_ctlr *um;
+       register struct uda *ud;
+       register struct uda_softc *sc;
+       int i;
+{
+       register struct mscp *mp;
+       struct uba_device *ui;
+       struct buf *dp, *bp;
+       int st;
+
+       mp = &ud->uda_rsp[i];
+       mp->mscp_header.uda_msglen = sizeof (struct mscp);
+       sc->sc_credits += mp->mscp_header.uda_credits & 0xf;
+       if ((mp->mscp_header.uda_credits & 0xf0) > 0x10)
+               return;
+       /*
+        * If it's an error log message (datagram),
+        * pass it on for more extensive processing.
+        */
+       if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) {
+               uderror(um, (struct mslg *)mp);
+               return;
+       }
+       if (mp->mscp_unit >= 8)
+               return;
+       if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0)
+               return;
+       st = mp->mscp_status&M_ST_MASK;
+       switch (mp->mscp_opcode) {
+       case M_OP_STCON|M_OP_END:
+               if (st == M_ST_SUCC)
+                       sc->sc_state = S_RUN;
+               else
+                       sc->sc_state = S_IDLE;
+               um->um_tab.b_active = 0;
+               wakeup((caddr_t)um);
+               break;
+
+       case M_OP_ONLIN|M_OP_END:
+               /*
+                * Link the drive onto the controller queue
+                */
+               dp = &udutab[ui->ui_unit];
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               if (st == M_ST_SUCC) {
+                       ui->ui_flags = 1;       /* mark it online */
+                       radsize[ui->ui_unit] = (daddr_t)mp->mscp_untsize;
+                       printd("uda: unit %d online\n", mp->mscp_unit);
+#ifdef notdef
+                       printf("uda%d: online, size=%d\n",
+                             mp->mscp_unit, (daddr_t)mp->mscp_untsize);
+#endif
+               } else {
+                       harderr(dp->b_actf, "ra");
+                       printf("OFFLINE\n");
+                       while (bp = dp->b_actf) {
+                               dp->b_actf = bp->av_forw;
+                               bp->b_flags |= B_ERROR;
+                               iodone(bp);
+                       }
+               }
+               dp->b_active = 1;
+               break;
+
+       case M_OP_AVATN:
+               printd("uda: unit %d attention\n", mp->mscp_unit);
+               ui->ui_flags = 0;       /* it went offline and we didn't notice */
+               break;
+
+       case M_OP_READ|M_OP_END:
+       case M_OP_WRITE|M_OP_END:
+               bp = (struct buf *)mp->mscp_cmdref;
+               ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo);
+               /*
+                * Unlink buffer from I/O wait queue.
+                */
+               bp->av_back->av_forw = bp->av_forw;
+               bp->av_forw->av_back = bp->av_back;
+#if defined(VAX750)
+               if (cpu == VAX_750
+                   && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) {
+                       if (um->um_ubinfo == 0)
+                               printf("udintr: um_ubinfo == 0\n");
+                       else
+                               ubarelse(um->um_ubanum, &um->um_ubinfo);
+               }
+#endif
+               dp = &udutab[ui->ui_unit];
+               if (ui->ui_dk >= 0)
+                       if (--dp->b_qsize == 0)
+                               dk_busy &= ~(1<<ui->ui_dk);
+               if (st == M_ST_OFFLN || st == M_ST_AVLBL) {
+                       ui->ui_flags = 0;       /* mark unit offline */
+                       /*
+                        * Link the buffer onto the front of the drive queue
+                        */
+                       if ((bp->av_forw = dp->b_actf) == 0)
+                               dp->b_actl = bp;
+                       dp->b_actf = bp;
+                       /*
+                        * Link the drive onto the controller queue
+                        */
+                       if (dp->b_active == 0) {
+                               dp->b_forw = NULL;
+                               if (um->um_tab.b_actf == NULL)
+                                       um->um_tab.b_actf = dp;
+                               else
+                                       um->um_tab.b_actl->b_forw = dp;
+                               um->um_tab.b_actl = dp;
+                               dp->b_active = 1;
+                       }
+#if defined(VAX750)
+                       if (cpu == VAX750 && um->um_ubinfo == 0)
+                               um->um_ubinfo =
+                                  uballoc(um->um_ubanum, (caddr_t)0, 0,
+                                       UBA_NEEDBDP);
+#endif
+                       return;
+               }
+               if (st != M_ST_SUCC) {
+                       harderr(bp, "ra");
+                       printf("status %o\n", mp->mscp_status);
+                       bp->b_flags |= B_ERROR;
+               }
+               bp->b_resid = bp->b_bcount - mp->mscp_bytecnt;
+               iodone(bp);
+               break;
+
+       case M_OP_GTUNT|M_OP_END:
+               break;
+
+       default:
+               printf("uda: unknown packet\n");
+       }
+}
+
+
+/*
+ * Process an error log message
+ *
+ * For now, just log the error on the console.
+ * Only minimal decoding is done, only "useful"
+ * information is printed.  Eventually should
+ * send message to an error logger.
+ */
+uderror(um, mp)
+       register struct uba_ctlr *um;
+       register struct mslg *mp;
+{
+       printf("uda%d: %s error, ", um->um_ctlr,
+               mp->mslg_flags&M_LF_SUCC ? "soft" : "hard");
+       switch (mp->mslg_format) {
+       case M_FM_CNTERR:
+               printf("controller error, event 0%o\n", mp->mslg_event);
+               break;
+
+       case M_FM_BUSADDR:
+               printf("host memory access error, event 0%o, addr 0%o\n",
+                       mp->mslg_event, mp->mslg_busaddr);
+               break;
+
+       case M_FM_DISKTRN:
+               printf("disk transfer error, unit %d, grp 0x%x, hdr 0x%x\n",
+                       mp->mslg_unit, mp->mslg_group, mp->mslg_hdr);
+               break;
+
+       case M_FM_SDI:
+               printf("SDI error, unit %d, event 0%o, hdr 0x%x\n",
+                       mp->mslg_unit, mp->mslg_event, mp->mslg_hdr);
+               break;
+
+       case M_FM_SMLDSK:
+               printf("small disk error, unit %d, event 0%o, cyl %d\n",
+                       mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl);
+               break;
+
+       default:
+               printf("unknown error, unit %d, format 0%o, event 0%o\n",
+                       mp->mslg_unit, mp->mslg_format, mp->mslg_event);
+       }
+
+       if (udaerror) {
+               register long *p = (long *)mp;
+               register int i;
+
+               for (i = 0; i < mp->mslg_header.uda_msglen; i += sizeof(*p))
+                       printf("%x ", *p++);
+               printf("\n");
+       }
+}
+
+
+/*
+ * Find an unused command packet
+ */
+struct mscp *
+udgetcp(um)
+       struct uba_ctlr *um;
+{
+       register struct mscp *mp;
+       register struct udaca *cp;
+       register struct uda_softc *sc;
+       register int i;
+
+       cp = &uda[um->um_ctlr].uda_ca;
+       sc = &uda_softc[um->um_ctlr];
+       i = sc->sc_lastcmd;
+       if ((cp->ca_cmddsc[i] & (UDA_OWN|UDA_INT)) == UDA_INT) {
+               cp->ca_cmddsc[i] &= ~UDA_INT;
+               mp = &uda[um->um_ctlr].uda_cmd[i];
+               mp->mscp_unit = mp->mscp_modifier = 0;
+               mp->mscp_opcode = mp->mscp_flags = 0;
+               mp->mscp_bytecnt = mp->mscp_buffer = 0;
+               mp->mscp_errlgfl = mp->mscp_copyspd = 0;
+               sc->sc_lastcmd = (i + 1) % NCMD;
+               return(mp);
+       }
+       return(NULL);
+}
+
+udread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRA)
+               return (ENXIO);
+       return (physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys, uio));
+}
+
+udwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRA)
+               return (ENXIO);
+       return (physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+udreset(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 < NUDA; d++) {
+               if ((um = udminfo[d]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               printf(" uda%d", d);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               uda_softc[d].sc_state = S_IDLE;
+               for (unit = 0; unit < NRA; unit++) {
+                       if ((ui = uddinfo[unit]) == 0)
+                               continue;
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
+                               continue;
+                       udutab[unit].b_active = 0;
+                       udutab[unit].b_qsize = 0;
+               }
+               for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) {
+                       nbp = bp->av_forw;
+                       bp->b_ubinfo = 0;
+                       /*
+                        * Link the buffer onto the drive queue
+                        */
+                       dp = &udutab[dkunit(bp)];
+                       if (dp->b_actf == 0)
+                               dp->b_actf = bp;
+                       else
+                               dp->b_actl->av_forw = bp;
+                       dp->b_actl = bp;
+                       bp->av_forw = 0;
+                       /*
+                        * Link the drive onto the controller queue
+                        */
+                       if (dp->b_active == 0) {
+                               dp->b_forw = NULL;
+                               if (um->um_tab.b_actf == NULL)
+                                       um->um_tab.b_actf = dp;
+                               else
+                                       um->um_tab.b_actl->b_forw = dp;
+                               um->um_tab.b_actl = dp;
+                               dp->b_active = 1;
+                       }
+               }
+               udinit(d);
+       }
+}
+
+uddump()
+{
+       return(ENXIO);
+}
+udsize(dev)
+       dev_t dev;
+{
+       int unit = minor(dev) >> 3;
+       struct uba_device *ui;
+
+       if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       return (ra_sizes[minor(dev) & 07].nblocks);     /* XXX */
+}
+#endif
diff --git a/usr/src/sys/vaxuba/udareg.h b/usr/src/sys/vaxuba/udareg.h
new file mode 100644 (file)
index 0000000..c507e67
--- /dev/null
@@ -0,0 +1,51 @@
+/*     udareg.h        6.1     83/07/29        */
+
+/*
+ * UDA-50 registers and structures
+ */
+
+struct udadevice {
+       short   udaip;          /* initialization and polling */
+       short   udasa;          /* status and address */
+};
+
+#define        UDA_ERR         0100000 /* error bit */
+#define        UDA_STEP4       0040000 /* step 4 has started */
+#define        UDA_STEP3       0020000 /* step 3 has started */
+#define        UDA_STEP2       0010000 /* step 2 has started */
+#define        UDA_STEP1       0004000 /* step 1 has started */
+#define        UDA_NV          0002000 /* no host settable interrupt vector */
+#define        UDA_QB          0001000 /* controller supports Q22 bus */
+#define        UDA_DI          0000400 /* controller implements diagnostics */
+#define        UDA_IE          0000200 /* interrupt enable */
+#define        UDA_PI          0000001 /* host requests adapter purge interrupts */
+#define        UDA_GO          0000001 /* start operation, after init */
+
+
+/*
+ * UDA Communications Area
+ */
+
+struct udaca {
+       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        UDA_OWN 0x80000000      /* UDA owns this descriptor */
+#define        UDA_INT 0x40000000      /* allow interrupt on ring transition */
+
+/*
+ * MSCP packet info
+ */
+struct mscp_header {
+       short   uda_msglen;     /* length of MSCP packet */
+       char    uda_credits;    /* low 4 bits: credits, high 4 bits: msgtype */
+       char    uda_vcid;       /* virtual circuit id */
+};
diff --git a/usr/src/sys/vaxuba/up.c b/usr/src/sys/vaxuba/up.c
new file mode 100644 (file)
index 0000000..86565f3
--- /dev/null
@@ -0,0 +1,1070 @@
+/*     up.c    6.1     83/07/29        */
+
+#include "up.h"
+#if NSC > 0
+/*
+ * UNIBUS disk driver with:
+ *     overlapped seeks,
+ *     ECC recovery, and
+ *     bad sector forwarding.
+ *
+ * TODO:
+ *     Check that offset recovery code works
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dk.h"
+#include "../h/dkbad.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vax/nexus.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/upreg.h"
+
+struct up_softc {
+       int     sc_softas;
+       int     sc_ndrive;
+       int     sc_wticks;
+       int     sc_recal;
+} up_softc[NSC];
+
+/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
+struct size {
+       daddr_t nblocks;
+       int     cyloff;
+} up9300_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 26 */
+       33440,  27,             /* B=cyl 27 thru 81 */
+       495520, 0,              /* C=cyl 0 thru 814 */
+       15884,  562,            /* D=cyl 562 thru 588 */
+       55936,  589,            /* E=cyl 589 thru 680 */
+       81376,  681,            /* F=cyl 681 thru 814 */
+       153728, 562,            /* G=cyl 562 thru 814 */
+       291346, 82,             /* H=cyl 82 thru 561 */
+}, up9766_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 26 */
+       33440,  27,             /* B=cyl 27 thru 81 */
+       500384, 0,              /* C=cyl 0 thru 822 */
+       15884,  562,            /* D=cyl 562 thru 588 */
+       55936,  589,            /* E=cyl 589 thru 680 */
+       86240,  681,            /* F=cyl 681 thru 822 */
+       158592, 562,            /* G=cyl 562 thru 822 */
+       291346, 82,             /* H=cyl 82 thru 561 */
+}, up160_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 49 */
+       33440,  50,             /* B=cyl 50 thru 154 */
+       263360, 0,              /* C=cyl 0 thru 822 */
+       15884,  155,            /* D=cyl 155 thru 204 */
+       55936,  205,            /* E=cyl 205 thru 379 */
+       141664, 380,            /* F=cyl 380 thru 822 */
+       213664, 155,            /* G=cyl 155 thru 822 */
+       0,      0,
+}, upam_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 31 */
+       33440,  32,             /* B=cyl 32 thru 97 */
+       524288, 0,              /* C=cyl 0 thru 1023 */
+       15884,  668,            /* D=cyl 668 thru 699 */
+       55936,  700,            /* E=cyl 700 thru 809 */
+       109472, 810,            /* F=cyl 810 thru 1023 */
+       182176, 668,            /* G=cyl 668 thru 1023 */
+       291346, 98,             /* H=cyl 98 thru 667 */
+}, up980_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 99 */
+       33440,  100,            /* B=cyl 100 thru 308 */
+       131680, 0,              /* C=cyl 0 thru 822 */
+       15884,  309,            /* D=cyl 309 thru 408 */
+       55936,  409,            /* E=cyl 409 thru 758 */
+       10080,  759,            /* F=cyl 759 thru 822 */
+       82080,  309,            /* G=cyl 309 thru 822 */
+       0,      0,
+};
+/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
+
+int    upprobe(), upslave(), upattach(), updgo(), upintr();
+struct uba_ctlr *upminfo[NSC];
+struct uba_device *updinfo[NUP];
+#define        UPIPUNITS       8
+struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */
+
+u_short        upstd[] = { 0776700, 0774400, 0776300, 0 };
+struct uba_driver scdriver =
+    { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
+struct buf     uputab[NUP];
+char upinit[NUP];
+
+struct upst {
+       short   nsect;          /* # sectors/track */
+       short   ntrak;          /* # tracks/cylinder */
+       short   nspc;           /* # sectors/cylinder */
+       short   ncyl;           /* # cylinders */
+       struct  size *sizes;    /* partition tables */
+       short   sdist;          /* seek distance metric */
+       short   rdist;          /* rotational distance metric */
+} upst[] = {
+       { 32,   19,     32*19,  815,    up9300_sizes,   3, 4 }, /* 9300 */
+       { 32,   19,     32*19,  823,    up9766_sizes,   3, 4 }, /* 9766 */
+       { 32,   10,     32*10,  823,    up160_sizes,    3, 4 }, /* fuji 160m */
+       { 32,   16,     32*16,  1024,   upam_sizes,     7, 8 }, /* Capricorn */
+       { 32,   5,      32*5,   823,    up980_sizes,    3, 4 }, /* DM980 */
+       { 0,    0,      0,      0,      0,              0, 0 }
+};
+
+u_char up_offset[16] = {
+       UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
+       UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 
+       UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
+       0, 0, 0, 0
+};
+
+struct buf     rupbuf[NUP];
+struct         buf     bupbuf[NUP];
+struct dkbad   upbad[NUP];
+
+#define        b_cylin b_resid
+
+#ifdef INTRLVE
+daddr_t dkblock();
+#endif
+
+int    upwstart, upwatch();            /* Have started guardian */
+int    upseek;
+int    upwaitdry;
+
+/*ARGSUSED*/
+upprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+
+#ifdef lint    
+       br = 0; cvec = br; br = cvec; upintr(0);
+#endif
+       ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
+       DELAY(10);
+       ((struct updevice *)reg)->upcs1 = 0;
+       return (sizeof (struct updevice));
+}
+
+upslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       register struct updevice *upaddr = (struct updevice *)reg;
+
+       upaddr->upcs1 = 0;              /* conservative */
+       upaddr->upcs2 = ui->ui_slave;
+       upaddr->upcs1 = UP_NOP|UP_GO;
+       if (upaddr->upcs2&UPCS2_NED) {
+               upaddr->upcs1 = UP_DCLR|UP_GO;
+               return (0);
+       }
+       return (1);
+}
+
+upattach(ui)
+       register struct uba_device *ui;
+{
+
+       if (upwstart == 0) {
+               timeout(upwatch, (caddr_t)0, hz);
+               upwstart++;
+       }
+       if (ui->ui_dk >= 0)
+               dk_mspw[ui->ui_dk] = .0000020345;
+       upip[ui->ui_ctlr][ui->ui_slave] = ui;
+       up_softc[ui->ui_ctlr].sc_ndrive++;
+       ui->ui_type = upmaptype(ui);
+}
+
+upmaptype(ui)
+       register struct uba_device *ui;
+{
+       register struct updevice *upaddr = (struct updevice *)ui->ui_addr;
+       int type = ui->ui_type;
+       register struct upst *st;
+
+       upaddr->upcs1 = 0;
+       upaddr->upcs2 = ui->ui_slave;
+       upaddr->uphr = UPHR_MAXTRAK;
+       for (st = upst; st->nsect != 0; st++)
+               if (upaddr->uphr == st->ntrak - 1) {
+                       type = st - upst;
+                       break;
+               }
+       if (st->nsect == 0)
+               printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr);
+       if (type == 0) {
+               upaddr->uphr = UPHR_MAXCYL;
+               if (upaddr->uphr == 822)
+                       type++;
+       }
+       upaddr->upcs2 = UPCS2_CLR;
+       return (type);
+}
+upopen(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       return (0);
+}
+
+upstrategy(bp)
+       register struct buf *bp;
+{
+       register struct uba_device *ui;
+       register struct upst *st;
+       register int unit;
+       register struct buf *dp;
+       int xunit = minor(bp->b_dev) & 07;
+       long bn, sz;
+
+       sz = (bp->b_bcount+511) >> 9;
+       unit = dkunit(bp);
+       if (unit >= NUP)
+               goto bad;
+       ui = updinfo[unit];
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       st = &upst[ui->ui_type];
+       if (bp->b_blkno < 0 ||
+           (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
+               goto bad;
+       bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
+       (void) spl5();
+       dp = &uputab[ui->ui_unit];
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               (void) upustart(ui);
+               bp = &ui->ui_mi->um_tab;
+               if (bp->b_actf && bp->b_active == 0)
+                       (void) upstart(ui->ui_mi);
+       }
+       (void) spl0();
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+/*
+ * Unit start routine.
+ * Seek the drive to be where the data is
+ * and then generate another interrupt
+ * to actually start the transfer.
+ * If there is only one drive on the controller,
+ * or we are very close to the data, don't
+ * bother with the search.  If called after
+ * searching once, don't bother to look where
+ * we are, just queue for transfer (to avoid
+ * positioning forever without transferrring.)
+ */
+upustart(ui)
+       register struct uba_device *ui;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um;
+       register struct updevice *upaddr;
+       register struct upst *st;
+       daddr_t bn;
+       int sn, csn;
+       /*
+        * The SC21 cancels commands if you just say
+        *      cs1 = UP_IE
+        * so we are cautious about handling of cs1.
+        * Also don't bother to clear as bits other than in upintr().
+        */
+       int didie = 0;
+
+       if (ui == 0)
+               return (0);
+       um = ui->ui_mi;
+       dk_busy &= ~(1<<ui->ui_dk);
+       dp = &uputab[ui->ui_unit];
+       if ((bp = dp->b_actf) == NULL)
+               goto out;
+       /*
+        * If the controller is active, just remember
+        * that this device would like to be positioned...
+        * if we tried to position now we would confuse the SC21.
+        */
+       if (um->um_tab.b_active) {
+               up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
+               return (0);
+       }
+       /*
+        * If we have already positioned this drive,
+        * then just put it on the ready queue.
+        */
+       if (dp->b_active)
+               goto done;
+       dp->b_active = 1;
+       upaddr = (struct updevice *)um->um_addr;
+       upaddr->upcs2 = ui->ui_slave;
+       /*
+        * If drive has just come up,
+        * setup the pack.
+        */
+       if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) {
+               struct buf *bbp = &bupbuf[ui->ui_unit];
+
+               /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
+               upinit[ui->ui_unit] = 1;
+               upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
+               upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
+               upaddr->upof = UPOF_FMT22;
+               didie = 1;
+               st = &upst[ui->ui_type];
+               bbp->b_flags = B_READ|B_BUSY;
+               bbp->b_dev = bp->b_dev;
+               bbp->b_bcount = 512;
+               bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit];
+               bbp->b_blkno = st->ncyl * st->nspc - st->nsect;
+               bbp->b_cylin = st->ncyl - 1;
+               dp->b_actf = bbp;
+               bbp->av_forw = bp;
+               bp = bbp;
+       }
+       /*
+        * If drive is offline, forget about positioning.
+        */
+       if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL))
+               goto done;
+       /*
+        * If there is only one drive,
+        * dont bother searching.
+        */
+       if (up_softc[um->um_ctlr].sc_ndrive == 1)
+               goto done;
+       /*
+        * Figure out where this transfer is going to
+        * and see if we are close enough to justify not searching.
+        */
+       st = &upst[ui->ui_type];
+       bn = dkblock(bp);
+       sn = bn%st->nspc;
+       sn = (sn + st->nsect - st->sdist) % st->nsect;
+       if (bp->b_cylin - upaddr->updc)
+               goto search;            /* Not on-cylinder */
+       else if (upseek)
+               goto done;              /* Ok just to be on-cylinder */
+       csn = (upaddr->upla>>6) - sn - 1;
+       if (csn < 0)
+               csn += st->nsect;
+       if (csn > st->nsect - st->rdist)
+               goto done;
+search:
+       upaddr->updc = bp->b_cylin;
+       /*
+        * Not on cylinder at correct position,
+        * seek/search.
+        */
+       if (upseek)
+               upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
+       else {
+               upaddr->upda = sn;
+               upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
+       }
+       didie = 1;
+       /*
+        * Mark unit busy for iostat.
+        */
+       if (ui->ui_dk >= 0) {
+               dk_busy |= 1<<ui->ui_dk;
+               dk_seek[ui->ui_dk]++;
+       }
+       goto out;
+done:
+       /*
+        * Device is ready to go.
+        * Put it on the ready queue for the controller
+        * (unless its already there.)
+        */
+       if (dp->b_active != 2) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_active = 2;
+       }
+out:
+       return (didie);
+}
+
+/*
+ * Start up a transfer on a drive.
+ */
+upstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct uba_device *ui;
+       register struct updevice *upaddr;
+       struct upst *st;
+       daddr_t bn;
+       int dn, sn, tn, cmd, waitdry;
+
+loop:
+       /*
+        * Pull a request off the controller queue
+        */
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return (0);
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       /*
+        * Mark controller busy, and
+        * determine destination of this request.
+        */
+       um->um_tab.b_active++;
+       ui = updinfo[dkunit(bp)];
+       bn = dkblock(bp);
+       dn = ui->ui_slave;
+       st = &upst[ui->ui_type];
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       upaddr = (struct updevice *)ui->ui_addr;
+       /*
+        * Select drive if not selected already.
+        */
+       if ((upaddr->upcs2&07) != dn)
+               upaddr->upcs2 = dn;
+       /*
+        * Check that it is ready and online
+        */
+       waitdry = 0;
+       while ((upaddr->upds&UPDS_DRY) == 0) {
+               printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds);
+               if (++waitdry > 512)
+                       break;
+               upwaitdry++;
+       }
+       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+               printf("up%d: not ready", dkunit(bp));
+               if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                       printf("\n");
+                       um->um_tab.b_active = 0;
+                       um->um_tab.b_errcnt = 0;
+                       dp->b_actf = bp->av_forw;
+                       dp->b_active = 0;
+                       bp->b_flags |= B_ERROR;
+                       iodone(bp);
+                       goto loop;
+               }
+               /*
+                * Oh, well, sometimes this
+                * happens, for reasons unknown.
+                */
+               printf(" (flakey)\n");
+       }
+       /*
+        * Setup for the transfer, and get in the
+        * UNIBUS adaptor queue.
+        */
+       upaddr->updc = bp->b_cylin;
+       upaddr->upda = (tn << 8) + sn;
+       upaddr->upwc = -bp->b_bcount / sizeof (short);
+       if (bp->b_flags & B_READ)
+               cmd = UP_IE|UP_RCOM|UP_GO;
+       else
+               cmd = UP_IE|UP_WCOM|UP_GO;
+       um->um_cmd = cmd;
+       (void) ubago(ui);
+       return (1);
+}
+
+/*
+ * Now all ready to go, stuff the registers.
+ */
+updgo(um)
+       struct uba_ctlr *um;
+{
+       register struct updevice *upaddr = (struct updevice *)um->um_addr;
+
+       um->um_tab.b_active = 2;        /* should now be 2 */
+       upaddr->upba = um->um_ubinfo;
+       upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
+}
+
+/*
+ * Handle a disk interrupt.
+ */
+upintr(sc21)
+       register sc21;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um = upminfo[sc21];
+       register struct uba_device *ui;
+       register struct updevice *upaddr = (struct updevice *)um->um_addr;
+       register unit;
+       struct up_softc *sc = &up_softc[um->um_ctlr];
+       int as = (upaddr->upas & 0377) | sc->sc_softas;
+       int needie = 1, waitdry;
+
+       sc->sc_wticks = 0;
+       sc->sc_softas = 0;
+       /*
+        * If controller wasn't transferring, then this is an
+        * interrupt for attention status on seeking drives.
+        * Just service them.
+        */
+       if (um->um_tab.b_active != 2 && !sc->sc_recal) {
+               if (upaddr->upcs1 & UP_TRE)
+                       upaddr->upcs1 = UP_TRE;
+               goto doattn;
+       }
+       um->um_tab.b_active = 1;
+       /*
+        * Get device and block structures, and a pointer
+        * to the uba_device for the drive.  Select the drive.
+        */
+       dp = um->um_tab.b_actf;
+       bp = dp->b_actf;
+       ui = updinfo[dkunit(bp)];
+       dk_busy &= ~(1 << ui->ui_dk);
+       if ((upaddr->upcs2&07) != ui->ui_slave)
+               upaddr->upcs2 = ui->ui_slave;
+       if (bp->b_flags&B_BAD) {
+               if (upecc(ui, CONT))
+                       return;
+       }
+       /*
+        * Check for and process errors on
+        * either the drive or the controller.
+        */
+       if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) {
+               waitdry = 0;
+               while ((upaddr->upds & UPDS_DRY) == 0) {
+                       if (++waitdry > 512)
+                               break;
+                       upwaitdry++;
+               }
+               if (upaddr->uper1&UPER1_WLE) {
+                       /*
+                        * Give up on write locked devices
+                        * immediately.
+                        */
+                       printf("up%d: write locked\n", dkunit(bp));
+                       bp->b_flags |= B_ERROR;
+               } else if (++um->um_tab.b_errcnt > 27) {
+                       /*
+                        * After 28 retries (16 without offset, and
+                        * 12 with offset positioning) give up.
+                        * If the error was header CRC, the header is 
+                        * screwed up, and the sector may in fact exist
+                        * in the bad sector table, better check...
+                        */
+                       if (upaddr->uper1&UPER1_HCRC) {
+                               if (upecc(ui, BSE))
+                                       return;
+                       }
+       hard:
+                       harderr(bp, "up");
+                       printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n",
+                               upaddr->updc, ((upaddr->upda)>>8)&077,
+                               (upaddr->upda)&037,
+                               upaddr->upcs2, UPCS2_BITS,
+                               upaddr->uper1, UPER1_BITS,
+                               upaddr->uper2, UPER2_BITS);
+                       bp->b_flags |= B_ERROR;
+               } else if (upaddr->uper2 & UPER2_BSE) {
+                       if (upecc(ui, BSE))
+                               return;
+                       else
+                               goto hard;
+               } else {
+                       /*
+                        * Retriable error.
+                        * If a soft ecc, correct it (continuing
+                        * by returning if necessary.
+                        * Otherwise fall through and retry the transfer
+                        */
+                       if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) {
+                               if (upecc(ui, ECC))
+                                       return;
+                       } else
+                               um->um_tab.b_active = 0; /* force retry */
+               }
+               /*
+                * Clear drive error and, every eight attempts,
+                * (starting with the fourth)
+                * recalibrate to clear the slate.
+                */
+               upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
+               needie = 0;
+               if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) {
+                       upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
+                       sc->sc_recal = 0;
+                       goto nextrecal;
+               }
+       }
+       /*
+        * Advance recalibration finite state machine
+        * if recalibrate in progress, through
+        *      RECAL
+        *      SEEK
+        *      OFFSET (optional)
+        *      RETRY
+        */
+       switch (sc->sc_recal) {
+
+       case 1:
+               upaddr->updc = bp->b_cylin;
+               upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO;
+               goto nextrecal;
+       case 2:
+               if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0)
+                       goto donerecal;
+               upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22;
+               upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
+               goto nextrecal;
+       nextrecal:
+               sc->sc_recal++;
+               um->um_tab.b_active = 1;
+               return;
+       donerecal:
+       case 3:
+               sc->sc_recal = 0;
+               um->um_tab.b_active = 0;
+               break;
+       }
+       /*
+        * If still ``active'', then don't need any more retries.
+        */
+       if (um->um_tab.b_active) {
+               /*
+                * If we were offset positioning,
+                * return to centerline.
+                */
+               if (um->um_tab.b_errcnt >= 16) {
+                       upaddr->upof = UPOF_FMT22;
+                       upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
+                       while (upaddr->upds & UPDS_PIP)
+                               DELAY(25);
+                       needie = 0;
+               }
+               um->um_tab.b_active = 0;
+               um->um_tab.b_errcnt = 0;
+               um->um_tab.b_actf = dp->b_forw;
+               dp->b_active = 0;
+               dp->b_errcnt = 0;
+               dp->b_actf = bp->av_forw;
+               bp->b_resid = (-upaddr->upwc * sizeof(short));
+               iodone(bp);
+               /*
+                * If this unit has more work to do,
+                * then start it up right away.
+                */
+               if (dp->b_actf)
+                       if (upustart(ui))
+                               needie = 0;
+       }
+       as &= ~(1<<ui->ui_slave);
+       /*
+        * Release unibus resources and flush data paths.
+        */
+       ubadone(um);
+doattn:
+       /*
+        * Process other units which need attention.
+        * For each unit which needs attention, call
+        * the unit start routine to place the slave
+        * on the controller device queue.
+        */
+       while (unit = ffs(as)) {
+               unit--;         /* was 1 origin */
+               as &= ~(1<<unit);
+               upaddr->upas = 1<<unit;
+               if (unit < UPIPUNITS && upustart(upip[sc21][unit]))
+                       needie = 0;
+       }
+       /*
+        * If the controller is not transferring, but
+        * there are devices ready to transfer, start
+        * the controller.
+        */
+       if (um->um_tab.b_actf && um->um_tab.b_active == 0)
+               if (upstart(um))
+                       needie = 0;
+       if (needie)
+               upaddr->upcs1 = UP_IE;
+}
+
+upread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NUP)
+               return (ENXIO);
+       return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio));
+}
+
+upwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NUP)
+               return (ENXIO);
+       return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Correct an ECC error, and restart the i/o to complete
+ * the transfer if necessary.  This is quite complicated because
+ * the transfer may be going to an odd memory address base and/or
+ * across a page boundary.
+ */
+upecc(ui, flag)
+       register struct uba_device *ui;
+       int flag;
+{
+       register struct updevice *up = (struct updevice *)ui->ui_addr;
+       register struct buf *bp = uputab[ui->ui_unit].b_actf;
+       register struct uba_ctlr *um = ui->ui_mi;
+       register struct upst *st;
+       struct uba_regs *ubp = ui->ui_hd->uh_uba;
+       register int i;
+       caddr_t addr;
+       int reg, bit, byte, npf, mask, o, cmd, ubaddr;
+       int bn, cn, tn, sn;
+
+       /*
+        * Npf is the number of sectors transferred before the sector
+        * containing the ECC error, and reg is the UBA register
+        * mapping (the first part of) the transfer.
+        * O is offset within a memory page of the first byte transferred.
+        */
+       if (flag == CONT)
+               npf = bp->b_error;
+       else
+               npf = btop((up->upwc * sizeof(short)) + bp->b_bcount);
+       reg = btop(um->um_ubinfo&0x3ffff) + npf;
+       o = (int)bp->b_un.b_addr & PGOFSET;
+       mask = up->upec2;
+#ifdef UPECCDEBUG
+       printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask,
+           up->upec1);
+#endif
+       bn = dkblock(bp);
+       st = &upst[ui->ui_type];
+       cn = bp->b_cylin;
+       sn = bn%st->nspc + npf;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       cn += tn/st->ntrak;
+       tn %= st->ntrak;
+       ubapurge(um);
+       um->um_tab.b_active=2;
+       /*
+        * action taken depends on the flag
+        */
+       switch(flag){
+       case ECC:
+               npf--;
+               reg--;
+               mask = up->upec2;
+               printf("up%d%c: soft ecc sn%d\n", dkunit(bp),
+                       'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
+               /*
+                * Flush the buffered data path, and compute the
+                * byte and bit position of the error.  The variable i
+                * is the byte offset in the transfer, the variable byte
+                * is the offset from a page boundary in main memory.
+                */
+               i = up->upec1 - 1;              /* -1 makes 0 origin */
+               bit = i&07;
+               i = (i&~07)>>3;
+               byte = i + o;
+               /*
+                * Correct while possible bits remain of mask.  Since mask
+                * contains 11 bits, we continue while the bit offset is > -11.
+                * Also watch out for end of this block and the end of the whole
+                * transfer.
+                */
+               while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
+                       struct pte pte;
+
+                       pte = ubp->uba_map[reg + btop(byte)];
+                       addr = ptob(pte.pg_pfnum) + (byte & PGOFSET);
+#ifdef UPECCDEBUG
+                       printf("addr %x map reg %x\n",
+                               addr, *(int *)(&ubp->uba_map[reg+btop(byte)]));
+                       printf("old: %x, ", getmemc(addr));
+#endif
+                       putmemc(addr, getmemc(addr)^(mask<<bit));
+#ifdef UPECCDEBUG
+                       printf("new: %x\n", getmemc(addr));
+#endif
+                       byte++;
+                       i++;
+                       bit -= 8;
+               }
+               if (up->upwc == 0)
+                       return (0);
+               npf++;
+               reg++;
+               break;
+       case BSE:
+               /*
+                * if not in bad sector table, return 0
+                */
+               if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0)
+                       return(0);
+               /*
+                * flag this one as bad
+                */
+               bp->b_flags |= B_BAD;
+               bp->b_error = npf + 1;
+#ifdef UPECCDEBUG
+               printf("BSE: restart at %d\n",npf+1);
+#endif
+               bn = st->ncyl * st->nspc -st->nsect - 1 - bn;
+               cn = bn / st->nspc;
+               sn = bn % st->nspc;
+               tn = sn / st->nsect;
+               sn %= st->nsect;
+               up->upwc = -(512 / sizeof (short));
+#ifdef UPECCDEBUG
+               printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
+#endif
+               break;
+       case CONT:
+#ifdef UPECCDEBUG
+               printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
+#endif
+               bp->b_flags &= ~B_BAD;
+               up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short));
+               if (up->upwc == 0)
+                       return(0);
+               break;
+       }
+       if (up->upwc == 0) {
+               um->um_tab.b_active = 0;
+               return (0);
+       }
+       /*
+        * Have to continue the transfer... clear the drive,
+        * and compute the position where the transfer is to continue.
+        * We have completed npf+1 sectors of the transfer already;
+        * restart at offset o of next sector (i.e. in UBA register reg+1).
+        */
+#ifdef notdef
+       up->uper1 = 0;
+       up->upcs1 |= UP_GO;
+#else
+       up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
+       up->updc = cn;
+       up->upda = (tn << 8) | sn;
+       ubaddr = (int)ptob(reg) + o;
+       up->upba = ubaddr;
+       cmd = (ubaddr >> 8) & 0x300;
+       cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO;
+       um->um_tab.b_errcnt = 0;
+       up->upcs1 = cmd;
+#endif
+       return (1);
+}
+
+/*
+ * Reset driver after UBA init.
+ * Cancel software state of all pending transfers
+ * and restart all units and the controller.
+ */
+upreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
+       register sc21, unit;
+
+       for (sc21 = 0; sc21 < NSC; sc21++) {
+               if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               printf(" sc%d", sc21);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               up_softc[sc21].sc_recal = 0;
+               up_softc[sc21].sc_wticks = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR;
+               for (unit = 0; unit < NUP; unit++) {
+                       if ((ui = updinfo[unit]) == 0)
+                               continue;
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
+                               continue;
+                       uputab[unit].b_active = 0;
+                       (void) upustart(ui);
+               }
+               (void) upstart(um);
+       }
+}
+
+/*
+ * Wake up every second and if an interrupt is pending
+ * but nothing has happened increment a counter.
+ * If nothing happens for 20 seconds, reset the UNIBUS
+ * and begin anew.
+ */
+upwatch()
+{
+       register struct uba_ctlr *um;
+       register sc21, unit;
+       register struct up_softc *sc;
+
+       timeout(upwatch, (caddr_t)0, hz);
+       for (sc21 = 0; sc21 < NSC; sc21++) {
+               um = upminfo[sc21];
+               if (um == 0 || um->um_alive == 0)
+                       continue;
+               sc = &up_softc[sc21];
+               if (um->um_tab.b_active == 0) {
+                       for (unit = 0; unit < NUP; unit++)
+                               if (uputab[unit].b_active &&
+                                   updinfo[unit]->ui_mi == um)
+                                       goto active;
+                       sc->sc_wticks = 0;
+                       continue;
+               }
+active:
+               sc->sc_wticks++;
+               if (sc->sc_wticks >= 20) {
+                       sc->sc_wticks = 0;
+                       printf("sc%d: lost interrupt\n", sc21);
+                       ubareset(um->um_ubanum);
+               }
+       }
+}
+
+#define        DBSIZE  20
+
+updump(dev)
+       dev_t dev;
+{
+       struct updevice *upaddr;
+       char *start;
+       int num, blk, unit;
+       struct size *sizes;
+       register struct uba_regs *uba;
+       register struct uba_device *ui;
+       register short *rp;
+       struct upst *st;
+       register int retry;
+
+       unit = minor(dev) >> 3;
+       if (unit >= NUP)
+               return (ENXIO);
+#define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
+       ui = phys(struct uba_device *, updinfo[unit]);
+       if (ui->ui_alive == 0)
+               return (ENXIO);
+       uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
+       ubainit(uba);
+       upaddr = (struct updevice *)ui->ui_physaddr;
+       DELAY(5000000);
+       num = maxfree;
+       upaddr->upcs2 = unit;
+       DELAY(100);
+       upaddr->upcs1 = UP_DCLR|UP_GO;
+       upaddr->upcs1 = UP_PRESET|UP_GO;
+       upaddr->upof = UPOF_FMT22;
+       retry = 0;
+       do {
+               DELAY(25);
+               if (++retry > 527)
+                       break;
+       } while ((upaddr->upds & UP_RDY) == 0);
+       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY)
+               return (EFAULT);
+       start = 0;
+       st = &upst[ui->ui_type];
+       sizes = phys(struct size *, st->sizes);
+       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
+               return (EINVAL);
+       while (num > 0) {
+               register struct pte *io;
+               register int i;
+               int cn, sn, tn;
+               daddr_t bn;
+
+               blk = num > DBSIZE ? DBSIZE : num;
+               io = uba->uba_map;
+               for (i = 0; i < blk; i++)
+                       *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
+               *(int *)io = 0;
+               bn = dumplo + btop(start);
+               cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
+               upaddr->updc = cn;
+               rp = (short *) &upaddr->upda;
+               *rp = (tn << 8) + sn;
+               *--rp = 0;
+               *--rp = -blk*NBPG / sizeof (short);
+               *--rp = UP_GO|UP_WCOM;
+               retry = 0;
+               do {
+                       DELAY(25);
+                       if (++retry > 527)
+                               break;
+               } while ((upaddr->upcs1 & UP_RDY) == 0);
+               if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                       printf("up%d: not ready", unit);
+                       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                               printf("\n");
+                               return (EIO);
+                       }
+                       printf(" (flakey)\n");
+               }
+               if (upaddr->upds&UPDS_ERR)
+                       return (EIO);
+               start += blk*NBPG;
+               num -= blk;
+       }
+       return (0);
+}
+
+upsize(dev)
+       dev_t dev;
+{
+       int unit = minor(dev) >> 3;
+       struct uba_device *ui;
+       struct upst *st;
+
+       if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       st = &upst[ui->ui_type];
+       return (st->sizes[minor(dev) & 07].nblocks);
+}
+#endif
diff --git a/usr/src/sys/vaxuba/upreg.h b/usr/src/sys/vaxuba/upreg.h
new file mode 100644 (file)
index 0000000..f49ba8b
--- /dev/null
@@ -0,0 +1,160 @@
+/*     upreg.h 6.1     83/07/29        */
+
+/*
+ * Unibus rm emulation via sc21:
+ * registers and bits.
+ */
+
+struct updevice
+{
+       u_short upcs1;          /* control and status register 1 */
+       short   upwc;           /* word count register */
+       u_short upba;           /* UNIBUS address register */
+       u_short upda;           /* desired address register */
+       u_short upcs2;          /* control and status register 2 */
+       u_short upds;           /* drive Status */
+       u_short uper1;          /* error register 1 */
+       u_short upas;           /* attention summary */
+       u_short upla;           /* look ahead */
+       u_short updb;           /* data buffer */
+       u_short upmr;           /* maintenance */ 
+       u_short updt;           /* drive type */
+       u_short upsn;           /* serial number */
+       u_short upof;           /* offset register */
+       u_short updc;           /* desired cylinder address register */
+       u_short uphr;           /* holding register */
+       u_short upmr2;          /* maintenance register 2 */
+       u_short uper2;          /* error register 2 */
+       u_short upec1;          /* burst error bit position */
+       u_short upec2;          /* burst error bit pattern */
+};
+
+/* Other bits of upcs1 */
+#define        UP_SC   0100000         /* special condition */
+#define        UP_TRE  0040000         /* transfer error */
+#define        UP_PSEL 0010000         /* port select */
+#define        UP_DVA  0004000         /* drive available */
+/* bits 8 and 9 are the extended address bits */
+#define        UP_RDY  0000200         /* controller ready */
+#define        UP_IE   0000100         /* interrupt enable */
+/* bits 5-1 are the command */
+#define        UP_GO   0000001
+
+/* commands */
+#define        UP_NOP          000
+#define        UP_SEEK         004             /* seek */
+#define        UP_RECAL        006             /* recalibrate */
+#define        UP_DCLR         010             /* drive clear */
+#define        UP_RELEASE      012             /* release */
+#define        UP_OFFSET       014             /* offset */
+#define        UP_RTC          016             /* return to center-line */
+#define        UP_PRESET       020             /* read-in preset */
+#define        UP_PACK         022             /* pack acknowledge */
+#define        UP_DMABAND      024             /* dma bandwidth set */
+#define        UP_SEARCH       030             /* search */
+#define        UP_WCDATA       050             /* write check data */
+#define        UP_WCHDR        052             /* write check header and data */
+#define        UP_WCOM         060             /* write */
+#define        UP_WHDR         062             /* write header and data */
+#define        UP_RCOM         070             /* read data */
+#define        UP_RHDR         072             /* read header and data */
+#define        UP_BOOT         074             /* boot */
+#define        UP_FORMAT       076             /* format */
+
+/* upcs2 */
+#define        UPCS2_DLT       0100000         /* data late */
+#define        UPCS2_WCE       0040000         /* write check error */
+#define        UPCS2_UPE       0020000         /* UNIBUS parity error */
+#define        UPCS2_NED       0010000         /* nonexistent drive */
+#define        UPCS2_NEM       0004000         /* nonexistent memory */
+#define        UPCS2_PGE       0002000         /* programming error */
+#define        UPCS2_MXF       0001000         /* missed transfer */
+#define        UPCS2_MDPE      0000400         /* massbus data parity error (0) */
+#define        UPCS2_OR        0000200         /* output ready */
+#define        UPCS2_IR        0000100         /* input ready */
+#define        UPCS2_CLR       0000040         /* controller clear */
+#define        UPCS2_PAT       0000020         /* parity test */
+#define        UPCS2_BAI       0000010         /* address increment inhibit */
+/* bits 0-2 are drive select */
+
+#define        UPCS2_BITS \
+"\10\20DLT\17WCE\16UPE\15NED\14NEM\13PGE\12MXF\11MDPE\
+\10OR\7IR\6CLR\5PAT\4BAI"
+
+/* upds */
+#define        UPDS_ATA        0100000         /* attention active */
+#define        UPDS_ERR        0040000         /* composite drive error */
+#define        UPDS_PIP        0020000         /* positioning in progress */
+#define        UPDS_MOL        0010000         /* medium on line */
+#define        UPDS_WRL        0004000         /* write locked */
+#define        UPDS_LST        0002000         /* last sector transferred */
+#define        UPDS_PGM        0001000         /* programmable */
+#define        UPDS_DPR        0000400         /* drive present */
+#define        UPDS_DRY        0000200         /* drive ready */
+#define        UPDS_VV         0000100         /* volume valid */
+/* bits 1-5 are spare */
+#define        UPDS_OM         0000001         /* offset mode */
+
+#define        UPDS_DREADY     (UPDS_DPR|UPDS_DRY|UPDS_MOL|UPDS_VV)
+
+#define        UPDS_BITS \
+"\10\20ATA\17ERR\16PIP\15MOL\14WRL\13LST\12PGM\11DPR\10DRY\7VV\1OM"
+
+/* uper1 */
+#define        UPER1_DCK       0100000         /* data check */
+#define        UPER1_UNS       0040000         /* drive unsafe */
+#define        UPER1_OPI       0020000         /* operation incomplete */
+#define        UPER1_DTE       0010000         /* drive timing error */
+#define        UPER1_WLE       0004000         /* write lock error */
+#define        UPER1_IAE       0002000         /* invalid address error */
+#define        UPER1_AOE       0001000         /* address overflow error */
+#define        UPER1_HCRC      0000400         /* header crc error */
+#define        UPER1_HCE       0000200         /* header compare error */
+#define        UPER1_ECH       0000100         /* ecc hard error */
+#define        UPER1_WCF       0000040         /* write clock fail (0) */
+#define        UPER1_FER       0000020         /* format error */
+#define        UPER1_PAR       0000010         /* parity error */
+#define        UPER1_RMR       0000004         /* register modification refused */
+#define        UPER1_ILR       0000002         /* illegal register */
+#define        UPER1_ILF       0000001         /* illegal function */
+
+#define        UPER1_BITS \
+"\10\20DCK\17UNS\16OPI\15DTE\14WLE\13IAE\12AOE\11HCRC\10HCE\
+\7ECH\6WCF\5FER\4PAR\3RMR\2ILR\1ILF"
+
+/* uphr */
+/* write these int uphr and then read back values */
+#define        UPHR_MAXCYL     0100027         /* max cyl address */
+#define        UPHR_MAXTRAK    0100030         /* max track address */
+#define        UPHR_MAXSECT    0100031         /* max sector address */
+
+/* uper2 */
+#define        UPER2_BSE       0100000         /* bad sector error */
+#define        UPER2_SKI       0040000         /* seek incomplete */
+#define        UPER2_OPE       0020000         /* operator plug error */
+#define        UPER2_IVC       0010000         /* invalid command */
+#define        UPER2_LSC       0004000         /* loss of sector clock */
+#define        UPER2_LBC       0002000         /* loss of bit clock */
+#define        UPER2_MDS       0001000         /* multiple drive select */
+#define        UPER2_DCU       0000400         /* dc power unsafe */
+#define        UPER2_DVC       0000200         /* device check */
+#define        UPER2_ACU       0000100         /* ac power unsafe */
+/* bits 5 and 4 are spare */
+#define        UPER2_DPE       0000010         /* data parity error (0) */
+/* bits 2-0 are spare */
+
+#define        UPER2_BITS \
+"\10\20BSE\17SKI\16OPE\15IVC\14LSC\13LBC\12MDS\11DCU\10DVC\7ACU\4DPE"
+
+/* upof */
+#define        UPOF_FMT22      0010000         /* 16 bit format */
+#define        UPOF_ECI        0004000         /* ecc inhibit */
+#define        UPOF_HCI        0002000         /* header compare inhibit */
+
+/* THE SC21 ACTUALLY JUST IMPLEMENTS ADVANCE/RETARD... */
+#define        UPOF_P400       0020            /*  +400 uinches */
+#define        UPOF_M400       0220            /*  -400 uinches */
+#define        UPOF_P800       0040            /*  +800 uinches */
+#define        UPOF_M800       0240            /*  -800 uinches */
+#define        UPOF_P1200      0060            /* +1200 uinches */
+#define        UPOF_M1200      0260            /* -1200 uinches */
diff --git a/usr/src/sys/vaxuba/ut.c b/usr/src/sys/vaxuba/ut.c
new file mode 100644 (file)
index 0000000..a298318
--- /dev/null
@@ -0,0 +1,906 @@
+/*     ut.c    6.1     83/07/29        */
+
+#include "tj.h"
+#if NUT > 0
+/*
+ * System Industries Model 9700 Tape Drive
+ *   emulates a TU45 on the UNIBUS
+ *
+ * TODO:
+ *     check out attention processing
+ *     try reset code and dump code
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/file.h"
+#include "../h/user.h"
+#include "../h/map.h"
+#include "../h/ioctl.h"
+#include "../h/mtio.h"
+#include "../h/cmap.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/utreg.h"
+
+struct buf     rutbuf[NUT];    /* bufs for raw i/o */
+struct buf     cutbuf[NUT];    /* bufs for control operations */
+struct buf     tjutab[NTJ];    /* bufs for slave queue headers */
+
+struct uba_ctlr *utminfo[NUT];
+struct uba_device *tjdinfo[NTJ];
+int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer();
+u_short utstd[] = { 0772440, 0 };
+struct uba_driver utdriver =
+  { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };
+
+#define        MASKREG(reg)    ((reg)&0xffff)
+
+/* bits in minor device */
+#define        TJUNIT(dev)     (minor(dev)&03)
+#define        T_NOREWIND      04
+#define        T_1600BPI       010
+#define        T_6250BPI       020
+short  utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI };
+
+/* slave to controller mapping table */
+short  tjtout[NTJ];
+#define UTUNIT(dev)    (tjtout[TJUNIT(dev)])
+
+#define        INF     (daddr_t)1000000L       /* a block number that wont exist */
+
+struct tj_softc {
+       char    sc_openf;       /* exclusive open */
+       char    sc_lastiow;     /* last I/O operation was a write */
+       daddr_t sc_blkno;       /* next block to transfer */
+       daddr_t sc_nxrec;       /* next record on tape */
+       u_short sc_erreg;       /* image of uter */
+       u_short sc_dsreg;       /* image of utds */
+       u_short sc_resid;       /* residual from transfer */
+       u_short sc_dens;        /* sticky selected density */
+       daddr_t sc_timo;        /* time until timeout expires */
+       short   sc_tact;        /* timeout is active flag */
+} tj_softc[NTJ];
+
+/*
+ * Internal per/slave states found in sc_state
+ */
+#define        SSEEK           1       /* seeking */
+#define        SIO             2       /* doing sequential I/O */
+#define        SCOM            3       /* sending a control command */
+#define        SREW            4       /* doing a rewind op */
+#define        SERASE          5       /* erase inter-record gap */
+#define        SERASED         6       /* erased inter-record gap */
+
+/*ARGSUSED*/
+utprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+#ifdef lint
+       br=0; cvec=br; br=cvec;
+       utintr(0);
+#endif
+       /*
+        * The SI documentation says you must set the RDY bit
+        * (even though it's read-only) to force an interrupt.
+        */
+       ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY;
+       DELAY(10000);
+       return (sizeof (struct utdevice));
+}
+
+/*ARGSUSED*/
+utslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       /*
+        * A real TU45 would support the slave present bit
+        * int the drive type register, but this thing doesn't,
+        * so there's no way to determine if a slave is present or not.
+        */
+        return(1);
+}
+
+utattach(ui)
+       struct uba_device *ui;
+{
+       tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr;
+}
+
+/*
+ * Open the device with exclusive access.
+ */
+utopen(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       register int tjunit = TJUNIT(dev);
+       register struct uba_device *ui;
+       register struct tj_softc *sc;
+       int olddens, dens;
+       register int s;
+
+       if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf ||
+           (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       olddens = sc->sc_dens;
+       dens = sc->sc_dens =
+           utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]|
+             PDP11FMT|(ui->ui_slave&07);
+get:
+       utcommand(dev, UT_SENSE, 1);
+       if (sc->sc_dsreg&UTDS_PIP) {
+               sleep((caddr_t)&lbolt, PZERO+1);
+               goto get;
+       }
+       sc->sc_dens = olddens;
+       if ((sc->sc_dsreg&UTDS_MOL) == 0) {
+               uprintf("tj%d: not online\n", tjunit);
+               return (EIO);
+       }
+       if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) {
+               uprintf("tj%d: no write ring\n", tjunit);
+               return (EIO);
+       }
+       if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) &&
+           dens != sc->sc_dens) {
+               uprintf("tj%d: can't change density in mid-tape\n", tjunit);
+               return (EIO);
+       }
+       sc->sc_openf = 1;
+       sc->sc_blkno = (daddr_t)0;
+       sc->sc_nxrec = INF;
+       sc->sc_lastiow = 0;
+       sc->sc_dens = dens;
+       /*
+        * For 6250 bpi take exclusive use of the UNIBUS.
+        */
+       ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI;
+       s = spl6();
+       if (sc->sc_tact == 0) {
+               sc->sc_timo = INF;
+               sc->sc_tact = 1;
+               timeout(uttimer, (caddr_t)dev, 5*hz);
+       }
+       splx(s);
+       return (0);
+}
+
+utclose(dev, flag)
+       register dev_t dev;
+       register flag;
+{
+       register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
+
+       if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) {
+               utcommand(dev, UT_WEOF, 1);
+               utcommand(dev, UT_WEOF, 1);
+               utcommand(dev, UT_SREV, 1);
+       }
+       if ((minor(dev)&T_NOREWIND) == 0)
+               utcommand(dev, UT_REW, 0);
+       sc->sc_openf = 0;
+}
+
+utcommand(dev, com, count)
+       dev_t dev;
+       int com, count;
+{
+       register struct buf *bp;
+       register int s;
+
+       bp = &cutbuf[UTUNIT(dev)];
+       s = spl5();
+       while (bp->b_flags&B_BUSY) {
+               if(bp->b_repcnt == 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);
+       bp->b_dev = dev;
+       bp->b_command = com;
+       bp->b_repcnt = count;
+       bp->b_blkno = 0;
+       utstrategy(bp);
+       if (count == 0)
+               return;
+       iowait(bp);
+       if (bp->b_flags&B_WANTED)
+               wakeup((caddr_t)bp);
+       bp->b_flags &= B_ERROR;
+}
+
+/*
+ * Queue a tape operation.
+ */
+utstrategy(bp)
+       register struct buf *bp;
+{
+       int tjunit = TJUNIT(bp->b_dev);
+       register struct uba_ctlr *um;
+       register struct buf *dp;
+
+       /*
+        * Put transfer at end of unit queue
+        */
+       dp = &tjutab[tjunit];
+       bp->av_forw = NULL;
+       (void) spl5();
+       if (dp->b_actf == NULL) {
+               dp->b_actf = bp;
+               /*
+                * Transport not active, so...
+                * put at end of controller queue
+                */
+               dp->b_forw = NULL;
+               um = tjdinfo[tjunit]->ui_mi;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+       } else
+               dp->b_actl->av_forw = bp;
+       dp->b_actl = bp;
+       /*
+        * If the controller is not busy, set it going.
+        */
+       if (um->um_tab.b_state == 0)
+               utstart(um);
+       (void) spl0();
+}
+
+utstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct utdevice *addr;
+       register struct buf *bp, *dp;
+       register struct tj_softc *sc;
+       struct uba_device *ui;
+       int tjunit;
+       daddr_t blkno;
+
+loop:
+       /*
+        * Scan controller queue looking for units with
+        * transaction queues to dispatch
+        */
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       addr = (struct utdevice *)um->um_addr;
+       tjunit = TJUNIT(bp->b_dev);
+       ui = tjdinfo[tjunit];
+       sc = &tj_softc[tjunit];
+       /* note slave select, density, and format were merged on open */
+       addr->uttc = sc->sc_dens;
+       sc->sc_dsreg = addr->utds;
+       sc->sc_erreg = addr->uter;
+       sc->sc_resid = MASKREG(addr->utfc);
+       /*
+        * Default is that last command was NOT a write command;
+        * if we do a write command we will notice this in utintr().
+        */
+       sc->sc_lastiow = 0;
+       if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) {
+               /*
+                * Have had a hard error on a non-raw tape
+                * or the tape unit is now unavailable
+                * (e.g. taken off line).
+                */
+               bp->b_flags |= B_ERROR;
+               goto next;
+       }
+       if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
+               /*
+                * Execute a control operation with the specified
+                * count.
+                */
+               if (bp->b_command == UT_SENSE)
+                       goto next;
+               if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) {
+                       bp->b_resid = bp->b_bcount;
+                       goto next;
+               }
+               /*
+                * Set next state; handle timeouts
+                */
+               if (bp->b_command == UT_REW) {
+                       um->um_tab.b_state = SREW;
+                       sc->sc_timo = 5*60;
+               } else {
+                       um->um_tab.b_state = SCOM;
+                       sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60);
+               }
+               /* NOTE: this depends on the ut command values */
+               if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF)
+                       addr->utfc = -bp->b_repcnt;
+               goto dobpcmd;
+       }
+       /*
+        * The following checks boundary conditions for operations
+        * on non-raw tapes.  On raw tapes the initialization of
+        * sc->sc_nxrec by utphys causes them to be skipped normally
+        * (except in the case of retries).
+        */
+       if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
+               /* can't read past end of file */
+               bp->b_flags |= B_ERROR;
+               bp->b_error = ENXIO;
+               goto next;
+       }
+       if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) {
+               /* read at eof returns 0 count */
+               bp->b_resid = bp->b_bcount;
+               clrbuf(bp);
+               goto next;
+       }
+       if ((bp->b_flags&B_READ) == 0)
+               sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1;
+       /*
+        * If the tape is correctly positioned, set up all the
+        * registers but the csr, and give control over to the
+        * UNIBUS adaptor routines, to wait for resources to
+        * start I/O.
+        */
+       if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
+               addr->utwc = -(((bp->b_bcount)+1)>>1);
+               addr->utfc = -bp->b_bcount;
+               if ((bp->b_flags&B_READ) == 0) {
+                       /*
+                        * On write error retries erase the
+                        * inter-record gap before rewriting.
+                        */
+                       if (um->um_tab.b_errcnt) {
+                               if (um->um_tab.b_state != SERASED) {
+                                       um->um_tab.b_state = SERASE;
+                                       sc->sc_timo = 60;
+                                       addr->utcs1 = UT_ERASE|UT_IE|UT_GO;
+                                       return;
+                               }
+                       }
+                       if (addr->utds & UTDS_EOT) {
+                               bp->b_resid = bp->b_bcount;
+                               um->um_tab.b_state = 0;
+                               goto next;
+                       }
+                       um->um_cmd = UT_WCOM;
+               } else
+                       um->um_cmd = UT_RCOM;
+               sc->sc_timo = 60;
+               um->um_tab.b_state = SIO;
+               (void) ubago(ui);
+               return;
+       }
+       /*
+        * Tape positioned incorrectly; seek forwards or
+        * backwards to the correct spot.  This happens for
+        * raw tapes only on error retries.
+        */
+       um->um_tab.b_state = SSEEK;
+       if (blkno < bdbtofsb(bp->b_blkno)) {
+               addr->utfc = blkno - bdbtofsb(bp->b_blkno);
+               bp->b_command = UT_SFORW;
+       } else {
+               addr->utfc = bdbtofsb(bp->b_blkno) - blkno;
+               bp->b_command = UT_SREV;
+       }
+       sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60);
+
+dobpcmd:
+       /*
+        * Perform the command setup in bp.
+        */
+       addr->utcs1 = bp->b_command|UT_IE|UT_GO;
+       return;
+next:
+       /*
+        * Advance to the next command in the slave queue,
+        * posting notice and releasing resources as needed.
+        */
+       if (um->um_ubinfo)
+               ubadone(um);
+       um->um_tab.b_errcnt = 0;
+       dp->b_actf = bp->av_forw;
+       iodone(bp);
+       goto loop;
+}
+
+/*
+ * Start operation on controller --
+ * UNIBUS resources have been allocated.
+ */
+utdgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct utdevice *addr = (struct utdevice *)um->um_addr;
+
+       addr->utba = (u_short) um->um_ubinfo;
+       addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO;
+}
+
+/*
+ * Ut interrupt handler
+ */
+/*ARGSUSED*/
+utintr(ut11)
+       int ut11;
+{
+       struct buf *dp;
+       register struct buf *bp;
+       register struct uba_ctlr *um = utminfo[ut11];
+       register struct utdevice *addr;
+       register struct tj_softc *sc;
+       u_short tjunit, cs2, cs1;
+       register state;
+
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       bp = dp->b_actf;
+       tjunit = TJUNIT(bp->b_dev);
+       addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr;
+       sc = &tj_softc[tjunit];
+       /*
+        * Record status...
+        */
+       sc->sc_timo = INF;
+       sc->sc_dsreg = addr->utds;
+       sc->sc_erreg = addr->uter;
+       sc->sc_resid = MASKREG(addr->utfc);
+       if ((bp->b_flags&B_READ) == 0)
+               sc->sc_lastiow = 1;
+       state = um->um_tab.b_state;
+       um->um_tab.b_state = 0;
+       /*
+        * Check for errors...
+        */
+       if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) {
+               /*
+                * To clear the ERR bit, we must issue a drive clear
+                * command, and to clear the TRE bit we must set the
+                * controller clear bit.
+                */
+               cs2 = addr->utcs2;
+               if ((cs1 = addr->utcs1)&UT_TRE)
+                       addr->utcs2 |= UTCS2_CLR;
+               /* is this dangerous ?? */
+               while ((addr->utcs1&UT_RDY) == 0)
+                       ;
+               addr->utcs1 = UT_CLEAR|UT_GO;
+               /*
+                * If we were reading at 1600 or 6250 bpi and the error
+                * was corrected, then don't consider this an error.
+                */
+               if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) &&
+                   (addr->uttc & UTTC_DEN) != UT_NRZI) {
+                       printf(
+                         "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
+                         tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
+                         UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
+                       sc->sc_erreg &= ~UTER_COR;
+               }
+               /*
+                * If we were reading from a raw tape and the only error
+                * was that the record was too long, then we don't consider
+                * this an error.
+                */
+               if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) &&
+                   (sc->sc_erreg&UTER_FCE))
+                       sc->sc_erreg &= ~UTER_FCE;
+               if (sc->sc_erreg == 0)
+                       goto ignoreerr;
+               /*
+                * Fix up errors which occur due to backspacing
+                * "over" the front of the tape.
+                */
+               if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV &&
+                   ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0))
+                       goto opdone;
+               /*
+                * Retry soft errors up to 8 times
+                */
+               if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) {
+                       if (++um->um_tab.b_errcnt < 7) {
+                               sc->sc_blkno++;
+                               ubadone(um);
+                               goto opcont;
+                       }
+               }
+               /*
+                * Hard or non-I/O errors on non-raw tape
+                * cause it to close.
+                */
+               if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)])
+                       sc->sc_openf = -1;
+               /*
+                * Couldn't recover error.
+                */
+               printf("ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
+                       tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
+                       UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
+               bp->b_flags |= B_ERROR;
+               goto opdone;
+       }
+
+ignoreerr:
+       /*
+        * If we hit a tape mark update our position.
+        */
+       if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) {
+               /*
+                * Set blkno and nxrec
+                */
+               if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
+                       if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
+                               sc->sc_nxrec =
+                                    bdbtofsb(bp->b_blkno) - addr->utfc;
+                               sc->sc_blkno = sc->sc_nxrec;
+                       } else {
+                               sc->sc_blkno =
+                                    bdbtofsb(bp->b_blkno) + addr->utfc;
+                               sc->sc_nxrec = sc->sc_blkno-1;
+                       }
+               } else
+                       sc->sc_nxrec = bdbtofsb(bp->b_blkno);
+               /*
+                * Note: if we get a tape mark on a read, the
+                * frame count register will be zero, so b_resid
+                * will be calculated correctly below.
+                */
+               goto opdone;
+       }
+       /*
+        * Advance tape control FSM.
+        */
+       switch (state) {
+
+       case SIO:               /* read/write increments tape block # */
+               sc->sc_blkno++;
+               break;
+
+       case SCOM:              /* motion commands update current position */
+               if (bp == &cutbuf[UTUNIT(bp->b_dev)])
+               switch (bp->b_command) {
+
+               case UT_SFORW:
+                       sc->sc_blkno -= bp->b_repcnt;
+                       break;
+
+               case UT_SREV:
+                       sc->sc_blkno += bp->b_repcnt;
+                       break;
+
+               case UT_REWOFFL:
+                       addr->utcs1 = UT_CLEAR|UT_GO;
+                       break;
+               }
+               break;
+
+       case SSEEK:
+               sc->sc_blkno = bdbtofsb(bp->b_blkno);
+               goto opcont;
+
+       case SERASE:
+               /*
+                * Completed erase of the inter-record gap due to a
+                * write error; now retry the write operation.
+                */
+               um->um_tab.b_state = SERASED;
+               goto opcont;
+
+       case SREW:                      /* clear attention bit */
+               addr->utcs1 = UT_CLEAR|UT_GO;
+               break;
+
+       default:
+               printf("bad state %d\n", state);
+               panic("utintr");
+       }
+
+opdone:
+       /*
+        * Reset error count and remove
+        * from device queue
+        */
+       um->um_tab.b_errcnt = 0;
+       dp->b_actf = bp->av_forw;
+       /*
+        * For read command, frame count register contains
+        * actual length of tape record.  Otherwise, it
+        * holds negative residual count.
+        */
+       if (state == SIO && um->um_cmd == UT_RCOM) {
+               bp->b_resid = 0;
+               if (bp->b_bcount > MASKREG(addr->utfc))
+                       bp->b_resid = bp->b_bcount - MASKREG(addr->utfc);
+       } else
+               bp->b_resid = MASKREG(-addr->utfc);
+       ubadone(um);
+       iodone(bp);
+       /*
+        * Circulate slave to end of controller queue
+        * to give other slaves a chance
+        */
+       um->um_tab.b_actf = dp->b_forw;
+       if (dp->b_actf) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+       }
+       if (um->um_tab.b_actf == 0)
+               return;
+opcont:
+       utstart(um);
+}
+
+/*
+ * Watchdog timer routine.
+ */
+uttimer(dev)
+       int dev;
+{
+       register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
+       register short x;
+
+       if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) {
+               printf("tj%d: lost interrupt\n", TJUNIT(dev));
+               sc->sc_timo = INF;
+               x = spl5();
+               utintr(UTUNIT(dev));
+               (void) splx(x);
+       }
+       timeout(uttimer, (caddr_t)dev, 5*hz);
+}
+
+/*
+ * Raw interface for a read
+ */
+utread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = utphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio));
+}
+
+/*
+ * Raw interface for a write
+ */
+utwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       int errno;
+
+       errno = utphys(dev, uio);
+       if (errno)
+               return (errno);
+       return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio));
+}
+
+/*
+ * Check for valid device number dev and update our notion
+ * of where we are on the tape
+ */
+utphys(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int tjunit = TJUNIT(dev);
+       register struct tj_softc *sc;
+       register struct uba_device *ui;
+
+       if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       sc = &tj_softc[tjunit];
+       sc->sc_blkno = bdbtofsb(uio->uio_offset>>9);
+       sc->sc_nxrec = sc->sc_blkno+1;
+       return (0);
+}
+
+/*ARGSUSED*/
+utioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
+       register struct buf *bp = &cutbuf[UTUNIT(dev)];
+       register callcount;
+       int fcount;
+       struct mtop *mtop;
+       struct mtget *mtget;
+       /* we depend of the values and order of the MT codes here */
+       static utops[] =
+      {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE};
+
+       switch (cmd) {
+
+       case MTIOCTOP:
+               mtop = (struct mtop *)data;
+               switch(mtop->mt_op) {
+
+               case MTWEOF:
+               case MTFSF: case MTBSF:
+               case MTFSR: case MTBSR:
+                       callcount = mtop->mt_count;
+                       fcount = 1;
+                       break;
+
+               case MTREW: case MTOFFL: case MTNOP:
+                       callcount = 1;
+                       fcount = 1;
+                       break;
+
+               default:
+                       return (ENXIO);
+               }
+               if (callcount <= 0 || fcount <= 0)
+                       return (EINVAL);
+               while (--callcount >= 0) {
+                       utcommand(dev, utops[mtop->mt_op], fcount);
+                       if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT))
+                               break;
+               }
+               return (geterror(bp));
+
+       case MTIOCGET:
+               mtget = (struct mtget *)data;
+               mtget->mt_dsreg = sc->sc_dsreg;
+               mtget->mt_erreg = sc->sc_erreg;
+               mtget->mt_resid = sc->sc_resid;
+               mtget->mt_type = MT_ISUT;
+               break;
+
+       default:
+               return (ENXIO);
+       }
+       return (0);
+}
+
+utreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register ut11, tjunit;
+       register struct uba_device *ui;
+       register struct buf *dp;
+
+       for (ut11 = 0; ut11 < NUT; ut11++) {
+               if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 ||
+                  um->um_ubanum != uban)
+                       continue;
+               printf(" ut%d", ut11);
+               um->um_tab.b_state = 0;
+               um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO;
+               ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR;
+               for (tjunit = 0; tjunit < NTJ; tjunit++) {
+                       if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um ||
+                           ui->ui_alive == 0)
+                               continue;
+                       dp = &tjutab[tjunit];
+                       dp->b_state = 0;
+                       dp->b_forw = 0;
+                       if (um->um_tab.b_actf == NULL)
+                               um->um_tab.b_actf = dp;
+                       else
+                               um->um_tab.b_actl->b_forw = dp;
+                       um->um_tab.b_actl = dp;
+                       if (tj_softc[tjunit].sc_openf > 0)
+                               tj_softc[tjunit].sc_openf = -1;
+               }
+               utstart(um);
+       }
+}
+
+/*
+ * Do a stand-alone core dump to tape --
+ * from here down, routines are used only in dump context
+ */
+#define        DBSIZE  20
+
+utdump()
+{
+       register struct uba_device *ui;
+       register struct uba_regs *up;
+       register struct utdevice *addr;
+       int blk, num = maxfree;
+       int start = 0;
+
+#define        phys(a,b)               ((b)((int)(a)&0x7fffffff))
+       if (tjdinfo[0] == 0)
+               return (ENXIO);
+       ui = phys(tjdinfo[0], struct uba_device *);
+       up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
+       ubainit(up);
+       DELAY(1000000);
+       addr = (struct utdevice *)ui->ui_physaddr;
+       utwait(addr);
+       /*
+        * Be sure to set the appropriate density here.  We use
+        * 6250, but maybe it should be done at 1600 to insure the
+        * tape can be read by most any other tape drive available.
+        */
+       addr->uttc = UT_GCR|PDP11FMT;   /* implicit slave 0 or-ed in */
+       addr->utcs1 = UT_CLEAR|UT_GO;
+       while (num > 0) {
+               blk = num > DBSIZE ? DBSIZE : num;
+               utdwrite(start, blk, addr, up);
+               if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
+                       return(EIO);
+               start += blk;
+               num -= blk;
+       }
+       uteof(addr);
+       uteof(addr);
+       utwait(addr);
+       if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
+               return(EIO);
+       addr->utcs1 = UT_REW|UT_GO;
+       return (0);
+}
+
+utdwrite(dbuf, num, addr, up)
+       register dbuf, num;
+       register struct utdevice *addr;
+       struct uba_regs *up;
+{
+       register struct pte *io;
+       register int npf;
+
+       utwait(addr);
+       io = up->uba_map;
+       npf = num + 1;
+       while (--npf != 0)
+               *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
+       *(int *)io = 0;
+       addr->utwc = -((num*NBPG)>>1);
+       addr->utfc = -(num*NBPG);
+       addr->utba = 0;
+       addr->utcs1 = UT_WCOM|UT_GO;
+}
+
+utwait(addr)
+       struct utdevice *addr;
+{
+       register s;
+
+       do
+               s = addr->utds;
+       while ((s&UTDS_DRY) == 0);
+}
+
+uteof(addr)
+       struct utdevice *addr;
+{
+
+       utwait(addr);
+       addr->utcs1 = UT_WEOF|UT_GO;
+}
+#endif
diff --git a/usr/src/sys/vaxuba/utreg.h b/usr/src/sys/vaxuba/utreg.h
new file mode 100644 (file)
index 0000000..1910b34
--- /dev/null
@@ -0,0 +1,169 @@
+/*     utreg.h 6.1     83/07/29        */
+
+/*
+ * System Industries Model 9700 Tape Drive
+ *   emulates TU45 on the UNIBUS
+ */
+
+struct utdevice {
+       u_short utcs1;          /* control status register 1 */
+       short   utwc;           /* word count register */
+       u_short utba;           /* low 16-bits of bus address */
+       short   utfc;           /* frame counter */
+       u_short utcs2;          /* control status register 2 */
+       u_short utds;           /* drive status register */
+       u_short uter;           /* error register */
+       u_short utas;           /* attention status register */
+       u_short utcc;           /* NRZI CRC character for validation */
+       u_short utdb;           /* data buffer reg (not emulated) */
+       u_short utmr;           /* maintenance reg (not emulated) */
+       u_short utdt;           /* drive type register (not emulated) */
+       u_short utsn;           /* serial number reg (not emulated) */
+       u_short uttc;           /* tape control register */
+       u_short utbae;          /* buffer address extension register */
+       u_short utcs3;          /* control and status register 3 */
+};
+
+/*
+ * utcs1 --
+ *   cmds, interrupt enable, extended address bits, and status
+ */
+#define        UT_GO           0x0001          /* go bit */
+/* function codes reside in bits 5-1 */
+#define        UT_NOP          0x0000          /* no operation */
+#define        UT_REWOFFL      0x0002          /* rewind offline */
+#define        UT_LOOP         0x0004          /* loop read/write */
+#define        UT_REW          0x0006          /* rewind */
+#define        UT_CLEAR        0x0008          /* drive clear */
+#define        UT_SENSE        0x000a          /* drive sense */
+#define        UT_PRESET       0x0010          /* read in preset */
+#define        UT_DIAGN        0x0012          /* diagnostic mode set */
+#define        UT_ERASE        0x0014          /* erase */
+#define        UT_WEOF         0x0016          /* write tape mark */
+#define        UT_SFORW        0x0018          /* forward space block */
+#define        UT_SREV         0x001a          /* reverse space block */
+#define        UT_SFORWF       0x001c          /* forward space file */
+#define        UT_SREVF        0x001e          /* reverse space file */
+#define        UT_WCHFORW      0x0028          /* write check forward */
+#define        UT_WCHREV       0x002e          /* write check reverse */
+#define        UT_WCOM         0x0030          /* write forward */
+#define        UT_RCOM         0x0038          /* read forward */
+#define        UT_RREV         0x003e          /* read reverse */
+/* the remainder are control and status bits */
+#define        UT_IE           0x0040          /* interrupt-enable */
+#define        UT_RDY          0x0080          /* controller ready */
+#define        UT_EADDR        0x0300          /* extended address bits */
+/* bit 10 unused */
+#define        UT_DVA          0x0800          /* drive available */
+/* bit 12 unused */
+/* bit 13 - massbus control parity error not emulated */
+#define        UT_TRE          0x4000          /* transfer error */
+#define        UT_SC           0x8000          /* special condition */
+
+#define        UT_BITS \
+"\10\20SC\17TRE\14DVA\10RDY\7IE\1GO"
+
+/*
+ * utcs2 --
+ *   controller clear, error flags, and unit select
+ */
+/* bits 0-2 are unit select */
+#define        UTCS2_BAI       0x0008          /* UNIBUS address increment inhibit */
+#define        UTCS2_PAT       0x0010          /* parity test */
+#define        UTCS2_CLR       0x0020          /* controller clear */
+#define        UTCS2_IR        0x0040          /* input ready (not emulated) */
+#define        UTCS2_OR        0x0080          /* output ready (not emulated) */
+#define        UTCS2_RPE       0x0100          /* rom parity error */
+#define        UTCS2_MXF       0x0200          /* missed transfer */
+#define        UTCS2_NEM       0x0400          /* non existant memory */
+#define        UTCS2_PGE       0x0800          /* program error */
+#define        UTCS2_NED       0x1000          /* non existent drive */
+#define        UTCS2_PE        0x2000          /* parity error */
+#define        UTCS2_WCE       0x4000          /* write check error */
+#define        UTCS2_DLT       0x8000          /* data late */
+
+#define        UTCS2_BITS \
+"\10\20DLT\17WCE\16PE\15NED\14\NEM\13\PGE\12\MXF\11RPE\10OR\7IR\6CLR\5PAT\4\BAI"
+
+/*
+ * utds --
+ *   beginning of tape, end of tape, error summary bit, plus lots more
+ */
+#define        UTDS_SLA        0x0001          /* slave attention */
+#define        UTDS_BOT        0x0002          /* beginning of tape */
+#define        UTDS_TM         0x0004          /* tape mark */
+#define        UTDS_IDB        0x0008          /* identification burst */
+#define        UTDS_SDWN       0x0010          /* slowing down */
+#define        UTDS_PES        0x0020          /* phase encode status */
+#define        UTDS_SSC        0x0040          /* slave status change */
+#define        UTDS_DRY        0x0080          /* drive ready */
+#define        UTDS_DPR        0x0100          /* drive present (always 1) */
+#define        UTDS_GCR        0x0200          /* GCR status */
+#define        UTDS_EOT        0x0400          /* end of tape */
+#define        UTDS_WRL        0x0800          /* write lock */
+#define        UTDS_MOL        0x1000          /* medium on line */
+#define        UTDS_PIP        0x2000          /* positioning in progress */
+#define        UTDS_ERR        0x4000          /* composite error */
+#define        UTDS_ATA        0x8000          /* attention active */
+
+#define        UTDS_BITS \
+"\10\20ATA\17ERR\16PIP\15MOL\14WRL\13EOT\12GCR\11DPR\10DRY\
+\7SSC\6PES\5SDWN\4IDB\3TM\2BOT\1SLA"
+
+/*
+ * uter --
+ *   detailed breakdown of error summary bit from cs2
+ */
+#define        UTER_ILF        0x0001          /* illegal function */
+#define        UTER_ILR        0x0002          /* illegal register (always 0) */
+#define        UTER_RMR        0x0004          /* register modification refused */
+#define        UTER_RPE        0x0008          /* read data parity error */
+#define        UTER_FMT        0x0010          /* format error */
+#define        UTER_DPAR       0x0020          /* data bus parity error */
+#define        UTER_INC        0x0040          /* incorrectable data */
+#define        UTER_PEF        0x0080          /* PE format error */
+#define        UTER_NSG        0x0100          /* non standard gap */
+#define        UTER_FCE        0x0200          /* frame count error */
+#define        UTER_CS         0x0400          /* correctable skew */
+#define        UTER_NEF        0x0800          /* non executable function */
+#define        UTER_DTE        0x1000          /* drive timing error */
+#define        UTER_OPI        0x2000          /* operation incomplete */
+#define        UTER_UNS        0x4000          /* unsafe */
+#define        UTER_COR        0x8000          /* correctible data error */
+
+/*
+ * These errors we consider "hard"; UTER_OPI and UTER_RPE
+ * are considered "soft", at least for the moment.
+ */
+#define        UTER_HARD       (UTER_UNS|UTER_NEF|UTER_DPAR|UTER_FMT|UTER_RMR|\
+                        UTER_ILR|UTER_ILF)
+
+#define        UTER_BITS \
+"\10\20COR\17UNS\16OPI\15DTE\14NEF\13CS\12FCE\11NSG\10PEF\
+\7INC\6DPAR\5FMT\4RPE\3RMR\2ILR\1ILF"
+
+/*
+ * uttc --
+ *   tape format and density
+ */
+/* bits 0-2 are slave select */
+#define        UTTC_EVPAR      0x0008          /* even parity */
+#define        UTTC_FMT        0x00f0          /* format select (see below) */
+#define        UTTC_DEN        0x0700          /* density select (see below) */
+/* bit 11 not used */
+#define        UTTC_EAODTE     0x1000          /* (not emulated) */
+#define        UTTC_TCW        0x2000          /* tape control write */
+#define        UTTC_FCS        0x4000          /* frame count status */
+#define        UTTC_ACCL       0x8000          /* acceleration */
+
+/* the bits to stuff in UTTC_DEN */
+#define        UT_NRZI         0x0000          /* 800 bpi code */
+#define        UT_PE           0x0400          /* 1600 bpi code */
+#define        UT_GCR          0x0500          /* 6250 bpi code */
+
+/* tape formats - only PDP-11 standard is supported */
+#define        PDP11FMT        0x00c0          /* PDP-11 standard */
+
+#define        b_repcnt  b_bcount
+#define        b_command b_resid
+#define        b_state   b_active  
diff --git a/usr/src/sys/vaxuba/uu.c b/usr/src/sys/vaxuba/uu.c
new file mode 100644 (file)
index 0000000..1d9175c
--- /dev/null
@@ -0,0 +1,836 @@
+/*     uu.c    6.1     83/07/29        */
+
+#include "uu.h"
+#if NUU > 0
+/*
+ * TU58 DECtape II/DL11 device driver
+ *
+ * The TU58 is treated as a block device (only).  Error detection and
+ * recovery is not very extensive, but sufficient to handle the most
+ * common errors. It is assumed that the TU58 will follow the RSP 
+ * protocol exactly, very few protocol errors are checked for.  
+ *
+ * To reduce interrupt latency, `options UUDMA' should be specified 
+ * in the config file to make sure the `pseudo-DMA' code in locore.s
+ * will be compiled into the system. Otherwise overrun errors will 
+ * occur frequently (these errors are not reported).
+ *
+ * TODO:
+ *
+ * - Add ioctl code to wind/rewind cassette
+ *
+ */
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/errno.h"
+#include "../h/file.h"
+
+#include "../vax/cpu.h"
+#include "../vax/nexus.h"
+#include "../vax/rsp.h"
+
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/uureg.h"
+
+#define        NTUBLK  512             /* number of blocks on a TU58 cassette */
+#define        WRV     01              /* bit in minor dev => write w. read verify */
+#define        NDPC    02              /* drives per controller */
+#define        NUX     NDPC * NUU      /* number of drives */
+#define        NUUQ    02              /* # of block which can be queued up */
+#define        UMASK   01              /* unit number mask */
+#define UUIPL  0x14            /* ipl level to use */
+
+struct packet uucmd[NUU];      /* a command sent to the TU58 */
+struct packet uudata[NUU];     /* a command or data returned from TU58 */
+struct buf uitab[NUU];         /* buffer queue headers */
+
+/*
+ * Driver soft carrier structure
+ */
+struct uu_softc {
+       u_char  *tu_rbptr;      /* pointer to buffer for read */
+       int     tu_rcnt;        /* how much to read */
+       u_char  *tu_wbptr;      /* pointer to buffer for write */
+       int     tu_wcnt;        /* how much to write */
+       int     tu_state;       /* current state of tansfer operation */
+       int     tu_flag;        /* read in progress flag */
+       char    *tu_addr;       /* real buffer data address */
+       int     tu_count;       /* real requested count */
+       int     tu_serrs;       /* count of soft errors */
+       int     tu_cerrs;       /* count of checksum errors */
+       int     tu_herrs;       /* count of hard errors */
+       char    tu_dopen[2];    /* drive is open */
+} uu_softc[NUU];
+
+#if defined(VAX750) || defined(VAX730)
+extern char *tustates[];
+#else
+char *tustates[TUS_NSTATES] = {
+       "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
+       "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
+};
+#endif
+
+#define        UNIT(dev)       (minor(dev)>>1)
+
+u_char uunull[2] = { 0, 0 };           /* nulls to send for initialization */
+u_char uuinit[2] = { TUF_INITF, TUF_INITF };   /* inits to send */
+
+struct uba_device      *uudinfo[NUU];
+
+int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
+u_short uustd[] = { 0176500 };
+struct uba_driver uudriver =
+    { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
+
+int    uuwstart;
+int    uuwake();
+static char uu_pcnt[NUX];              /* pee/vee counters, one per drive */
+
+/*ARGSUSED*/
+uuprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;                  /* value result */
+       struct uudevice *uuaddr = (struct uudevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       uurintr(0); uuxintr(0);
+#endif
+       uuaddr->tcs = UUCS_INTR;
+       DELAY(1000);
+       uuaddr->tcs = 0;
+       cvec -= 4;              /* since we are using the xmitter intrpt */
+       return(sizeof (*uuaddr));
+}
+
+uuattach(ui)
+       register struct uba_device *ui;
+{
+}
+
+/*ARGSUSED1*/
+uuopen(dev, flag)
+       dev_t dev;
+       int flag;       
+{
+       register struct uba_device *ui;
+       register struct uu_softc *uuc;
+       register struct uudevice *uuaddr;
+       int ctlr, unit = UNIT(dev), s;
+
+       ctlr = unit / NDPC;
+       if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       uuc = &uu_softc[ctlr];
+       if (uuc->tu_dopen[unit&UMASK])
+               return (EBUSY);
+       if (uuwstart++ == 0)
+               timeout(uuwatch, (caddr_t)0, hz);
+
+       uuc->tu_dopen[unit&UMASK]++;
+       uuaddr = (struct uudevice *)ui->ui_addr;
+       s = splx(UUIPL);
+       /*
+        * If the other device on this controller
+        * is already active, no need to initialize
+        */
+       if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
+               goto ok;
+
+       /*
+        * If the unit already initialized,
+        * just enable interrupts and return.
+        */
+       if (uuc->tu_state == TUS_IDLE) {
+               uuaddr->rcs = UUCS_INTR;
+               goto ok;
+       }
+
+       /* 
+        * Must initialize, reset the cassette
+        * and wait for things to settle down.
+        */
+       uureset(ctlr);
+       sleep((caddr_t)uuc, PZERO+1);
+       uitab[ctlr].b_active = NULL;
+       if (uuc->tu_state != TUS_IDLE) {
+               uuc->tu_state = TUS_INIT1;
+               uuc->tu_dopen[unit&UMASK] = 0;
+               uuc->tu_rcnt = uuc->tu_wcnt = 0;
+               uuaddr->rcs = 0;
+               uuaddr->tcs = 0;
+               splx(s);
+               return (EIO);
+       }
+ok:
+       splx(s);
+       return (0);
+}
+
+/*
+ * Wait for all outstanding IO on this drive
+ * complete, before closing. If both drives on
+ * this controller are idle, mark the controller
+ * `inactive'.
+ */
+
+uuclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       int s, unit = UNIT(dev);
+       register struct uu_softc *uuc = &uu_softc[unit/NDPC];
+       struct buf *bp, *last = NULL;
+       struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
+
+       s = splx(UUIPL);
+       while (uu_pcnt[unit])
+               sleep(&uu_pcnt[unit], PRIBIO);
+       /*
+        * No more writes are pending, scan the 
+        * buffer queue for oustanding reads from
+        * this unit.
+        */
+       for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) {
+               if (bp->b_dev == dev)
+                       last = bp;
+       }
+       if (last) {
+               last->b_flags |= B_CALL;
+               last->b_iodone = uuwake;
+               sleep((caddr_t)last, PRIBIO);
+       }
+       uuc->tu_dopen[unit&UMASK] = 0;
+       if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
+               uuc->tu_flag = 0;
+               uuaddr->rcs = 0;
+       }
+       splx(s);
+}
+
+uuwake(bp)
+       struct buf *bp;
+{
+       wakeup(bp);
+}
+
+uureset(ctlr)
+       int ctlr;
+{
+       register struct uu_softc *uuc = &uu_softc[ctlr];
+       register struct packet *cmd = &uucmd[ctlr];
+       struct uba_device *ui = uudinfo[ctlr];
+       register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
+
+       uitab[ctlr].b_active++;
+       uuc->tu_state = TUS_INIT1;
+       uuc->tu_wbptr = uunull;
+       uuc->tu_wcnt = sizeof (uunull);
+       uuc->tu_rcnt = 0;
+       cmd->pk_flag = TUF_CMD;
+       cmd->pk_mcount = sizeof (*cmd) - 4;
+       cmd->pk_mod = 0;
+       cmd->pk_seq = 0;
+       cmd->pk_sw = 0;
+       uuaddr->rcs = 0;
+       uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
+       uuxintr(ctlr);                          /* start output */
+}
+
+/*
+ * Strategy routine for block I/O
+ */
+uustrategy(bp)
+       register struct buf *bp;
+{
+       register struct buf *uutab;
+       struct uba_device *ui;
+       int s, unit = UNIT(bp->b_dev);
+
+       if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
+               goto bad;
+       ui = uudinfo[unit/NDPC];
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       uutab = &uitab[unit/NDPC];      /* one request queue per controller */
+       s = splx(UUIPL);
+       if ((bp->b_flags&B_READ) == 0)
+               tu_pee(&uu_pcnt[unit]);
+       bp->b_actf = NULL;
+       if (uutab->b_actf == NULL)
+               uutab->b_actf = bp;
+       else
+               uutab->b_actl->b_actf = bp;
+       uutab->b_actl = bp;
+       if (uutab->b_active == 0)
+               uustart(ui);
+       splx(s);
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       bp->b_error = ENXIO;
+       iodone(bp);
+       return;
+}
+
+/*
+ * Start the transfer
+ */
+uustart(ui)
+       register struct uba_device *ui;
+{
+       register struct buf *bp;
+       register struct uu_softc *uuc;
+       struct packet *cmd;
+       int ctlr = ui->ui_unit, s;
+
+       if ((bp = uitab[ctlr].b_actf) == NULL)
+               return;
+       s = splx(UUIPL);
+       uuc = &uu_softc[ctlr];
+       if (uuc->tu_state != TUS_IDLE) {
+               uureset(ctlr);
+               splx(s);
+               return;
+       }
+       cmd = &uucmd[ctlr];
+       uitab[ctlr].b_active++;
+       uitab[ctlr].b_errcnt = 0;
+       uuc->tu_addr = bp->b_un.b_addr;
+       uuc->tu_count = cmd->pk_count = bp->b_bcount;
+       cmd->pk_block = bp->b_blkno;
+       if (bp->b_flags&B_READ) {
+               cmd->pk_op = TUOP_READ;
+               cmd->pk_mod = 0;
+               uuc->tu_state = TUS_SENDR;
+       } else {
+               cmd->pk_op = TUOP_WRITE;
+               cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
+               uuc->tu_state = TUS_SENDW;
+       }
+       cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
+       cmd->pk_sw = 0;
+       cmd->pk_chksum =
+           tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
+       uuc->tu_wbptr = (u_char *)cmd;
+       uuc->tu_wcnt = sizeof (*cmd);
+       uuxintr(ctlr);
+       splx(s);
+}
+
+/*
+ * TU58 receiver interrupt, handles whatever condition the
+ * pseudo DMA routine in locore is unable to handle, 
+ * or, if UUDMA is undefined, handle all receiver interrupt
+ * processing.
+ */
+uurintr(ctlr)
+       int ctlr;
+{
+       struct uba_device *ui = uudinfo[ctlr];
+       register struct uu_softc *uuc = &uu_softc[ctlr];
+       register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
+       register struct buf *uutab = &uitab[ctlr];
+       struct packet *data, *cmd;
+       struct buf *bp;
+       int c, unit;
+
+       c = uuaddr->rdb;
+       data = &uudata[ctlr];
+       cmd = &uucmd[ctlr];
+#if !defined(UUDMA)
+       if (c & UURDB_ERROR)
+               uuc->tu_state = TUS_RCVERR;
+       else {
+               if (uuc->tu_rcnt) {
+                       *uuc->tu_rbptr++ = c;
+                       if (--uuc->tu_rcnt)
+                               return;
+               }
+       }
+#endif
+
+       /*
+        * Switch on the tu_state of the transfer.
+        */
+       switch(uuc->tu_state) {
+
+       /*
+        * A data error occured in uudma
+        * (either overrun or break)
+        */
+       case TUS_RCVERR:
+               if ((c & UURDB_ORUN) == 0)
+                       printf("uu%d: break received, transfer restarted\n",
+                           data->pk_unit);
+#ifdef UUDEBUG
+               else
+                       printf("uu%d: data overrun, recovered\n", 
+                           data->pk_unit);
+#endif
+               uuc->tu_serrs++;
+               uu_restart(ctlr, ui);   
+               break;
+
+       /*
+        * If we get an unexpected "continue",
+        * start all over again...
+        */
+       case TUS_INIT2:
+               uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
+               uuc->tu_flag = 0;
+               wakeup((caddr_t)uuc);
+               uustart(ui);
+               break;
+
+       /*
+        * Only transition from this state
+        * is on a "continue", so if we don't
+        * get it, reset the world.
+        */
+       case TUS_WAIT:                  /* waiting for continue */
+               switch(c) {
+               case TUF_CONT:  /* got the expected continue */
+                       uuc->tu_flag = 0;
+                       data->pk_flag = TUF_DATA;
+                       data->pk_mcount = MIN(128, uuc->tu_count);
+                       data->pk_chksum =
+                           tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
+                               (int)data->pk_mcount);
+                       uuc->tu_state = TUS_SENDH;
+                       uuc->tu_wbptr = (u_char *)data;
+                       uuc->tu_wcnt = 2;
+                       uuxintr(ctlr);
+                       break;
+
+               case TUF_CMD:   /* sending us an END packet...error */
+                       uuc->tu_state = TUS_GET;
+                       uuc->tu_rbptr = (u_char *)data;
+                       uuc->tu_rcnt = sizeof (*data) - 1;
+                       uuc->tu_flag = 1;
+                       uuaddr->tcs = 0;
+                       *uuc->tu_rbptr++ = c & UUDB_DMASK;
+                       break;
+
+               case TUF_INITF:
+                       uureset(ctlr);
+                       break;
+
+               default:        /* something random...bad news */
+                       uuc->tu_state = TUS_INIT1;
+                       break;
+               }
+               break;
+
+       case TUS_SENDW:
+               if (c != TUF_CONT && c != TUF_INITF)
+                       goto bad;
+               uu_restart(ctlr, ui);
+               break;
+
+       /*
+        * Got header, now get data; amount to
+        * fetch is included in packet.
+        * (data packets are handled entirely
+        * in uudma)
+        */
+       case TUS_GETH:
+#ifndef UUDMA
+               if (data->pk_flag == TUF_DATA)
+                       uuc->tu_rbptr = (u_char *)uuc->tu_addr;
+#endif
+               uuc->tu_rcnt = data->pk_mcount;
+               uuc->tu_state = TUS_GETD;
+               break;
+
+       /*
+        * Got the data, now fetch the checksum.
+        */
+       case TUS_GETD:
+               uuc->tu_rbptr = (u_char *)&data->pk_chksum;
+               uuc->tu_rcnt = sizeof (data->pk_chksum);
+               uuc->tu_state = TUS_GETC;
+               break;
+
+       case TUS_GETC:
+               /* got entire packet */
+               if (data->pk_chksum !=
+                   tuchk(*((short *)data), (u_short *)
+                    (data->pk_flag == TUF_DATA ?
+                    (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
+                    (int)data->pk_mcount))
+       case TUS_CHKERR:
+                       uuc->tu_cerrs++;
+       case TUS_GET:
+               if (data->pk_flag == TUF_DATA) {
+                       /* data packet, advance to next */
+                       uuc->tu_addr += data->pk_mcount;
+                       uuc->tu_count -= data->pk_mcount;
+                       uuc->tu_state = TUS_GETH;
+                       uuc->tu_rbptr = (u_char *)data; /* next packet */
+                       uuc->tu_rcnt = 2;
+               } else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
+                       /* end packet, idle and reenable transmitter */
+                       uuc->tu_state = TUS_IDLE;
+                       uuc->tu_flag = 0;
+                       uuaddr->tcs = UUCS_INTR;
+                       if ((bp = uutab->b_actf) == NULL) {
+                               printf("uu%d: no bp, active %d\n", 
+                                   data->pk_unit, uitab[ctlr].b_active);
+                               uustart(ui);
+                               return;
+                       }
+                       unit = UNIT(bp->b_dev);
+                       if (data->pk_mod > 1) {        /* hard error */
+                               printf("uu%d: hard error bn%d,", unit, 
+                                   bp->b_blkno);
+                               printf(" pk_mod 0%o\n", data->pk_mod&0xff);
+                               bp->b_flags |= B_ERROR;
+                               uuc->tu_herrs++;
+                       } else if (data->pk_mod)        /* soft error */
+                               uuc->tu_serrs++;
+                       uutab->b_active = NULL;
+                       uutab->b_actf = bp->b_actf;
+                       bp->b_resid = uuc->tu_count;
+                       if ((bp->b_flags&B_READ) == 0)
+                               tu_vee(&uu_pcnt[unit]);
+                       iodone(bp);
+                       uustart(ui);
+               } else {
+                       /*
+                        * Neither data nor end: data was lost
+                        * somehow, flush and restart the transfer.
+                        */
+                       uuaddr->rcs = 0;
+                       uu_restart(ctlr, ui);
+                       uuc->tu_serrs++;
+               }
+               break;
+
+       case TUS_IDLE:
+       case TUS_INIT1:
+               break;
+
+       default:
+bad:
+               if (c == TUF_INITF) {
+                       printf("uu%d protocol error, state=", data->pk_unit);
+                       printstate(uuc->tu_state);
+                       printf(", op=%x, cnt=%d, block=%d\n",
+                           cmd->pk_op, cmd->pk_count, cmd->pk_block);
+                       uutab->b_active = NULL;
+                       if (bp = uutab->b_actf) {
+                               bp->b_flags |= B_ERROR;
+                               uutab->b_actf = bp->b_actf;
+                               if ((bp->b_flags&B_READ) == 0)
+                                       tu_vee(&uu_pcnt[unit]);
+                               iodone(bp);
+                       }
+                       uuc->tu_state = TUS_INIT1;
+               } else {
+                       printf("uu%d receive state error, state=", 
+                               data->pk_unit);
+                       printstate(uuc->tu_state);
+                       printf(", byte=%x\n", c & 0xff);
+#ifdef notdef
+                       uuc->tu_state = TUS_INIT1;
+#endif
+                       wakeup((caddr_t)uuc);
+               }
+       }
+}
+
+
+/*
+ * TU58 transmitter interrupt
+ */
+uuxintr(ctlr)
+       int ctlr;
+{
+       register struct uu_softc *uuc = &uu_softc[ctlr];
+       register struct uudevice *uuaddr;
+       register struct packet *data;
+       struct uba_device *ui = uudinfo[ctlr];
+       int c;
+
+       data = &uudata[ctlr];
+       uuaddr = (struct uudevice *) ui->ui_addr;
+top:
+       if (uuc->tu_wcnt > 0) {
+               /* still stuff to send, send one byte */
+               while ((uuaddr->tcs & UUCS_READY) == 0)
+                       ;
+               uuaddr->tdb = *uuc->tu_wbptr++;
+               uuc->tu_wcnt--;
+               return;
+       }
+
+       /*
+        * Last message byte was sent out.
+        * Switch on tu_state of transfer.
+        */
+       switch(uuc->tu_state) {
+
+       /*
+        * Two nulls have been sent, remove break, and send inits
+        */
+       case TUS_INIT1: 
+               uuc->tu_flag = 0;
+               uuaddr->tcs = UUCS_INTR;
+               uuc->tu_state = TUS_INIT2;
+               uuc->tu_wbptr = uuinit;
+               uuc->tu_wcnt = sizeof (uuinit);
+               goto top;
+
+       /*
+        * Inits have been sent, wait for a continue msg.
+        */
+       case TUS_INIT2: 
+               c = uuaddr->rdb;        /* prevent overrun error */
+               uuaddr->rcs = UUCS_INTR;
+               uuc->tu_flag = 1;
+               break;
+
+       /*
+        * Read cmd packet sent, get ready for data
+        */
+       case TUS_SENDR:
+               uuc->tu_state = TUS_GETH;
+               uuc->tu_rbptr = (u_char *)data;
+               uuc->tu_rcnt = 2;
+               uuc->tu_flag = 1;
+               uuaddr->tcs = 0;
+               uuaddr->rcs = UUCS_INTR;
+               break;
+
+       /*
+        * Write cmd packet sent, wait for continue
+        */
+       case TUS_SENDW: 
+               uuc->tu_state = TUS_WAIT;
+               uuc->tu_flag = 1;
+               if ((uuaddr->rcs&UUCS_INTR) == 0) {
+                       printf("NO IE\n");
+                       uuaddr->rcs = UUCS_INTR;
+               }
+               break;
+
+       /*
+        * Header sent, send data.
+        */
+       case TUS_SENDH:
+               uuc->tu_state = TUS_SENDD;
+               uuc->tu_wbptr = (u_char *)uuc->tu_addr;
+               uuc->tu_wcnt = data->pk_mcount;
+               goto top;
+
+       /*
+        * Data sent, follow with checksum.
+        */
+       case TUS_SENDD: 
+               uuc->tu_state = TUS_SENDC;
+               uuc->tu_wbptr = (u_char *)&data->pk_chksum;
+               uuc->tu_wcnt = 2;
+               goto top;
+
+       /* 
+        * Checksum sent, wait for continue.
+        */
+       case TUS_SENDC:
+               /*
+                * Update buffer address and count.
+                */
+               uuc->tu_addr += data->pk_mcount;
+               uuc->tu_count -= data->pk_mcount;
+               if (uuc->tu_count > 0) {
+                       uuc->tu_state = TUS_WAIT;
+                       uuc->tu_flag = 1;
+                       break;
+               }
+
+               /*
+                * End of transmission, get ready for end packet.
+                */
+               uuc->tu_state = TUS_GET;
+               uuc->tu_rbptr = (u_char *)data;
+               uuc->tu_rcnt = sizeof (*data);
+               uuc->tu_flag = 1;
+               uuaddr->tcs = 0;
+               break;
+
+       /*
+        * Random interrupt
+        */
+       case TUS_IDLE:          /* stray interrupt? */
+
+       default:
+               break;
+       }
+}
+
+uuwatch()
+{
+       register struct uu_softc *uuc;
+       register struct uudevice *uuaddr;
+       struct uba_device *ui;
+       struct buf *bp, *uutab;
+       int s, ctlr, active = 0;
+
+       for (ctlr=0; ctlr<NUU; ctlr++) {
+               int i;
+
+               uuc = &uu_softc[ctlr];
+
+               if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
+                       active++;
+               if (uuc->tu_flag == 0)
+                       /*
+                        * If no read is in progress
+                        * just skip
+                        */
+                       continue;
+
+               ui = uudinfo[ctlr];
+               uuaddr = (struct uudevice *)ui->ui_addr;
+               uutab = &uitab[ctlr];
+               if (uuc->tu_flag++ < 40)
+                       continue;
+               printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
+#ifdef UUDEBUG
+               printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt,
+                      uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr,
+                      uuc->tu_count);
+#endif
+               s = splx(UUIPL);
+               uuc->tu_flag = 0;
+               i = uuaddr->rdb;                /* dummy */
+               uuaddr->rcs = UUCS_INTR;        /* in case we were flushing */
+               uuaddr->tcs = UUCS_INTR;
+               uuc->tu_state = TUS_IDLE;
+               if (!uutab->b_active) {
+                       wakeup((caddr_t)uuc);
+                       goto retry;
+               }
+               if (++uutab->b_errcnt <= 1) {
+                       uustart(ui);
+                       goto retry;
+               }
+               if (bp = uutab->b_actf) {
+                       bp->b_flags |= B_ERROR;
+                       if ((bp->b_flags&B_READ) == 0)
+                               tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
+                       iodone(bp);
+               }
+retry:
+               (void) splx(s);
+       }
+       if (active)
+               timeout(uuwatch, (caddr_t)0, hz);
+       else
+               uuwstart = 0;
+       return;
+}
+
+#if !defined(VAX750) && !defined(VAX730)
+/*
+ * Compute checksum TU58 fashion
+ */
+#ifdef lint
+tuchk(word, cp, n)
+       register word;
+       register unsigned short *cp;
+       int n;
+{
+       register int c = n >> 1;
+       register long temp;
+
+       do {
+               temp = *cp++;   /* temp, only because vax cc won't *r++ */
+               word += temp;
+       } while (--c > 0);
+       if (n & 1)
+               word += *(unsigned char *)cp;
+       while (word & 0xffff0000)
+               word = (word & 0xffff) + ((word >> 16) & 0xffff);
+       return (word);
+}
+#else
+tuchk(word0, wp, n)
+       register int word0;                     /* r11 */
+       register char *wp;                      /* r10 */
+       register int n;                         /* r9 */
+{
+       asm("loop:");
+       asm("   addw2   (r10)+,r11");           /* add a word to sum */
+       asm("   adwc    $0,r11");               /* add in carry, end-around */
+       asm("   acbl    $2,$-2,r9,loop");       /* done yet? */
+       asm("   blbc    r9,ok");                /* odd byte count? */
+       asm("   movzbw  (r10),r10");            /* yes, get last byte */
+       asm("   addw2   r10,r11");              /* add it in */
+       asm("   adwc    $0,r11");               /* and the carry */
+       asm("ok:");
+       asm("   movl    r11,r0");               /* return sum */
+}
+#endif
+
+/*
+ * Make sure this incredibly slow device
+ * doesn't eat up all the buffers in the
+ * system by putting the requesting process
+ * (remember: this device is 'single-user')
+ * to sleep if the write-behind queue grows
+ * larger than NUUQ.
+ */
+tu_pee(cp)
+       char *cp;
+{
+       register int s;
+
+       s = splx(UUIPL);
+       if (++(*cp) > NUUQ) 
+               sleep(cp, PRIBIO);
+       splx(s);
+}
+
+tu_vee(cp)
+       char *cp;
+{
+       register int s;
+
+       s = splx(UUIPL);
+       if (--(*cp) <= NUUQ) 
+               wakeup(cp);
+       splx(s);
+}
+#endif
+
+uuioctl(dev, cmd, data, flag)
+       dev_t dev;
+       caddr_t data;
+{
+       /*
+        * add code to wind/rewind cassette here
+        */
+       return (ENXIO);
+}
+
+uu_restart(ctlr, ui)
+       int ctlr;
+       struct uba_device *ui;
+{
+       uureset(ctlr);
+       timeout(uustart, (caddr_t)ui, hz * 3);
+}
+
+#endif
diff --git a/usr/src/sys/vaxuba/uureg.h b/usr/src/sys/vaxuba/uureg.h
new file mode 100644 (file)
index 0000000..44e7c7b
--- /dev/null
@@ -0,0 +1,31 @@
+
+/*     uureg.h 6.1     83/07/29        */
+
+/*
+ * DL11-E/DL11-W UNIBUS (for TU58) controller registers
+ */
+struct uudevice {
+       short   rcs;    /* receiver status register */
+       short   rdb;    /* receiver data buffer register */
+       short   tcs;    /* transmitter status register */
+       short   tdb;    /* transmitter data buffer register */
+};
+
+/*
+ * Receiver/transmitter status register status/command bits
+ */
+#define UUCS_DONE      0x80    /* done/ready */
+#define        UUCS_READY      0x80
+#define UUCS_INTR      0x40    /* interrupt enable */
+#define        UUCS_MAINT      0x02    /* maintenance check (xmitter only) */
+#define        UUCS_BREAK      0x01    /* send break (xmitter only) */
+
+/*
+ * Receiver data buffer register status bits
+ */
+#define        UURDB_ERROR     0x8000  /* Error (overrun or break) */
+#define UURDB_ORUN     0x4000  /* Data overrun error */
+#define        UURDB_BREAK     0x2000  /* TU58 break */
+
+#define        UUDB_DMASK      0x00ff  /* data mask (send and receive data) */
+
diff --git a/usr/src/sys/vaxuba/va.c b/usr/src/sys/vaxuba/va.c
new file mode 100644 (file)
index 0000000..020f19a
--- /dev/null
@@ -0,0 +1,468 @@
+/*     va.c    6.1     83/07/29        */
+
+#include "va.h"
+#if NVA > 0
+/*
+ * Varian printer plotter
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/ioctl.h"
+#include "../h/vcmd.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+int    vadebug = 0;
+#define        dprintf if(vadebug)printf
+
+unsigned minvaph();
+
+#define        VAPRI   (PZERO-1)
+
+struct vadevice {
+       u_short vaba;                   /* buffer address */
+       short   vawc;                   /* word count (2's complement) */
+       union {
+               short   Vacsw;          /* control status as word */
+               struct {                /* control status as bytes */
+                       char Vacsl;
+                       char Vacsh;
+               } vacsr;
+       } vacs;
+       short   vadata;                 /* programmed i/o data buffer */
+};
+
+#define        vacsw   vacs.Vacsw
+#define        vacsh   vacs.vacsr.Vacsh
+#define        vacsl   vacs.vacsr.Vacsl
+
+/* vacsw bits */
+#define        VA_ERROR        0100000         /* some error has occurred */
+#define        VA_NPRTIMO      0001000         /* DMA timeout error */
+#define        VA_NOTREADY     0000400         /* something besides NPRTIMO */
+#define        VA_DONE         0000200
+#define        VA_IENABLE      0000100         /* interrupt enable */
+#define        VA_DMAGO        0000010         /* DMA go bit */
+#define        VA_DMAGO        0000010         /* DMA go bit */
+#define        VA_SUPPLIESLOW  0000004
+#define        VA_BOTOFFORM    0000002
+#define        VA_BYTEREVERSE  0000001         /* reverse byte order in words */
+
+/* vacsh command bytes */
+#define        VAPLOT          0000340
+#define        VAPRINT         0000100
+#define        VAPRINTPLOT     0000160
+#define        VAAUTOSTEP      0000244
+#define        VANOAUTOSTEP    0000045
+#define        VAFORMFEED      0000263
+#define        VASLEW          0000265
+#define        VASTEP          0000064
+
+struct va_softc {
+       u_char  sc_openf;               /* exclusive open flag */
+       u_char  sc_iostate;             /* kind of I/O going on */
+#define        VAS_IDLE        0       /* no I/O, free */
+#define        VAS_PIO         1       /* programmed I/O */
+#define        VAS_DMA         2       /* DMA, block pio */
+#define        VAS_WANT        4       /* wakeup when iostate changes */
+       short   sc_tocnt;               /* time out counter */
+       short   sc_info;                /* csw passed from vaintr */
+       int     sc_state;               /* print/plot state of device */
+} va_softc[NVA];
+
+#define        VAUNIT(dev)     (minor(dev))
+
+struct buf rvabuf[NVA];
+
+int    vaprobe(), vaslave(), vaattach(), vadgo();
+struct uba_device *vadinfo[NVA];
+struct uba_ctlr *vaminfo[NVA];
+struct buf vabhdr[NVA];
+u_short        vastd[] = { 0764000, 0 };
+struct uba_driver vadriver =
+    { vaprobe, vaslave, vaattach, vadgo, vastd, "vz", vadinfo, "va", vaminfo };
+
+vaprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* value-result */
+       register struct vadevice *vaaddr = (struct vadevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       vaintr(0);
+#endif
+#ifndef UCBVAX
+       vaaddr->vacsl = VA_IENABLE;
+       vaaddr->vaba = 0;
+       vaaddr->vacsh = VAPLOT;
+       vaaddr->vacsl = VA_IENABLE|VA_DMAGO;
+       vaaddr->vawc = -1;
+       DELAY(10000);
+       vaaddr->vacsl = 0;
+       vaaddr->vawc = 0;
+#else
+       br=0x14;
+       cvec=0170;
+#endif
+       return (sizeof (struct vadevice));
+}
+
+/*ARGSUSED*/
+vaslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+
+       ui->ui_dk = 0;
+       return (ui->ui_unit <= 0);
+}
+
+/*ARGSUSED*/
+vaattach(ui)
+       struct uba_device *ui;
+{
+
+       ui->ui_mi->um_tab.b_actf = &vabhdr[ui->ui_unit];
+}
+
+vaopen(dev)
+       dev_t dev;
+{
+       register struct va_softc *sc;
+       register struct vadevice *vaaddr;
+       register struct uba_device *ui;
+       int error;
+       int unit = VAUNIT(dev);
+
+       if (unit >= NVA || (sc = &va_softc[unit])->sc_openf ||
+           (ui = vadinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       vaaddr = (struct vadevice *)ui->ui_addr;
+       sc->sc_openf = 1;
+       vaaddr->vawc = 0;
+       sc->sc_state = 0;
+       sc->sc_tocnt = 0;
+       sc->sc_iostate = VAS_IDLE;
+       vaaddr->vacsl = VA_IENABLE;
+       vatimo(dev);
+       error = vacmd(dev, VPRINT);
+       if (error)
+               vaclose(dev);
+       return (error);
+}
+
+vastrategy(bp)
+       register struct buf *bp;
+{
+       register struct uba_device *ui;
+       register struct uba_ctlr *um;
+       int s;
+
+       dprintf("vastrategy(%x)\n", bp);
+       ui = vadinfo[VAUNIT(bp->b_dev)];
+       if (ui == 0 || ui->ui_alive == 0) {
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               return;
+       }
+       s = spl4();
+       um = ui->ui_mi;
+       bp->b_actf = NULL;
+       if (um->um_tab.b_actf->b_actf == NULL)
+               um->um_tab.b_actf->b_actf = bp;
+       else {
+               printf("bp = 0x%x, um->um_tab.b_actf->b_actf = 0x%x\n",
+                       bp, um->um_tab.b_actf->b_actf);
+               panic("vastrategy");
+               um->um_tab.b_actf->b_actl->b_forw = bp;
+       }
+       um->um_tab.b_actf->b_actl = bp;
+       bp = um->um_tab.b_actf;
+       dprintf("vastrategy: bp=%x actf=%x active=%d\n",
+               bp, bp->b_actf, bp->b_active);
+       if (bp->b_actf && bp->b_active == 0)
+               (void) vastart(um);
+       splx(s);
+}
+
+int    vablock = 16384;
+
+unsigned
+minvaph(bp)
+       struct buf *bp;
+{
+
+       if (bp->b_bcount > vablock)
+               bp->b_bcount = vablock;
+}
+
+/*ARGSUSED*/
+vawrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+
+       if (VAUNIT(dev) > NVA)
+               return (ENXIO);
+       return (physio(vastrategy, &rvabuf[VAUNIT(dev)], dev, B_WRITE,
+                   minvaph, uio));
+}
+
+vastart(um)
+       register struct uba_ctlr *um;
+{
+       struct buf *bp;
+       struct vadevice *vaaddr;
+       register struct va_softc *sc;
+       int unit;
+
+       dprintf("vastart(%x), bp=%x\n", um, um->um_tab.b_actf->b_actf);
+       if ((bp = um->um_tab.b_actf->b_actf) == NULL)
+               return;
+       unit = VAUNIT(bp->b_dev);
+       sc = &va_softc[unit];
+       sc->sc_tocnt = 0;
+       while (sc->sc_iostate&VAS_PIO) {
+               sc->sc_iostate |= VAS_WANT;
+               sleep((caddr_t)&sc->sc_iostate, VAPRI);
+       }
+       sc->sc_iostate |= VAS_DMA;
+       vaaddr = (struct vadevice *)um->um_addr;
+       vaaddr->vacsl = 0;
+       vaaddr->vawc = -(bp->b_bcount / 2);
+       um->um_cmd = VA_DMAGO | VA_IENABLE;
+       (void) ubago(vadinfo[unit]);
+}
+
+vadgo(um)
+       register struct uba_ctlr *um;
+{
+       register struct vadevice *vaaddr = (struct vadevice *)um->um_addr;
+       register struct buf *bp;
+
+       bp = um->um_tab.b_actf;
+       va_softc[VAUNIT(bp->b_actf->b_dev)].sc_tocnt = 0;
+       bp->b_active++;
+       vaaddr->vaba = um->um_ubinfo;
+       vaaddr->vacsl = ((um->um_ubinfo >> 12) & 0x30) | um->um_cmd;
+}
+
+/*ARGSUSED*/
+vaioctl(dev, cmd, data, flag)
+       register caddr_t data;
+{
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+
+       switch (cmd) {
+
+       case VGETSTATE:
+               *(int *)data = sc->sc_state;
+               break;
+
+       case VSETSTATE:
+               return (vacmd(dev, *(int *)data));
+
+       default:
+               return (ENOTTY);
+       }
+       return (0);
+}
+
+vacmd(dev, vcmd)
+       dev_t dev;
+       int vcmd;
+{
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+       int error = 0;
+       int s, cmd;
+
+       s = spl4();
+       while (sc->sc_iostate&VAS_DMA) {
+               sc->sc_iostate |= VAS_WANT;
+               sleep((caddr_t)&sc->sc_iostate, VAPRI);
+       }
+       sc->sc_iostate |= VAS_PIO;
+       sc->sc_tocnt = 0;
+       cmd = 0;
+       switch (vcmd) {
+
+       case VPLOT:
+               /* Must turn on plot AND autostep modes. */
+               if (vadopio(dev, VAPLOT))
+                       error = EIO;
+               cmd = VAAUTOSTEP;
+               break;
+
+       case VPRINT:
+               cmd = VAPRINT;
+               break;
+
+       case VPRINTPLOT:
+               cmd = VAPRINTPLOT;
+               break;
+       }
+       sc->sc_state = (sc->sc_state & ~(VPLOT|VPRINT|VPRINTPLOT)) | vcmd;
+       if (cmd && vadopio(dev, cmd))
+               error = EIO;
+       sc->sc_iostate &= ~VAS_PIO;
+       if (sc->sc_iostate&VAS_WANT) {
+               sc->sc_iostate &= ~VAS_WANT;
+               wakeup((caddr_t)&sc->sc_iostate);
+       }
+       splx(s);
+       return (error);
+}
+
+vadopio(dev, cmd)
+       dev_t dev;
+       int cmd;
+{
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vaminfo[VAUNIT(dev)]->um_addr;
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+
+       sc->sc_info = 0;
+       vaaddr->vacsh = cmd;
+       while ((sc->sc_info&(VA_DONE|VA_ERROR)) == 0)
+               sleep((caddr_t)&sc->sc_info, VAPRI);
+       return (sc->sc_info&VA_ERROR);
+}
+
+vatimo(dev)
+       dev_t dev;
+{
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+
+       if (sc->sc_openf)
+               timeout(vatimo, (caddr_t)dev, hz/2);
+       if (++sc->sc_tocnt < 2)
+               return;
+       sc->sc_tocnt = 0;
+       dprintf("vatimo: calling vaintr\n");
+       vaintr(dev);
+}
+
+/*ARGSUSED*/
+vaintr(dev)
+       dev_t dev;
+{
+       register struct uba_ctlr *um;
+       struct vadevice *vaaddr;
+       struct buf *bp;
+       register int unit = VAUNIT(dev), e;
+       register struct va_softc *sc = &va_softc[unit];
+
+       um = vaminfo[unit];
+       vaaddr = (struct vadevice *)um->um_addr;
+       e = vaaddr->vacsw;
+       dprintf("vaintr: um=0x%x, e=0x%x, b_active %d\n",
+               um, e, um->um_tab.b_actf->b_active);
+       if ((e&(VA_DONE|VA_ERROR)) == 0)
+               return;
+       vaaddr->vacsl = 0;
+       if ((e&VA_ERROR) && (e&VA_NPRTIMO))
+               printf("va%d: npr timeout\n", unit);
+       if (sc->sc_iostate&VAS_PIO) {
+               sc->sc_info = e;
+               wakeup((caddr_t)&sc->sc_info);
+               return;
+       }
+       if (um->um_tab.b_actf->b_active) {
+               bp = um->um_tab.b_actf->b_actf;
+               if (e&VA_ERROR)
+                       bp->b_flags |= B_ERROR;
+               if (sc->sc_state&VPRINTPLOT) {
+                       sc->sc_state = (sc->sc_state & ~VPRINTPLOT) | VPLOT;
+                       vaaddr->vacsh = VAAUTOSTEP;
+                       return;
+               }
+               ubadone(um);
+               um->um_tab.b_actf->b_active = 0;
+               um->um_tab.b_actf->b_actf = bp->b_forw;
+               bp->b_active = 0;
+               bp->b_errcnt = 0;
+               bp->b_resid = 0;
+               iodone(bp);
+       }
+       if (um->um_tab.b_actf->b_actf == 0) {
+               sc->sc_iostate &= ~VAS_DMA;
+               if (sc->sc_iostate&VAS_WANT) {
+                       sc->sc_iostate &= ~VAS_WANT;
+                       wakeup((caddr_t)&sc->sc_iostate);
+               }
+               return;
+       }
+       if (um->um_tab.b_actf->b_active == 0)
+               vastart(um);
+}
+
+vaclose(dev)
+       dev_t dev;
+{
+       register struct va_softc *sc = &va_softc[VAUNIT(dev)];
+       register struct vadevice *vaaddr =
+           (struct vadevice *)vadinfo[VAUNIT(dev)]->ui_addr;
+
+       sc->sc_openf = 0;
+       sc->sc_state = 0;
+       if (sc->sc_iostate != VAS_IDLE)
+               wakeup((caddr_t)&sc->sc_iostate);
+       sc->sc_iostate = VAS_IDLE;
+       vaaddr->vacsl = 0;
+       vaaddr->vawc = 0;
+}
+
+vareset(uban)
+       int uban;
+{
+       register int va11;
+       register struct uba_ctlr *um;
+       register struct vadevice *vaaddr;
+       register struct va_softc *sc;
+
+       for (va11 = 0; va11 < NVA; va11++, sc++) {
+               if ((um = vaminfo[va11]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               sc = &va_softc[um->um_ctlr];
+               if (sc->sc_openf == 0)
+                       continue;
+               printf(" va%d", va11);
+               vaaddr = (struct vadevice *)um->um_addr;
+               vaaddr->vacsl = VA_IENABLE;
+               if (sc->sc_state & VPLOT) {
+                       vaaddr->vacsh = VAPLOT;
+                       DELAY(10000);
+                       vaaddr->vacsh = VAAUTOSTEP;
+               } else if (sc->sc_state & VPRINTPLOT)
+                       vaaddr->vacsh = VPRINTPLOT;
+               else
+                       vaaddr->vacsh = VAPRINTPLOT;
+               DELAY(10000);
+               sc->sc_iostate = VAS_IDLE;
+               um->um_tab.b_actf->b_active = 0;
+               um->um_tab.b_actf->b_actf = um->um_tab.b_actf->b_actl = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo >> 28) & 0xf);
+                       um->um_ubinfo = 0;
+               }
+               (void) vastart(um);
+       }
+}
+
+vaselect()
+{
+
+       return (1);
+}
+#endif
diff --git a/usr/src/sys/vaxuba/vpreg.h b/usr/src/sys/vaxuba/vpreg.h
new file mode 100644 (file)
index 0000000..b8b0d5e
--- /dev/null
@@ -0,0 +1,26 @@
+/*     vpreg.h 6.1     83/07/29        */
+
+#define        VPPRI   (PZERO-1)
+
+struct vpdevice {
+       short   plbcr;
+       short   pbxaddr;
+       short   prbcr;
+       u_short pbaddr;
+       short   plcsr;
+       short   plbuf;
+       short   prcsr;
+       u_short prbuf;
+};
+
+#define        VP_ERROR        0100000
+#define        VP_DTCINTR      0040000
+#define        VP_DMAACT       0020000
+#define        VP_READY        0000200
+#define        VP_IENABLE      0000100
+#define        VP_TERMCOM      0000040
+#define        VP_FFCOM        0000020
+#define        VP_EOTCOM       0000010
+#define        VP_CLRCOM       0000004
+#define        VP_RESET        0000002
+#define        VP_SPP          0000001