123357Smckusick /*
229255Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323357Smckusick * All rights reserved. The Berkeley software License Agreement
423357Smckusick * specifies the terms and conditions for redistribution.
523357Smckusick *
6*45810Sbostic * @(#)ut.c 7.12 (Berkeley) 12/16/90
723357Smckusick */
84744Swnj
94862Sroot #include "tj.h"
104744Swnj #if NUT > 0
114744Swnj /*
124744Swnj * System Industries Model 9700 Tape Drive
134744Swnj * emulates a TU45 on the UNIBUS
144744Swnj *
154744Swnj * TODO:
164744Swnj * check out attention processing
174744Swnj * try reset code and dump code
184744Swnj */
19*45810Sbostic #include "sys/param.h"
20*45810Sbostic #include "sys/systm.h"
21*45810Sbostic #include "sys/buf.h"
22*45810Sbostic #include "sys/conf.h"
23*45810Sbostic #include "sys/errno.h"
24*45810Sbostic #include "sys/file.h"
25*45810Sbostic #include "sys/map.h"
26*45810Sbostic #include "sys/ioctl.h"
27*45810Sbostic #include "sys/mtio.h"
28*45810Sbostic #include "sys/cmap.h"
29*45810Sbostic #include "sys/time.h"
30*45810Sbostic #include "sys/uio.h"
31*45810Sbostic #include "sys/kernel.h"
32*45810Sbostic #include "sys/syslog.h"
33*45810Sbostic #include "sys/tprintf.h"
344744Swnj
35*45810Sbostic #include "../include/pte.h"
36*45810Sbostic #include "../include/cpu.h"
3717083Sbloom #include "ubareg.h"
3817083Sbloom #include "ubavar.h"
3917083Sbloom #include "utreg.h"
404744Swnj
414744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */
424744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */
434744Swnj
444744Swnj struct uba_ctlr *utminfo[NUT];
454744Swnj struct uba_device *tjdinfo[NTJ];
464833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer();
474744Swnj u_short utstd[] = { 0772440, 0 };
484744Swnj struct uba_driver utdriver =
494744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 };
504744Swnj
5111176Ssam #define MASKREG(reg) ((reg)&0xffff)
5211176Ssam
534744Swnj /* bits in minor device */
544744Swnj #define TJUNIT(dev) (minor(dev)&03)
554744Swnj #define T_NOREWIND 04
564744Swnj #define T_1600BPI 010
574744Swnj #define T_6250BPI 020
584744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI };
594744Swnj
604744Swnj /* slave to controller mapping table */
614744Swnj short tjtout[NTJ];
624744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)])
634744Swnj
644744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */
654744Swnj
664744Swnj struct tj_softc {
674744Swnj char sc_openf; /* exclusive open */
684744Swnj char sc_lastiow; /* last I/O operation was a write */
694744Swnj daddr_t sc_blkno; /* next block to transfer */
704744Swnj daddr_t sc_nxrec; /* next record on tape */
714744Swnj u_short sc_erreg; /* image of uter */
724744Swnj u_short sc_dsreg; /* image of utds */
734746Ssam u_short sc_resid; /* residual from transfer */
744744Swnj u_short sc_dens; /* sticky selected density */
754833Swnj daddr_t sc_timo; /* time until timeout expires */
764833Swnj short sc_tact; /* timeout is active flag */
7744395Smarc tpr_t sc_tpr; /* tprintf handle */
7830917Skarels int sc_blks; /* number of I/O operations since open */
7930917Skarels int sc_softerrs; /* number of soft I/O errors since open */
804744Swnj } tj_softc[NTJ];
814744Swnj
824744Swnj /*
834744Swnj * Internal per/slave states found in sc_state
844744Swnj */
854744Swnj #define SSEEK 1 /* seeking */
864744Swnj #define SIO 2 /* doing sequential I/O */
874744Swnj #define SCOM 3 /* sending a control command */
884744Swnj #define SREW 4 /* doing a rewind op */
894746Ssam #define SERASE 5 /* erase inter-record gap */
904746Ssam #define SERASED 6 /* erased inter-record gap */
914744Swnj
924941Swnj /*ARGSUSED*/
utprobe(reg)934744Swnj utprobe(reg)
944744Swnj caddr_t reg;
954744Swnj {
964744Swnj register int br, cvec;
974744Swnj #ifdef lint
984744Swnj br=0; cvec=br; br=cvec;
994941Swnj utintr(0);
1004744Swnj #endif
1014746Ssam /*
1026954Sroot * The SI documentation says you must set the RDY bit
1036954Sroot * (even though it's read-only) to force an interrupt.
1044746Ssam */
1056954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY;
1064744Swnj DELAY(10000);
1077405Skre return (sizeof (struct utdevice));
1084744Swnj }
1094744Swnj
1104744Swnj /*ARGSUSED*/
1114744Swnj utslave(ui, reg)
1124744Swnj struct uba_device *ui;
1134744Swnj caddr_t reg;
1144744Swnj {
1154744Swnj /*
1164744Swnj * A real TU45 would support the slave present bit
1174744Swnj * int the drive type register, but this thing doesn't,
1184744Swnj * so there's no way to determine if a slave is present or not.
1194744Swnj */
1204744Swnj return(1);
1214744Swnj }
1224744Swnj
1234744Swnj utattach(ui)
1244744Swnj struct uba_device *ui;
1254744Swnj {
1264744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr;
1274744Swnj }
1284744Swnj
1294744Swnj /*
1304744Swnj * Open the device with exclusive access.
1314744Swnj */
utopen(dev,flag)1324744Swnj utopen(dev, flag)
1334744Swnj dev_t dev;
1344744Swnj int flag;
1354744Swnj {
1364744Swnj register int tjunit = TJUNIT(dev);
1374744Swnj register struct uba_device *ui;
1384744Swnj register struct tj_softc *sc;
13940725Skarels int olddens, dens, error;
1405439Sroot register int s;
1414744Swnj
14225053Skarels if (tjunit >= NTJ || (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0)
1438577Sroot return (ENXIO);
14425053Skarels if ((sc = &tj_softc[tjunit])->sc_openf)
14525053Skarels return (EBUSY);
14630917Skarels sc->sc_openf = 1;
1474744Swnj olddens = sc->sc_dens;
1488577Sroot dens = sc->sc_dens =
1498577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]|
1508577Sroot PDP11FMT|(ui->ui_slave&07);
1514744Swnj get:
1524744Swnj utcommand(dev, UT_SENSE, 1);
1534744Swnj if (sc->sc_dsreg&UTDS_PIP) {
15440725Skarels if (error = tsleep((caddr_t)&lbolt, (PZERO+1) | PCATCH,
15540725Skarels devopn, 0))
15640725Skarels return (error);
1574744Swnj goto get;
1584744Swnj }
1594744Swnj sc->sc_dens = olddens;
1604744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) {
16130917Skarels sc->sc_openf = 0;
1624744Swnj uprintf("tj%d: not online\n", tjunit);
1638577Sroot return (EIO);
1644744Swnj }
1654744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) {
16630917Skarels sc->sc_openf = 0;
1674744Swnj uprintf("tj%d: no write ring\n", tjunit);
1688577Sroot return (EIO);
1694744Swnj }
1704744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) &&
1714744Swnj dens != sc->sc_dens) {
17230917Skarels sc->sc_openf = 0;
1734744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit);
1748577Sroot return (EIO);
1754744Swnj }
1764744Swnj sc->sc_blkno = (daddr_t)0;
1774744Swnj sc->sc_nxrec = INF;
1784744Swnj sc->sc_lastiow = 0;
17930917Skarels sc->sc_blks = 0;
18030917Skarels sc->sc_softerrs = 0;
1814744Swnj sc->sc_dens = dens;
18244395Smarc sc->sc_tpr = tprintf_open();
1834746Ssam /*
1844746Ssam * For 6250 bpi take exclusive use of the UNIBUS.
1854746Ssam */
1864746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI;
18726374Skarels s = splclock();
1884833Swnj if (sc->sc_tact == 0) {
1894833Swnj sc->sc_timo = INF;
1904833Swnj sc->sc_tact = 1;
1914833Swnj timeout(uttimer, (caddr_t)dev, 5*hz);
1924833Swnj }
1935439Sroot splx(s);
1948577Sroot return (0);
1954744Swnj }
1964744Swnj
utclose(dev,flag)1974744Swnj utclose(dev, flag)
1984744Swnj register dev_t dev;
1994744Swnj register flag;
2004744Swnj {
2014744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
2024744Swnj
2034744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) {
2044744Swnj utcommand(dev, UT_WEOF, 1);
2054744Swnj utcommand(dev, UT_WEOF, 1);
2064744Swnj utcommand(dev, UT_SREV, 1);
2074744Swnj }
2084744Swnj if ((minor(dev)&T_NOREWIND) == 0)
2094744Swnj utcommand(dev, UT_REW, 0);
21030917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
21130917Skarels log(LOG_INFO, "tj%d: %d soft errors in %d blocks\n",
21230917Skarels TJUNIT(dev), sc->sc_softerrs, sc->sc_blks);
21344395Smarc tprintf_close(sc->sc_tpr);
2144744Swnj sc->sc_openf = 0;
21540725Skarels return (0);
2164744Swnj }
2174744Swnj
utcommand(dev,com,count)2184744Swnj utcommand(dev, com, count)
2194744Swnj dev_t dev;
2204744Swnj int com, count;
2214744Swnj {
2224744Swnj register struct buf *bp;
2235439Sroot register int s;
2244744Swnj
2254744Swnj bp = &cutbuf[UTUNIT(dev)];
2265439Sroot s = spl5();
2274744Swnj while (bp->b_flags&B_BUSY) {
2284744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
2294744Swnj break;
2304744Swnj bp->b_flags |= B_WANTED;
2314744Swnj sleep((caddr_t)bp, PRIBIO);
2324744Swnj }
2334744Swnj bp->b_flags = B_BUSY|B_READ;
2345439Sroot splx(s);
2354744Swnj bp->b_dev = dev;
2364744Swnj bp->b_command = com;
2374744Swnj bp->b_repcnt = count;
2384744Swnj bp->b_blkno = 0;
2394744Swnj utstrategy(bp);
2404744Swnj if (count == 0)
2414744Swnj return;
2424744Swnj iowait(bp);
2434744Swnj if (bp->b_flags&B_WANTED)
2444744Swnj wakeup((caddr_t)bp);
2454744Swnj bp->b_flags &= B_ERROR;
2464744Swnj }
2474744Swnj
2484744Swnj /*
2494744Swnj * Queue a tape operation.
2504744Swnj */
utstrategy(bp)2514744Swnj utstrategy(bp)
2524744Swnj register struct buf *bp;
2534744Swnj {
2544744Swnj int tjunit = TJUNIT(bp->b_dev);
2554744Swnj register struct uba_ctlr *um;
2564744Swnj register struct buf *dp;
25734218Sbostic int s;
2584744Swnj
2594744Swnj /*
2604744Swnj * Put transfer at end of unit queue
2614744Swnj */
2624744Swnj dp = &tjutab[tjunit];
2634744Swnj bp->av_forw = NULL;
26417433Skarels um = tjdinfo[tjunit]->ui_mi;
26534218Sbostic s = spl5();
2664744Swnj if (dp->b_actf == NULL) {
2674744Swnj dp->b_actf = bp;
2684744Swnj /*
2694744Swnj * Transport not active, so...
2704744Swnj * put at end of controller queue
2714744Swnj */
2724744Swnj dp->b_forw = NULL;
2734744Swnj if (um->um_tab.b_actf == NULL)
2744744Swnj um->um_tab.b_actf = dp;
2754744Swnj else
2764744Swnj um->um_tab.b_actl->b_forw = dp;
2774744Swnj um->um_tab.b_actl = dp;
2784744Swnj } else
2794744Swnj dp->b_actl->av_forw = bp;
2804744Swnj dp->b_actl = bp;
2814744Swnj /*
2824744Swnj * If the controller is not busy, set it going.
2834744Swnj */
2844746Ssam if (um->um_tab.b_state == 0)
2854744Swnj utstart(um);
28634218Sbostic splx(s);
2874744Swnj }
2884744Swnj
utstart(um)2894744Swnj utstart(um)
2904744Swnj register struct uba_ctlr *um;
2914744Swnj {
2924746Ssam register struct utdevice *addr;
2934744Swnj register struct buf *bp, *dp;
2944744Swnj register struct tj_softc *sc;
2954744Swnj struct uba_device *ui;
2964744Swnj int tjunit;
2974744Swnj daddr_t blkno;
2984744Swnj
2994744Swnj loop:
3004744Swnj /*
3014744Swnj * Scan controller queue looking for units with
3024744Swnj * transaction queues to dispatch
3034744Swnj */
3044744Swnj if ((dp = um->um_tab.b_actf) == NULL)
3054744Swnj return;
3064744Swnj if ((bp = dp->b_actf) == NULL) {
3074744Swnj um->um_tab.b_actf = dp->b_forw;
3084744Swnj goto loop;
3094744Swnj }
3104746Ssam addr = (struct utdevice *)um->um_addr;
3114744Swnj tjunit = TJUNIT(bp->b_dev);
3124744Swnj ui = tjdinfo[tjunit];
3134744Swnj sc = &tj_softc[tjunit];
3144744Swnj /* note slave select, density, and format were merged on open */
3154746Ssam addr->uttc = sc->sc_dens;
3164746Ssam sc->sc_dsreg = addr->utds;
3174746Ssam sc->sc_erreg = addr->uter;
31811176Ssam sc->sc_resid = MASKREG(addr->utfc);
3194744Swnj /*
3204744Swnj * Default is that last command was NOT a write command;
3214744Swnj * if we do a write command we will notice this in utintr().
3224744Swnj */
3234744Swnj sc->sc_lastiow = 0;
3244746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) {
3254744Swnj /*
3264744Swnj * Have had a hard error on a non-raw tape
3274744Swnj * or the tape unit is now unavailable
3284744Swnj * (e.g. taken off line).
3294744Swnj */
3304744Swnj bp->b_flags |= B_ERROR;
3314744Swnj goto next;
3324744Swnj }
3334744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
3344744Swnj /*
3354744Swnj * Execute a control operation with the specified
3364744Swnj * count.
3374744Swnj */
3384744Swnj if (bp->b_command == UT_SENSE)
3394744Swnj goto next;
34011176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) {
34111176Ssam bp->b_resid = bp->b_bcount;
34211176Ssam goto next;
34311176Ssam }
3444744Swnj /*
3454744Swnj * Set next state; handle timeouts
3464744Swnj */
3474833Swnj if (bp->b_command == UT_REW) {
3484746Ssam um->um_tab.b_state = SREW;
3494833Swnj sc->sc_timo = 5*60;
3504833Swnj } else {
3514746Ssam um->um_tab.b_state = SCOM;
3524833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60);
3534833Swnj }
3544744Swnj /* NOTE: this depends on the ut command values */
3554744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF)
3564746Ssam addr->utfc = -bp->b_repcnt;
3574744Swnj goto dobpcmd;
3584744Swnj }
3594744Swnj /*
36034218Sbostic * For raw I/O, save the current block
36134218Sbostic * number in case we have to retry.
3624744Swnj */
36334218Sbostic if (bp->b_flags & B_RAW) {
36434218Sbostic if (um->um_tab.b_errcnt == 0) {
36534218Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno);
36634218Sbostic sc->sc_nxrec = sc->sc_blkno + 1;
36734218Sbostic }
3684744Swnj }
36934218Sbostic else {
37034218Sbostic /*
37134218Sbostic * Handle boundary cases for operation
37234218Sbostic * on non-raw tapes.
37334218Sbostic */
37434218Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
37534218Sbostic /* can't read past end of file */
37634218Sbostic bp->b_flags |= B_ERROR;
37734218Sbostic bp->b_error = ENXIO;
37834218Sbostic goto next;
37934218Sbostic }
38034218Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
38134218Sbostic (bp->b_flags&B_READ)) {
38234218Sbostic /*
38334218Sbostic * Reading at end of file returns 0 bytes.
38434218Sbostic */
38534218Sbostic bp->b_resid = bp->b_bcount;
38634218Sbostic clrbuf(bp);
38734218Sbostic goto next;
38834218Sbostic }
38934218Sbostic if ((bp->b_flags&B_READ) == 0)
39034218Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3914744Swnj }
3924744Swnj /*
3934744Swnj * If the tape is correctly positioned, set up all the
3944744Swnj * registers but the csr, and give control over to the
3954744Swnj * UNIBUS adaptor routines, to wait for resources to
3964744Swnj * start I/O.
3974744Swnj */
3987382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3994746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1);
4004746Ssam addr->utfc = -bp->b_bcount;
4014744Swnj if ((bp->b_flags&B_READ) == 0) {
4024744Swnj /*
4034744Swnj * On write error retries erase the
4044746Ssam * inter-record gap before rewriting.
4054744Swnj */
4064746Ssam if (um->um_tab.b_errcnt) {
4074746Ssam if (um->um_tab.b_state != SERASED) {
4084759Swnj um->um_tab.b_state = SERASE;
4094833Swnj sc->sc_timo = 60;
4104746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO;
4114746Ssam return;
4124746Ssam }
4134746Ssam }
41411176Ssam if (addr->utds & UTDS_EOT) {
41511176Ssam bp->b_resid = bp->b_bcount;
41611176Ssam um->um_tab.b_state = 0;
41711176Ssam goto next;
41811176Ssam }
4194746Ssam um->um_cmd = UT_WCOM;
4204744Swnj } else
4214744Swnj um->um_cmd = UT_RCOM;
4224833Swnj sc->sc_timo = 60;
4234746Ssam um->um_tab.b_state = SIO;
4244744Swnj (void) ubago(ui);
4254744Swnj return;
4264744Swnj }
4274744Swnj /*
4284744Swnj * Tape positioned incorrectly; seek forwards or
4294744Swnj * backwards to the correct spot. This happens for
4304744Swnj * raw tapes only on error retries.
4314744Swnj */
4324746Ssam um->um_tab.b_state = SSEEK;
4337382Ssam if (blkno < bdbtofsb(bp->b_blkno)) {
4347382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno);
4354744Swnj bp->b_command = UT_SFORW;
4364744Swnj } else {
4377382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno;
4384744Swnj bp->b_command = UT_SREV;
4394744Swnj }
4404833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60);
4414744Swnj
4424744Swnj dobpcmd:
4434744Swnj /*
4444744Swnj * Perform the command setup in bp.
4454744Swnj */
4464746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO;
4474744Swnj return;
4484744Swnj next:
4494744Swnj /*
4504744Swnj * Advance to the next command in the slave queue,
4514744Swnj * posting notice and releasing resources as needed.
4524744Swnj */
4534744Swnj if (um->um_ubinfo)
4544744Swnj ubadone(um);
4554744Swnj um->um_tab.b_errcnt = 0;
4564744Swnj dp->b_actf = bp->av_forw;
4574744Swnj iodone(bp);
4584744Swnj goto loop;
4594744Swnj }
4604744Swnj
4614744Swnj /*
4624744Swnj * Start operation on controller --
4634744Swnj * UNIBUS resources have been allocated.
4644744Swnj */
utdgo(um)4654744Swnj utdgo(um)
4664744Swnj register struct uba_ctlr *um;
4674744Swnj {
4684744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr;
4694744Swnj
4704744Swnj addr->utba = (u_short) um->um_ubinfo;
47111176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO;
4724744Swnj }
4734744Swnj
4744744Swnj /*
4754744Swnj * Ut interrupt handler
4764744Swnj */
4774744Swnj /*ARGSUSED*/
utintr(ut11)4784744Swnj utintr(ut11)
4794744Swnj int ut11;
4804744Swnj {
4814744Swnj struct buf *dp;
4824744Swnj register struct buf *bp;
4834744Swnj register struct uba_ctlr *um = utminfo[ut11];
4844744Swnj register struct utdevice *addr;
4854744Swnj register struct tj_softc *sc;
4864746Ssam u_short tjunit, cs2, cs1;
4874744Swnj register state;
4884744Swnj
4894744Swnj if ((dp = um->um_tab.b_actf) == NULL)
4904744Swnj return;
4914744Swnj bp = dp->b_actf;
4924744Swnj tjunit = TJUNIT(bp->b_dev);
4934744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr;
4944744Swnj sc = &tj_softc[tjunit];
4954744Swnj /*
4964744Swnj * Record status...
4974744Swnj */
4984877Ssam sc->sc_timo = INF;
4994744Swnj sc->sc_dsreg = addr->utds;
5004744Swnj sc->sc_erreg = addr->uter;
50111176Ssam sc->sc_resid = MASKREG(addr->utfc);
5024746Ssam if ((bp->b_flags&B_READ) == 0)
5034744Swnj sc->sc_lastiow = 1;
5044746Ssam state = um->um_tab.b_state;
5054746Ssam um->um_tab.b_state = 0;
5064744Swnj /*
5074744Swnj * Check for errors...
5084744Swnj */
5094744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) {
5104744Swnj /*
5114759Swnj * To clear the ERR bit, we must issue a drive clear
5124759Swnj * command, and to clear the TRE bit we must set the
5134759Swnj * controller clear bit.
5144759Swnj */
5154759Swnj cs2 = addr->utcs2;
5164759Swnj if ((cs1 = addr->utcs1)&UT_TRE)
5174759Swnj addr->utcs2 |= UTCS2_CLR;
5184759Swnj /* is this dangerous ?? */
5194759Swnj while ((addr->utcs1&UT_RDY) == 0)
5204759Swnj ;
5214759Swnj addr->utcs1 = UT_CLEAR|UT_GO;
5224759Swnj /*
52311176Ssam * If we were reading at 1600 or 6250 bpi and the error
52411176Ssam * was corrected, then don't consider this an error.
5254744Swnj */
52611190Ssam if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) &&
52711176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) {
52844395Smarc tprintf(sc->sc_tpr,
52911176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
53011176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
53111176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
53211176Ssam sc->sc_erreg &= ~UTER_COR;
5334744Swnj }
5344744Swnj /*
5354744Swnj * If we were reading from a raw tape and the only error
5364744Swnj * was that the record was too long, then we don't consider
5374744Swnj * this an error.
5384744Swnj */
53934218Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&
5404744Swnj (sc->sc_erreg&UTER_FCE))
54111176Ssam sc->sc_erreg &= ~UTER_FCE;
54211197Slayer if (sc->sc_erreg == 0)
5434744Swnj goto ignoreerr;
5444744Swnj /*
54511176Ssam * Fix up errors which occur due to backspacing
54611176Ssam * "over" the front of the tape.
5474746Ssam */
54811176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV &&
5494746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0))
5504746Ssam goto opdone;
5514746Ssam /*
5524744Swnj * Retry soft errors up to 8 times
5534744Swnj */
5544744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) {
5554744Swnj if (++um->um_tab.b_errcnt < 7) {
5564744Swnj sc->sc_blkno++;
5574744Swnj ubadone(um);
5584744Swnj goto opcont;
5594744Swnj }
56011176Ssam }
5614744Swnj /*
56211176Ssam * Hard or non-I/O errors on non-raw tape
56311176Ssam * cause it to close.
56411176Ssam */
56534218Sbostic if ((bp->b_flags&B_RAW) == 0 && sc->sc_openf > 0)
56611176Ssam sc->sc_openf = -1;
56711176Ssam /*
5684744Swnj * Couldn't recover error.
5694744Swnj */
57044395Smarc tprintf(sc->sc_tpr,
57118323Sralph "ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n",
5724746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg,
5734746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS);
5744744Swnj bp->b_flags |= B_ERROR;
5754744Swnj goto opdone;
5764744Swnj }
57711176Ssam
5784744Swnj ignoreerr:
5794744Swnj /*
58011176Ssam * If we hit a tape mark update our position.
58111176Ssam */
58211176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) {
58311176Ssam /*
58411176Ssam * Set blkno and nxrec
58511176Ssam */
58611176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) {
58711176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
58811176Ssam sc->sc_nxrec =
58911176Ssam bdbtofsb(bp->b_blkno) - addr->utfc;
59011176Ssam sc->sc_blkno = sc->sc_nxrec;
59111176Ssam } else {
59211176Ssam sc->sc_blkno =
59311176Ssam bdbtofsb(bp->b_blkno) + addr->utfc;
59411176Ssam sc->sc_nxrec = sc->sc_blkno-1;
59511176Ssam }
59611176Ssam } else
59711176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno);
59811176Ssam /*
59911176Ssam * Note: if we get a tape mark on a read, the
60011176Ssam * frame count register will be zero, so b_resid
60111176Ssam * will be calculated correctly below.
60211176Ssam */
60311176Ssam goto opdone;
60411176Ssam }
60511176Ssam /*
6064744Swnj * Advance tape control FSM.
6074744Swnj */
6084744Swnj switch (state) {
6094744Swnj
6104744Swnj case SIO: /* read/write increments tape block # */
6114744Swnj sc->sc_blkno++;
61230917Skarels sc->sc_blks++;
61330917Skarels if (um->um_tab.b_errcnt)
61430917Skarels sc->sc_softerrs++;
6154746Ssam break;
6164744Swnj
61711176Ssam case SCOM: /* motion commands update current position */
6184744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)])
61926296Skarels switch ((int)bp->b_command) {
6204744Swnj
6214744Swnj case UT_SFORW:
6224744Swnj sc->sc_blkno -= bp->b_repcnt;
6234744Swnj break;
6244744Swnj
6254744Swnj case UT_SREV:
6264744Swnj sc->sc_blkno += bp->b_repcnt;
6274744Swnj break;
62811176Ssam
62911176Ssam case UT_REWOFFL:
63011176Ssam addr->utcs1 = UT_CLEAR|UT_GO;
63111176Ssam break;
6324744Swnj }
6334746Ssam break;
6344744Swnj
6354744Swnj case SSEEK:
6367382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno);
6374744Swnj goto opcont;
6384744Swnj
6394746Ssam case SERASE:
6404746Ssam /*
6414746Ssam * Completed erase of the inter-record gap due to a
6424746Ssam * write error; now retry the write operation.
6434746Ssam */
6444746Ssam um->um_tab.b_state = SERASED;
6454746Ssam goto opcont;
6464746Ssam
6474746Ssam case SREW: /* clear attention bit */
6484746Ssam addr->utcs1 = UT_CLEAR|UT_GO;
6494746Ssam break;
6504746Ssam
6514744Swnj default:
6524746Ssam printf("bad state %d\n", state);
6534744Swnj panic("utintr");
6544744Swnj }
6554744Swnj
6564744Swnj opdone:
6574744Swnj /*
6584744Swnj * Reset error count and remove
6594744Swnj * from device queue
6604744Swnj */
6614744Swnj um->um_tab.b_errcnt = 0;
6624746Ssam dp->b_actf = bp->av_forw;
66311176Ssam /*
66411176Ssam * For read command, frame count register contains
66511176Ssam * actual length of tape record. Otherwise, it
66611176Ssam * holds negative residual count.
66711176Ssam */
66811176Ssam if (state == SIO && um->um_cmd == UT_RCOM) {
66911176Ssam bp->b_resid = 0;
67011176Ssam if (bp->b_bcount > MASKREG(addr->utfc))
67111176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc);
67211176Ssam } else
67311176Ssam bp->b_resid = MASKREG(-addr->utfc);
6744744Swnj ubadone(um);
6754744Swnj iodone(bp);
6764744Swnj /*
6774744Swnj * Circulate slave to end of controller queue
6784744Swnj * to give other slaves a chance
6794744Swnj */
6804744Swnj um->um_tab.b_actf = dp->b_forw;
6814744Swnj if (dp->b_actf) {
6824744Swnj dp->b_forw = NULL;
6834744Swnj if (um->um_tab.b_actf == NULL)
6844744Swnj um->um_tab.b_actf = dp;
6854744Swnj else
6864744Swnj um->um_tab.b_actl->b_forw = dp;
6874744Swnj um->um_tab.b_actl = dp;
6884744Swnj }
6894744Swnj if (um->um_tab.b_actf == 0)
6904744Swnj return;
6914744Swnj opcont:
6924744Swnj utstart(um);
6934744Swnj }
6944744Swnj
6954744Swnj /*
6964833Swnj * Watchdog timer routine.
6974833Swnj */
uttimer(dev)6984833Swnj uttimer(dev)
6994833Swnj int dev;
7004833Swnj {
7014833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
7024846Sroot register short x;
7034833Swnj
7044833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) {
7054859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev));
7064833Swnj sc->sc_timo = INF;
7074846Sroot x = spl5();
7084833Swnj utintr(UTUNIT(dev));
7094846Sroot (void) splx(x);
7104833Swnj }
7114833Swnj timeout(uttimer, (caddr_t)dev, 5*hz);
7124833Swnj }
7134833Swnj
7144744Swnj /*ARGSUSED*/
utioctl(dev,cmd,data,flag)7157634Ssam utioctl(dev, cmd, data, flag)
7164744Swnj dev_t dev;
7177634Ssam caddr_t data;
7184744Swnj {
7194744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)];
7204744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)];
7214744Swnj register callcount;
72240911Ssklower int fcount, error = 0;
7237634Ssam struct mtop *mtop;
7247634Ssam struct mtget *mtget;
7254744Swnj /* we depend of the values and order of the MT codes here */
7264744Swnj static utops[] =
7274744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE};
7284744Swnj
7294744Swnj switch (cmd) {
7304744Swnj
7314744Swnj case MTIOCTOP:
7327634Ssam mtop = (struct mtop *)data;
7337634Ssam switch(mtop->mt_op) {
7344744Swnj
7354744Swnj case MTWEOF:
73611413Ssam case MTFSF: case MTBSF:
73711413Ssam case MTFSR: case MTBSR:
7387634Ssam callcount = mtop->mt_count;
7394744Swnj fcount = 1;
7404744Swnj break;
7414744Swnj
7424744Swnj case MTREW: case MTOFFL: case MTNOP:
7434744Swnj callcount = 1;
7444744Swnj fcount = 1;
7454744Swnj break;
7464744Swnj
7474744Swnj default:
7488577Sroot return (ENXIO);
7494744Swnj }
7508577Sroot if (callcount <= 0 || fcount <= 0)
7518577Sroot return (EINVAL);
7524744Swnj while (--callcount >= 0) {
7537634Ssam utcommand(dev, utops[mtop->mt_op], fcount);
7544744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT))
7554744Swnj break;
7564744Swnj }
75740911Ssklower if (bp->b_flags&B_ERROR)
75840911Ssklower if ((error = bp->b_error)==0)
75940911Ssklower return (EIO);
76040911Ssklower return (error);
7614744Swnj
7624744Swnj case MTIOCGET:
7637634Ssam mtget = (struct mtget *)data;
7647634Ssam mtget->mt_dsreg = sc->sc_dsreg;
7657634Ssam mtget->mt_erreg = sc->sc_erreg;
7667634Ssam mtget->mt_resid = sc->sc_resid;
7677634Ssam mtget->mt_type = MT_ISUT;
7688577Sroot break;
7694744Swnj
7704744Swnj default:
7718577Sroot return (ENXIO);
7724744Swnj }
7738577Sroot return (0);
7744744Swnj }
7754744Swnj
utreset(uban)7764744Swnj utreset(uban)
7774744Swnj int uban;
7784744Swnj {
7794744Swnj register struct uba_ctlr *um;
7804744Swnj register ut11, tjunit;
7814744Swnj register struct uba_device *ui;
7824744Swnj register struct buf *dp;
7834744Swnj
7844744Swnj for (ut11 = 0; ut11 < NUT; ut11++) {
7854744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 ||
7864744Swnj um->um_ubanum != uban)
7874744Swnj continue;
7884744Swnj printf(" ut%d", ut11);
7894746Ssam um->um_tab.b_state = 0;
7904744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0;
7914744Swnj if (um->um_ubinfo) {
7924744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf);
7939358Ssam um->um_ubinfo = 0;
7944744Swnj }
7954744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO;
7964746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR;
7974744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) {
7984744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um ||
7994744Swnj ui->ui_alive == 0)
8004744Swnj continue;
8014744Swnj dp = &tjutab[tjunit];
8024746Ssam dp->b_state = 0;
8034744Swnj dp->b_forw = 0;
8044744Swnj if (um->um_tab.b_actf == NULL)
8054744Swnj um->um_tab.b_actf = dp;
8064744Swnj else
8074744Swnj um->um_tab.b_actl->b_forw = dp;
8084744Swnj um->um_tab.b_actl = dp;
8094744Swnj if (tj_softc[tjunit].sc_openf > 0)
8104744Swnj tj_softc[tjunit].sc_openf = -1;
8114744Swnj }
8124744Swnj utstart(um);
8134744Swnj }
8144744Swnj }
8154744Swnj
8164744Swnj /*
8174744Swnj * Do a stand-alone core dump to tape --
8184744Swnj * from here down, routines are used only in dump context
8194744Swnj */
8204744Swnj #define DBSIZE 20
8214744Swnj
utdump()8224744Swnj utdump()
8234744Swnj {
8244744Swnj register struct uba_device *ui;
8254744Swnj register struct uba_regs *up;
8264746Ssam register struct utdevice *addr;
8274744Swnj int blk, num = maxfree;
8284744Swnj int start = 0;
8294744Swnj
8304744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff))
8314744Swnj if (tjdinfo[0] == 0)
8324744Swnj return (ENXIO);
8334744Swnj ui = phys(tjdinfo[0], struct uba_device *);
8344744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
8354941Swnj ubainit(up);
8364744Swnj DELAY(1000000);
8374941Swnj addr = (struct utdevice *)ui->ui_physaddr;
8384746Ssam utwait(addr);
8394746Ssam /*
8404746Ssam * Be sure to set the appropriate density here. We use
8414746Ssam * 6250, but maybe it should be done at 1600 to insure the
8424746Ssam * tape can be read by most any other tape drive available.
8434746Ssam */
8444746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */
8454746Ssam addr->utcs1 = UT_CLEAR|UT_GO;
8464744Swnj while (num > 0) {
8474744Swnj blk = num > DBSIZE ? DBSIZE : num;
8484746Ssam utdwrite(start, blk, addr, up);
8494746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
8504746Ssam return(EIO);
8514744Swnj start += blk;
8524744Swnj num -= blk;
8534744Swnj }
8544746Ssam uteof(addr);
8554746Ssam uteof(addr);
8564746Ssam utwait(addr);
8574746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE))
8584744Swnj return(EIO);
8594746Ssam addr->utcs1 = UT_REW|UT_GO;
8604744Swnj return (0);
8614744Swnj }
8624744Swnj
utdwrite(dbuf,num,addr,up)8634746Ssam utdwrite(dbuf, num, addr, up)
8644744Swnj register dbuf, num;
8654746Ssam register struct utdevice *addr;
8664744Swnj struct uba_regs *up;
8674744Swnj {
8684744Swnj register struct pte *io;
8694744Swnj register int npf;
8704744Swnj
8714746Ssam utwait(addr);
8724744Swnj io = up->uba_map;
8734744Swnj npf = num + 1;
8744744Swnj while (--npf != 0)
8754744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV);
8764744Swnj *(int *)io = 0;
8774746Ssam addr->utwc = -((num*NBPG)>>1);
8784746Ssam addr->utfc = -(num*NBPG);
8794746Ssam addr->utba = 0;
8804746Ssam addr->utcs1 = UT_WCOM|UT_GO;
8814744Swnj }
8824744Swnj
8834746Ssam utwait(addr)
8844746Ssam struct utdevice *addr;
8854744Swnj {
8864744Swnj register s;
8874744Swnj
8884744Swnj do
8894746Ssam s = addr->utds;
8904744Swnj while ((s&UTDS_DRY) == 0);
8914744Swnj }
8924744Swnj
8934746Ssam uteof(addr)
8944746Ssam struct utdevice *addr;
8954744Swnj {
8964744Swnj
8974746Ssam utwait(addr);
8984746Ssam addr->utcs1 = UT_WEOF|UT_GO;
8994744Swnj }
9004744Swnj #endif
901