1*4759Swnj /* ut.c 4.3 81/11/07 */ 24744Swnj 34744Swnj #include "ut.h" 44744Swnj #if NUT > 0 54744Swnj /* 64744Swnj * System Industries Model 9700 Tape Drive 74744Swnj * emulates a TU45 on the UNIBUS 84744Swnj * 94744Swnj * TODO: 104744Swnj * check out attention processing 114744Swnj * try reset code and dump code 124744Swnj */ 134744Swnj #include "../h/param.h" 144744Swnj #include "../h/systm.h" 154744Swnj #include "../h/buf.h" 164744Swnj #include "../h/conf.h" 174744Swnj #include "../h/dir.h" 184744Swnj #include "../h/file.h" 194744Swnj #include "../h/user.h" 204744Swnj #include "../h/map.h" 214744Swnj #include "../h/pte.h" 224744Swnj #include "../h/ubareg.h" 234744Swnj #include "../h/ubavar.h" 244744Swnj #include "../h/mtio.h" 254744Swnj #include "../h/ioctl.h" 264744Swnj #include "../h/cmap.h" 274744Swnj #include "../h/cpu.h" 284744Swnj 294744Swnj #include "../h/utreg.h" 304744Swnj 314744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 324744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 334744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 344744Swnj 354744Swnj struct uba_ctlr *utminfo[NUT]; 364744Swnj struct uba_device *tjdinfo[NTJ]; 374744Swnj int utprobe(), utslave(), utattach(), utdgo(); 384744Swnj u_short utstd[] = { 0772440, 0 }; 394744Swnj struct uba_driver utdriver = 404744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 414744Swnj 424744Swnj /* bits in minor device */ 434744Swnj #define TJUNIT(dev) (minor(dev)&03) 444744Swnj #define T_NOREWIND 04 454744Swnj #define T_1600BPI 010 464744Swnj #define T_6250BPI 020 474744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 484744Swnj 494744Swnj /* slave to controller mapping table */ 504744Swnj short tjtout[NTJ]; 514744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 524744Swnj 534744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 544744Swnj 554744Swnj struct tj_softc { 564744Swnj char sc_openf; /* exclusive open */ 574744Swnj char sc_lastiow; /* last I/O operation was a write */ 584744Swnj daddr_t sc_blkno; /* next block to transfer */ 594744Swnj daddr_t sc_nxrec; /* next record on tape */ 604744Swnj u_short sc_erreg; /* image of uter */ 614744Swnj u_short sc_dsreg; /* image of utds */ 624746Ssam u_short sc_resid; /* residual from transfer */ 634744Swnj u_short sc_dens; /* sticky selected density */ 644744Swnj } tj_softc[NTJ]; 654744Swnj 664744Swnj /* 674744Swnj * Internal per/slave states found in sc_state 684744Swnj */ 694744Swnj #define SSEEK 1 /* seeking */ 704744Swnj #define SIO 2 /* doing sequential I/O */ 714744Swnj #define SCOM 3 /* sending a control command */ 724744Swnj #define SREW 4 /* doing a rewind op */ 734746Ssam #define SERASE 5 /* erase inter-record gap */ 744746Ssam #define SERASED 6 /* erased inter-record gap */ 754744Swnj 764744Swnj /* 774744Swnj * A NOP should get an interrupt back, if the 784744Swnj * device is there. 794744Swnj */ 804744Swnj utprobe(reg) 814744Swnj caddr_t reg; 824744Swnj { 834744Swnj register int br, cvec; 844744Swnj #ifdef lint 854744Swnj br=0; cvec=br; br=cvec; 864744Swnj #endif 874746Ssam /* 884746Ssam * It appears the controller won't interrupt unless the 894746Ssam * slave is off-line...this is as bad as the TS-11. 904746Ssam */ 914746Ssam #ifdef notdef 924744Swnj ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_GO; 934744Swnj DELAY(10000); 944744Swnj ((struct utdevice *) reg)->utcs1 = UT_CLEAR|UT_GO; 954746Ssam #else 964746Ssam br = 0x15; 974746Ssam cvec = 0164; 984744Swnj return(1); 994746Ssam #endif 1004744Swnj } 1014744Swnj 1024744Swnj /*ARGSUSED*/ 1034744Swnj utslave(ui, reg) 1044744Swnj struct uba_device *ui; 1054744Swnj caddr_t reg; 1064744Swnj { 1074744Swnj /* 1084744Swnj * A real TU45 would support the slave present bit 1094744Swnj * int the drive type register, but this thing doesn't, 1104744Swnj * so there's no way to determine if a slave is present or not. 1114744Swnj */ 1124744Swnj return(1); 1134744Swnj } 1144744Swnj 1154744Swnj utattach(ui) 1164744Swnj struct uba_device *ui; 1174744Swnj { 1184744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1194744Swnj } 1204744Swnj 1214744Swnj /* 1224744Swnj * Open the device with exclusive access. 1234744Swnj */ 1244744Swnj utopen(dev, flag) 1254744Swnj dev_t dev; 1264744Swnj int flag; 1274744Swnj { 1284744Swnj register int tjunit = TJUNIT(dev); 1294744Swnj register struct uba_device *ui; 1304744Swnj register struct tj_softc *sc; 1314744Swnj int olddens, dens; 1324744Swnj 1334744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 1344744Swnj (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) { 1354744Swnj u.u_error = ENXIO; 1364744Swnj return; 1374744Swnj } 1384744Swnj olddens = sc->sc_dens; 1394744Swnj dens = sc->sc_dens = utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1404744Swnj PDP11FMT|(ui->ui_slave&07); 1414744Swnj get: 1424744Swnj utcommand(dev, UT_SENSE, 1); 1434744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1444744Swnj sleep((caddr_t) &lbolt, PZERO+1); 1454744Swnj goto get; 1464744Swnj } 1474744Swnj sc->sc_dens = olddens; 1484744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 1494744Swnj uprintf("tj%d: not online\n", tjunit); 1504744Swnj u.u_error = EIO; 1514744Swnj return; 1524744Swnj } 1534744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 1544744Swnj uprintf("tj%d: no write ring\n", tjunit); 1554744Swnj u.u_error = EIO; 1564744Swnj return; 1574744Swnj } 1584744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1594744Swnj dens != sc->sc_dens) { 1604744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1614744Swnj u.u_error = EIO; 1624744Swnj return; 1634744Swnj } 1644744Swnj sc->sc_openf = 1; 1654744Swnj sc->sc_blkno = (daddr_t)0; 1664744Swnj sc->sc_nxrec = INF; 1674744Swnj sc->sc_lastiow = 0; 1684744Swnj sc->sc_dens = dens; 1694746Ssam /* 1704746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1714746Ssam */ 1724746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 1734744Swnj } 1744744Swnj 1754744Swnj utclose(dev, flag) 1764744Swnj register dev_t dev; 1774744Swnj register flag; 1784744Swnj { 1794744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 1804744Swnj 1814744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 1824744Swnj utcommand(dev, UT_WEOF, 1); 1834744Swnj utcommand(dev, UT_WEOF, 1); 1844744Swnj utcommand(dev, UT_SREV, 1); 1854744Swnj } 1864744Swnj if ((minor(dev)&T_NOREWIND) == 0) 1874744Swnj utcommand(dev, UT_REW, 0); 1884744Swnj sc->sc_openf = 0; 1894744Swnj } 1904744Swnj 1914744Swnj utcommand(dev, com, count) 1924744Swnj dev_t dev; 1934744Swnj int com, count; 1944744Swnj { 1954744Swnj register struct buf *bp; 1964744Swnj 1974744Swnj bp = &cutbuf[UTUNIT(dev)]; 1984744Swnj (void) spl5(); 1994744Swnj while (bp->b_flags&B_BUSY) { 2004744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2014744Swnj break; 2024744Swnj bp->b_flags |= B_WANTED; 2034744Swnj sleep((caddr_t)bp, PRIBIO); 2044744Swnj } 2054744Swnj bp->b_flags = B_BUSY|B_READ; 2064744Swnj (void) spl0(); 2074744Swnj bp->b_dev = dev; 2084744Swnj bp->b_command = com; 2094744Swnj bp->b_repcnt = count; 2104744Swnj bp->b_blkno = 0; 2114744Swnj utstrategy(bp); 2124744Swnj if (count == 0) 2134744Swnj return; 2144744Swnj iowait(bp); 2154744Swnj if (bp->b_flags&B_WANTED) 2164744Swnj wakeup((caddr_t)bp); 2174744Swnj bp->b_flags &= B_ERROR; 2184744Swnj } 2194744Swnj 2204744Swnj /* 2214744Swnj * Queue a tape operation. 2224744Swnj */ 2234744Swnj utstrategy(bp) 2244744Swnj register struct buf *bp; 2254744Swnj { 2264744Swnj int tjunit = TJUNIT(bp->b_dev); 2274744Swnj register struct uba_ctlr *um; 2284744Swnj register struct buf *dp; 2294744Swnj 2304744Swnj /* 2314744Swnj * Put transfer at end of unit queue 2324744Swnj */ 2334744Swnj dp = &tjutab[tjunit]; 2344744Swnj bp->av_forw = NULL; 2354744Swnj (void) spl5(); 2364744Swnj if (dp->b_actf == NULL) { 2374744Swnj dp->b_actf = bp; 2384744Swnj /* 2394744Swnj * Transport not active, so... 2404744Swnj * put at end of controller queue 2414744Swnj */ 2424744Swnj dp->b_forw = NULL; 2434744Swnj um = tjdinfo[tjunit]->ui_mi; 2444744Swnj if (um->um_tab.b_actf == NULL) 2454744Swnj um->um_tab.b_actf = dp; 2464744Swnj else 2474744Swnj um->um_tab.b_actl->b_forw = dp; 2484744Swnj um->um_tab.b_actl = dp; 2494744Swnj } else 2504744Swnj dp->b_actl->av_forw = bp; 2514744Swnj dp->b_actl = bp; 2524744Swnj /* 2534744Swnj * If the controller is not busy, set it going. 2544744Swnj */ 2554746Ssam if (um->um_tab.b_state == 0) 2564744Swnj utstart(um); 2574744Swnj (void) spl0(); 2584744Swnj } 2594744Swnj 2604744Swnj utstart(um) 2614744Swnj register struct uba_ctlr *um; 2624744Swnj { 2634746Ssam register struct utdevice *addr; 2644744Swnj register struct buf *bp, *dp; 2654744Swnj register struct tj_softc *sc; 2664744Swnj struct uba_device *ui; 2674744Swnj int tjunit; 2684744Swnj daddr_t blkno; 2694744Swnj 2704744Swnj loop: 2714744Swnj /* 2724744Swnj * Scan controller queue looking for units with 2734744Swnj * transaction queues to dispatch 2744744Swnj */ 2754744Swnj if ((dp = um->um_tab.b_actf) == NULL) 2764744Swnj return; 2774744Swnj if ((bp = dp->b_actf) == NULL) { 2784744Swnj um->um_tab.b_actf = dp->b_forw; 2794744Swnj goto loop; 2804744Swnj } 2814746Ssam addr = (struct utdevice *)um->um_addr; 2824744Swnj tjunit = TJUNIT(bp->b_dev); 2834744Swnj ui = tjdinfo[tjunit]; 2844744Swnj sc = &tj_softc[tjunit]; 2854744Swnj /* note slave select, density, and format were merged on open */ 2864746Ssam addr->uttc = sc->sc_dens; 2874746Ssam sc->sc_dsreg = addr->utds; 2884746Ssam sc->sc_erreg = addr->uter; 2894746Ssam /* watch this, sports fans */ 2904746Ssam sc->sc_resid = bp->b_flags&B_READ ? 2914746Ssam bp->b_bcount - ((-addr->utfc)&0xffff) : -addr->utwc<<1; 2924744Swnj /* 2934744Swnj * Default is that last command was NOT a write command; 2944744Swnj * if we do a write command we will notice this in utintr(). 2954744Swnj */ 2964744Swnj sc->sc_lastiow = 0; 2974746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 2984744Swnj /* 2994744Swnj * Have had a hard error on a non-raw tape 3004744Swnj * or the tape unit is now unavailable 3014744Swnj * (e.g. taken off line). 3024744Swnj */ 3034744Swnj bp->b_flags |= B_ERROR; 3044744Swnj goto next; 3054744Swnj } 3064744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3074744Swnj /* 3084744Swnj * Execute a control operation with the specified 3094744Swnj * count. 3104744Swnj */ 3114744Swnj if (bp->b_command == UT_SENSE) 3124744Swnj goto next; 3134744Swnj /* 3144744Swnj * Set next state; handle timeouts 3154744Swnj */ 3164744Swnj if (bp->b_command == UT_REW) 3174746Ssam um->um_tab.b_state = SREW; 3184744Swnj else 3194746Ssam um->um_tab.b_state = SCOM; 3204744Swnj /* NOTE: this depends on the ut command values */ 3214744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3224746Ssam addr->utfc = -bp->b_repcnt; 3234744Swnj goto dobpcmd; 3244744Swnj } 3254744Swnj /* 3264744Swnj * The following checks boundary conditions for operations 3274744Swnj * on non-raw tapes. On raw tapes the initialization of 3284744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3294744Swnj * (except in the case of retries). 3304744Swnj */ 3314744Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3324744Swnj /* can't read past end of file */ 3334744Swnj bp->b_flags |= B_ERROR; 3344744Swnj bp->b_error = ENXIO; 3354744Swnj goto next; 3364744Swnj } 3374744Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3384744Swnj /* read at eof returns 0 count */ 3394744Swnj bp->b_resid = bp->b_bcount; 3404744Swnj clrbuf(bp); 3414744Swnj goto next; 3424744Swnj } 3434744Swnj if ((bp->b_flags&B_READ) == 0) 3444744Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno)+1; 3454744Swnj /* 3464744Swnj * If the tape is correctly positioned, set up all the 3474744Swnj * registers but the csr, and give control over to the 3484744Swnj * UNIBUS adaptor routines, to wait for resources to 3494744Swnj * start I/O. 3504744Swnj */ 3514744Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 3524746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3534746Ssam addr->utfc = -bp->b_bcount; 3544744Swnj if ((bp->b_flags&B_READ) == 0) { 3554744Swnj /* 3564744Swnj * On write error retries erase the 3574746Ssam * inter-record gap before rewriting. 3584744Swnj */ 3594746Ssam if (um->um_tab.b_errcnt) { 3604746Ssam if (um->um_tab.b_state != SERASED) { 361*4759Swnj um->um_tab.b_state = SERASE; 3624746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3634746Ssam return; 3644746Ssam } 3654746Ssam } 3664746Ssam um->um_cmd = UT_WCOM; 3674744Swnj } else 3684744Swnj um->um_cmd = UT_RCOM; 3694746Ssam um->um_tab.b_state = SIO; 3704744Swnj (void) ubago(ui); 3714744Swnj return; 3724744Swnj } 3734744Swnj /* 3744744Swnj * Tape positioned incorrectly; seek forwards or 3754744Swnj * backwards to the correct spot. This happens for 3764744Swnj * raw tapes only on error retries. 3774744Swnj */ 3784746Ssam um->um_tab.b_state = SSEEK; 3794744Swnj if (blkno < dbtofsb(bp->b_blkno)) { 3804746Ssam addr->utfc = blkno - dbtofsb(bp->b_blkno); 3814744Swnj bp->b_command = UT_SFORW; 3824744Swnj } else { 3834746Ssam addr->utfc = dbtofsb(bp->b_blkno) - blkno; 3844744Swnj bp->b_command = UT_SREV; 3854744Swnj } 3864744Swnj 3874744Swnj dobpcmd: 3884744Swnj /* 3894744Swnj * Perform the command setup in bp. 3904744Swnj */ 3914746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 3924744Swnj return; 3934744Swnj next: 3944744Swnj /* 3954744Swnj * Advance to the next command in the slave queue, 3964744Swnj * posting notice and releasing resources as needed. 3974744Swnj */ 3984744Swnj if (um->um_ubinfo) 3994744Swnj ubadone(um); 4004744Swnj um->um_tab.b_errcnt = 0; 4014744Swnj dp->b_actf = bp->av_forw; 4024744Swnj iodone(bp); 4034744Swnj goto loop; 4044744Swnj } 4054744Swnj 4064744Swnj /* 4074744Swnj * Start operation on controller -- 4084744Swnj * UNIBUS resources have been allocated. 4094744Swnj */ 4104744Swnj utdgo(um) 4114744Swnj register struct uba_ctlr *um; 4124744Swnj { 4134744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4144744Swnj 4154744Swnj addr->utba = (u_short) um->um_ubinfo; 4164744Swnj addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x30)|UT_IE|UT_GO; 4174744Swnj } 4184744Swnj 4194744Swnj /* 4204744Swnj * Ut interrupt handler 4214744Swnj */ 4224744Swnj /*ARGSUSED*/ 4234744Swnj utintr(ut11) 4244744Swnj int ut11; 4254744Swnj { 4264744Swnj struct buf *dp; 4274744Swnj register struct buf *bp; 4284744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4294744Swnj register struct utdevice *addr; 4304744Swnj register struct tj_softc *sc; 4314746Ssam u_short tjunit, cs2, cs1; 4324744Swnj register state; 4334744Swnj 4344744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4354744Swnj return; 4364744Swnj bp = dp->b_actf; 4374744Swnj tjunit = TJUNIT(bp->b_dev); 4384744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4394744Swnj sc = &tj_softc[tjunit]; 4404744Swnj /* 4414744Swnj * Record status... 4424744Swnj */ 4434744Swnj sc->sc_dsreg = addr->utds; 4444744Swnj sc->sc_erreg = addr->uter; 4454746Ssam sc->sc_resid = bp->b_flags&B_READ ? 4464746Ssam bp->b_bcount - (-addr->utfc)&0xffff : -addr->utwc<<1; 4474746Ssam if ((bp->b_flags&B_READ) == 0) 4484744Swnj sc->sc_lastiow = 1; 4494746Ssam state = um->um_tab.b_state; 4504746Ssam um->um_tab.b_state = 0; 4514744Swnj /* 4524744Swnj * Check for errors... 4534744Swnj */ 4544744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4554744Swnj /* 456*4759Swnj * To clear the ERR bit, we must issue a drive clear 457*4759Swnj * command, and to clear the TRE bit we must set the 458*4759Swnj * controller clear bit. 459*4759Swnj */ 460*4759Swnj cs2 = addr->utcs2; 461*4759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 462*4759Swnj addr->utcs2 |= UTCS2_CLR; 463*4759Swnj /* is this dangerous ?? */ 464*4759Swnj while ((addr->utcs1&UT_RDY) == 0) 465*4759Swnj ; 466*4759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 467*4759Swnj /* 4684746Ssam * If we hit a tape mark or EOT update our position. 4694744Swnj */ 470*4759Swnj if (sc->sc_dsreg&(UTDS_TM|UTDS_EOT)) { 4714744Swnj /* 472*4759Swnj * Set blkno and nxrec 4734744Swnj */ 4744744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 4754744Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 4764744Swnj sc->sc_nxrec = 4774744Swnj dbtofsb(bp->b_blkno) - addr->utfc; 4784744Swnj sc->sc_blkno = sc->sc_nxrec; 4794744Swnj } else { 4804744Swnj sc->sc_blkno = 4814744Swnj dbtofsb(bp->b_blkno) + addr->utfc; 4824744Swnj sc->sc_nxrec = sc->sc_blkno-1; 4834744Swnj } 4844746Ssam } else 4854744Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 4864744Swnj state = SCOM; /* force completion */ 4874744Swnj /* 4884746Ssam * Stuff so we can unstuff later 4894746Ssam * to get the residual. 4904744Swnj */ 4914746Ssam addr->utwc = (-bp->b_bcount)>>1; 4924744Swnj addr->utfc = -bp->b_bcount; 4934746Ssam if (sc->sc_dsreg&UTDS_EOT) 4944746Ssam goto harderror; 4954744Swnj goto opdone; 4964744Swnj } 4974744Swnj /* 4984744Swnj * If we were reading from a raw tape and the only error 4994744Swnj * was that the record was too long, then we don't consider 5004744Swnj * this an error. 5014744Swnj */ 5024744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5034744Swnj (sc->sc_erreg&UTER_FCE)) 5044744Swnj goto ignoreerr; 5054744Swnj /* 5064746Ssam * Fix up errors which occur due to backspacing "over" the 5074746Ssam * front of the tape. 5084746Ssam */ 5094746Ssam if ((sc->sc_dsreg&UTDS_BOT) && 5104746Ssam (bp->b_command == UT_SREV || bp->b_command == UT_SREV) && 5114746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5124746Ssam goto opdone; 5134746Ssam /* 5144744Swnj * Retry soft errors up to 8 times 5154744Swnj */ 5164744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5174744Swnj if (++um->um_tab.b_errcnt < 7) { 5184744Swnj sc->sc_blkno++; 5194744Swnj ubadone(um); 5204744Swnj goto opcont; 5214744Swnj } 5224744Swnj } else 5234746Ssam harderror: 5244744Swnj /* 5254744Swnj * Hard or non-I/O errors on non-raw tape 5264746Ssam * cause it to close; also, reading off the 5274746Ssam * end of the tape. 5284744Swnj */ 5294746Ssam if (sc->sc_openf > 0 && 5304746Ssam bp != &rutbuf[UTUNIT(bp->b_dev)] || 5314746Ssam sc->sc_dsreg&UTDS_EOT) 5324744Swnj sc->sc_openf = -1; 5334744Swnj /* 5344744Swnj * Couldn't recover error. 5354744Swnj */ 5364746Ssam printf("ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5374746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5384746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5394744Swnj bp->b_flags |= B_ERROR; 5404744Swnj goto opdone; 5414744Swnj } 5424744Swnj ignoreerr: 5434744Swnj /* 5444744Swnj * Advance tape control FSM. 5454744Swnj */ 5464744Swnj switch (state) { 5474744Swnj 5484744Swnj case SIO: /* read/write increments tape block # */ 5494744Swnj sc->sc_blkno++; 5504746Ssam break; 5514744Swnj 5524744Swnj case SCOM: /* forw/rev space updates current position */ 5534744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 5544744Swnj switch (bp->b_command) { 5554744Swnj 5564744Swnj case UT_SFORW: 5574744Swnj sc->sc_blkno -= bp->b_repcnt; 5584744Swnj break; 5594744Swnj 5604744Swnj case UT_SREV: 5614744Swnj sc->sc_blkno += bp->b_repcnt; 5624744Swnj break; 5634744Swnj } 5644746Ssam break; 5654744Swnj 5664744Swnj case SSEEK: 5674744Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 5684744Swnj goto opcont; 5694744Swnj 5704746Ssam case SERASE: 5714746Ssam /* 5724746Ssam * Completed erase of the inter-record gap due to a 5734746Ssam * write error; now retry the write operation. 5744746Ssam */ 5754746Ssam um->um_tab.b_state = SERASED; 5764746Ssam goto opcont; 5774746Ssam 5784746Ssam case SREW: /* clear attention bit */ 5794746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 5804746Ssam break; 5814746Ssam 5824744Swnj default: 5834746Ssam printf("bad state %d\n", state); 5844744Swnj panic("utintr"); 5854744Swnj } 5864744Swnj 5874744Swnj opdone: 5884744Swnj /* 5894744Swnj * Reset error count and remove 5904744Swnj * from device queue 5914744Swnj */ 5924744Swnj um->um_tab.b_errcnt = 0; 5934746Ssam dp->b_actf = bp->av_forw; 5944746Ssam bp->b_resid = bp->b_command&B_READ ? 5954746Ssam bp->b_bcount - ((-addr->utfc)&0xffff) : -addr->utwc<<1; 5964744Swnj ubadone(um); 5974744Swnj iodone(bp); 5984744Swnj /* 5994744Swnj * Circulate slave to end of controller queue 6004744Swnj * to give other slaves a chance 6014744Swnj */ 6024744Swnj um->um_tab.b_actf = dp->b_forw; 6034744Swnj if (dp->b_actf) { 6044744Swnj dp->b_forw = NULL; 6054744Swnj if (um->um_tab.b_actf == NULL) 6064744Swnj um->um_tab.b_actf = dp; 6074744Swnj else 6084744Swnj um->um_tab.b_actl->b_forw = dp; 6094744Swnj um->um_tab.b_actl = dp; 6104744Swnj } 6114744Swnj if (um->um_tab.b_actf == 0) 6124744Swnj return; 6134744Swnj opcont: 6144744Swnj utstart(um); 6154744Swnj } 6164744Swnj 6174744Swnj /* 6184744Swnj * Raw interface for a read 6194744Swnj */ 6204744Swnj utread(dev) 6214744Swnj dev_t dev; 6224744Swnj { 6234744Swnj utphys(dev); 6244744Swnj if (u.u_error) 6254744Swnj return; 6264744Swnj physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys); 6274744Swnj } 6284744Swnj 6294744Swnj /* 6304744Swnj * Raw interface for a write 6314744Swnj */ 6324744Swnj utwrite(dev) 6334744Swnj { 6344744Swnj utphys(dev); 6354744Swnj if (u.u_error) 6364744Swnj return; 6374744Swnj physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys); 6384744Swnj } 6394744Swnj 6404744Swnj /* 6414744Swnj * Check for valid device number dev and update our notion 6424744Swnj * of where we are on the tape 6434744Swnj */ 6444744Swnj utphys(dev) 6454744Swnj dev_t dev; 6464744Swnj { 6474744Swnj register int tjunit = TJUNIT(dev); 6484744Swnj register struct tj_softc *sc; 6494744Swnj register struct uba_device *ui; 6504744Swnj 6514744Swnj if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) { 6524744Swnj u.u_error = ENXIO; 6534744Swnj return; 6544744Swnj } 6554744Swnj sc = &tj_softc[tjunit]; 6564746Ssam sc->sc_blkno = dbtofsb(u.u_offset>>9); 6574746Ssam sc->sc_nxrec = sc->sc_blkno+1; 6584744Swnj } 6594744Swnj 6604744Swnj /*ARGSUSED*/ 6614744Swnj utioctl(dev, cmd, addr, flag) 6624744Swnj dev_t dev; 6634744Swnj caddr_t addr; 6644744Swnj { 6654744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6664744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 6674744Swnj register callcount; 6684744Swnj int fcount; 6694744Swnj struct mtop mtop; 6704744Swnj struct mtget mtget; 6714744Swnj /* we depend of the values and order of the MT codes here */ 6724744Swnj static utops[] = 6734744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 6744744Swnj 6754744Swnj switch (cmd) { 6764744Swnj 6774744Swnj case MTIOCTOP: 6784744Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 6794744Swnj u.u_error = EFAULT; 6804744Swnj return; 6814744Swnj } 6824744Swnj switch(mtop.mt_op) { 6834744Swnj 6844744Swnj case MTWEOF: 6854744Swnj callcount = mtop.mt_count; 6864744Swnj fcount = 1; 6874744Swnj break; 6884744Swnj 6894744Swnj case MTFSF: case MTBSF: 6904744Swnj case MTFSR: case MTBSR: 6914744Swnj callcount = 1; 6924744Swnj fcount = mtop.mt_count; 6934744Swnj break; 6944744Swnj 6954744Swnj case MTREW: case MTOFFL: case MTNOP: 6964744Swnj callcount = 1; 6974744Swnj fcount = 1; 6984744Swnj break; 6994744Swnj 7004744Swnj default: 7014744Swnj u.u_error = ENXIO; 7024744Swnj return; 7034744Swnj } 7044744Swnj if (callcount <= 0 || fcount <= 0) { 7054744Swnj u.u_error = ENXIO; 7064744Swnj return; 7074744Swnj } 7084744Swnj while (--callcount >= 0) { 7094744Swnj utcommand(dev, utops[mtop.mt_op], fcount); 7104746Ssam /* note this depends on the mtop values */ 7114746Ssam if ((mtop.mt_op >= MTFSF || mtop.mt_op <= MTBSR) && 7124744Swnj bp->b_resid) { 7134744Swnj u.u_error = EIO; 7144744Swnj break; 7154744Swnj } 7164744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7174744Swnj break; 7184744Swnj } 7194744Swnj geterror(bp); 7204744Swnj return; 7214744Swnj 7224744Swnj case MTIOCGET: 7234744Swnj mtget.mt_dsreg = sc->sc_dsreg; 7244744Swnj mtget.mt_erreg = sc->sc_erreg; 7254744Swnj mtget.mt_resid = sc->sc_resid; 7264744Swnj mtget.mt_type = MT_ISUT; 7274744Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 7284744Swnj u.u_error = EFAULT; 7294744Swnj return; 7304744Swnj 7314744Swnj default: 7324744Swnj u.u_error = ENXIO; 7334744Swnj } 7344744Swnj } 7354744Swnj 7364744Swnj utreset(uban) 7374744Swnj int uban; 7384744Swnj { 7394744Swnj register struct uba_ctlr *um; 7404744Swnj register ut11, tjunit; 7414744Swnj register struct uba_device *ui; 7424744Swnj register struct buf *dp; 7434744Swnj 7444744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 7454744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 7464744Swnj um->um_ubanum != uban) 7474744Swnj continue; 7484744Swnj printf(" ut%d", ut11); 7494746Ssam um->um_tab.b_state = 0; 7504744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7514744Swnj if (um->um_ubinfo) { 7524744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7534744Swnj ubadone(um); 7544744Swnj } 7554744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 7564746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 7574744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 7584744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 7594744Swnj ui->ui_alive == 0) 7604744Swnj continue; 7614744Swnj dp = &tjutab[tjunit]; 7624746Ssam dp->b_state = 0; 7634744Swnj dp->b_forw = 0; 7644744Swnj if (um->um_tab.b_actf == NULL) 7654744Swnj um->um_tab.b_actf = dp; 7664744Swnj else 7674744Swnj um->um_tab.b_actl->b_forw = dp; 7684744Swnj um->um_tab.b_actl = dp; 7694744Swnj if (tj_softc[tjunit].sc_openf > 0) 7704744Swnj tj_softc[tjunit].sc_openf = -1; 7714744Swnj } 7724744Swnj utstart(um); 7734744Swnj } 7744744Swnj } 7754744Swnj 7764744Swnj /* 7774744Swnj * Do a stand-alone core dump to tape -- 7784744Swnj * from here down, routines are used only in dump context 7794744Swnj */ 7804744Swnj #define DBSIZE 20 7814744Swnj 7824744Swnj utdump() 7834744Swnj { 7844744Swnj register struct uba_device *ui; 7854744Swnj register struct uba_regs *up; 7864746Ssam register struct utdevice *addr; 7874744Swnj int blk, num = maxfree; 7884744Swnj int start = 0; 7894744Swnj 7904744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 7914744Swnj if (tjdinfo[0] == 0) 7924744Swnj return (ENXIO); 7934744Swnj ui = phys(tjdinfo[0], struct uba_device *); 7944744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 7954744Swnj ubainit(); 7964744Swnj DELAY(1000000); 7974746Ssam utwait(addr); 7984746Ssam addr = (struct utdevice *)ui->ui_physaddr; 7994746Ssam /* 8004746Ssam * Be sure to set the appropriate density here. We use 8014746Ssam * 6250, but maybe it should be done at 1600 to insure the 8024746Ssam * tape can be read by most any other tape drive available. 8034746Ssam */ 8044746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8054746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8064744Swnj while (num > 0) { 8074744Swnj blk = num > DBSIZE ? DBSIZE : num; 8084746Ssam utdwrite(start, blk, addr, up); 8094746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8104746Ssam return(EIO); 8114744Swnj start += blk; 8124744Swnj num -= blk; 8134744Swnj } 8144746Ssam uteof(addr); 8154746Ssam uteof(addr); 8164746Ssam utwait(addr); 8174746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8184744Swnj return(EIO); 8194746Ssam addr->utcs1 = UT_REW|UT_GO; 8204744Swnj return (0); 8214744Swnj } 8224744Swnj 8234746Ssam utdwrite(dbuf, num, addr, up) 8244744Swnj register dbuf, num; 8254746Ssam register struct utdevice *addr; 8264744Swnj struct uba_regs *up; 8274744Swnj { 8284744Swnj register struct pte *io; 8294744Swnj register int npf; 8304744Swnj 8314746Ssam utwait(addr); 8324744Swnj io = up->uba_map; 8334744Swnj npf = num + 1; 8344744Swnj while (--npf != 0) 8354744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8364744Swnj *(int *)io = 0; 8374746Ssam addr->utwc = -((num*NBPG)>>1); 8384746Ssam addr->utfc = -(num*NBPG); 8394746Ssam addr->utba = 0; 8404746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8414744Swnj } 8424744Swnj 8434746Ssam utwait(addr) 8444746Ssam struct utdevice *addr; 8454744Swnj { 8464744Swnj register s; 8474744Swnj 8484744Swnj do 8494746Ssam s = addr->utds; 8504744Swnj while ((s&UTDS_DRY) == 0); 8514744Swnj } 8524744Swnj 8534746Ssam uteof(addr) 8544746Ssam struct utdevice *addr; 8554744Swnj { 8564744Swnj 8574746Ssam utwait(addr); 8584746Ssam addr->utcs1 = UT_WEOF|UT_GO; 8594744Swnj } 8604744Swnj #endif 861