123359Smckusick /* 223359Smckusick * Copyright (c) 1982 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*25521Stef * @(#)uu.c 6.4 (Berkeley) 11/22/85 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 3012332Shelge #include "../machine/pte.h" 3111896Shelge 3217084Sbloom #include "param.h" 3317084Sbloom #include "systm.h" 3417084Sbloom #include "buf.h" 3517084Sbloom #include "conf.h" 3617084Sbloom #include "time.h" 3717084Sbloom #include "kernel.h" 3817084Sbloom #include "errno.h" 3917084Sbloom #include "file.h" 4011876Shelge 4111876Shelge #include "../vax/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(); 96*25521Stef 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*/ 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 12211896Shelge uuattach(ui) 12312857Shelge register struct uba_device *ui; 12411896Shelge { 12511896Shelge } 12611896Shelge 12711896Shelge /*ARGSUSED1*/ 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; 13512332Shelge int ctlr, unit = UNIT(dev), s; 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); 17011896Shelge sleep((caddr_t)uuc, PZERO+1); 17112857Shelge uitab[ctlr].b_active = NULL; 17212937Shelge if (uuc->tu_state != TUS_IDLE) { 17312937Shelge uuc->tu_state = TUS_INIT1; 17412937Shelge uuc->tu_dopen[unit&UMASK] = 0; 17512937Shelge uuc->tu_rcnt = uuc->tu_wcnt = 0; 17611896Shelge uuaddr->rcs = 0; 17711896Shelge uuaddr->tcs = 0; 17811896Shelge splx(s); 17912937Shelge return (EIO); 18011876Shelge } 18112937Shelge ok: 18211876Shelge splx(s); 18311876Shelge return (0); 18411876Shelge } 18511876Shelge 18614091Shelge /* 18714091Shelge * Wait for all outstanding IO on this drive 18814091Shelge * complete, before closing. If both drives on 18914091Shelge * this controller are idle, mark the controller 19014091Shelge * `inactive'. 19114091Shelge */ 19214091Shelge 19311896Shelge uuclose(dev, flag) 19411896Shelge dev_t dev; 19511896Shelge int flag; 19611876Shelge { 19714091Shelge int s, unit = UNIT(dev); 19814091Shelge register struct uu_softc *uuc = &uu_softc[unit/NDPC]; 19914091Shelge struct buf *bp, *last = NULL; 20014091Shelge struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr; 20111876Shelge 20214091Shelge s = splx(UUIPL); 20314091Shelge while (uu_pcnt[unit]) 20414091Shelge sleep(&uu_pcnt[unit], PRIBIO); 20514091Shelge /* 20614091Shelge * No more writes are pending, scan the 20714091Shelge * buffer queue for oustanding reads from 20814091Shelge * this unit. 20914091Shelge */ 21014152Shelge for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) { 21114091Shelge if (bp->b_dev == dev) 21214091Shelge last = bp; 21314152Shelge } 21414152Shelge if (last) { 21514152Shelge last->b_flags |= B_CALL; 21614152Shelge last->b_iodone = uuwake; 21714152Shelge sleep((caddr_t)last, PRIBIO); 21814152Shelge } 21914091Shelge uuc->tu_dopen[unit&UMASK] = 0; 22014091Shelge if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) { 22114091Shelge uuc->tu_flag = 0; 22214091Shelge uuaddr->rcs = 0; 22314091Shelge } 22414091Shelge splx(s); 22511876Shelge } 22611876Shelge 22714152Shelge uuwake(bp) 22814152Shelge struct buf *bp; 22914152Shelge { 23014152Shelge wakeup(bp); 23114152Shelge } 23214152Shelge 23311896Shelge uureset(ctlr) 23411896Shelge int ctlr; 23511876Shelge { 23613014Shelge register struct uu_softc *uuc = &uu_softc[ctlr]; 23712332Shelge register struct packet *cmd = &uucmd[ctlr]; 23812857Shelge struct uba_device *ui = uudinfo[ctlr]; 23912857Shelge register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr; 24011876Shelge 24112857Shelge uitab[ctlr].b_active++; 24212937Shelge uuc->tu_state = TUS_INIT1; 24312937Shelge uuc->tu_wbptr = uunull; 24412937Shelge uuc->tu_wcnt = sizeof (uunull); 24514091Shelge uuc->tu_rcnt = 0; 24611896Shelge cmd->pk_flag = TUF_CMD; 24712332Shelge cmd->pk_mcount = sizeof (*cmd) - 4; 24811896Shelge cmd->pk_mod = 0; 24911896Shelge cmd->pk_seq = 0; 25012332Shelge cmd->pk_sw = 0; 25111896Shelge uuaddr->rcs = 0; 25211896Shelge uuaddr->tcs = UUCS_INTR | UUCS_BREAK; 25311896Shelge uuxintr(ctlr); /* start output */ 25411876Shelge } 25511876Shelge 25611876Shelge /* 25711876Shelge * Strategy routine for block I/O 25811876Shelge */ 25911896Shelge uustrategy(bp) 26011876Shelge register struct buf *bp; 26111876Shelge { 26212332Shelge register struct buf *uutab; 26311896Shelge struct uba_device *ui; 26414091Shelge int s, unit = UNIT(bp->b_dev); 26511876Shelge 26614091Shelge if ((unit > NUX) || (bp->b_blkno >= NTUBLK)) 26711896Shelge goto bad; 26812857Shelge ui = uudinfo[unit/NDPC]; 26911896Shelge if (ui == 0 || ui->ui_alive == 0) 27011896Shelge goto bad; 27112857Shelge uutab = &uitab[unit/NDPC]; /* one request queue per controller */ 27213156Shelge s = splx(UUIPL); 27312332Shelge if ((bp->b_flags&B_READ) == 0) 27414091Shelge tu_pee(&uu_pcnt[unit]); 27514091Shelge bp->b_actf = NULL; 27612332Shelge if (uutab->b_actf == NULL) 27712332Shelge uutab->b_actf = bp; 27812332Shelge else 27914091Shelge uutab->b_actl->b_actf = bp; 28012332Shelge uutab->b_actl = bp; 28112332Shelge if (uutab->b_active == 0) 28212857Shelge uustart(ui); 28311876Shelge splx(s); 28411896Shelge return; 28511896Shelge 28611896Shelge bad: 28711896Shelge bp->b_flags |= B_ERROR; 28812332Shelge bp->b_error = ENXIO; 28911896Shelge iodone(bp); 29011896Shelge return; 29111876Shelge } 29211876Shelge 29311876Shelge /* 29411876Shelge * Start the transfer 29511876Shelge */ 29612857Shelge uustart(ui) 29712857Shelge register struct uba_device *ui; 29811876Shelge { 29911876Shelge register struct buf *bp; 30013014Shelge register struct uu_softc *uuc; 30111896Shelge struct packet *cmd; 30214152Shelge int ctlr = ui->ui_unit, s; 30311876Shelge 30412857Shelge if ((bp = uitab[ctlr].b_actf) == NULL) 30511876Shelge return; 30614152Shelge s = splx(UUIPL); 30712937Shelge uuc = &uu_softc[ctlr]; 30812937Shelge if (uuc->tu_state != TUS_IDLE) { 30912332Shelge uureset(ctlr); 31014152Shelge splx(s); 31111876Shelge return; 31211876Shelge } 31314091Shelge cmd = &uucmd[ctlr]; 31412857Shelge uitab[ctlr].b_active++; 31512937Shelge uitab[ctlr].b_errcnt = 0; 31612937Shelge uuc->tu_addr = bp->b_un.b_addr; 31712937Shelge uuc->tu_count = cmd->pk_count = bp->b_bcount; 31812937Shelge cmd->pk_block = bp->b_blkno; 31912937Shelge if (bp->b_flags&B_READ) { 32012937Shelge cmd->pk_op = TUOP_READ; 32112937Shelge cmd->pk_mod = 0; 32212937Shelge uuc->tu_state = TUS_SENDR; 32312937Shelge } else { 32412937Shelge cmd->pk_op = TUOP_WRITE; 32512937Shelge cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0; 32612937Shelge uuc->tu_state = TUS_SENDW; 32712937Shelge } 32814091Shelge cmd->pk_unit = UNIT(bp->b_dev)&UMASK; 32912332Shelge cmd->pk_sw = 0; 33011896Shelge cmd->pk_chksum = 33112937Shelge tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount); 33212937Shelge uuc->tu_wbptr = (u_char *)cmd; 33312937Shelge uuc->tu_wcnt = sizeof (*cmd); 33412332Shelge uuxintr(ctlr); 33514152Shelge splx(s); 33611876Shelge } 33711876Shelge 33811876Shelge /* 33914091Shelge * TU58 receiver interrupt, handles whatever condition the 34014091Shelge * pseudo DMA routine in locore is unable to handle, 34114091Shelge * or, if UUDMA is undefined, handle all receiver interrupt 34214091Shelge * processing. 34311876Shelge */ 34412332Shelge uurintr(ctlr) 34512332Shelge int ctlr; 34611876Shelge { 34712857Shelge struct uba_device *ui = uudinfo[ctlr]; 34813014Shelge register struct uu_softc *uuc = &uu_softc[ctlr]; 34912857Shelge register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr; 35012857Shelge register struct buf *uutab = &uitab[ctlr]; 35112332Shelge struct packet *data, *cmd; 35212937Shelge struct buf *bp; 35312937Shelge int c, unit; 35411876Shelge 35512857Shelge c = uuaddr->rdb; 35612937Shelge data = &uudata[ctlr]; 35713014Shelge cmd = &uucmd[ctlr]; 35813014Shelge #if !defined(UUDMA) 35913014Shelge if (c & UURDB_ERROR) 36013014Shelge uuc->tu_state = TUS_RCVERR; 36113014Shelge else { 36213014Shelge if (uuc->tu_rcnt) { 36313014Shelge *uuc->tu_rbptr++ = c; 36413014Shelge if (--uuc->tu_rcnt) 36513014Shelge return; 36613014Shelge } 36713014Shelge } 36813014Shelge #endif 36913014Shelge 37013014Shelge /* 37113014Shelge * Switch on the tu_state of the transfer. 37213014Shelge */ 37313014Shelge switch(uuc->tu_state) { 37413014Shelge 37513014Shelge /* 37613014Shelge * A data error occured in uudma 37713014Shelge * (either overrun or break) 37813014Shelge */ 37913014Shelge case TUS_RCVERR: 38013156Shelge if ((c & UURDB_ORUN) == 0) 38113156Shelge printf("uu%d: break received, transfer restarted\n", 38213834Ssam data->pk_unit); 38314091Shelge #ifdef UUDEBUG 38414091Shelge else 38514091Shelge printf("uu%d: data overrun, recovered\n", 38614091Shelge data->pk_unit); 38714091Shelge #endif 38813156Shelge uuc->tu_serrs++; 38913014Shelge uu_restart(ctlr, ui); 39013014Shelge break; 39111876Shelge 39211876Shelge /* 39311876Shelge * If we get an unexpected "continue", 39411876Shelge * start all over again... 39511876Shelge */ 39612937Shelge case TUS_INIT2: 39712937Shelge uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1; 39812937Shelge uuc->tu_flag = 0; 39912332Shelge wakeup((caddr_t)uuc); 40012857Shelge uustart(ui); 40111876Shelge break; 40211876Shelge 40311876Shelge /* 40411876Shelge * Only transition from this state 40511876Shelge * is on a "continue", so if we don't 40611876Shelge * get it, reset the world. 40711876Shelge */ 40812937Shelge case TUS_WAIT: /* waiting for continue */ 40912332Shelge switch(c) { 41012332Shelge case TUF_CONT: /* got the expected continue */ 41112937Shelge uuc->tu_flag = 0; 41212332Shelge data->pk_flag = TUF_DATA; 41312937Shelge data->pk_mcount = MIN(128, uuc->tu_count); 41412332Shelge data->pk_chksum = 41512937Shelge tuchk(*((short *)data), (caddr_t)uuc->tu_addr, 41612332Shelge (int)data->pk_mcount); 41712937Shelge uuc->tu_state = TUS_SENDH; 41812937Shelge uuc->tu_wbptr = (u_char *)data; 41912937Shelge uuc->tu_wcnt = 2; 42012857Shelge uuxintr(ctlr); 42111876Shelge break; 42212332Shelge 42312332Shelge case TUF_CMD: /* sending us an END packet...error */ 42412937Shelge uuc->tu_state = TUS_GET; 42512937Shelge uuc->tu_rbptr = (u_char *)data; 42613014Shelge uuc->tu_rcnt = sizeof (*data) - 1; 42712937Shelge uuc->tu_flag = 1; 42812332Shelge uuaddr->tcs = 0; 42913014Shelge *uuc->tu_rbptr++ = c & UUDB_DMASK; 43013014Shelge break; 43112332Shelge 43212332Shelge case TUF_INITF: 43312857Shelge uureset(ctlr); 43412332Shelge break; 43512332Shelge 43612332Shelge default: /* something random...bad news */ 43712937Shelge uuc->tu_state = TUS_INIT1; 43812332Shelge break; 43911876Shelge } 44011876Shelge break; 44111876Shelge 44212937Shelge case TUS_SENDW: 44312937Shelge if (c != TUF_CONT && c != TUF_INITF) 44411876Shelge goto bad; 44513014Shelge uu_restart(ctlr, ui); 44611876Shelge break; 44711876Shelge 44811876Shelge /* 44911876Shelge * Got header, now get data; amount to 45011896Shelge * fetch is included in packet. 45113014Shelge * (data packets are handled entirely 45213014Shelge * in uudma) 45311876Shelge */ 45412937Shelge case TUS_GETH: 45513156Shelge #ifndef UUDMA 45613156Shelge if (data->pk_flag == TUF_DATA) 45713156Shelge uuc->tu_rbptr = (u_char *)uuc->tu_addr; 45813156Shelge #endif 45912937Shelge uuc->tu_rcnt = data->pk_mcount; 46012937Shelge uuc->tu_state = TUS_GETD; 46111876Shelge break; 46211876Shelge 46311876Shelge /* 46411876Shelge * Got the data, now fetch the checksum. 46511876Shelge */ 46612937Shelge case TUS_GETD: 46712937Shelge uuc->tu_rbptr = (u_char *)&data->pk_chksum; 46812937Shelge uuc->tu_rcnt = sizeof (data->pk_chksum); 46912937Shelge uuc->tu_state = TUS_GETC; 47011876Shelge break; 47111876Shelge 47212937Shelge case TUS_GETC: 47311876Shelge /* got entire packet */ 47412332Shelge if (data->pk_chksum != 47512937Shelge tuchk(*((short *)data), (u_short *) 47613014Shelge (data->pk_flag == TUF_DATA ? 47713156Shelge (u_short *) uuc->tu_addr : (u_short *)&data->pk_op), 47812332Shelge (int)data->pk_mcount)) 47913014Shelge case TUS_CHKERR: 48012937Shelge uuc->tu_cerrs++; 48113014Shelge case TUS_GET: 48212332Shelge if (data->pk_flag == TUF_DATA) { 48311876Shelge /* data packet, advance to next */ 48412937Shelge uuc->tu_addr += data->pk_mcount; 48512937Shelge uuc->tu_count -= data->pk_mcount; 48612937Shelge uuc->tu_state = TUS_GETH; 48712937Shelge uuc->tu_rbptr = (u_char *)data; /* next packet */ 48812937Shelge uuc->tu_rcnt = 2; 48912332Shelge } else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) { 49011876Shelge /* end packet, idle and reenable transmitter */ 49112937Shelge uuc->tu_state = TUS_IDLE; 49212937Shelge uuc->tu_flag = 0; 49312937Shelge uuaddr->tcs = UUCS_INTR; 49412937Shelge if ((bp = uutab->b_actf) == NULL) { 49513156Shelge printf("uu%d: no bp, active %d\n", 49613834Ssam data->pk_unit, uitab[ctlr].b_active); 49712857Shelge uustart(ui); 49811876Shelge return; 49911876Shelge } 50014091Shelge unit = UNIT(bp->b_dev); 50112332Shelge if (data->pk_mod > 1) { /* hard error */ 50213014Shelge printf("uu%d: hard error bn%d,", unit, 50313834Ssam bp->b_blkno); 50414091Shelge printf(" pk_mod 0%o\n", data->pk_mod&0xff); 50511876Shelge bp->b_flags |= B_ERROR; 50612937Shelge uuc->tu_herrs++; 50714091Shelge } else if (data->pk_mod) /* soft error */ 50812937Shelge uuc->tu_serrs++; 50912332Shelge uutab->b_active = NULL; 51014091Shelge uutab->b_actf = bp->b_actf; 51112937Shelge bp->b_resid = uuc->tu_count; 51211876Shelge if ((bp->b_flags&B_READ) == 0) 51314091Shelge tu_vee(&uu_pcnt[unit]); 51411876Shelge iodone(bp); 51512857Shelge uustart(ui); 51611876Shelge } else { 51713156Shelge /* 51813156Shelge * Neither data nor end: data was lost 51914091Shelge * somehow, flush and restart the transfer. 52013156Shelge */ 52114091Shelge uuaddr->rcs = 0; 52213014Shelge uu_restart(ctlr, ui); 52313156Shelge uuc->tu_serrs++; 52411876Shelge } 52511876Shelge break; 52611876Shelge 52712937Shelge case TUS_IDLE: 52812937Shelge case TUS_INIT1: 52911876Shelge break; 53011876Shelge 53111876Shelge default: 53211876Shelge bad: 53311876Shelge if (c == TUF_INITF) { 53413156Shelge printf("uu%d protocol error, state=", data->pk_unit); 53512937Shelge printstate(uuc->tu_state); 53611876Shelge printf(", op=%x, cnt=%d, block=%d\n", 53712332Shelge cmd->pk_op, cmd->pk_count, cmd->pk_block); 53812332Shelge uutab->b_active = NULL; 53912332Shelge if (bp = uutab->b_actf) { 54011876Shelge bp->b_flags |= B_ERROR; 54114091Shelge uutab->b_actf = bp->b_actf; 54211876Shelge if ((bp->b_flags&B_READ) == 0) 54314091Shelge tu_vee(&uu_pcnt[unit]); 54411876Shelge iodone(bp); 54511876Shelge } 54612937Shelge uuc->tu_state = TUS_INIT1; 54711876Shelge } else { 54812332Shelge printf("uu%d receive state error, state=", 54913156Shelge data->pk_unit); 55012937Shelge printstate(uuc->tu_state); 55113014Shelge printf(", byte=%x\n", c & 0xff); 55211876Shelge #ifdef notdef 55312937Shelge uuc->tu_state = TUS_INIT1; 55411876Shelge #endif 55512332Shelge wakeup((caddr_t)uuc); 55611876Shelge } 55711876Shelge } 55811876Shelge } 55911876Shelge 56012937Shelge 56112937Shelge /* 56211876Shelge * TU58 transmitter interrupt 56311876Shelge */ 56412332Shelge uuxintr(ctlr) 56512332Shelge int ctlr; 56611876Shelge { 56713014Shelge register struct uu_softc *uuc = &uu_softc[ctlr]; 56812857Shelge register struct uudevice *uuaddr; 56912332Shelge register struct packet *data; 57012857Shelge struct uba_device *ui = uudinfo[ctlr]; 57112332Shelge int c; 57211876Shelge 57312857Shelge data = &uudata[ctlr]; 57412857Shelge uuaddr = (struct uudevice *) ui->ui_addr; 57511876Shelge top: 57614091Shelge if (uuc->tu_wcnt > 0) { 57711876Shelge /* still stuff to send, send one byte */ 57812332Shelge while ((uuaddr->tcs & UUCS_READY) == 0) 57911876Shelge ; 58012937Shelge uuaddr->tdb = *uuc->tu_wbptr++; 58112937Shelge uuc->tu_wcnt--; 58211876Shelge return; 58311876Shelge } 58411876Shelge 58511876Shelge /* 58611876Shelge * Last message byte was sent out. 58712937Shelge * Switch on tu_state of transfer. 58811876Shelge */ 58912937Shelge switch(uuc->tu_state) { 59011876Shelge 59111876Shelge /* 59211876Shelge * Two nulls have been sent, remove break, and send inits 59311876Shelge */ 59412937Shelge case TUS_INIT1: 59514091Shelge uuc->tu_flag = 0; 59612332Shelge uuaddr->tcs = UUCS_INTR; 59712937Shelge uuc->tu_state = TUS_INIT2; 59812937Shelge uuc->tu_wbptr = uuinit; 59912937Shelge uuc->tu_wcnt = sizeof (uuinit); 60011876Shelge goto top; 60111876Shelge 60211876Shelge /* 60311876Shelge * Inits have been sent, wait for a continue msg. 60411876Shelge */ 60512937Shelge case TUS_INIT2: 60612857Shelge c = uuaddr->rdb; /* prevent overrun error */ 60712332Shelge uuaddr->rcs = UUCS_INTR; 60812937Shelge uuc->tu_flag = 1; 60911876Shelge break; 61011876Shelge 61111876Shelge /* 61211876Shelge * Read cmd packet sent, get ready for data 61311876Shelge */ 61412937Shelge case TUS_SENDR: 61512937Shelge uuc->tu_state = TUS_GETH; 61612937Shelge uuc->tu_rbptr = (u_char *)data; 61712937Shelge uuc->tu_rcnt = 2; 61812937Shelge uuc->tu_flag = 1; 61914091Shelge uuaddr->tcs = 0; 62012937Shelge uuaddr->rcs = UUCS_INTR; 62111876Shelge break; 62211876Shelge 62311876Shelge /* 62411876Shelge * Write cmd packet sent, wait for continue 62511876Shelge */ 62612937Shelge case TUS_SENDW: 62712937Shelge uuc->tu_state = TUS_WAIT; 62812937Shelge uuc->tu_flag = 1; 62912332Shelge if ((uuaddr->rcs&UUCS_INTR) == 0) { 63011876Shelge printf("NO IE\n"); 63112332Shelge uuaddr->rcs = UUCS_INTR; 63211876Shelge } 63311876Shelge break; 63411876Shelge 63511876Shelge /* 63611876Shelge * Header sent, send data. 63711876Shelge */ 63812937Shelge case TUS_SENDH: 63912937Shelge uuc->tu_state = TUS_SENDD; 64012937Shelge uuc->tu_wbptr = (u_char *)uuc->tu_addr; 64112937Shelge uuc->tu_wcnt = data->pk_mcount; 64211876Shelge goto top; 64311876Shelge 64411876Shelge /* 64511876Shelge * Data sent, follow with checksum. 64611876Shelge */ 64712937Shelge case TUS_SENDD: 64812937Shelge uuc->tu_state = TUS_SENDC; 64912937Shelge uuc->tu_wbptr = (u_char *)&data->pk_chksum; 65014091Shelge uuc->tu_wcnt = 2; 65111876Shelge goto top; 65211876Shelge 65311876Shelge /* 65411876Shelge * Checksum sent, wait for continue. 65511876Shelge */ 65612937Shelge case TUS_SENDC: 65711876Shelge /* 65812937Shelge * Update buffer address and count. 65911876Shelge */ 66012937Shelge uuc->tu_addr += data->pk_mcount; 66112937Shelge uuc->tu_count -= data->pk_mcount; 66214091Shelge if (uuc->tu_count > 0) { 66312937Shelge uuc->tu_state = TUS_WAIT; 66412937Shelge uuc->tu_flag = 1; 66511876Shelge break; 66611876Shelge } 66711876Shelge 66811876Shelge /* 66911876Shelge * End of transmission, get ready for end packet. 67011876Shelge */ 67112937Shelge uuc->tu_state = TUS_GET; 67212937Shelge uuc->tu_rbptr = (u_char *)data; 67312937Shelge uuc->tu_rcnt = sizeof (*data); 67412937Shelge uuc->tu_flag = 1; 67514091Shelge uuaddr->tcs = 0; 67611876Shelge break; 67711876Shelge 67811876Shelge /* 67912332Shelge * Random interrupt 68011876Shelge */ 68113156Shelge case TUS_IDLE: /* stray interrupt? */ 68213156Shelge 68311876Shelge default: 68411876Shelge break; 68511876Shelge } 68612937Shelge } 68712937Shelge 68812937Shelge uuwatch() 68912937Shelge { 69013014Shelge register struct uu_softc *uuc; 69112937Shelge register struct uudevice *uuaddr; 69212937Shelge struct uba_device *ui; 69312937Shelge struct buf *bp, *uutab; 69412937Shelge int s, ctlr, active = 0; 69512937Shelge 69612937Shelge for (ctlr=0; ctlr<NUU; ctlr++) { 69712937Shelge int i; 69812937Shelge 69912937Shelge uuc = &uu_softc[ctlr]; 70014091Shelge 70114091Shelge if (uuc->tu_dopen[0] || uuc->tu_dopen[1]) 70214091Shelge active++; 70314091Shelge if (uuc->tu_flag == 0) 70414091Shelge /* 70514091Shelge * If no read is in progress 70614091Shelge * just skip 70714091Shelge */ 70814091Shelge continue; 70914091Shelge 71012937Shelge ui = uudinfo[ctlr]; 71112937Shelge uuaddr = (struct uudevice *)ui->ui_addr; 71212937Shelge uutab = &uitab[ctlr]; 71314091Shelge if (uuc->tu_flag++ < 40) 71412937Shelge continue; 71513156Shelge printf("uu%d: read stalled\n", uudata[ctlr].pk_unit); 71614091Shelge #ifdef UUDEBUG 71712937Shelge printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt, 71813156Shelge uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr, 71913156Shelge uuc->tu_count); 72013834Ssam #endif 72114091Shelge s = splx(UUIPL); 72212937Shelge uuc->tu_flag = 0; 72312937Shelge i = uuaddr->rdb; /* dummy */ 72412937Shelge uuaddr->rcs = UUCS_INTR; /* in case we were flushing */ 72512937Shelge uuaddr->tcs = UUCS_INTR; 72612937Shelge uuc->tu_state = TUS_IDLE; 72712937Shelge if (!uutab->b_active) { 72812937Shelge wakeup((caddr_t)uuc); 72912937Shelge goto retry; 73012937Shelge } 73112937Shelge if (++uutab->b_errcnt <= 1) { 73212937Shelge uustart(ui); 73312937Shelge goto retry; 73412937Shelge } 73512937Shelge if (bp = uutab->b_actf) { 73612937Shelge bp->b_flags |= B_ERROR; 73712937Shelge if ((bp->b_flags&B_READ) == 0) 73814091Shelge tu_vee(&uu_pcnt[UNIT(bp->b_dev)]); 73912937Shelge iodone(bp); 74012937Shelge } 74112937Shelge retry: 74212937Shelge (void) splx(s); 74311876Shelge } 74412937Shelge if (active) 74512937Shelge timeout(uuwatch, (caddr_t)0, hz); 74612937Shelge else 74712937Shelge uuwstart = 0; 74812937Shelge return; 74911876Shelge } 75011876Shelge 75112937Shelge #if !defined(VAX750) && !defined(VAX730) 75211876Shelge /* 75311876Shelge * Compute checksum TU58 fashion 75411876Shelge */ 75511876Shelge #ifdef lint 75612937Shelge tuchk(word, cp, n) 75711876Shelge register word; 75811876Shelge register unsigned short *cp; 75911876Shelge int n; 76011876Shelge { 76111876Shelge register int c = n >> 1; 76211876Shelge register long temp; 76311876Shelge 76411876Shelge do { 76511876Shelge temp = *cp++; /* temp, only because vax cc won't *r++ */ 76611876Shelge word += temp; 76711876Shelge } while (--c > 0); 76811876Shelge if (n & 1) 76911876Shelge word += *(unsigned char *)cp; 77011876Shelge while (word & 0xffff0000) 77111876Shelge word = (word & 0xffff) + ((word >> 16) & 0xffff); 77211876Shelge return (word); 77311876Shelge } 77411876Shelge #else 77512937Shelge tuchk(word0, wp, n) 77611896Shelge register int word0; /* r11 */ 77711896Shelge register char *wp; /* r10 */ 77811896Shelge register int n; /* r9 */ 77911876Shelge { 78011876Shelge asm("loop:"); 78111896Shelge asm(" addw2 (r10)+,r11"); /* add a word to sum */ 78211896Shelge asm(" adwc $0,r11"); /* add in carry, end-around */ 78311876Shelge asm(" acbl $2,$-2,r9,loop"); /* done yet? */ 78411896Shelge asm(" blbc r9,ok"); /* odd byte count? */ 78511896Shelge asm(" movzbw (r10),r10"); /* yes, get last byte */ 78611896Shelge asm(" addw2 r10,r11"); /* add it in */ 78711896Shelge asm(" adwc $0,r11"); /* and the carry */ 78811876Shelge asm("ok:"); 78911896Shelge asm(" movl r11,r0"); /* return sum */ 79011876Shelge } 79111876Shelge #endif 79211876Shelge 79314091Shelge /* 79414091Shelge * Make sure this incredibly slow device 79514091Shelge * doesn't eat up all the buffers in the 79614091Shelge * system by putting the requesting process 79714091Shelge * (remember: this device is 'single-user') 79814091Shelge * to sleep if the write-behind queue grows 79914091Shelge * larger than NUUQ. 80014091Shelge */ 80112937Shelge tu_pee(cp) 80214091Shelge char *cp; 80312332Shelge { 80412332Shelge register int s; 80512332Shelge 80612857Shelge s = splx(UUIPL); 80714091Shelge if (++(*cp) > NUUQ) 80812332Shelge sleep(cp, PRIBIO); 80912332Shelge splx(s); 81012332Shelge } 81112332Shelge 81212937Shelge tu_vee(cp) 81314091Shelge char *cp; 81412332Shelge { 81512332Shelge register int s; 81612332Shelge 81712857Shelge s = splx(UUIPL); 81814091Shelge if (--(*cp) <= NUUQ) 81912332Shelge wakeup(cp); 82011876Shelge splx(s); 82111876Shelge } 82211876Shelge #endif 82312332Shelge 82412937Shelge uuioctl(dev, cmd, data, flag) 82512937Shelge dev_t dev; 82612937Shelge caddr_t data; 82712937Shelge { 82812937Shelge /* 82913156Shelge * add code to wind/rewind cassette here 83012937Shelge */ 83112937Shelge return (ENXIO); 83212937Shelge } 83312937Shelge 83413014Shelge uu_restart(ctlr, ui) 83513014Shelge int ctlr; 83613014Shelge struct uba_device *ui; 83713014Shelge { 83813014Shelge uureset(ctlr); 83913014Shelge timeout(uustart, (caddr_t)ui, hz * 3); 84013014Shelge } 84114091Shelge 84214091Shelge #endif 843