1*1947Swnj /* ts.c 4.4 12/20/80 */ 21900Swnj 31941Swnj #include "ts.h" 41900Swnj #if NTS > 0 51900Swnj /* 61900Swnj * TS11 tape driver 71900Swnj */ 81900Swnj 91900Swnj #include "../h/param.h" 101900Swnj #include "../h/systm.h" 111900Swnj #include "../h/buf.h" 121900Swnj #include "../h/conf.h" 131900Swnj #include "../h/dir.h" 141900Swnj #include "../h/file.h" 151900Swnj #include "../h/user.h" 161900Swnj #include "../h/pte.h" 171900Swnj #include "../h/map.h" 181900Swnj #include "../h/uba.h" 19*1947Swnj #include "../h/vm.h" 201900Swnj 211900Swnj struct device { 221918Swnj u_short tsdb; 231918Swnj u_short tssr; 241900Swnj }; 251900Swnj 261900Swnj struct buf tstab; 271900Swnj struct buf rtsbuf; 281900Swnj struct buf ctsbuf; 291900Swnj 301900Swnj #define INF 1000000000 311900Swnj 321918Swnj u_short ts_uba; 331900Swnj long ts_iouba; 341900Swnj char ts_flags; 351900Swnj char ts_openf; 361900Swnj daddr_t ts_blkno; 371900Swnj daddr_t ts_nxrec; 381900Swnj 391900Swnj /* status message */ 401900Swnj struct sts { 411918Swnj u_short s_sts; 42*1947Swnj u_short len; 43*1947Swnj u_short rbpcr; 441918Swnj u_short xs0; 451918Swnj u_short xs1; 461918Swnj u_short xs2; 471918Swnj u_short xs3; 481900Swnj }; 491900Swnj 501900Swnj /* Error codes in stat 0 */ 511900Swnj #define TMK 0100000 521900Swnj #define RLS 040000 531900Swnj #define ONL 0100 541900Swnj #define WLE 04000 551900Swnj 561900Swnj /* command message */ 571900Swnj struct cmd { 581918Swnj u_short c_cmd; 591918Swnj u_short c_loba; 601918Swnj u_short c_hiba; 611918Swnj u_short c_size; 621900Swnj }; 631900Swnj 641900Swnj #define ACK 0100000 651900Swnj #define CVC 040000 661900Swnj #define IE 0200 671900Swnj #define READ 01 681900Swnj #define REREAD 01001 691900Swnj 701900Swnj #define SETCHR 04 711900Swnj 721900Swnj #define WRITE 05 731900Swnj #define REWRITE 01005 741900Swnj 751900Swnj #define SFORW 010 761900Swnj #define SREV 0410 771900Swnj #define REW 02010 781900Swnj 791900Swnj #define WTM 011 801900Swnj 811900Swnj #define GSTAT 017 821900Swnj 831900Swnj /* characteristics data */ 841900Swnj struct charac { 851918Swnj u_short char_loba; 861918Swnj u_short char_hiba; 871918Swnj u_short char_size; 881918Swnj u_short char_mode; 891900Swnj }; 901900Swnj 911900Swnj /* All the packets, collected */ 921900Swnj struct tsmesg { 931900Swnj struct cmd ts_cmd; 941900Swnj struct sts ts_sts; 951900Swnj struct charac ts_char; 961900Swnj int align; /* Should force alignment */ 971900Swnj } ts; 981900Swnj 991900Swnj /* Bits in (unibus) status register */ 1001900Swnj #define SC 0100000 1011900Swnj #define SSR 0200 1021900Swnj #define OFL 0100 1031900Swnj #define NBA 02000 1041900Swnj 1051900Swnj /* states */ 1061900Swnj #define SIO 1 1071900Swnj #define SSFOR 2 1081900Swnj #define SSREV 3 1091900Swnj #define SRETRY 4 1101900Swnj #define SCOM 5 1111900Swnj #define SOK 6 1121900Swnj 1131900Swnj #define H_WRITTEN 1 1141900Swnj 1151900Swnj tsopen(dev, flag) 1161900Swnj { 1171900Swnj register struct device *tsaddr = TSADDR; 1181900Swnj static struct tsmesg *ubaddr; 1191900Swnj 1201900Swnj tstab.b_flags |= B_TAPE; 1211900Swnj if (ts_openf) { 1221900Swnj u.u_error = ENXIO; 1231900Swnj return; 1241900Swnj } 1251900Swnj if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) { 1261900Swnj long i = 0; 1271900Swnj tsaddr->tssr = 0; 1281900Swnj while ((tsaddr->tssr & SSR)==0) { 1291900Swnj if (++i > 1000000) { 1301900Swnj printf("Tape unready\n"); 1311900Swnj u.u_error = ENXIO; 1321900Swnj return; 1331900Swnj } 1341900Swnj } 1351900Swnj } 1361900Swnj if (tsaddr->tssr&OFL) { 1371900Swnj printf("Tape offline\n"); 1381900Swnj u.u_error = ENXIO; 1391900Swnj return; 1401900Swnj } 1411900Swnj if (tsaddr->tssr&NBA) { 1421900Swnj ctsbuf.b_un.b_addr = (caddr_t) &ts; 1431900Swnj ctsbuf.b_bcount = sizeof(ts); 1441900Swnj if (ubaddr == 0) 1451900Swnj ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0); 1461918Swnj ts_uba = (u_short)((long)ubaddr + (((long)ubaddr >> 16) & 03)); 1471900Swnj ts.ts_char.char_loba = (int)&ubaddr->ts_sts; 1481918Swnj ts.ts_char.char_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03; 1491900Swnj ts.ts_char.char_size = sizeof(ts.ts_sts); 1501900Swnj ts.ts_char.char_mode = 0400; /* Stop on 2 tape marks */ 1511900Swnj ts.ts_cmd.c_cmd = ACK + 04; /* write characteristics */ 1521900Swnj ts.ts_cmd.c_loba = (int)&ubaddr->ts_char; 1531918Swnj ts.ts_cmd.c_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03; 1541900Swnj ts.ts_cmd.c_size = sizeof(ts.ts_sts); 1551900Swnj tsaddr->tsdb = ts_uba; 1561900Swnj } 1571900Swnj ts_blkno = 0; 1581900Swnj ts_nxrec = INF; 1591900Swnj ts_flags = 0; 1601900Swnj if (u.u_error==0) 1611900Swnj ts_openf++; 1621900Swnj } 1631900Swnj 1641900Swnj tsclose(dev, flag) 1651900Swnj { 1661900Swnj 1671900Swnj if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) { 1681900Swnj tscommand(WTM); 1691900Swnj tscommand(WTM); 1701900Swnj tscommand(SREV); 1711900Swnj } 1721900Swnj if ((minor(dev)&4) == 0) 1731900Swnj tscommand(REW); 1741900Swnj ts_openf = 0; 1751900Swnj } 1761900Swnj 1771900Swnj tscommand(com) 1781900Swnj { 1791900Swnj register struct buf *bp; 1801900Swnj 1811900Swnj bp = &ctsbuf; 1821900Swnj spl5(); 1831900Swnj while(bp->b_flags&B_BUSY) { 1841900Swnj bp->b_flags |= B_WANTED; 1851900Swnj sleep((caddr_t)bp, PRIBIO); 1861900Swnj } 1871900Swnj spl0(); 1881900Swnj bp->b_resid = com; 1891900Swnj bp->b_blkno = 0; 1901900Swnj bp->b_flags = B_BUSY|B_READ; 1911900Swnj tsstrategy(bp); 1921900Swnj iowait(bp); 1931900Swnj if(bp->b_flags&B_WANTED) 1941900Swnj wakeup((caddr_t)bp); 1951900Swnj bp->b_flags = 0; 1961900Swnj return(bp->b_resid); 1971900Swnj } 1981900Swnj 1991900Swnj tsstrategy(bp) 2001900Swnj register struct buf *bp; 2011900Swnj { 2021900Swnj register daddr_t *p; 2031900Swnj 2041900Swnj if(bp != &ctsbuf) { 2051900Swnj p = &ts_nxrec; 2061900Swnj if(dbtofsb(bp->b_blkno) > *p) { 2071900Swnj bp->b_flags |= B_ERROR; 2081900Swnj bp->b_error = ENXIO; 2091900Swnj iodone(bp); 2101900Swnj return; 2111900Swnj } 2121900Swnj if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 2131900Swnj bp->b_resid = bp->b_bcount; 2141900Swnj iodone(bp); 2151900Swnj return; 2161900Swnj } 2171900Swnj if ((bp->b_flags&B_READ)==0) { 2181900Swnj *p = dbtofsb(bp->b_blkno) + 1; 2191900Swnj ts_flags |= H_WRITTEN; 2201900Swnj } 2211900Swnj } 2221900Swnj bp->av_forw = NULL; 2231900Swnj spl5(); 2241900Swnj if (tstab.b_actf == NULL) 2251900Swnj tstab.b_actf = bp; 2261900Swnj else 2271900Swnj tstab.b_actl->av_forw = bp; 2281900Swnj tstab.b_actl = bp; 2291900Swnj if (tstab.b_active==0) 2301900Swnj tsstart(); 2311900Swnj spl0(); 2321900Swnj } 2331900Swnj 2341900Swnj tsstart() 2351900Swnj { 2361900Swnj register struct buf *bp; 2371900Swnj register struct device *tsaddr = TSADDR; 2381900Swnj daddr_t blkno; 2391900Swnj 2401900Swnj loop: 2411900Swnj if ((bp = tstab.b_actf) == NULL) 2421900Swnj return; 2431900Swnj blkno = ts_blkno; 2441900Swnj if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec) 2451900Swnj goto abort; 2461900Swnj if (bp == &ctsbuf) { 2471900Swnj tstab.b_active = SCOM; 2481900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid; 2491900Swnj ts.ts_cmd.c_loba = 1; /* count always 1 */ 2501900Swnj } else if (blkno == dbtofsb(bp->b_blkno)) { 2511900Swnj tstab.b_active = SIO; 2521900Swnj ts_iouba = ubasetup(bp, 1); 2531918Swnj ts.ts_cmd.c_loba = (u_short)ts_iouba; 2541918Swnj ts.ts_cmd.c_hiba = (u_short)(ts_iouba >> 16) & 03; 2551900Swnj ts.ts_cmd.c_size = bp->b_bcount; 2561900Swnj if(bp->b_flags & B_READ) 2571900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+READ; 2581900Swnj else 2591900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE; 2601900Swnj } else { 2611900Swnj if (blkno < dbtofsb(bp->b_blkno)) { 2621900Swnj tstab.b_active = SSFOR; 2631900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW; 2641900Swnj ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno; 2651900Swnj } else { 2661900Swnj tstab.b_active = SSREV; 2671900Swnj ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV; 2681900Swnj ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno); 2691900Swnj } 2701900Swnj } 2711900Swnj tsaddr->tsdb = ts_uba; 2721900Swnj return; 2731900Swnj 2741900Swnj abort: 2751900Swnj bp->b_flags |= B_ERROR; 2761900Swnj 2771900Swnj next: 2781900Swnj tstab.b_active = 0; 2791900Swnj tstab.b_actf = bp->av_forw; 2801900Swnj iodone(bp); 2811900Swnj goto loop; 2821900Swnj } 2831900Swnj 2841900Swnj tsintr() 2851900Swnj { 2861900Swnj register struct buf *bp; 2871900Swnj register struct device *tsaddr = TSADDR; 2881900Swnj register err, errclass, state; 2891900Swnj 2901900Swnj if ((bp = tstab.b_actf)==NULL) 2911900Swnj return; 2921900Swnj state = tstab.b_active; 2931900Swnj tstab.b_active = 0; 2941900Swnj err = tsaddr->tssr & 016; 2951900Swnj if ((tsaddr->tssr & SC) == 0) 2961900Swnj err = 0; 2971900Swnj errclass = 0; 2981900Swnj switch (err) { 2991900Swnj case 014: /* unrecoverable */ 3001900Swnj case 016: /* fatal */ 3011900Swnj case 002: /* attention (shouldn't happen) */ 3021900Swnj case 012: /* "recoverable", but shouldn't happen */ 3031900Swnj errclass = 2; 3041900Swnj break; 3051900Swnj 3061900Swnj case 0: /* all OK */ 3071900Swnj break; 3081900Swnj 3091900Swnj case 004: /* status alert */ 3101900Swnj if (ts.ts_sts.xs0&RLS && bp==&rtsbuf) /* short record */ 3111900Swnj break; 3121900Swnj if (ts.ts_sts.xs0 & TMK) { /* tape mark */ 3131900Swnj ts.ts_sts.rbpcr = bp->b_bcount; 3141900Swnj break; 3151900Swnj } 3161900Swnj errclass = 1; 3171900Swnj break; 3181900Swnj 3191900Swnj case 010: /* recoverable, tape moved */ 3201900Swnj if (state==SIO && ++bp->b_errcnt < 10) { 3211900Swnj ts.ts_cmd.c_cmd |= 01000; /* redo bit */ 3221900Swnj tstab.b_active = SIO; 3231900Swnj tsaddr->tsdb = ts_uba; 3241900Swnj return; 3251900Swnj } 3261900Swnj errclass = 1; 3271900Swnj break; 3281900Swnj 3291900Swnj case 006: /* Function reject */ 3301900Swnj if (state==SIO && ts.ts_sts.xs0 & WLE) 3311900Swnj printf("Tape needs a ring\n"); 3321900Swnj if ((ts.ts_sts.xs0&ONL) == 0) /* tape offline */ 3331900Swnj printf("Tape offline\n"); 3341900Swnj errclass = 2; 3351900Swnj } 3361900Swnj if (errclass) 3371900Swnj printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr, 3381900Swnj ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr, 3391900Swnj ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3); 3401900Swnj switch(state) { 3411900Swnj case SIO: 3421900Swnj ts_blkno++; 3431900Swnj if (ts_iouba) 3441900Swnj ubafree(ts_iouba); 3451900Swnj else 3461900Swnj printf("uba alloc botch\n"); 3471900Swnj ts_iouba = 0; 3481900Swnj case SCOM: 3491900Swnj tstab.b_errcnt = 0; 3501900Swnj tstab.b_actf = bp->av_forw; 3511900Swnj bp->b_resid = ts.ts_sts.rbpcr; 3521900Swnj iodone(bp); 3531900Swnj break; 3541900Swnj 3551900Swnj case SSFOR: 3561900Swnj case SSREV: 3571900Swnj ts_blkno = dbtofsb(bp->b_blkno); 3581900Swnj break; 3591900Swnj 3601900Swnj default: 3611900Swnj printf("Unknown tape interrupt\n"); 3621900Swnj errclass = 2; 3631900Swnj break; 3641900Swnj } 3651900Swnj if (errclass > 1) { 3661900Swnj while (bp = tstab.b_actf) { 3671900Swnj bp->b_flags |= B_ERROR; 3681900Swnj iodone(bp); 3691900Swnj tstab.b_actf = bp->av_forw; 3701900Swnj } 3711900Swnj } 3721900Swnj tsstart(); 3731900Swnj } 3741900Swnj 3751900Swnj tsread(dev) 3761900Swnj { 3771900Swnj tsphys(dev); 3781900Swnj physio(tsstrategy, &rtsbuf, dev, B_READ, minphys); 3791900Swnj } 3801900Swnj 3811900Swnj tswrite(dev) 3821900Swnj { 3831900Swnj tsphys(dev); 3841900Swnj physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys); 3851900Swnj } 3861900Swnj 3871900Swnj tsphys(dev) 3881900Swnj { 3891900Swnj register unit; 3901900Swnj daddr_t a; 3911900Swnj 3921900Swnj a = u.u_offset >> 9; 3931900Swnj ts_blkno = dbtofsb(a); 3941900Swnj ts_nxrec = dbtofsb(a)+1; 3951900Swnj } 3961918Swnj 3971918Swnj #define UBMAP (int *)0xf30800 3981918Swnj 3991918Swnj int dtsinfo; 400*1947Swnj struct tsmesg dts; 4011918Swnj 4021918Swnj twall(start, num) 4031918Swnj { 4041918Swnj register struct device *tsaddr = TSPHYS; 4051918Swnj register int *ubap = UBMAP; 4061918Swnj register int p, i; 4071918Swnj 4081918Swnj tsinit(); 4091918Swnj /* dump mem */ 4101918Swnj p = PG_V; 4111918Swnj i = 0; 4121918Swnj while (i<num) { 4131918Swnj *(ubap) = p|i++; 4141918Swnj *(ubap+1) = p|i; 4151918Swnj dts.ts_cmd.c_loba = 0; 4161918Swnj dts.ts_cmd.c_hiba = 0; 4171918Swnj dts.ts_cmd.c_size = NBPG; 4181918Swnj dts.ts_cmd.c_cmd = ACK+CVC+WRITE; 4191918Swnj tsaddr->tsdb = dtsinfo; 4201918Swnj twait(); 4211918Swnj } 4221918Swnj printf("done\n"); 4231918Swnj } 4241918Swnj 4251918Swnj tsinit() 4261918Swnj { 4271918Swnj register struct device *tsaddr = TSPHYS; 4281918Swnj register struct tsmesg *tsm; 4291918Swnj register int *ubap = UBMAP; 4301918Swnj register i; 4311918Swnj 4321918Swnj tsaddr->tssr = 0; 4331918Swnj while ((tsaddr->tssr&SSR)==0) 4341918Swnj ; 4351918Swnj i = (int)&dts; 4361918Swnj i &= 0xefffff; 4371918Swnj dtsinfo = ((i&0777)|02000); 4381918Swnj tsm = (struct tsmesg *)dtsinfo; 4391918Swnj i >>= 9; 4401918Swnj i |= PG_V; 4411918Swnj *(ubap+2) = i; 4421918Swnj *(ubap+3) = i+1; 4431918Swnj dts.ts_cmd.c_cmd = ACK + 04; 444*1947Swnj dts.ts_cmd.c_loba = (int)&tsm->ts_char; 4451918Swnj dts.ts_cmd.c_hiba = 0; 4461918Swnj dts.ts_cmd.c_size = sizeof(dts.ts_char); 447*1947Swnj dts.ts_char.char_loba = (int)&tsm->ts_sts; 4481918Swnj dts.ts_char.char_hiba = 0; 4491918Swnj dts.ts_char.char_size = sizeof(dts.ts_sts); 4501918Swnj dts.ts_char.char_mode = 0400; 4511918Swnj tsaddr->tsdb = dtsinfo; 4521918Swnj twait(); 4531918Swnj } 4541918Swnj 4551918Swnj teof() 4561918Swnj { 4571918Swnj 4581918Swnj dtscommand(WTM); 4591918Swnj } 4601918Swnj 4611918Swnj rewind() 4621918Swnj { 4631918Swnj 4641918Swnj dtscommand(REW); 4651918Swnj } 4661918Swnj 4671918Swnj dtscommand(com) 4681918Swnj { 4691918Swnj register struct device *tsaddr = TSPHYS; 4701918Swnj 4711918Swnj dts.ts_cmd.c_cmd = ACK+CVC+com; 4721918Swnj dts.ts_cmd.c_loba = 1; 4731918Swnj tsaddr->tsdb = dtsinfo; 4741918Swnj twait(); 4751918Swnj } 4761918Swnj 4771918Swnj twait() 4781918Swnj { 4791918Swnj register struct device *tsaddr = TSPHYS; 4801918Swnj register i; 4811918Swnj 4821918Swnj while ((tsaddr->tssr&SSR)==0) 4831918Swnj ; 4841918Swnj i = tsaddr->tssr; 4851918Swnj if (i&SC) 4861918Swnj printf("tssr %x ", i); 4871918Swnj } 4881900Swnj #endif 489