123359Smckusick /*
229257Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323359Smckusick * All rights reserved. The Berkeley software License Agreement
423359Smckusick * specifies the terms and conditions for redistribution.
523359Smckusick *
6*49876Sbostic * @(#)uu.c 7.6 (Berkeley) 05/25/91
723359Smckusick */
811876Shelge
912332Shelge #include "uu.h"
1012857Shelge #if NUU > 0
1111876Shelge /*
1211896Shelge * TU58 DECtape II/DL11 device driver
1311876Shelge *
1413156Shelge * The TU58 is treated as a block device (only). Error detection and
1513156Shelge * recovery is not very extensive, but sufficient to handle the most
1614091Shelge * common errors. It is assumed that the TU58 will follow the RSP
1714091Shelge * protocol exactly, very few protocol errors are checked for.
1814091Shelge *
1914091Shelge * To reduce interrupt latency, `options UUDMA' should be specified
2014091Shelge * in the config file to make sure the `pseudo-DMA' code in locore.s
2114091Shelge * will be compiled into the system. Otherwise overrun errors will
2214091Shelge * occur frequently (these errors are not reported).
2314091Shelge *
2414091Shelge * TODO:
2514091Shelge *
2614091Shelge * - Add ioctl code to wind/rewind cassette
2714091Shelge *
2811876Shelge */
2911896Shelge
3045810Sbostic #include "../include/pte.h"
3111896Shelge
3245810Sbostic #include "sys/param.h"
3345810Sbostic #include "sys/systm.h"
3445810Sbostic #include "sys/buf.h"
3545810Sbostic #include "sys/conf.h"
3645810Sbostic #include "sys/time.h"
3745810Sbostic #include "sys/kernel.h"
3845810Sbostic #include "sys/errno.h"
3945810Sbostic #include "sys/file.h"
4011876Shelge
4145810Sbostic #include "../include/cpu.h"
4212332Shelge #include "../vax/nexus.h"
4312937Shelge #include "../vax/rsp.h"
4412332Shelge
4517084Sbloom #include "ubavar.h"
4617084Sbloom #include "ubareg.h"
4717084Sbloom #include "uureg.h"
4811876Shelge
4911876Shelge #define NTUBLK 512 /* number of blocks on a TU58 cassette */
5012857Shelge #define WRV 01 /* bit in minor dev => write w. read verify */
5112332Shelge #define NDPC 02 /* drives per controller */
5212857Shelge #define NUX NDPC * NUU /* number of drives */
5314091Shelge #define NUUQ 02 /* # of block which can be queued up */
5412857Shelge #define UMASK 01 /* unit number mask */
5512937Shelge #define UUIPL 0x14 /* ipl level to use */
5611876Shelge
5712857Shelge struct packet uucmd[NUU]; /* a command sent to the TU58 */
5812857Shelge struct packet uudata[NUU]; /* a command or data returned from TU58 */
5912857Shelge struct buf uitab[NUU]; /* buffer queue headers */
6011876Shelge
6111876Shelge /*
6212937Shelge * Driver soft carrier structure
6311876Shelge */
6412937Shelge struct uu_softc {
6512937Shelge u_char *tu_rbptr; /* pointer to buffer for read */
6612937Shelge int tu_rcnt; /* how much to read */
6712937Shelge u_char *tu_wbptr; /* pointer to buffer for write */
6812937Shelge int tu_wcnt; /* how much to write */
6912937Shelge int tu_state; /* current state of tansfer operation */
7012937Shelge int tu_flag; /* read in progress flag */
7112937Shelge char *tu_addr; /* real buffer data address */
7212937Shelge int tu_count; /* real requested count */
7312937Shelge int tu_serrs; /* count of soft errors */
7412937Shelge int tu_cerrs; /* count of checksum errors */
7512937Shelge int tu_herrs; /* count of hard errors */
7612937Shelge char tu_dopen[2]; /* drive is open */
7713014Shelge } uu_softc[NUU];
7811876Shelge
7912937Shelge #if defined(VAX750) || defined(VAX730)
8012937Shelge extern char *tustates[];
8112937Shelge #else
8212937Shelge char *tustates[TUS_NSTATES] = {
8311876Shelge "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
8413014Shelge "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
8511876Shelge };
8612937Shelge #endif
8712332Shelge
8812857Shelge #define UNIT(dev) (minor(dev)>>1)
8911876Shelge
9014091Shelge u_char uunull[2] = { 0, 0 }; /* nulls to send for initialization */
9111896Shelge u_char uuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
9211876Shelge
9311896Shelge struct uba_device *uudinfo[NUU];
9411896Shelge
9512857Shelge int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
9625521Stef u_short uustd[] = { 0176500, 0 };
9712857Shelge struct uba_driver uudriver =
9812857Shelge { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
9911896Shelge
10011896Shelge int uuwstart;
10114152Shelge int uuwake();
10214091Shelge static char uu_pcnt[NUX]; /* pee/vee counters, one per drive */
10311896Shelge
10411876Shelge /*ARGSUSED*/
uuprobe(reg)10511896Shelge uuprobe(reg)
10611896Shelge caddr_t reg;
10711876Shelge {
10811896Shelge register int br, cvec; /* value result */
10911896Shelge struct uudevice *uuaddr = (struct uudevice *)reg;
11011876Shelge
11111876Shelge #ifdef lint
11211896Shelge br = 0; cvec = br; br = cvec;
11311896Shelge uurintr(0); uuxintr(0);
11411876Shelge #endif
11512857Shelge uuaddr->tcs = UUCS_INTR;
11612857Shelge DELAY(1000);
11712857Shelge uuaddr->tcs = 0;
11812857Shelge cvec -= 4; /* since we are using the xmitter intrpt */
11911896Shelge return(sizeof (*uuaddr));
12011896Shelge }
12111896Shelge
uuattach(ui)12211896Shelge uuattach(ui)
12312857Shelge register struct uba_device *ui;
12411896Shelge {
12511896Shelge }
12611896Shelge
12711896Shelge /*ARGSUSED1*/
uuopen(dev,flag)12811896Shelge uuopen(dev, flag)
12911896Shelge dev_t dev;
13011896Shelge int flag;
13111896Shelge {
13211896Shelge register struct uba_device *ui;
13313014Shelge register struct uu_softc *uuc;
13411896Shelge register struct uudevice *uuaddr;
13540728Skarels int ctlr, unit = UNIT(dev), s, error;
13611896Shelge
13712857Shelge ctlr = unit / NDPC;
13812857Shelge if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
13911876Shelge return (ENXIO);
14012937Shelge uuc = &uu_softc[ctlr];
14112937Shelge if (uuc->tu_dopen[unit&UMASK])
14211896Shelge return (EBUSY);
14311896Shelge if (uuwstart++ == 0)
14411896Shelge timeout(uuwatch, (caddr_t)0, hz);
14511896Shelge
14612937Shelge uuc->tu_dopen[unit&UMASK]++;
14712857Shelge uuaddr = (struct uudevice *)ui->ui_addr;
14812857Shelge s = splx(UUIPL);
14911876Shelge /*
15013014Shelge * If the other device on this controller
15114091Shelge * is already active, no need to initialize
15213014Shelge */
15313014Shelge if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
15413156Shelge goto ok;
15513014Shelge
15613014Shelge /*
15711896Shelge * If the unit already initialized,
15811876Shelge * just enable interrupts and return.
15911876Shelge */
16012937Shelge if (uuc->tu_state == TUS_IDLE) {
16111896Shelge uuaddr->rcs = UUCS_INTR;
16212937Shelge goto ok;
16311876Shelge }
16411876Shelge
16511876Shelge /*
16611876Shelge * Must initialize, reset the cassette
16711876Shelge * and wait for things to settle down.
16811876Shelge */
16911896Shelge uureset(ctlr);
17040728Skarels if (error = tsleep((caddr_t)uuc, (PZERO+1) | PCATCH, devopn, 0)) {
17140728Skarels splx(s);
17240728Skarels return (error);
17340728Skarels }
17412857Shelge uitab[ctlr].b_active = NULL;
17512937Shelge if (uuc->tu_state != TUS_IDLE) {
17612937Shelge uuc->tu_state = TUS_INIT1;
17712937Shelge uuc->tu_dopen[unit&UMASK] = 0;
17812937Shelge uuc->tu_rcnt = uuc->tu_wcnt = 0;
17911896Shelge uuaddr->rcs = 0;
18011896Shelge uuaddr->tcs = 0;
18111896Shelge splx(s);
18212937Shelge return (EIO);
18311876Shelge }
18412937Shelge ok:
18511876Shelge splx(s);
18611876Shelge return (0);
18711876Shelge }
18811876Shelge
18914091Shelge /*
19014091Shelge * Wait for all outstanding IO on this drive
19114091Shelge * complete, before closing. If both drives on
19214091Shelge * this controller are idle, mark the controller
19314091Shelge * `inactive'.
19414091Shelge */
19514091Shelge
uuclose(dev,flag)19611896Shelge uuclose(dev, flag)
19711896Shelge dev_t dev;
19811896Shelge int flag;
19911876Shelge {
20014091Shelge int s, unit = UNIT(dev);
20114091Shelge register struct uu_softc *uuc = &uu_softc[unit/NDPC];
20214091Shelge struct buf *bp, *last = NULL;
20314091Shelge struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
20411876Shelge
20514091Shelge s = splx(UUIPL);
20614091Shelge while (uu_pcnt[unit])
20714091Shelge sleep(&uu_pcnt[unit], PRIBIO);
20814091Shelge /*
20914091Shelge * No more writes are pending, scan the
21014091Shelge * buffer queue for oustanding reads from
21114091Shelge * this unit.
21214091Shelge */
21314152Shelge for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) {
21414091Shelge if (bp->b_dev == dev)
21514091Shelge last = bp;
21614152Shelge }
21714152Shelge if (last) {
21814152Shelge last->b_flags |= B_CALL;
21914152Shelge last->b_iodone = uuwake;
22014152Shelge sleep((caddr_t)last, PRIBIO);
22114152Shelge }
22214091Shelge uuc->tu_dopen[unit&UMASK] = 0;
22314091Shelge if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
22414091Shelge uuc->tu_flag = 0;
22514091Shelge uuaddr->rcs = 0;
22614091Shelge }
22714091Shelge splx(s);
22840728Skarels return (0);
22911876Shelge }
23011876Shelge
23114152Shelge uuwake(bp)
23214152Shelge struct buf *bp;
23314152Shelge {
23414152Shelge wakeup(bp);
23514152Shelge }
23614152Shelge
uureset(ctlr)23711896Shelge uureset(ctlr)
23811896Shelge int ctlr;
23911876Shelge {
24013014Shelge register struct uu_softc *uuc = &uu_softc[ctlr];
24112332Shelge register struct packet *cmd = &uucmd[ctlr];
24212857Shelge struct uba_device *ui = uudinfo[ctlr];
24312857Shelge register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
24411876Shelge
24512857Shelge uitab[ctlr].b_active++;
24612937Shelge uuc->tu_state = TUS_INIT1;
24712937Shelge uuc->tu_wbptr = uunull;
24812937Shelge uuc->tu_wcnt = sizeof (uunull);
24914091Shelge uuc->tu_rcnt = 0;
25011896Shelge cmd->pk_flag = TUF_CMD;
25112332Shelge cmd->pk_mcount = sizeof (*cmd) - 4;
25211896Shelge cmd->pk_mod = 0;
25311896Shelge cmd->pk_seq = 0;
25412332Shelge cmd->pk_sw = 0;
25511896Shelge uuaddr->rcs = 0;
25611896Shelge uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
25711896Shelge uuxintr(ctlr); /* start output */
25811876Shelge }
25911876Shelge
26011876Shelge /*
26111876Shelge * Strategy routine for block I/O
26211876Shelge */
uustrategy(bp)26311896Shelge uustrategy(bp)
26411876Shelge register struct buf *bp;
26511876Shelge {
26612332Shelge register struct buf *uutab;
26711896Shelge struct uba_device *ui;
26814091Shelge int s, unit = UNIT(bp->b_dev);
26911876Shelge
27014091Shelge if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
27111896Shelge goto bad;
27212857Shelge ui = uudinfo[unit/NDPC];
27311896Shelge if (ui == 0 || ui->ui_alive == 0)
27411896Shelge goto bad;
27512857Shelge uutab = &uitab[unit/NDPC]; /* one request queue per controller */
27613156Shelge s = splx(UUIPL);
27712332Shelge if ((bp->b_flags&B_READ) == 0)
27814091Shelge tu_pee(&uu_pcnt[unit]);
27914091Shelge bp->b_actf = NULL;
28012332Shelge if (uutab->b_actf == NULL)
28112332Shelge uutab->b_actf = bp;
28212332Shelge else
28314091Shelge uutab->b_actl->b_actf = bp;
28412332Shelge uutab->b_actl = bp;
28512332Shelge if (uutab->b_active == 0)
28612857Shelge uustart(ui);
28711876Shelge splx(s);
28811896Shelge return;
28911896Shelge
29011896Shelge bad:
29111896Shelge bp->b_flags |= B_ERROR;
29212332Shelge bp->b_error = ENXIO;
29311896Shelge iodone(bp);
29411896Shelge return;
29511876Shelge }
29611876Shelge
29711876Shelge /*
29811876Shelge * Start the transfer
29911876Shelge */
uustart(ui)30012857Shelge uustart(ui)
30112857Shelge register struct uba_device *ui;
30211876Shelge {
30311876Shelge register struct buf *bp;
30413014Shelge register struct uu_softc *uuc;
30511896Shelge struct packet *cmd;
30614152Shelge int ctlr = ui->ui_unit, s;
30711876Shelge
30812857Shelge if ((bp = uitab[ctlr].b_actf) == NULL)
30911876Shelge return;
31014152Shelge s = splx(UUIPL);
31112937Shelge uuc = &uu_softc[ctlr];
31212937Shelge if (uuc->tu_state != TUS_IDLE) {
31312332Shelge uureset(ctlr);
31414152Shelge splx(s);
31511876Shelge return;
31611876Shelge }
31714091Shelge cmd = &uucmd[ctlr];
31812857Shelge uitab[ctlr].b_active++;
31912937Shelge uitab[ctlr].b_errcnt = 0;
32012937Shelge uuc->tu_addr = bp->b_un.b_addr;
32112937Shelge uuc->tu_count = cmd->pk_count = bp->b_bcount;
32212937Shelge cmd->pk_block = bp->b_blkno;
32312937Shelge if (bp->b_flags&B_READ) {
32412937Shelge cmd->pk_op = TUOP_READ;
32512937Shelge cmd->pk_mod = 0;
32612937Shelge uuc->tu_state = TUS_SENDR;
32712937Shelge } else {
32812937Shelge cmd->pk_op = TUOP_WRITE;
32912937Shelge cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
33012937Shelge uuc->tu_state = TUS_SENDW;
33112937Shelge }
33214091Shelge cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
33312332Shelge cmd->pk_sw = 0;
33411896Shelge cmd->pk_chksum =
33512937Shelge tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
33612937Shelge uuc->tu_wbptr = (u_char *)cmd;
33712937Shelge uuc->tu_wcnt = sizeof (*cmd);
33812332Shelge uuxintr(ctlr);
33914152Shelge splx(s);
34011876Shelge }
34111876Shelge
34211876Shelge /*
34314091Shelge * TU58 receiver interrupt, handles whatever condition the
34414091Shelge * pseudo DMA routine in locore is unable to handle,
34514091Shelge * or, if UUDMA is undefined, handle all receiver interrupt
34614091Shelge * processing.
34711876Shelge */
uurintr(ctlr)34812332Shelge uurintr(ctlr)
34912332Shelge int ctlr;
35011876Shelge {
35112857Shelge struct uba_device *ui = uudinfo[ctlr];
35213014Shelge register struct uu_softc *uuc = &uu_softc[ctlr];
35312857Shelge register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
35412857Shelge register struct buf *uutab = &uitab[ctlr];
35512332Shelge struct packet *data, *cmd;
35612937Shelge struct buf *bp;
35712937Shelge int c, unit;
35811876Shelge
35912857Shelge c = uuaddr->rdb;
36012937Shelge data = &uudata[ctlr];
36113014Shelge cmd = &uucmd[ctlr];
36213014Shelge #if !defined(UUDMA)
36313014Shelge if (c & UURDB_ERROR)
36413014Shelge uuc->tu_state = TUS_RCVERR;
36513014Shelge else {
36613014Shelge if (uuc->tu_rcnt) {
36713014Shelge *uuc->tu_rbptr++ = c;
36813014Shelge if (--uuc->tu_rcnt)
36913014Shelge return;
37013014Shelge }
37113014Shelge }
37213014Shelge #endif
37313014Shelge
37413014Shelge /*
37513014Shelge * Switch on the tu_state of the transfer.
37613014Shelge */
37713014Shelge switch(uuc->tu_state) {
37813014Shelge
37913014Shelge /*
38013014Shelge * A data error occured in uudma
38113014Shelge * (either overrun or break)
38213014Shelge */
38313014Shelge case TUS_RCVERR:
38413156Shelge if ((c & UURDB_ORUN) == 0)
38513156Shelge printf("uu%d: break received, transfer restarted\n",
38613834Ssam data->pk_unit);
38714091Shelge #ifdef UUDEBUG
38814091Shelge else
38914091Shelge printf("uu%d: data overrun, recovered\n",
39014091Shelge data->pk_unit);
39114091Shelge #endif
39213156Shelge uuc->tu_serrs++;
39313014Shelge uu_restart(ctlr, ui);
39413014Shelge break;
39511876Shelge
39611876Shelge /*
39711876Shelge * If we get an unexpected "continue",
39811876Shelge * start all over again...
39911876Shelge */
40012937Shelge case TUS_INIT2:
40112937Shelge uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
40212937Shelge uuc->tu_flag = 0;
40312332Shelge wakeup((caddr_t)uuc);
40412857Shelge uustart(ui);
40511876Shelge break;
40611876Shelge
40711876Shelge /*
40811876Shelge * Only transition from this state
40911876Shelge * is on a "continue", so if we don't
41011876Shelge * get it, reset the world.
41111876Shelge */
41212937Shelge case TUS_WAIT: /* waiting for continue */
41312332Shelge switch(c) {
41412332Shelge case TUF_CONT: /* got the expected continue */
41512937Shelge uuc->tu_flag = 0;
41612332Shelge data->pk_flag = TUF_DATA;
41712937Shelge data->pk_mcount = MIN(128, uuc->tu_count);
41812332Shelge data->pk_chksum =
41912937Shelge tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
42012332Shelge (int)data->pk_mcount);
42112937Shelge uuc->tu_state = TUS_SENDH;
42212937Shelge uuc->tu_wbptr = (u_char *)data;
42312937Shelge uuc->tu_wcnt = 2;
42412857Shelge uuxintr(ctlr);
42511876Shelge break;
42612332Shelge
42712332Shelge case TUF_CMD: /* sending us an END packet...error */
42812937Shelge uuc->tu_state = TUS_GET;
42912937Shelge uuc->tu_rbptr = (u_char *)data;
43013014Shelge uuc->tu_rcnt = sizeof (*data) - 1;
43112937Shelge uuc->tu_flag = 1;
43212332Shelge uuaddr->tcs = 0;
43313014Shelge *uuc->tu_rbptr++ = c & UUDB_DMASK;
43413014Shelge break;
43512332Shelge
43612332Shelge case TUF_INITF:
43712857Shelge uureset(ctlr);
43812332Shelge break;
43912332Shelge
44012332Shelge default: /* something random...bad news */
44112937Shelge uuc->tu_state = TUS_INIT1;
44212332Shelge break;
44311876Shelge }
44411876Shelge break;
44511876Shelge
44612937Shelge case TUS_SENDW:
44712937Shelge if (c != TUF_CONT && c != TUF_INITF)
44811876Shelge goto bad;
44913014Shelge uu_restart(ctlr, ui);
45011876Shelge break;
45111876Shelge
45211876Shelge /*
45311876Shelge * Got header, now get data; amount to
45411896Shelge * fetch is included in packet.
45513014Shelge * (data packets are handled entirely
45613014Shelge * in uudma)
45711876Shelge */
45812937Shelge case TUS_GETH:
45913156Shelge #ifndef UUDMA
46013156Shelge if (data->pk_flag == TUF_DATA)
46113156Shelge uuc->tu_rbptr = (u_char *)uuc->tu_addr;
46213156Shelge #endif
46312937Shelge uuc->tu_rcnt = data->pk_mcount;
46412937Shelge uuc->tu_state = TUS_GETD;
46511876Shelge break;
46611876Shelge
46711876Shelge /*
46811876Shelge * Got the data, now fetch the checksum.
46911876Shelge */
47012937Shelge case TUS_GETD:
47112937Shelge uuc->tu_rbptr = (u_char *)&data->pk_chksum;
47212937Shelge uuc->tu_rcnt = sizeof (data->pk_chksum);
47312937Shelge uuc->tu_state = TUS_GETC;
47411876Shelge break;
47511876Shelge
47612937Shelge case TUS_GETC:
47711876Shelge /* got entire packet */
47812332Shelge if (data->pk_chksum !=
47912937Shelge tuchk(*((short *)data), (u_short *)
48013014Shelge (data->pk_flag == TUF_DATA ?
48113156Shelge (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
48212332Shelge (int)data->pk_mcount))
48313014Shelge case TUS_CHKERR:
48412937Shelge uuc->tu_cerrs++;
48513014Shelge case TUS_GET:
48612332Shelge if (data->pk_flag == TUF_DATA) {
48711876Shelge /* data packet, advance to next */
48812937Shelge uuc->tu_addr += data->pk_mcount;
48912937Shelge uuc->tu_count -= data->pk_mcount;
49012937Shelge uuc->tu_state = TUS_GETH;
49112937Shelge uuc->tu_rbptr = (u_char *)data; /* next packet */
49212937Shelge uuc->tu_rcnt = 2;
49312332Shelge } else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
49411876Shelge /* end packet, idle and reenable transmitter */
49512937Shelge uuc->tu_state = TUS_IDLE;
49612937Shelge uuc->tu_flag = 0;
49712937Shelge uuaddr->tcs = UUCS_INTR;
49812937Shelge if ((bp = uutab->b_actf) == NULL) {
49913156Shelge printf("uu%d: no bp, active %d\n",
50013834Ssam data->pk_unit, uitab[ctlr].b_active);
50112857Shelge uustart(ui);
50211876Shelge return;
50311876Shelge }
50414091Shelge unit = UNIT(bp->b_dev);
50512332Shelge if (data->pk_mod > 1) { /* hard error */
50613014Shelge printf("uu%d: hard error bn%d,", unit,
50713834Ssam bp->b_blkno);
50814091Shelge printf(" pk_mod 0%o\n", data->pk_mod&0xff);
50911876Shelge bp->b_flags |= B_ERROR;
51012937Shelge uuc->tu_herrs++;
51114091Shelge } else if (data->pk_mod) /* soft error */
51212937Shelge uuc->tu_serrs++;
51312332Shelge uutab->b_active = NULL;
51414091Shelge uutab->b_actf = bp->b_actf;
51512937Shelge bp->b_resid = uuc->tu_count;
51611876Shelge if ((bp->b_flags&B_READ) == 0)
51714091Shelge tu_vee(&uu_pcnt[unit]);
51811876Shelge iodone(bp);
51912857Shelge uustart(ui);
52011876Shelge } else {
52113156Shelge /*
52213156Shelge * Neither data nor end: data was lost
52314091Shelge * somehow, flush and restart the transfer.
52413156Shelge */
52514091Shelge uuaddr->rcs = 0;
52613014Shelge uu_restart(ctlr, ui);
52713156Shelge uuc->tu_serrs++;
52811876Shelge }
52911876Shelge break;
53011876Shelge
53112937Shelge case TUS_IDLE:
53212937Shelge case TUS_INIT1:
53311876Shelge break;
53411876Shelge
53511876Shelge default:
53611876Shelge bad:
53711876Shelge if (c == TUF_INITF) {
53813156Shelge printf("uu%d protocol error, state=", data->pk_unit);
53912937Shelge printstate(uuc->tu_state);
54011876Shelge printf(", op=%x, cnt=%d, block=%d\n",
54112332Shelge cmd->pk_op, cmd->pk_count, cmd->pk_block);
54212332Shelge uutab->b_active = NULL;
54312332Shelge if (bp = uutab->b_actf) {
54411876Shelge bp->b_flags |= B_ERROR;
54514091Shelge uutab->b_actf = bp->b_actf;
54611876Shelge if ((bp->b_flags&B_READ) == 0)
54714091Shelge tu_vee(&uu_pcnt[unit]);
54811876Shelge iodone(bp);
54911876Shelge }
55012937Shelge uuc->tu_state = TUS_INIT1;
55111876Shelge } else {
55212332Shelge printf("uu%d receive state error, state=",
55313156Shelge data->pk_unit);
55412937Shelge printstate(uuc->tu_state);
55513014Shelge printf(", byte=%x\n", c & 0xff);
55611876Shelge #ifdef notdef
55712937Shelge uuc->tu_state = TUS_INIT1;
55811876Shelge #endif
55912332Shelge wakeup((caddr_t)uuc);
56011876Shelge }
56111876Shelge }
56211876Shelge }
56311876Shelge
56412937Shelge
56512937Shelge /*
56611876Shelge * TU58 transmitter interrupt
56711876Shelge */
uuxintr(ctlr)56812332Shelge uuxintr(ctlr)
56912332Shelge int ctlr;
57011876Shelge {
57113014Shelge register struct uu_softc *uuc = &uu_softc[ctlr];
57212857Shelge register struct uudevice *uuaddr;
57312332Shelge register struct packet *data;
57412857Shelge struct uba_device *ui = uudinfo[ctlr];
57512332Shelge int c;
57611876Shelge
57712857Shelge data = &uudata[ctlr];
57812857Shelge uuaddr = (struct uudevice *) ui->ui_addr;
57911876Shelge top:
58014091Shelge if (uuc->tu_wcnt > 0) {
58111876Shelge /* still stuff to send, send one byte */
58212332Shelge while ((uuaddr->tcs & UUCS_READY) == 0)
58311876Shelge ;
58412937Shelge uuaddr->tdb = *uuc->tu_wbptr++;
58512937Shelge uuc->tu_wcnt--;
58611876Shelge return;
58711876Shelge }
58811876Shelge
58911876Shelge /*
59011876Shelge * Last message byte was sent out.
59112937Shelge * Switch on tu_state of transfer.
59211876Shelge */
59312937Shelge switch(uuc->tu_state) {
59411876Shelge
59511876Shelge /*
59611876Shelge * Two nulls have been sent, remove break, and send inits
59711876Shelge */
59812937Shelge case TUS_INIT1:
59914091Shelge uuc->tu_flag = 0;
60012332Shelge uuaddr->tcs = UUCS_INTR;
60112937Shelge uuc->tu_state = TUS_INIT2;
60212937Shelge uuc->tu_wbptr = uuinit;
60312937Shelge uuc->tu_wcnt = sizeof (uuinit);
60411876Shelge goto top;
60511876Shelge
60611876Shelge /*
60711876Shelge * Inits have been sent, wait for a continue msg.
60811876Shelge */
60912937Shelge case TUS_INIT2:
61012857Shelge c = uuaddr->rdb; /* prevent overrun error */
61112332Shelge uuaddr->rcs = UUCS_INTR;
61212937Shelge uuc->tu_flag = 1;
61311876Shelge break;
61411876Shelge
61511876Shelge /*
61611876Shelge * Read cmd packet sent, get ready for data
61711876Shelge */
61812937Shelge case TUS_SENDR:
61912937Shelge uuc->tu_state = TUS_GETH;
62012937Shelge uuc->tu_rbptr = (u_char *)data;
62112937Shelge uuc->tu_rcnt = 2;
62212937Shelge uuc->tu_flag = 1;
62314091Shelge uuaddr->tcs = 0;
62412937Shelge uuaddr->rcs = UUCS_INTR;
62511876Shelge break;
62611876Shelge
62711876Shelge /*
62811876Shelge * Write cmd packet sent, wait for continue
62911876Shelge */
63012937Shelge case TUS_SENDW:
63112937Shelge uuc->tu_state = TUS_WAIT;
63212937Shelge uuc->tu_flag = 1;
63312332Shelge if ((uuaddr->rcs&UUCS_INTR) == 0) {
63411876Shelge printf("NO IE\n");
63512332Shelge uuaddr->rcs = UUCS_INTR;
63611876Shelge }
63711876Shelge break;
63811876Shelge
63911876Shelge /*
64011876Shelge * Header sent, send data.
64111876Shelge */
64212937Shelge case TUS_SENDH:
64312937Shelge uuc->tu_state = TUS_SENDD;
64412937Shelge uuc->tu_wbptr = (u_char *)uuc->tu_addr;
64512937Shelge uuc->tu_wcnt = data->pk_mcount;
64611876Shelge goto top;
64711876Shelge
64811876Shelge /*
64911876Shelge * Data sent, follow with checksum.
65011876Shelge */
65112937Shelge case TUS_SENDD:
65212937Shelge uuc->tu_state = TUS_SENDC;
65312937Shelge uuc->tu_wbptr = (u_char *)&data->pk_chksum;
65414091Shelge uuc->tu_wcnt = 2;
65511876Shelge goto top;
65611876Shelge
65711876Shelge /*
65811876Shelge * Checksum sent, wait for continue.
65911876Shelge */
66012937Shelge case TUS_SENDC:
66111876Shelge /*
66212937Shelge * Update buffer address and count.
66311876Shelge */
66412937Shelge uuc->tu_addr += data->pk_mcount;
66512937Shelge uuc->tu_count -= data->pk_mcount;
66614091Shelge if (uuc->tu_count > 0) {
66712937Shelge uuc->tu_state = TUS_WAIT;
66812937Shelge uuc->tu_flag = 1;
66911876Shelge break;
67011876Shelge }
67111876Shelge
67211876Shelge /*
67311876Shelge * End of transmission, get ready for end packet.
67411876Shelge */
67512937Shelge uuc->tu_state = TUS_GET;
67612937Shelge uuc->tu_rbptr = (u_char *)data;
67712937Shelge uuc->tu_rcnt = sizeof (*data);
67812937Shelge uuc->tu_flag = 1;
67914091Shelge uuaddr->tcs = 0;
68011876Shelge break;
68111876Shelge
68211876Shelge /*
68312332Shelge * Random interrupt
68411876Shelge */
68513156Shelge case TUS_IDLE: /* stray interrupt? */
68613156Shelge
68711876Shelge default:
68811876Shelge break;
68911876Shelge }
69012937Shelge }
69112937Shelge
uuwatch()69212937Shelge uuwatch()
69312937Shelge {
69413014Shelge register struct uu_softc *uuc;
69512937Shelge register struct uudevice *uuaddr;
69612937Shelge struct uba_device *ui;
69712937Shelge struct buf *bp, *uutab;
69812937Shelge int s, ctlr, active = 0;
69912937Shelge
70012937Shelge for (ctlr=0; ctlr<NUU; ctlr++) {
70112937Shelge int i;
70212937Shelge
70312937Shelge uuc = &uu_softc[ctlr];
70414091Shelge
70514091Shelge if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
70614091Shelge active++;
70714091Shelge if (uuc->tu_flag == 0)
70814091Shelge /*
70914091Shelge * If no read is in progress
71014091Shelge * just skip
71114091Shelge */
71214091Shelge continue;
71314091Shelge
71412937Shelge ui = uudinfo[ctlr];
71512937Shelge uuaddr = (struct uudevice *)ui->ui_addr;
71612937Shelge uutab = &uitab[ctlr];
71714091Shelge if (uuc->tu_flag++ < 40)
71812937Shelge continue;
71913156Shelge printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
72014091Shelge #ifdef UUDEBUG
721*49876Sbostic printf("%lx %lx %lx %lx %lx %lx %lx\n",
722*49876Sbostic uuc->tu_rbptr, uuc->tu_rcnt, uuc->tu_wbptr, uuc->tu_wcnt,
723*49876Sbostic uuc->tu_state, uuc->tu_addr, uuc->tu_count);
72413834Ssam #endif
72514091Shelge s = splx(UUIPL);
72612937Shelge uuc->tu_flag = 0;
72712937Shelge i = uuaddr->rdb; /* dummy */
72812937Shelge uuaddr->rcs = UUCS_INTR; /* in case we were flushing */
72912937Shelge uuaddr->tcs = UUCS_INTR;
73012937Shelge uuc->tu_state = TUS_IDLE;
73112937Shelge if (!uutab->b_active) {
73212937Shelge wakeup((caddr_t)uuc);
73312937Shelge goto retry;
73412937Shelge }
73512937Shelge if (++uutab->b_errcnt <= 1) {
73612937Shelge uustart(ui);
73712937Shelge goto retry;
73812937Shelge }
73912937Shelge if (bp = uutab->b_actf) {
74012937Shelge bp->b_flags |= B_ERROR;
74112937Shelge if ((bp->b_flags&B_READ) == 0)
74214091Shelge tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
74312937Shelge iodone(bp);
74412937Shelge }
74512937Shelge retry:
74612937Shelge (void) splx(s);
74711876Shelge }
74812937Shelge if (active)
74912937Shelge timeout(uuwatch, (caddr_t)0, hz);
75012937Shelge else
75112937Shelge uuwstart = 0;
75212937Shelge return;
75311876Shelge }
75411876Shelge
75512937Shelge #if !defined(VAX750) && !defined(VAX730)
75611876Shelge /*
75711876Shelge * Compute checksum TU58 fashion
75811876Shelge */
75911876Shelge #ifdef lint
tuchk(word,cp,n)76012937Shelge tuchk(word, cp, n)
76111876Shelge register word;
76211876Shelge register unsigned short *cp;
76311876Shelge int n;
76411876Shelge {
76511876Shelge register int c = n >> 1;
76611876Shelge register long temp;
76711876Shelge
76811876Shelge do {
76911876Shelge temp = *cp++; /* temp, only because vax cc won't *r++ */
77011876Shelge word += temp;
77111876Shelge } while (--c > 0);
77211876Shelge if (n & 1)
77311876Shelge word += *(unsigned char *)cp;
77411876Shelge while (word & 0xffff0000)
77511876Shelge word = (word & 0xffff) + ((word >> 16) & 0xffff);
77611876Shelge return (word);
77711876Shelge }
77811876Shelge #else
tuchk(word0,wp,n)77912937Shelge tuchk(word0, wp, n)
78011896Shelge register int word0; /* r11 */
78111896Shelge register char *wp; /* r10 */
78211896Shelge register int n; /* r9 */
78311876Shelge {
78411876Shelge asm("loop:");
78511896Shelge asm(" addw2 (r10)+,r11"); /* add a word to sum */
78611896Shelge asm(" adwc $0,r11"); /* add in carry, end-around */
78711876Shelge asm(" acbl $2,$-2,r9,loop"); /* done yet? */
78811896Shelge asm(" blbc r9,ok"); /* odd byte count? */
78911896Shelge asm(" movzbw (r10),r10"); /* yes, get last byte */
79011896Shelge asm(" addw2 r10,r11"); /* add it in */
79111896Shelge asm(" adwc $0,r11"); /* and the carry */
79211876Shelge asm("ok:");
79311896Shelge asm(" movl r11,r0"); /* return sum */
79411876Shelge }
79511876Shelge #endif
79611876Shelge
79714091Shelge /*
79814091Shelge * Make sure this incredibly slow device
79914091Shelge * doesn't eat up all the buffers in the
80014091Shelge * system by putting the requesting process
80114091Shelge * (remember: this device is 'single-user')
80214091Shelge * to sleep if the write-behind queue grows
80314091Shelge * larger than NUUQ.
80414091Shelge */
tu_pee(cp)80512937Shelge tu_pee(cp)
80614091Shelge char *cp;
80712332Shelge {
80812332Shelge register int s;
80912332Shelge
81012857Shelge s = splx(UUIPL);
81114091Shelge if (++(*cp) > NUUQ)
81212332Shelge sleep(cp, PRIBIO);
81312332Shelge splx(s);
81412332Shelge }
81512332Shelge
tu_vee(cp)81612937Shelge tu_vee(cp)
81714091Shelge char *cp;
81812332Shelge {
81912332Shelge register int s;
82012332Shelge
82112857Shelge s = splx(UUIPL);
82214091Shelge if (--(*cp) <= NUUQ)
82312332Shelge wakeup(cp);
82411876Shelge splx(s);
82511876Shelge }
82611876Shelge #endif
82712332Shelge
uuioctl(dev,cmd,data,flag)82812937Shelge uuioctl(dev, cmd, data, flag)
82912937Shelge dev_t dev;
83012937Shelge caddr_t data;
83112937Shelge {
83212937Shelge /*
83313156Shelge * add code to wind/rewind cassette here
83412937Shelge */
83512937Shelge return (ENXIO);
83612937Shelge }
83712937Shelge
uu_restart(ctlr,ui)83813014Shelge uu_restart(ctlr, ui)
83913014Shelge int ctlr;
84013014Shelge struct uba_device *ui;
84113014Shelge {
84213014Shelge uureset(ctlr);
84313014Shelge timeout(uustart, (caddr_t)ui, hz * 3);
84413014Shelge }
84514091Shelge
84614091Shelge #endif
847